diff --git a/dGame/dComponents/Character/CharacterComponent.cpp b/dGame/dComponents/Character/CharacterComponent.cpp index f363841e9..ebc45df96 100644 --- a/dGame/dComponents/Character/CharacterComponent.cpp +++ b/dGame/dComponents/Character/CharacterComponent.cpp @@ -245,11 +245,15 @@ void CharacterComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInit outBitStream.Write(m_GMLevel); outBitStream.Write(m_EditorEnabled); outBitStream.Write(m_EditorLevel); + if (!bIsInitialUpdate) m_DirtyGMInfo = false; } const bool writeCurrentActivity = bIsInitialUpdate || m_DirtyCurrentActivity; outBitStream.Write(writeCurrentActivity); - if (writeCurrentActivity) outBitStream.Write(m_CurrentActivity); + if (writeCurrentActivity) { + outBitStream.Write(m_CurrentActivity); + if (!bIsInitialUpdate) m_DirtyCurrentActivity = false; + } const bool writeSocialInfo = bIsInitialUpdate || m_DirtySocialInfo; outBitStream.Write(writeSocialInfo); diff --git a/tests/dGameTests/dComponentsTests/ReplicaConstructionTests.cpp b/tests/dGameTests/dComponentsTests/ReplicaConstructionTests.cpp index 798089e8c..1672577cb 100644 --- a/tests/dGameTests/dComponentsTests/ReplicaConstructionTests.cpp +++ b/tests/dGameTests/dComponentsTests/ReplicaConstructionTests.cpp @@ -23,6 +23,7 @@ #include "MovingPlatformComponent.h" #include "SimplePhysicsComponent.h" #include "User.h" +#include "eGameActivity.h" #include "eReplicaComponentType.h" #include "eReplicaPacketType.h" @@ -130,6 +131,48 @@ TEST_F(ReplicaConstructionTest, CharacterConstructionAlwaysWritesGmActivityAndSo player.SetCharacter(nullptr); } +// A current-activity or PVP change is written once, as a guild change is: LWOCharacterComponent::Deserialize reads each +// block behind its own flag bit. +TEST_F(ReplicaConstructionTest, CharacterActivityAndPvpChangesAreWrittenOnce) { + User user(UNASSIGNED_SYSTEM_ADDRESS, "tester", "key"); + Character character(1, &user); + info.lot = 1; + Entity player(1152921506064087005, info); + player.SetCharacter(&character); + character.SetEntity(&player); + auto* const component = player.AddComponent(-1, &character, UNASSIGNED_SYSTEM_ADDRESS); + + component->SetCurrentActivity(eGameActivity::QUICKBUILDING); + component->SetPvpEnabled(true); + RakNet::BitStream serialization; + component->Serialize(serialization, false); + RakNet::BitStream expected; + expected.Write1(); // gm_pvp_info + expected.Write1(); // pvp_enabled + expected.Write0(); // is_gm + expected.Write(0); // gm_level + expected.Write0(); // editor_enabled + expected.Write(0); // editor_level + expected.Write1(); // current_activity + expected.Write(eGameActivity::QUICKBUILDING); + expected.Write0(); // social_info + ExpectSameBits(serialization, expected); + + RakNet::BitStream again; + component->Serialize(again, false); + EXPECT_EQ(again.GetNumberOfBitsUsed(), 3u); + + // A construction in between (another player coming into range) doesn't swallow a pending change + component->SetCurrentActivity(eGameActivity::NONE); + RakNet::BitStream construction; + component->Serialize(construction, true); + RakNet::BitStream after; + component->Serialize(after, false); + EXPECT_EQ(after.GetNumberOfBitsUsed(), 3u + 32u); + + player.SetCharacter(nullptr); +} + // A guild change (docs/Guilds.md) is written once: the client reads guild id, a u8 length and 16-bit characters, and // redraws the name billboard every time it reads a name. TEST_F(ReplicaConstructionTest, CharacterGuildChangeIsWrittenOnce) {