From 94bbd5685e7b7f8acc2a7f2ef47847a0f3bedcb8 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Thu, 2 Mar 2023 16:58:30 -0800 Subject: [PATCH] support size disparities in ReplaySession --- src/ReplaySession.cc | 118 ++++++++++++++++++++++++++----------------- src/ReplaySession.hh | 1 + 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/src/ReplaySession.cc b/src/ReplaySession.cc index fafcf4ae..be5a57bb 100644 --- a/src/ReplaySession.cc +++ b/src/ReplaySession.cc @@ -13,7 +13,11 @@ using namespace std; ReplaySession::Event::Event(Type type, uint64_t client_id, size_t line_num) - : type(type), client_id(client_id), complete(false), line_num(line_num) { } + : type(type), + client_id(client_id), + allow_size_disparity(false), + complete(false), + line_num(line_num) { } string ReplaySession::Event::str() const { string ret; @@ -26,6 +30,9 @@ string ReplaySession::Event::str() const { } else if (this->type == Type::RECEIVE) { ret = string_printf("Event[%" PRIu64 ", RECEIVE %04zX", this->client_id, this->data.size()); } + if (this->allow_size_disparity) { + ret += ", size disparity allowed"; + } if (this->complete) { ret += ", done"; } @@ -212,15 +219,17 @@ void ReplaySession::check_for_password(shared_ptr ev) const { void ReplaySession::apply_default_mask(shared_ptr ev) { auto version = this->clients.at(ev->client_id)->version; - void* cmd_data = ev->mask.data() + ((version == GameVersion::BB) ? 8 : 4); - size_t cmd_size = ev->mask.size() - ((version == GameVersion::BB) ? 8 : 4); + void* cmd_data = ev->data.data() + ((version == GameVersion::BB) ? 8 : 4); + size_t cmd_size = ev->data.size() - ((version == GameVersion::BB) ? 8 : 4); + void* mask_data = ev->mask.data() + ((version == GameVersion::BB) ? 8 : 4); + size_t mask_size = ev->mask.size() - ((version == GameVersion::BB) ? 8 : 4); switch (version) { case GameVersion::PATCH: { const auto& header = check_size_t( ev->data, sizeof(PSOCommandHeaderPC), 0xFFFF); if (header.command == 0x02) { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); + auto& cmd_mask = check_size_t(mask_data, mask_size); cmd_mask.server_key = 0; cmd_mask.client_key = 0; } @@ -243,46 +252,46 @@ void ReplaySession::apply_default_mask(shared_ptr ev) { case 0x17: case 0x91: case 0x9B: { - auto& cmd_mask = check_size_t( - cmd_data, cmd_size, sizeof(S_ServerInitDefault_DC_PC_V3_02_17_91_9B), 0xFFFF); - cmd_mask.server_key = 0; - cmd_mask.client_key = 0; + auto& mask = check_size_t( + mask_data, mask_size, sizeof(S_ServerInitDefault_DC_PC_V3_02_17_91_9B), 0xFFFF); + mask.server_key = 0; + mask.client_key = 0; break; } case 0x19: { - if (cmd_size == sizeof(S_ReconnectSplit_19)) { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.pc_address = 0; - cmd_mask.gc_address = 0; + if (mask_size == sizeof(S_ReconnectSplit_19)) { + auto& mask = check_size_t(mask_data, mask_size); + mask.pc_address = 0; + mask.gc_address = 0; } else { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.address = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.address = 0; } break; } case 0x41: { if (version == GameVersion::PC) { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.reconnect_command.address = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.reconnect_command.address = 0; } else if (version == GameVersion::BB) { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.reconnect_command.address = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.reconnect_command.address = 0; } else { // V3 - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.reconnect_command.address = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.reconnect_command.address = 0; } break; } case 0x64: { if (version == GameVersion::PC) { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.variations.clear(0); - cmd_mask.rare_seed = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.variations.clear(0); + mask.rare_seed = 0; } else { // V3 - auto& cmd_mask = check_size_t(cmd_data, cmd_size, + auto& mask = check_size_t(mask_data, mask_size, sizeof(S_JoinGame_DC_GC_64), sizeof(S_JoinGame_GC_Ep3_64)); - cmd_mask.variations.clear(0); - cmd_mask.rare_seed = 0; + mask.variations.clear(0); + mask.rare_seed = 0; } break; } @@ -293,12 +302,31 @@ void ReplaySession::apply_default_mask(shared_ptr ev) { break; } case 0xC9: { - if (cmd_size == 0xCC) { - auto& cmd_mask = check_size_t( - cmd_data, cmd_size); - cmd_mask.version_signature.clear(0); - cmd_mask.date_str1.clear(0); - cmd_mask.date_str2.clear(0); + if (mask_size == 0xCC) { + auto& mask = check_size_t( + mask_data, mask_size); + mask.version_signature.clear(0); + mask.date_str1.clear(0); + mask.date_str2.clear(0); + } + break; + } + case 0x6C: { + if (version == GameVersion::GC && mask_size >= 0x14) { + const auto& cmd = check_size_t( + cmd_data, cmd_size, sizeof(G_MapList_GC_Ep3_6xB6x40), 0xFFFF); + if ((cmd.header.header.basic_header.subcommand == 0xB6) && + (cmd.header.subsubcommand == 0x40)) { + check_size_t(ev->mask, sizeof(PSOCommandHeaderDCV3), 0xFFFF).size = 0; + auto& mask = check_size_t( + mask_data, mask_size, sizeof(G_MapList_GC_Ep3_6xB6x40), 0xFFFF); + mask.header.header.size = 0; + mask.compressed_data_size = 0; + ev->allow_size_disparity = true; + for (size_t z = sizeof(PSOCommandHeaderDCV3) + sizeof(G_MapList_GC_Ep3_6xB6x40); z < ev->mask.size(); z++) { + ev->mask[z] = 0; + } + } } break; } @@ -310,21 +338,21 @@ void ReplaySession::apply_default_mask(shared_ptr ev) { ev->data, sizeof(PSOCommandHeaderBB), 0xFFFF).command; switch (command) { case 0x0003: { - auto& cmd_mask = check_size_t( - cmd_data, cmd_size, sizeof(S_ServerInitDefault_BB_03_9B), 0xFFFF); - cmd_mask.server_key.clear(0); - cmd_mask.client_key.clear(0); + auto& mask = check_size_t( + mask_data, mask_size, sizeof(S_ServerInitDefault_BB_03_9B), 0xFFFF); + mask.server_key.clear(0); + mask.client_key.clear(0); break; } case 0x0019: { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.address = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.address = 0; break; } case 0x0064: { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.variations.clear(0); - cmd_mask.rare_seed = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.variations.clear(0); + mask.rare_seed = 0; break; } case 0x00B1: { @@ -334,8 +362,8 @@ void ReplaySession::apply_default_mask(shared_ptr ev) { break; } case 0x00E6: { - auto& cmd_mask = check_size_t(cmd_data, cmd_size); - cmd_mask.team_id = 0; + auto& mask = check_size_t(mask_data, mask_size); + mask.team_id = 0; break; } } @@ -616,14 +644,14 @@ void ReplaySession::on_command_received( } auto& ev = c->receive_events.front(); - if (full_command.size() != ev->data.size()) { + if ((full_command.size() != ev->data.size()) && !ev->allow_size_disparity) { replay_log.error("Expected command:"); print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); replay_log.error("Received command:"); print_data(stderr, full_command, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); throw runtime_error(string_printf("(ev-line %zu) received command sizes do not match", ev->line_num)); } - for (size_t x = 0; x < full_command.size(); x++) { + for (size_t x = 0; x < min(full_command.size(), ev->data.size()); x++) { if ((full_command[x] & ev->mask[x]) != (ev->data[x] & ev->mask[x])) { replay_log.error("Expected command:"); print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); diff --git a/src/ReplaySession.hh b/src/ReplaySession.hh index 5dcee72d..33b75925 100644 --- a/src/ReplaySession.hh +++ b/src/ReplaySession.hh @@ -42,6 +42,7 @@ private: uint64_t client_id; std::string data; // Only used for SEND and RECEIVE std::string mask; // Only used for RECEIVE + bool allow_size_disparity; bool complete; size_t line_num;