unify menu item format
This commit is contained in:
+29
-33
@@ -515,50 +515,37 @@ struct S_UpdateClientConfig_BB_04 {
|
||||
// there was a separate command to send the block list, but it was scrapped.
|
||||
// Perhaps this was used for command A1, which is identical to 07 and A0 in all
|
||||
// versions of PSO (except DC NTE).
|
||||
// The menu is titles "Ship Select" unless the first menu item begins with the
|
||||
// The menu is titled "Ship Select" unless the first menu item begins with the
|
||||
// text "BLOCK" (all caps), in which case it is titled "Block Select".
|
||||
|
||||
// Command is a list of these; header.flag is the entry count. The first entry
|
||||
// is not included in the count and does not appear on the client. The text of
|
||||
// the first entry becomes the ship name when the client joins a lobby.
|
||||
template <TextEncoding Encoding, size_t Chars>
|
||||
struct S_MenuEntryT {
|
||||
// is not included in the count and does not appear on the client. The first
|
||||
// entry's text becomes the ship name displayed in the corner of the lobby HUD,
|
||||
// unless it begins with "BLOCK", in which case it is ignored.
|
||||
template <TextEncoding Encoding>
|
||||
struct S_MenuItemT {
|
||||
le_uint32_t menu_id = 0;
|
||||
le_uint32_t item_id = 0;
|
||||
le_uint16_t flags = 0x0F04; // Should be this value, apparently
|
||||
pstring<Encoding, Chars> text;
|
||||
} __packed__;
|
||||
using S_MenuEntry_PC_BB_07_1F = S_MenuEntryT<TextEncoding::UTF16, 0x11>;
|
||||
using S_MenuEntry_DC_V3_07_1F = S_MenuEntryT<TextEncoding::MARKED, 0x12>;
|
||||
check_struct_size(S_MenuEntry_PC_BB_07_1F, 0x2C);
|
||||
check_struct_size(S_MenuEntry_DC_V3_07_1F, 0x1C);
|
||||
|
||||
// 08 (C->S): Request game list
|
||||
// Internal name: SndGameList
|
||||
// No arguments
|
||||
|
||||
// 08 (S->C): Game list
|
||||
// Internal name: RcvGameList
|
||||
// Client responds with 09 and 10 commands (or nothing if the player cancels).
|
||||
|
||||
// Command is a list of these; header.flag is the entry count. The first entry
|
||||
// is not included in the count and does not appear on the client.
|
||||
template <TextEncoding Encoding>
|
||||
struct S_GameMenuEntryT {
|
||||
le_uint32_t menu_id = 0;
|
||||
le_uint32_t game_id = 0;
|
||||
// The following two fields are only used for the game menu; for Ship Select,
|
||||
// Block Select, and Information, they are unused.
|
||||
// difficulty_tag is 0x0A on Episode 3; on all other versions, it's
|
||||
// difficulty + 0x22 (so 0x25 means Ultimate, for example)
|
||||
// difficulty + 0x22 (so 0x25 means Ultimate, for example).
|
||||
uint8_t difficulty_tag = 0;
|
||||
uint8_t num_players = 0;
|
||||
|
||||
pstring<Encoding, 0x10> name;
|
||||
|
||||
// The episode field is only used for the game menu; for Ship Select, Block
|
||||
// Select, and Information, it is unused.
|
||||
// The episode field is used differently by different versions:
|
||||
// - On DCv1, PC, and GC Episode 3, the value is ignored.
|
||||
// - On DCv2, 1 means v1 players can't join the game, and 0 means they can.
|
||||
// - On GC Ep1&2, 0x40 means Episode 1, and 0x41 means Episode 2.
|
||||
// - On BB, 0x40/0x41 mean Episodes 1/2 as on GC, and 0x43 means Episode 4.
|
||||
uint8_t episode = 0;
|
||||
// Flags:
|
||||
// Flags (01 and 02 are used for all menus; the rest are only used for the
|
||||
// game menu):
|
||||
// 01 = Send name? (client sends the name field in the 10 command if this
|
||||
// item is chosen, but it's blank)
|
||||
// 02 = Locked (lock icon appears in menu; player is prompted for password if
|
||||
@@ -567,16 +554,25 @@ struct S_GameMenuEntryT {
|
||||
// 04 = Disabled (BB; used for solo games)
|
||||
// 10 = Is battle mode
|
||||
// 20 = Is challenge mode
|
||||
// 40 = Is v2 only (DCv2/PC); name renders in orange
|
||||
// 40 = Is v2 only (DCv2/PC); game name renders in orange
|
||||
// 40 = Is Episode 1 (V3/BB)
|
||||
// 80 = Is Episode 2 (V3/BB)
|
||||
// C0 = Is Episode 4 (BB)
|
||||
uint8_t flags = 0;
|
||||
} __packed__;
|
||||
using S_GameMenuEntry_PC_BB_08 = S_GameMenuEntryT<TextEncoding::UTF16>;
|
||||
using S_GameMenuEntry_DC_V3_08_Ep3_E6 = S_GameMenuEntryT<TextEncoding::MARKED>;
|
||||
check_struct_size(S_GameMenuEntry_PC_BB_08, 0x2C);
|
||||
check_struct_size(S_GameMenuEntry_DC_V3_08_Ep3_E6, 0x1C);
|
||||
using S_MenuItem_PC_BB_08 = S_MenuItemT<TextEncoding::UTF16>;
|
||||
using S_MenuItem_DC_V3_08_Ep3_E6 = S_MenuItemT<TextEncoding::MARKED>;
|
||||
check_struct_size(S_MenuItem_PC_BB_08, 0x2C);
|
||||
check_struct_size(S_MenuItem_DC_V3_08_Ep3_E6, 0x1C);
|
||||
|
||||
// 08 (C->S): Request game list
|
||||
// Internal name: SndGameList
|
||||
// No arguments
|
||||
|
||||
// 08 (S->C): Game list
|
||||
// Internal name: RcvGameList
|
||||
// Client responds with 09 and 10 commands (or nothing if the player cancels).
|
||||
// Command format is the same as 07.
|
||||
|
||||
// 09 (C->S): Menu item info request
|
||||
// Internal name: SndInfo
|
||||
|
||||
@@ -484,7 +484,7 @@ void DownloadSession::on_channel_input(uint16_t command, uint32_t flag, std::str
|
||||
this->log.info("Ship Select menu:");
|
||||
for (item_index = 1; item_index <= flag; item_index++) {
|
||||
const auto& item = items[item_index];
|
||||
auto text = strip_color(item.text.decode());
|
||||
auto text = strip_color(item.name.decode());
|
||||
this->log.info("%zu: (%08" PRIX32 " %08" PRIX32 ") %s", item_index, item.menu_id.load(), item.item_id.load(), text.c_str());
|
||||
if (this->ship_menu_selections.count(text)) {
|
||||
break;
|
||||
@@ -506,9 +506,9 @@ void DownloadSession::on_channel_input(uint16_t command, uint32_t flag, std::str
|
||||
};
|
||||
|
||||
if (uses_utf16(this->channel.version)) {
|
||||
handle_command.operator()<S_MenuEntry_PC_BB_07_1F>();
|
||||
handle_command.operator()<S_MenuItem_PC_BB_08>();
|
||||
} else {
|
||||
handle_command.operator()<S_MenuEntry_DC_V3_07_1F>();
|
||||
handle_command.operator()<S_MenuItem_DC_V3_08_Ep3_E6>();
|
||||
}
|
||||
|
||||
this->channel.send(0x10, 0x00, ret);
|
||||
|
||||
+3
-1
@@ -13,8 +13,10 @@
|
||||
|
||||
class HTTPServer {
|
||||
public:
|
||||
// shared_base should be null unless
|
||||
// shared_base should be null unless the HTTP server should run on the main
|
||||
// thread (on Windows).
|
||||
HTTPServer(std::shared_ptr<ServerState> state, std::shared_ptr<struct event_base> shared_base);
|
||||
|
||||
HTTPServer(const HTTPServer&) = delete;
|
||||
HTTPServer(HTTPServer&&) = delete;
|
||||
HTTPServer& operator=(const HTTPServer&) = delete;
|
||||
|
||||
@@ -885,19 +885,15 @@ uint32_t encrypt_challenge_time(uint16_t value) {
|
||||
available_bits.erase(it);
|
||||
}
|
||||
|
||||
uint32_t ret = (mask << 16) | (value ^ mask);
|
||||
fprintf(stderr, "encrypt_challenge_time %04hX => %08" PRIX32 "\n", value, ret);
|
||||
return ret;
|
||||
return (mask << 16) | (value ^ mask);
|
||||
}
|
||||
|
||||
uint16_t decrypt_challenge_time(uint32_t value) {
|
||||
uint16_t mask = (value >> 0x10);
|
||||
uint8_t mask_one_bits = count_one_bits(mask);
|
||||
uint16_t ret = ((mask_one_bits < 4) || (mask_one_bits > 12))
|
||||
return ((mask_one_bits < 4) || (mask_one_bits > 12))
|
||||
? 0xFFFF
|
||||
: ((mask ^ value) & 0xFFFF);
|
||||
fprintf(stderr, "decrypt_challenge_time %08" PRIX32 " => %04hX\n", value, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string decrypt_v2_registry_value(const void* data, size_t size) {
|
||||
|
||||
@@ -391,7 +391,6 @@ void forward_subcommand_with_entity_id_transcode_t(
|
||||
lc->log.info("Subcommand cannot be translated to client\'s version");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "NOCOMMIT: same version\n");
|
||||
send_command_t(lc, command, flag, cmd);
|
||||
}
|
||||
}
|
||||
@@ -2903,7 +2902,7 @@ static void on_entity_drop_item_request(shared_ptr<Client> c, uint8_t command, u
|
||||
return;
|
||||
case Lobby::DropMode::CLIENT: {
|
||||
// If the leader is BB, use SERVER_SHARED instead
|
||||
// NOCOMMIT: We should also use server drops if any clients have incompatible object lists, since they might generate incorrect IDs for items and we can't override them
|
||||
// TODO: We should also use server drops if any clients have incompatible object lists, since they might generate incorrect IDs for items and we can't override them
|
||||
auto leader = l->clients[l->leader_id];
|
||||
if (leader && leader->version() == Version::BB_V4) {
|
||||
drop_mode = Lobby::DropMode::SERVER_SHARED;
|
||||
|
||||
+10
-9
@@ -1385,8 +1385,7 @@ void send_menu_t(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = menu->menu_id;
|
||||
e.item_id = 0xFFFFFFFF;
|
||||
e.flags = 0x0004;
|
||||
e.text.encode(menu->name, c->language());
|
||||
e.name.encode(menu->name, c->language());
|
||||
}
|
||||
|
||||
for (const auto& item : menu->items) {
|
||||
@@ -1440,8 +1439,10 @@ void send_menu_t(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = menu->menu_id;
|
||||
e.item_id = item.item_id;
|
||||
e.flags = (c->version() == Version::BB_V4) ? 0x0004 : 0x0F04;
|
||||
e.text.encode(item.name, c->language());
|
||||
e.name.encode(item.name, c->language());
|
||||
e.difficulty_tag = 0x04;
|
||||
e.num_players = (c->version() == Version::BB_V4) ? 0x00 : 0x0F;
|
||||
e.flags = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1451,9 +1452,9 @@ void send_menu_t(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info
|
||||
|
||||
void send_menu(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info_menu) {
|
||||
if (uses_utf16(c->version())) {
|
||||
send_menu_t<S_MenuEntry_PC_BB_07_1F>(c, menu, is_info_menu);
|
||||
send_menu_t<S_MenuItem_PC_BB_08>(c, menu, is_info_menu);
|
||||
} else {
|
||||
send_menu_t<S_MenuEntry_DC_V3_07_1F>(c, menu, is_info_menu);
|
||||
send_menu_t<S_MenuItem_DC_V3_08_Ep3_E6>(c, menu, is_info_menu);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,11 +1465,11 @@ void send_game_menu_t(
|
||||
bool show_tournaments_only) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
vector<S_GameMenuEntryT<Encoding>> entries;
|
||||
vector<S_MenuItemT<Encoding>> entries;
|
||||
{
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = MenuID::GAME;
|
||||
e.game_id = 0x00000000;
|
||||
e.item_id = 0x00000000;
|
||||
e.difficulty_tag = 0x00;
|
||||
e.num_players = 0x00;
|
||||
e.name.encode(s->name, c->language());
|
||||
@@ -1512,7 +1513,7 @@ void send_game_menu_t(
|
||||
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = MenuID::GAME;
|
||||
e.game_id = l->lobby_id;
|
||||
e.item_id = l->lobby_id;
|
||||
e.difficulty_tag = (is_ep3(c->version()) ? 0x0A : (l->difficulty + 0x22));
|
||||
e.num_players = l->count_clients();
|
||||
if (is_dc(c->version())) {
|
||||
|
||||
Reference in New Issue
Block a user