mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-12 19:18:20 +00:00
Merge #2512
2512: Fix prediction when chatting while shooting/walking (fixes #2506) r=def- a=trml Also fixed a case when switching to the dummy and back while holding fire (the reload timer should now stay in sync afterwards). Co-authored-by: trml <trml@users.noreply.github.com>
This commit is contained in:
commit
c6ec6c5e50
|
@ -17,10 +17,10 @@ void CCharacter::SetWeapon(int W)
|
||||||
|
|
||||||
m_LastWeapon = m_Core.m_ActiveWeapon;
|
m_LastWeapon = m_Core.m_ActiveWeapon;
|
||||||
m_QueuedWeapon = -1;
|
m_QueuedWeapon = -1;
|
||||||
m_Core.m_ActiveWeapon = W;
|
SetActiveWeapon(W);
|
||||||
|
|
||||||
if(m_Core.m_ActiveWeapon < 0 || m_Core.m_ActiveWeapon >= NUM_WEAPONS)
|
if(m_Core.m_ActiveWeapon < 0 || m_Core.m_ActiveWeapon >= NUM_WEAPONS)
|
||||||
m_Core.m_ActiveWeapon = 0;
|
SetActiveWeapon(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCharacter::SetSolo(bool Solo)
|
void CCharacter::SetSolo(bool Solo)
|
||||||
|
@ -497,6 +497,10 @@ void CCharacter::GiveNinja()
|
||||||
|
|
||||||
void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput)
|
void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput)
|
||||||
{
|
{
|
||||||
|
// skip the input if chat is active
|
||||||
|
if(pNewInput->m_PlayerFlags&PLAYERFLAG_CHATTING)
|
||||||
|
return;
|
||||||
|
|
||||||
// copy new input
|
// copy new input
|
||||||
mem_copy(&m_Input, pNewInput, sizeof(m_Input));
|
mem_copy(&m_Input, pNewInput, sizeof(m_Input));
|
||||||
//m_NumInputs++;
|
//m_NumInputs++;
|
||||||
|
@ -510,6 +514,15 @@ void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput)
|
||||||
|
|
||||||
void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
|
void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
|
||||||
{
|
{
|
||||||
|
// skip the input if chat is active
|
||||||
|
if(pNewInput->m_PlayerFlags&PLAYERFLAG_CHATTING)
|
||||||
|
{
|
||||||
|
// reset input
|
||||||
|
ResetInput();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_NumInputs++;
|
m_NumInputs++;
|
||||||
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
|
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
|
||||||
mem_copy(&m_LatestInput, pNewInput, sizeof(m_LatestInput));
|
mem_copy(&m_LatestInput, pNewInput, sizeof(m_LatestInput));
|
||||||
|
@ -527,6 +540,18 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
|
||||||
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
|
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCharacter::ResetInput()
|
||||||
|
{
|
||||||
|
m_Input.m_Direction = 0;
|
||||||
|
//m_Input.m_Hook = 0;
|
||||||
|
// simulate releasing the fire button
|
||||||
|
if((m_Input.m_Fire&1) != 0)
|
||||||
|
m_Input.m_Fire++;
|
||||||
|
m_Input.m_Fire &= INPUT_STATE_MASK;
|
||||||
|
m_Input.m_Jump = 0;
|
||||||
|
m_LatestPrevInput = m_LatestInput = m_Input;
|
||||||
|
}
|
||||||
|
|
||||||
void CCharacter::Tick()
|
void CCharacter::Tick()
|
||||||
{
|
{
|
||||||
DDRaceTick();
|
DDRaceTick();
|
||||||
|
@ -833,7 +858,7 @@ void CCharacter::HandleTiles(int Index)
|
||||||
void CCharacter::HandleTuneLayer()
|
void CCharacter::HandleTuneLayer()
|
||||||
{
|
{
|
||||||
int CurrentIndex = Collision()->GetMapIndex(m_Pos);
|
int CurrentIndex = Collision()->GetMapIndex(m_Pos);
|
||||||
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(CurrentIndex) : 0;
|
SetTuneZone(GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(CurrentIndex) : 0);
|
||||||
|
|
||||||
m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = *GetTuning(m_TuneZone); // throw tunings (from specific zone if in a tunezone) into gamecore
|
m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = *GetTuning(m_TuneZone); // throw tunings (from specific zone if in a tunezone) into gamecore
|
||||||
}
|
}
|
||||||
|
@ -1028,6 +1053,8 @@ void CCharacter::ResetPrediction()
|
||||||
m_Core.m_HookedPlayer = -1;
|
m_Core.m_HookedPlayer = -1;
|
||||||
m_Core.m_HookState = HOOK_IDLE;
|
m_Core.m_HookState = HOOK_IDLE;
|
||||||
}
|
}
|
||||||
|
m_LastWeaponSwitchTick = 0;
|
||||||
|
m_LastTuneZoneTick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal)
|
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal)
|
||||||
|
@ -1174,13 +1201,14 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
|
||||||
m_LastSnapWeapon = pChar->m_Weapon;
|
m_LastSnapWeapon = pChar->m_Weapon;
|
||||||
m_Alive = true;
|
m_Alive = true;
|
||||||
|
|
||||||
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
|
SetTuneZone(GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0);
|
||||||
|
|
||||||
// set the current weapon
|
// set the current weapon
|
||||||
if(pChar->m_Weapon != WEAPON_NINJA)
|
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;
|
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_Weapon != m_Core.m_ActiveWeapon)
|
||||||
|
SetActiveWeapon(pChar->m_Weapon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset all input except direction and hook for non-local players (as in vanilla prediction)
|
// reset all input except direction and hook for non-local players (as in vanilla prediction)
|
||||||
|
@ -1193,6 +1221,19 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
|
||||||
m_Input.m_TargetX = cosf(pChar->m_Angle/256.0f);
|
m_Input.m_TargetX = cosf(pChar->m_Angle/256.0f);
|
||||||
m_Input.m_TargetY = sinf(pChar->m_Angle/256.0f);
|
m_Input.m_TargetY = sinf(pChar->m_Angle/256.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in most cases the reload timer can be determined from the last attack tick
|
||||||
|
// (this is only needed for autofire weapons to prevent the predicted reload timer from desyncing)
|
||||||
|
if(IsLocal && m_Core.m_ActiveWeapon != WEAPON_HAMMER)
|
||||||
|
{
|
||||||
|
if(maximum(m_LastTuneZoneTick, m_LastWeaponSwitchTick) + GameWorld()->GameTickSpeed() < GameWorld()->GameTick())
|
||||||
|
{
|
||||||
|
float FireDelay;
|
||||||
|
GetTuning(m_TuneZone)->Get(38 + m_Core.m_ActiveWeapon, &FireDelay);
|
||||||
|
const int FireDelayTicks = FireDelay * GameWorld()->GameTickSpeed() / 1000;
|
||||||
|
m_ReloadTimer = maximum(0, m_AttackTick + FireDelayTicks - GameWorld()->GameTick());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCharacter::SetCoreWorld(CGameWorld *pGameWorld)
|
void CCharacter::SetCoreWorld(CGameWorld *pGameWorld)
|
||||||
|
@ -1208,3 +1249,17 @@ bool CCharacter::Match(CCharacter *pChar)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCharacter::SetActiveWeapon(int ActiveWeap)
|
||||||
|
{
|
||||||
|
m_Core.m_ActiveWeapon = ActiveWeap;
|
||||||
|
m_LastWeaponSwitchTick = GameWorld()->GameTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCharacter::SetTuneZone(int Zone)
|
||||||
|
{
|
||||||
|
if(Zone == m_TuneZone)
|
||||||
|
return;
|
||||||
|
m_TuneZone = Zone;
|
||||||
|
m_LastTuneZoneTick = GameWorld()->GameTick();
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
|
|
||||||
void OnPredictedInput(CNetObj_PlayerInput *pNewInput);
|
void OnPredictedInput(CNetObj_PlayerInput *pNewInput);
|
||||||
void OnDirectInput(CNetObj_PlayerInput *pNewInput);
|
void OnDirectInput(CNetObj_PlayerInput *pNewInput);
|
||||||
|
void ResetInput();
|
||||||
void FireWeapon();
|
void FireWeapon();
|
||||||
|
|
||||||
bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
|
bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
|
||||||
|
@ -104,7 +105,7 @@ public:
|
||||||
int GetLastWeapon() { return m_LastWeapon; };
|
int GetLastWeapon() { return m_LastWeapon; };
|
||||||
void SetLastWeapon(int LastWeap) { m_LastWeapon = LastWeap; };
|
void SetLastWeapon(int LastWeap) { m_LastWeapon = LastWeap; };
|
||||||
int GetActiveWeapon() { return m_Core.m_ActiveWeapon; };
|
int GetActiveWeapon() { return m_Core.m_ActiveWeapon; };
|
||||||
void SetActiveWeapon(int ActiveWeap) { m_Core.m_ActiveWeapon = ActiveWeap; };
|
void SetActiveWeapon(int ActiveWeap);
|
||||||
CCharacterCore GetCore() { return m_Core; };
|
CCharacterCore GetCore() { return m_Core; };
|
||||||
void SetCore(CCharacterCore Core) { m_Core = Core; };
|
void SetCore(CCharacterCore Core) { m_Core = Core; };
|
||||||
CCharacterCore* Core() { return &m_Core; };
|
CCharacterCore* Core() { return &m_Core; };
|
||||||
|
@ -134,6 +135,7 @@ public:
|
||||||
bool Match(CCharacter *pChar);
|
bool Match(CCharacter *pChar);
|
||||||
void ResetPrediction();
|
void ResetPrediction();
|
||||||
CCharacter() { m_Alive = false; }
|
CCharacter() { m_Alive = false; }
|
||||||
|
void SetTuneZone(int Zone);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// weapon info
|
// weapon info
|
||||||
|
@ -187,6 +189,9 @@ private:
|
||||||
void HandleTuneLayer();
|
void HandleTuneLayer();
|
||||||
|
|
||||||
int m_StrongWeakID;
|
int m_StrongWeakID;
|
||||||
|
|
||||||
|
int m_LastWeaponSwitchTick;
|
||||||
|
int m_LastTuneZoneTick;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
Loading…
Reference in a new issue