Revert "Remove the dummy prediction"

This reverts commit 681f30950c.
This commit is contained in:
trml 2020-04-18 22:16:25 +02:00
parent 56c55d4081
commit 99baf219d0
5 changed files with 50 additions and 14 deletions

View file

@ -132,8 +132,8 @@ public:
virtual int MapDownloadTotalsize() = 0; virtual int MapDownloadTotalsize() = 0;
// input // input
virtual int *GetInput(int Tick) = 0; virtual int *GetInput(int Tick, int IsDummy = 0) = 0;
virtual int *GetDirectInput(int Tick) = 0; virtual int *GetDirectInput(int Tick, int IsDummy = 0) = 0;
// remote console // remote console
virtual void RconAuth(const char *pUsername, const char *pPassword) = 0; virtual void RconAuth(const char *pUsername, const char *pPassword) = 0;

View file

@ -502,7 +502,7 @@ void CClient::SendInput()
Msg.AddInt(m_PredTick[i]); Msg.AddInt(m_PredTick[i]);
Msg.AddInt(Size); Msg.AddInt(Size);
m_aInputs[i][m_CurrentInput[i]].m_Tick = m_PredTick[i]; m_aInputs[i][m_CurrentInput[i]].m_Tick = m_PredTick[g_Config.m_ClDummy];
m_aInputs[i][m_CurrentInput[i]].m_PredictedTime = m_PredictedTime.Get(Now); m_aInputs[i][m_CurrentInput[i]].m_PredictedTime = m_PredictedTime.Get(Now);
m_aInputs[i][m_CurrentInput[i]].m_Time = Now; m_aInputs[i][m_CurrentInput[i]].m_Time = Now;
@ -529,12 +529,13 @@ const char *CClient::LatestVersion()
} }
// TODO: OPT: do this a lot smarter! // TODO: OPT: do this a lot smarter!
int *CClient::GetInput(int Tick) int *CClient::GetInput(int Tick, int IsDummy)
{ {
int Best = -1; int Best = -1;
const int d = IsDummy ^ g_Config.m_ClDummy;
for(int i = 0; i < 200; i++) for(int i = 0; i < 200; i++)
{ {
if(m_aInputs[g_Config.m_ClDummy][i].m_Tick <= Tick && (Best == -1 || m_aInputs[g_Config.m_ClDummy][Best].m_Tick < m_aInputs[g_Config.m_ClDummy][i].m_Tick)) if(m_aInputs[d][i].m_Tick <= Tick && (Best == -1 || m_aInputs[d][Best].m_Tick < m_aInputs[d][i].m_Tick))
Best = i; Best = i;
} }
@ -543,11 +544,12 @@ int *CClient::GetInput(int Tick)
return 0; return 0;
} }
int *CClient::GetDirectInput(int Tick) int *CClient::GetDirectInput(int Tick, int IsDummy)
{ {
const int d = IsDummy ^ g_Config.m_ClDummy;
for(int i = 0; i < 200; i++) for(int i = 0; i < 200; i++)
if(m_aInputs[g_Config.m_ClDummy][i].m_Tick == Tick) if(m_aInputs[d][i].m_Tick == Tick)
return (int *)m_aInputs[g_Config.m_ClDummy][i].m_aData; return (int *)m_aInputs[d][i].m_aData;
return 0; return 0;
} }

View file

@ -274,8 +274,8 @@ public:
void SendInput(); void SendInput();
// TODO: OPT: do this a lot smarter! // TODO: OPT: do this a lot smarter!
virtual int *GetInput(int Tick); virtual int *GetInput(int Tick, int IsDummy);
virtual int *GetDirectInput(int Tick); virtual int *GetDirectInput(int Tick, int IsDummy);
const char *LatestVersion(); const char *LatestVersion();

View file

