From 12d3c8245d8dd486e79c61dbe4ea8796944931c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 17 Apr 2024 22:58:54 +0200 Subject: [PATCH] Fix prediction errors and incorrect rendering after changing map Fix game times and prediction not being updated when only exactly two snapshots have been received, due to the conditions `m_aReceivedSnapshots[...] >= 3`. These specific condition are not necessary and replaced with simpler checks whether the current snapshot is set. Some duplicate nested conditions are also removed. Pump the network first in `CClient::Update` before updating anything else, to ensure that snapshots are received from the network client before the game times and prediction are being updated based on the current snapshots. Fix current and previous game tick always being `0` on the first call of `IGameClient::OnNewSnapshot` when two snapshot have been received. Now, the game ticks are properly initialized from the two initial snapshots. Fix old inputs sometimes being used in prediction after changing map because inputs with tick `-1` were not being ignored. Ensure all snapshots and game times are properly cleared when entering the game. --- src/engine/client/client.cpp | 48 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 8e1b5af31..86581ee78 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -295,7 +295,7 @@ int *CClient::GetInput(int Tick, int IsDummy) const const int d = IsDummy ^ g_Config.m_ClDummy; for(int i = 0; i < 200; i++) { - if(m_aInputs[d][i].m_Tick <= Tick && (Best == -1 || m_aInputs[d][Best].m_Tick < m_aInputs[d][i].m_Tick)) + if(m_aInputs[d][i].m_Tick != -1 && m_aInputs[d][i].m_Tick <= Tick && (Best == -1 || m_aInputs[d][Best].m_Tick < m_aInputs[d][i].m_Tick)) Best = i; } @@ -357,20 +357,30 @@ void CClient::OnEnterGame(bool Dummy) m_aCurrentInput[Dummy] = 0; // reset snapshots - m_aapSnapshots[Dummy][SNAP_CURRENT] = 0; - m_aapSnapshots[Dummy][SNAP_PREV] = 0; + m_aapSnapshots[Dummy][SNAP_CURRENT] = nullptr; + m_aapSnapshots[Dummy][SNAP_PREV] = nullptr; m_aSnapshotStorage[Dummy].PurgeAll(); - // Also make gameclient aware that snapshots have been purged - GameClient()->InvalidateSnapshot(); m_aReceivedSnapshots[Dummy] = 0; m_aSnapshotParts[Dummy] = 0; - m_aPredTick[Dummy] = 0; + m_aSnapshotIncomingDataSize[Dummy] = 0; + m_SnapCrcErrors = 0; + // Also make gameclient aware that snapshots have been purged + GameClient()->InvalidateSnapshot(); + + // reset times m_aAckGameTick[Dummy] = -1; m_aCurrentRecvTick[Dummy] = 0; - m_aCurGameTick[Dummy] = 0; m_aPrevGameTick[Dummy] = 0; + m_aCurGameTick[Dummy] = 0; + m_aGameIntraTick[Dummy] = 0.0f; + m_aGameTickTime[Dummy] = 0.0f; + m_aGameIntraTickSincePrev[Dummy] = 0.0f; + m_aPredTick[Dummy] = 0; + m_aPredIntraTick[Dummy] = 0.0f; + m_aGameTime[Dummy].Init(0); + m_PredictedTime.Init(0); - if(Dummy == 0) + if(!Dummy) { m_LastDummyConnectTime = 0; } @@ -1846,6 +1856,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) m_aGameTime[Conn].Init((GameTick - 1) * time_freq() / GameTickSpeed()); m_aapSnapshots[Conn][SNAP_PREV] = m_aSnapshotStorage[Conn].m_pFirst; m_aapSnapshots[Conn][SNAP_CURRENT] = m_aSnapshotStorage[Conn].m_pLast; + m_aPrevGameTick[Conn] = m_aapSnapshots[Conn][SNAP_PREV]->m_Tick; + m_aCurGameTick[Conn] = m_aapSnapshots[Conn][SNAP_CURRENT]->m_Tick; if(!Dummy) { m_LocalStartTime = time_get(); @@ -2349,6 +2361,8 @@ void CClient::UpdateDemoIntraTimers() void CClient::Update() { + PumpNetwork(); + if(State() == IClient::STATE_DEMOPLAYBACK) { if(m_DemoPlayer.IsPlaying()) @@ -2394,7 +2408,7 @@ void CClient::Update() GameClient()->OnDummySwap(); } - if(m_aReceivedSnapshots[!g_Config.m_ClDummy] >= 3) + if(m_aapSnapshots[!g_Config.m_ClDummy][SNAP_CURRENT]) { // switch dummy snapshot int64_t Now = m_aGameTime[!g_Config.m_ClDummy].Get(time_get()); @@ -2415,14 +2429,14 @@ void CClient::Update() } } - if(m_aReceivedSnapshots[g_Config.m_ClDummy] >= 3) + if(m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]) { // switch snapshot bool Repredict = false; int64_t Now = m_aGameTime[g_Config.m_ClDummy].Get(time_get()); int64_t PredNow = m_PredictedTime.Get(time_get()); - if(m_LastDummy != (bool)g_Config.m_ClDummy && m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT] && m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) + if(m_LastDummy != (bool)g_Config.m_ClDummy && m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) { // Load snapshot for m_ClDummy GameClient()->OnNewSnapshot(); @@ -2444,14 +2458,11 @@ void CClient::Update() m_aCurGameTick[g_Config.m_ClDummy] = m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]->m_Tick; m_aPrevGameTick[g_Config.m_ClDummy] = m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]->m_Tick; - if(m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT] && m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) - { - GameClient()->OnNewSnapshot(); - Repredict = true; - } + GameClient()->OnNewSnapshot(); + Repredict = true; } - if(m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT] && m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) + if(m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) { int64_t CurTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]->m_Tick * time_freq() / GameTickSpeed(); int64_t PrevTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]->m_Tick * time_freq() / GameTickSpeed(); @@ -2554,9 +2565,6 @@ void CClient::Update() } #endif - // pump the network - PumpNetwork(); - if(m_pMapdownloadTask) { if(m_pMapdownloadTask->State() == EHttpState::DONE)