From 718bd78e8cc9e82bc767bbf4a5c4582a099a3184 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Tue, 10 Nov 2026 13:08:57 -0600 Subject: [PATCH] fix: check for the player before handling the messages a player sends Several messages used the player, the character or the user they named without checking that there is one. A match request and a trade request are now only handled for the player that sent them, a linked mission request and a build mode change only for the sending player, and the remaining handlers return when the player, character or user is missing. Co-Authored-By: Claude Fable 5.2 --- dGame/dGameMessages/ActivityMessages.cpp | 5 +++++ dGame/dGameMessages/BuildingMessages.cpp | 13 +++++++++---- dGame/dGameMessages/MissionMessages.cpp | 6 ++++++ dGame/dGameMessages/ObjectMessages.cpp | 2 +- dGame/dGameMessages/TradeMessages.cpp | 8 ++++++++ dGame/dUtilities/SlashCommands/DEVGMCommands.cpp | 1 + 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/dGame/dGameMessages/ActivityMessages.cpp b/dGame/dGameMessages/ActivityMessages.cpp index 673fcca43..8c787f51c 100644 --- a/dGame/dGameMessages/ActivityMessages.cpp +++ b/dGame/dGameMessages/ActivityMessages.cpp @@ -136,6 +136,11 @@ namespace GameMessages { } void MatchRequest::Handle(Entity& entity, const SystemAddress& sysAddr) { + // A player asks for their own match + if (!entity.IsPlayer() || entity.GetSystemAddress() != sysAddr) { + LOG("Object %llu (LOT %i) is not the player that sent a match request for it", entity.GetObjectID(), entity.GetLOT()); + return; + } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); if (type == 0) { // join if (value != 0) { diff --git a/dGame/dGameMessages/BuildingMessages.cpp b/dGame/dGameMessages/BuildingMessages.cpp index eb82a1d14..1534c00a5 100644 --- a/dGame/dGameMessages/BuildingMessages.cpp +++ b/dGame/dGameMessages/BuildingMessages.cpp @@ -1,5 +1,6 @@ #include "BuildingMessages.h" +#include "PlayerManager.h" #include "BitStreamUtils.h" #include "Character.h" #include "ClientPackets.h" @@ -99,9 +100,8 @@ namespace GameMessages { LOG("Handling start building with item (%i): (%d) (%d) (%i) (%llu) (%i) (%i) (%llu) (%i) (%i)", entity.GetLOT(), firstTime, success, sourceBag, sourceId, sourceLot, arrangedSourceType, targetId, targetLot, targetType); - auto* user = UserManager::Instance()->GetUser(sysAddr); - - auto* player = Game::entityManager->GetEntity(user->GetLoggedInChar()); + auto* player = PlayerManager::GetPlayer(sysAddr); + if (!player) return; StartArrangingWithItem arranging; arranging.target = player->GetObjectID(); @@ -435,7 +435,12 @@ namespace GameMessages { void SetBuildMode::Handle(Entity& entity, const SystemAddress& sysAddr) { auto* player = Game::entityManager->GetEntity(playerId); - if (!player || !player->GetCharacter()) return; + + // A player sets their own build mode + if (!player || !player->IsPlayer() || player->GetSystemAddress() != sysAddr || !player->GetCharacter()) { + LOG("Player %llu of a build mode change is not the player that sent it", playerId); + return; + } auto confirmedStartPos = startPos; if (confirmedStartPos == NiPoint3Constant::ZERO) { diff --git a/dGame/dGameMessages/MissionMessages.cpp b/dGame/dGameMessages/MissionMessages.cpp index 26aeeb4e0..0c21df6ba 100644 --- a/dGame/dGameMessages/MissionMessages.cpp +++ b/dGame/dGameMessages/MissionMessages.cpp @@ -223,6 +223,12 @@ namespace GameMessages { void RequestLinkedMission::Handle(Entity& entity, const SystemAddress& sysAddr) { auto* player = Game::entityManager->GetEntity(playerID); + // A player asks for the missions offered to themselves + if (!player || !player->IsPlayer() || player->GetSystemAddress() != sysAddr) { + LOG("Player %llu of a linked mission request is not the player that sent it", playerID); + return; + } + auto* missionOfferComponent = static_cast(entity.GetComponent(eReplicaComponentType::MISSION_OFFER)); if (missionOfferComponent != nullptr) { diff --git a/dGame/dGameMessages/ObjectMessages.cpp b/dGame/dGameMessages/ObjectMessages.cpp index 588afbc10..e3d7f65ad 100644 --- a/dGame/dGameMessages/ObjectMessages.cpp +++ b/dGame/dGameMessages/ObjectMessages.cpp @@ -246,7 +246,7 @@ namespace GameMessages { return; } - if (interactedObject->GetLOT() == 9524) { + if (interactedObject->GetLOT() == 9524 && entity.GetCharacter()) { entity.GetCharacter()->SetBuildMode(true); } diff --git a/dGame/dGameMessages/TradeMessages.cpp b/dGame/dGameMessages/TradeMessages.cpp index 48df485f6..2d21720fd 100644 --- a/dGame/dGameMessages/TradeMessages.cpp +++ b/dGame/dGameMessages/TradeMessages.cpp @@ -114,8 +114,15 @@ namespace GameMessages { } void ClientTradeRequest::Handle(Entity& entity, const SystemAddress& sysAddr) { + // A player asks for their own trade + if (!entity.IsPlayer() || entity.GetSystemAddress() != sysAddr) { + LOG("Object %llu (LOT %i) is not the player that sent a trade request for it", entity.GetObjectID(), entity.GetLOT()); + return; + } + // Check if the player has restricted trade access auto* character = entity.GetCharacter(); + if (!character || !character->GetParentUser()) return; const bool restrictTradeOnMute = UserManager::Instance()->GetMuteRestrictTrade(); if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) { @@ -132,6 +139,7 @@ namespace GameMessages { if (invitee != nullptr && invitee->IsPlayer()) { character = invitee->GetCharacter(); + if (!character || !character->GetParentUser()) return; if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) { // Send a message to the player diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index 2260f3283..e4d4a1b62 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -70,6 +70,7 @@ namespace DEVGMCommands { void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { User* user = UserManager::Instance()->GetUser(entity->GetSystemAddress()); + if (!user) return; const auto level_intermed = GeneralUtils::TryParse(args); if (!level_intermed) {