From c6b4302b216b5a07de5a8fe6f2f804c469190e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 1 Jul 2023 11:01:18 +0200 Subject: [PATCH 1/2] Prevent /swap with paused players Prevent swapping if either of the players is paused (i.e. their character is not in the gameworld), as this can cause them to be stuck in midair after swapping, which can be exploited to skip parts. --- src/game/server/ddracechat.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index 8b037d423..88750431d 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -750,6 +750,11 @@ void CGameContext::ConSwap(IConsole::IResult *pResult, void *pUserData) pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp", "Need to have started the map to swap with a player."); return; } + if(pSelf->m_World.m_Core.m_apCharacters[pResult->m_ClientID] == nullptr || pSelf->m_World.m_Core.m_apCharacters[TargetClientId] == nullptr) + { + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp", "You and the other player must not be paused."); + return; + } bool SwapPending = pSwapPlayer->m_SwapTargetsClientID != pResult->m_ClientID; if(SwapPending) From bc73ea30c742a2bd532bac95590a88d5f436c21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 28 Jun 2023 22:14:51 +0200 Subject: [PATCH 2/2] Use `std::vector` and `std::deque` instead of most `std::list`s Use `std::vector` in cases where elements are only inserted at the end of the collection. Use `std::deque` in cases where elements are only inserted/deleted at the beginning/end of the collection. Use `std::list` in the remaining single case where elements are being removed from arbitrary positions and added at either the beginning or the end of the collection. Adjust variables names. Don't use separate prefix for `std::deque`s and `std::list`s, as they are only used very rarely. Closes #6779. --- src/engine/client/client.cpp | 14 +++++++------- src/engine/client/client.h | 4 ++-- src/engine/server/server.cpp | 12 ++++++------ src/engine/server/server.h | 3 ++- .../client/prediction/entities/character.cpp | 6 +++--- src/game/client/prediction/gameworld.cpp | 9 ++++----- src/game/client/prediction/gameworld.h | 3 ++- src/game/client/race.cpp | 6 +++--- src/game/collision.cpp | 18 +++++++++--------- src/game/collision.h | 4 ++-- src/game/editor/editor.cpp | 8 ++++---- src/game/editor/editor.h | 4 ++-- src/game/editor/io.cpp | 4 ++-- src/game/server/entities/character.cpp | 6 +++--- src/game/server/entities/light.cpp | 7 +++---- src/game/server/gameworld.cpp | 9 ++++----- src/game/server/gameworld.h | 4 ++-- 17 files changed, 60 insertions(+), 61 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index e4856238f..f64a977fb 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2879,18 +2879,18 @@ void CClient::Update() if(State() == IClient::STATE_ONLINE) { - if(!m_lpEditJobs.empty()) + if(!m_EditJobs.empty()) { - std::shared_ptr e = m_lpEditJobs.front(); - if(e->Status() == IJob::STATE_DONE) + std::shared_ptr pJob = m_EditJobs.front(); + if(pJob->Status() == IJob::STATE_DONE) { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "Successfully saved the replay to %s!", e->Destination()); + char aBuf[IO_MAX_PATH_LENGTH + 64]; + str_format(aBuf, sizeof(aBuf), "Successfully saved the replay to %s!", pJob->Destination()); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "replay", aBuf); GameClient()->Echo(Localize("Successfully saved the replay!")); - m_lpEditJobs.pop_front(); + m_EditJobs.pop_front(); } } } @@ -3818,7 +3818,7 @@ void CClient::SaveReplay(const int Length, const char *pFilename) // Create a job to do this slicing in background because it can be a bit long depending on the file size std::shared_ptr pDemoEditTask = std::make_shared(GameClient()->NetVersion(), &m_SnapshotDelta, m_pStorage, pSrc, aFilename, StartTick, EndTick); Engine()->AddJob(pDemoEditTask); - m_lpEditJobs.push_back(pDemoEditTask); + m_EditJobs.push_back(pDemoEditTask); // And we restart the recorder DemoRecorder_StartReplayRecorder(); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 307ba3357..59be66856 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -3,7 +3,7 @@ #ifndef ENGINE_CLIENT_CLIENT_H #define ENGINE_CLIENT_CLIENT_H -#include +#include #include #include @@ -246,7 +246,7 @@ class CClient : public IClient, public CDemoPlayer::IListener CSnapshotDelta m_SnapshotDelta; - std::list> m_lpEditJobs; + std::deque> m_EditJobs; // bool m_CanReceiveServerCapabilities; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 7737233c8..8b1377a65 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1858,7 +1858,7 @@ static inline int GetCacheIndex(int Type, bool SendClient) CServer::CCache::CCache() { - m_Cache.clear(); + m_vCache.clear(); } CServer::CCache::~CCache() @@ -1873,12 +1873,12 @@ CServer::CCache::CCacheChunk::CCacheChunk(const void *pData, int Size) void CServer::CCache::AddChunk(const void *pData, int Size) { - m_Cache.emplace_back(pData, Size); + m_vCache.emplace_back(pData, Size); } void CServer::CCache::Clear() { - m_Cache.clear(); + m_vCache.clear(); } void CServer::CacheServerInfo(CCache *pCache, int Type, bool SendClients) @@ -2178,12 +2178,12 @@ void CServer::SendServerInfo(const NETADDR *pAddr, int Token, int Type, bool Sen Packet.m_Address = *pAddr; Packet.m_Flags = NETSENDFLAG_CONNLESS; - for(const auto &Chunk : pCache->m_Cache) + for(const auto &Chunk : pCache->m_vCache) { p.Reset(); if(Type == SERVERINFO_EXTENDED) { - if(&Chunk == &pCache->m_Cache.front()) + if(&Chunk == &pCache->m_vCache.front()) p.AddRaw(SERVERBROWSE_INFO_EXTENDED, sizeof(SERVERBROWSE_INFO_EXTENDED)); else p.AddRaw(SERVERBROWSE_INFO_EXTENDED_MORE, sizeof(SERVERBROWSE_INFO_EXTENDED_MORE)); @@ -2222,7 +2222,7 @@ void CServer::GetServerInfoSixup(CPacker *pPacker, int Token, bool SendClients) SendClients = SendClients && Token != -1; - CCache::CCacheChunk &FirstChunk = m_aSixupServerInfoCache[SendClients].m_Cache.front(); + CCache::CCacheChunk &FirstChunk = m_aSixupServerInfoCache[SendClients].m_vCache.front(); pPacker->AddRaw(FirstChunk.m_vData.data(), FirstChunk.m_vData.size()); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 2f8d6cffd..8e5285e63 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -350,11 +350,12 @@ public: public: CCacheChunk(const void *pData, int Size); CCacheChunk(const CCacheChunk &) = delete; + CCacheChunk(CCacheChunk &&) = default; std::vector m_vData; }; - std::list m_Cache; + std::vector m_vCache; CCache(); ~CCache(); diff --git a/src/game/client/prediction/entities/character.cpp b/src/game/client/prediction/entities/character.cpp index f05978fa6..39dcb8154 100644 --- a/src/game/client/prediction/entities/character.cpp +++ b/src/game/client/prediction/entities/character.cpp @@ -1029,9 +1029,9 @@ void CCharacter::DDRacePostCoreTick() HandleSkippableTiles(CurrentIndex); // handle Anti-Skip tiles - std::list Indices = Collision()->GetMapIndices(m_PrevPos, m_Pos); - if(!Indices.empty()) - for(int Index : Indices) + std::vector vIndices = Collision()->GetMapIndices(m_PrevPos, m_Pos); + if(!vIndices.empty()) + for(int Index : vIndices) HandleTiles(Index); else { diff --git a/src/game/client/prediction/gameworld.cpp b/src/game/client/prediction/gameworld.cpp index 7ae7ffc0b..63d250c22 100644 --- a/src/game/client/prediction/gameworld.cpp +++ b/src/game/client/prediction/gameworld.cpp @@ -287,10 +287,9 @@ CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, v return pClosest; } -std::list CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis) +std::vector CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis) { - std::list listOfChars; - + std::vector vpCharacters; CCharacter *pChr = (CCharacter *)FindFirst(CGameWorld::ENTTYPE_CHARACTER); for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) { @@ -303,11 +302,11 @@ std::list CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 float Len = distance(pChr->m_Pos, IntersectPos); if(Len < pChr->m_ProximityRadius + Radius) { - listOfChars.push_back(pChr); + vpCharacters.push_back(pChr); } } } - return listOfChars; + return vpCharacters; } void CGameWorld::ReleaseHooked(int ClientID) diff --git a/src/game/client/prediction/gameworld.h b/src/game/client/prediction/gameworld.h index 79d855dc6..696956f8c 100644 --- a/src/game/client/prediction/gameworld.h +++ b/src/game/client/prediction/gameworld.h @@ -7,6 +7,7 @@ #include #include +#include class CCollision; class CCharacter; @@ -49,7 +50,7 @@ public: // DDRace void ReleaseHooked(int ClientID); - std::list IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr); + std::vector IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr); int m_GameTick; int m_GameTickSpeed; diff --git a/src/game/client/race.cpp b/src/game/client/race.cpp index 57a08893b..d71c4a3ab 100644 --- a/src/game/client/race.cpp +++ b/src/game/client/race.cpp @@ -76,9 +76,9 @@ bool CRaceHelper::IsStart(CGameClient *pClient, vec2 Prev, vec2 Pos) } else { - std::list Indices = pCollision->GetMapIndices(Prev, Pos); - if(!Indices.empty()) - for(int &Indice : Indices) + std::vector vIndices = pCollision->GetMapIndices(Prev, Pos); + if(!vIndices.empty()) + for(int &Indice : vIndices) { if(pCollision->GetTileIndex(Indice) == TILE_START) return true; diff --git a/src/game/collision.cpp b/src/game/collision.cpp index 4d2f6560a..35718b589 100644 --- a/src/game/collision.cpp +++ b/src/game/collision.cpp @@ -880,9 +880,9 @@ int CCollision::GetMapIndex(vec2 Pos) const return -1; } -std::list CCollision::GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxIndices) const +std::vector CCollision::GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxIndices) const { - std::list Indices; + std::vector vIndices; float d = distance(PrevPos, Pos); int End(d + 1); if(!d) @@ -893,11 +893,11 @@ std::list CCollision::GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxInd if(TileExists(Index)) { - Indices.push_back(Index); - return Indices; + vIndices.push_back(Index); + return vIndices; } else - return Indices; + return vIndices; } else { @@ -911,14 +911,14 @@ std::list CCollision::GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxInd int Index = Ny * m_Width + Nx; if(TileExists(Index) && LastIndex != Index) { - if(MaxIndices && Indices.size() > MaxIndices) - return Indices; - Indices.push_back(Index); + if(MaxIndices && vIndices.size() > MaxIndices) + return vIndices; + vIndices.push_back(Index); LastIndex = Index; } } - return Indices; + return vIndices; } } diff --git a/src/game/collision.h b/src/game/collision.h index 2f7908df8..a8ae749c3 100644 --- a/src/game/collision.h +++ b/src/game/collision.h @@ -6,7 +6,7 @@ #include #include -#include +#include enum { @@ -73,7 +73,7 @@ public: int Entity(int x, int y, int Layer) const; int GetPureMapIndex(float x, float y) const; int GetPureMapIndex(vec2 Pos) const { return GetPureMapIndex(Pos.x, Pos.y); } - std::list GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxIndices = 0) const; + std::vector GetMapIndices(vec2 PrevPos, vec2 Pos, unsigned MaxIndices = 0) const; int GetMapIndex(vec2 Pos) const; bool TileExists(int Index) const; bool TileExistsNext(int Index) const; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 563906c4b..1cc39464f 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -6459,7 +6459,7 @@ void CEditor::RenderPressedKeys(CUIRect View) void CEditor::RenderSavingIndicator(CUIRect View) { - if(m_lpWriterFinishJobs.empty()) + if(m_WriterFinishJobs.empty()) return; UI()->MapScreen(); @@ -7065,10 +7065,10 @@ bool CEditor::PerformAutosave() void CEditor::HandleWriterFinishJobs() { - if(m_lpWriterFinishJobs.empty()) + if(m_WriterFinishJobs.empty()) return; - std::shared_ptr pJob = m_lpWriterFinishJobs.front(); + std::shared_ptr pJob = m_WriterFinishJobs.front(); if(pJob->Status() != IJob::STATE_DONE) return; @@ -7095,7 +7095,7 @@ void CEditor::HandleWriterFinishJobs() } } - m_lpWriterFinishJobs.pop_front(); + m_WriterFinishJobs.pop_front(); } void CEditor::OnUpdate() diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 7f3ef5ddf..4074b1f71 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -20,7 +20,7 @@ #include "auto_map.h" #include -#include +#include #include #include @@ -1154,7 +1154,7 @@ public: static const void *ms_pUiGotContext; CEditorMap m_Map; - std::list> m_lpWriterFinishJobs; + std::deque> m_WriterFinishJobs; int m_ShiftBy; diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index fd1dc8374..f7ea4dac9 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -34,7 +34,7 @@ struct CSoundSource_DEPRECATED bool CEditor::Save(const char *pFilename) { // Check if file with this name is already being saved at the moment - if(std::any_of(std::begin(m_lpWriterFinishJobs), std::end(m_lpWriterFinishJobs), [pFilename](const std::shared_ptr &Job) { return str_comp(pFilename, Job->GetFileName()) == 0; })) + if(std::any_of(std::begin(m_WriterFinishJobs), std::end(m_WriterFinishJobs), [pFilename](const std::shared_ptr &Job) { return str_comp(pFilename, Job->GetFileName()) == 0; })) return false; return m_Map.Save(pFilename); @@ -378,7 +378,7 @@ bool CEditorMap::Save(const char *pFileName) // finish the data file std::shared_ptr pWriterFinishJob = std::make_shared(pFileName, std::move(df)); m_pEditor->Engine()->AddJob(pWriterFinishJob); - m_pEditor->m_lpWriterFinishJobs.push_back(pWriterFinishJob); + m_pEditor->m_WriterFinishJobs.push_back(pWriterFinishJob); return true; } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 1d40933a7..27365d79f 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -2094,10 +2094,10 @@ void CCharacter::DDRacePostCoreTick() return; // handle Anti-Skip tiles - std::list Indices = Collision()->GetMapIndices(m_PrevPos, m_Pos); - if(!Indices.empty()) + std::vector vIndices = Collision()->GetMapIndices(m_PrevPos, m_Pos); + if(!vIndices.empty()) { - for(int &Index : Indices) + for(int &Index : vIndices) { HandleTiles(Index); if(!m_Alive) diff --git a/src/game/server/entities/light.cpp b/src/game/server/entities/light.cpp index f351745c2..957b8715b 100644 --- a/src/game/server/entities/light.cpp +++ b/src/game/server/entities/light.cpp @@ -28,11 +28,10 @@ CLight::CLight(CGameWorld *pGameWorld, vec2 Pos, float Rotation, int Length, bool CLight::HitCharacter() { - std::list HitCharacters = - GameServer()->m_World.IntersectedCharacters(m_Pos, m_To, 0.0f, 0); - if(HitCharacters.empty()) + std::vector vpHitCharacters = GameServer()->m_World.IntersectedCharacters(m_Pos, m_To, 0.0f, 0); + if(vpHitCharacters.empty()) return false; - for(auto *pChar : HitCharacters) + for(auto *pChar : vpHitCharacters) { if(m_Layer == LAYER_SWITCH && m_Number > 0 && !Switchers()[m_Number].m_aStatus[pChar->Team()]) continue; diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index adc53a933..7ea14b342 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -399,10 +399,9 @@ CCharacter *CGameWorld::ClosestCharacter(vec2 Pos, float Radius, const CEntity * return pClosest; } -std::list CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis) +std::vector CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis) { - std::list listOfChars; - + std::vector vpCharacters; CCharacter *pChr = (CCharacter *)FindFirst(CGameWorld::ENTTYPE_CHARACTER); for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) { @@ -416,11 +415,11 @@ std::list CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 if(Len < pChr->m_ProximityRadius + Radius) { pChr->m_Intersection = IntersectPos; - listOfChars.push_back(pChr); + vpCharacters.push_back(pChr); } } } - return listOfChars; + return vpCharacters; } void CGameWorld::ReleaseHooked(int ClientID) diff --git a/src/game/server/gameworld.h b/src/game/server/gameworld.h index 9cec9ae31..120a550a1 100644 --- a/src/game/server/gameworld.h +++ b/src/game/server/gameworld.h @@ -5,7 +5,7 @@ #include -#include +#include class CEntity; class CCharacter; @@ -165,7 +165,7 @@ public: Returns: Returns list with all Characters on line. */ - std::list IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr); + std::vector IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr); }; #endif