diff --git a/src/game/client/prediction/entities/character.cpp b/src/game/client/prediction/entities/character.cpp index d1c1570f136..0f46c97d0a2 100644 --- a/src/game/client/prediction/entities/character.cpp +++ b/src/game/client/prediction/entities/character.cpp @@ -546,6 +546,19 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput) mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); } +void CCharacter::ReleaseHook() +{ + m_Core.SetHookedPlayer(-1); + m_Core.m_HookState = HOOK_RETRACTED; + m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; +} + +void CCharacter::ResetHook() +{ + ReleaseHook(); + m_Core.m_HookPos = m_Core.m_Pos; +} + void CCharacter::ResetInput() { m_Input.m_Direction = 0; @@ -1105,6 +1118,33 @@ void CCharacter::GiveAllWeapons() } } +void CCharacter::ResetVelocity() +{ + m_Core.m_Vel = vec2(0, 0); +} + +// The method is needed only to reproduce 'shotgun bug' ddnet#5258 +// Use SetVelocity() instead. +void CCharacter::SetVelocity(const vec2 NewVelocity) +{ + m_Core.m_Vel = ClampVel(m_MoveRestrictions, NewVelocity); +} + +void CCharacter::SetRawVelocity(const vec2 NewVelocity) +{ + m_Core.m_Vel = NewVelocity; +} + +void CCharacter::AddVelocity(const vec2 Addition) +{ + SetVelocity(m_Core.m_Vel + Addition); +} + +void CCharacter::ApplyMoveRestrictions() +{ + m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel); +} + CTeamsCore *CCharacter::TeamsCore() { return GameWorld()->Teams(); diff --git a/src/game/client/prediction/entities/character.h b/src/game/client/prediction/entities/character.h index b424a8c9b73..e197bf20bc8 100644 --- a/src/game/client/prediction/entities/character.h +++ b/src/game/client/prediction/entities/character.h @@ -51,6 +51,8 @@ class CCharacter : public CEntity void OnPredictedInput(CNetObj_PlayerInput *pNewInput); void OnDirectInput(CNetObj_PlayerInput *pNewInput); + void ReleaseHook(); + void ResetHook(); void ResetInput(); void FireWeapon(); @@ -60,6 +62,12 @@ class CCharacter : public CEntity void GiveNinja(); void RemoveNinja(); + void ResetVelocity(); + void SetVelocity(vec2 NewVelocity); + void SetRawVelocity(vec2 NewVelocity); + void AddVelocity(vec2 Addition); + void ApplyMoveRestrictions(); + bool m_IsLocal; CTeamsCore *TeamsCore(); @@ -81,7 +89,6 @@ class CCharacter : public CEntity int m_TileIndex; int m_TileFIndex; - int m_MoveRestrictions; bool m_LastRefillJumps; // Setters/Getters because i don't want to modify vanilla vars access modifiers @@ -91,7 +98,7 @@ class CCharacter : public CEntity void SetActiveWeapon(int ActiveWeap); CCharacterCore GetCore() { return m_Core; } void SetCore(CCharacterCore Core) { m_Core = Core; } - CCharacterCore *Core() { return &m_Core; } + const CCharacterCore *Core() const { return &m_Core; } bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; } void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; } int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; } @@ -145,6 +152,8 @@ class CCharacter : public CEntity int m_ReloadTimer; int m_AttackTick; + int m_MoveRestrictions; + // these are non-heldback inputs CNetObj_PlayerInput m_LatestPrevInput; CNetObj_PlayerInput m_LatestInput; diff --git a/src/game/client/prediction/entities/dragger.cpp b/src/game/client/prediction/entities/dragger.cpp index 07aec45afcd..189d7e1a019 100644 --- a/src/game/client/prediction/entities/dragger.cpp +++ b/src/game/client/prediction/entities/dragger.cpp @@ -124,8 +124,7 @@ void CDragger::DraggerBeamTick() // In the center of the dragger a tee does not experience speed-up else if(distance(pTarget->m_Pos, m_Pos) > 28) { - vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength); - pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp); + pTarget->AddVelocity(normalize(m_Pos - pTarget->m_Pos) * m_Strength); } } diff --git a/src/game/client/prediction/entities/laser.cpp b/src/game/client/prediction/entities/laser.cpp index 6b0fb9247d3..0b9954169af 100644 --- a/src/game/client/prediction/entities/laser.cpp +++ b/src/game/client/prediction/entities/laser.cpp @@ -47,36 +47,39 @@ bool CLaser::HitCharacter(vec2 From, vec2 To) m_Energy = -1; if(m_Type == WEAPON_SHOTGUN) { - vec2 Temp; - float Strength = GetTuning(m_TuneZone)->m_ShotgunStrength; + float Strength; + if(!m_TuneZone) + Strength = Tuning()->m_ShotgunStrength; + else + Strength = TuningList()[m_TuneZone].m_ShotgunStrength; + const vec2 &HitPos = pHit->Core()->m_Pos; if(!g_Config.m_SvOldLaser) { if(m_PrevPos != HitPos) { - Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - HitPos) * Strength; - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp); + pHit->AddVelocity(normalize(m_PrevPos - HitPos) * Strength); } else { - pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; + pHit->SetRawVelocity(StackedLaserShotgunBugSpeed); } } else if(g_Config.m_SvOldLaser && pOwnerChar) { if(pOwnerChar->Core()->m_Pos != HitPos) { - Temp = pHit->Core()->m_Vel + normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength; - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp); + pHit->AddVelocity(normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength); } else { - pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; + pHit->SetRawVelocity(StackedLaserShotgunBugSpeed); } } else { - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, pHit->Core()->m_Vel); + // Re-apply move restrictions as a part of 'shotgun bug' reproduction + pHit->ApplyMoveRestrictions(); } } else if(m_Type == WEAPON_LASER) diff --git a/src/game/client/prediction/gameworld.cpp b/src/game/client/prediction/gameworld.cpp index a2fb7012367..1b8817140af 100644 --- a/src/game/client/prediction/gameworld.cpp +++ b/src/game/client/prediction/gameworld.cpp @@ -116,7 +116,7 @@ void CGameWorld::InsertEntity(CEntity *pEnt, bool Last) if(ID >= 0 && ID < MAX_CLIENTS) { m_apCharacters[ID] = pChar; - m_Core.m_apCharacters[ID] = pChar->Core(); + m_Core.m_apCharacters[ID] = &pChar->m_Core; } pChar->SetCoreWorld(this); } @@ -309,12 +309,9 @@ void CGameWorld::ReleaseHooked(int ClientID) CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER); for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) { - CCharacterCore *pCore = pChr->Core(); - if(pCore->HookedPlayer() == ClientID) + if(pChr->Core()->HookedPlayer() == ClientID && !pChr->IsSuper()) { - pCore->SetHookedPlayer(-1); - pCore->m_HookState = HOOK_RETRACTED; - pCore->m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; + pChr->ReleaseHook(); } } } @@ -557,7 +554,7 @@ void CGameWorld::NetObjEnd() if(pHookedChar->m_MarkedForDestroy) { pHookedChar->m_Pos = pHookedChar->m_Core.m_Pos = pChar->m_Core.m_HookPos; - pHookedChar->m_Core.m_Vel = vec2(0, 0); + pHookedChar->ResetVelocity(); mem_zero(&pHookedChar->m_SavedInput, sizeof(pHookedChar->m_SavedInput)); pHookedChar->m_SavedInput.m_TargetY = -1; pHookedChar->m_KeepHooked = true; @@ -577,7 +574,7 @@ void CGameWorld::NetObjEnd() if(ID >= 0 && ID < MAX_CLIENTS) { m_apCharacters[ID] = pChar; - m_Core.m_apCharacters[ID] = pChar->Core(); + m_Core.m_apCharacters[ID] = &pChar->m_Core; } } } diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index e886c5f490f..c95f8e8ef35 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -1593,7 +1593,7 @@ void CGameContext::ConTeleTo(IConsole::IResult *pResult, void *pUserData) // Teleport tee pSelf->Teleport(pCallingCharacter, Pos); pCallingCharacter->UnFreeze(); - pCallingCharacter->Core()->m_Vel = vec2(0, 0); + pCallingCharacter->ResetVelocity(); pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter); } @@ -1670,7 +1670,7 @@ void CGameContext::ConTeleXY(IConsole::IResult *pResult, void *pUserData) // Teleport tee pSelf->Teleport(pCallingCharacter, Pos); pCallingCharacter->UnFreeze(); - pCallingCharacter->Core()->m_Vel = vec2(0, 0); + pCallingCharacter->ResetVelocity(); pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter); } @@ -1722,7 +1722,7 @@ void CGameContext::ConTeleCursor(IConsole::IResult *pResult, void *pUserData) } pSelf->Teleport(pChr, Pos); pChr->UnFreeze(); - pChr->Core()->m_Vel = vec2(0, 0); + pChr->ResetVelocity(); pPlayer->m_LastTeleTee.Save(pChr); } diff --git a/src/game/server/ddracecommands.cpp b/src/game/server/ddracecommands.cpp index 27eacf94e55..186e84eca74 100644 --- a/src/game/server/ddracecommands.cpp +++ b/src/game/server/ddracecommands.cpp @@ -77,8 +77,7 @@ void CGameContext::MoveCharacter(int ClientID, int X, int Y, bool Raw) if(!pChr) return; - pChr->Core()->m_Pos.x += ((Raw) ? 1 : 32) * X; - pChr->Core()->m_Pos.y += ((Raw) ? 1 : 32) * Y; + pChr->Move(vec2((Raw ? 1 : 32) * X, Raw ? 1 : 32) * Y); pChr->m_DDRaceState = DDRACE_CHEAT; } @@ -348,7 +347,7 @@ void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData, void CGameContext::Teleport(CCharacter *pChr, vec2 Pos) { - pChr->Core()->m_Pos = Pos; + pChr->SetPosition(Pos); pChr->m_Pos = Pos; pChr->m_PrevPos = Pos; pChr->m_DDRaceState = DDRACE_CHEAT; @@ -412,7 +411,7 @@ void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData) } pSelf->Teleport(pChr, Pos); pChr->UnFreeze(); - pChr->Core()->m_Vel = vec2(0, 0); + pChr->SetVelocity(vec2(0, 0)); } } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index ad405eb287b..926b6e6a0a9 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -262,7 +262,7 @@ void CCharacter::HandleNinja() Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), GroundElasticity); // reset velocity so the client doesn't predict stuff - m_Core.m_Vel = vec2(0.f, 0.f); + ResetVelocity(); // check if we Hit anything along the way { @@ -698,11 +698,16 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput) mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); } -void CCharacter::ResetHook() +void CCharacter::ReleaseHook() { m_Core.SetHookedPlayer(-1); m_Core.m_HookState = HOOK_RETRACTED; m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; +} + +void CCharacter::ResetHook() +{ + ReleaseHook(); m_Core.m_HookPos = m_Core.m_Pos; } @@ -1640,7 +1645,7 @@ void CCharacter::HandleTiles(int Index) m_Core.m_Jumped = 0; m_Core.m_JumpedTotal = 0; } - m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel); + ApplyMoveRestrictions(); // handle switch tiles if(Collision()->GetSwitchType(MapIndex) == TILE_SWITCHOPEN && Team() != TEAM_SUPER && Collision()->GetSwitchNumber(MapIndex) > 0) @@ -2357,6 +2362,43 @@ CClientMask CCharacter::TeamMask() return Teams()->TeamMask(Team(), -1, GetPlayer()->GetCID()); } +void CCharacter::SetPosition(const vec2 &Position) +{ + m_Core.m_Pos = Position; +} + +void CCharacter::Move(vec2 RelPos) +{ + m_Core.m_Pos += RelPos; +} + +void CCharacter::ResetVelocity() +{ + m_Core.m_Vel = vec2(0, 0); +} + +void CCharacter::SetVelocity(vec2 NewVelocity) +{ + m_Core.m_Vel = ClampVel(m_MoveRestrictions, NewVelocity); +} + +// The method is needed only to reproduce 'shotgun bug' ddnet#5258 +// Use SetVelocity() instead. +void CCharacter::SetRawVelocity(vec2 NewVelocity) +{ + m_Core.m_Vel = NewVelocity; +} + +void CCharacter::AddVelocity(vec2 Addition) +{ + SetVelocity(m_Core.m_Vel + Addition); +} + +void CCharacter::ApplyMoveRestrictions() +{ + m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel); +} + void CCharacter::SwapClients(int Client1, int Client2) { const int HookedPlayer = m_Core.HookedPlayer(); diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 8f984b77015..52c3a5e1afa 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -60,6 +60,7 @@ class CCharacter : public CEntity void OnPredictedInput(CNetObj_PlayerInput *pNewInput); void OnDirectInput(CNetObj_PlayerInput *pNewInput); + void ReleaseHook(); void ResetHook(); void ResetInput(); void FireWeapon(); @@ -88,6 +89,15 @@ class CCharacter : public CEntity class CPlayer *GetPlayer() { return m_pPlayer; } CClientMask TeamMask(); + void SetPosition(const vec2 &Position); + void Move(vec2 RelPos); + + void ResetVelocity(); + void SetVelocity(vec2 NewVelocity); + void SetRawVelocity(vec2 NewVelocity); + void AddVelocity(vec2 Addition); + void ApplyMoveRestrictions(); + private: // player controlling this character class CPlayer *m_pPlayer; @@ -106,6 +116,8 @@ class CCharacter : public CEntity int m_ReloadTimer; int m_AttackTick; + int m_MoveRestrictions; + int m_DamageTaken; int m_EmoteType; @@ -201,8 +213,6 @@ class CCharacter : public CEntity int m_TileIndex; int m_TileFIndex; - int m_MoveRestrictions; - int64_t m_LastStartWarning; int64_t m_LastRescue; bool m_LastRefillJumps; @@ -226,7 +236,7 @@ class CCharacter : public CEntity void SetArmor(int Armor) { m_Armor = Armor; } CCharacterCore GetCore() { return m_Core; } void SetCore(CCharacterCore Core) { m_Core = Core; } - CCharacterCore *Core() { return &m_Core; } + const CCharacterCore *Core() const { return &m_Core; } bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; } void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; } int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; } diff --git a/src/game/server/entities/dragger_beam.cpp b/src/game/server/entities/dragger_beam.cpp index 26f03dab736..fb8f3f870d4 100644 --- a/src/game/server/entities/dragger_beam.cpp +++ b/src/game/server/entities/dragger_beam.cpp @@ -71,8 +71,7 @@ void CDraggerBeam::Tick() // In the center of the dragger a tee does not experience speed-up else if(distance(pTarget->m_Pos, m_Pos) > 28) { - vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength); - pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp); + pTarget->AddVelocity(normalize(m_Pos - pTarget->m_Pos) * m_Strength); } } diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp index 2907d5b9589..be4ed55c15e 100644 --- a/src/game/server/entities/laser.cpp +++ b/src/game/server/entities/laser.cpp @@ -44,9 +44,9 @@ bool CLaser::HitCharacter(vec2 From, vec2 To) bool pDontHitSelf = g_Config.m_SvOldLaser || (m_Bounces == 0 && !m_WasTele); if(pOwnerChar ? (!pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (!pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : g_Config.m_SvHit) - pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner); + pHit = GameWorld()->IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner); else - pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar); + pHit = GameWorld()->IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar); if(!pHit || (pHit == pOwnerChar && g_Config.m_SvOldLaser) || (pHit != pOwnerChar && pOwnerChar ? (pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : !g_Config.m_SvHit)) return false; @@ -55,42 +55,39 @@ bool CLaser::HitCharacter(vec2 From, vec2 To) m_Energy = -1; if(m_Type == WEAPON_SHOTGUN) { - vec2 Temp; - float Strength; if(!m_TuneZone) Strength = Tuning()->m_ShotgunStrength; else Strength = TuningList()[m_TuneZone].m_ShotgunStrength; - vec2 &HitPos = pHit->Core()->m_Pos; + const vec2 &HitPos = pHit->Core()->m_Pos; if(!g_Config.m_SvOldLaser) { if(m_PrevPos != HitPos) { - Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - HitPos) * Strength; - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp); + pHit->AddVelocity(normalize(m_PrevPos - HitPos) * Strength); } else { - pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; + pHit->SetRawVelocity(StackedLaserShotgunBugSpeed); } } else if(g_Config.m_SvOldLaser && pOwnerChar) { if(pOwnerChar->Core()->m_Pos != HitPos) { - Temp = pHit->Core()->m_Vel + normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength; - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp); + pHit->AddVelocity(normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength); } else { - pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; + pHit->SetRawVelocity(StackedLaserShotgunBugSpeed); } } else { - pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, pHit->Core()->m_Vel); + // Re-apply move restrictions as a part of 'shotgun bug' reproduction + pHit->ApplyMoveRestrictions(); } } else if(m_Type == WEAPON_LASER) diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index 9247cca8838..053c0a6d467 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -361,12 +361,9 @@ void CGameWorld::ReleaseHooked(int ClientID) CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER); for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) { - CCharacterCore *pCore = pChr->Core(); - if(pCore->HookedPlayer() == ClientID && !pChr->IsSuper()) + if(pChr->Core()->HookedPlayer() == ClientID && !pChr->IsSuper()) { - pCore->SetHookedPlayer(-1); - pCore->m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; - pCore->m_HookState = HOOK_RETRACTED; + pChr->ReleaseHook(); } } }