mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Merge #1802
1802: Prediction fixes r=def- a=trml I believe this fixes #1671 (uninitialized variables). Some other things: Use new ddnetchar fields in prediction, small fix for prediction of moving pickups, fix the freeze end tick in ddnetcharacter (will add it to the client later) Also adds a setting for choosing between new/old antiping for grenade like suggested in #1683 (cl_antiping_gunfire 0 to disable). Co-authored-by: trml <trml@users.noreply.github.com>
This commit is contained in:
commit
b50e7ee674
|
@ -112,7 +112,7 @@ void CItems::RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID)
|
|||
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y);
|
||||
}
|
||||
|
||||
void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent)
|
||||
void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted)
|
||||
{
|
||||
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
|
||||
Graphics()->QuadsSetRotation(0);
|
||||
|
@ -120,7 +120,8 @@ void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCu
|
|||
|
||||
int QuadOffset = 2;
|
||||
|
||||
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), Client()->IntraGameTick());
|
||||
float IntraTick = IsPredicted ? Client()->PredIntraGameTick() : Client()->IntraGameTick();
|
||||
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), IntraTick);
|
||||
float Angle = 0.0f;
|
||||
if(pCurrent->m_Type == POWERUP_WEAPON)
|
||||
{
|
||||
|
@ -270,7 +271,7 @@ void CItems::OnRender()
|
|||
if(Client()->State() < IClient::STATE_ONLINE)
|
||||
return;
|
||||
|
||||
bool UsePredicted = (GameClient()->Predict() && GameClient()->AntiPingWeapons() && GameClient()->AntiPingGrenade());
|
||||
bool UsePredicted = GameClient()->Predict() && GameClient()->AntiPingGunfire();
|
||||
if(UsePredicted)
|
||||
{
|
||||
for(auto *pProj = (CProjectile*) GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile*) pProj->NextEntity())
|
||||
|
@ -297,7 +298,7 @@ void CItems::OnRender()
|
|||
CNetObj_Pickup Data, Prev;
|
||||
pPickup->FillInfo(&Data);
|
||||
pPrev->FillInfo(&Prev);
|
||||
RenderPickup(&Prev, &Data);
|
||||
RenderPickup(&Prev, &Data, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +440,7 @@ void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemI
|
|||
|
||||
if(m_pClient->m_Snap.m_pLocalInfo)
|
||||
LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientID].m_Team != -1;
|
||||
if(!m_pClient->AntiPingGrenade() || !m_pClient->AntiPingWeapons() || !LocalPlayerInGame)
|
||||
if(!m_pClient->AntiPingGunfire() || !LocalPlayerInGame)
|
||||
return;
|
||||
if(Client()->PredGameTick() == pCurrent->m_StartTick)
|
||||
return;
|
||||
|
|
|
@ -15,7 +15,7 @@ class CItems : public CComponent
|
|||
int m_NumExtraProjectiles;
|
||||
|
||||
void RenderProjectile(const CNetObj_Projectile *pCurrent, int ItemID);
|
||||
void RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent);
|
||||
void RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted = false);
|
||||
void RenderFlag(const CNetObj_Flag *pPrev, const CNetObj_Flag *pCurrent, const CNetObj_GameData *pPrevGameData, const CNetObj_GameData *pCurGameData);
|
||||
void RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted = false);
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ void CPlayers::RenderPlayer(
|
|||
bool PredictLocalWeapons = false;
|
||||
float AttackTime = (Client()->PrevGameTick() - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime();
|
||||
float LastAttackTime = (Client()->PrevGameTick() - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + s_LastGameTickTime;
|
||||
if(Local && m_pClient->m_aClients[ClientID].m_IsPredicted && m_pClient->AntiPingWeapons() && m_pClient->AntiPingGrenade())
|
||||
if(m_pClient->m_aClients[ClientID].m_IsPredictedLocal && m_pClient->AntiPingGunfire())
|
||||
{
|
||||
PredictLocalWeapons = true;
|
||||
AttackTime = (Client()->PredIntraGameTick() + (Client()->PredGameTick() - 1 - Player.m_AttackTick)) / (float)SERVER_TICK_SPEED;
|
||||
|
|
|
@ -1209,42 +1209,29 @@ void CGameClient::OnNewSnapshot()
|
|||
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedData = true;
|
||||
|
||||
// Collision
|
||||
m_aClients[Item.m_ID].m_Solo = m_aClients[Item.m_ID].m_Predicted.m_Solo =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_SOLO;
|
||||
m_aClients[Item.m_ID].m_NoCollision = m_aClients[Item.m_ID].m_Predicted.m_NoCollision =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_COLLISION;
|
||||
m_aClients[Item.m_ID].m_NoHammerHit = m_aClients[Item.m_ID].m_Predicted.m_NoHammerHit =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_HAMMER_HIT;
|
||||
m_aClients[Item.m_ID].m_NoGrenadeHit = m_aClients[Item.m_ID].m_Predicted.m_NoGrenadeHit =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_GRENADE_HIT;
|
||||
m_aClients[Item.m_ID].m_NoRifleHit = m_aClients[Item.m_ID].m_Predicted.m_NoRifleHit =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_RIFLE_HIT;
|
||||
m_aClients[Item.m_ID].m_NoShotgunHit = m_aClients[Item.m_ID].m_Predicted.m_NoShotgunHit =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT;
|
||||
m_aClients[Item.m_ID].m_NoHookHit = m_aClients[Item.m_ID].m_Predicted.m_NoHookHit =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_NO_HOOK;
|
||||
m_aClients[Item.m_ID].m_Super = m_aClients[Item.m_ID].m_Predicted.m_Super =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_SUPER;
|
||||
m_aClients[Item.m_ID].m_Solo = pCharacterData->m_Flags & CHARACTERFLAG_SOLO;
|
||||
m_aClients[Item.m_ID].m_NoCollision = pCharacterData->m_Flags & CHARACTERFLAG_NO_COLLISION;
|
||||
m_aClients[Item.m_ID].m_NoHammerHit = pCharacterData->m_Flags & CHARACTERFLAG_NO_HAMMER_HIT;
|
||||
m_aClients[Item.m_ID].m_NoGrenadeHit = pCharacterData->m_Flags & CHARACTERFLAG_NO_GRENADE_HIT;
|
||||
m_aClients[Item.m_ID].m_NoRifleHit = pCharacterData->m_Flags & CHARACTERFLAG_NO_RIFLE_HIT;
|
||||
m_aClients[Item.m_ID].m_NoShotgunHit = pCharacterData->m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT;
|
||||
m_aClients[Item.m_ID].m_NoHookHit = pCharacterData->m_Flags & CHARACTERFLAG_NO_HOOK;
|
||||
m_aClients[Item.m_ID].m_Super = pCharacterData->m_Flags & CHARACTERFLAG_SUPER;
|
||||
|
||||
// Endless
|
||||
m_aClients[Item.m_ID].m_EndlessHook = m_aClients[Item.m_ID].m_Predicted.m_EndlessHook =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
|
||||
m_aClients[Item.m_ID].m_EndlessJump = m_aClients[Item.m_ID].m_Predicted.m_EndlessJump =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_ENDLESS_JUMP;
|
||||
m_aClients[Item.m_ID].m_EndlessHook = pCharacterData->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
|
||||
m_aClients[Item.m_ID].m_EndlessJump = pCharacterData->m_Flags & CHARACTERFLAG_ENDLESS_JUMP;
|
||||
|
||||
// Freeze
|
||||
m_aClients[Item.m_ID].m_FreezeEnd = m_aClients[Item.m_ID].m_Predicted.m_FreezeEnd =
|
||||
pCharacterData->m_FreezeEnd;
|
||||
m_aClients[Item.m_ID].m_DeepFrozen = m_aClients[Item.m_ID].m_Predicted.m_DeepFrozen =
|
||||
pCharacterData->m_FreezeEnd == -1;
|
||||
m_aClients[Item.m_ID].m_FreezeEnd = pCharacterData->m_FreezeEnd;
|
||||
m_aClients[Item.m_ID].m_DeepFrozen = pCharacterData->m_FreezeEnd == -1;
|
||||
|
||||
// Telegun
|
||||
m_aClients[Item.m_ID].m_HasTelegunGrenade = m_aClients[Item.m_ID].m_Predicted.m_HasTelegunGrenade =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_GRENADE;
|
||||
m_aClients[Item.m_ID].m_HasTelegunGun = m_aClients[Item.m_ID].m_Predicted.m_HasTelegunGun =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_GUN;
|
||||
m_aClients[Item.m_ID].m_HasTelegunLaser = m_aClients[Item.m_ID].m_Predicted.m_HasTelegunLaser =
|
||||
pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_LASER;
|
||||
m_aClients[Item.m_ID].m_HasTelegunGrenade = pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_GRENADE;
|
||||
m_aClients[Item.m_ID].m_HasTelegunGun = pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_GUN;
|
||||
m_aClients[Item.m_ID].m_HasTelegunLaser = pCharacterData->m_Flags & CHARACTERFLAG_TELEGUN_LASER;
|
||||
|
||||
m_aClients[Item.m_ID].m_Predicted.ReadDDNet(pCharacterData);
|
||||
}
|
||||
else if(Item.m_Type == NETOBJTYPE_SPECTATORINFO)
|
||||
{
|
||||
|
@ -2020,13 +2007,33 @@ void CGameClient::UpdatePrediction()
|
|||
|
||||
// update strong and weak hook
|
||||
if(pLocalChar && AntiPingPlayers())
|
||||
DetectStrongHook();
|
||||
for(int i : m_CharOrder.m_IDs)
|
||||
if(CCharacter *pChar = m_GameWorld.GetCharacterByID(i))
|
||||
{
|
||||
if(m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_HasExtendedData)
|
||||
{
|
||||
m_GameWorld.RemoveEntity(pChar);
|
||||
m_GameWorld.InsertEntity(pChar);
|
||||
int aIDs[MAX_CLIENTS];
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
aIDs[i] = -1;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(CCharacter *pChar = m_GameWorld.GetCharacterByID(i))
|
||||
aIDs[pChar->GetStrongWeakID()] = i;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(aIDs[i] >= 0)
|
||||
m_CharOrder.GiveStrong(aIDs[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// manual detection
|
||||
DetectStrongHook();
|
||||
}
|
||||
for(int i : m_CharOrder.m_IDs)
|
||||
{
|
||||
if(CCharacter *pChar = m_GameWorld.GetCharacterByID(i))
|
||||
{
|
||||
m_GameWorld.RemoveEntity(pChar);
|
||||
m_GameWorld.InsertEntity(pChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// advance the gameworld to the current gametick
|
||||
if(pLocalChar && abs(m_GameWorld.GameTick() - Client()->GameTick()) < SERVER_TICK_SPEED)
|
||||
|
@ -2128,7 +2135,7 @@ void CGameClient::UpdateRenderedCharacters()
|
|||
{
|
||||
m_aClients[i].m_IsPredictedLocal = true;
|
||||
CCharacter *pChar = m_PredictedWorld.GetCharacterByID(i);
|
||||
if(pChar && AntiPingWeapons() && AntiPingGrenade() && ((pChar->m_NinjaJetpack && pChar->m_FreezeTime == 0) || m_Snap.m_aCharacters[i].m_Cur.m_Weapon != WEAPON_NINJA || m_Snap.m_aCharacters[i].m_Cur.m_Weapon == m_aClients[i].m_Predicted.m_ActiveWeapon))
|
||||
if(pChar && AntiPingGunfire() && ((pChar->m_NinjaJetpack && pChar->m_FreezeTime == 0) || m_Snap.m_aCharacters[i].m_Cur.m_Weapon != WEAPON_NINJA || m_Snap.m_aCharacters[i].m_Cur.m_Weapon == m_aClients[i].m_Predicted.m_ActiveWeapon))
|
||||
{
|
||||
m_aClients[i].m_RenderCur.m_AttackTick = pChar->GetAttackTick();
|
||||
if(m_Snap.m_aCharacters[i].m_Cur.m_Weapon != WEAPON_NINJA && !(pChar->m_NinjaJetpack && pChar->Core()->m_ActiveWeapon == WEAPON_GUN))
|
||||
|
@ -2169,6 +2176,12 @@ void CGameClient::DetectStrongHook()
|
|||
if(m_Snap.m_aCharacters[FromPlayer].m_Prev.m_Direction != m_Snap.m_aCharacters[FromPlayer].m_Cur.m_Direction
|
||||
|| m_Snap.m_aCharacters[ToPlayer].m_Prev.m_Direction != m_Snap.m_aCharacters[ToPlayer].m_Cur.m_Direction)
|
||||
continue;
|
||||
|
||||
CCharacter *pFromCharWorld = m_GameWorld.GetCharacterByID(FromPlayer);
|
||||
CCharacter *pToCharWorld = m_GameWorld.GetCharacterByID(ToPlayer);
|
||||
if(!pFromCharWorld || !pToCharWorld)
|
||||
continue;
|
||||
|
||||
s_LastUpdateTick[ToPlayer] = s_LastUpdateTick[FromPlayer] = Client()->GameTick();
|
||||
|
||||
float PredictErr[2];
|
||||
|
@ -2177,14 +2190,15 @@ void CGameClient::DetectStrongHook()
|
|||
|
||||
CWorldCore World;
|
||||
World.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
|
||||
CCharacterCore ToChar;
|
||||
CCharacterCore FromChar;
|
||||
|
||||
for(int dir = 0; dir < 2; dir++)
|
||||
{
|
||||
CCharacterCore ToChar = pFromCharWorld->GetCore();
|
||||
ToChar.Init(&World, Collision(), &m_Teams);
|
||||
World.m_apCharacters[ToPlayer] = &ToChar;
|
||||
ToChar.Read(&m_Snap.m_aCharacters[ToPlayer].m_Prev);
|
||||
|
||||
CCharacterCore FromChar = pFromCharWorld->GetCore();
|
||||
FromChar.Init(&World, Collision(), &m_Teams);
|
||||
World.m_apCharacters[FromPlayer] = &FromChar;
|
||||
FromChar.Read(&m_Snap.m_aCharacters[FromPlayer].m_Prev);
|
||||
|
|
|
@ -440,6 +440,7 @@ public:
|
|||
bool AntiPingPlayers() { return g_Config.m_ClAntiPing && g_Config.m_ClAntiPingPlayers && !m_Snap.m_SpecInfo.m_Active && Client()->State() != IClient::STATE_DEMOPLAYBACK && (m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_Tuning[g_Config.m_ClDummy].m_PlayerHooking); }
|
||||
bool AntiPingGrenade() { return g_Config.m_ClAntiPing && g_Config.m_ClAntiPingGrenade && !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 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; }
|
||||
|
||||
CGameWorld m_GameWorld;
|
||||
|
|
|
@ -1021,6 +1021,8 @@ CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar,
|
|||
m_Super = false;
|
||||
m_CanMoveInFreeze = false;
|
||||
m_Alive = true;
|
||||
m_TeleCheckpoint = 0;
|
||||
m_StrongWeakID = 0;
|
||||
|
||||
ResetPrediction();
|
||||
Read(pChar, pExtended, false);
|
||||
|
@ -1043,7 +1045,10 @@ void CCharacter::ResetPrediction()
|
|||
m_DeepFreeze = 0;
|
||||
m_Super = false;
|
||||
for(int w = 0; w < NUM_WEAPONS; w++)
|
||||
{
|
||||
SetWeaponGot(w, false);
|
||||
SetWeaponAmmo(w, -1);
|
||||
}
|
||||
if(m_Core.m_HookedPlayer >= 0)
|
||||
{
|
||||
m_Core.m_HookedPlayer = -1;
|
||||
|
@ -1053,126 +1058,22 @@ void CCharacter::ResetPrediction()
|
|||
|
||||
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal)
|
||||
{
|
||||
vec2 PosBefore = m_Pos;
|
||||
|
||||
m_Core.Read((CNetObj_CharacterCore*) pChar);
|
||||
m_Pos = m_Core.m_Pos;
|
||||
m_AttackTick = pChar->m_AttackTick;
|
||||
|
||||
if(distance(PosBefore, m_Pos) > 2.f) // misprediction, don't use prevpos
|
||||
m_PrevPos = m_Pos;
|
||||
|
||||
if(distance(m_PrevPos, m_Pos) > 10.f * 32.f) // reset prevpos if the distance is high
|
||||
m_PrevPos = m_Pos;
|
||||
|
||||
// remove weapons that are unavailable. if the current weapon is ninja just set ammo to zero in case the player is frozen
|
||||
if(pChar->m_Weapon != m_Core.m_ActiveWeapon)
|
||||
{
|
||||
if(pChar->m_Weapon == WEAPON_NINJA)
|
||||
m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo = 0;
|
||||
else
|
||||
{
|
||||
if(m_Core.m_ActiveWeapon == WEAPON_NINJA)
|
||||
{
|
||||
SetNinjaActivationDir(vec2(0,0));
|
||||
SetNinjaActivationTick(-500);
|
||||
SetNinjaCurrentMoveTime(0);
|
||||
}
|
||||
if(pChar->m_Weapon == m_LastSnapWeapon)
|
||||
m_aWeapons[m_Core.m_ActiveWeapon].m_Got = false;
|
||||
}
|
||||
}
|
||||
m_LastSnapWeapon = pChar->m_Weapon;
|
||||
|
||||
// add weapons
|
||||
if(pChar->m_Weapon != WEAPON_NINJA)
|
||||
{
|
||||
m_aWeapons[pChar->m_Weapon].m_Got = true;
|
||||
m_aWeapons[pChar->m_Weapon].m_Ammo = (GameWorld()->m_WorldConfig.m_InfiniteAmmo || GameWorld()->m_WorldConfig.m_IsDDRace || pChar->m_Weapon == WEAPON_HAMMER) ? -1 : pChar->m_AmmoCount;
|
||||
SetActiveWeapon(pChar->m_Weapon);
|
||||
}
|
||||
|
||||
if(pChar->m_Emote != EMOTE_PAIN && pChar->m_Emote != EMOTE_NORMAL)
|
||||
m_DeepFreeze = false;
|
||||
if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_FreezeTick || absolute(pChar->m_VelX) == 256*10)
|
||||
{
|
||||
m_DeepFreeze = false;
|
||||
UnFreeze();
|
||||
}
|
||||
if(!GameWorld()->m_WorldConfig.m_PredictFreeze)
|
||||
{
|
||||
m_DeepFreeze = false;
|
||||
UnFreeze();
|
||||
}
|
||||
|
||||
if(GameWorld()->m_WorldConfig.m_PredictWeapons && Tuning()->m_JetpackStrength > 0)
|
||||
{
|
||||
m_LastJetpackStrength = Tuning()->m_JetpackStrength;
|
||||
m_Jetpack = true;
|
||||
m_aWeapons[WEAPON_GUN].m_Got = true;
|
||||
m_aWeapons[WEAPON_GUN].m_Ammo = -1;
|
||||
m_NinjaJetpack = pChar->m_Weapon == WEAPON_NINJA;
|
||||
}
|
||||
else if(pChar->m_Weapon != WEAPON_NINJA)
|
||||
m_Jetpack = false;
|
||||
|
||||
if(GameWorld()->m_WorldConfig.m_PredictTiles)
|
||||
{
|
||||
if(pChar->m_Jumped&2)
|
||||
{
|
||||
m_SuperJump = false;
|
||||
if(m_Core.m_Jumps > m_Core.m_JumpedTotal && m_Core.m_JumpedTotal > 0 && m_Core.m_Jumps > 2)
|
||||
m_Core.m_Jumps = m_Core.m_JumpedTotal + 1;
|
||||
else
|
||||
m_Core.m_JumpedTotal = m_Core.m_Jumps;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_Core.m_Jumps < 2)
|
||||
m_Core.m_Jumps = m_Core.m_JumpedTotal + 2;
|
||||
}
|
||||
if(Tuning()->m_AirJumpImpulse == 0)
|
||||
{
|
||||
m_Core.m_Jumps = 0;
|
||||
m_Core.m_Jumped = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_Core.m_HookTick != 0)
|
||||
m_EndlessHook = false;
|
||||
|
||||
// reset player collision
|
||||
if(!pExtended)
|
||||
SetSolo(!Tuning()->m_PlayerCollision && !Tuning()->m_PlayerHooking);
|
||||
m_Core.m_Collision = Tuning()->m_PlayerCollision;
|
||||
m_Core.m_Hook = Tuning()->m_PlayerHooking;
|
||||
|
||||
// reset all input except direction and hook for non-local players (as in vanilla prediction)
|
||||
if(!IsLocal)
|
||||
{
|
||||
mem_zero(&m_Input, sizeof(m_Input));
|
||||
mem_zero(&m_SavedInput, sizeof(m_SavedInput));
|
||||
m_Input.m_Direction = m_SavedInput.m_Direction = m_Core.m_Direction;
|
||||
m_Input.m_Hook = m_SavedInput.m_Hook = (m_Core.m_HookState != HOOK_IDLE);
|
||||
m_Input.m_TargetX = cosf(pChar->m_Angle/256.0f);
|
||||
m_Input.m_TargetY = sinf(pChar->m_Angle/256.0f);
|
||||
}
|
||||
|
||||
m_Alive = true;
|
||||
|
||||
if(pExtended)
|
||||
{
|
||||
m_Super = pExtended->m_Flags & CHARACTERFLAG_SUPER;
|
||||
m_Core.ReadDDNet(pExtended);
|
||||
|
||||
SetSolo(pExtended->m_Flags & CHARACTERFLAG_SOLO);
|
||||
m_Super = pExtended->m_Flags & CHARACTERFLAG_SUPER;
|
||||
if(m_Super)
|
||||
TeamsCore()->Team(GetCID(), TeamsCore()->m_IsDDRace16 ? VANILLA_TEAM_SUPER : TEAM_SUPER);
|
||||
|
||||
m_EndlessHook = pExtended->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
|
||||
m_Core.m_Collision = !(pExtended->m_Flags & CHARACTERFLAG_NO_COLLISION);
|
||||
m_Core.m_Hook = !(pExtended->m_Flags & CHARACTERFLAG_NO_HOOK);
|
||||
m_SuperJump = pExtended->m_Flags & CHARACTERFLAG_ENDLESS_JUMP;
|
||||
m_Jetpack = pExtended->m_Flags & CHARACTERFLAG_JETPACK;
|
||||
m_TeleCheckpoint = pExtended->m_TeleCheckpoint;
|
||||
m_StrongWeakID = pExtended->m_StrongWeakID;
|
||||
|
||||
m_Hit = HIT_ALL;
|
||||
if(pExtended->m_Flags & CHARACTERFLAG_NO_GRENADE_HIT)
|
||||
|
@ -1183,6 +1084,123 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
|
|||
m_Hit |= DISABLE_HIT_RIFLE;
|
||||
if(pExtended->m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT)
|
||||
m_Hit |= DISABLE_HIT_SHOTGUN;
|
||||
|
||||
m_aWeapons[WEAPON_HAMMER].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_HAMMER) != 0;
|
||||
m_aWeapons[WEAPON_GUN].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_GUN) != 0;
|
||||
m_aWeapons[WEAPON_SHOTGUN].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_SHOTGUN) != 0;
|
||||
m_aWeapons[WEAPON_GRENADE].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_GRENADE) != 0;
|
||||
m_aWeapons[WEAPON_RIFLE].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_LASER) != 0;
|
||||
|
||||
const bool Ninja = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_NINJA) != 0;
|
||||
if(Ninja && m_Core.m_ActiveWeapon != WEAPON_NINJA)
|
||||
GiveNinja();
|
||||
else if(!Ninja && m_Core.m_ActiveWeapon == WEAPON_NINJA)
|
||||
RemoveNinja();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ddnetcharacter is not available, try to get some info from the tunings and the character netobject instead.
|
||||
|
||||
// remove weapons that are unavailable. if the current weapon is ninja just set ammo to zero in case the player is frozen
|
||||
if(pChar->m_Weapon != m_Core.m_ActiveWeapon)
|
||||
{
|
||||
if(pChar->m_Weapon == WEAPON_NINJA)
|
||||
m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo = 0;
|
||||
else
|
||||
{
|
||||
if(m_Core.m_ActiveWeapon == WEAPON_NINJA)
|
||||
{
|
||||
SetNinjaActivationDir(vec2(0,0));
|
||||
SetNinjaActivationTick(-500);
|
||||
SetNinjaCurrentMoveTime(0);
|
||||
}
|
||||
if(pChar->m_Weapon == m_LastSnapWeapon)
|
||||
m_aWeapons[m_Core.m_ActiveWeapon].m_Got = false;
|
||||
}
|
||||
}
|
||||
// add weapon
|
||||
if(pChar->m_Weapon != WEAPON_NINJA)
|
||||
m_aWeapons[pChar->m_Weapon].m_Got = true;
|
||||
|
||||
// jetpack
|
||||
if(GameWorld()->m_WorldConfig.m_PredictWeapons && Tuning()->m_JetpackStrength > 0)
|
||||
{
|
||||
m_LastJetpackStrength = Tuning()->m_JetpackStrength;
|
||||
m_Jetpack = true;
|
||||
m_aWeapons[WEAPON_GUN].m_Got = true;
|
||||
m_aWeapons[WEAPON_GUN].m_Ammo = -1;
|
||||
m_NinjaJetpack = pChar->m_Weapon == WEAPON_NINJA;
|
||||
}
|
||||
else if(pChar->m_Weapon != WEAPON_NINJA)
|
||||
m_Jetpack = false;
|
||||
|
||||
// number of jumps
|
||||
if(GameWorld()->m_WorldConfig.m_PredictTiles)
|
||||
{
|
||||
if(pChar->m_Jumped&2)
|
||||
{
|
||||
m_SuperJump = false;
|
||||
if(m_Core.m_Jumps > m_Core.m_JumpedTotal && m_Core.m_JumpedTotal > 0 && m_Core.m_Jumps > 2)
|
||||
m_Core.m_Jumps = m_Core.m_JumpedTotal + 1;
|
||||
}
|
||||
else if(m_Core.m_Jumps < 2)
|
||||
m_Core.m_Jumps = m_Core.m_JumpedTotal + 2;
|
||||
if(Tuning()->m_AirJumpImpulse == 0)
|
||||
{
|
||||
m_Core.m_Jumps = 0;
|
||||
m_Core.m_Jumped = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// set player collision
|
||||
SetSolo(!Tuning()->m_PlayerCollision && !Tuning()->m_PlayerHooking);
|
||||
m_Core.m_Collision = Tuning()->m_PlayerCollision;
|
||||
m_Core.m_Hook = Tuning()->m_PlayerHooking;
|
||||
|
||||
if(m_Core.m_HookTick != 0)
|
||||
m_EndlessHook = false;
|
||||
}
|
||||
|
||||
// detect unfreeze (in case the player was frozen in the tile prediction and not correclty unfrozen)
|
||||
if(pChar->m_Emote != EMOTE_PAIN && pChar->m_Emote != EMOTE_NORMAL)
|
||||
m_DeepFreeze = false;
|
||||
if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_FreezeTick || absolute(pChar->m_VelX) == 256*10 || !GameWorld()->m_WorldConfig.m_PredictFreeze)
|
||||
{
|
||||
m_DeepFreeze = false;
|
||||
UnFreeze();
|
||||
}
|
||||
|
||||
vec2 PosBefore = m_Pos;
|
||||
m_Pos = m_Core.m_Pos;
|
||||
|
||||
if(distance(PosBefore, m_Pos) > 2.f) // misprediction, don't use prevpos
|
||||
m_PrevPos = m_Pos;
|
||||
|
||||
if(distance(m_PrevPos, m_Pos) > 10.f * 32.f) // reset prevpos if the distance is high
|
||||
m_PrevPos = m_Pos;
|
||||
|
||||
if(pChar->m_Jumped&2)
|
||||
m_Core.m_JumpedTotal = m_Core.m_Jumps;
|
||||
m_AttackTick = pChar->m_AttackTick;
|
||||
m_LastSnapWeapon = pChar->m_Weapon;
|
||||
m_Alive = true;
|
||||
|
||||
// set the current weapon
|
||||
if(pChar->m_Weapon != WEAPON_NINJA)
|
||||
{
|
||||
m_aWeapons[pChar->m_Weapon].m_Ammo = (GameWorld()->m_WorldConfig.m_InfiniteAmmo || GameWorld()->m_WorldConfig.m_IsDDRace || pChar->m_Weapon == WEAPON_HAMMER) ? -1 : pChar->m_AmmoCount;
|
||||
SetActiveWeapon(pChar->m_Weapon);
|
||||
}
|
||||
|
||||
// reset all input except direction and hook for non-local players (as in vanilla prediction)
|
||||
if(!IsLocal)
|
||||
{
|
||||
mem_zero(&m_Input, sizeof(m_Input));
|
||||
mem_zero(&m_SavedInput, sizeof(m_SavedInput));
|
||||
m_Input.m_Direction = m_SavedInput.m_Direction = m_Core.m_Direction;
|
||||
m_Input.m_Hook = m_SavedInput.m_Hook = (m_Core.m_HookState != HOOK_IDLE);
|
||||
m_Input.m_TargetX = cosf(pChar->m_Angle/256.0f);
|
||||
m_Input.m_TargetY = sinf(pChar->m_Angle/256.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ public:
|
|||
int m_Hit;
|
||||
vec2 m_PrevPos;
|
||||
vec2 m_PrevPrevPos;
|
||||
int m_TeleCheckpoint;
|
||||
|
||||
int m_TileIndex;
|
||||
int m_TileFlags;
|
||||
|
@ -142,6 +143,7 @@ public:
|
|||
void SetInput(CNetObj_PlayerInput *pNewInput) { m_LatestInput = m_Input = *pNewInput; };
|
||||
int GetJumped() { return m_Core.m_Jumped; }
|
||||
int GetAttackTick() { return m_AttackTick; }
|
||||
int GetStrongWeakID() { return m_StrongWeakID; }
|
||||
|
||||
CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended = 0);
|
||||
void Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal);
|
||||
|
@ -205,6 +207,8 @@ private:
|
|||
void HandleSkippableTiles(int Index);
|
||||
void DDRaceTick();
|
||||
void DDRacePostCoreTick();
|
||||
|
||||
int m_StrongWeakID;
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
@ -93,6 +93,8 @@ CPickup::CPickup(CGameWorld *pGameWorld, int ID, CNetObj_Pickup *pPickup)
|
|||
m_Subtype = pPickup->m_Subtype;
|
||||
m_Core = vec2(0.f, 0.f);
|
||||
m_ID = ID;
|
||||
m_Layer = LAYER_GAME;
|
||||
m_Number = 0;
|
||||
}
|
||||
|
||||
void CPickup::FillInfo(CNetObj_Pickup *pPickup)
|
||||
|
|
|
@ -606,6 +606,34 @@ void CCharacterCore::Read(const CNetObj_CharacterCore *pObjCore)
|
|||
m_Angle = pObjCore->m_Angle;
|
||||
}
|
||||
|
||||
void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
|
||||
{
|
||||
// Collision
|
||||
m_Solo = pObjDDNet->m_Flags & CHARACTERFLAG_SOLO;
|
||||
m_NoCollision = pObjDDNet->m_Flags & CHARACTERFLAG_NO_COLLISION;
|
||||
m_NoHammerHit = pObjDDNet->m_Flags & CHARACTERFLAG_NO_HAMMER_HIT;
|
||||
m_NoGrenadeHit = pObjDDNet->m_Flags & CHARACTERFLAG_NO_GRENADE_HIT;
|
||||
m_NoRifleHit = pObjDDNet->m_Flags & CHARACTERFLAG_NO_RIFLE_HIT;
|
||||
m_NoShotgunHit = pObjDDNet->m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT;
|
||||
m_NoHookHit = pObjDDNet->m_Flags & CHARACTERFLAG_NO_HOOK;
|
||||
m_Super = pObjDDNet->m_Flags & CHARACTERFLAG_SUPER;
|
||||
|
||||
// Endless
|
||||
m_EndlessHook = pObjDDNet->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
|
||||
m_EndlessJump = pObjDDNet->m_Flags & CHARACTERFLAG_ENDLESS_JUMP;
|
||||
|
||||
// Freeze
|
||||
m_FreezeEnd = pObjDDNet->m_FreezeEnd;
|
||||
m_DeepFrozen = pObjDDNet->m_FreezeEnd == -1;
|
||||
|
||||
// Telegun
|
||||
m_HasTelegunGrenade = pObjDDNet->m_Flags & CHARACTERFLAG_TELEGUN_GRENADE;
|
||||
m_HasTelegunGun = pObjDDNet->m_Flags & CHARACTERFLAG_TELEGUN_GUN;
|
||||
m_HasTelegunLaser = pObjDDNet->m_Flags & CHARACTERFLAG_TELEGUN_LASER;
|
||||
|
||||
m_Jumps = pObjDDNet->m_Jumps;
|
||||
}
|
||||
|
||||
void CCharacterCore::Quantize()
|
||||
{
|
||||
CNetObj_CharacterCore Core;
|
||||
|
|
|
@ -232,6 +232,7 @@ public:
|
|||
bool m_LeftWall;
|
||||
|
||||
// DDnet Character
|
||||
void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet);
|
||||
bool m_Solo;
|
||||
bool m_Jetpack;
|
||||
bool m_NoCollision;
|
||||
|
|
|
@ -1213,7 +1213,7 @@ void CCharacter::Snap(int SnappingClient)
|
|||
if(m_Core.m_ActiveWeapon == WEAPON_NINJA)
|
||||
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_NINJA;
|
||||
|
||||
pDDNetCharacter->m_FreezeEnd = m_DeepFreeze ? -1 : m_FreezeTick + m_FreezeTime;
|
||||
pDDNetCharacter->m_FreezeEnd = m_DeepFreeze ? -1 : m_FreezeTime == 0 ? 0 : Server()->Tick() + m_FreezeTime;
|
||||
pDDNetCharacter->m_Jumps = m_Core.m_Jumps;
|
||||
pDDNetCharacter->m_TeleCheckpoint = m_TeleCheckpoint;
|
||||
pDDNetCharacter->m_StrongWeakID = m_StrongWeakID;
|
||||
|
|
|
@ -12,6 +12,7 @@ MACRO_CONFIG_INT(ClAntiPingPlayers, cl_antiping_players, 1, 0, 1, CFGFLAG_CLIENT
|
|||
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)")
|
||||
MACRO_CONFIG_INT(ClAntiPingWeapons, cl_antiping_weapons, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict weapon projectiles (only enabled if cl_antiping is set to 1)")
|
||||
MACRO_CONFIG_INT(ClAntiPingSmooth, cl_antiping_smooth, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Make the prediction of other player's movement smoother")
|
||||
MACRO_CONFIG_INT(ClAntiPingGunfire, cl_antiping_gunfire, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict gunfire and show predicted weapon physics (with cl_antiping_grenade 1 and cl_antiping_weapons 1)")
|
||||
|
||||
MACRO_CONFIG_INT(ClNameplates, cl_nameplates, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show name plates")
|
||||
MACRO_CONFIG_INT(ClNameplatesAlways, cl_nameplates_always, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Always show name plates disregarding of distance")
|
||||
|
|
Loading…
Reference in a new issue