fix 6x70 handling in dc/pc cross-play

This commit is contained in:
Martin Michelsen
2023-10-08 15:20:48 -07:00
parent 5673de78be
commit 812310054c
2 changed files with 33 additions and 26 deletions
+4 -1
View File
@@ -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<G_UnusedHeader> header;
// Offsets in this struct are relative to the overall command header
/* 000C */ le_uint16_t client_id;
+29 -25
View File
@@ -243,9 +243,12 @@ static void on_sync_joining_player_item_state(shared_ptr<Client> c, uint8_t comm
}
}
static void on_sync_joining_player_disp_and_inventory(shared_ptr<Client> c, uint8_t command, uint8_t flag, const void* data, size_t size) {
static void on_sync_joining_player_disp_and_inventory(
shared_ptr<Client> 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<Client> 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<G_SyncPlayerDispAndInventory_V3_6x70>(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<G_SyncPlayerDispAndInventory_DC_PC_V3_6x70>(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);
}
}