support size disparities in ReplaySession
This commit is contained in:
+73
-45
@@ -13,7 +13,11 @@ using namespace std;
|
|||||||
|
|
||||||
|
|
||||||
ReplaySession::Event::Event(Type type, uint64_t client_id, size_t line_num)
|
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 ReplaySession::Event::str() const {
|
||||||
string ret;
|
string ret;
|
||||||
@@ -26,6 +30,9 @@ string ReplaySession::Event::str() const {
|
|||||||
} else if (this->type == Type::RECEIVE) {
|
} else if (this->type == Type::RECEIVE) {
|
||||||
ret = string_printf("Event[%" PRIu64 ", RECEIVE %04zX", this->client_id, this->data.size());
|
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) {
|
if (this->complete) {
|
||||||
ret += ", done";
|
ret += ", done";
|
||||||
}
|
}
|
||||||
@@ -212,15 +219,17 @@ void ReplaySession::check_for_password(shared_ptr<const Event> ev) const {
|
|||||||
void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
||||||
auto version = this->clients.at(ev->client_id)->version;
|
auto version = this->clients.at(ev->client_id)->version;
|
||||||
|
|
||||||
void* cmd_data = ev->mask.data() + ((version == GameVersion::BB) ? 8 : 4);
|
void* cmd_data = ev->data.data() + ((version == GameVersion::BB) ? 8 : 4);
|
||||||
size_t cmd_size = ev->mask.size() - ((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) {
|
switch (version) {
|
||||||
case GameVersion::PATCH: {
|
case GameVersion::PATCH: {
|
||||||
const auto& header = check_size_t<PSOCommandHeaderPC>(
|
const auto& header = check_size_t<PSOCommandHeaderPC>(
|
||||||
ev->data, sizeof(PSOCommandHeaderPC), 0xFFFF);
|
ev->data, sizeof(PSOCommandHeaderPC), 0xFFFF);
|
||||||
if (header.command == 0x02) {
|
if (header.command == 0x02) {
|
||||||
auto& cmd_mask = check_size_t<S_ServerInit_Patch_02>(cmd_data, cmd_size);
|
auto& cmd_mask = check_size_t<S_ServerInit_Patch_02>(mask_data, mask_size);
|
||||||
cmd_mask.server_key = 0;
|
cmd_mask.server_key = 0;
|
||||||
cmd_mask.client_key = 0;
|
cmd_mask.client_key = 0;
|
||||||
}
|
}
|
||||||
@@ -243,46 +252,46 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
case 0x17:
|
case 0x17:
|
||||||
case 0x91:
|
case 0x91:
|
||||||
case 0x9B: {
|
case 0x9B: {
|
||||||
auto& cmd_mask = check_size_t<S_ServerInitDefault_DC_PC_V3_02_17_91_9B>(
|
auto& mask = check_size_t<S_ServerInitDefault_DC_PC_V3_02_17_91_9B>(
|
||||||
cmd_data, cmd_size, sizeof(S_ServerInitDefault_DC_PC_V3_02_17_91_9B), 0xFFFF);
|
mask_data, mask_size, sizeof(S_ServerInitDefault_DC_PC_V3_02_17_91_9B), 0xFFFF);
|
||||||
cmd_mask.server_key = 0;
|
mask.server_key = 0;
|
||||||
cmd_mask.client_key = 0;
|
mask.client_key = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x19: {
|
case 0x19: {
|
||||||
if (cmd_size == sizeof(S_ReconnectSplit_19)) {
|
if (mask_size == sizeof(S_ReconnectSplit_19)) {
|
||||||
auto& cmd_mask = check_size_t<S_ReconnectSplit_19>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_ReconnectSplit_19>(mask_data, mask_size);
|
||||||
cmd_mask.pc_address = 0;
|
mask.pc_address = 0;
|
||||||
cmd_mask.gc_address = 0;
|
mask.gc_address = 0;
|
||||||
} else {
|
} else {
|
||||||
auto& cmd_mask = check_size_t<S_Reconnect_19>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_Reconnect_19>(mask_data, mask_size);
|
||||||
cmd_mask.address = 0;
|
mask.address = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x41: {
|
case 0x41: {
|
||||||
if (version == GameVersion::PC) {
|
if (version == GameVersion::PC) {
|
||||||
auto& cmd_mask = check_size_t<S_GuildCardSearchResult_PC_41>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_GuildCardSearchResult_PC_41>(mask_data, mask_size);
|
||||||
cmd_mask.reconnect_command.address = 0;
|
mask.reconnect_command.address = 0;
|
||||||
} else if (version == GameVersion::BB) {
|
} else if (version == GameVersion::BB) {
|
||||||
auto& cmd_mask = check_size_t<S_GuildCardSearchResult_BB_41>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_GuildCardSearchResult_BB_41>(mask_data, mask_size);
|
||||||
cmd_mask.reconnect_command.address = 0;
|
mask.reconnect_command.address = 0;
|
||||||
} else { // V3
|
} else { // V3
|
||||||
auto& cmd_mask = check_size_t<S_GuildCardSearchResult_DC_V3_41>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_GuildCardSearchResult_DC_V3_41>(mask_data, mask_size);
|
||||||
cmd_mask.reconnect_command.address = 0;
|
mask.reconnect_command.address = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x64: {
|
case 0x64: {
|
||||||
if (version == GameVersion::PC) {
|
if (version == GameVersion::PC) {
|
||||||
auto& cmd_mask = check_size_t<S_JoinGame_PC_64>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_JoinGame_PC_64>(mask_data, mask_size);
|
||||||
cmd_mask.variations.clear(0);
|
mask.variations.clear(0);
|
||||||
cmd_mask.rare_seed = 0;
|
mask.rare_seed = 0;
|
||||||
} else { // V3
|
} else { // V3
|
||||||
auto& cmd_mask = check_size_t<S_JoinGame_DC_GC_64>(cmd_data, cmd_size,
|
auto& mask = check_size_t<S_JoinGame_DC_GC_64>(mask_data, mask_size,
|
||||||
sizeof(S_JoinGame_DC_GC_64), sizeof(S_JoinGame_GC_Ep3_64));
|
sizeof(S_JoinGame_DC_GC_64), sizeof(S_JoinGame_GC_Ep3_64));
|
||||||
cmd_mask.variations.clear(0);
|
mask.variations.clear(0);
|
||||||
cmd_mask.rare_seed = 0;
|
mask.rare_seed = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -293,12 +302,31 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xC9: {
|
case 0xC9: {
|
||||||
if (cmd_size == 0xCC) {
|
if (mask_size == 0xCC) {
|
||||||
auto& cmd_mask = check_size_t<G_ServerVersionStrings_GC_Ep3_6xB4x46>(
|
auto& mask = check_size_t<G_ServerVersionStrings_GC_Ep3_6xB4x46>(
|
||||||
cmd_data, cmd_size);
|
mask_data, mask_size);
|
||||||
cmd_mask.version_signature.clear(0);
|
mask.version_signature.clear(0);
|
||||||
cmd_mask.date_str1.clear(0);
|
mask.date_str1.clear(0);
|
||||||
cmd_mask.date_str2.clear(0);
|
mask.date_str2.clear(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x6C: {
|
||||||
|
if (version == GameVersion::GC && mask_size >= 0x14) {
|
||||||
|
const auto& cmd = check_size_t<G_MapList_GC_Ep3_6xB6x40>(
|
||||||
|
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<PSOCommandHeaderDCV3>(ev->mask, sizeof(PSOCommandHeaderDCV3), 0xFFFF).size = 0;
|
||||||
|
auto& mask = check_size_t<G_MapList_GC_Ep3_6xB6x40>(
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -310,21 +338,21 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
ev->data, sizeof(PSOCommandHeaderBB), 0xFFFF).command;
|
ev->data, sizeof(PSOCommandHeaderBB), 0xFFFF).command;
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 0x0003: {
|
case 0x0003: {
|
||||||
auto& cmd_mask = check_size_t<S_ServerInitDefault_BB_03_9B>(
|
auto& mask = check_size_t<S_ServerInitDefault_BB_03_9B>(
|
||||||
cmd_data, cmd_size, sizeof(S_ServerInitDefault_BB_03_9B), 0xFFFF);
|
mask_data, mask_size, sizeof(S_ServerInitDefault_BB_03_9B), 0xFFFF);
|
||||||
cmd_mask.server_key.clear(0);
|
mask.server_key.clear(0);
|
||||||
cmd_mask.client_key.clear(0);
|
mask.client_key.clear(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0019: {
|
case 0x0019: {
|
||||||
auto& cmd_mask = check_size_t<S_Reconnect_19>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_Reconnect_19>(mask_data, mask_size);
|
||||||
cmd_mask.address = 0;
|
mask.address = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0064: {
|
case 0x0064: {
|
||||||
auto& cmd_mask = check_size_t<S_JoinGame_BB_64>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_JoinGame_BB_64>(mask_data, mask_size);
|
||||||
cmd_mask.variations.clear(0);
|
mask.variations.clear(0);
|
||||||
cmd_mask.rare_seed = 0;
|
mask.rare_seed = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x00B1: {
|
case 0x00B1: {
|
||||||
@@ -334,8 +362,8 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x00E6: {
|
case 0x00E6: {
|
||||||
auto& cmd_mask = check_size_t<S_ClientInit_BB_00E6>(cmd_data, cmd_size);
|
auto& mask = check_size_t<S_ClientInit_BB_00E6>(mask_data, mask_size);
|
||||||
cmd_mask.team_id = 0;
|
mask.team_id = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -616,14 +644,14 @@ void ReplaySession::on_command_received(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& ev = c->receive_events.front();
|
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:");
|
replay_log.error("Expected command:");
|
||||||
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
||||||
replay_log.error("Received command:");
|
replay_log.error("Received command:");
|
||||||
print_data(stderr, full_command, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
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));
|
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<size_t>(full_command.size(), ev->data.size()); x++) {
|
||||||
if ((full_command[x] & ev->mask[x]) != (ev->data[x] & ev->mask[x])) {
|
if ((full_command[x] & ev->mask[x]) != (ev->data[x] & ev->mask[x])) {
|
||||||
replay_log.error("Expected command:");
|
replay_log.error("Expected command:");
|
||||||
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ private:
|
|||||||
uint64_t client_id;
|
uint64_t client_id;
|
||||||
std::string data; // Only used for SEND and RECEIVE
|
std::string data; // Only used for SEND and RECEIVE
|
||||||
std::string mask; // Only used for RECEIVE
|
std::string mask; // Only used for RECEIVE
|
||||||
|
bool allow_size_disparity;
|
||||||
bool complete;
|
bool complete;
|
||||||
size_t line_num;
|
size_t line_num;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user