From d2d96d9c0ab94d0b90ffe692218416729a9f8189 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 22 Oct 2023 08:55:09 -0700 Subject: [PATCH] get client language from login command instead of player data --- src/Client.cc | 1 + src/Client.hh | 5 +---- src/Episode3/Server.cc | 17 ++++++++--------- src/ReceiveCommands.cc | 25 ++++++++++++++++--------- src/SendCommands.cc | 6 +++--- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/Client.cc b/src/Client.cc index e43790f6..83f67ce1 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -61,6 +61,7 @@ Client::Client( should_send_to_proxy_server(false), proxy_destination_address(0), proxy_destination_port(0), + language(1), x(0.0f), z(0.0f), area(0), diff --git a/src/Client.hh b/src/Client.hh index da775502..a76bb871 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -150,6 +150,7 @@ struct Client : public std::enable_shared_from_this { // Lobby/positioning ClientOptions options; + uint8_t language; float x; float z; uint32_t area; @@ -191,10 +192,6 @@ struct Client : public std::enable_shared_from_this { void reschedule_ping_and_timeout_events(); - inline uint8_t language() const { - auto p = this->game_data.player(true, false); - return p ? p->inventory.language : 1; // English by default - } inline GameVersion version() const { return this->channel.version; } diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index e12d3553..b3208c8a 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -2318,7 +2318,7 @@ void Server::handle_CAx40_map_list_request(shared_ptr sender_c, const st } const auto& list_data = this->options.map_index->get_compressed_list( - l->count_clients(), sender_c->language()); + l->count_clients(), sender_c->language); StringWriter w; uint32_t subcommand_size = (list_data.size() + sizeof(G_MapList_GC_Ep3_6xB6x40) + 3) & (~3); @@ -2347,16 +2347,15 @@ void Server::send_6xB6x41_to_all_clients() const { if (!c) { return; } - uint8_t language = c->language(); - if (map_commands_by_language.size() <= language) { - map_commands_by_language.resize(language + 1); + if (map_commands_by_language.size() <= c->language) { + map_commands_by_language.resize(c->language + 1); } - if (map_commands_by_language[language].empty()) { - map_commands_by_language[language] = this->prepare_6xB6x41_map_definition( - this->last_chosen_map, language, l->flags & Lobby::Flag::IS_EP3_TRIAL); + if (map_commands_by_language[c->language].empty()) { + map_commands_by_language[c->language] = this->prepare_6xB6x41_map_definition( + this->last_chosen_map, c->language, l->flags & Lobby::Flag::IS_EP3_TRIAL); } - this->log().info("Sending %c version of map %08" PRIX32, char_for_language_code(language), this->last_chosen_map->map_number); - send_command(c, 0x6C, 0x00, map_commands_by_language[language]); + this->log().info("Sending %c version of map %08" PRIX32, char_for_language_code(c->language), this->last_chosen_map->map_number); + send_command(c, 0x6C, 0x00, map_commands_by_language[c->language]); }; for (const auto& c : l->clients) { send_to_client(c); diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 5a905419..0799978f 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -430,6 +430,7 @@ static void on_8B_DCNTE(shared_ptr c, uint16_t, uint32_t, const string& c->channel.version = GameVersion::DC; c->flags |= flags_for_version(c->version(), -1); c->flags |= Client::Flag::IS_DC_V1 | Client::Flag::IS_DC_TRIAL_EDITION; + c->language = cmd.language; uint32_t serial_number = stoul(cmd.serial_number, nullptr, 16); try { @@ -505,7 +506,8 @@ static void on_90_DC(shared_ptr c, uint16_t, uint32_t, const string& dat } static void on_92_DC(shared_ptr c, uint16_t, uint32_t, const string& data) { - check_size_t(data); + const auto& cmd = check_size_t(data); + c->language = cmd.language; // It appears that in response to 90 01, the DCv1 prototype sends 93 rather // than 92, so we use the presence of a 92 command to determine that the // client is actually DCv1 and not the prototype. @@ -518,6 +520,7 @@ static void on_93_DC(shared_ptr c, uint16_t, uint32_t, const string& dat auto s = c->require_server_state(); set_console_client_flags(c, cmd.sub_version); + c->language = cmd.language; uint32_t serial_number = stoul(cmd.serial_number, nullptr, 16); try { @@ -633,6 +636,7 @@ static void on_9C(shared_ptr c, uint16_t, uint32_t, const string& data) auto s = c->require_server_state(); set_console_client_flags(c, cmd.sub_version); + c->language = cmd.language; uint32_t serial_number = stoul(cmd.serial_number, nullptr, 16); try { @@ -740,6 +744,8 @@ static void on_9D_9E(shared_ptr c, uint16_t command, uint32_t, const str } set_console_client_flags(c, base_cmd->sub_version); + c->language = base_cmd->language; + // See system/ppc/Episode3USAQuestBufferOverflow.s for where this value gets // set. We use this to determine if the client has already run the code or // not; sending it again when the client has already run it will likely cause @@ -1494,7 +1500,7 @@ static void on_09(shared_ptr c, uint16_t, uint32_t, const string& data) if (!q) { send_quest_info(c, u"$C4Quest does not\nexist.", is_download_quest); } else { - auto vq = q->version(c->quest_version(), c->language()); + auto vq = q->version(c->quest_version(), c->language); if (!vq) { send_quest_info(c, u"$C4Quest does not\nexist for this game\nversion.", is_download_quest); } else { @@ -1747,7 +1753,7 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) if (num_ep3_categories == 1) { auto quest_index = s->quest_index_for_client(c); if (quest_index) { - auto quests = quest_index->filter(ep3_category_id, c->quest_version(), c->language()); + auto quests = quest_index->filter(ep3_category_id, c->quest_version(), c->language); send_quest_menu(c, MenuID::QUEST, quests, true); } else { send_lobby_message_box(c, u"$C6Quests are not available."); @@ -2033,7 +2039,7 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) break; } shared_ptr l = c->lobby.lock(); - auto quests = quest_index->filter(item_id, c->quest_version(), c->language()); + auto quests = quest_index->filter(item_id, c->quest_version(), c->language); // Hack: Assume the menu to be sent is the download quest menu if the // client is not in any lobby @@ -2089,7 +2095,7 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) continue; } - auto vq = q->version(lc->quest_version(), lc->language()); + auto vq = q->version(lc->quest_version(), lc->language); if (!vq) { send_lobby_message_box(lc, u"$C6Quest does not exist\nfor this game version."); lc->should_disconnect = true; @@ -2137,7 +2143,7 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) } else { string quest_name = encode_sjis(q->name); - auto vq = q->version(c->quest_version(), c->language()); + auto vq = q->version(c->quest_version(), c->language); if (!vq) { send_lobby_message_box(c, u"$C6Quest does not exist\nfor this game version."); break; @@ -2491,7 +2497,7 @@ static void on_AC_V3_BB(shared_ptr c, uint16_t, uint32_t, const string& (l->base_version == GameVersion::BB) && l->map && l->quest) { - auto dat_contents = prs_decompress(*l->quest->version(QuestScriptVersion::BB_V4, c->language())->dat_contents); + auto dat_contents = prs_decompress(*l->quest->version(QuestScriptVersion::BB_V4, c->language)->dat_contents); l->map->clear(); l->map->add_enemies_from_quest_data(l->episode, l->difficulty, l->event, dat_contents.data(), dat_contents.size()); c->log.info("Replaced enemies list with quest layout (%zu entries)", @@ -2689,6 +2695,7 @@ static void on_61_98(shared_ptr c, uint16_t command, uint32_t flag, cons throw logic_error("player data command not implemented for version"); } player->inventory.decode_mags(c->version()); + c->language = player->inventory.language; string name_str = remove_language_marker(encode_sjis(player->disp.name)); c->channel.name = string_printf("C-%" PRIX64 " (%s)", c->id, name_str.c_str()); @@ -3663,7 +3670,7 @@ static void on_6F(shared_ptr c, uint16_t, uint32_t, const string& data) if (!l->quest) { throw runtime_error("JOINABLE_QUEST_IN_PROGRESS is set, but lobby has no quest"); } - auto vq = l->quest->version(c->quest_version(), c->language()); + auto vq = l->quest->version(c->quest_version(), c->language); if (!vq) { throw runtime_error("JOINABLE_QUEST_IN_PROGRESS is set, but lobby has no quest for client version"); } @@ -3685,7 +3692,7 @@ static void on_6F(shared_ptr c, uint16_t, uint32_t, const string& data) } else if (watched_lobby && watched_lobby->ep3_server) { if (!watched_lobby->ep3_server->battle_finished) { watched_lobby->ep3_server->send_commands_for_joining_spectator( - c->channel, c->language(), c->flags & Client::Flag::IS_EP3_TRIAL_EDITION); + c->channel, c->language, c->flags & Client::Flag::IS_EP3_TRIAL_EDITION); } send_ep3_update_game_metadata(watched_lobby); } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index b8b5af26..7bc46cb6 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -1279,7 +1279,7 @@ void send_quest_menu_t( auto v = c->quest_version(); vector entries; for (const auto& quest : quests) { - auto vq = quest->version(v, c->language()); + auto vq = quest->version(v, c->language); if (!vq) { continue; } @@ -2390,7 +2390,7 @@ void send_ep3_tournament_details( shared_ptr tourn) { S_TournamentGameDetails_GC_Ep3_E3 cmd; cmd.name = tourn->get_name(); - cmd.map_name = tourn->get_map()->version(c->language())->map->name; + cmd.map_name = tourn->get_map()->version(c->language)->map->name; cmd.rules = tourn->get_rules(); const auto& teams = tourn->all_teams(); for (size_t z = 0; z < min(teams.size(), 0x20); z++) { @@ -2431,7 +2431,7 @@ void send_ep3_game_details(shared_ptr c, shared_ptr l) { S_TournamentGameDetails_GC_Ep3_E3 cmd; cmd.name = encode_sjis(l->name); - cmd.map_name = tourn->get_map()->version(c->language())->map->name; + cmd.map_name = tourn->get_map()->version(c->language)->map->name; cmd.rules = tourn->get_rules(); const auto& teams = tourn->all_teams();