From 5f784cbcda0bc0690350520c7c019c04b7a48e7e Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Mon, 29 Apr 2024 08:25:34 +0800 Subject: [PATCH] Make sixup TriggeredEvents reliable Relevant upstream commit: https://github.com/teeworlds/teeworlds/commit/d2924b5ad6982945da5f2db299d964133a3e5e63 Closes https://github.com/ChillerDragon/ddnet/issues/7 The snap item obj_character contains a field called m_TriggeredEvents https://chillerdragon.github.io/teeworlds-protocol/07/snap_items.html#obj_character It is responsible for effects and sounds. Those flags are set in the gamecore. So if the servers gamecore ticks twice and resets the flags before a snap is sent the client misses the information. Which is not too big of a problem since the client has his own gamecore running (prediction) which also sets those flags. But it is still wrong and teeworlds does always include the triggered events in the snap. So this commit fixes it using the same approach as teeworlds. By not resetting the triggered events until a snap was sent. --- src/game/server/entities/character.cpp | 30 +++++++++++++++----------- src/game/server/entities/character.h | 3 +++ src/game/server/entity.h | 6 ++++++ src/game/server/gamecontext.cpp | 1 + src/game/server/gameworld.cpp | 13 +++++++++++ src/game/server/gameworld.h | 6 ++++++ 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 3465133c5..de6a54bce 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -28,6 +28,7 @@ CCharacter::CCharacter(CGameWorld *pWorld, CNetObj_PlayerInput LastInput) : { m_Health = 0; m_Armor = 0; + m_TriggeredEvents7 = 0; m_StrongWeakId = 0; m_Input = LastInput; @@ -861,6 +862,17 @@ void CCharacter::TickDeferred() if(Events & COREEVENT_HOOK_HIT_NOHOOK) GameServer()->CreateSound(m_Pos, SOUND_HOOK_NOATTACH, TeamMaskExceptSelf); + + if(Events & COREEVENT_GROUND_JUMP) + m_TriggeredEvents7 |= protocol7::COREEVENTFLAG_GROUND_JUMP; + if(Events & COREEVENT_AIR_JUMP) + m_TriggeredEvents7 |= protocol7::COREEVENTFLAG_AIR_JUMP; + if(Events & COREEVENT_HOOK_ATTACH_PLAYER) + m_TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_ATTACH_PLAYER; + if(Events & COREEVENT_HOOK_ATTACH_GROUND) + m_TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_ATTACH_GROUND; + if(Events & COREEVENT_HOOK_HIT_NOHOOK) + m_TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_HIT_NOHOOK; } if(m_pPlayer->GetTeam() == TEAM_SPECTATORS) @@ -1122,18 +1134,7 @@ void CCharacter::SnapCharacter(int SnappingClient, int Id) pCharacter->m_Health = Health; pCharacter->m_Armor = Armor; - int TriggeredEvents7 = 0; - if(m_Core.m_TriggeredEvents & COREEVENT_GROUND_JUMP) - TriggeredEvents7 |= protocol7::COREEVENTFLAG_GROUND_JUMP; - if(m_Core.m_TriggeredEvents & COREEVENT_AIR_JUMP) - TriggeredEvents7 |= protocol7::COREEVENTFLAG_AIR_JUMP; - if(m_Core.m_TriggeredEvents & COREEVENT_HOOK_ATTACH_PLAYER) - TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_ATTACH_PLAYER; - if(m_Core.m_TriggeredEvents & COREEVENT_HOOK_ATTACH_GROUND) - TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_ATTACH_GROUND; - if(m_Core.m_TriggeredEvents & COREEVENT_HOOK_HIT_NOHOOK) - TriggeredEvents7 |= protocol7::COREEVENTFLAG_HOOK_HIT_NOHOOK; - pCharacter->m_TriggeredEvents = TriggeredEvents7; + pCharacter->m_TriggeredEvents = m_TriggeredEvents7; } } @@ -1277,6 +1278,11 @@ void CCharacter::Snap(int SnappingClient) pDDNetCharacter->m_TargetY = m_Core.m_Input.m_TargetY; } +void CCharacter::PostSnap() +{ + m_TriggeredEvents7 = 0; +} + // DDRace bool CCharacter::CanCollide(int ClientId) diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 6d85e134a..d9670e194 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -38,6 +38,7 @@ public: void TickDeferred() override; void TickPaused() override; void Snap(int SnappingClient) override; + void PostSnap() override; void SwapClients(int Client1, int Client2) override; bool CanSnapCharacter(int SnappingClient); @@ -144,6 +145,8 @@ private: int m_Health; int m_Armor; + int m_TriggeredEvents7; + // the player core for the physics CCharacterCore m_Core; CGameTeams *m_pTeams = nullptr; diff --git a/src/game/server/entity.h b/src/game/server/entity.h index 07f64cf86..03930b252 100644 --- a/src/game/server/entity.h +++ b/src/game/server/entity.h @@ -122,6 +122,12 @@ public: // TODO: Maybe make protected */ virtual void Snap(int SnappingClient) {} + /* + Function: PostSnap + Called after all clients received their snapshot. + */ + virtual void PostSnap() {} + /* Function: SwapClients Called when two players have swapped their client ids. diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 7b6b0e22e..022b79cd9 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -4235,6 +4235,7 @@ void CGameContext::OnSnap(int ClientId) void CGameContext::OnPreSnap() {} void CGameContext::OnPostSnap() { + m_World.PostSnap(); m_Events.Clear(); } diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index 24e11ac19..6166d2ff1 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -129,6 +129,19 @@ void CGameWorld::Snap(int SnappingClient) } } +void CGameWorld::PostSnap() +{ + for(auto *pEnt : m_apFirstEntityTypes) + { + for(; pEnt;) + { + m_pNextTraverseEntity = pEnt->m_pNextTypeEntity; + pEnt->PostSnap(); + pEnt = m_pNextTraverseEntity; + } + } +} + void CGameWorld::Reset() { // reset all entities diff --git a/src/game/server/gameworld.h b/src/game/server/gameworld.h index 27568e3b2..15f338a2e 100644 --- a/src/game/server/gameworld.h +++ b/src/game/server/gameworld.h @@ -133,6 +133,12 @@ public: */ void Snap(int SnappingClient); + /* + Function: PostSnap + Called after all clients received their snapshot. + */ + void PostSnap(); + /* Function: Tick Calls Tick on all the entities in the world to progress