handle one 6x63 data race

This commit is contained in:
Martin Michelsen
2024-07-06 09:54:01 -07:00
parent c58b37be23
commit 21c8bab91c
4 changed files with 54 additions and 24 deletions
+3 -1
View File
@@ -4676,7 +4676,9 @@ struct G_ActivateMagEffect_6x61 {
// 6x62: Unknown // 6x62: Unknown
// This command has a handler, but it does nothing even on DC NTE. // This command has a handler, but it does nothing even on DC NTE.
// 6x63: Destroy floor item (used when too many items have been dropped) // 6x63: Destroy floor item
// This is sent by the leader to destroy a floor item when there are 50 or more
// items already on the ground on the current floor.
struct G_DestroyFloorItem_6x5C_6x63 { struct G_DestroyFloorItem_6x5C_6x63 {
G_UnusedHeader header; G_UnusedHeader header;
+1 -2
View File
@@ -91,8 +91,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
SERVER_DUPLICATE = 4, SERVER_DUPLICATE = 4,
}; };
std::weak_ptr<ServerState> std::weak_ptr<ServerState> server_state;
server_state;
PrefixedLogger log; PrefixedLogger log;
uint32_t lobby_id; uint32_t lobby_id;
+6
View File
@@ -3243,6 +3243,12 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->update_channel_name(); c->update_channel_name();
// If the player is BB and has just left a game, sync their save file to the
// client to make sure it's up to date
if ((c->version() == Version::BB_V4) && (command == 0x98)) {
send_complete_player_bb(c);
}
if (command == 0x61) { if (command == 0x61) {
if (c->pending_character_export) { if (c->pending_character_export) {
unique_ptr<Client::PendingCharacterExport> pending_export = std::move(c->pending_character_export); unique_ptr<Client::PendingCharacterExport> pending_export = std::move(c->pending_character_export);
+24 -1
View File
@@ -3724,7 +3724,29 @@ static void on_destroy_floor_item(shared_ptr<Client> c, uint8_t command, uint8_t
} }
auto s = c->require_server_state(); auto s = c->require_server_state();
auto fi = l->remove_item(cmd.floor, cmd.item_id, 0xFF); shared_ptr<Lobby::FloorItem> fi;
try {
fi = l->remove_item(cmd.floor, cmd.item_id, 0xFF);
} catch (const out_of_range&) {
}
if (!fi) {
// There are generally two data races that could occur here. Either the
// player attempted to evict the item at the same time the server did (that
// is, the client's and server's 6x63 commands crossed paths on the
// network), or the player attempted to evict an item that was already
// picked up. The former case is easy to handle; we can just ignore the
// command. The latter case is more difficult - we have to know which
// player picked up the item and send a 6x2B command to the sender, to sync
// their item state with the server's again. We can't just look through the
// players' inventories to find the item ID, since item IDs can be
// destroyed when stackable items or Meseta are picked up.
// TODO: We don't actually handle the evict/pickup conflict case. This case
// is probably quite rare, but we should eventually handle it.
l->log.info("Player %hhu attempted to destroy floor item %08" PRIX32 ", but it is missing",
c->lobby_client_id, cmd.item_id.load());
} else {
auto name = s->describe_item(c->version(), fi->data, false); auto name = s->describe_item(c->version(), fi->data, false);
l->log.info("Player %hhu destroyed floor item %08" PRIX32 " (%s)", c->lobby_client_id, cmd.item_id.load(), name.c_str()); l->log.info("Player %hhu destroyed floor item %08" PRIX32 " (%s)", c->lobby_client_id, cmd.item_id.load(), name.c_str());
@@ -3751,6 +3773,7 @@ static void on_destroy_floor_item(shared_ptr<Client> c, uint8_t command, uint8_t
} }
} }
} }
}
static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, void* data, size_t size) { static void on_identify_item_bb(shared_ptr<Client> c, uint8_t command, uint8_t flag, void* data, size_t size) {
auto l = c->require_lobby(); auto l = c->require_lobby();