fix(solocraft): purge _unitDifficulty au logout (stats divisees par 5)

Bug: un moine niveau 1 se retrouvait a ~20% de ses stats (28 PV au lieu
de ~150), rendant un mob niveau 1 "trop fort". La map statique
_unitDifficulty survivait a la deconnexion alors que les modificateurs
TOTAL_PCT de stats sont remis a 1.0 a chaque login. Apres un passage en
donjon puis relog, ClearBuffs retrouvait l'entree fantome et RETIRAIT un
buff jamais reapplique, divisant les stats par 5. Persos touches:
Selena guid 59 et Hakirosa guid 22.

Fix: hook OnLogout qui fait _unitDifficulty.erase(guid), resynchronisant
la map avec les modificateurs runtime. Le restart vide aussi la map
statique, les persos abimes se soignent au prochain login sans retouche
DB.

Integre aussi le travail Solocraft non commite anterieur present dans
l'arbre: exclusion Mythique et Mythique+, lecture de la config a chaque
changement de carte tunable par 'reload config' sans restart, et les
logs SoloDBG ayant servi au diagnostic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
SylvaniaCore deploy
2026-07-08 20:31:57 +00:00
parent 7b178bb198
commit 86f07c3366
+27 -8
View File
@@ -40,6 +40,7 @@ namespace {
void OnMapChanged(Player* player) override
{
TC_LOG_INFO("server.worldserver", "[SoloDBG] OnMapChanged player=%s mapId=%u maxHP=%u", player->GetName().c_str(), player->GetMapId(), (uint32)player->GetMaxHealth());
if (sConfigMgr->GetBoolDefault("Solocraft.Enable", false))
{
Map* map = player->GetMap();
@@ -49,23 +50,38 @@ namespace {
}
}
void OnLogout(Player* player) override
{
// Les modificateurs de stats (TOTAL_PCT) sont remis a 1.0 a chaque login,
// mais _unitDifficulty (statique) survivait a la deconnexion. Un ClearBuffs
// ulterieur retrouvait alors une entree fantome et DIVISAIT des stats jamais
// buffees (perso niveau 1 rabaisse a 20% de ses stats -> 28 PV, cf. bug Selena).
_unitDifficulty.erase(player->GetGUID());
}
private:
std::map<uint64, float> _unitDifficulty;
// Get difficulty values from config
const float D5 = sConfigMgr->GetFloatDefault("Solocraft.Dungeon", 5.0);
const float D5H = sConfigMgr->GetFloatDefault("Solocraft.Heroic", 10.0);
const float D10 = sConfigMgr->GetFloatDefault("Solocraft.Raid10", 10.0);
const float D25 = sConfigMgr->GetFloatDefault("Solocraft.Raid25", 25.0);
const float D30 = sConfigMgr->GetFloatDefault("Solocraft.Raid30", 30.0);
const float D40 = sConfigMgr->GetFloatDefault("Solocraft.Raid40", 40.0);
// Set the instance difficulty
float CalculateDifficulty(Map* map, Player* player)
{
// Valeurs lues a CHAQUE changement de carte (evenement peu frequent) plutot qu'une seule fois
// au boot -> 'reload config' (tmux: reload config) suffit desormais pour tuner, sans restart.
const float D5 = sConfigMgr->GetFloatDefault("Solocraft.Dungeon", 5.0f);
const float D5H = sConfigMgr->GetFloatDefault("Solocraft.Heroic", 10.0f);
const float D10 = sConfigMgr->GetFloatDefault("Solocraft.Raid10", 10.0f);
const float D25 = sConfigMgr->GetFloatDefault("Solocraft.Raid25", 25.0f);
const float D30 = sConfigMgr->GetFloatDefault("Solocraft.Raid30", 30.0f);
const float D40 = sConfigMgr->GetFloatDefault("Solocraft.Raid40", 40.0f);
float difficulty = 1.0;
if (map)
{
// Pas de Solocraft en Mythique / Mythique+ : Map::IsMythic() couvre le donjon Mythique (23),
// la clef Mythique+ (DIFFICULTY_MYTHIC_KEYSTONE 8) et le raid Mythique. Contenu reserve au groupe.
// On retourne 0 (aucun buff) ; ApplyBuffs/ClearBuffs retirera tout buff Solocraft anterieur.
if (map->IsMythic())
return 0.0f;
if (map->IsRaid())
{
switch (map->GetMapDifficulty()->MaxPlayers)
@@ -125,11 +141,13 @@ namespace {
// Adjust player stats
_unitDifficulty[player->GetGUID()] = difficulty;
TC_LOG_INFO("server.worldserver", "[SoloDBG] ApplyBuffs player=%s diff=%.2f stamPctBefore=%.3f maxHPbefore=%u", player->GetName().c_str(), difficulty, player->GetModifierValue(UNIT_MOD_STAT_STAMINA, TOTAL_PCT), (uint32)player->GetMaxHealth());
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
// Buff the player
player->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, difficulty * 100.0, true);
}
TC_LOG_INFO("server.worldserver", "[SoloDBG] ApplyBuffs DONE player=%s stamPctAfter=%.3f maxHPafter=%u", player->GetName().c_str(), player->GetModifierValue(UNIT_MOD_STAT_STAMINA, TOTAL_PCT), (uint32)player->GetMaxHealth());
// Set player health
player->SetFullHealth();
@@ -144,6 +162,7 @@ namespace {
void ClearBuffs(Player* player, Map* map)
{
std::map<uint64, float>::iterator unitDifficultyIterator = _unitDifficulty.find(player->GetGUID());
TC_LOG_INFO("server.worldserver", "[SoloDBG] ClearBuffs player=%s found=%d stamPct=%.3f maxHP=%u", player->GetName().c_str(), unitDifficultyIterator != _unitDifficulty.end() ? 1 : 0, player->GetModifierValue(UNIT_MOD_STAT_STAMINA, TOTAL_PCT), (uint32)player->GetMaxHealth());
if (unitDifficultyIterator != _unitDifficulty.end())
{
float difficulty = unitDifficultyIterator->second;