@ -397,6 +397,7 @@ void CGameClient::OnDummySwap()
int tmp = m_DummyInput.m_Fire; int tmp = m_DummyInput.m_Fire;
m_DummyInput = m_pControls->m_InputData[!g_Config.m_ClDummy]; m_DummyInput = m_pControls->m_InputData[!g_Config.m_ClDummy];
m_pControls->m_InputData[g_Config.m_ClDummy].m_Fire = tmp; m_pControls->m_InputData[g_Config.m_ClDummy].m_Fire = tmp;
m_IsDummySwapping = 1;
} }
int CGameClient::OnSnapInput(int *pData, bool Dummy, bool Force) int CGameClient::OnSnapInput(int *pData, bool Dummy, bool Force)
@ -490,6 +491,7 @@ void CGameClient::OnConnected()
m_GameWorld.Clear(); m_GameWorld.Clear();
m_GameWorld.m_WorldConfig.m_InfiniteAmmo = true; m_GameWorld.m_WorldConfig.m_InfiniteAmmo = true;
m_PredictedDummyID = -1;
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
m_aLastWorldCharacters[i].m_Alive = false; m_aLastWorldCharacters[i].m_Alive = false;
LoadMapSettings(); LoadMapSettings();
@ -673,6 +675,7 @@ void CGameClient::OnDummyDisconnect()
m_DDRaceMsgSent[1] = false; m_DDRaceMsgSent[1] = false;
m_ShowOthers[1] = -1; m_ShowOthers[1] = -1;
m_LastNewPredictedTick[1] = -1; m_LastNewPredictedTick[1] = -1;
m_PredictedDummyID = -1;
} }
int CGameClient::GetLastRaceTick() int CGameClient::GetLastRaceTick()
@ -1516,6 +1519,12 @@ void CGameClient::OnNewSnapshot()
m_pEffects->AirJump(Pos); m_pEffects->AirJump(Pos);
} }
static int PrevLocalID = -1;
if(m_Snap.m_LocalClientID != PrevLocalID)
m_PredictedDummyID = PrevLocalID;
PrevLocalID = m_Snap.m_LocalClientID;
m_IsDummySwapping = 0;
// update prediction data // update prediction data
if(Client()->State() != IClient::STATE_DEMOPLAYBACK) if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
UpdatePrediction(); UpdatePrediction();
@ -1552,6 +1561,7 @@ void CGameClient::OnPredict()
aBeforeRender[i] = GetSmoothPos(i); aBeforeRender[i] = GetSmoothPos(i);
// init // init
bool Dummy = g_Config.m_ClDummy ^ m_IsDummySwapping;
m_PredictedWorld.CopyWorld(&m_GameWorld); m_PredictedWorld.CopyWorld(&m_GameWorld);
// don't predict inactive players // don't predict inactive players
@ -1563,6 +1573,9 @@ void CGameClient::OnPredict()
CCharacter *pLocalChar = m_PredictedWorld.GetCharacterByID(m_Snap.m_LocalClientID); CCharacter *pLocalChar = m_PredictedWorld.GetCharacterByID(m_Snap.m_LocalClientID);
if(!pLocalChar) if(!pLocalChar)
return; return;
CCharacter *pDummyChar = 0;
if(PredictDummy())
pDummyChar = m_PredictedWorld.GetCharacterByID(m_PredictedDummyID);
// predict // predict
for(int Tick = Client()->GameTick(g_Config.m_ClDummy) + 1; Tick <= Client()->PredGameTick(g_Config.m_ClDummy); Tick++) for(int Tick = Client()->GameTick(g_Config.m_ClDummy) + 1; Tick <= Client()->PredGameTick(g_Config.m_ClDummy); Tick++)
@ -1582,12 +1595,17 @@ void CGameClient::OnPredict()
pLocalChar->m_CanMoveInFreeze = true; pLocalChar->m_CanMoveInFreeze = true;
// apply inputs and tick // apply inputs and tick
CNetObj_PlayerInput *pInputData = (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick); CNetObj_PlayerInput *pInputData = (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick, m_IsDummySwapping);
CNetObj_PlayerInput *pDummyInputData = !pDummyChar ? 0 : (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick, m_IsDummySwapping^1);
if(pInputData) if(pInputData)
pLocalChar->OnDirectInput(pInputData); pLocalChar->OnDirectInput(pInputData);
if(pDummyInputData)
pDummyChar->OnDirectInput(pDummyInputData);
m_PredictedWorld.m_GameTick = Tick; m_PredictedWorld.m_GameTick = Tick;
if(pInputData) if(pInputData)
pLocalChar->OnPredictedInput(pInputData); pLocalChar->OnPredictedInput(pInputData);
if(pDummyInputData)
pDummyChar->OnPredictedInput(pDummyInputData);
m_PredictedWorld.Tick(); m_PredictedWorld.Tick();
// fetch the current characters // fetch the current characters
@ -1607,9 +1625,9 @@ void CGameClient::OnPredict()
} }
// check if we want to trigger effects // check if we want to trigger effects
if(Tick > m_LastNewPredictedTick[g_Config.m_ClDummy]) if(Tick > m_LastNewPredictedTick[Dummy])
{ {
m_LastNewPredictedTick[g_Config.m_ClDummy] = Tick; m_LastNewPredictedTick[Dummy] = Tick;
m_NewPredictedTick = true; m_NewPredictedTick = true;
vec2 Pos = pLocalChar->Core()->m_Pos; vec2 Pos = pLocalChar->Core()->m_Pos;
int Events = pLocalChar->Core()->m_TriggeredEvents; int Events = pLocalChar->Core()->m_TriggeredEvents;
@ -2052,6 +2070,9 @@ void CGameClient::UpdatePrediction()
} }
CCharacter *pLocalChar = m_GameWorld.GetCharacterByID(m_Snap.m_LocalClientID); CCharacter *pLocalChar = m_GameWorld.GetCharacterByID(m_Snap.m_LocalClientID);
CCharacter *pDummyChar = 0;
if(PredictDummy())
pDummyChar = m_GameWorld.GetCharacterByID(m_PredictedDummyID);
// update strong and weak hook // update strong and weak hook
if(pLocalChar && AntiPingPlayers()) if(pLocalChar && AntiPingPlayers())
@ -2089,11 +2110,18 @@ void CGameClient::UpdatePrediction()
for(int Tick = m_GameWorld.GameTick() + 1; Tick <= Client()->GameTick(g_Config.m_ClDummy); Tick++) for(int Tick = m_GameWorld.GameTick() + 1; Tick <= Client()->GameTick(g_Config.m_ClDummy); Tick++)
{ {
CNetObj_PlayerInput *pInput = (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick); CNetObj_PlayerInput *pInput = (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick);
CNetObj_PlayerInput *pDummyInput = 0;
if(pDummyChar)
pDummyInput = (CNetObj_PlayerInput*) Client()->GetDirectInput(Tick, 1);
if(pInput) if(pInput)
pLocalChar->OnDirectInput(pInput); pLocalChar->OnDirectInput(pInput);
if(pDummyInput)
pDummyChar->OnDirectInput(pDummyInput);
m_GameWorld.m_GameTick = Tick; m_GameWorld.m_GameTick = Tick;
if(pInput) if(pInput)
pLocalChar->OnPredictedInput(pInput); pLocalChar->OnPredictedInput(pInput);
if(pDummyInput)
pDummyChar->OnPredictedInput(pDummyInput);
m_GameWorld.Tick(); m_GameWorld.Tick();
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
@ -2111,6 +2139,9 @@ void CGameClient::UpdatePrediction()
if(pLocalChar) if(pLocalChar)
if(CNetObj_PlayerInput *pInput = (CNetObj_PlayerInput*) Client()->GetInput(Client()->GameTick(g_Config.m_ClDummy))) if(CNetObj_PlayerInput *pInput = (CNetObj_PlayerInput*) Client()->GetInput(Client()->GameTick(g_Config.m_ClDummy)))
pLocalChar->SetInput(pInput); pLocalChar->SetInput(pInput);
if(pDummyChar)
if(CNetObj_PlayerInput *pInput = (CNetObj_PlayerInput*) Client()->GetInput(Client()->GameTick(), 1))
pDummyChar->SetInput(pInput);
} }
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
@ -2128,7 +2159,7 @@ void CGameClient::UpdatePrediction()
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
if(m_Snap.m_aCharacters[i].m_Active) if(m_Snap.m_aCharacters[i].m_Active)
{ {
bool IsLocal = (i == m_Snap.m_LocalClientID); bool IsLocal = (i == m_Snap.m_LocalClientID || (PredictDummy() && i == m_PredictedDummyID));
int GameTeam = (m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) ? m_aClients[i].m_Team : i; int GameTeam = (m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) ? m_aClients[i].m_Team : i;
m_GameWorld.NetCharAdd(i, &m_Snap.m_aCharacters[i].m_Cur, m_GameWorld.NetCharAdd(i, &m_Snap.m_aCharacters[i].m_Cur,
m_Snap.m_aCharacters[i].m_HasExtendedData ? &m_Snap.m_aCharacters[i].m_ExtendedData : 0, m_Snap.m_aCharacters[i].m_HasExtendedData ? &m_Snap.m_aCharacters[i].m_ExtendedData : 0,

View file

@ -454,6 +454,7 @@ public:
bool AntiPingWeapons() { return g_Config.m_ClAntiPing && g_Config.m_ClAntiPingWeapons && !m_Snap.m_SpecInfo.m_Active && Client()->State() != IClient::STATE_DEMOPLAYBACK; } bool AntiPingWeapons() { return g_Config.m_ClAntiPing && g_Config.m_ClAntiPingWeapons && !m_Snap.m_SpecInfo.m_Active && Client()->State() != IClient::STATE_DEMOPLAYBACK; }
bool AntiPingGunfire() { return AntiPingGrenade() && AntiPingWeapons() && g_Config.m_ClAntiPingGunfire; } bool AntiPingGunfire() { return AntiPingGrenade() && AntiPingWeapons() && g_Config.m_ClAntiPingGunfire; }
bool Predict() { return g_Config.m_ClPredict && !(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) && !m_Snap.m_SpecInfo.m_Active && Client()->State() != IClient::STATE_DEMOPLAYBACK && m_Snap.m_pLocalCharacter; } bool Predict() { return g_Config.m_ClPredict && !(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) && !m_Snap.m_SpecInfo.m_Active && Client()->State() != IClient::STATE_DEMOPLAYBACK && m_Snap.m_pLocalCharacter; }
bool PredictDummy() { return AntiPingPlayers() && Client()->DummyConnected() && m_Snap.m_LocalClientID >= 0 && m_PredictedDummyID >= 0; }
CGameWorld m_GameWorld; CGameWorld m_GameWorld;
CGameWorld m_PredictedWorld; CGameWorld m_PredictedWorld;
@ -471,6 +472,8 @@ private:
void DetectStrongHook(); void DetectStrongHook();
vec2 GetSmoothPos(int ClientID); vec2 GetSmoothPos(int ClientID);
int m_PredictedDummyID;
int m_IsDummySwapping;
CCharOrder m_CharOrder; CCharOrder m_CharOrder;
class CCharacter m_aLastWorldCharacters[MAX_CLIENTS]; class CCharacter m_aLastWorldCharacters[MAX_CLIENTS];