add tests for quest indexes and function compiler

This commit is contained in:
Martin Michelsen
2025-10-21 22:52:35 -07:00
parent 790363adb5
commit be4c7f80cb
11 changed files with 66 additions and 17 deletions
+10 -3
View File
@@ -218,7 +218,8 @@ static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
const string& function_directory, const string& function_directory,
const string& system_directory, const string& system_directory,
const string& name, const string& name,
const string& text) { const string& text,
bool raise_on_any_failure) {
unordered_set<string> get_include_stack; unordered_set<string> get_include_stack;
function<string(const string&)> get_include = [&](const string& name) -> string { function<string(const string&)> get_include = [&](const string& name) -> string {
const char* arch_name_token; const char* arch_name_token;
@@ -335,6 +336,9 @@ static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
} catch (const exception& e) { } catch (const exception& e) {
string version_str = specific_version ? (" (" + str_for_specific_version(specific_version) + ")") : ""; string version_str = specific_version ? (" (" + str_for_specific_version(specific_version) + ")") : "";
if (raise_on_any_failure) {
throw;
}
function_compiler_log.warning_f("Failed to compile function {}{}: {}", name, version_str, e.what()); function_compiler_log.warning_f("Failed to compile function {}{}: {}", name, version_str, e.what());
} }
} }
@@ -342,7 +346,7 @@ static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
return ret; return ret;
} }
FunctionCodeIndex::FunctionCodeIndex(const string& directory) { FunctionCodeIndex::FunctionCodeIndex(const string& directory, bool raise_on_any_failure) {
string system_dir_path = directory.ends_with("/") ? (directory + "System") : (directory + "/System"); string system_dir_path = directory.ends_with("/") ? (directory + "System") : (directory + "/System");
uint32_t next_menu_item_id = 1; uint32_t next_menu_item_id = 1;
@@ -404,7 +408,7 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
string path = subdir_path + "/" + filename; string path = subdir_path + "/" + filename;
string text = phosg::load_file(path); string text = phosg::load_file(path);
for (auto code : compile_function_code(arch, subdir_path, system_dir_path, name, text)) { for (auto code : compile_function_code(arch, subdir_path, system_dir_path, name, text, raise_on_any_failure)) {
if (code->specific_version == 0) { if (code->specific_version == 0) {
code->specific_version = specific_version; code->specific_version = specific_version;
} }
@@ -425,6 +429,9 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
} }
} catch (const exception& e) { } catch (const exception& e) {
if (raise_on_any_failure) {
throw runtime_error(format("({}) {}", filename, e.what()));
}
function_compiler_log.warning_f("Failed to compile function {}: {}", filename, e.what()); function_compiler_log.warning_f("Failed to compile function {}: {}", filename, e.what());
} }
}; };
+1 -1
View File
@@ -54,7 +54,7 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch);
struct FunctionCodeIndex { struct FunctionCodeIndex {
FunctionCodeIndex() = default; FunctionCodeIndex() = default;
explicit FunctionCodeIndex(const std::string& directory); FunctionCodeIndex(const std::string& directory, bool raise_on_any_failure);
std::unordered_map<std::string, std::shared_ptr<CompiledFunctionCode>> name_to_function; std::unordered_map<std::string, std::shared_ptr<CompiledFunctionCode>> name_to_function;
std::unordered_map<uint8_t, std::shared_ptr<CompiledFunctionCode>> index_to_function; std::unordered_map<uint8_t, std::shared_ptr<CompiledFunctionCode>> index_to_function;
+11 -2
View File
@@ -1720,7 +1720,7 @@ Action a_assemble_all_patches(
versions, and one encrypted, for PSO GC JP v1.4, JP Ep3, and Ep3 Trial\n\ versions, and one encrypted, for PSO GC JP v1.4, JP Ep3, and Ep3 Trial\n\
Edition). The output files are saved in system/client-functions.\n", Edition). The output files are saved in system/client-functions.\n",
+[](phosg::Arguments& args) { +[](phosg::Arguments& args) {
auto fci = make_shared<FunctionCodeIndex>("system/client-functions"); auto fci = make_shared<FunctionCodeIndex>("system/client-functions", false);
bool skip_encrypted = args.get<bool>("skip-encrypted"); bool skip_encrypted = args.get<bool>("skip-encrypted");
auto process_code = [&](shared_ptr<const CompiledFunctionCode> code, auto process_code = [&](shared_ptr<const CompiledFunctionCode> code,
@@ -3038,7 +3038,16 @@ Action a_check_quests(
s->load_patch_indexes(); s->load_patch_indexes();
s->load_set_data_tables(); s->load_set_data_tables();
s->load_maps(); s->load_maps();
s->load_quest_index(); s->load_quest_index(true);
phosg::fwrite_fmt(stdout, "All quests indexed\n");
});
Action a_check_client_functions(
"check-client-functions", nullptr,
+[](phosg::Arguments&) {
set_all_log_levels(phosg::LogLevel::L_DEBUG);
FunctionCodeIndex fci("system/client-functions", true);
phosg::fwrite_fmt(stdout, "All client functions compiled\n");
}); });
Action a_parse_object_graph( Action a_parse_object_graph(
+8 -1
View File
@@ -436,7 +436,8 @@ QuestIndex::QuestIndex(
const string& directory, const string& directory,
shared_ptr<const QuestCategoryIndex> category_index, shared_ptr<const QuestCategoryIndex> category_index,
const unordered_map<string, shared_ptr<const CommonItemSet>>& common_item_sets, const unordered_map<string, shared_ptr<const CommonItemSet>>& common_item_sets,
const unordered_map<string, shared_ptr<const RareItemSet>>& rare_item_sets) const unordered_map<string, shared_ptr<const RareItemSet>>& rare_item_sets,
bool raise_on_any_failure)
: directory(directory), : directory(directory),
category_index(category_index) { category_index(category_index) {
@@ -585,6 +586,9 @@ QuestIndex::QuestIndex(
} }
} catch (const exception& e) { } catch (const exception& e) {
if (raise_on_any_failure) {
throw runtime_error(format("({}) {}", filename, e.what()));
}
static_game_data_log.warning_f("({}) Failed to load quest file: ({})", filename, e.what()); static_game_data_log.warning_f("({}) Failed to load quest file: ({})", filename, e.what());
} }
} }
@@ -803,6 +807,9 @@ QuestIndex::QuestIndex(
vq->meta.joinable ? "joinable" : "not joinable"); vq->meta.joinable ? "joinable" : "not joinable");
} }
} catch (const exception& e) { } catch (const exception& e) {
if (raise_on_any_failure) {
throw runtime_error(format("({}) {}", basename, e.what()));
}
static_game_data_log.warning_f("({}) Failed to index quest file: {}", basename, e.what()); static_game_data_log.warning_f("({}) Failed to index quest file: {}", basename, e.what());
} }
} }
+2 -1
View File
@@ -136,7 +136,8 @@ struct QuestIndex {
const std::string& directory, const std::string& directory,
std::shared_ptr<const QuestCategoryIndex> category_index, std::shared_ptr<const QuestCategoryIndex> category_index,
const std::unordered_map<std::string, std::shared_ptr<const CommonItemSet>>& common_item_sets, const std::unordered_map<std::string, std::shared_ptr<const CommonItemSet>>& common_item_sets,
const std::unordered_map<std::string, std::shared_ptr<const RareItemSet>>& rare_item_sets); const std::unordered_map<std::string, std::shared_ptr<const RareItemSet>>& rare_item_sets,
bool raise_on_any_failure);
phosg::JSON json() const; phosg::JSON json() const;
std::shared_ptr<const Quest> get(uint32_t quest_number) const; std::shared_ptr<const Quest> get(uint32_t quest_number) const;
+7 -2
View File
@@ -4019,7 +4019,7 @@ AssembledQuestScript assemble_quest_script(
wrap_exceptions_with_line_ref(line, [&]() -> void { wrap_exceptions_with_line_ref(line, [&]() -> void {
if (line.text[0] == '.') { if (line.text[0] == '.') {
if (line.text.starts_with(".include ")) { if (line.text.starts_with(".include ")) {
// Nothing to do // Nothing to do (see above)
} else if (line.text.starts_with(".version ")) { } else if (line.text.starts_with(".version ")) {
string name = line.text.substr(9); string name = line.text.substr(9);
phosg::strip_leading_whitespace(name); phosg::strip_leading_whitespace(name);
@@ -4268,7 +4268,12 @@ AssembledQuestScript assemble_quest_script(
} }
auto line_tokens = phosg::split(line.text, ' ', 1); auto line_tokens = phosg::split(line.text, ' ', 1);
const auto& opcode_def = opcodes.at(phosg::tolower(line_tokens.at(0))); const QuestScriptOpcodeDefinition* opcode_def;
try {
opcode_def = opcodes.at(phosg::tolower(line_tokens.at(0)));
} catch (const out_of_range&) {
throw std::runtime_error(std::format("invalid opcode name: {}", line_tokens.at(0)));
}
bool use_args = version_has_args && (opcode_def->flags & F_ARGS); bool use_args = version_has_args && (opcode_def->flags & F_ARGS);
if (!use_args) { if (!use_args) {
+4 -4
View File
@@ -2161,15 +2161,15 @@ void ServerState::load_ep3_tournament_state() {
this->ep3_tournament_index->link_all_clients(this->shared_from_this()); this->ep3_tournament_index->link_all_clients(this->shared_from_this());
} }
void ServerState::load_quest_index() { void ServerState::load_quest_index(bool raise_on_any_failure) {
config_log.info_f("Collecting quests"); config_log.info_f("Collecting quests");
this->quest_index = make_shared<QuestIndex>( this->quest_index = make_shared<QuestIndex>(
"system/quests", this->quest_category_index, this->common_item_sets, this->rare_item_sets); "system/quests", this->quest_category_index, this->common_item_sets, this->rare_item_sets, raise_on_any_failure);
} }
void ServerState::compile_functions() { void ServerState::compile_functions(bool raise_on_any_failure) {
config_log.info_f("Compiling client functions"); config_log.info_f("Compiling client functions");
this->function_code_index = make_shared<FunctionCodeIndex>("system/client-functions"); this->function_code_index = make_shared<FunctionCodeIndex>("system/client-functions", raise_on_any_failure);
} }
void ServerState::load_dol_files() { void ServerState::load_dol_files() {
+2 -2
View File
@@ -440,8 +440,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
void load_ep3_cards(); void load_ep3_cards();
void load_ep3_maps(); void load_ep3_maps();
void load_ep3_tournament_state(); void load_ep3_tournament_state();
void load_quest_index(); void load_quest_index(bool raise_on_any_failure = false);
void compile_functions(); void compile_functions(bool raise_on_any_failure = false);
void load_dol_files(); void load_dol_files();
void load_all(bool enable_thread_pool); void load_all(bool enable_thread_pool);
@@ -14,7 +14,7 @@ start:
.data <VERS 0x802AB424 0x802AC2CC 0x802AD3F8 0x802AD1AC 0x802ABDE0 0x802ABE24 0x802AD360 0x802ACAF4> .data <VERS 0x802AB424 0x802AC2CC 0x802AD3F8 0x802AD1AC 0x802ABDE0 0x802ABE24 0x802AD360 0x802ACAF4>
.data 0x00000004 .data 0x00000004
li r4, 0xFF00 li r4, -0x100
.data <VERS 0x804A1F38 0x804A5658 0x804A7AF8 0x804A78B8 0x804A26E8 0x804A2BC8 0x804A7188 0x804A7608> .data <VERS 0x804A1F38 0x804A5658 0x804A7AF8 0x804A78B8 0x804A26E8 0x804A2BC8 0x804A7188 0x804A7608>
.data 0x0000000C .data 0x0000000C
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
set -e
EXECUTABLE="$1"
if [ -z "$EXECUTABLE" ]; then
EXECUTABLE="./newserv"
fi
$EXECUTABLE --config=tests/config.json check-client-functions
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
set -e
EXECUTABLE="$1"
if [ -z "$EXECUTABLE" ]; then
EXECUTABLE="./newserv"
fi
$EXECUTABLE --config=tests/config.json check-quests