diff --git a/src/ServerShell.cc b/src/ServerShell.cc index 47d2e8c3..fb52aa87 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -120,7 +120,7 @@ Server commands:\n\ quests - reindex all quests\n\ functions - recompile all client-side functions\n\ dol-files - reindex all DOL files\n\ - config - reload some fields from config.json\n\ + config - reload most fields from config.json\n\ Reloading will not affect items that are in use; for example, if an Episode\n\ 3 battle is in progress, it will continue to use the previous map and card\n\ definitions. Similarly, BB clients are not forced to disconnect or reload\n\ @@ -287,6 +287,10 @@ Proxy session commands:\n\ auto config_json = this->state->load_config(); this->state->load_dol_files(); this->state->create_menus(config_json); + } else if (type == "config") { + auto config_json = this->state->load_config(); + this->state->parse_config(config_json, true); + this->state->resolve_ep3_card_auction_pool(); } else { throw invalid_argument("incorrect data type"); } diff --git a/src/ServerState.cc b/src/ServerState.cc index 2f455fe3..308159b5 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -85,13 +85,15 @@ ServerState::ServerState(const char* config_filename, bool is_replay) // Load all the necessary data auto config = this->load_config(); this->collect_network_addresses(); - this->parse_config(config); + this->parse_config(config, false); + this->load_bb_private_keys(); this->load_licenses(); this->load_patch_indexes(); this->load_battle_params(); this->load_level_table(); this->load_item_tables(); this->load_ep3_data(); + this->resolve_ep3_card_auction_pool(); this->load_quest_index(); this->compile_functions(); this->load_dol_files(); @@ -566,24 +568,33 @@ static vector parse_port_configuration(const JSON& json) { return ret; } -void ServerState::parse_config(const JSON& json) { +void ServerState::parse_config(const JSON& json, bool is_reload) { config_log.info("Parsing configuration"); this->name = decode_sjis(json.at("ServerName").as_string()); - try { - this->username = json.at("User").as_string(); - if (this->username == "$SUDO_USER") { - const char* user_from_env = getenv("SUDO_USER"); - if (!user_from_env) { - throw runtime_error("configuration specifies $SUDO_USER, but variable is not defined"); + if (!is_reload) { + try { + this->username = json.at("User").as_string(); + if (this->username == "$SUDO_USER") { + const char* user_from_env = getenv("SUDO_USER"); + if (!user_from_env) { + throw runtime_error("configuration specifies $SUDO_USER, but variable is not defined"); + } + this->username = user_from_env; } - this->username = user_from_env; + } catch (const out_of_range&) { } - } catch (const out_of_range&) { - } - this->set_port_configuration(parse_port_configuration(json.at("PortConfiguration"))); + this->set_port_configuration(parse_port_configuration(json.at("PortConfiguration"))); + this->dns_server_port = json.get_int("DNSServerPort", this->dns_server_port); + try { + for (const auto& item : json.at("IPStackListen").as_list()) { + this->ip_stack_addresses.emplace_back(item->as_string()); + } + } catch (const out_of_range&) { + } + } auto local_address_str = json.at("LocalAddress").as_string(); try { @@ -595,6 +606,7 @@ void ServerState::parse_config(const JSON& json) { this->local_address = address_for_string(local_address_str.c_str()); config_log.info("Added local address: %s", local_address_str.c_str()); } + this->all_addresses.erase(""); this->all_addresses.emplace("", this->local_address); auto external_address_str = json.at("ExternalAddress").as_string(); @@ -607,16 +619,9 @@ void ServerState::parse_config(const JSON& json) { this->external_address = address_for_string(external_address_str.c_str()); config_log.info("Added external address: %s", external_address_str.c_str()); } + this->all_addresses.erase(""); this->all_addresses.emplace("", this->external_address); - this->dns_server_port = json.get_int("DNSServerPort", this->dns_server_port); - - try { - for (const auto& item : json.at("IPStackListen").as_list()) { - this->ip_stack_addresses.emplace_back(item->as_string()); - } - } catch (const out_of_range&) { - } this->ip_stack_debug = json.get_bool("IPStackDebug", this->ip_stack_debug); this->allow_unregistered_users = json.get_bool("AllowUnregisteredUsers", this->allow_unregistered_users); this->item_tracking_enabled = json.get_bool("EnableItemTracking", this->item_tracking_enabled); @@ -702,21 +707,13 @@ void ServerState::parse_config(const JSON& json) { set_log_levels_from_json(json.get("LogLevels", JSON::dict())); - for (const string& filename : list_directory("system/blueburst/keys")) { - if (!ends_with(filename, ".nsk")) { - continue; + if (!is_reload) { + try { + this->run_shell_behavior = json.at("RunInteractiveShell").as_bool() + ? ServerState::RunShellBehavior::ALWAYS + : ServerState::RunShellBehavior::NEVER; + } catch (const out_of_range&) { } - this->bb_private_keys.emplace_back(new PSOBBEncryption::KeyFile( - load_object_file("system/blueburst/keys/" + filename))); - config_log.info("Loaded Blue Burst key file: %s", filename.c_str()); - } - config_log.info("%zu Blue Burst key file(s) loaded", this->bb_private_keys.size()); - - try { - this->run_shell_behavior = json.at("RunInteractiveShell").as_bool() - ? ServerState::RunShellBehavior::ALWAYS - : ServerState::RunShellBehavior::NEVER; - } catch (const out_of_range&) { } try { @@ -745,14 +742,28 @@ void ServerState::parse_config(const JSON& json) { this->ep3_menu_song = json.get_int("Episode3MenuSong", this->ep3_menu_song); - try { - this->quest_category_index.reset(new QuestCategoryIndex(json.at("QuestCategories"))); - } catch (const exception& e) { - throw runtime_error(string_printf( - "QuestCategories is missing or invalid in config.json (%s) - see config.example.json for an example", e.what())); + if (!is_reload) { + try { + this->quest_category_index.reset(new QuestCategoryIndex(json.at("QuestCategories"))); + } catch (const exception& e) { + throw runtime_error(string_printf( + "QuestCategories is missing or invalid in config.json (%s) - see config.example.json for an example", e.what())); + } } } +void ServerState::load_bb_private_keys() { + for (const string& filename : list_directory("system/blueburst/keys")) { + if (!ends_with(filename, ".nsk")) { + continue; + } + this->bb_private_keys.emplace_back(new PSOBBEncryption::KeyFile( + load_object_file("system/blueburst/keys/" + filename))); + config_log.info("Loaded Blue Burst key file: %s", filename.c_str()); + } + config_log.info("%zu Blue Burst key file(s) loaded", this->bb_private_keys.size()); +} + void ServerState::load_licenses() { config_log.info("Loading license list"); this->license_manager.reset(new LicenseManager("system/licenses.nsi")); @@ -872,7 +883,9 @@ void ServerState::load_ep3_data() { this->ep3_tournament_index.reset(new Episode3::TournamentIndex( this->ep3_map_index, this->ep3_com_deck_index, tournament_state_filename)); config_log.info("Loaded Episode 3 tournament state"); +} +void ServerState::resolve_ep3_card_auction_pool() { config_log.info("Resolving Episode 3 card auction pool"); for (auto& e : this->ep3_card_auction_pool) { try { diff --git a/src/ServerState.hh b/src/ServerState.hh index 1558c1b5..c423a882 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -187,13 +187,15 @@ struct ServerState { JSON load_config() const; void collect_network_addresses(); - void parse_config(const JSON& config_json); + void parse_config(const JSON& config_json, bool is_reload); + void load_bb_private_keys(); void load_licenses(); void load_patch_indexes(); void load_battle_params(); void load_level_table(); void load_item_tables(); void load_ep3_data(); + void resolve_ep3_card_auction_pool(); void load_quest_index(); void compile_functions(); void load_dol_files();