Fix creature level reverting, invisible mobs, unscaled adds, evade healing, and gender-byte writes - #20
Open
talia-danielsdottir wants to merge 1 commit into
Conversation
…aling, and gender-byte writes Five defects, all observed on a live realm. 1. Spawned creature levels revert (issue InstanceForge#13) Creature::SelectLevel() re-rolls urand(minlevel, maxlevel) straight from creature_template on the respawn path and from UpdateEntry(updateAI = true), and other modules call SetLevel() from their own update hooks. mod-autobalance is the common case: it hooks OnPlayerLevelChanged, marks every creature on the map stale, and ResetCreatureIfNeeded() then calls SetLevel(UnmodifiedLevel) — the template value. Either way the level band chosen for the run is lost and the party sees skulls the moment someone dings. The manager now records the level and max health it assigns, and re-asserts them. Case 1 is intercepted via OnBeforeCreatureSelectLevel. Case 2 is a plain SetLevel() from outside this module and cannot be hooked, so it is corrected on this module's own update tick — self-healing and independent of script registration order, so it behaves identically with or without AutoBalance present. An atomic counter gates the hooks so they cost nothing when no session is running, and ownership is released on creature removal and session cleanup. 2. Invisible mobs The trash pool excluded suspicious names but not degenerate models. A creature_model_info row with BoundingRadius or CombatReach of 0 renders as nothing client-side: the mob is targetable and fights back, but cannot be seen. Roughly 2,100 otherwise-eligible entries in a stock 3.3.5a world DB are affected, so a name filter or entry blacklist does not scale. The pool query now drops any entry with a degenerate model, checking every model an entry has since the client picks among them at spawn time. 3. Summoned adds keep their own level SelectCreatureForTheme() matches on creature type only and no summon hook was installed, so an add summoned by a dungeon creature entered at its template level — e.g. a level-69 Fel Imp inside a level-25 run. Adds are now scaled to the session level via OnCreatureAddWorld. Player pets, totems and guardians are explicitly excluded. 4. Creatures heal to full mid-fight Creatures are spawned at generated points, frequently off the navmesh or far from a home position the core considers reachable, so the core fires EVADE_REASON_BOUNDARY / EVADE_REASON_NO_PATH during combat. _EnterEvadeMode() drops combat and LoadCreaturesAddon(true) restores the creature, which then walks home at full health — in play, a mob that heals faster than the group can damage it. Genuine resets are honoured; the positional ones are refused while the creature is alive and still engaged. The override also forwards `why`, which the previous one dropped. 5. Bogus UNIT_FIELD_BYTES_0 writes Two sites wrote byte 2 of UNIT_FIELD_BYTES_0 intending to set elite/rare rank. That byte is gender (byte 0=race, 1=class, 2=gender, 3=power type — the field has no classification byte). Rank lives in creature_template and is cached by the client per entry, so it cannot be set at runtime at all. The writes only changed gender; the "rare" site wrote 4, which is not a valid gender value. Both are removed. Nothing is lost: the boss and rare pools are already filtered to `rank IN (1,2)`, so those creatures carry an elite frame from their template and the client draws the dragon portrait on its own. The scale changes are deliberate and kept.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five defects, all observed on a live realm running this module. Happy to split
this into separate PRs if you'd rather review them independently — they're
described separately below and touch mostly distinct code.
1. Spawned creature levels revert (#13)
Creature::SelectLevel()re-rollsurand(minlevel, maxlevel)straight fromcreature_templateon the respawn path and fromUpdateEntry(updateAI = true),and other modules call
SetLevel()from their own update hooks. mod-autobalanceis the common case: it hooks
OnPlayerLevelChanged, marks every creature on themap stale, and
ResetCreatureIfNeeded()then callsSetLevel(UnmodifiedLevel)—the template value. Either way the level band chosen for the run is lost, which
is why mobs sprout a skull the moment a party member levels up.
The manager now records the level and max health it assigns and re-asserts them:
OnBeforeCreatureSelectLevel;SetLevel()from outside this module and cannot be hooked,so it is corrected on this module's own update tick.
Doing it on our own tick keeps the fix self-healing and independent of script
registration order, so it behaves identically with or without AutoBalance
present. An atomic counter gates the hooks so they cost nothing when no session
is running, and ownership is released on creature removal and on session cleanup.
2. Invisible mobs
The trash pool filtered suspicious names but not degenerate models. A
creature_model_inforow withBoundingRadiusorCombatReachof 0 renders asnothing client-side: the mob is targetable and fights back, but cannot be seen.
Around 2,100 otherwise-eligible entries in a stock 3.3.5a world DB are affected,
so a name filter or an entry blacklist doesn't scale. The pool query now drops any
entry with a degenerate model, checking every model an entry has, since the client
picks among them at spawn time. On my world DB the trash pool goes from 13,600 to
11,480 entries with all nine creature types still well populated.
3. Summoned adds keep their own level
SelectCreatureForTheme()matches on creature type only and there was no summonhook, so an add summoned by a dungeon creature entered at its own template level —
e.g. a level-69 Fel Imp inside a level-25 run. Adds are now scaled to the session
level via
OnCreatureAddWorld. Player pets, totems and guardians are explicitlyexcluded.
4. Creatures heal to full mid-fight
Creatures are spawned at generated points, frequently off the navmesh or far from
a home position the core considers reachable, so the core fires
EVADE_REASON_BOUNDARY/EVADE_REASON_NO_PATHduring combat._EnterEvadeMode()drops combat and
LoadCreaturesAddon(true)restores the creature, which then walkshome at full health — in play, a mob that heals faster than the group can damage it.
Genuine resets (empty threat list, sequence break) are honoured; the positional
ones are refused while the creature is alive and still engaged. The override also
forwards
why, which the previous one dropped.5. Bogus
UNIT_FIELD_BYTES_0writesTwo sites wrote byte 2 of
UNIT_FIELD_BYTES_0intending to set elite/rare rank:That byte is gender (byte 0 = race, 1 = class, 2 = gender, 3 = power type — the
field has no classification byte). Rank lives in
creature_templateand is cachedby the client per entry, so it can't be set at runtime at all. The writes only
changed gender, and the "rare" site wrote 4, which isn't a valid gender value.
Both are removed, and nothing is lost: the boss and rare pools are already filtered
to
rank IN (1,2)(305 rank-1 and 2 rank-2 entries on my world DB, i.e. all ofthem), so those creatures carry an elite frame from their template and the client
draws the dragon portrait on its own. The
SetObjectScale()calls are deliberatedesign and are kept.
Testing
Compiled with
-DMODULES=staticagainst AzerothCore rev190184a04539(Playerbotbranch) and deployed to a live realm. Clean boot, no errors,
restarts=0, and thepool loads 8,585 trash / 2,895 boss entries across all nine creature types.
One note on scope: I left the gold-reward calculation alone. It uses the session
level rather than the killed creature's level, which interacts oddly with fix 3,
but that's a design call rather than a defect so it seemed better left to you.