From 5f0a6f3d8e70b40550408680e626c870127fd20b Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Wed, 25 Oct 2023 15:06:04 -0700 Subject: [PATCH] factor FloorItem struct into 6x5F format --- src/CommandFormats.hh | 31 +++++++++++++------------------ src/ReceiveSubcommands.cc | 39 ++++++++++++++++++++++++++------------- src/SendCommands.cc | 4 ++-- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 91917367..33a88ef5 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -4317,7 +4317,7 @@ struct G_Unknown_6x5C { struct G_DropStackedItem_DC_6x5D { G_ClientIDHeader header; le_uint16_t area; - le_uint16_t unused2; + le_uint16_t unknown_a2; // Corresponds to FloorItem::unknown_a2 le_float x; le_float z; ItemData item_data; @@ -4336,16 +4336,23 @@ struct G_BuyShopItem_6x5E { // 6x5F: Drop item from box/enemy -struct G_DropItem_DC_6x5F { - G_UnusedHeader header; +struct FloorItem { uint8_t area; uint8_t from_enemy; - le_uint16_t request_id; // < 0x0B50 if from_enemy != 0; otherwise < 0x0BA0 + le_uint16_t entity_id; // < 0x0B50 if from_enemy != 0; otherwise < 0x0BA0 le_float x; le_float z; - le_uint16_t unknown_a1; le_uint16_t unknown_a2; - ItemData item_data; + // The drop number is scoped to the area and increments by 1 each time an + // item is dropped. The last item dropped in each area has drop_number equal + // to total_items_dropped_per_area[area - 1] - 1. + le_uint16_t drop_number; + ItemData item; +} __packed__; + +struct G_DropItem_DC_6x5F { + G_UnusedHeader header; + FloorItem item; } __packed__; struct G_DropItem_PC_V3_BB_6x5F : G_DropItem_DC_6x5F { @@ -4492,18 +4499,6 @@ struct G_SyncItemState_6x6D_Decompressed { // the client fills in all 12 of these with reasonable values. parray next_item_id_per_player; parray floor_item_count_per_area; - struct FloorItem { - le_uint16_t area; - le_uint16_t unknown_a1; - le_float x; - le_float z; - le_uint16_t unknown_a2; - // The drop number is scoped to the area and increments by 1 each time an - // item is dropped. The last item dropped in each area has drop_number equal - // to total_items_dropped_per_area[area - 1] - 1. - le_uint16_t drop_number; - ItemData item_data; - } __packed__; // Variable-length field: // FloorItem items[sum(floor_item_count_per_area)]; } __packed__; diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 9540f1de..e5de85ac 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -210,14 +210,13 @@ static void on_sync_joining_player_item_state(shared_ptr c, uint8_t comm num_floor_items += decompressed_cmd->floor_item_count_per_area[z]; } - size_t required_size = sizeof(G_SyncItemState_6x6D_Decompressed) + num_floor_items * sizeof(G_SyncItemState_6x6D_Decompressed::FloorItem); + size_t required_size = sizeof(G_SyncItemState_6x6D_Decompressed) + num_floor_items * sizeof(FloorItem); if (decompressed.size() < required_size) { throw runtime_error(string_printf( "decompressed 6x6D data (0x%zX bytes) is too short for all items (0x%zX bytes)", decompressed.size(), required_size)); } - auto* floor_items = reinterpret_cast( - decompressed.data() + sizeof(G_SyncItemState_6x6D_Decompressed)); + auto* floor_items = reinterpret_cast(decompressed.data() + sizeof(G_SyncItemState_6x6D_Decompressed)); for (size_t z = 0; z < num_floor_items; z++) { // NOTE: If we use this codepath for non-V3 in the future, we'll need to @@ -900,6 +899,12 @@ static void on_buy_shop_item(shared_ptr c, uint8_t command, uint8_t flag template static void on_box_or_enemy_item_drop_t(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { + // I'm lazy and this should never happen for item commands (since all players + // need to stay in sync) + if (command_is_private(command)) { + throw runtime_error("item subcommand sent via private command"); + } + const auto& cmd = check_size_t(data, size); auto l = c->require_lobby(); @@ -911,22 +916,30 @@ static void on_box_or_enemy_item_drop_t(shared_ptr c, uint8_t command, u } if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) { - { - ItemData item = cmd.item_data; - item.decode_if_mag(c->version()); - l->add_item(item, cmd.area, cmd.x, cmd.z); - } + ItemData item = cmd.item.item; + item.decode_if_mag(c->version()); + l->add_item(item, cmd.item.area, cmd.item.x, cmd.item.z); - auto name = cmd.item_data.name(false); + auto name = item.name(false); l->log.info("Leader created ground item %08" PRIX32 " (%s) at %hhu:(%g, %g)", - cmd.item_data.id.load(), name.c_str(), cmd.area, cmd.x.load(), cmd.z.load()); + item.id.load(), name.c_str(), cmd.item.area, cmd.item.x.load(), cmd.item.z.load()); if (c->options.debug) { - string name = cmd.item_data.name(true); - send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s", cmd.item_data.id.load(), name.c_str()); + string name = item.name(true); + send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s", item.id.load(), name.c_str()); } } - forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); + for (auto& lc : l->clients) { + if (!lc || lc == c) { + continue; + } + CmdT out_cmd = cmd; + if (c->version() != lc->version()) { + out_cmd.item.item.decode_if_mag(c->version()); + out_cmd.item.item.encode_if_mag(lc->version()); + } + send_command_t(lc, command, flag, out_cmd); + } } static void on_box_or_enemy_item_drop(shared_ptr c, uint8_t command, uint8_t flag, const void* data, size_t size) { diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 8ceb6a44..0e8f6d7a 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2009,8 +2009,8 @@ void send_set_player_visibility(shared_ptr l, shared_ptr c, void send_drop_item(Channel& ch, const ItemData& item, bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) { G_DropItem_PC_V3_BB_6x5F cmd = { - {{0x5F, 0x0B, 0x0000}, area, from_enemy, entity_id, x, z, 0, 0, item}, 0}; - cmd.item_data.encode_if_mag(ch.version); + {{0x5F, 0x0B, 0x0000}, {area, from_enemy, entity_id, x, z, 0, 0, item}}, 0}; + cmd.item.item.encode_if_mag(ch.version); ch.send(0x60, 0x00, &cmd, sizeof(cmd)); }