From f170b46a5e3172883a0282095d9e6ee937fe98eb Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Tue, 10 Nov 2026 13:05:08 -0600 Subject: [PATCH] fix: check the player's score before a level up A level up was applied every time the client reported one. The next level now has to exist, the player needs the score that level asks for, and the message has to come from the player it is for. Co-Authored-By: Claude Fable 5.2 --- dGame/dGameMessages/ZoneMessages.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dGame/dGameMessages/ZoneMessages.cpp b/dGame/dGameMessages/ZoneMessages.cpp index 5d7b11804..e70882337 100644 --- a/dGame/dGameMessages/ZoneMessages.cpp +++ b/dGame/dGameMessages/ZoneMessages.cpp @@ -5,6 +5,8 @@ #include "BitStreamUtils.h" #include "CDClientManager.h" #include "Character.h" +#include "CDClientManager.h" +#include "CDLevelProgressionLookupTable.h" #include "CharacterComponent.h" #include "CppScripts.h" #include "DestroyableComponent.h" @@ -299,11 +301,25 @@ namespace GameMessages { } void NotifyServerLevelProcessingComplete::Handle(Entity& entity, const SystemAddress& sysAddr) { + // A player levels themselves up + if (!entity.IsPlayer() || entity.GetSystemAddress() != sysAddr) return; + auto* levelComp = entity.GetComponent(); if (!levelComp) return; auto* character = entity.GetComponent(); if (!character) return; + // The next level has to exist and the player needs the score for it + const uint32_t nextLevel = levelComp->GetLevel() + 1; + const auto nextLevelEntries = CDClientManager::GetTable()->Query([nextLevel](const CDLevelProgressionLookup& entry) { + return entry.id == nextLevel; + }); + + if (nextLevelEntries.empty() || character->GetUScore() < static_cast(nextLevelEntries.front().requiredUScore)) { + LOG("Player %llu asked for level %u with a score of %lld, which is not enough for it", entity.GetObjectID(), nextLevel, character->GetUScore()); + return; + } + //Update our character's level in memory: levelComp->SetLevel(levelComp->GetLevel() + 1);