mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 14:38:18 +00:00
parent
56c55d4081
commit
99baf219d0
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue