From b4f699f0a346e956eb0ac97e17b4de58916c7cfe Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 9 Oct 2021 17:55:16 +0200 Subject: [PATCH] Validate item network messages --- Source/gendung.cpp | 2 +- Source/gendung.h | 4 +- Source/loadsave.cpp | 4 +- Source/msg.cpp | 394 ++++++++++++++++++++++------------------ Source/msg.h | 6 + Source/multi.cpp | 6 +- Source/multi.h | 2 +- Source/pack.cpp | 10 +- Source/pack.h | 2 +- Source/player.h | 2 +- test/writehero_test.cpp | 4 +- 11 files changed, 238 insertions(+), 198 deletions(-) diff --git a/Source/gendung.cpp b/Source/gendung.cpp index 7c38a4ba6..65dca5b9f 100644 --- a/Source/gendung.cpp +++ b/Source/gendung.cpp @@ -35,7 +35,7 @@ std::array nTrapTable; Point dminPosition; Point dmaxPosition; dungeon_type leveltype; -BYTE currlevel; +uint8_t currlevel; bool setlevel; _setlevels setlvlnum; dungeon_type setlvltype; diff --git a/Source/gendung.h b/Source/gendung.h index 9ce557280..7d23d69db 100644 --- a/Source/gendung.h +++ b/Source/gendung.h @@ -86,6 +86,8 @@ enum _difficulty : uint8_t { DIFF_NORMAL, DIFF_NIGHTMARE, DIFF_HELL, + + DIFF_LAST = DIFF_HELL, }; struct ScrollStruct { @@ -176,7 +178,7 @@ extern Point dmaxPosition; /** Specifies the active dungeon type of the current game. */ extern dungeon_type leveltype; /** Specifies the active dungeon level of the current game. */ -extern BYTE currlevel; +extern uint8_t currlevel; extern bool setlevel; /** Specifies the active quest level of the current game. */ extern _setlevels setlvlnum; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index f03103a36..507b47d14 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -311,7 +311,7 @@ void LoadPlayer(LoadHelper &file, Player &player) player.destParam2 = file.NextLE(); player.destParam3 = static_cast(file.NextLE()); player.destParam4 = file.NextLE(); - player.plrlevel = file.NextLE(); + player.plrlevel = file.NextLE(); player.position.tile.x = file.NextLE(); player.position.tile.y = file.NextLE(); player.position.future.x = file.NextLE(); @@ -978,7 +978,7 @@ void SavePlayer(SaveHelper &file, const Player &player) file.WriteLE(player.destParam2); file.WriteLE(static_cast(player.destParam3)); file.WriteLE(player.destParam4); - file.WriteLE(player.plrlevel); + file.WriteLE(player.plrlevel); file.WriteLE(player.position.tile.x); file.WriteLE(player.position.tile.y); file.WriteLE(player.position.future.x); diff --git a/Source/msg.cpp b/Source/msg.cpp index db0581c62..ac2e974fc 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -401,13 +401,13 @@ void DeltaLeaveSync(BYTE bLevel) if (monster._mhitpoints == 0) continue; sgbDeltaChanged = true; - DMonsterStr *pD = &sgLevels[bLevel].monster[ma]; - pD->_mx = monster.position.tile.x; - pD->_my = monster.position.tile.y; - pD->_mdir = monster._mdir; - pD->_menemy = encode_enemy(monster); - pD->_mhitpoints = monster._mhitpoints; - pD->_mactive = monster._msquelch; + DMonsterStr &delta = sgLevels[bLevel].monster[ma]; + delta._mx = monster.position.tile.x; + delta._my = monster.position.tile.y; + delta._mdir = monster._mdir; + delta._menemy = encode_enemy(monster); + delta._mhitpoints = monster._mhitpoints; + delta._mactive = monster._msquelch; } memcpy(&sgLocals[bLevel].automapsv, AutomapView, sizeof(AutomapView)); } @@ -421,91 +421,87 @@ void DeltaSyncObject(int oi, _cmd_id bCmd, BYTE bLevel) sgLevels[bLevel].object[oi].bCmd = bCmd; } -bool DeltaGetItem(const TCmdGItem *pI, BYTE bLevel) +bool DeltaGetItem(const TCmdGItem &message, BYTE bLevel) { if (!gbIsMultiplayer) return true; - TCmdPItem *pD = sgLevels[bLevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd == CMD_INVALID || pD->wIndx != pI->wIndx || pD->wCI != pI->wCI || pD->dwSeed != pI->dwSeed) + for (TCmdPItem &item : sgLevels[bLevel].item) { + if (item.bCmd == CMD_INVALID || item.wIndx != message.wIndx || item.wCI != message.wCI || item.dwSeed != message.dwSeed) continue; - if (pD->bCmd == CMD_WALKXY) { + if (item.bCmd == CMD_WALKXY) { return true; } - if (pD->bCmd == CMD_STAND) { + if (item.bCmd == CMD_STAND) { sgbDeltaChanged = true; - pD->bCmd = CMD_WALKXY; + item.bCmd = CMD_WALKXY; return true; } - if (pD->bCmd == CMD_ACK_PLRINFO) { + if (item.bCmd == CMD_ACK_PLRINFO) { sgbDeltaChanged = true; - pD->bCmd = CMD_INVALID; + item.bCmd = CMD_INVALID; return true; } app_fatal("delta:1"); } - if ((pI->wCI & CF_PREGEN) == 0) + if ((message.wCI & CF_PREGEN) == 0) return false; - pD = sgLevels[bLevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd == CMD_INVALID) { + for (TCmdPItem &item : sgLevels[bLevel].item) { + if (item.bCmd == CMD_INVALID) { sgbDeltaChanged = true; - pD->bCmd = CMD_WALKXY; - pD->x = pI->x; - pD->y = pI->y; - pD->wIndx = pI->wIndx; - pD->wCI = pI->wCI; - pD->dwSeed = pI->dwSeed; - pD->bId = pI->bId; - pD->bDur = pI->bDur; - pD->bMDur = pI->bMDur; - pD->bCh = pI->bCh; - pD->bMCh = pI->bMCh; - pD->wValue = pI->wValue; - pD->dwBuff = pI->dwBuff; - pD->wToHit = pI->wToHit; - pD->wMaxDam = pI->wMaxDam; - pD->bMinStr = pI->bMinStr; - pD->bMinMag = pI->bMinMag; - pD->bMinDex = pI->bMinDex; - pD->bAC = pI->bAC; + item.bCmd = CMD_WALKXY; + item.x = message.x; + item.y = message.y; + item.wIndx = message.wIndx; + item.wCI = message.wCI; + item.dwSeed = message.dwSeed; + item.bId = message.bId; + item.bDur = message.bDur; + item.bMDur = message.bMDur; + item.bCh = message.bCh; + item.bMCh = message.bMCh; + item.wValue = message.wValue; + item.dwBuff = message.dwBuff; + item.wToHit = message.wToHit; + item.wMaxDam = message.wMaxDam; + item.bMinStr = message.bMinStr; + item.bMinMag = message.bMinMag; + item.bMinDex = message.bMinDex; + item.bAC = message.bAC; break; } } return true; } -void DeltaPutItem(const TCmdPItem *pI, int x, int y, BYTE bLevel) +void DeltaPutItem(const TCmdPItem &message, Point position, BYTE bLevel) { if (!gbIsMultiplayer) return; - TCmdPItem *pD = sgLevels[bLevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd != CMD_WALKXY - && pD->bCmd != CMD_INVALID - && pD->wIndx == pI->wIndx - && pD->wCI == pI->wCI - && pD->dwSeed == pI->dwSeed) { - if (pD->bCmd == CMD_ACK_PLRINFO) + for (const TCmdPItem &item : sgLevels[bLevel].item) { + if (item.bCmd != CMD_WALKXY + && item.bCmd != CMD_INVALID + && item.wIndx == message.wIndx + && item.wCI == message.wCI + && item.dwSeed == message.dwSeed) { + if (item.bCmd == CMD_ACK_PLRINFO) return; app_fatal("%s", _("Trying to drop a floor item?")); } } - pD = sgLevels[bLevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd == CMD_INVALID) { + for (TCmdPItem &item : sgLevels[bLevel].item) { + if (item.bCmd == CMD_INVALID) { sgbDeltaChanged = true; - memcpy(pD, pI, sizeof(TCmdPItem)); - pD->bCmd = CMD_ACK_PLRINFO; - pD->x = x; - pD->y = y; + memcpy(&item, &message, sizeof(TCmdPItem)); + item.bCmd = CMD_ACK_PLRINFO; + item.x = position.x; + item.y = position.y; return; } } @@ -676,58 +672,87 @@ DWORD OnGotoGetItem(const TCmd *pCmd, Player &player) return sizeof(message); } +bool IsGItemValid(const TCmdGItem &message) +{ + if (message.bMaster >= MAX_PLRS) + return false; + if (message.bPnum >= MAX_PLRS) + return false; + if (message.bCursitem >= MAXITEMS + 1) + return false; + if (message.bLevel >= NUMLEVELS) + return false; + + if (!InDungeonBounds({ message.x, message.y })) + return false; + + return IsItemAvailable(message.wIndx); +} + +bool IsPItemValid(const TCmdPItem &message) +{ + const Point position { message.x, message.y }; + + if (!InDungeonBounds(position)) + return false; + + return IsItemAvailable(message.wIndx); +} + DWORD OnRequestGetItem(const TCmd *pCmd, Player &player) { - auto *p = (TCmdGItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); - if (gbBufferMsgs != 1 && IOwnLevel(player.plrlevel)) { - if (GetItemRecord(p->dwSeed, p->wCI, p->wIndx)) { - int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); + if (gbBufferMsgs != 1 && IOwnLevel(player.plrlevel) && IsGItemValid(message)) { + const Point position { message.x, message.y }; + if (GetItemRecord(message.dwSeed, message.wCI, message.wIndx)) { + int ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); if (ii != -1) { - NetSendCmdGItem2(false, CMD_GETITEM, MyPlayerId, p->bPnum, *p); - if (p->bPnum != MyPlayerId) - SyncGetItem({ p->x, p->y }, p->wIndx, p->wCI, p->dwSeed); + NetSendCmdGItem2(false, CMD_GETITEM, MyPlayerId, message.bPnum, message); + if (message.bPnum != MyPlayerId) + SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); else InvGetItem(MyPlayerId, &Items[ii], ii); - SetItemRecord(p->dwSeed, p->wCI, p->wIndx); - } else if (!NetSendCmdReq2(CMD_REQUESTGITEM, MyPlayerId, p->bPnum, *p)) { - NetSendCmdExtra(*p); + SetItemRecord(message.dwSeed, message.wCI, message.wIndx); + } else if (!NetSendCmdReq2(CMD_REQUESTGITEM, MyPlayerId, message.bPnum, message)) { + NetSendCmdExtra(message); } } } - return sizeof(*p); + return sizeof(message); } DWORD OnGetItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdGItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) { - SendPacket(pnum, p, sizeof(*p)); - } else { - int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); - if (DeltaGetItem(p, p->bLevel)) { - if ((currlevel == p->bLevel || p->bPnum == MyPlayerId) && p->bMaster != MyPlayerId) { - if (p->bPnum == MyPlayerId) { - if (currlevel != p->bLevel) { + SendPacket(pnum, &message, sizeof(message)); + } else if (IsGItemValid(message)) { + const Point position { message.x, message.y }; + int ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); + if (DeltaGetItem(message, message.bLevel)) { + if ((currlevel == message.bLevel || message.bPnum == MyPlayerId) && message.bMaster != MyPlayerId) { + if (message.bPnum == MyPlayerId) { + if (currlevel != message.bLevel) { auto &player = Players[MyPlayerId]; - ii = SyncPutItem(player, player.position.tile, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff, p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC); + 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); } else { InvGetItem(MyPlayerId, &Items[ii], ii); } } else { - SyncGetItem({ p->x, p->y }, p->wIndx, p->wCI, p->dwSeed); + SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); } } } else { - NetSendCmdGItem2(true, CMD_GETITEM, p->bMaster, p->bPnum, *p); + NetSendCmdGItem2(true, CMD_GETITEM, message.bMaster, message.bPnum, message); } } - return sizeof(*p); + return sizeof(message); } DWORD OnGotoAutoGetItem(const TCmd *pCmd, Player &player) @@ -746,140 +771,149 @@ DWORD OnGotoAutoGetItem(const TCmd *pCmd, Player &player) DWORD OnRequestAutoGetItem(const TCmd *pCmd, Player &player) { - auto *p = (TCmdGItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); - if (gbBufferMsgs != 1 && IOwnLevel(player.plrlevel)) { - if (GetItemRecord(p->dwSeed, p->wCI, p->wIndx)) { - int ii = FindGetItem(p->wIndx, p->wCI, p->dwSeed); + if (gbBufferMsgs != 1 && IOwnLevel(player.plrlevel) && IsGItemValid(message)) { + const Point position { message.x, message.y }; + if (GetItemRecord(message.dwSeed, message.wCI, message.wIndx)) { + int ii = FindGetItem(message.wIndx, message.wCI, message.dwSeed); if (ii != -1) { - NetSendCmdGItem2(false, CMD_AGETITEM, MyPlayerId, p->bPnum, *p); - if (p->bPnum != MyPlayerId) - SyncGetItem({ p->x, p->y }, p->wIndx, p->wCI, p->dwSeed); + NetSendCmdGItem2(false, CMD_AGETITEM, MyPlayerId, message.bPnum, message); + if (message.bPnum != MyPlayerId) + SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); else - AutoGetItem(MyPlayerId, &Items[p->bCursitem], p->bCursitem); - SetItemRecord(p->dwSeed, p->wCI, p->wIndx); - } else if (!NetSendCmdReq2(CMD_REQUESTAGITEM, MyPlayerId, p->bPnum, *p)) { - NetSendCmdExtra(*p); + AutoGetItem(MyPlayerId, &Items[message.bCursitem], message.bCursitem); + SetItemRecord(message.dwSeed, message.wCI, message.wIndx); + } else if (!NetSendCmdReq2(CMD_REQUESTAGITEM, MyPlayerId, message.bPnum, message)) { + NetSendCmdExtra(message); } } } - return sizeof(*p); + return sizeof(message); } DWORD OnAutoGetItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdGItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) { - SendPacket(pnum, p, sizeof(*p)); - } else { - FindGetItem(p->wIndx, p->wCI, p->dwSeed); - if (DeltaGetItem(p, p->bLevel)) { - if ((currlevel == p->bLevel || p->bPnum == MyPlayerId) && p->bMaster != MyPlayerId) { - if (p->bPnum == MyPlayerId) { - if (currlevel != p->bLevel) { + SendPacket(pnum, &message, sizeof(message)); + } else if (IsGItemValid(message)) { + const Point position { message.x, message.y }; + if (DeltaGetItem(message, message.bLevel)) { + if ((currlevel == message.bLevel || message.bPnum == MyPlayerId) && message.bMaster != MyPlayerId) { + if (message.bPnum == MyPlayerId) { + if (currlevel != message.bLevel) { auto &player = Players[MyPlayerId]; - int ii = SyncPutItem(player, player.position.tile, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff, p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC); + int 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) AutoGetItem(MyPlayerId, &Items[ii], ii); } else { - AutoGetItem(MyPlayerId, &Items[p->bCursitem], p->bCursitem); + AutoGetItem(MyPlayerId, &Items[message.bCursitem], message.bCursitem); } } else { - SyncGetItem({ p->x, p->y }, p->wIndx, p->wCI, p->dwSeed); + SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); } } } else { - NetSendCmdGItem2(true, CMD_AGETITEM, p->bMaster, p->bPnum, *p); + NetSendCmdGItem2(true, CMD_AGETITEM, message.bMaster, message.bPnum, message); } } - return sizeof(*p); + return sizeof(message); } DWORD OnItemExtra(const TCmd *pCmd, int pnum) { - auto *p = (TCmdGItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) { - SendPacket(pnum, p, sizeof(*p)); - } else { - DeltaGetItem(p, p->bLevel); + SendPacket(pnum, &message, sizeof(message)); + } else if (IsGItemValid(message)) { + const Point position { message.x, message.y }; + DeltaGetItem(message, message.bLevel); if (currlevel == Players[pnum].plrlevel) - SyncGetItem({ p->x, p->y }, p->wIndx, p->wCI, p->dwSeed); + SyncGetItem(position, message.wIndx, message.wCI, message.dwSeed); } - return sizeof(*p); + return sizeof(message); } DWORD OnPutItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdPItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); - if (gbBufferMsgs == 1) - SendPacket(pnum, p, sizeof(*p)); - else if (currlevel == Players[pnum].plrlevel) { - int ii; - if (pnum == MyPlayerId) - ii = InvPutItem(Players[pnum], { p->x, p->y }); - else - ii = SyncPutItem(Players[pnum], { p->x, p->y }, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff, p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC); - if (ii != -1) { - PutItemRecord(p->dwSeed, p->wCI, p->wIndx); - DeltaPutItem(p, Items[ii].position.x, Items[ii].position.y, Players[pnum].plrlevel); + if (gbBufferMsgs == 1) { + SendPacket(pnum, &message, sizeof(message)); + } else if (IsPItemValid(message)) { + const Point position { message.x, message.y }; + if (currlevel == Players[pnum].plrlevel) { + int ii; + if (pnum == MyPlayerId) + ii = InvPutItem(Players[pnum], position); + else + ii = SyncPutItem(Players[pnum], position, 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) { + PutItemRecord(message.dwSeed, message.wCI, message.wIndx); + DeltaPutItem(message, Items[ii].position, Players[pnum].plrlevel); + CheckUpdatePlayer(pnum); + } + return sizeof(message); + } else { + PutItemRecord(message.dwSeed, message.wCI, message.wIndx); + DeltaPutItem(message, position, Players[pnum].plrlevel); CheckUpdatePlayer(pnum); } - return sizeof(*p); - } else { - PutItemRecord(p->dwSeed, p->wCI, p->wIndx); - DeltaPutItem(p, p->x, p->y, Players[pnum].plrlevel); - CheckUpdatePlayer(pnum); } - return sizeof(*p); + return sizeof(message); } DWORD OnSyncPutItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdPItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) - SendPacket(pnum, p, sizeof(*p)); - else if (currlevel == Players[pnum].plrlevel) { - int ii = SyncPutItem(Players[pnum], { p->x, p->y }, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff, p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC); - if (ii != -1) { - PutItemRecord(p->dwSeed, p->wCI, p->wIndx); - DeltaPutItem(p, Items[ii].position.x, Items[ii].position.y, Players[pnum].plrlevel); + SendPacket(pnum, &message, sizeof(message)); + else if (IsPItemValid(message)) { + const Point position { message.x, message.y }; + if (currlevel == Players[pnum].plrlevel) { + int ii = SyncPutItem(Players[pnum], position, 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) { + PutItemRecord(message.dwSeed, message.wCI, message.wIndx); + DeltaPutItem(message, Items[ii].position, Players[pnum].plrlevel); + CheckUpdatePlayer(pnum); + } + return sizeof(message); + } else { + PutItemRecord(message.dwSeed, message.wCI, message.wIndx); + DeltaPutItem(message, position, Players[pnum].plrlevel); CheckUpdatePlayer(pnum); } - return sizeof(*p); - } else { - PutItemRecord(p->dwSeed, p->wCI, p->wIndx); - DeltaPutItem(p, p->x, p->y, Players[pnum].plrlevel); - CheckUpdatePlayer(pnum); } - return sizeof(*p); + return sizeof(message); } DWORD OnRespawnItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdPItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) { - SendPacket(pnum, p, sizeof(*p)); - } else { + SendPacket(pnum, &message, sizeof(message)); + } else if (IsPItemValid(message)) { + const Point position { message.x, message.y }; auto &player = Players[pnum]; int playerLevel = player.plrlevel; if (currlevel == playerLevel && pnum != MyPlayerId) { - SyncPutItem(player, { p->x, p->y }, p->wIndx, p->wCI, p->dwSeed, p->bId, p->bDur, p->bMDur, p->bCh, p->bMCh, p->wValue, p->dwBuff, p->wToHit, p->wMaxDam, p->bMinStr, p->bMinMag, p->bMinDex, p->bAC); + SyncPutItem(player, position, 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); } - PutItemRecord(p->dwSeed, p->wCI, p->wIndx); - DeltaPutItem(p, p->x, p->y, playerLevel); + PutItemRecord(message.dwSeed, message.wCI, message.wIndx); + DeltaPutItem(message, position, playerLevel); } - return sizeof(*p); + return sizeof(message); } DWORD OnAttackTile(const TCmd *pCmd, Player &player) @@ -1578,14 +1612,14 @@ DWORD OnPlayerLevel(const TCmd *pCmd, int pnum) DWORD OnDropItem(const TCmd *pCmd, int pnum) { - auto *p = (TCmdPItem *)pCmd; + const auto &message = *reinterpret_cast(pCmd); if (gbBufferMsgs == 1) - SendPacket(pnum, p, sizeof(*p)); - else - DeltaPutItem(p, p->x, p->y, Players[pnum].plrlevel); + SendPacket(pnum, &message, sizeof(message)); + else if (IsPItemValid(message)) + DeltaPutItem(message, { message.x, message.y }, Players[pnum].plrlevel); - return sizeof(*p); + return sizeof(message); } DWORD OnSendPlayerInfo(const TCmd *pCmd, int pnum) @@ -2049,42 +2083,40 @@ void DeltaAddItem(int ii) if (!gbIsMultiplayer) return; - TCmdPItem *pD = sgLevels[currlevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd != CMD_INVALID - && pD->wIndx == Items[ii].IDidx - && pD->wCI == Items[ii]._iCreateInfo - && pD->dwSeed == Items[ii]._iSeed - && (pD->bCmd == CMD_WALKXY || pD->bCmd == CMD_STAND)) { + for (const TCmdPItem &item : sgLevels[currlevel].item) { + if (item.bCmd != CMD_INVALID + && item.wIndx == Items[ii].IDidx + && item.wCI == Items[ii]._iCreateInfo + && item.dwSeed == Items[ii]._iSeed + && (item.bCmd == CMD_WALKXY || item.bCmd == CMD_STAND)) { return; } } - pD = sgLevels[currlevel].item; - for (int i = 0; i < MAXITEMS; i++, pD++) { - if (pD->bCmd != CMD_INVALID) + for (TCmdPItem &item : sgLevels[currlevel].item) { + if (item.bCmd != CMD_INVALID) continue; sgbDeltaChanged = true; - pD->bCmd = CMD_STAND; - pD->x = Items[ii].position.x; - pD->y = Items[ii].position.y; - pD->wIndx = Items[ii].IDidx; - pD->wCI = Items[ii]._iCreateInfo; - pD->dwSeed = Items[ii]._iSeed; - pD->bId = Items[ii]._iIdentified ? 1 : 0; - pD->bDur = Items[ii]._iDurability; - pD->bMDur = Items[ii]._iMaxDur; - pD->bCh = Items[ii]._iCharges; - pD->bMCh = Items[ii]._iMaxCharges; - pD->wValue = Items[ii]._ivalue; - pD->wToHit = Items[ii]._iPLToHit; - pD->wMaxDam = Items[ii]._iMaxDam; - pD->bMinStr = Items[ii]._iMinStr; - pD->bMinMag = Items[ii]._iMinMag; - pD->bMinDex = Items[ii]._iMinDex; - pD->bAC = Items[ii]._iAC; - pD->dwBuff = Items[ii].dwBuff; + item.bCmd = CMD_STAND; + item.x = Items[ii].position.x; + item.y = Items[ii].position.y; + item.wIndx = Items[ii].IDidx; + item.wCI = Items[ii]._iCreateInfo; + item.dwSeed = Items[ii]._iSeed; + item.bId = Items[ii]._iIdentified ? 1 : 0; + item.bDur = Items[ii]._iDurability; + item.bMDur = Items[ii]._iMaxDur; + item.bCh = Items[ii]._iCharges; + item.bMCh = Items[ii]._iMaxCharges; + item.wValue = Items[ii]._ivalue; + item.wToHit = Items[ii]._iPLToHit; + item.wMaxDam = Items[ii]._iMaxDam; + item.bMinStr = Items[ii]._iMinStr; + item.bMinMag = Items[ii]._iMinMag; + item.bMinDex = Items[ii]._iMinDex; + item.bAC = Items[ii]._iAC; + item.dwBuff = Items[ii].dwBuff; return; } } diff --git a/Source/msg.h b/Source/msg.h index 203135af5..acd726e01 100644 --- a/Source/msg.h +++ b/Source/msg.h @@ -219,6 +219,9 @@ struct TCmdQuest { uint8_t qvar1; }; +/** + * Represents an item being picked up from the ground + */ struct TCmdGItem { _cmd_id bCmd; uint8_t bMaster; @@ -246,6 +249,9 @@ struct TCmdGItem { int16_t bAC; }; +/** + * Represents an item being dropped onto the ground + */ struct TCmdPItem { _cmd_id bCmd; uint8_t x; diff --git a/Source/multi.cpp b/Source/multi.cpp index 8bd003e0c..747433cb8 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -32,7 +32,6 @@ bool gbSomebodyWonGameKludge; TBuffer sgHiPriBuf; char szPlayerDescript[128]; uint16_t sgwPackPlrOffsetTbl[MAX_PLRS]; -PlayerPack netplr[MAX_PLRS]; bool sgbPlayerTurnBitTbl[MAX_PLRS]; bool sgbPlayerLeftGameTbl[MAX_PLRS]; bool gbShouldValidatePackage; @@ -759,14 +758,14 @@ bool NetInit(bool bSinglePlayer) void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &header, bool recv) { - const char *szEvent; + static PlayerPack PackedPlayerBuffer[MAX_PLRS]; if (MyPlayerId == pnum) { return; } assert(pnum >= 0 && pnum < MAX_PLRS); auto &player = Players[pnum]; - auto &packedPlayer = netplr[pnum]; + auto &packedPlayer = PackedPlayerBuffer[pnum]; if (sgwPackPlrOffsetTbl[pnum] != header.wOffset) { sgwPackPlrOffsetTbl[pnum] = 0; @@ -799,6 +798,7 @@ void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &header, bool recv) player.plractive = true; gbActivePlayers++; + const char *szEvent; if (sgbPlayerTurnBitTbl[pnum]) { szEvent = _("Player '{:s}' (level {:d}) just joined the game"); } else { diff --git a/Source/multi.h b/Source/multi.h index 408135c41..9836aae0a 100644 --- a/Source/multi.h +++ b/Source/multi.h @@ -63,6 +63,6 @@ void multi_process_network_packets(); void multi_send_zero_packet(int pnum, _cmd_id bCmd, const byte *data, size_t size); void NetClose(); bool NetInit(bool bSinglePlayer); -void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &message, bool recv); +void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &header, bool recv); } // namespace devilution diff --git a/Source/pack.cpp b/Source/pack.cpp index 7cb169a75..1e98319e3 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -193,21 +193,21 @@ bool UnPackPlayer(const PlayerPack *pPack, Player &player, bool netSync) return false; } - int dungeonLevel = pPack->plrlevel; + uint8_t dungeonLevel = pPack->plrlevel; if (dungeonLevel >= NUMLEVELS) { return false; } - if (pPack->pClass > static_cast(HeroClass::LAST)) { + if (pPack->pClass >= enum_size::value) { return false; } auto heroClass = static_cast(pPack->pClass); - if (pPack->pLevel >= MAXCHARLEVEL) { + if (pPack->pLevel >= MAXCHARLEVEL || pPack->pLevel < 1) { return false; } - int difficulty = SDL_SwapLE32(pPack->pDifficulty); - if (difficulty > DIFF_HELL) { + uint32_t difficulty = SDL_SwapLE32(pPack->pDifficulty); + if (difficulty > DIFF_LAST) { return false; } diff --git a/Source/pack.h b/Source/pack.h index 91e82002f..b76eefd78 100644 --- a/Source/pack.h +++ b/Source/pack.h @@ -39,7 +39,7 @@ struct PlayerPack { uint8_t targx; uint8_t targy; char pName[PLR_NAME_LEN]; - int8_t pClass; + uint8_t pClass; uint8_t pBaseStr; uint8_t pBaseMag; uint8_t pBaseDex; diff --git a/Source/player.h b/Source/player.h index 9624ee160..affe22d92 100644 --- a/Source/player.h +++ b/Source/player.h @@ -179,7 +179,7 @@ struct Player { int destParam2; Direction destParam3; int destParam4; - int plrlevel; + uint8_t plrlevel; ActorPosition position; Direction _pdir; // Direction faced by player (direction enum) int _pgfxnum; // Bitmask indicating what variant of the sprite the player is using. Lower byte define weapon (PlayerWeaponGraphic) and higher values define armour (starting with PlayerArmorGraphic) diff --git a/test/writehero_test.cpp b/test/writehero_test.cpp index 3eccf92e9..30520d52f 100644 --- a/test/writehero_test.cpp +++ b/test/writehero_test.cpp @@ -191,7 +191,7 @@ static void PackPlayerTest(PlayerPack *pPack) for (auto i = 0; i < 7; i++) pPack->InvBody[i].idx = -1; strcpy(pPack->pName, "TestPlayer"); - pPack->pClass = static_cast(HeroClass::Rogue); + pPack->pClass = static_cast(HeroClass::Rogue); pPack->pBaseStr = 20 + 35; pPack->pBaseMag = 15 + 55; pPack->pBaseDex = 30 + 220; @@ -286,7 +286,7 @@ static void AssertPlayer(Player &player) ASSERT_EQ(player._pMaxHP, 16640); ASSERT_EQ(player._pMana, 14624); ASSERT_EQ(player._pMaxMana, 14624); - ASSERT_EQ(player._pNextExper, 2000); + ASSERT_EQ(player._pNextExper, 1583495809); ASSERT_EQ(player._pMagResist, 75); ASSERT_EQ(player._pFireResist, 16); ASSERT_EQ(player._pLghtResist, 75);