Skip to content

Commit

Permalink
Character: Incapsulate m_MoveRestrictions and m_Core
Browse files Browse the repository at this point in the history
Instead of leaking the m_MoveRestrictions to all classes which needs to
adjust the Character velocity, add a setter which takes into account those
restrictions.

The shotgun bug replication requires an access to the Velocity without the
restrictions applied (so we have to have this dirty setter).

Expose only *const* CCharacterCore to force the setters usage and prevent
incorrect write.
  • Loading branch information
Kaffeine committed Jan 21, 2024
1 parent 432b431 commit 386935f
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 53 deletions.
40 changes: 40 additions & 0 deletions src/game/client/prediction/entities/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
13 changes: 11 additions & 2 deletions src/game/client/prediction/entities/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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();
Expand All @@ -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
Expand All @@ -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; }
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/game/client/prediction/entities/dragger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
21 changes: 12 additions & 9 deletions src/game/client/prediction/entities/laser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 5 additions & 8 deletions src/game/client/prediction/gameworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/game/server/ddracechat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down
7 changes: 3 additions & 4 deletions src/game/server/ddracecommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}

Expand Down
48 changes: 45 additions & 3 deletions src/game/server/entities/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
16 changes: 13 additions & 3 deletions src/game/server/entities/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -106,6 +116,8 @@ class CCharacter : public CEntity
int m_ReloadTimer;
int m_AttackTick;

int m_MoveRestrictions;

int m_DamageTaken;

int m_EmoteType;
Expand Down Expand Up @@ -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;
Expand All @@ -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; }
Expand Down
3 changes: 1 addition & 2 deletions src/game/server/entities/dragger_beam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Loading

0 comments on commit 386935f

Please sign in to comment.