From 500ba7609f065d0df7e313c6acce023b6b0315f7 Mon Sep 17 00:00:00 2001 From: Freddie Wang Date: Thu, 13 May 2021 00:57:50 +0800 Subject: [PATCH 1/2] Respect tunezone for characters --- src/game/client/gameclient.cpp | 66 ++++++++++++++++++- src/game/client/gameclient.h | 4 ++ .../client/prediction/entities/character.cpp | 10 ++- .../client/prediction/entities/character.h | 3 + src/game/gamecore.cpp | 41 ++++++------ src/game/gamecore.h | 1 + src/game/server/entities/character.cpp | 4 +- 7 files changed, 103 insertions(+), 26 deletions(-) diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index c4f7605f6..80fe42c21 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -540,6 +540,15 @@ void CGameClient::OnReset() m_LastNewPredictedTick[0] = -1; m_LastNewPredictedTick[1] = -1; + m_LocalTuneZone[0] = 0; + m_LocalTuneZone[1] = 0; + + m_ExpectingTuningForZone[0] = -1; + m_ExpectingTuningForZone[1] = -1; + + m_ReceivedTuning[0] = false; + m_ReceivedTuning[1] = false; + InvalidateSnapshot(); for(auto &Client : m_aClients) @@ -782,6 +791,7 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, bool IsDummy) m_ServerMode = SERVERMODE_PURE; + m_ReceivedTuning[IsDummy ? !g_Config.m_ClDummy : g_Config.m_ClDummy] = true; // apply new tuning m_Tuning[IsDummy ? !g_Config.m_ClDummy : g_Config.m_ClDummy] = NewTuning; return; @@ -2233,10 +2243,62 @@ void CGameClient::UpdatePrediction() m_GameWorld.m_WorldConfig.m_IsSolo = !m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_HasExtendedData && !m_Tuning[g_Config.m_ClDummy].m_PlayerCollision && !m_Tuning[g_Config.m_ClDummy].m_PlayerHooking; // update the tuning/tunezone at the local character position with the latest tunings received before the new snapshot + vec2 LocalCharPos = vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y); + m_GameWorld.m_Core.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy]; + int TuneZone = 0; if(m_GameWorld.m_WorldConfig.m_UseTuneZones) - TuneZone = Collision()->IsTune(Collision()->GetMapIndex(vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y))); - m_GameWorld.TuningList()[TuneZone] = m_GameWorld.m_Core.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy]; + { + TuneZone = Collision()->IsTune(Collision()->GetMapIndex(LocalCharPos)); + + if(TuneZone != m_LocalTuneZone[g_Config.m_ClDummy]) + { + // our tunezone changed, expecting tuning message + m_LocalTuneZone[g_Config.m_ClDummy] = m_ExpectingTuningForZone[g_Config.m_ClDummy] = TuneZone; + m_ExpectingTuningSince[g_Config.m_ClDummy] = 0; + } + + if(m_ExpectingTuningForZone[g_Config.m_ClDummy] >= 0) + { + if(m_ReceivedTuning[g_Config.m_ClDummy]) + { + dbg_msg("tunezone", "got tuning for zone %d", m_ExpectingTuningForZone[g_Config.m_ClDummy]); + m_GameWorld.TuningList()[m_ExpectingTuningForZone[g_Config.m_ClDummy]] = m_Tuning[g_Config.m_ClDummy]; + m_ReceivedTuning[g_Config.m_ClDummy] = false; + m_ExpectingTuningForZone[g_Config.m_ClDummy] = -1; + } + else if(m_ExpectingTuningSince[g_Config.m_ClDummy] >= 5) + { + // if we are expecting tuning for more than 10 snaps (less than a quarter of a second) + // it is probably dropped or it was received out of order + // or applied to another tunezone. + // we need to fallback to current tuning to fix ourselves. + m_ExpectingTuningForZone[g_Config.m_ClDummy] = -1; + m_ExpectingTuningSince[g_Config.m_ClDummy] = 0; + m_ReceivedTuning[g_Config.m_ClDummy] = false; + dbg_msg("tunezone", "the tuning was missed"); + } + else + { + // if we are expecting tuning and have not received one yet. + // do not update any tuning, so we don't apply it to the wrong tunezone. + dbg_msg("tunezone", "waiting for tuning for zone %d", m_ExpectingTuningForZone[g_Config.m_ClDummy]); + m_ExpectingTuningSince[g_Config.m_ClDummy]++; + } + } + else + { + // if we have processed what we need, and the tuning is still wrong due to out of order messege + // fix our tuning by using the current one + m_GameWorld.TuningList()[TuneZone] = m_Tuning[g_Config.m_ClDummy]; + m_ExpectingTuningSince[g_Config.m_ClDummy] = 0; + m_ReceivedTuning[g_Config.m_ClDummy] = false; + } + } + else + { + m_GameWorld.TuningList()[0] = m_Tuning[g_Config.m_ClDummy]; + } // if ddnetcharacter is available, ignore server-wide tunings for hook and collision if(m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_HasExtendedData) diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 1c5857992..588c73a3e 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -238,6 +238,10 @@ public: }; CSnapState m_Snap; + int m_LocalTuneZone[2]; + bool m_ReceivedTuning[2]; + int m_ExpectingTuningForZone[2]; + int m_ExpectingTuningSince[2]; // client data struct CClientData diff --git a/src/game/client/prediction/entities/character.cpp b/src/game/client/prediction/entities/character.cpp index 7676fa376..06bed235e 100644 --- a/src/game/client/prediction/entities/character.cpp +++ b/src/game/client/prediction/entities/character.cpp @@ -864,9 +864,11 @@ void CCharacter::HandleTiles(int Index) void CCharacter::HandleTuneLayer() { int CurrentIndex = Collision()->GetMapIndex(m_Pos); - SetTuneZone(GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(CurrentIndex) : 0); + SetTuneZone(GameWorld()->m_WorldConfig.m_UseTuneZones ? 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 + if(m_IsLocal) + m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = *GetTuning(m_TuneZone); // throw tunings (from specific zone if in a tunezone) into gamecore if the character is local + m_Core.m_Tuning = *GetTuning(m_TuneZone); } void CCharacter::DDRaceTick() @@ -1003,6 +1005,7 @@ CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CEntity(pGameWorld, CGameWorld::ENTTYPE_CHARACTER) { m_ID = ID; + m_IsLocal = false; m_LastWeapon = WEAPON_HAMMER; m_QueuedWeapon = -1; @@ -1072,6 +1075,7 @@ void CCharacter::ResetPrediction() void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal) { m_Core.Read((CNetObj_CharacterCore *)pChar); + m_IsLocal = IsLocal; if(pExtended) { @@ -1213,7 +1217,7 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende m_LastSnapWeapon = pChar->m_Weapon; m_Alive = true; - SetTuneZone(GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0); + SetTuneZone(GameWorld()->m_WorldConfig.m_UseTuneZones ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0); // set the current weapon if(pChar->m_Weapon != WEAPON_NINJA) diff --git a/src/game/client/prediction/entities/character.h b/src/game/client/prediction/entities/character.h index 0a70d970d..eb8ed8cae 100644 --- a/src/game/client/prediction/entities/character.h +++ b/src/game/client/prediction/entities/character.h @@ -64,6 +64,7 @@ public: bool IsAlive() { return m_Alive; } bool m_Alive; + bool m_IsLocal; CTeamsCore *TeamsCore(); bool Freeze(int Time); @@ -197,6 +198,8 @@ private: void DDRacePostCoreTick(); void HandleTuneLayer(); + CTuningParams *CharacterTuning(); + int m_StrongWeakID; int m_LastWeaponSwitchTick; diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp index 5f9366c11..7abf17c61 100644 --- a/src/game/gamecore.cpp +++ b/src/game/gamecore.cpp @@ -64,6 +64,9 @@ void CCharacterCore::Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore m_pTeams = pTeams; m_Id = -1; + + // fail safe, if core's tuning didn't get updated at all, just fallback to world tuning. + m_Tuning = m_pWorld->m_Tuning[g_Config.m_ClDummy]; Reset(); } @@ -122,11 +125,11 @@ void CCharacterCore::Tick(bool UseInput) vec2 TargetDirection = normalize(vec2(m_Input.m_TargetX, m_Input.m_TargetY)); - m_Vel.y += m_pWorld->m_Tuning[g_Config.m_ClDummy].m_Gravity; + m_Vel.y += m_Tuning.m_Gravity; - float MaxSpeed = Grounded ? m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GroundControlSpeed : m_pWorld->m_Tuning[g_Config.m_ClDummy].m_AirControlSpeed; - float Accel = Grounded ? m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GroundControlAccel : m_pWorld->m_Tuning[g_Config.m_ClDummy].m_AirControlAccel; - float Friction = Grounded ? m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GroundFriction : m_pWorld->m_Tuning[g_Config.m_ClDummy].m_AirFriction; + float MaxSpeed = Grounded ? m_Tuning.m_GroundControlSpeed : m_Tuning.m_AirControlSpeed; + float Accel = Grounded ? m_Tuning.m_GroundControlAccel : m_Tuning.m_AirControlAccel; + float Friction = Grounded ? m_Tuning.m_GroundFriction : m_Tuning.m_AirFriction; // handle input if(UseInput) @@ -153,14 +156,14 @@ void CCharacterCore::Tick(bool UseInput) if(Grounded) { m_TriggeredEvents |= COREEVENT_GROUND_JUMP; - m_Vel.y = -m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GroundJumpImpulse; + m_Vel.y = -m_Tuning.m_GroundJumpImpulse; m_Jumped |= 1; m_JumpedTotal = 1; } else if(!(m_Jumped & 2)) { m_TriggeredEvents |= COREEVENT_AIR_JUMP; - m_Vel.y = -m_pWorld->m_Tuning[g_Config.m_ClDummy].m_AirJumpImpulse; + m_Vel.y = -m_Tuning.m_AirJumpImpulse; m_Jumped |= 3; m_JumpedTotal++; } @@ -178,7 +181,7 @@ void CCharacterCore::Tick(bool UseInput) m_HookPos = m_Pos + TargetDirection * PhysSize * 1.5f; m_HookDir = TargetDirection; m_HookedPlayer = -1; - m_HookTick = SERVER_TICK_SPEED * (1.25f - m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookDuration); + m_HookTick = SERVER_TICK_SPEED * (1.25f - m_Tuning.m_HookDuration); m_TriggeredEvents |= COREEVENT_HOOK_LAUNCH; } } @@ -226,11 +229,11 @@ void CCharacterCore::Tick(bool UseInput) } else if(m_HookState == HOOK_FLYING) { - vec2 NewPos = m_HookPos + m_HookDir * m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookFireSpeed; - if((!m_NewHook && distance(m_Pos, NewPos) > m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookLength) || (m_NewHook && distance(m_HookTeleBase, NewPos) > m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookLength)) + vec2 NewPos = m_HookPos + m_HookDir * m_Tuning.m_HookFireSpeed; + if((!m_NewHook && distance(m_Pos, NewPos) > m_Tuning.m_HookLength) || (m_NewHook && distance(m_HookTeleBase, NewPos) > m_Tuning.m_HookLength)) { m_HookState = HOOK_RETRACT_START; - NewPos = m_Pos + normalize(NewPos - m_Pos) * m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookLength; + NewPos = m_Pos + normalize(NewPos - m_Pos) * m_Tuning.m_HookLength; m_pReset = true; } @@ -255,7 +258,7 @@ void CCharacterCore::Tick(bool UseInput) } // Check against other players first - if(this->m_Hook && m_pWorld && m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking) + if(this->m_Hook && m_pWorld && m_Tuning.m_PlayerHooking) { float Distance = 0.0f; for(int i = 0; i < MAX_CLIENTS; i++) @@ -336,7 +339,7 @@ void CCharacterCore::Tick(bool UseInput) // don't do this hook rutine when we are hook to a player if(m_HookedPlayer == -1 && distance(m_HookPos, m_Pos) > 46.0f) { - vec2 HookVel = normalize(m_HookPos - m_Pos) * m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookDragAccel; + vec2 HookVel = normalize(m_HookPos - m_Pos) * m_Tuning.m_HookDragAccel; // the hook as more power to drag you up then down. // this makes it easier to get on top of an platform if(HookVel.y > 0) @@ -352,7 +355,7 @@ void CCharacterCore::Tick(bool UseInput) vec2 NewVel = m_Vel + HookVel; // check if we are under the legal limit for the hook - if(length(NewVel) < m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookDragSpeed || length(NewVel) < length(m_Vel)) + if(length(NewVel) < m_Tuning.m_HookDragSpeed || length(NewVel) < length(m_Vel)) m_Vel = NewVel; // no problem. apply } @@ -389,7 +392,7 @@ void CCharacterCore::Tick(bool UseInput) { vec2 Dir = normalize(m_Pos - pCharCore->m_Pos); - bool CanCollide = (m_Super || pCharCore->m_Super) || (pCharCore->m_Collision && m_Collision && !m_NoCollision && !pCharCore->m_NoCollision && m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision); + bool CanCollide = (m_Super || pCharCore->m_Super) || (pCharCore->m_Collision && m_Collision && !m_NoCollision && !pCharCore->m_NoCollision && m_Tuning.m_PlayerCollision); if(CanCollide && Distance < PhysSize * 1.25f && Distance > 0.0f) { @@ -406,12 +409,12 @@ void CCharacterCore::Tick(bool UseInput) } // handle hook influence - if(m_Hook && m_HookedPlayer == i && m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking) + if(m_Hook && m_HookedPlayer == i && m_Tuning.m_PlayerHooking) { if(Distance > PhysSize * 1.50f) // TODO: fix tweakable variable { - float Accel = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookDragAccel * (Distance / m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookLength); - float DragSpeed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_HookDragSpeed; + float Accel = m_Tuning.m_HookDragAccel * (Distance / m_Tuning.m_HookLength); + float DragSpeed = m_Tuning.m_HookDragSpeed; vec2 Temp; // add force to the hooked player @@ -440,7 +443,7 @@ void CCharacterCore::Tick(bool UseInput) void CCharacterCore::Move() { - float RampValue = VelocityRamp(length(m_Vel) * 50, m_pWorld->m_Tuning[g_Config.m_ClDummy].m_VelrampStart, m_pWorld->m_Tuning[g_Config.m_ClDummy].m_VelrampRange, m_pWorld->m_Tuning[g_Config.m_ClDummy].m_VelrampCurvature); + float RampValue = VelocityRamp(length(m_Vel) * 50, m_Tuning.m_VelrampStart, m_Tuning.m_VelrampRange, m_Tuning.m_VelrampCurvature); m_Vel.x = m_Vel.x * RampValue; @@ -462,7 +465,7 @@ void CCharacterCore::Move() m_Vel.x = m_Vel.x * (1.0f / RampValue); - if(m_pWorld && (m_Super || (m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision && m_Collision && !m_NoCollision && !m_Solo))) + if(m_pWorld && (m_Super || (m_Tuning.m_PlayerCollision && m_Collision && !m_NoCollision && !m_Solo))) { // check player collision float Distance = distance(m_Pos, NewPos); diff --git a/src/game/gamecore.h b/src/game/gamecore.h index d2d476fc7..1f122d427 100644 --- a/src/game/gamecore.h +++ b/src/game/gamecore.h @@ -265,6 +265,7 @@ public: bool m_HasTelegunLaser; int m_FreezeEnd; bool m_DeepFrozen; + CTuningParams m_Tuning; private: CTeamsCore *m_pTeams; diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 962bd4f33..a3472c0f0 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -2009,9 +2009,9 @@ void CCharacter::HandleTuneLayer() m_TuneZone = GameServer()->Collision()->IsTune(CurrentIndex); if(m_TuneZone) - m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = GameServer()->TuningList()[m_TuneZone]; // throw tunings from specific zone into gamecore + m_Core.m_Tuning = GameServer()->TuningList()[m_TuneZone]; // throw tunings from specific zone into gamecore else - m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = *GameServer()->Tuning(); + m_Core.m_Tuning = *GameServer()->Tuning(); if(m_TuneZone != m_TuneZoneOld) // don't send tunigs all the time { From ae6a78c0ca8925bb5cedfc711f2922b2b11164b2 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 19 May 2021 12:58:04 +0200 Subject: [PATCH 2/2] Try to fix clang-tidy warnings (untested) --- src/game/gamecore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp index 7abf17c61..98bab9bb7 100644 --- a/src/game/gamecore.cpp +++ b/src/game/gamecore.cpp @@ -298,7 +298,7 @@ void CCharacterCore::Tick(bool UseInput) m_HookState = HOOK_RETRACT_START; } - if(GoingThroughTele && m_pTeleOuts && m_pTeleOuts->size() && (*m_pTeleOuts)[teleNr - 1].size()) + if(GoingThroughTele && m_pWorld && m_pTeleOuts && m_pTeleOuts->size() && (*m_pTeleOuts)[teleNr - 1].size()) { m_TriggeredEvents = 0; m_HookedPlayer = -1; @@ -318,7 +318,7 @@ void CCharacterCore::Tick(bool UseInput) if(m_HookState == HOOK_GRABBED) { - if(m_HookedPlayer != -1) + if(m_HookedPlayer != -1 && m_pWorld) { CCharacterCore *pCharCore = m_pWorld->m_apCharacters[m_HookedPlayer]; if(pCharCore && m_Id != -1 && m_pTeams->CanKeepHook(m_Id, pCharCore->m_Id)) @@ -361,7 +361,7 @@ void CCharacterCore::Tick(bool UseInput) // release hook (max default hook time is 1.25 s) m_HookTick++; - if(m_HookedPlayer != -1 && (m_HookTick > SERVER_TICK_SPEED + SERVER_TICK_SPEED / 5 || !m_pWorld->m_apCharacters[m_HookedPlayer])) + if(m_HookedPlayer != -1 && (m_HookTick > SERVER_TICK_SPEED + SERVER_TICK_SPEED / 5 || (m_pWorld && !m_pWorld->m_apCharacters[m_HookedPlayer]))) { m_HookedPlayer = -1; m_HookState = HOOK_RETRACTED;