diff --git a/dGame/dGameMessages/CombatMessages.cpp b/dGame/dGameMessages/CombatMessages.cpp index dba6dc2e4..b9283a5b6 100644 --- a/dGame/dGameMessages/CombatMessages.cpp +++ b/dGame/dGameMessages/CombatMessages.cpp @@ -1,5 +1,6 @@ #include "CombatMessages.h" +#include "CheatDetection.h" #include "BitStreamUtils.h" #include "ControllablePhysicsComponent.h" #include "CppScripts.h" @@ -69,6 +70,13 @@ namespace GameMessages { void RequestDie::Handle(Entity& entityRef, const SystemAddress& sysAddr) { Entity* entity = &entityRef; + + // A player asks for their own death or that of the vehicle they drive + if (!CheatDetection::IsSendersPlayer(entity->GetObjectID(), sysAddr)) { + LOG("Object %llu (LOT %i) is not the player that asked for its death or their vehicle", entity->GetObjectID(), entity->GetLOT()); + return; + } + auto* zoneController = Game::zoneManager->GetZoneControlObject(); auto* racingControlComponent = zoneController->GetComponent(); @@ -103,6 +111,11 @@ namespace GameMessages { } void RequestSmashPlayer::Handle(Entity& entity, const SystemAddress& sysAddr) { + // A player asks for their own smash + if (!entity.IsPlayer() || entity.GetSystemAddress() != sysAddr) { + LOG("Object %llu (LOT %i) is not the player that asked for its smash", entity.GetObjectID(), entity.GetLOT()); + return; + } entity.Smash(entity.GetObjectID()); } diff --git a/dGame/dGameMessages/PlayerMessages.cpp b/dGame/dGameMessages/PlayerMessages.cpp index 52bff2c8c..909ccf619 100644 --- a/dGame/dGameMessages/PlayerMessages.cpp +++ b/dGame/dGameMessages/PlayerMessages.cpp @@ -1,5 +1,6 @@ #include "PlayerMessages.h" +#include "Logger.h" #include "BitStreamUtils.h" #include "Character.h" #include "CharacterComponent.h" @@ -190,6 +191,11 @@ namespace GameMessages { } void ParseChatMessage::Handle(Entity& entity, const SystemAddress& sysAddr) { + // A chat command runs for the player that typed it + if (!entity.IsPlayer() || entity.GetSystemAddress() != sysAddr) { + LOG("Object %llu (LOT %i) is not the player that sent a chat command for it", entity.GetObjectID(), entity.GetLOT()); + return; + } if (!wsString.empty() && wsString[0] == L'/') { SlashCommandHandler::HandleChatCommand(wsString, &entity, sysAddr); } diff --git a/dGame/dGameMessages/RacingMessages.cpp b/dGame/dGameMessages/RacingMessages.cpp index 32b7679cb..b4ac589a9 100644 --- a/dGame/dGameMessages/RacingMessages.cpp +++ b/dGame/dGameMessages/RacingMessages.cpp @@ -1,5 +1,7 @@ #include "RacingMessages.h" +#include "CheatDetection.h" +#include "PossessorComponent.h" #include "BitStreamUtils.h" #include "CharacterComponent.h" #include "Entity.h" @@ -215,6 +217,21 @@ namespace GameMessages { return; } + // A player reports the pickups their own vehicle drove through + if (!CheatDetection::IsSendersPlayer(vehicle.GetObjectID(), sysAddr)) { + LOG("Object %llu (LOT %i) is not the vehicle of the player that reported a pickup for it", vehicle.GetObjectID(), vehicle.GetLOT()); + return; + } + + // Pickups are objects of a race track, and never a player, a vehicle or the zone's own object + const auto* const zoneControl = Game::zoneManager->GetZoneControlObject(); + if (!zoneControl || !zoneControl->GetComponent() + || pickup == zoneControl || pickup->IsPlayer() + || pickup->GetComponent() || pickup->GetComponent()) { + LOG("Object %llu (LOT %i) is not a pickup of a race track", pickupObjID, pickup->GetLOT()); + return; + } + // The sender is the vehicle; credit its driver if it has one. Entity* entity = &vehicle; auto* possessableComponent = entity->GetComponent(); diff --git a/dGame/dGameMessages/ZoneMessages.cpp b/dGame/dGameMessages/ZoneMessages.cpp index e70882337..5937a01e4 100644 --- a/dGame/dGameMessages/ZoneMessages.cpp +++ b/dGame/dGameMessages/ZoneMessages.cpp @@ -1,4 +1,5 @@ #include "ZoneMessages.h" +#include "Logger.h" #include "MovementMessages.h" #include "MissionMessages.h" @@ -63,6 +64,11 @@ namespace GameMessages { void PlayerLoaded::Handle(Entity& entityRef, const SystemAddress& sysAddr) { auto* entity = &entityRef; + // A player reports that they themselves have loaded + if (!entity->IsPlayer() || entity->GetSystemAddress() != sysAddr) { + LOG("Object %llu (LOT %i) is not the player that reported it as loaded", entity->GetObjectID(), entity->GetLOT()); + return; + } const auto* const zoneControlEntity = Game::entityManager->GetZoneControlEntity(); SendPlayerReady(entity->GetObjectID(), zoneControlEntity ? zoneControlEntity->GetObjectID() : LWOOBJID_EMPTY, sysAddr); entity->SetPlayerReadyForUpdates(); diff --git a/dGame/dUtilities/CheatDetection.cpp b/dGame/dUtilities/CheatDetection.cpp index acc415a69..9c34a00e6 100644 --- a/dGame/dUtilities/CheatDetection.cpp +++ b/dGame/dUtilities/CheatDetection.cpp @@ -105,6 +105,12 @@ void CheatDetection::ReportCheat(User* user, const SystemAddress& sysAddr, const va_end(args); } +bool CheatDetection::IsSendersPlayer(const LWOOBJID& id, const SystemAddress& sysAddr) { + // The player themselves, or the player that possesses the object + const auto* const entity = GetPossessedEntity(id); + return entity && entity->IsPlayer() && entity->GetSystemAddress() == sysAddr; +} + bool CheatDetection::VerifyLwoobjidIsSender(const LWOOBJID& id, const SystemAddress& sysAddr, const CheckType checkType, const char* messageIfNotSender, ...) { // Get variables we'll need for the whole function bool invalidPacket = false; diff --git a/dGame/dUtilities/CheatDetection.h b/dGame/dUtilities/CheatDetection.h index ee0dce89b..a80a25782 100644 --- a/dGame/dUtilities/CheatDetection.h +++ b/dGame/dUtilities/CheatDetection.h @@ -24,6 +24,15 @@ namespace CheatDetection { */ bool VerifyLwoobjidIsSender(const LWOOBJID& id, const SystemAddress& sysAddr, const CheckType checkType, const char* messageIfNotSender, ...); void ReportCheat(User* user, const SystemAddress& sysAddr, const char* messageIfNotSender, ...); + + /** + * @brief Whether an object is the player at a system address or the object that player possesses, such as their vehicle. + * Unlike VerifyLwoobjidIsSender this is false for every other object, so it is for messages only a player sends about themselves. + * + * @param id The object ID a message was sent for + * @param sysAddr The system address which sent the message + */ + bool IsSendersPlayer(const LWOOBJID& id, const SystemAddress& sysAddr); }; #endif //!__CHEATDETECTION__H__