diff --git a/Source/inv.cpp b/Source/inv.cpp index b8ab50a4e..8143912d0 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -1084,11 +1084,12 @@ void OpenCrypt() NetSendCmdQuest(true, quest); } -void CleanupItems(Item *item, int ii) +void CleanupItems(int ii) { - dItem[item->position.x][item->position.y] = 0; + auto &item = Items[ii]; + dItem[item.position.x][item.position.y] = 0; - if (currlevel == 21 && item->position == CornerStone.position) { + if (currlevel == 21 && item.position == CornerStone.position) { CornerStone.item._itype = ItemType::None; CornerStone.item._iSelFlag = 0; CornerStone.item.position = { 0, 0 }; @@ -1627,14 +1628,15 @@ void CheckItemStats(Player &player) } } -void InvGetItem(int pnum, Item *item, int ii) +void InvGetItem(int pnum, int ii) { + auto &item = Items[ii]; if (dropGoldFlag) { CloseGoldDrop(); dropGoldValue = 0; } - if (dItem[item->position.x][item->position.y] == 0) + if (dItem[item.position.x][item.position.y] == 0) return; auto &player = Players[pnum]; @@ -1642,15 +1644,15 @@ void InvGetItem(int pnum, Item *item, int ii) if (MyPlayerId == pnum && pcurs >= CURSOR_FIRSTITEM) NetSendCmdPItem(true, CMD_SYNCPUTITEM, player.position.tile); - item->_iCreateInfo &= ~CF_PREGEN; - player.HoldItem = *item; + item._iCreateInfo &= ~CF_PREGEN; + player.HoldItem = item; CheckQuestItem(player); CheckBookLevel(player); CheckItemStats(player); bool cursorUpdated = false; if (player.HoldItem._itype == ItemType::Gold && GoldAutoPlace(player)) cursorUpdated = true; - CleanupItems(item, ii); + CleanupItems(ii); pcursitem = -1; if (!cursorUpdated) NewCursor(player.HoldItem._iCurs + CURSOR_FIRSTITEM); @@ -1706,7 +1708,7 @@ void AutoGetItem(int pnum, Item *item, int ii) PlaySFX(IS_IGRAB); } - CleanupItems(&Items[ii], ii); + CleanupItems(ii); return; } @@ -1742,25 +1744,30 @@ int FindGetItem(int idx, uint16_t ci, int iseed) void SyncGetItem(Point position, int idx, uint16_t ci, int iseed) { - int ii; + // Check what the local client has at the target position + int ii = dItem[position.x][position.y] - 1; - if (dItem[position.x][position.y] != 0) { - ii = dItem[position.x][position.y] - 1; - if (Items[ii].IDidx == idx - && Items[ii]._iSeed == iseed - && Items[ii]._iCreateInfo == ci) { - FindGetItem(idx, ci, iseed); - } else { - ii = FindGetItem(idx, ci, iseed); + if (ii >= 0 && ii < MAXITEMS) { + // If there was an item there, check that it's the same item as the remote player has + if (Items[ii].IDidx != idx + || Items[ii]._iSeed != iseed + || Items[ii]._iCreateInfo != ci) { + // Key attributes don't match so we must've desynced, ignore this index and try find a matching item via lookup + ii = -1; } - } else { + } + + if (ii == -1) { + // Either there's no item at the expected position or it doesn't match what is being picked up, so look for an item that matches the key attributes ii = FindGetItem(idx, ci, iseed); } - if (ii == -1) + if (ii == -1) { + // Still can't find the expected item, assume it was collected earlier and this caused the desync return; + } - CleanupItems(&Items[ii], ii); + CleanupItems(ii); } bool CanPut(Point position) diff --git a/Source/inv.h b/Source/inv.h index da3f3fd5b..7a6ccaf15 100644 --- a/Source/inv.h +++ b/Source/inv.h @@ -159,7 +159,7 @@ void CheckInvItem(bool isShiftHeld = false, bool isCtrlHeld = false); */ void CheckInvScrn(bool isShiftHeld, bool isCtrlHeld); void CheckItemStats(Player &player); -void InvGetItem(int pnum, Item *item, int ii); +void InvGetItem(int pnum, int ii); void AutoGetItem(int pnum, Item *item, int ii); int FindGetItem(int idx, uint16_t ci, int iseed); void SyncGetItem(Point position, int idx, uint16_t ci, int iseed); diff --git a/Source/msg.cpp b/Source/msg.cpp index d1000d524..67a23ff87 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -724,7 +724,7 @@ DWORD OnRequestGetItem(const TCmd *pCmd, Player &player) if (message.bPnum != MyPlayerId) SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); else - InvGetItem(MyPlayerId, &Items[ii], ii); + InvGetItem(MyPlayerId, ii); SetItemRecord(message.dwSeed, message.wCI, message.wIndx); } else if (!NetSendCmdReq2(CMD_REQUESTGITEM, MyPlayerId, message.bPnum, message)) { NetSendCmdExtra(message); @@ -751,9 +751,9 @@ DWORD OnGetItem(const TCmd *pCmd, int pnum) auto &player = Players[MyPlayerId]; ii = SyncPutItem(player, player.position.tile, message.wIndx, message.wCI, message.dwSeed, message.bId, message.bDur, message.bMDur, message.bCh, message.bMCh, message.wValue, message.dwBuff, message.wToHit, message.wMaxDam, message.bMinStr, message.bMinMag, message.bMinDex, message.bAC); if (ii != -1) - InvGetItem(MyPlayerId, &Items[ii], ii); + InvGetItem(MyPlayerId, ii); } else { - InvGetItem(MyPlayerId, &Items[ii], ii); + InvGetItem(MyPlayerId, ii); } } else { SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed);