From 36eeee5641922b2265cc4851290dc5c10a6e875d Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Wed, 5 Nov 2025 22:29:43 -0800 Subject: [PATCH] clean up character load function --- src/ChatCommands.cc | 2 +- src/Client.cc | 176 ++++++++++++++++++++++------------------- src/Client.hh | 2 +- src/ReceiveCommands.cc | 8 +- 4 files changed, 99 insertions(+), 89 deletions(-) diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 20c3cd1d..69fb109f 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -2752,7 +2752,7 @@ ChatCommandDefinition cc_switchchar( throw precondition_failed("No character exists\nin that slot"); } - a.c->save_and_unload_character(); + a.c->unload_character(true); a.c->bb_character_index = index; a.c->bb_bank_character_index = index; diff --git a/src/Client.cc b/src/Client.cc index 4d28626d..3313cef5 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -563,6 +563,9 @@ shared_ptr Client::character_file(bool allow_load, bool allo throw runtime_error("character index not specified"); } this->load_all_files(); + if (!this->character_data) { + throw std::runtime_error("none of the corresponding character files exist"); + } } return this->character_data; } @@ -871,20 +874,17 @@ void Client::load_all_files() { throw logic_error("cannot load BB player data until client is logged in"); } - this->system_data.reset(); - this->character_data.reset(); - this->guild_card_data.reset(); - this->bank_data.reset(); - - string sys_filename = this->system_filename(); - if (std::filesystem::is_regular_file(sys_filename)) { - this->system_data = make_shared(phosg::load_object_file(sys_filename, true)); - this->log.info_f("Loaded system data from {}", sys_filename); - } else { - this->log.info_f("System file is missing: {}", sys_filename); + if (!this->system_data) { + string sys_filename = this->system_filename(); + if (std::filesystem::is_regular_file(sys_filename)) { + this->system_data = make_shared(phosg::load_object_file(sys_filename, true)); + this->log.info_f("Loaded system data from {}", sys_filename); + } else { + this->log.info_f("System file is missing: {}", sys_filename); + } } - if (this->bb_character_index >= 0) { + if (!this->character_data && (this->bb_character_index >= 0)) { string char_filename = this->character_filename(); if (std::filesystem::is_regular_file(char_filename)) { auto psochar = PSOCHARFile::load_shared(char_filename, !this->system_data); @@ -909,15 +909,18 @@ void Client::load_all_files() { } } - string card_filename = this->guild_card_filename(); - if (std::filesystem::is_regular_file(card_filename)) { - this->guild_card_data = make_shared(phosg::load_object_file(card_filename)); - this->log.info_f("Loaded Guild Card data from {}", card_filename); - } else { - this->log.info_f("Guild Card file is missing: {}", card_filename); + if (!this->guild_card_data) { + string card_filename = this->guild_card_filename(); + if (std::filesystem::is_regular_file(card_filename)) { + this->guild_card_data = make_shared(phosg::load_object_file(card_filename)); + this->log.info_f("Loaded Guild Card data from {}", card_filename); + } else { + this->log.info_f("Guild Card file is missing: {}", card_filename); + } } - // If any of the above files were missing, try to load from .nsa/.nsc files instead + // If any of the above files are still missing, try to load from .nsa/.nsc + // files instead if (!this->system_data || (!this->character_data && (this->bb_character_index >= 0)) || !this->guild_card_data) { string nsa_filename = this->legacy_account_filename(); shared_ptr nsa_data; @@ -936,75 +939,75 @@ void Client::load_all_files() { } } - if (!this->system_data) { - this->system_data = make_shared(); - auto s = this->require_server_state(); - if (s->bb_default_keyboard_config) { - this->system_data->key_config = *s->bb_default_keyboard_config; - } - if (s->bb_default_joystick_config) { - this->system_data->joystick_config = *s->bb_default_joystick_config; - } - this->log.info_f("Created new system data"); - } - if (!this->guild_card_data) { - this->guild_card_data = make_shared(); - this->log.info_f("Created new Guild Card data"); - } - if (!this->character_data && (this->bb_character_index >= 0)) { string nsc_filename = this->legacy_player_filename(); - auto nsc_data = phosg::load_object_file(nsc_filename); - if (nsc_data.signature == LegacySavedPlayerDataBB::SIGNATURE_V0) { - nsc_data.signature = LegacySavedPlayerDataBB::SIGNATURE_V0; - nsc_data.unused.clear(); - nsc_data.battle_records.place_counts.clear(0); - nsc_data.battle_records.disconnect_count = 0; - nsc_data.battle_records.unknown_a1.clear(0); - } else if (nsc_data.signature != LegacySavedPlayerDataBB::SIGNATURE_V1) { - throw runtime_error("legacy player data has incorrect signature"); - } + if (std::filesystem::is_regular_file(nsc_filename)) { + auto nsc_data = phosg::load_object_file(nsc_filename); + if (nsc_data.signature == LegacySavedPlayerDataBB::SIGNATURE_V0) { + nsc_data.signature = LegacySavedPlayerDataBB::SIGNATURE_V0; + nsc_data.unused.clear(); + nsc_data.battle_records.place_counts.clear(0); + nsc_data.battle_records.disconnect_count = 0; + nsc_data.battle_records.unknown_a1.clear(0); + } else if (nsc_data.signature != LegacySavedPlayerDataBB::SIGNATURE_V1) { + throw runtime_error("legacy player data has incorrect signature"); + } - this->character_data = make_shared(); - this->character_data->inventory = nsc_data.inventory; - this->character_data->disp = nsc_data.disp; - this->character_data->play_time_seconds = 0; - this->character_data->quest_flags = nsc_data.quest_flags; - this->character_data->death_count = nsc_data.death_count; - this->character_data->bank = nsc_data.bank; - this->character_data->guild_card.guild_card_number = this->login->account->account_id; - this->character_data->guild_card.name = nsc_data.disp.name; - this->character_data->guild_card.description = nsc_data.guild_card_description; - this->character_data->guild_card.present = 1; - this->character_data->guild_card.language = nsc_data.inventory.language; - this->character_data->guild_card.section_id = nsc_data.disp.visual.section_id; - this->character_data->guild_card.char_class = nsc_data.disp.visual.char_class; - this->character_data->auto_reply = nsc_data.auto_reply; - this->character_data->info_board = nsc_data.info_board; - this->character_data->battle_records = nsc_data.battle_records; - this->character_data->challenge_records = nsc_data.challenge_records; - this->character_data->tech_menu_shortcut_entries = nsc_data.tech_menu_shortcut_entries; - this->character_data->quest_counters = nsc_data.quest_counters; - if (nsa_data) { - this->character_data->option_flags = nsa_data->option_flags; - this->character_data->symbol_chats = nsa_data->symbol_chats; - this->character_data->shortcuts = nsa_data->shortcuts; - this->log.info_f("Loaded legacy player data from {} and {}", nsa_filename, nsc_filename); - } else { - this->log.info_f("Loaded legacy player data from {}", nsc_filename); + this->character_data = make_shared(); + this->character_data->inventory = nsc_data.inventory; + this->character_data->disp = nsc_data.disp; + this->character_data->play_time_seconds = 0; + this->character_data->quest_flags = nsc_data.quest_flags; + this->character_data->death_count = nsc_data.death_count; + this->character_data->bank = nsc_data.bank; + this->character_data->guild_card.guild_card_number = this->login->account->account_id; + this->character_data->guild_card.name = nsc_data.disp.name; + this->character_data->guild_card.description = nsc_data.guild_card_description; + this->character_data->guild_card.present = 1; + this->character_data->guild_card.language = nsc_data.inventory.language; + this->character_data->guild_card.section_id = nsc_data.disp.visual.section_id; + this->character_data->guild_card.char_class = nsc_data.disp.visual.char_class; + this->character_data->auto_reply = nsc_data.auto_reply; + this->character_data->info_board = nsc_data.info_board; + this->character_data->battle_records = nsc_data.battle_records; + this->character_data->challenge_records = nsc_data.challenge_records; + this->character_data->tech_menu_shortcut_entries = nsc_data.tech_menu_shortcut_entries; + this->character_data->quest_counters = nsc_data.quest_counters; + if (nsa_data) { + this->character_data->option_flags = nsa_data->option_flags; + this->character_data->symbol_chats = nsa_data->symbol_chats; + this->character_data->shortcuts = nsa_data->shortcuts; + this->log.info_f("Loaded legacy player data from {} and {}", nsa_filename, nsc_filename); + } else { + this->log.info_f("Loaded legacy player data from {}", nsc_filename); + } + this->update_character_data_after_load(this->character_data); } - this->update_character_data_after_load(this->character_data); } } + // The system and Guild Card files can be auto-created if they can't be + // loaded. After this, system_data and guild_card_data are always non-null, + // but character_data may still be null + if (!this->system_data) { + this->system_data = make_shared(); + auto s = this->require_server_state(); + if (s->bb_default_keyboard_config) { + this->system_data->key_config = *s->bb_default_keyboard_config; + } + if (s->bb_default_joystick_config) { + this->system_data->joystick_config = *s->bb_default_joystick_config; + } + this->log.info_f("Created new system data"); + } + if (!this->guild_card_data) { + this->guild_card_data = make_shared(); + this->log.info_f("Created new Guild Card data"); + } + auto s = this->require_server_state(); auto stack_limits = s->item_stack_limits(this->version()); - if (this->bb_character_index >= 0) { - // bank_file() loads the bank data - this->bank_file()->enforce_stack_limits(stack_limits); - } - this->blocked_senders.clear(); for (size_t z = 0; z < this->guild_card_data->blocked.size(); z++) { if (this->guild_card_data->blocked[z].present) { @@ -1015,12 +1018,15 @@ void Client::load_all_files() { if (this->character_data) { // Clear legacy play_time field this->character_data->disp.name.clear_after_bytes(0x18); - this->character_data->inventory.enforce_stack_limits(stack_limits); - this->login->account->auto_reply_message = this->character_data->auto_reply.decode(); this->login->account->save(); this->last_play_time_update = phosg::now(); + if (this->bb_character_index >= 0) { + // Note that bank_file() can't recur infinitely here because + // character_file is already set; it will not call load_all_files() again + this->bank_file()->enforce_stack_limits(stack_limits); + } } } @@ -1065,13 +1071,17 @@ shared_ptr Client::load_ep3_backup_character(u return ch; } -void Client::save_and_unload_character() { +void Client::unload_character(bool save) { if (this->character_data) { - this->save_character_file(); + if (save) { + this->save_character_file(); + } this->character_data.reset(); this->log.info_f("Unloaded character"); if (this->bank_data) { - this->save_bank_file(); + if (save) { + this->save_bank_file(); + } this->bank_data.reset(); this->log.info_f("Unloaded bank"); } diff --git a/src/Client.hh b/src/Client.hh index c18ecd05..eddb2047 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -343,7 +343,7 @@ public: void load_backup_character(uint32_t account_id, size_t index); std::shared_ptr load_ep3_backup_character(uint32_t account_id, size_t index); - void save_and_unload_character(); + void unload_character(bool save); void print_inventory() const; void print_bank() const; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 038d04e3..8297b9f9 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -3752,7 +3752,7 @@ static asio::awaitable on_E3_BB(shared_ptr c, Channel::Message& ms const auto& cmd = check_size_t(msg.data); if (c->bb_connection_phase != 0x00) { - c->save_and_unload_character(); + c->unload_character(false); c->bb_character_index = cmd.character_index; c->bb_bank_character_index = cmd.character_index; send_approve_player_choice_bb(c); @@ -3764,18 +3764,18 @@ static asio::awaitable on_E3_BB(shared_ptr c, Channel::Message& ms } auto send_preview = [&c](size_t index) -> void { - c->save_and_unload_character(); + c->unload_character(false); c->bb_character_index = index; c->bb_bank_character_index = index; try { auto preview = c->character_file()->to_preview(); send_player_preview_bb(c, c->bb_character_index, &preview); - } catch (const exception& e) { // Player doesn't exist - c->log.warning_f("Can\'t load character data: {}", e.what()); + c->log.info_f("Can\'t load character data: {}", e.what()); send_player_preview_bb(c, c->bb_character_index, nullptr); } + c->unload_character(false); }; if (msg.flag == 0) {