From c90dbe5ba07c5d449d1734774b6aa5f5de97e2fc Mon Sep 17 00:00:00 2001 From: Tater Date: Sat, 1 Jun 2024 22:22:49 -0500 Subject: [PATCH] Remove m_CurrentInput, Enforce 1 input per tick This converts m_aInputs from an unordered buffer of inputs that can be intended for any tick into a strict ring buffer that tracks the 100 inputs ahead of the current gametick and 100 inputs behind. The client is only allowed to have 1 input for each gametick in the buffer and cannot change inputs for ticks they have already sent. --- src/engine/server/server.cpp | 14 ++++++++------ src/engine/server/server.h | 3 +-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 2c9484bdf49..0cc56503160 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -207,7 +207,6 @@ void CServer::CClient::Reset() // reset input for(auto &Input : m_aInputs) Input.m_GameTick = -1; - m_CurrentInput = 0; m_Snapshots.PurgeAll(); m_LastAckedSnapshot = -1; @@ -1625,6 +1624,13 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) const int LastAckedSnapshot = Unpacker.GetInt(); int IntendedTick = Unpacker.GetInt(); int Size = Unpacker.GetInt(); + + int BufferPosition = IntendedTick % 200; + // The client is not allowed to change inputs for a tick they have already sent to the server + if(m_aClients[ClientId].m_aInputs[BufferPosition].m_GameTick == IntendedTick) + { + return; + } if(Unpacker.Error() || Size / 4 > MAX_INPUT_SIZE || IntendedTick < MIN_TICK || IntendedTick >= MAX_TICK) { return; @@ -1655,7 +1661,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) m_aClients[ClientId].m_LastInputTick = IntendedTick; - CClient::CInput *pInput = &m_aClients[ClientId].m_aInputs[m_aClients[ClientId].m_CurrentInput]; + CClient::CInput *pInput = &m_aClients[ClientId].m_aInputs[BufferPosition]; // TODO: This should probably not be here, the most recent input can be found by looping over the ring buffer // so we should not change the inputs original intended tick since we might need that information @@ -1676,12 +1682,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) GameServer()->OnClientPrepareInput(ClientId, pInput->m_aData); CClient::CInput LatestInput; - mem_copy(LatestInput.m_aData, pInput->m_aData, MAX_INPUT_SIZE * sizeof(int)); - m_aClients[ClientId].m_CurrentInput++; - m_aClients[ClientId].m_CurrentInput %= 200; - // call the mod with the fresh input data if(m_aClients[ClientId].m_State == CClient::STATE_INGAME) GameServer()->OnClientDirectInput(ClientId, LatestInput.m_aData); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index deed3cf60c9..4ed99fed7c3 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -147,8 +147,7 @@ class CServer : public IServer int m_LastInputTick; CSnapshotStorage m_Snapshots; - CInput m_aInputs[200]; // TODO: handle input better - int m_CurrentInput; + CInput m_aInputs[200]; char m_aName[MAX_NAME_LENGTH]; char m_aClan[MAX_CLAN_LENGTH];