From 3c7f93dac49d49c365f5551dabbefc32ab89fa37 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Tue, 29 Sep 2026 03:25:15 -0500 Subject: [PATCH] feat(messages): read ModifyGhostingDistance LWOCharacterComponent sends ModifyGhostingDistance (1485: an optional fDistanceScalar, default 1) on load. All 239 live packets were the single byte 00 (default scale), so there is nothing for the server to change; it was logged as an unknown game message. It is now read and ignored. Check in game: nothing changes; the world server log no longer has "Received Unknown GM ... 1485" on each load. Co-Authored-By: Claude Opus 5.5 --- dGame/dGameMessages/GameMessageHandler.cpp | 1 + dGame/dGameMessages/MovementMessages.cpp | 9 +++++++++ dGame/dGameMessages/MovementMessages.h | 11 +++++++++++ .../dGameMessagesTests/ClientMessagesTests.cpp | 11 +++++++++++ 4 files changed, 32 insertions(+) diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 1d87239f5..a77e8dc42 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -220,6 +220,7 @@ namespace { { ACKNOWLEDGE_POSSESSION, []() { return std::make_unique(); } }, { TOGGLE_GHOST_REFERENCE_OVERRIDE, []() { return std::make_unique(); } }, { SET_GHOST_REFERENCE_POSITION, []() { return std::make_unique(); } }, + { MODIFY_GHOSTING_DISTANCE, []() { return std::make_unique(); } }, }; }; diff --git a/dGame/dGameMessages/MovementMessages.cpp b/dGame/dGameMessages/MovementMessages.cpp index 509fd7442..ea6fa48d5 100644 --- a/dGame/dGameMessages/MovementMessages.cpp +++ b/dGame/dGameMessages/MovementMessages.cpp @@ -396,6 +396,15 @@ namespace GameMessages { return ReadPoint(bitStream, pos); } + void ModifyGhostingDistance::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, fDistanceScalar, 1.0f); + } + + bool ModifyGhostingDistance::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fDistanceScalar, 1.0f)); + return true; + } + void SetGhostReferencePosition::Handle(Entity& entity, const SystemAddress& sysAddr) { auto* player = PlayerManager::GetPlayer(sysAddr); if (player == nullptr) return; diff --git a/dGame/dGameMessages/MovementMessages.h b/dGame/dGameMessages/MovementMessages.h index fbd94b030..a1a8524e4 100644 --- a/dGame/dGameMessages/MovementMessages.h +++ b/dGame/dGameMessages/MovementMessages.h @@ -253,6 +253,17 @@ namespace GameMessages { LWOOBJID possessedObjID{ LWOOBJID_EMPTY }; // optional }; + // Client -> server. LWOCharacterComponent sends it on load: a scale for the distance at which objects are ghosted + // for this player. All 239 live packets left the optional scale at its default (1), so the server keeps its own + // ghosting distances. + struct ModifyGhostingDistance : public NetGameMsg { + ModifyGhostingDistance() : NetGameMsg(MessageType::Game::MODIFY_GHOSTING_DISTANCE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float fDistanceScalar{ 1.0f }; // optional + }; + // Client -> server. struct ToggleGhostReferenceOverride : public NetGameMsg { ToggleGhostReferenceOverride() : NetGameMsg(MessageType::Game::TOGGLE_GHOST_REFERENCE_OVERRIDE) {} diff --git a/tests/dGameTests/dGameMessagesTests/ClientMessagesTests.cpp b/tests/dGameTests/dGameMessagesTests/ClientMessagesTests.cpp index 9d332850b..e712a5fcb 100644 --- a/tests/dGameTests/dGameMessagesTests/ClientMessagesTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/ClientMessagesTests.cpp @@ -12,6 +12,7 @@ #include "Entity.h" #include "InventoryComponent.h" #include "InventoryMessages.h" +#include "MovementMessages.h" #include "PlayerMessages.h" #include @@ -144,3 +145,13 @@ TEST_F(ClientMessagesTests, ResyncEquipmentResendsTheEquipment) { ASSERT_TRUE(resent.Read(equipmentSent)); EXPECT_TRUE(equipmentSent); } + +// ModifyGhostingDistance (1485): an optional scale, default 1. Every one of the 239 live packets was the default. +TEST_F(ClientMessagesTests, ModifyGhostingDistanceMatchesLiveCapture) { + auto msg = FromLiveClientCapture(std::string(PLAYER_HEADER) + "cd05" + "00"); + EXPECT_EQ(msg.fDistanceScalar, 1.0f); + msg.fDistanceScalar = 0.5f; + EXPECT_EQ(RoundTrip(msg).fDistanceScalar, 0.5f); + ExpectTruncatedFails(msg); + msg.Handle(*player, UNASSIGNED_SYSTEM_ADDRESS); // nothing to do +}