diff --git a/src/FunctionCompiler.cc b/src/FunctionCompiler.cc index 2ed9b299..7a45037a 100644 --- a/src/FunctionCompiler.cc +++ b/src/FunctionCompiler.cc @@ -223,6 +223,7 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) { } } code->specific_version = specific_version; + code->source_path = path; code->short_name = short_name; this->name_to_function.emplace(name, code); if (is_patch) { diff --git a/src/FunctionCompiler.hh b/src/FunctionCompiler.hh index 85571b34..8332094a 100644 --- a/src/FunctionCompiler.hh +++ b/src/FunctionCompiler.hh @@ -27,6 +27,7 @@ struct CompiledFunctionCode { std::vector relocation_deltas; std::unordered_map label_offsets; uint32_t entrypoint_offset_offset; + std::string source_path; // Path to source file from newserv root std::string short_name; // Based on filename std::string long_name; // From .meta name directive std::string description; // From .meta description directive diff --git a/src/Main.cc b/src/Main.cc index 7681b705..93da7a75 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -31,6 +31,7 @@ #include "Loggers.hh" #include "NetworkAddresses.hh" #include "PSOGCObjectGraph.hh" +#include "PSOProtocol.hh" #include "ProxyServer.hh" #include "Quest.hh" #include "QuestScript.hh" @@ -1092,6 +1093,49 @@ Action a_assemble_quest_script( write_output_data(args, result.data(), result.size(), compress ? "bin" : "bind"); }); +Action a_assemble_all_patches( + "assemble-all-patches", "\ + assemble-all-patches\n\ + Assemble all patches in the system/ppc directory, and produce two compiled\n\ + .bin files for each patch (one unencrypted, for most PSO versions, and one\n\ + encrypted, for PSO JP v1.04, JP Ep3, and Ep3 Trial Edition). The output\n\ + files are written to the system/ppc directory.\n", + +[](Arguments&) { + ServerState s; + s.load_objects_and_upstream_dependents("functions"); + + auto process_code = +[](shared_ptr code, + uint32_t checksum_addr, + uint32_t checksum_size, + uint32_t override_start_addr) -> void { + for (uint8_t encrypted = 0; encrypted < 2; encrypted++) { + StringWriter w; + string data = prepare_send_function_call_data(code, {}, "", checksum_addr, checksum_size, override_start_addr, encrypted); + w.put(PSOCommandHeaderDCV3{.command = 0xB2, .flag = code->index, .size = data.size() + 4}); + w.write(data); + string out_path = code->source_path + (encrypted ? ".enc.bin" : ".std.bin"); + save_file(out_path, w.str()); + fprintf(stderr, "... %s\n", out_path.c_str()); + } + }; + + for (const auto& it : s.function_code_index->name_and_specific_version_to_patch_function) { + process_code(it.second, 0, 0, 0); + } + try { + process_code(s.function_code_index->name_to_function.at("VersionDetect"), 0, 0, 0); + } catch (const out_of_range&) { + } + try { + process_code(s.function_code_index->name_to_function.at("CacheClearFix-Phase1"), 0x80000000, 8, 0x7F2734EC); + } catch (const out_of_range&) { + } + try { + process_code(s.function_code_index->name_to_function.at("CacheClearFix-Phase2"), 0, 0, 0); + } catch (const out_of_range&) { + } + }); + void a_extract_archive_fn(Arguments& args) { string output_prefix = args.get(2, false); if (output_prefix == "-") { diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 8aa74124..a5928585 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -402,48 +402,19 @@ void prepare_client_for_patches(shared_ptr c, function on_comple } } -void send_function_call( - shared_ptr c, - shared_ptr code, +string prepare_send_function_call_data( + shared_ptr code, const unordered_map& label_writes, const string& suffix, uint32_t checksum_addr, uint32_t checksum_size, - uint32_t override_relocations_offset) { - return send_function_call( - c->channel, - c->config, - code, - label_writes, - suffix, - checksum_addr, - checksum_size, - override_relocations_offset); -} - -void send_function_call( - Channel& ch, - const Client::Config& client_config, - shared_ptr code, - const unordered_map& label_writes, - const string& suffix, - uint32_t checksum_addr, - uint32_t checksum_size, - uint32_t override_relocations_offset) { - if (client_config.check_flag(Client::Flag::NO_SEND_FUNCTION_CALL)) { - throw logic_error("client does not support function calls"); - } - if (code.get() && client_config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) { - throw logic_error("client only supports checksums in send_function_call"); - } - + uint32_t override_relocations_offset, + bool use_encrypted_format) { string data; - uint32_t index = 0; if (code.get()) { data = code->generate_client_command(label_writes, suffix, override_relocations_offset); - index = code->index; - if (client_config.check_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL)) { + if (use_encrypted_format) { uint32_t key = random_object(); // This format was probably never used on any little-endian system, but we @@ -473,13 +444,52 @@ void send_function_call( } } - S_ExecuteCode_B2 header = {data.size(), checksum_addr, checksum_size}; - StringWriter w; - w.put(header); + w.put(S_ExecuteCode_B2{data.size(), checksum_addr, checksum_size}); w.write(data); + return std::move(w.str()); +} - ch.send(0xB2, index, w.str()); +void send_function_call( + shared_ptr c, + shared_ptr code, + const unordered_map& label_writes, + const string& suffix, + uint32_t checksum_addr, + uint32_t checksum_size, + uint32_t override_relocations_offset) { + return send_function_call( + c->channel, + c->config, + code, + label_writes, + suffix, + checksum_addr, + checksum_size, + override_relocations_offset); +} + +void send_function_call( + Channel& ch, + const Client::Config& client_config, + shared_ptr code, + const unordered_map& label_writes, + const string& suffix, + uint32_t checksum_addr, + uint32_t checksum_size, + uint32_t override_relocations_offset) { + if (client_config.check_flag(Client::Flag::NO_SEND_FUNCTION_CALL)) { + throw logic_error("client does not support function calls"); + } + if (code.get() && client_config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) { + throw logic_error("client only supports checksums in send_function_call"); + } + + string data = prepare_send_function_call_data( + code, label_writes, suffix, checksum_addr, checksum_size, override_relocations_offset, + client_config.check_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL)); + + ch.send(0xB2, code ? code->index : 0x00, data); } void send_reconnect(shared_ptr c, uint32_t address, uint16_t port) { diff --git a/src/SendCommands.hh b/src/SendCommands.hh index a24b00f1..282a7604 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -134,10 +134,18 @@ void empty_function_call_response_handler(uint32_t, uint32_t); void send_quest_buffer_overflow(std::shared_ptr c); void prepare_client_for_patches(std::shared_ptr c, std::function on_complete); +std::string prepare_send_function_call_data( + std::shared_ptr code, + const std::unordered_map& label_writes, + const std::string& suffix, + uint32_t checksum_addr, + uint32_t checksum_size, + uint32_t override_relocations_offset, + bool use_encrypted_format); void send_function_call( Channel& ch, const Client::Config& client_config, - std::shared_ptr code, + std::shared_ptr code, const std::unordered_map& label_writes = {}, const std::string& suffix = "", uint32_t checksum_addr = 0, @@ -145,7 +153,7 @@ void send_function_call( uint32_t override_relocations_offset = 0); void send_function_call( std::shared_ptr c, - std::shared_ptr code, + std::shared_ptr code, const std::unordered_map& label_writes = {}, const std::string& suffix = "", uint32_t checksum_addr = 0,