diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index b814d0959..b368ec3d1 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1016,11 +1016,11 @@ void CClient::Render() GameClient()->OnRender(); DebugRender(); - if(State() == IClient::STATE_ONLINE && g_Config.m_ClAntiPingLimit) - { - int64_t Now = time_get(); - g_Config.m_ClAntiPing = (m_PredictedTime.Get(Now) - m_aGameTime[g_Config.m_ClDummy].Get(Now)) * 1000 / (float)time_freq() > g_Config.m_ClAntiPingLimit; - } + // if(State() == IClient::STATE_ONLINE && g_Config.m_ClAntiPingLimit) + // { + // int64_t Now = time_get(); + // g_Config.m_ClAntiPing = (m_PredictedTime.Get(Now) - m_aGameTime[g_Config.m_ClDummy].Get(Now)) * 1000 / (float)time_freq() > g_Config.m_ClAntiPingLimit; + // } } const char *CClient::LoadMap(const char *pName, const char *pFilename, SHA256_DIGEST *pWantedSha256, unsigned WantedCrc) diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 02849f17c..7b401c3a4 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -13,7 +13,8 @@ // client MACRO_CONFIG_INT(ClPredict, cl_predict, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict client movements") MACRO_CONFIG_INT(ClPredictDummy, cl_predict_dummy, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict dummy movements") -MACRO_CONFIG_INT(ClAntiPingLimit, cl_antiping_limit, 0, 0, 200, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Antiping limit (0 to disable)") +MACRO_CONFIG_INT(ClAntiPingLimit, cl_antiping_limit, 0, 0, 200, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Adds delay to antiping (0 to disable)") +MACRO_CONFIG_INT(ClAntiPingpercent, cl_antiping_percent, 100, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "how far ahead Antiping predicts, ignored when antiping limit is used") MACRO_CONFIG_INT(ClAntiPing, cl_antiping, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable antiping, i. e. more aggressive prediction.") MACRO_CONFIG_INT(ClAntiPingPlayers, cl_antiping_players, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict other player's movement more aggressively (only enabled if cl_antiping is set to 1)") MACRO_CONFIG_INT(ClAntiPingGrenade, cl_antiping_grenade, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict grenades (only enabled if cl_antiping is set to 1)") diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp index d58dea182..becf052e0 100644 --- a/src/game/client/components/items.cpp +++ b/src/game/client/components/items.cpp @@ -58,9 +58,11 @@ void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemId) bool IsOtherTeam = (pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner)); + int predictTick = GameClient()->GetPredictionTick(); + float Ct; if(m_pClient->Predict() && m_pClient->AntiPingGrenade() && LocalPlayerInGame && !IsOtherTeam) - Ct = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); + Ct = ((float)(predictTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); else Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() + s_LastGameTickTime; if(Ct < 0) @@ -304,9 +306,11 @@ void CItems::RenderLaser(const CLaserData *pCurrent, bool IsPredicted) { Dir = normalize_pre_length(Pos - From, Len); + int predictTick = GameClient()->GetPredictionTick(); + float Ticks; if(IsPredicted) - Ticks = (float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy); + Ticks = (float)(predictTick - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy); else Ticks = (float)(Client()->GameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->IntraGameTick(g_Config.m_ClDummy); float Ms = (Ticks / Client()->GameTickSpeed()) * 1000.0f; @@ -377,7 +381,7 @@ void CItems::OnRender() auto &aSwitchers = GameClient()->Switchers(); if(UsePredicted) { - for(auto *pProj = (CProjectile *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity()) + for(auto *pProj = (CProjectile *)GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity()) { if(!IsSuper && pProj->m_Number > 0 && pProj->m_Number < (int)aSwitchers.size() && !aSwitchers[pProj->m_Number].m_aStatus[SwitcherTeam] && (pProj->m_Explosive ? BlinkingProjEx : BlinkingProj)) continue; @@ -385,7 +389,7 @@ void CItems::OnRender() CProjectileData Data = pProj->GetData(); RenderProjectile(&Data, pProj->GetId()); } - for(CEntity *pEnt = GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->NextEntity()) + for(CEntity *pEnt = GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->NextEntity()) { auto *const pLaser = dynamic_cast(pEnt); if(!pLaser || pLaser->GetOwner() < 0 || !GameClient()->m_aClients[pLaser->GetOwner()].m_IsPredictedLocal) @@ -393,7 +397,7 @@ void CItems::OnRender() CLaserData Data = pLaser->GetData(); RenderLaser(&Data, true); } - for(auto *pPickup = (CPickup *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PICKUP); pPickup; pPickup = (CPickup *)pPickup->NextEntity()) + for(auto *pPickup = (CPickup *)GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_PICKUP); pPickup; pPickup = (CPickup *)pPickup->NextEntity()) { if(!IsSuper && pPickup->m_Layer == LAYER_SWITCH && pPickup->m_Number > 0 && pPickup->m_Number < (int)aSwitchers.size() && !aSwitchers[pPickup->m_Number].m_aStatus[SwitcherTeam] && BlinkingPickup) continue; @@ -601,7 +605,10 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientId].m_Team != TEAM_SPECTATORS; if(!m_pClient->AntiPingGunfire() || !LocalPlayerInGame) return; - if(Client()->PredGameTick(g_Config.m_ClDummy) == pCurrent->m_StartTick) + + int predictTick = GameClient()->GetPredictionTick(); + + if(predictTick == pCurrent->m_StartTick) return; // get positions @@ -625,7 +632,7 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT Speed = pTuning->m_GunSpeed; } - float Pt = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); + float Pt = ((float)(predictTick - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); if(Pt < 0) return; // projectile haven't been shot yet diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 5ac98249a..7c07b850c 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -2100,6 +2100,25 @@ void CGameClient::UpdateEditorIngameMoved() } } +int CGameClient::GetPredictionTick() +{ + int predictTick = Client()->GetPredictionTime() * Client()->GameTickSpeed() / 1000.0f; + + float predictPercentage = 1 - g_Config.m_ClAntiPingpercent / 100.0f; + int predictMin = std::floor(predictTick * predictPercentage); + int predictMin2 = g_Config.m_ClAntiPingLimit * Client()->GameTickSpeed() / 1000.0f; + if (g_Config.m_ClAntiPingLimit != 0) + predictMin = predictMin2; + + predictTick = Client()->PredGameTick(g_Config.m_ClDummy) - predictMin; + + if(predictTick < Client()->GameTick(g_Config.m_ClDummy) + 1) + { + predictTick = Client()->GameTick(g_Config.m_ClDummy) + 1; + } + return predictTick; +} + void CGameClient::OnPredict() { // store the previous values so we can detect prediction errors @@ -2156,20 +2175,33 @@ void CGameClient::OnPredict() CCharacter *pDummyChar = 0; if(PredictDummy()) pDummyChar = m_PredictedWorld.GetCharacterById(m_PredictedDummyId); - + + int predictTick = GetPredictionTick(); // predict for(int Tick = Client()->GameTick(g_Config.m_ClDummy) + 1; Tick <= Client()->PredGameTick(g_Config.m_ClDummy); Tick++) { // fetch the previous characters - if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) + if(Tick == predictTick) { - m_PrevPredictedWorld.CopyWorld(&m_PredictedWorld); - m_PredictedPrevChar = pLocalChar->GetCore(); for(int i = 0; i < MAX_CLIENTS; i++) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) m_aClients[i].m_PrevPredicted = pChar->GetCore(); } + if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) + { + m_PredictedPrevChar = pLocalChar->GetCore(); + m_aClients[m_Snap.m_LocalClientId].m_PrevPredicted = pLocalChar->GetCore(); + + if(pDummyChar) + m_aClients[m_PredictedDummyId].m_PrevPredicted = pDummyChar->GetCore(); + } + + if(Tick == predictTick) + { + m_PrevPredictedWorld.CopyWorld(&m_PredictedWorld); + } + // optionally allow some movement in freeze by not predicting freeze the last one to two ticks if(g_Config.m_ClPredictFreeze == 2 && Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Client()->PredGameTick(g_Config.m_ClDummy) % 2 <= Tick) pLocalChar->m_CanMoveInFreeze = true; @@ -2193,14 +2225,22 @@ void CGameClient::OnPredict() m_PredictedWorld.Tick(); // fetch the current characters - if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) + if(Tick == predictTick) { - m_PredictedChar = pLocalChar->GetCore(); for(int i = 0; i < MAX_CLIENTS; i++) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) m_aClients[i].m_Predicted = pChar->GetCore(); } + if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) + { + m_PredictedChar = pLocalChar->GetCore(); + m_aClients[m_Snap.m_LocalClientId].m_Predicted = pLocalChar->GetCore(); + + if(pDummyChar) + m_aClients[m_PredictedDummyId].m_Predicted = pDummyChar->GetCore(); + } + for(int i = 0; i < MAX_CLIENTS; i++) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) { diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 175c0d414..0d6719026 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -499,6 +499,7 @@ public: CRenderTools m_RenderTools; void OnReset(); + int GetPredictionTick(); size_t ComponentCount() { return m_vpAll.size(); }