rewrite quest disassembler

This commit is contained in:
Martin Michelsen
2025-11-24 01:03:24 -08:00
parent 474ad99396
commit 566de06fd1
4 changed files with 824 additions and 574 deletions
+12 -4
View File
@@ -1595,7 +1595,7 @@ Action a_check_quest_opcodes(
}); });
Action a_disassemble_quest_script( Action a_disassemble_quest_script(
"disassemble-quest-script", "\ "disassemble-quest-script", "\
disassemble-quest-script [INPUT-FILENAME [OUTPUT-FILENAME]]\n\ disassemble-quest-script [OPTIONS] [INPUT-FILENAME [OUTPUT-FILENAME]]\n\
Disassemble the input quest script (.bin file) into a text representation\n\ Disassemble the input quest script (.bin file) into a text representation\n\
of the commands and metadata it contains. Specify the quest\'s game version\n\ of the commands and metadata it contains. Specify the quest\'s game version\n\
with one of the --dc-nte, --dc-v1, --dc-v2, --pc, --gc-nte, --gc, --gc-ep3,\n\ with one of the --dc-nte, --dc-v1, --dc-v2, --pc, --gc-nte, --gc, --gc-ep3,\n\
@@ -1603,17 +1603,25 @@ Action a_disassemble_quest_script(
default; the --qedit option will result in names matching those used by\n\ default; the --qedit option will result in names matching those used by\n\
QEdit. If you intend to reassemble the script, after editing it, use the\n\ QEdit. If you intend to reassemble the script, after editing it, use the\n\
--reassembly option to add explicit label numbers and remove offsets and\n\ --reassembly option to add explicit label numbers and remove offsets and\n\
data in code sections.\n", data in code sections. To include script references from the map, use the\n\
--map-file=FILENAME option.",
+[](phosg::Arguments& args) { +[](phosg::Arguments& args) {
string data = read_input_data(args); string data = read_input_data(args);
auto version = get_cli_version(args); auto version = get_cli_version(args);
if (!args.get<bool>("decompressed")) { if (!args.get<bool>("decompressed")) {
data = prs_decompress(data); data = prs_decompress(data);
} }
Language override_language = static_cast<Language>(args.get<uint8_t>("language", 0xFF)); shared_ptr<MapFile> map_file;
string map_filename = args.get<string>("map-file", false);
if (!map_filename.empty()) {
auto map_data = make_shared<string>(prs_decompress(phosg::load_file(map_filename)));
map_file = make_shared<MapFile>(map_data);
}
Language language = static_cast<Language>(args.get<uint8_t>("language", 0xFF));
bool reassembly_mode = args.get<bool>("reassembly"); bool reassembly_mode = args.get<bool>("reassembly");
bool use_qedit_names = args.get<bool>("qedit"); bool use_qedit_names = args.get<bool>("qedit");
string result = disassemble_quest_script(data.data(), data.size(), version, override_language, reassembly_mode, use_qedit_names); string result = disassemble_quest_script(
data.data(), data.size(), version, language, map_file, reassembly_mode, use_qedit_names);
write_output_data(args, result.data(), result.size(), "txt"); write_output_data(args, result.data(), result.size(), "txt");
}); });
Action a_disassemble_quest_map( Action a_disassemble_quest_map(
-9
View File
@@ -1338,15 +1338,6 @@ static asio::awaitable<HandlerResult> S_13_A7(shared_ptr<Client> c, Channel::Mes
sf->data = decode_dlq_data(sf->data); sf->data = decode_dlq_data(sf->data);
} }
phosg::save_file(sf->output_filename, sf->data); phosg::save_file(sf->output_filename, sf->data);
if (sf->basename.ends_with(".bin")) {
try {
string decompressed = prs_decompress(sf->data);
auto disassembly = disassemble_quest_script(decompressed.data(), decompressed.size(), c->version(), c->language(), false);
phosg::save_file(sf->output_filename + ".txt", disassembly);
} catch (const exception& e) {
c->log.warning_f("Failed to disassemble quest file: {}", e.what());
}
}
} else { } else {
c->log.info_f("Download complete for file {}", sf->basename); c->log.info_f("Download complete for file {}", sf->basename);
} }
+802 -552
View File
File diff suppressed because it is too large Load Diff
+10 -9
View File
@@ -12,7 +12,7 @@
struct PSOQuestHeaderDCNTE { struct PSOQuestHeaderDCNTE {
/* 0000 */ le_uint32_t code_offset = 0; /* 0000 */ le_uint32_t code_offset = 0;
/* 0004 */ le_uint32_t function_table_offset = 0; /* 0004 */ le_uint32_t label_table_offset = 0;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -22,7 +22,7 @@ struct PSOQuestHeaderDCNTE {
struct PSOQuestHeaderDC112000 { struct PSOQuestHeaderDC112000 {
/* 0000 */ le_uint32_t code_offset = 0; /* 0000 */ le_uint32_t code_offset = 0;
/* 0004 */ le_uint32_t function_table_offset = 0; /* 0004 */ le_uint32_t label_table_offset = 0;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -34,7 +34,7 @@ struct PSOQuestHeaderDC112000 {
struct PSOQuestHeaderDC { // Same format for DC v1 and v2 struct PSOQuestHeaderDC { // Same format for DC v1 and v2
/* 0000 */ le_uint32_t code_offset = 0; /* 0000 */ le_uint32_t code_offset = 0;
/* 0004 */ le_uint32_t function_table_offset = 0; /* 0004 */ le_uint32_t label_table_offset = 0;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -49,7 +49,7 @@ struct PSOQuestHeaderDC { // Same format for DC v1 and v2
struct PSOQuestHeaderPC { struct PSOQuestHeaderPC {
/* 0000 */ le_uint32_t code_offset; /* 0000 */ le_uint32_t code_offset;
/* 0004 */ le_uint32_t function_table_offset; /* 0004 */ le_uint32_t label_table_offset;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -66,7 +66,7 @@ struct PSOQuestHeaderPC {
// separate struct; if so, rename this struct to V3. // separate struct; if so, rename this struct to V3.
struct PSOQuestHeaderGC { struct PSOQuestHeaderGC {
/* 0000 */ le_uint32_t code_offset = 0; /* 0000 */ le_uint32_t code_offset = 0;
/* 0004 */ le_uint32_t function_table_offset = 0; /* 0004 */ le_uint32_t label_table_offset = 0;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -99,7 +99,7 @@ struct CreateItemMaskEntry {
struct PSOQuestHeaderBBBase { struct PSOQuestHeaderBBBase {
/* 0000 */ le_uint32_t code_offset = 0; /* 0000 */ le_uint32_t code_offset = 0;
/* 0004 */ le_uint32_t function_table_offset = 0; /* 0004 */ le_uint32_t label_table_offset = 0;
/* 0008 */ le_uint32_t size = 0; /* 0008 */ le_uint32_t size = 0;
/* 000C */ le_uint16_t unknown_a1 = 0; /* 000C */ le_uint16_t unknown_a1 = 0;
/* 000E */ le_uint16_t unknown_a2 = 0; /* 000E */ le_uint16_t unknown_a2 = 0;
@@ -126,10 +126,11 @@ void check_opcode_definitions();
Episode episode_for_quest_episode_number(uint8_t episode_number); Episode episode_for_quest_episode_number(uint8_t episode_number);
std::string disassemble_quest_script( std::string disassemble_quest_script(
const void* data, const void* bin_data, // Must not be null
size_t size, size_t bin_size,
Version version, Version version,
Language override_language = Language::UNKNOWN, Language language = Language::UNKNOWN,
std::shared_ptr<const MapFile> dat = nullptr,
bool reassembly_mode = false, bool reassembly_mode = false,
bool use_qedit_names = false); bool use_qedit_names = false);