From 812310054c3c0905fa50b2b7fa35d4206512f919 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 8 Oct 2023 15:20:48 -0700 Subject: [PATCH] fix 6x70 handling in dc/pc cross-play --- src/CommandFormats.hh | 5 +++- src/ReceiveSubcommands.cc | 54 +++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 5ed50c71..2e0d7544 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -4547,8 +4547,11 @@ struct G_Unknown_6x6F { // 6x70: Sync player disp data and inventory (used while loading into game) // Annoyingly, they didn't use the same format as the 65/67/68 commands here, // and instead rearranged a bunch of things. +// The format appears to be the same for all pre-BB PSO versions, although +// Episode 3 does not send this command at all since the relevant data is sent +// tothe joining player in the 64 command instead. -struct G_SyncPlayerDispAndInventory_V3_6x70 { +struct G_SyncPlayerDispAndInventory_DC_PC_V3_6x70 { G_ExtendedHeader header; // Offsets in this struct are relative to the overall command header /* 000C */ le_uint16_t client_id; diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 41096771..8dc784eb 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -243,9 +243,12 @@ static void on_sync_joining_player_item_state(shared_ptr c, uint8_t comm } } -static void on_sync_joining_player_disp_and_inventory(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { +static void on_sync_joining_player_disp_and_inventory( + shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { auto l = c->require_lobby(); - if (!l->is_game() || !l->any_client_loading()) { + // In V1/V2 games, this command sometimes is sent after the new client has + // finished loading, so we don't check l->any_client_loading() here. + if (!l->is_game()) { return; } @@ -254,33 +257,34 @@ static void on_sync_joining_player_disp_and_inventory(shared_ptr c, uint if (!command_is_private(command)) { throw runtime_error("6x70 sent via public command"); } + if (flag >= l->max_clients) { + return; + } + auto target = l->clients[flag]; + if (!target) { + return; + } - // For non-V3 versions, just forward the data verbatim. For V3, we need to - // byteswap mags' data2 fields if exactly one of the sender and recipient are - // PSO GC + // This command's format is different on BB and non-BB + bool sender_is_bb = (c->version() == GameVersion::BB); + bool target_is_bb = (target->version() == GameVersion::BB); + if (sender_is_bb != target_is_bb) { + // TODO: Figure out the BB 6x70 format and implement this + throw runtime_error("6x70 command cannot be translated across BB boundary"); + } + + // We need to byteswap mags' data2 fields if exactly one of the sender and + // recipient are PSO GC bool sender_is_gc = (c->version() == GameVersion::GC); - if (!sender_is_gc && (c->version() != GameVersion::XB)) { - forward_subcommand(c, command, flag, data, size); - + bool target_is_gc = (target->version() == GameVersion::GC); + if (target_is_gc == sender_is_gc) { + send_command(target, command, flag, data, size); } else { - if (flag >= l->max_clients) { - return; - } - auto target = l->clients[flag]; - if (!target) { - return; - } - bool target_is_gc = (target->version() == GameVersion::GC); - - if (target_is_gc == sender_is_gc) { - send_command(target, command, flag, data, size); - } else { - auto out_cmd = check_size_t(data, size); - for (size_t z = 0; z < 30; z++) { - out_cmd.inventory.items[z].data.bswap_data2_if_mag(); - } - send_command_t(target, command, flag, out_cmd); + auto out_cmd = check_size_t(data, size); + for (size_t z = 0; z < 30; z++) { + out_cmd.inventory.items[z].data.bswap_data2_if_mag(); } + send_command_t(target, command, flag, out_cmd); } }