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.
|
// 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
|
// Perhaps this was used for command A1, which is identical to 07 and A0 in all
|
||||||
// versions of PSO (except DC NTE).
|
// 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".
|
// 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
|
// 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
|
// is not included in the count and does not appear on the client. The first
|
||||||
// the first entry becomes the ship name when the client joins a lobby.
|
// entry's text becomes the ship name displayed in the corner of the lobby HUD,
|
||||||
template <TextEncoding Encoding, size_t Chars>
|
// unless it begins with "BLOCK", in which case it is ignored.
|
||||||
struct S_MenuEntryT {
|
template <TextEncoding Encoding>
|
||||||
|
struct S_MenuItemT {
|
||||||
le_uint32_t menu_id = 0;
|
le_uint32_t menu_id = 0;
|
||||||
le_uint32_t item_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
|
// The following two fields are only used for the game menu; for Ship Select,
|
||||||
// Internal name: SndGameList
|
// Block Select, and Information, they are unused.
|
||||||
// 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;
|
|
||||||
// difficulty_tag is 0x0A on Episode 3; on all other versions, it's
|
// 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 difficulty_tag = 0;
|
||||||
uint8_t num_players = 0;
|
uint8_t num_players = 0;
|
||||||
|
|
||||||
pstring<Encoding, 0x10> name;
|
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:
|
// The episode field is used differently by different versions:
|
||||||
// - On DCv1, PC, and GC Episode 3, the value is ignored.
|
// - 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 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 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.
|
// - On BB, 0x40/0x41 mean Episodes 1/2 as on GC, and 0x43 means Episode 4.
|
||||||
uint8_t episode = 0;
|
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
|
// 01 = Send name? (client sends the name field in the 10 command if this
|
||||||
// item is chosen, but it's blank)
|
// item is chosen, but it's blank)
|
||||||
// 02 = Locked (lock icon appears in menu; player is prompted for password if
|
// 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)
|
// 04 = Disabled (BB; used for solo games)
|
||||||
// 10 = Is battle mode
|
// 10 = Is battle mode
|
||||||
// 20 = Is challenge 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)
|
// 40 = Is Episode 1 (V3/BB)
|
||||||
// 80 = Is Episode 2 (V3/BB)
|
// 80 = Is Episode 2 (V3/BB)
|
||||||
// C0 = Is Episode 4 (BB)
|
// C0 = Is Episode 4 (BB)
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
} __packed__;
|
} __packed__;
|
||||||
using S_GameMenuEntry_PC_BB_08 = S_GameMenuEntryT<TextEncoding::UTF16>;
|
using S_MenuItem_PC_BB_08 = S_MenuItemT<TextEncoding::UTF16>;
|
||||||
using S_GameMenuEntry_DC_V3_08_Ep3_E6 = S_GameMenuEntryT<TextEncoding::MARKED>;
|
using S_MenuItem_DC_V3_08_Ep3_E6 = S_MenuItemT<TextEncoding::MARKED>;
|
||||||
check_struct_size(S_GameMenuEntry_PC_BB_08, 0x2C);
|
check_struct_size(S_MenuItem_PC_BB_08, 0x2C);
|
||||||
check_struct_size(S_GameMenuEntry_DC_V3_08_Ep3_E6, 0x1C);
|
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
|
// 09 (C->S): Menu item info request
|
||||||
// Internal name: SndInfo
|
// 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:");
|
this->log.info("Ship Select menu:");
|
||||||
for (item_index = 1; item_index <= flag; item_index++) {
|
for (item_index = 1; item_index <= flag; item_index++) {
|
||||||
const auto& item = items[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());
|
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)) {
|
if (this->ship_menu_selections.count(text)) {
|
||||||
break;
|
break;
|
||||||
@@ -506,9 +506,9 @@ void DownloadSession::on_channel_input(uint16_t command, uint32_t flag, std::str
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (uses_utf16(this->channel.version)) {
|
if (uses_utf16(this->channel.version)) {
|
||||||
handle_command.operator()<S_MenuEntry_PC_BB_07_1F>();
|
handle_command.operator()<S_MenuItem_PC_BB_08>();
|
||||||
} else {
|
} 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);
|
this->channel.send(0x10, 0x00, ret);
|
||||||
|
|||||||
+3
-1
@@ -13,8 +13,10 @@
|
|||||||
|
|
||||||
class HTTPServer {
|
class HTTPServer {
|
||||||
public:
|
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(std::shared_ptr<ServerState> state, std::shared_ptr<struct event_base> shared_base);
|
||||||
|
|
||||||
HTTPServer(const HTTPServer&) = delete;
|
HTTPServer(const HTTPServer&) = delete;
|
||||||
HTTPServer(HTTPServer&&) = delete;
|
HTTPServer(HTTPServer&&) = delete;
|
||||||
HTTPServer& operator=(const HTTPServer&) = delete;
|
HTTPServer& operator=(const HTTPServer&) = delete;
|
||||||
|
|||||||
@@ -885,19 +885,15 @@ uint32_t encrypt_challenge_time(uint16_t value) {
|
|||||||
available_bits.erase(it);
|
available_bits.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ret = (mask << 16) | (value ^ mask);
|
return (mask << 16) | (value ^ mask);
|
||||||
fprintf(stderr, "encrypt_challenge_time %04hX => %08" PRIX32 "\n", value, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t decrypt_challenge_time(uint32_t value) {
|
uint16_t decrypt_challenge_time(uint32_t value) {
|
||||||
uint16_t mask = (value >> 0x10);
|
uint16_t mask = (value >> 0x10);
|
||||||
uint8_t mask_one_bits = count_one_bits(mask);
|
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
|
? 0xFFFF
|
||||||
: ((mask ^ value) & 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) {
|
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");
|
lc->log.info("Subcommand cannot be translated to client\'s version");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "NOCOMMIT: same version\n");
|
|
||||||
send_command_t(lc, command, flag, cmd);
|
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;
|
return;
|
||||||
case Lobby::DropMode::CLIENT: {
|
case Lobby::DropMode::CLIENT: {
|
||||||
// If the leader is BB, use SERVER_SHARED instead
|
// 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];
|
auto leader = l->clients[l->leader_id];
|
||||||
if (leader && leader->version() == Version::BB_V4) {
|
if (leader && leader->version() == Version::BB_V4) {
|
||||||
drop_mode = Lobby::DropMode::SERVER_SHARED;
|
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();
|
auto& e = entries.emplace_back();
|
||||||
e.menu_id = menu->menu_id;
|
e.menu_id = menu->menu_id;
|
||||||
e.item_id = 0xFFFFFFFF;
|
e.item_id = 0xFFFFFFFF;
|
||||||
e.flags = 0x0004;
|
e.name.encode(menu->name, c->language());
|
||||||
e.text.encode(menu->name, c->language());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& item : menu->items) {
|
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();
|
auto& e = entries.emplace_back();
|
||||||
e.menu_id = menu->menu_id;
|
e.menu_id = menu->menu_id;
|
||||||
e.item_id = item.item_id;
|
e.item_id = item.item_id;
|
||||||
e.flags = (c->version() == Version::BB_V4) ? 0x0004 : 0x0F04;
|
e.name.encode(item.name, c->language());
|
||||||
e.text.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) {
|
void send_menu(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info_menu) {
|
||||||
if (uses_utf16(c->version())) {
|
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 {
|
} 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) {
|
bool show_tournaments_only) {
|
||||||
auto s = c->require_server_state();
|
auto s = c->require_server_state();
|
||||||
|
|
||||||
vector<S_GameMenuEntryT<Encoding>> entries;
|
vector<S_MenuItemT<Encoding>> entries;
|
||||||
{
|
{
|
||||||
auto& e = entries.emplace_back();
|
auto& e = entries.emplace_back();
|
||||||
e.menu_id = MenuID::GAME;
|
e.menu_id = MenuID::GAME;
|
||||||
e.game_id = 0x00000000;
|
e.item_id = 0x00000000;
|
||||||
e.difficulty_tag = 0x00;
|
e.difficulty_tag = 0x00;
|
||||||
e.num_players = 0x00;
|
e.num_players = 0x00;
|
||||||
e.name.encode(s->name, c->language());
|
e.name.encode(s->name, c->language());
|
||||||
@@ -1512,7 +1513,7 @@ void send_game_menu_t(
|
|||||||
|
|
||||||
auto& e = entries.emplace_back();
|
auto& e = entries.emplace_back();
|
||||||
e.menu_id = MenuID::GAME;
|
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.difficulty_tag = (is_ep3(c->version()) ? 0x0A : (l->difficulty + 0x22));
|
||||||
e.num_players = l->count_clients();
|
e.num_players = l->count_clients();
|
||||||
if (is_dc(c->version())) {
|
if (is_dc(c->version())) {
|
||||||
|
|||||||
Reference in New Issue
Block a user