From 01f3ed7bc60e780147a32013884b2a0bac86a7ae Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Tue, 7 Nov 2023 16:35:21 -0800 Subject: [PATCH] fix some endianness differences on GC/XB --- src/CommandFormats.hh | 40 ++++++++++++++-- src/ReceiveSubcommands.cc | 96 +++++++++++++++++++++++++++++++++------ 2 files changed, 119 insertions(+), 17 deletions(-) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 20ed691b..05973ab3 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -3768,12 +3768,18 @@ struct G_Unknown_6x09 { // 6x0A: Enemy hit +template struct G_EnemyHitByPlayer_6x0A { G_EnemyIDHeader header; // Note: enemy_id (in header) is in the range [0x1000, 0x4000) le_uint16_t enemy_id = 0; le_uint16_t remaining_hp = 0; - be_uint32_t flags = 0; + typename std::conditional::type flags = 0; +} __packed__; + +struct G_EnemyHitByPlayer_GC_6x0A : G_EnemyHitByPlayer_6x0A { +} __packed__; +struct G_EnemyHitByPlayer_DC_PC_XB_BB_6x0A : G_EnemyHitByPlayer_6x0A { } __packed__; // 6x0B: Box destroyed @@ -3814,7 +3820,22 @@ struct G_Unknown_6x10_6x11_6x12_6x14 { // Same format as 6x10 // 6x12: Dragon boss actions (not valid on Episode 3) -// Same format as 6x10 + +template +struct G_DragonBossActions_6x12 { + using F32T = typename std::conditional::type; + G_EnemyIDHeader header; + le_uint16_t unknown_a2 = 0; + le_uint16_t unknown_a3 = 0; + le_uint32_t unknown_a4 = 0; + F32T x = 0.0f; + F32T z = 0.0f; +} __packed__; + +struct G_DragonBossActions_DC_PC_XB_BB_6x12 : G_DragonBossActions_6x12 { +} __packed__; +struct G_DragonBossActions_GC_6x12 : G_DragonBossActions_6x12 { +} __packed__; // 6x13: De Rol Le boss actions (not valid on Episode 3) @@ -5068,11 +5089,22 @@ struct G_ModifyTradeProposal_6xA6 { // 6xA8: Gol Dragon boss actions (not valid on pre-V3 or Episode 3) +template struct G_GolDragonBossActions_6xA8 { + using F32T = typename std::conditional::type; G_EnemyIDHeader header; - le_uint16_t unknown_a1 = 0; le_uint16_t unknown_a2 = 0; - le_uint32_t unknown_a3 = 0; + le_uint16_t unknown_a3 = 0; + le_uint32_t unknown_a4 = 0; + F32T x = 0.0f; + F32T z = 0.0f; + uint8_t unknown_a5 = 0; + parray unused; +} __packed__; + +struct G_GolDragonBossActions_XB_BB_6xA8 : G_GolDragonBossActions_6xA8 { +} __packed__; +struct G_GolDragonBossActions_GC_6xA8 : G_GolDragonBossActions_6xA8 { } __packed__; // 6xA9: Barba Ray boss actions (not valid on pre-V3 or Episode 3) diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 4d123811..19e67925 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -729,7 +729,7 @@ static void on_player_drop_item(shared_ptr c, uint8_t command, uint8_t f } template -void forward_subcommand_with_mag_transcode_t(shared_ptr c, uint8_t command, uint8_t flag, const CmdT& cmd) { +void forward_subcommand_with_item_transcode_t(shared_ptr c, uint8_t command, uint8_t flag, const CmdT& cmd) { // I'm lazy and this should never happen for item commands (since all players // need to stay in sync) if (command_is_private(command)) { @@ -784,7 +784,7 @@ static void on_create_inventory_item_t(shared_ptr c, uint8_t command, ui p->print_inventory(stderr, c->version(), s->item_name_index); } - forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); + forward_subcommand_with_item_transcode_t(c, command, flag, cmd); } static void on_create_inventory_item(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { @@ -830,7 +830,7 @@ static void on_drop_partial_stack_t(shared_ptr c, uint8_t command, uint8 c->game_data.player()->print_inventory(stderr, c->version(), s->item_name_index); } - forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); + forward_subcommand_with_item_transcode_t(c, command, flag, cmd); } static void on_drop_partial_stack(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { @@ -924,7 +924,7 @@ static void on_buy_shop_item(shared_ptr c, uint8_t command, uint8_t flag p->print_inventory(stderr, c->version(), s->item_name_index); } - forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); + forward_subcommand_with_item_transcode_t(c, command, flag, cmd); } template @@ -1547,14 +1547,74 @@ static void on_set_quest_flag(shared_ptr c, uint8_t command, uint8_t fla } } -static void on_enemy_hit(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { - auto l = c->require_lobby(); - if (l->base_version == GameVersion::BB) { - const auto& cmd = check_size_t(data, size); +static void on_dragon_actions(shared_ptr c, uint8_t command, uint8_t, const void* data, size_t size) { + const auto& cmd = check_size_t(data, size); - if (!l->is_game()) { - return; + if (command_is_private(command)) { + return; + } + auto l = c->require_lobby(); + if (!l->is_game()) { + return; + } + + G_DragonBossActions_GC_6x12 sw_cmd = {{{cmd.header.subcommand, cmd.header.size, cmd.header.enemy_id}, + cmd.unknown_a2, cmd.unknown_a3, cmd.unknown_a4, cmd.x.load(), cmd.z.load()}}; + bool sender_is_gc = (c->version() == GameVersion::GC); + for (auto lc : l->clients) { + if (lc && (lc != c)) { + if ((lc->version() == GameVersion::GC) == sender_is_gc) { + send_command_t(lc, 0x60, 0x00, cmd); + } else { + send_command_t(lc, 0x60, 0x00, sw_cmd); + } } + } +} + +static void on_gol_dragon_actions(shared_ptr c, uint8_t command, uint8_t, const void* data, size_t size) { + const auto& cmd = check_size_t(data, size); + + if (command_is_private(command)) { + return; + } + auto l = c->require_lobby(); + if (!l->is_game()) { + return; + } + + G_GolDragonBossActions_GC_6xA8 sw_cmd = {{{cmd.header.subcommand, cmd.header.size, cmd.header.enemy_id}, + cmd.unknown_a2, + cmd.unknown_a3, + cmd.unknown_a4, + cmd.x.load(), + cmd.z.load(), + cmd.unknown_a5, + 0}}; + bool sender_is_gc = (c->version() == GameVersion::GC); + for (auto lc : l->clients) { + if (lc && (lc != c)) { + if ((lc->version() == GameVersion::GC) == sender_is_gc) { + send_command_t(lc, 0x60, 0x00, cmd); + } else { + send_command_t(lc, 0x60, 0x00, sw_cmd); + } + } + } +} + +static void on_enemy_hit(shared_ptr c, uint8_t command, uint8_t, const void* data, size_t size) { + const auto& cmd = check_size_t(data, size); + + if (command_is_private(command)) { + return; + } + auto l = c->require_lobby(); + if (!l->is_game()) { + return; + } + + if (l->base_version == GameVersion::BB) { if (c->lobby_client_id > 3) { throw logic_error("client ID is above 3"); } @@ -1573,7 +1633,17 @@ static void on_enemy_hit(shared_ptr c, uint8_t command, uint8_t flag, co enemy.last_hit_by_client_id = c->lobby_client_id; } - forward_subcommand(c, command, flag, data, size); + G_EnemyHitByPlayer_GC_6x0A sw_cmd = {{{cmd.header.subcommand, cmd.header.size, cmd.header.enemy_id}, cmd.enemy_id, cmd.remaining_hp, cmd.flags.load()}}; + bool sender_is_gc = (c->version() == GameVersion::GC); + for (auto lc : l->clients) { + if (lc && (lc != c)) { + if ((lc->version() == GameVersion::GC) == sender_is_gc) { + send_command_t(lc, 0x60, 0x00, cmd); + } else { + send_command_t(lc, 0x60, 0x00, sw_cmd); + } + } + } } static void on_charge_attack_bb(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { @@ -2225,7 +2295,7 @@ subcommand_handler_t subcommand_handlers[0x100] = { /* 6x0F */ nullptr, /* 6x10 */ nullptr, /* 6x11 */ nullptr, - /* 6x12 */ on_forward_check_size_game, + /* 6x12 */ on_dragon_actions, /* 6x13 */ on_forward_check_size_game, /* 6x14 */ on_forward_check_size_game, /* 6x15 */ on_forward_check_size_game, @@ -2375,7 +2445,7 @@ subcommand_handler_t subcommand_handlers[0x100] = { /* 6xA5 */ on_forward_check_size_game, /* 6xA6 */ on_forward_check_size, /* 6xA7 */ nullptr, - /* 6xA8 */ on_forward_check_size_game, + /* 6xA8 */ on_gol_dragon_actions, /* 6xA9 */ on_forward_check_size_game, /* 6xAA */ on_forward_check_size_game, /* 6xAB */ on_forward_check_size_client,