From 9c1f184d5adc017469e528435ef3ab7d3a86c477 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 3 May 2026 16:28:52 -0300 Subject: [PATCH] perf(Core): Optimize damage/heal hot paths and gate Mythic AI - Cache SpellBuff/MeleeBuff OnlyBosses config bools at load time; avoids per-hit string lookups via sConfigMgr->GetOption. - Replace mutating NerfInfo[mapId][phase] reads with find()/cached refs to stop std::map::operator[] from inserting empty entries on hot damage/heal paths. Also fixes a silent-insert in the debug branch of ModifySpellDamageTaken when matchingPhase == -1. - Switch NerfInfo (outer), SpellNerfOverrides, MythicmodeInstanceData, and Expansion from std::map to std::unordered_map. NerfInfo's inner map stays std::map because GetLowestMatchingPhase relies on ordered iteration. - Add ModZoneDifficulty.MythicmodeAI.Enable (default 0) so OnUnitEnterCombat can early-out without doing IsInstanceMythic / MythicmodeAI lookups when the scripted AI is unused. - Guard attacker null in the OnlyBosses checks (caster can be null for periodic ticks; matches the existing debug-branch guard). Co-Authored-By: Claude Opus 4.7 --- conf/mod-zone-difficulty.conf.dist | 10 ++ src/ZoneDifficulty.h | 13 +- src/mod_zone_difficulty_scripts.cpp | 205 ++++++++++++++++++++-------- 3 files changed, 168 insertions(+), 60 deletions(-) diff --git a/conf/mod-zone-difficulty.conf.dist b/conf/mod-zone-difficulty.conf.dist index fc107447..9fc93363 100644 --- a/conf/mod-zone-difficulty.conf.dist +++ b/conf/mod-zone-difficulty.conf.dist @@ -77,3 +77,13 @@ ModZoneDifficulty.Mythicmode.HpModifier = 2.0 # 1 - Enabled ModZoneDifficulty.Mythicmode.InNormalDungeons = 0 + +# +# ModZoneDifficulty.MythicmodeAI.Enable +# Description: Enable scripted Mythic mode AI from `zone_difficulty_mythicmode_ai`. +# When disabled, OnUnitEnterCombat skips the AI lookup entirely +# for every unit that enters combat in a mythic instance. +# Default: 0 - Disabled +# 1 - Enabled + +ModZoneDifficulty.MythicmodeAI.Enable = 0 diff --git a/src/ZoneDifficulty.h b/src/ZoneDifficulty.h index 9c5368f3..42e2be04 100644 --- a/src/ZoneDifficulty.h +++ b/src/ZoneDifficulty.h @@ -194,25 +194,30 @@ class ZoneDifficulty float MythicmodeHpModifier{ 2.0 }; bool MythicmodeEnable{ false }; bool MythicmodeInNormalDungeons{ false }; + bool MythicmodeAIEnable{ false }; bool UseVendorInterface{ false }; + bool SpellBuffOnlyBosses{ false }; + bool MeleeBuffOnlyBosses{ false }; bool IsBlackTempleDone{ false }; bool IsSunwellPlateauDone{ false }; std::vector DailyHeroicQuests; std::map HeroicTBCQuestMapList; std::map EncounterCounter; - std::map Expansion; + std::unordered_map Expansion; std::map CreatureOverrides; std::map EncountersInProgress; std::map ItemIcons; std::map TierRewards; - typedef std::map > ZoneDifficultyNerfDataMap; + // Inner phase map remains std::map: GetLowestMatchingPhase() iterates it + // and relies on ascending key order to return the lowest matching phase. + typedef std::unordered_map > ZoneDifficultyNerfDataMap; ZoneDifficultyNerfDataMap NerfInfo; - typedef std::map > ZoneDifficultySpellNerfMap; + typedef std::unordered_map > ZoneDifficultySpellNerfMap; ZoneDifficultySpellNerfMap SpellNerfOverrides; typedef std::map > ZoneDifficultyDisablesMap; ZoneDifficultyDisablesMap DisallowedBuffs; - typedef std::map ZoneDifficultyMythicmodeInstDataMap; + typedef std::unordered_map ZoneDifficultyMythicmodeInstDataMap; ZoneDifficultyMythicmodeInstDataMap MythicmodeInstanceData; typedef std::map > ZoneDifficultyMythicmodeLootMap; ZoneDifficultyMythicmodeLootMap MythicmodeLoot; diff --git a/src/mod_zone_difficulty_scripts.cpp b/src/mod_zone_difficulty_scripts.cpp index 50b56a8e..c3a67343 100644 --- a/src/mod_zone_difficulty_scripts.cpp +++ b/src/mod_zone_difficulty_scripts.cpp @@ -60,35 +60,49 @@ class mod_zone_difficulty_unitscript : public UnitScript continue; int32 absorb = eff->GetAmount(); + Map* map = target->GetMap(); uint32 mapId = target->GetMapId(); - uint32 instanceId = target->GetMap()->GetInstanceId(); + uint32 instanceId = map->GetInstanceId(); uint32 phaseMask = target->GetPhaseMask(); int phase = sZoneDifficulty->GetLowestMatchingPhase(mapId, phaseMask); bool isMythic = sZoneDifficulty->IsInstanceMythic(instanceId); bool nerfInDuel = sZoneDifficulty->ShouldNerfInDuels(target); - + auto scaleAbsorb = [](int32 amount, float pct) -> int32 { float scaled = amount * pct; return (scaled < 0) ? static_cast(std::floor(scaled)) : static_cast(scaled); }; // Apply duel-based nerf if no valid map phase - if (phase == -1 && nerfInDuel && sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) + if (phase == -1 && nerfInDuel) { - absorb = scaleAbsorb(absorb, sZoneDifficulty->NerfInfo[DUEL_INDEX][0].AbsorbNerfPct); + auto duelMapIt = sZoneDifficulty->NerfInfo.find(DUEL_INDEX); + if (duelMapIt != sZoneDifficulty->NerfInfo.end()) + { + auto duelPhaseIt = duelMapIt->second.find(0); + if (duelPhaseIt != duelMapIt->second.end() && duelPhaseIt->second.Enabled > 0) + absorb = scaleAbsorb(absorb, duelPhaseIt->second.AbsorbNerfPct); + } } else if (phase != -1) { - int8 mode = sZoneDifficulty->NerfInfo[mapId][phase].Enabled; + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt != sZoneDifficulty->NerfInfo.end()) + { + auto phaseIt = mapIt->second.find(phase); + if (phaseIt != mapIt->second.end()) + { + ZoneDifficultyNerfData const& nerfData = phaseIt->second; - if (!isMythic && sZoneDifficulty->HasNormalMode(mode)) - absorb = scaleAbsorb(absorb, sZoneDifficulty->NerfInfo[mapId][phase].AbsorbNerfPct); + if (!isMythic && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + absorb = scaleAbsorb(absorb, nerfData.AbsorbNerfPct); - if (isMythic && sZoneDifficulty->HasMythicmode(mode)) - { - Map* map = target->GetMap(); - if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - absorb = scaleAbsorb(absorb, sZoneDifficulty->NerfInfo[mapId][phase].AbsorbNerfPctHard); + if (isMythic && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) + { + if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) + absorb = scaleAbsorb(absorb, nerfData.AbsorbNerfPctHard); + } + } } } @@ -186,7 +200,14 @@ class mod_zone_difficulty_unitscript : public UnitScript int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, target->GetPhaseMask()); if (matchingPhase != -1) { - auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt == sZoneDifficulty->NerfInfo.end()) + return; + auto phaseIt = mapIt->second.find(matchingPhase); + if (phaseIt == mapIt->second.end()) + return; + + ZoneDifficultyNerfData const& nerfData = phaseIt->second; Map* map = target->GetMap(); bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); @@ -197,9 +218,15 @@ class mod_zone_difficulty_unitscript : public UnitScript if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) heal = heal * nerfData.HealingNerfPctHard; } - else if (nerfInDuel && sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) + else if (nerfInDuel) { - heal = heal * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].HealingNerfPct; + auto duelMapIt = sZoneDifficulty->NerfInfo.find(DUEL_INDEX); + if (duelMapIt != sZoneDifficulty->NerfInfo.end()) + { + auto duelPhaseIt = duelMapIt->second.find(0); + if (duelPhaseIt != duelMapIt->second.end() && duelPhaseIt->second.Enabled > 0) + heal = heal * duelPhaseIt->second.HealingNerfPct; + } } } @@ -226,9 +253,10 @@ class mod_zone_difficulty_unitscript : public UnitScript return; // Disclaimer: also affects disables boss adds buff. - if (sConfigMgr->GetOption("ModZoneDifficulty.SpellBuff.OnlyBosses", false)) - if (attacker->ToCreature() && !attacker->ToCreature()->IsDungeonBoss()) - return; + if (sZoneDifficulty->SpellBuffOnlyBosses && attacker) + if (Creature* creatureAttacker = attacker->ToCreature()) + if (!creatureAttacker->IsDungeonBoss()) + return; if (sZoneDifficulty->IsValidNerfTarget(target)) { @@ -242,20 +270,35 @@ class mod_zone_difficulty_unitscript : public UnitScript if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; - Map* map = target->GetMap(); - bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt != sZoneDifficulty->NerfInfo.end()) + { + auto phaseIt = mapIt->second.find(matchingPhase); + if (phaseIt != mapIt->second.end()) + { + ZoneDifficultyNerfData const& nerfData = phaseIt->second; + Map* map = target->GetMap(); + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) - damage = damage * nerfData.SpellDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.SpellDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) - if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * nerfData.SpellDamageBuffPctHard; + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) + if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) + damage = damage * nerfData.SpellDamageBuffPctHard; + } + } } else if (sZoneDifficulty->ShouldNerfInDuels(target)) - if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) - damage = damage * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].SpellDamageBuffPct; + { + auto duelMapIt = sZoneDifficulty->NerfInfo.find(DUEL_INDEX); + if (duelMapIt != sZoneDifficulty->NerfInfo.end()) + { + auto duelPhaseIt = duelMapIt->second.find(0); + if (duelPhaseIt != duelMapIt->second.end() && duelPhaseIt->second.Enabled > 0) + damage = damage * duelPhaseIt->second.SpellDamageBuffPct; + } + } if (sZoneDifficulty->IsDebugInfoEnabled && attacker) if (Player* player = attacker->ToPlayer()) @@ -272,9 +315,10 @@ class mod_zone_difficulty_unitscript : public UnitScript return; // Disclaimer: also affects disables boss adds buff. - if (sConfigMgr->GetOption("ModZoneDifficulty.SpellBuff.OnlyBosses", false)) - if (attacker->ToCreature() && !attacker->ToCreature()->IsDungeonBoss()) - return; + if (sZoneDifficulty->SpellBuffOnlyBosses && attacker) + if (Creature* creatureAttacker = attacker->ToCreature()) + if (!creatureAttacker->IsDungeonBoss()) + return; if (sZoneDifficulty->IsValidNerfTarget(target)) { @@ -309,28 +353,55 @@ class mod_zone_difficulty_unitscript : public UnitScript { if (Player* player = target->ToPlayer()) { - ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Normal Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPct); - ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Mythic Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPctHard); + float dbgNormal = 0.0f; + float dbgHard = 0.0f; + auto dbgMapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (dbgMapIt != sZoneDifficulty->NerfInfo.end() && matchingPhase != -1) + { + auto dbgPhaseIt = dbgMapIt->second.find(matchingPhase); + if (dbgPhaseIt != dbgMapIt->second.end()) + { + dbgNormal = dbgPhaseIt->second.SpellDamageBuffPct; + dbgHard = dbgPhaseIt->second.SpellDamageBuffPctHard; + } + } + ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Normal Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, dbgNormal); + ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Mythic Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, dbgHard); } } } if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; - Map* map = target->GetMap(); - bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt != sZoneDifficulty->NerfInfo.end()) + { + auto phaseIt = mapIt->second.find(matchingPhase); + if (phaseIt != mapIt->second.end()) + { + ZoneDifficultyNerfData const& nerfData = phaseIt->second; + Map* map = target->GetMap(); + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) - damage = damage * nerfData.SpellDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.SpellDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) - if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * nerfData.SpellDamageBuffPctHard; + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) + if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) + damage = damage * nerfData.SpellDamageBuffPctHard; + } + } } else if (sZoneDifficulty->ShouldNerfInDuels(target)) - if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) - damage = damage * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].SpellDamageBuffPct; + { + auto duelMapIt = sZoneDifficulty->NerfInfo.find(DUEL_INDEX); + if (duelMapIt != sZoneDifficulty->NerfInfo.end()) + { + auto duelPhaseIt = duelMapIt->second.find(0); + if (duelPhaseIt != duelMapIt->second.end() && duelPhaseIt->second.Enabled > 0) + damage = damage * duelPhaseIt->second.SpellDamageBuffPct; + } + } if (sZoneDifficulty->IsDebugInfoEnabled && target) if (Player* player = target->ToPlayer()) @@ -347,9 +418,10 @@ class mod_zone_difficulty_unitscript : public UnitScript return; // Disclaimer: also affects disables boss adds buff. - if (sConfigMgr->GetOption("ModZoneDifficulty.MeleeBuff.OnlyBosses", false)) - if (attacker->ToCreature() && !attacker->ToCreature()->IsDungeonBoss()) - return; + if (sZoneDifficulty->MeleeBuffOnlyBosses && attacker) + if (Creature* creatureAttacker = attacker->ToCreature()) + if (!creatureAttacker->IsDungeonBoss()) + return; if (sZoneDifficulty->IsValidNerfTarget(target)) { @@ -357,20 +429,35 @@ class mod_zone_difficulty_unitscript : public UnitScript int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, target->GetPhaseMask()); if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; - Map* map = target->GetMap(); - bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt != sZoneDifficulty->NerfInfo.end()) + { + auto phaseIt = mapIt->second.find(matchingPhase); + if (phaseIt != mapIt->second.end()) + { + ZoneDifficultyNerfData const& nerfData = phaseIt->second; + Map* map = target->GetMap(); + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) - damage = damage * nerfData.MeleeDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.MeleeDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) - if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * nerfData.MeleeDamageBuffPctHard; + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) + if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) + damage = damage * nerfData.MeleeDamageBuffPctHard; + } + } } else if (sZoneDifficulty->ShouldNerfInDuels(target)) - if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) - damage = damage * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].MeleeDamageBuffPct; + { + auto duelMapIt = sZoneDifficulty->NerfInfo.find(DUEL_INDEX); + if (duelMapIt != sZoneDifficulty->NerfInfo.end()) + { + auto duelPhaseIt = duelMapIt->second.find(0); + if (duelPhaseIt != duelMapIt->second.end() && duelPhaseIt->second.Enabled > 0) + damage = damage * duelPhaseIt->second.MeleeDamageBuffPct; + } + } } } @@ -379,6 +466,9 @@ class mod_zone_difficulty_unitscript : public UnitScript */ void OnUnitEnterCombat(Unit* unit, Unit* /*victim*/) override { + if (!sZoneDifficulty->MythicmodeAIEnable) + return; + if (!sZoneDifficulty->IsInstanceMythic(unit->GetInstanceId())) return; @@ -446,7 +536,10 @@ class mod_zone_difficulty_worldscript : public WorldScript sZoneDifficulty->MythicmodeHpModifier = sConfigMgr->GetOption("ModZoneDifficulty.Mythicmode.HpModifier", 2); sZoneDifficulty->MythicmodeEnable = sConfigMgr->GetOption("ModZoneDifficulty.Mythicmode.Enable", false); sZoneDifficulty->MythicmodeInNormalDungeons = sConfigMgr->GetOption("ModZoneDifficulty.Mythicmode.InNormalDungeons", false); + sZoneDifficulty->MythicmodeAIEnable = sConfigMgr->GetOption("ModZoneDifficulty.MythicmodeAI.Enable", false); sZoneDifficulty->UseVendorInterface = sConfigMgr->GetOption("ModZoneDifficulty.UseVendorInterface", false); + sZoneDifficulty->SpellBuffOnlyBosses = sConfigMgr->GetOption("ModZoneDifficulty.SpellBuff.OnlyBosses", false); + sZoneDifficulty->MeleeBuffOnlyBosses = sConfigMgr->GetOption("ModZoneDifficulty.MeleeBuff.OnlyBosses", false); sZoneDifficulty->LoadMapDifficultySettings(); if (CharacterDatabase.Query("SELECT 1 FROM zone_difficulty_completion_logs WHERE type = {}", TYPE_RAID_T6))