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& system_directory,
const string& name,
const string& text) {
const string& text,
bool raise_on_any_failure) {
unordered_set<string> get_include_stack;
function<string(const string&)> get_include = [&](const string& name) -> string {
const char* arch_name_token;
@@ -335,6 +336,9 @@ static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
} catch (const exception& e) {
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());
}
}
@@ -342,7 +346,7 @@ static vector<shared_ptr<CompiledFunctionCode>> compile_function_code(
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");
uint32_t next_menu_item_id = 1;
@@ -404,7 +408,7 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
string path = subdir_path + "/" + filename;
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) {
code->specific_version = specific_version;
}
@@ -425,6 +429,9 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
}
} 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());
}
};
+1 -1
View File
@@ -54,7 +54,7 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch);
struct FunctionCodeIndex {
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<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\
Edition). The output files are saved in system/client-functions.\n",
+[](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");
auto process_code = [&](shared_ptr<const CompiledFunctionCode> code,
@@ -3038,7 +3038,16 @@ Action a_check_quests(
s->load_patch_indexes();
s->load_set_data_tables();
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(
+8 -1
View File
@@ -436,7 +436,8 @@ QuestIndex::QuestIndex(
const string& directory,
shared_ptr<const QuestCategoryIndex> category_index,
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),
category_index(category_index) {
@@ -585,6 +586,9 @@ QuestIndex::QuestIndex(
}
} 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());
}
}
@@ -803,6 +807,9 @@ QuestIndex::QuestIndex(
vq->meta.joinable ? "joinable" : "not joinable");
}
} 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());
}
}
+2 -1
View File
@@ -136,7 +136,8 @@ struct QuestIndex {
const std::string& directory,
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 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;
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 {
if (line.text[0] == '.') {
if (line.text.starts_with(".include ")) {
// Nothing to do
// Nothing to do (see above)
} else if (line.text.starts_with(".version ")) {
string name = line.text.substr(9);
phosg::strip_leading_whitespace(name);
@@ -4268,7 +4268,12 @@ AssembledQuestScript assemble_quest_script(
}
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);
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());
}
void ServerState::load_quest_index() {
void ServerState::load_quest_index(bool raise_on_any_failure) {
config_log.info_f("Collecting quests");
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");
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() {
+2 -2
View File
@@ -440,8 +440,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
void load_ep3_cards();
void load_ep3_maps();
void load_ep3_tournament_state();
void load_quest_index();
void compile_functions();
void load_quest_index(bool raise_on_any_failure = false);
void compile_functions(bool raise_on_any_failure = false);
void load_dol_files();
void load_all(bool enable_thread_pool);
@@ -14,7 +14,7 @@ start:
.data <VERS 0x802AB424 0x802AC2CC 0x802AD3F8 0x802AD1AC 0x802ABDE0 0x802ABE24 0x802AD360 0x802ACAF4>
.data 0x00000004
li r4, 0xFF00
li r4, -0x100
.data <VERS 0x804A1F38 0x804A5658 0x804A7AF8 0x804A78B8 0x804A26E8 0x804A2BC8 0x804A7188 0x804A7608>
.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