diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 09699ea2..ea0c63da 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -4203,6 +4203,17 @@ static void on_0C_C1_E7_EC(shared_ptr c, uint16_t command, uint32_t, str if (game) { s->change_client_lobby(c, game); c->config.set_flag(Client::Flag::LOADING); + + // There is a bug in DC NTE and 11/2000 that causes them to assign item IDs + // twice when joining a game. If there are other players in the game, this + // isn't an issue because the equivalent of the 6x6D command resets the next + // item ID before the second assignment, so the item IDs stay in sync with + // the server. If there was no one else in the game, however (as in this + // case, when it was just created), we need to artificially change the next + // item IDs during the client's loading procedure. + if (is_pre_v1(c->version())) { + c->config.set_flag(Client::Flag::SHOULD_SEND_ARTIFICIAL_ITEM_STATE); + } } } diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 532796a8..bd073855 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -905,12 +905,9 @@ static void on_change_floor_6x1F(shared_ptr c, uint8_t command, uint8_t if (is_pre_v1(c->version())) { check_size_t(data, size); // DC NTE and 11/2000 don't send 6F when they're done loading, so we clear - // the loading flag here instead. On these versions, it also seems to be - // necessary to assign item IDs again here. + // the loading flag here instead. if (c->config.check_flag(Client::Flag::LOADING)) { c->config.clear_flag(Client::Flag::LOADING); - auto l = c->require_lobby(); - l->assign_inventory_and_bank_item_ids(c); } } else { diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 987cae7b..c35f9a93 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2360,8 +2360,25 @@ void send_game_item_state(shared_ptr c) { G_SyncItemState_6x6D_Decompressed decompressed_header; for (size_t z = 0; z < 12; z++) { - decompressed_header.next_item_id_per_player[z] = l->next_item_id_for_client[z]; + if (z == c->lobby_client_id) { + // If the player is joining, adjust the next item ID to use the value + // before inventory item IDs are assigned + size_t num_items = c->character()->inventory.num_items; + uint32_t next_id = l->next_item_id_for_client[z] - num_items; + if ((next_id & 0xFFE00000) != (l->next_item_id_for_client[z] & 0xFFE00000)) { + throw runtime_error("next item ID underflow during joining player item state generation"); + } + decompressed_header.next_item_id_per_player[z] = next_id; + } else { + decompressed_header.next_item_id_per_player[z] = l->next_item_id_for_client[z]; + } } + l->log.info("Sending next item IDs to client: %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32, + decompressed_header.next_item_id_per_player[0].load(), + decompressed_header.next_item_id_per_player[1].load(), + decompressed_header.next_item_id_per_player[2].load(), + decompressed_header.next_item_id_per_player[3].load()); + for (size_t floor = 0; floor < 0x10; floor++) { const auto& m = l->floor_item_managers.at(floor); for (const auto& it : m.queue_for_client.at(c->lobby_client_id)) { diff --git a/tests/DCNTE-GameSmokeTest.test.txt b/tests/DCNTE-GameSmokeTest.test.txt index 3a91e3be..36853d93 100644 --- a/tests/DCNTE-GameSmokeTest.test.txt +++ b/tests/DCNTE-GameSmokeTest.test.txt @@ -887,6 +887,13 @@ I 25793 2023-11-24 23:08:15 - [Commands] Sending to C-A (ABCDEFGHIJKL) (version= I 25793 2023-11-24 23:08:15 - [Commands] Received from C-A (ABCDEFGHIJKL) (version=DC_NTE command=1D flag=00) 0000 | 1D 00 04 00 | I 25793 2023-11-24 23:08:15 - [C-A] Sending 0 queued command(s) +I 58396 2023-12-27 10:39:54 - [Lobby:15] Sending next item IDs to client: 00010000 00210000 00410000 00610000 +I 58396 2023-12-27 10:39:54 - [Commands] Sending to C-A (ABCDEFGHIJKL) (version=DC_NTE command=6D flag=00) +0000 | 6D 00 44 00 5E 00 00 00 40 00 00 00 8C 00 00 00 | m D ^ @ +0010 | A9 00 EE FF 00 0C 01 0D 00 21 11 00 41 AA 15 00 | ! A +0020 | 61 19 00 81 1D 00 A1 21 00 C1 52 25 00 E1 0D 01 | a ! R% +0030 | 10 00 21 31 00 41 35 00 01 61 10 01 40 0F 52 0F | !1 A5 a @ R +0040 | 64 0F 29 00 | d ) I 25793 2023-11-24 23:08:27 - [Commands] Received from C-A (ABCDEFGHIJKL) (version=DC_NTE command=60 flag=00) 0000 | 60 00 1C 00 36 06 00 00 00 00 00 00 00 00 00 00 | ` 6 0010 | 5C 0F C6 43 00 00 00 00 C3 75 95 42 | \ C u B