Skip to content

Commit

Permalink
Move early weapon physics into gameworld
Browse files Browse the repository at this point in the history
  • Loading branch information
sjrc6 committed Jun 2, 2024
1 parent e3723d3 commit 9c6e8c9
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 14 deletions.
4 changes: 1 addition & 3 deletions src/engine/server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1661,13 +1661,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)

m_aClients[ClientId].m_LastInputTick = IntendedTick;

CClient::CInput *pInput = &m_aClients[ClientId].m_aInputs[BufferPosition];

// TODO: This should probably not be here, the most recent input can be found by looping over the ring buffer
// so we should not change the inputs original intended tick since we might need that information
if(IntendedTick <= Tick())
IntendedTick = Tick() + 1;

CClient::CInput *pInput = &m_aClients[ClientId].m_aInputs[BufferPosition];
pInput->m_GameTick = IntendedTick;

for(int i = 0; i < Size / 4; i++)
Expand Down Expand Up @@ -2949,7 +2948,6 @@ int CServer::Run()
if(!ClientHadInput)
GameServer()->OnClientPredictedInput(c, nullptr);
}

GameServer()->OnTick();
if(ErrorShutdown())
{
Expand Down
29 changes: 25 additions & 4 deletions src/game/server/entities/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ void CCharacter::HandleWeaponSwitch()
DoWeaponSwitch();
}

void CCharacter::FireWeapon()
void CCharacter::FireWeapon(bool EarlyFire)
{
if(m_ReloadTimer != 0)
{
Expand Down Expand Up @@ -514,6 +514,10 @@ void CCharacter::FireWeapon()
else
Lifetime = (int)(Server()->TickSpeed() * TuningList()[m_TuneZone].m_GunLifetime);

int StartTick = Server()->Tick();
if(EarlyFire)
StartTick--;

new CProjectile(
GameWorld(),
WEAPON_GUN, //Type
Expand All @@ -524,7 +528,10 @@ void CCharacter::FireWeapon()
false, //Freeze
false, //Explosive
-1, //SoundImpact
MouseTarget //InitDir
MouseTarget, //InitDir
0,
0,
StartTick // StartTick
);

GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
Expand Down Expand Up @@ -553,6 +560,10 @@ void CCharacter::FireWeapon()
else
Lifetime = (int)(Server()->TickSpeed() * TuningList()[m_TuneZone].m_GrenadeLifetime);

int StartTick = Server()->Tick();
if(EarlyFire)
StartTick--;

new CProjectile(
GameWorld(),
WEAPON_GRENADE, //Type
Expand All @@ -563,7 +574,10 @@ void CCharacter::FireWeapon()
false, //Freeze
true, //Explosive
SOUND_GRENADE_EXPLODE, //SoundImpact
MouseTarget // MouseTarget
MouseTarget, // MouseTarget
0,
0,
StartTick //StartTick
);

GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask());
Expand Down Expand Up @@ -598,6 +612,8 @@ void CCharacter::FireWeapon()
}

m_AttackTick = Server()->Tick();
if(EarlyFire)
m_AttackTick--;

if(!m_ReloadTimer)
{
Expand Down Expand Up @@ -693,7 +709,7 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
if(m_NumInputs > 1 && m_pPlayer->GetTeam() != TEAM_SPECTATORS)
{
HandleWeaponSwitch();
FireWeapon();
FireWeapon(true);
}

mem_copy(&m_LatestPrevPrevInput, &m_LatestPrevInput, sizeof(m_LatestInput));
Expand Down Expand Up @@ -724,6 +740,11 @@ void CCharacter::ResetInput()
m_LatestPrevInput = m_LatestInput = m_Input;
}

void CCharacter::WeaponTick()
{
OnDirectInput(&m_Input);
}

void CCharacter::PreTick()
{
if(m_StartTime > Server()->Tick())
Expand Down
4 changes: 3 additions & 1 deletion src/game/server/entities/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CCharacter : public CEntity
void Reset() override;
void Destroy() override;
void PreTick();
void WeaponTick();
void Tick() override;
void TickDeferred() override;
void TickPaused() override;
Expand Down Expand Up @@ -61,10 +62,11 @@ class CCharacter : public CEntity

void OnPredictedInput(CNetObj_PlayerInput *pNewInput);
void OnDirectInput(CNetObj_PlayerInput *pNewInput);

void ReleaseHook();
void ResetHook();
void ResetInput();
void FireWeapon();
void FireWeapon(bool EarlyFire = false);

void Die(int Killer, int Weapon, bool SendKillMsg = true);
bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
Expand Down
7 changes: 6 additions & 1 deletion src/game/server/entities/projectile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ CProjectile::CProjectile(
int SoundImpact,
vec2 InitDir,
int Layer,
int Number) :
int Number,
int StartTick) :
CEntity(pGameWorld, CGameWorld::ENTTYPE_PROJECTILE)
{
m_Type = Type;
Expand All @@ -34,6 +35,10 @@ CProjectile::CProjectile(
//m_Damage = Damage;
m_SoundImpact = SoundImpact;
m_StartTick = Server()->Tick();

if(StartTick >= 0)
m_StartTick = StartTick;

m_Explosive = Explosive;

m_Layer = Layer;
Expand Down
3 changes: 2 additions & 1 deletion src/game/server/entities/projectile.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class CProjectile : public CEntity
int SoundImpact,
vec2 InitDir,
int Layer = 0,
int Number = 0);
int Number = 0,
int StartTick = -1);

vec2 GetPos(float Time);
void FillInfo(CNetObj_Projectile *pProj);
Expand Down
6 changes: 4 additions & 2 deletions src/game/server/gamecontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,8 @@ void CGameContext::OnClientFreshInput(int ClientId, void *pInput)
}
}

// Called once per input that happens on this tick after OnClientPredictedEarlyInput is called. pInput is nullptr if the client did not send any fresh input this tick
// Called once per input that happens on this tick after OnClientPredictedEarlyInput is called.
// pInput is nullptr if the client did not send any fresh input this tick.
void CGameContext::OnClientPredictedInput(int ClientId, void *pInput)
{
// early return if no input has ever been sent by the player
Expand All @@ -1333,7 +1334,8 @@ void CGameContext::OnClientPredictedInput(int ClientId, void *pInput)
m_apPlayers[ClientId]->OnPlayerInput(pApplyInput);
}

// Called once per tick BEFORE OnClientPredictedInput. pInput is nullptr if the client did not send any fresh input this tick
// Called once per tick BEFORE OnClientPredictedInput.
// pInput is nullptr if the client did not send any fresh input this tick.
void CGameContext::OnClientPredictedEarlyInput(int ClientId, void *pInput)
{
// early return if no input has ever been sent by the player
Expand Down
9 changes: 9 additions & 0 deletions src/game/server/gameworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ void CGameWorld::Tick()
if(GameServer()->m_pController->IsForceBalanced())
GameServer()->SendChat(-1, TEAM_ALL, "Teams have been balanced");

// This is placed here so that certain weapon physics can happen before the regular Charecter Tick() to preserve physics accuracy
auto *pEnt = m_apFirstEntityTypes[ENTTYPE_CHARACTER];
for(; pEnt;)
{
m_pNextTraverseEntity = pEnt->m_pNextTypeEntity;
((CCharacter *)pEnt)->WeaponTick();
pEnt = m_pNextTraverseEntity;
}

// update all objects
for(int i = 0; i < NUM_ENTTYPES; i++)
{
Expand Down
4 changes: 2 additions & 2 deletions src/game/server/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,8 @@ void CPlayer::OnPredictedEarlyInput(CNetObj_PlayerInput *pNewInput)
if(m_PlayerFlags & PLAYERFLAG_CHATTING)
return;

if(m_pCharacter && !m_Paused)
m_pCharacter->OnDirectInput(pNewInput);
//if(m_pCharacter && !m_Paused)
//m_pCharacter->OnDirectInput(pNewInput);
}

int CPlayer::GetClientVersion() const
Expand Down

0 comments on commit 9c6e8c9

Please sign in to comment.