From 680ddcba8a938359802b79194ea23f5564f59deb Mon Sep 17 00:00:00 2001 From: DuvelCorp Date: Tue, 24 Mar 2026 14:21:58 +0100 Subject: [PATCH] v1.4.1 event leak fixes, chronometer trap fix, profile memory, autostrip alloc fix --- CHANGELOG.md | 22 +++++ MetaHunt.toc | 2 +- README.MD | 11 ++- api/AutoStrip.lua | 24 ++++-- api/constants.lua | 2 +- api/core-framework.lua | 2 +- api/profile.lua | 28 +++++- api/version-check.lua | 4 +- modules/autobuy/module.lua | 2 +- modules/autoquest/module.lua | 2 +- modules/chronometer/data-hunter.lua | 11 ++- modules/chronometer/engine.lua | 45 ++++++++-- modules/chronometer/module.lua | 2 +- modules/expammo/engine.lua | 127 ++++++++++++++++++---------- modules/feedomatic/FeedOMatic.lua | 48 +++++------ modules/feedomatic/module.lua | 2 +- modules/icu/module.lua | 2 +- modules/smartammo/engine.lua | 21 +++++ modules/smartammo/module.lua | 2 +- modules/tooltips/module.lua | 2 +- modules/zhunter/Localization.lua | 1 + modules/zhunter/module.lua | 2 +- modules/zhunter/zButtonMounts.lua | 7 +- modules/zhunter/zButtonPet.lua | 12 ++- modules/zhunter/zButtonToys.lua | 7 +- modules/zhunter/zButtonTrack.lua | 15 +++- modules/zhunter/zButtonTrap.lua | 10 ++- 27 files changed, 298 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fd5326..0561666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,32 @@ All notable changes to MetaHunt will be documented in this file. +## [1.4.1] - 2026-03-24 + +### Added + +- **zTrack**: added `Find Trees` in tracking spells. + +### Changed + +- **Performance — MM Widget / ExpAmmo**: Replaced tooltip-based aura scanning (which triggered hidden tooltip rendering on every aura check) with direct texture/icon comparison via `UnitBuff`/`UnitDebuff`. Added a 150 ms throttle on `PLAYER_AURAS_CHANGED`, which fires 10–50+ times per second in combat. Lock and Load detection and ammo cycle recovery after `/reload` both updated to use the new zero-cost texture path. + +- **Performance — event frame leaks**: Some addon features were registering WoW game events at load time and never unregistering them when the feature was disabled from the options, causing their `OnEvent` handlers to fire even with the option turned off. Fixed for: Auto-Strip (`PLAYER_REGEN_*`), Smart Ammo (`SPELLCAST_*`, `START/STOP_AUTOREPEAT_SPELL`), and some zButton frames (Pet, Mounts, Track, Trap, Toys). Events are now properly registered on enable and unregistered on disable. + +- **Chronometer — trap effects from other hunters**: Trap effect bars (`Immolation Trap Effect`, `Explosive Trap Effect`, `Freezing Trap Effect`, `Frost Trap Aura`) were incorrectly appearing when another hunter's trap triggered on a mob you were also targeting. . + +- **Version check broadcast interval**: Increased update notification broadcast cooldown from 10 minutes to 1 hour to reduce channel traffic now that the user base has grown. + +- **Profile snapshot memory**: The auto `BuildSnapshot` (called on every `/reload` via `PLAYER_LOGOUT`) was deep-copying `feedomatic.legacy`, a large migration table mirroring `FOM_Cooking`, `FOM_QuestFood`, `FOM_AddedFoods` etc. These are runtime/operational blobs, not user configuration settings, and should never be included in a profile. Introduced `MTH_Profile_CopyModules` which skips `legacy` and `history` keys, reducing the snapshot allocation from ~1 MB to a few KB. + + + ## [1.4.0] - 2026-03-23 ### TWoW 1.18.1 "Nightmares of Ursol" support +### Added + - **Complete beast database overhaul**: The MTH beast datastore was reconstructed from scratch, based on a full (beasts) 1.18.1 extract from live DB, gladly provided by Twow staff (thanks @Haaxor!). The beast data should now be 100% accurate, and notably all spawn coordinates, respawn times and pet abilities learnable on all beasts in the world. - The **Beast Lore** page of the Book now allows to filter the list by Zone. Additionally, the beast inspector has been reformatted and all meaningful beast's data is displayed nicely. diff --git a/MetaHunt.toc b/MetaHunt.toc index d6a0525..4d2de40 100644 --- a/MetaHunt.toc +++ b/MetaHunt.toc @@ -1,5 +1,5 @@ ## Interface: 11200 -## Version: 1.4.0 +## Version: 1.4.1 ## Title: MetaHunt - |cff00ff00Hunter ## Author: Metasploit and his Copilot ;) ## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities. diff --git a/README.MD b/README.MD index f70176c..af23c41 100644 --- a/README.MD +++ b/README.MD @@ -1,12 +1,12 @@ # MetaHunt MetaHunt is a Turtle WoW Hunter toolkit. -It is a modern modular addon that combines never-seen features, and improves/fixes a few old hunter add-ons. -It provides a bunch useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider. +It is a modern modular addon compiling brand new features, and improving a few old hunter add-ons, that were broken on twow. +It provides a bunch of useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider. ## Twow Data -MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter needs : +MetaHunt ships with large Turtle WOW datastores : - 100% accurate beasts' data, their locations, and the abilities they can learn you - All Pet families, their abilities and their diet @@ -31,7 +31,7 @@ MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter - Vendors : Shows if a vendor sells Arrows and/or Bullets. - Your pet : Shows your pet's XP, loyalty, happiness and how much you fed it this session. - ## zBouttons + ## zButtons Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with new functionalities @@ -63,6 +63,9 @@ Define your own simple rules for auto buy ammo and pet food when you open a vend Just spam SHIFT-click on the NPC to validate quests Scorpok and Thorium arrows. Additionally you can have an enhanced tooltip that display your actual Scorpok-related items when you mouseover the mobs involved. + ## Beast model Viewer + +Display the model of all beasts in the world. Always know what you are going to tame exactly before running there ! You can also browse all skin models of the same pet family to find the best-looking pet according to your tastes. ## The Great Book of Huntards diff --git a/api/AutoStrip.lua b/api/AutoStrip.lua index f0642d9..2876689 100644 --- a/api/AutoStrip.lua +++ b/api/AutoStrip.lua @@ -150,6 +150,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent) if enabled then saved["autostrip"] = 1 AutoStrip_On = 1 + if AutoStrip_Frame then + AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED") + AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED") + end if AutoStripDisplay and AutoStripDisplay:IsVisible() and AutoStripDisplayAutoCast then AutoStripDisplayAutoCast:Show() end @@ -159,6 +163,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent) else saved["autostrip"] = nil AutoStrip_On = nil + if AutoStrip_Frame then + AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_DISABLED") + AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_ENABLED") + end if AutoStripDisplayAutoCast then AutoStripDisplayAutoCast:Hide() end @@ -252,10 +260,12 @@ function AutoStrip_UnequipAll(weaponsOnly) end local function AutoStrip_OnEvent() - AutoStrip_Trace("OnEvent evt=" .. tostring(event or "") - .. " runtime=" .. tostring(AutoStrip_On and 1 or 0) - .. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0) - .. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0)) + if AutoStrip_TraceEnabled then + AutoStrip_Trace("OnEvent evt=" .. tostring(event or "") + .. " runtime=" .. tostring(AutoStrip_On and 1 or 0) + .. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0) + .. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0)) + end if event == "VARIABLES_LOADED" then local saved = AutoStrip_GetSaved() AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0) @@ -318,9 +328,11 @@ end AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent") if AutoStrip_Frame then + -- PLAYER_REGEN_DISABLED / PLAYER_REGEN_ENABLED are intentionally NOT registered here. + -- They are registered only when the feature is enabled via AutoStrip_SetAutoStripToggle(true), + -- and unregistered when it is disabled. This prevents any combat event overhead when the + -- feature is off. AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED") - AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED") - AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED") AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD") AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT") AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent) diff --git a/api/constants.lua b/api/constants.lua index ef3ecc0..dd856fc 100644 --- a/api/constants.lua +++ b/api/constants.lua @@ -1,5 +1,5 @@ MTH_CONST = MTH_CONST or {} -MTH_CONST.version = MTH_CONST.version or "1.4.0" +MTH_CONST.version = MTH_CONST.version or "1.4.1" MTH_CONST.WEAPON_TYPES = { BOWS = "Bows", diff --git a/api/core-framework.lua b/api/core-framework.lua index 80a1c5c..aee3d8f 100644 --- a/api/core-framework.lua +++ b/api/core-framework.lua @@ -1,5 +1,5 @@ MTH = MTH or { - version = "1.4.0", + version = "1.4.1", name = "MetaHunt", modules = {}, config = {}, diff --git a/api/profile.lua b/api/profile.lua index 9213314..b59951b 100644 --- a/api/profile.lua +++ b/api/profile.lua @@ -19,6 +19,30 @@ local function MTH_Profile_DeepCopy(orig) return copy end +-- Shallow-copy a module's saved data, skipping keys that hold large operational +-- blobs (e.g. feedomatic's "legacy" table which mirrors FOM_Cooking, FOM_QuestFood +-- etc.) — those are runtime migration artifacts, not user configuration settings. +local MTH_PROFILE_SKIP_KEYS = { legacy = true, history = true } + +local function MTH_Profile_CopyModules(src) + if type(src) ~= "table" then return {} end + local out = {} + for modName, modData in src do + if type(modData) == "table" then + local modCopy = {} + for k, v in modData do + if not MTH_PROFILE_SKIP_KEYS[k] then + modCopy[MTH_Profile_DeepCopy(k)] = MTH_Profile_DeepCopy(v) + end + end + out[modName] = modCopy + else + out[modName] = modData + end + end + return out +end + local function MTH_Profile_EnsureStore() if type(MTH_SavedVariables) ~= "table" then MTH_SavedVariables = {} @@ -47,13 +71,13 @@ local function MTH_Profile_BuildSnapshot() -- Account-wide module option values (e.g. feedomatic) snap.config = (type(MTH_SavedVariables) == "table" and type(MTH_SavedVariables.modules) == "table") - and MTH_Profile_DeepCopy(MTH_SavedVariables.modules) + and MTH_Profile_CopyModules(MTH_SavedVariables.modules) or {} -- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.) snap.charConfig = (type(MTH_CharSavedVariables) == "table" and type(MTH_CharSavedVariables.modules) == "table") - and MTH_Profile_DeepCopy(MTH_CharSavedVariables.modules) + and MTH_Profile_CopyModules(MTH_CharSavedVariables.modules) or {} -- Per-character module enabled/disabled states diff --git a/api/version-check.lua b/api/version-check.lua index 804b5c0..363e0fc 100644 --- a/api/version-check.lua +++ b/api/version-check.lua @@ -221,8 +221,8 @@ end function VC:ResetPublishDelay() local now = VC_GetTimeNow() - if self.lastPublishedAt and (now - self.lastPublishedAt) < 600 then - return -- 10-minute cooldown between publishes + if self.lastPublishedAt and (now - self.lastPublishedAt) < 3600 then + return -- 1-hour cooldown between publishes end self.nextPublishAt = now + math.random(10, 20) end diff --git a/modules/autobuy/module.lua b/modules/autobuy/module.lua index 9df70dc..94b047f 100644 --- a/modules/autobuy/module.lua +++ b/modules/autobuy/module.lua @@ -6,7 +6,7 @@ local MTH_AutoBuy = { name = "autobuy", enabled = false, - version = "1.4.0", + version = "1.4.1", events = { "VARIABLES_LOADED", "MERCHANT_SHOW", diff --git a/modules/autoquest/module.lua b/modules/autoquest/module.lua index 570ccdc..0df6cff 100644 --- a/modules/autoquest/module.lua +++ b/modules/autoquest/module.lua @@ -6,7 +6,7 @@ local MTH_AutoQuest = { name = "autoquest", enabled = false, - version = "1.4.0", + version = "1.4.1", events = { "GOSSIP_SHOW", "QUEST_GREETING", diff --git a/modules/chronometer/data-hunter.lua b/modules/chronometer/data-hunter.lua index 216e76c..93cdf18 100644 --- a/modules/chronometer/data-hunter.lua +++ b/modules/chronometer/data-hunter.lua @@ -40,10 +40,13 @@ function MTH_ChronometerHunterInstallData(engine) engine:AddTimer(engine.SPELL, BS["Wyvern Sting"], 12, 1, 0, 0, { gr = 2, cr = "MAROON", rc = true }) engine:AddTimer(engine.SPELL, BS["Feed Pet"], 20, 0, 0, 0, { cr = "MAROON" }) - engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Explosive Trap"] }) - engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", a = 1, d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] }) - engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", a = 1, d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] }) - engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Immolation Trap"] }) + -- Trap effects: no "a=1" here — primed by the SPELL timer's "ea" chain (cast hook sets timer.v + -- and timer.t). Using "a=1" would trigger on any hunter's affliction message since + -- CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS never embeds a caster name. + engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", xn = BS["Explosive Trap"] }) + engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] }) + engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] }) + engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", xn = BS["Immolation Trap"] }) engine:AddTimer(engine.EVENT, BS["Improved Concussive Shot"], 3, 1, 0, 0, { a = 1, cr = "BLUE", xn = BS["Concussive Shot"] }) engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] }) engine:AddTimer(engine.EVENT, BS["Lock and Load"], 10, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\ability_hunter_lockandload" }) -- 10s (tooltip confirmed; expires on Aimed Shot cast) diff --git a/modules/chronometer/engine.lua b/modules/chronometer/engine.lua index 8aab36f..561a394 100644 --- a/modules/chronometer/engine.lua +++ b/modules/chronometer/engine.lua @@ -580,14 +580,18 @@ function Chronometer:OnEnable() self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_SELF", function(event, info) self:SPELL_FADE(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_OTHER", function(event, info) self:SPELL_FADE(event, info) end) + -- Registered events: + -- SELF_BUFFS / SELF_DAMAGE → our own procs & self-damage (source == ParserLib_SELF confirmed) + -- CREATURE_DAMAGE → DOT ticks on creatures ("from your X" embeds source; filtered in SPELL_PERIODIC) + -- CREATURE_BUFFS → debuff APPLICATION on creatures ("X is afflicted by Y"; no source embedded). + -- Needed for non-ticking debuffs: Poisonous/Enchanted Ammunition, Piercing Shot. + -- Foreign-bar risk is mitigated in SPELL_PERIODIC by requiring victim == target + -- when source is nil and no confirmed cast record exists. + -- FRIENDLYPLAYER_*, HOSTILEPLAYER_* are other players' events → intentionally NOT registered. self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) - self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) - self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) - self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) - self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) local enableRoM = false for _, timer in pairs(self.timers[self.SPELL] or {}) do @@ -1274,11 +1278,20 @@ end function Chronometer:SPELL_PERIODIC(event, info) local aura, rank, unit, isgain - -- Ignore events not caused by the player (e.g. other players' DOTs/traps nearby) + -- Primary filter: explicit non-self source → always ignore (other player's confirmed event) if info.source and info.source ~= ParserLib_SELF then return end + -- Secondary filter: creature/friendly periodic events do NOT embed a caster name, + -- so info.source is nil even for other players' effects. Track whether this event + -- was provably ours (SELF_BUFFS / SELF_DAMAGE events give source == ParserLib_SELF). + local sourceIsConfirmedSelf = (info.source == ParserLib_SELF) + if info.type == "buff" then isgain = 1 + -- Buff gained by someone other than self with no source confirmation → another player's proc + if not sourceIsConfirmedSelf and info.victim ~= nil and info.victim ~= ParserLib_SELF then + return + end elseif info.type == "debuff" then isgain = nil elseif not info.isDOT then @@ -1306,7 +1319,27 @@ function Chronometer:SPELL_PERIODIC(event, info) if timer.k.t then if not unit then unit = UnitName("player") end if timer.k.s then - if timer.t and timer.t ~= unit then return end + -- Selforselect: four-tier confirmation. + -- 1. Confirmed cast record (timer.t set by CastSpell hook): require target match. + -- 2. Confirmed self source (SELF_BUFFS / SELF_DAMAGE events, source == SELF): accept. + -- 3. Cast-window confirmed (timer.v fresh, timer.t nil): untargeted spells like traps + -- where the caster is known but the trigger victim cannot be predicted in advance. + -- Accept unconditionally — the mob that walked into the trap may not be our target. + -- 4. Source unconfirmed AND no cast record (CREATURE_BUFFS affliction messages never + -- embed a caster name): fall back to target-check. This lets non-ticking debuffs + -- (Poisonous Ammo, Enchanted Ammo, Piercing Shot…) show when applied to our current + -- target, while blocking the same debuff on a mob we are NOT targeting (i.e. another + -- player's debuff on a different dummy). + if timer.t then + if timer.t ~= unit then return end + elseif sourceIsConfirmedSelf then + -- source confirmed → accept unconditionally + elseif timer.v and timer.v > GetTime() then + -- cast-window confirmed, timer.t nil → untargeted cast (e.g. trap placed on ground) + -- victim unknown at cast time; accept whatever mob triggered it + elseif not UnitExists("target") or unit ~= UnitName("target") then + return + end else if not UnitExists("target") or unit ~= UnitName("target") then return end end diff --git a/modules/chronometer/module.lua b/modules/chronometer/module.lua index 71224da..bbd8385 100644 --- a/modules/chronometer/module.lua +++ b/modules/chronometer/module.lua @@ -1,7 +1,7 @@ local MTH_ChronometerModule = { name = "chronometer", enabled = true, - version = "1.4.0", + version = "1.4.1", events = {}, initialized = false, } diff --git a/modules/expammo/engine.lua b/modules/expammo/engine.lua index 022b319..41e3ae7 100644 --- a/modules/expammo/engine.lua +++ b/modules/expammo/engine.lua @@ -169,28 +169,66 @@ local function MTH_EA_GetLnLRemaining() return nil end --- Scan all player auras (buffs then debuffs) for an active ammo state. --- Returns the matching STATE_ORDER key, or nil if none found. -local function MTH_EA_FindAmmoAura() - -- Try buffs first +-- ── Fast texture-based aura scanners (no tooltip, no pcall) ───────────────── +-- UnitBuff("player", i) → icon texture path for buff slot i (nil = end) +-- UnitDebuff("player", i) → icon texture path for debuff slot i (nil = end) +-- We match by icon basename instead of buff name: zero rendering cost. + +-- Known icon basenames (lower-case, no path prefix, no extension): +local MTH_EA_AMMO_TEX = { + [EXPLOSIVE] = "ability_searingarrow", + [POISONOUS] = "ability_poisonarrow", + [ENCHANTED] = "ability_theblackarrow", +} +local MTH_EA_LNL_TEX = "lockandload" -- matches "ability_hunter_lockandload" + +local function MTH_EA_IconBasename(texturePath) + if not texturePath then return "" end + local s = string.lower(tostring(texturePath)) + local _, _, base = string.find(s, "([^\\]+)$") + return base or s +end + +-- Scan player buffs+debuffs for an active ammo state via texture comparison. +local function MTH_EA_FindAmmoStateByTexture() for i = 1, 32 do - local name = MTH_EA_GetAuraName(false, i) - if not name then break end - for _, stateKey in ipairs(STATE_ORDER) do - if name == STATE_BUFF[stateKey] then return stateKey end + local t = UnitBuff("player", i) + if not t then break end + local base = MTH_EA_IconBasename(t) + for stateKey, frag in pairs(MTH_EA_AMMO_TEX) do + if base == frag then return stateKey end end end - -- Fall back to debuffs ("You are afflicted by" = player debuff) for i = 1, 16 do - local name = MTH_EA_GetAuraName(true, i) - if not name then break end - for _, stateKey in ipairs(STATE_ORDER) do - if name == STATE_BUFF[stateKey] then return stateKey end + local t = UnitDebuff("player", i) + if not t then break end + local base = MTH_EA_IconBasename(t) + for stateKey, frag in pairs(MTH_EA_AMMO_TEX) do + if base == frag then return stateKey end end end return nil end +-- Returns true if LnL buff is currently on the player. +local function MTH_EA_HasLnLByTexture() + for i = 1, 32 do + local t = UnitBuff("player", i) + if not t then break end + if string.find(MTH_EA_IconBasename(t), MTH_EA_LNL_TEX, 1, true) then + return true + end + end + return false +end + +-- Scan all player auras (buffs then debuffs) for an active ammo state. +-- Returns the matching STATE_ORDER key, or nil if none found. +-- (Delegates to the fast texture path; tooltip path kept for debug use only.) +local function MTH_EA_FindAmmoAura() + return MTH_EA_FindAmmoStateByTexture() +end + -- Restore cycle state from active auras (survives /reload within session). local function MTH_EA_RecoverStateFromBuffs() local stateKey = MTH_EA_FindAmmoAura() @@ -234,6 +272,10 @@ end -- Combat state flag (avoids needing InCombatLockdown, which doesn't exist in 1.12) local inCombat = false +-- Throttle for PLAYER_AURAS_CHANGED: even with the fast texture path this event +-- fires 10-50+/sec in combat, so cap processing at ~6/sec. +local MTH_EA_AurasChangedLastTime = 0 + -- UI frame handles — declared here so MTH_EA_RefreshVisibility (and every -- function defined below) all close over the SAME locals. local strip = nil -- root drag frame (sized to 3×1 row) @@ -834,47 +876,40 @@ frame:SetScript("OnEvent", function() if event == "PLAYER_AURAS_CHANGED" then if not MTH_EA_IsEnabled() then return end - -- Pending LnL icon capture: buff is now on the unit, do the diff. + + -- Throttle: cap processing at ~6/sec. Chat-message handlers cover all + -- real-time state transitions; this path is only for /reload recovery + -- and LnL sync, so a 150 ms gate is perfectly safe. + local now = GetTime() + if (now - MTH_EA_AurasChangedLastTime) < 0.15 then return end + MTH_EA_AurasChangedLastTime = now + + -- Pending LnL icon capture (no-op stub; kept to avoid errors). if lnlPendingCapture then MTH_EA_TryCaptureNewBuffIcon() end - -- ── LnL detection: always sync timer from tooltip ──────────────── - -- PLAYER_AURAS_CHANGED fires for every buff change (unrelated to LnL), - -- so we CANNOT just reset to DURATION on each fire. Instead we read - -- the actual remaining time from the game's own buff tooltip — this - -- gives correct values for both initial proc AND mid-buff refresh. - local lnlBuffIndex = nil - for i = 1, 32 do - local name = MTH_EA_GetAuraName(false, i) - if not name then break end - if string.find(name, "Lock and Load", 1, true) then - lnlBuffIndex = i - break - end - end - if lnlBuffIndex then - local rem = MTH_EA_GetLnLRemaining() - if rem and rem > 0 then - -- Sync to game's real remaining time (handles refresh correctly too). + + -- ── LnL sync: texture-based, zero tooltip cost ─────────────────── + -- We only SET active here (initial gain / missed chat message). + -- LOSS is authoritative from the AURA_GONE_SELF chat handler + OnUpdate + -- expiry, so we deliberately do NOT clear lnl.active when not found — + -- AURAS_CHANGED fires for every unrelated buff change and a transient + -- miss during slot reordering would prematurely kill the timer. + if MTH_EA_HasLnLByTexture() then + if not lnl.active then lnl.active = true - lnl.expiresAt = GetTime() + rem - elseif not lnl.active then - -- Tooltip parse failed; first-gain fallback only. - lnl.active = true - lnl.expiresAt = GetTime() + lnl.DURATION + lnl.expiresAt = now + lnl.DURATION end - -- If already active and parse failed: leave expiresAt as-is. lnlPendingCapture = false end - -- NOTE: do NOT set lnl.active=false here when the buff is not found. - -- AURAS_CHANGED fires for every unrelated buff change and the tooltip - -- scan can transiently miss LnL during slot reordering. - -- Loss is handled by the "fades from you" chat handler + OnUpdate expiry. - -- Recovery path: resync ammo state after /reload. + + -- ── Recovery: resync ammo state after /reload ───────────────────── if rt.state == IDLE then - local before = rt.state - MTH_EA_RecoverStateFromBuffs() - if MTH_EA_DebugMode and rt.state ~= before then + local stateKey = MTH_EA_FindAmmoStateByTexture() + if stateKey then + rt.state = stateKey + rt.expiresAt = now + CYCLE_DURATION + rt.consumed = false end MTH_EA_UpdateUI() end diff --git a/modules/feedomatic/FeedOMatic.lua b/modules/feedomatic/FeedOMatic.lua index 9f89b76..d9d2223 100644 --- a/modules/feedomatic/FeedOMatic.lua +++ b/modules/feedomatic/FeedOMatic.lua @@ -926,7 +926,7 @@ function FOM_OnEvent(event, arg1) end if (foodID) then FOM_LastFood = GFWUtils.ItemLink(foodID); - GFWUtils.DebugLog("Manually fed "..FOM_LastFood); + FOM_DebugLog("Manually fed "..FOM_LastFood); end end return; @@ -1245,31 +1245,31 @@ end function FOM_CanFeed() local petInfo = MTH_FOM_GetCorePetInfo(); if ( not (petInfo and petInfo.liveExists) ) then - GFWUtils.DebugLog("Can't feed; pet doesn't exist."); + FOM_DebugLog("Can't feed; pet doesn't exist."); return false; end if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then - GFWUtils.DebugLog("Can't feed; pet is dead."); + FOM_DebugLog("Can't feed; pet is dead."); return false; end if ( UnitHealth("player") <= 0 ) then - GFWUtils.DebugLog("Can't feed; I'm dead."); + FOM_DebugLog("Can't feed; I'm dead."); return false; end if ( CastingBarFrameStatusBar:IsVisible() ) then - GFWUtils.DebugLog("Can't feed; casting a spell / tradeksill."); + FOM_DebugLog("Can't feed; casting a spell / tradeksill."); return false; end if ( UnitOnTaxi("player") ) then - GFWUtils.DebugLog("Can't feed; flying."); + FOM_DebugLog("Can't feed; flying."); return false; end if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then - GFWUtils.DebugLog("Can't feed; in combat."); + FOM_DebugLog("Can't feed; in combat."); return false; end if ( LootFrame:IsVisible() ) then - GFWUtils.DebugLog("Shouldn't feed; loot window is open."); + FOM_DebugLog("Shouldn't feed; loot window is open."); return false; end @@ -1290,7 +1290,7 @@ function FOM_CanFeed() if ( buff ~= nil) then for _, buffTexture in dontFeedBuffTextures do if ( buff == buffTexture ) then - GFWUtils.DebugLog("Can't feed; currently, eating, drinking, or feigning death."); + FOM_DebugLog("Can't feed; currently, eating, drinking, or feigning death."); return false; end end @@ -1303,7 +1303,7 @@ function FOM_CanFeed() msg = string.lower(msg); for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do if (string.find(msg, mountName)) then - GFWUtils.DebugLog("Can't feed; mounted."); + FOM_DebugLog("Can't feed; mounted."); return false; end end @@ -1856,13 +1856,13 @@ end function FOM_AddFood(diet, food) if (FOM_Foods[diet] == nil) then - GFWUtils.DebugLog("FOM_Foods[diet] == nil"); + FOM_DebugLog("FOM_Foods[diet] == nil"); end if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then - GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); + FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); end if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then - GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); + FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); end if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then if (FOM_AddedFoods == nil) then @@ -1898,13 +1898,13 @@ end function FOM_RemoveFood(diet, food) if (FOM_Foods[diet] == nil) then - GFWUtils.DebugLog("FOM_Foods[diet] == nil"); + FOM_DebugLog("FOM_Foods[diet] == nil"); end if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then - GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); + FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); end if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then - GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); + FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); end if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then if (FOM_RemovedFoods == nil) then @@ -2341,7 +2341,7 @@ function FOM_Feed(aFood, options) foodLevel = selectedFoodLevel, }) - GFWUtils.DebugLog("Picked "..FOM_LastFood.." (bag "..foodBag..", slot "..foodItem..") for feeding."); + FOM_DebugLog("Picked "..FOM_LastFood.." (bag "..foodBag..", slot "..foodItem..") for feeding."); if (FOM_Config.Debug) then -- don't actually feed anything, just show what we would choose return false; @@ -2708,12 +2708,12 @@ end function FOM_IsUsefulFood(itemID, quantity) local foodName = GetItemInfo(itemID); if (foodName == nil) then - GFWUtils.DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat."); + FOM_DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat."); return false; end if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then - GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking."); + FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking."); return true; end end @@ -2725,19 +2725,19 @@ function FOM_IsUsefulFood(itemID, quantity) FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity; end if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then - GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough."); + FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough."); return false; else - GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest."); + FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest."); return true; end end end if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then - GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player."); + FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player."); return true; end - --GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses."); + --FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses."); return false; end @@ -2775,7 +2775,7 @@ function FOM_IsInDiet(food, dietList) diet = ""; end if (FOM_Foods[diet] == nil) then - GFWUtils.DebugLog("FOM_Foods[diet] == nil"); + FOM_DebugLog("FOM_Foods[diet] == nil"); end if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then return false; diff --git a/modules/feedomatic/module.lua b/modules/feedomatic/module.lua index 233e7e3..80726ba 100644 --- a/modules/feedomatic/module.lua +++ b/modules/feedomatic/module.lua @@ -6,7 +6,7 @@ local MTH_FeedOMatic = { name = "feedomatic", enabled = false, - version = "1.4.0", + version = "1.4.1", events = { "VARIABLES_LOADED", "MERCHANT_SHOW", diff --git a/modules/icu/module.lua b/modules/icu/module.lua index 7073c6c..e8d713a 100644 --- a/modules/icu/module.lua +++ b/modules/icu/module.lua @@ -6,7 +6,7 @@ local MTH_ICU = { name = "icu", enabled = false, - version = "1.4.0", + version = "1.4.1", events = { "VARIABLES_LOADED", }, diff --git a/modules/smartammo/engine.lua b/modules/smartammo/engine.lua index 4db7d1c..8cc19c2 100644 --- a/modules/smartammo/engine.lua +++ b/modules/smartammo/engine.lua @@ -48,10 +48,25 @@ end local MTHSmartAmmo_InitializeHooks MTHSmartAmmo_EnsureHooks = nil +local MTH_SA_SPELL_EVENTS = { + "START_AUTOREPEAT_SPELL", + "STOP_AUTOREPEAT_SPELL", + "SPELLCAST_INTERRUPTED", + "SPELLCAST_FAILED", + "SPELLCAST_STOP", + "SPELLCAST_DELAYED", +} + function MTHSmartAmmo_SetSmartEnabled(enabled, silent) local saved = MTHSmartAmmo_GetSaved() if enabled then saved["enabled"] = 1 + local evFrame = getglobal("MTH_SA_EventFrame") + if evFrame then + for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do + evFrame:RegisterEvent(ev) + end + end if MTHSmartAmmo_InitializeHooks then MTHSmartAmmo_InitializeHooks() end @@ -63,6 +78,12 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent) end else saved["enabled"] = false + local evFrame = getglobal("MTH_SA_EventFrame") + if evFrame then + for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do + evFrame:UnregisterEvent(ev) + end + end if not silent and DEFAULT_CHAT_FRAME then MTH_SA_Print("Smart Ammo Disabled.") end diff --git a/modules/smartammo/module.lua b/modules/smartammo/module.lua index 87bb1d5..e73e6a7 100644 --- a/modules/smartammo/module.lua +++ b/modules/smartammo/module.lua @@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true local MTH_SmartAmmo = { name = "smartammo", enabled = true, - version = "1.4.0", + version = "1.4.1", events = { "VARIABLES_LOADED", -- PLAYER_ENTERING_WORLD handled by engine's own frame diff --git a/modules/tooltips/module.lua b/modules/tooltips/module.lua index fa975e0..8fcb1cb 100644 --- a/modules/tooltips/module.lua +++ b/modules/tooltips/module.lua @@ -6,7 +6,7 @@ local MTH_Tooltips = { name = "tooltips", enabled = true, - version = "1.4.0", + version = "1.4.1", events = { "UPDATE_MOUSEOVER_UNIT", "UNIT_NAME_UPDATE", diff --git a/modules/zhunter/Localization.lua b/modules/zhunter/Localization.lua index 448854d..46f1d15 100644 --- a/modules/zhunter/Localization.lua +++ b/modules/zhunter/Localization.lua @@ -86,6 +86,7 @@ ZHUNTER_TRACK_GIANTS = "Track Giants" ZHUNTER_TRACK_MINERALS = "Find Minerals" ZHUNTER_TRACK_HERBS = "Find Herbs" ZHUNTER_TRACK_TREASURE = "Find Treasure" +ZHUNTER_TRACK_TREES = "Find Trees" ZHUNTER_TRAP_FREEZING = "Freezing Trap" ZHUNTER_TRAP_FROST = "Frost Trap" diff --git a/modules/zhunter/module.lua b/modules/zhunter/module.lua index 40c77f6..9f91764 100644 --- a/modules/zhunter/module.lua +++ b/modules/zhunter/module.lua @@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true local MTH_ZHunter = { name = "zhunter", enabled = true, - version = "1.4.0", + version = "1.4.1", events = { "VARIABLES_LOADED", -- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames diff --git a/modules/zhunter/zButtonMounts.lua b/modules/zhunter/zButtonMounts.lua index 149a63b..83a9e7b 100644 --- a/modules/zhunter/zButtonMounts.lua +++ b/modules/zhunter/zButtonMounts.lua @@ -249,7 +249,8 @@ end function zButtonMounts_SetupSizeAndPosition() local saved = zButtonMounts_GetSaved() if saved["enabled"] == false or saved["enabled"] == 0 then - if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then + if MTH_ZH_MountsAdjust then + MTH_ZH_MountsAdjust:UnregisterAllEvents() MTH_ZH_MountsAdjust:SetScript("OnEvent", nil) end if zButtonMounts and zButtonMounts.Hide then @@ -257,7 +258,9 @@ function zButtonMounts_SetupSizeAndPosition() end return end - if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then + if MTH_ZH_MountsAdjust then + MTH_ZH_MountsAdjust:RegisterEvent("SPELLS_CHANGED") + MTH_ZH_MountsAdjust:RegisterEvent("PLAYER_ENTERING_WORLD") MTH_ZH_MountsAdjust:SetScript("OnEvent", MTH_ZH_MountsAdjust_OnEvent) end local displayCount = zButtonMounts.found or 0 diff --git a/modules/zhunter/zButtonPet.lua b/modules/zhunter/zButtonPet.lua index 28c7bd6..2fb2905 100644 --- a/modules/zhunter/zButtonPet.lua +++ b/modules/zhunter/zButtonPet.lua @@ -235,7 +235,8 @@ end function zButtonPet_SetupSizeAndPosition() local saved = zButtonPet_GetSaved() if saved["enabled"] == false or saved["enabled"] == 0 then - if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then + if MTH_ZH_PetAdjust then + MTH_ZH_PetAdjust:UnregisterAllEvents() MTH_ZH_PetAdjust:SetScript("OnEvent", nil) end if zButtonPet and zButtonPet.Hide then @@ -243,7 +244,14 @@ function zButtonPet_SetupSizeAndPosition() end return end - if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then + if MTH_ZH_PetAdjust then + MTH_ZH_PetAdjust:RegisterEvent("UNIT_HEALTH") + MTH_ZH_PetAdjust:RegisterEvent("UNIT_HAPPINESS") + MTH_ZH_PetAdjust:RegisterEvent("UNIT_PET") + MTH_ZH_PetAdjust:RegisterEvent("PET_BAR_UPDATE") + MTH_ZH_PetAdjust:RegisterEvent("PLAYER_ENTERING_WORLD") + MTH_ZH_PetAdjust:RegisterEvent("SPELLS_CHANGED") + MTH_ZH_PetAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB") MTH_ZH_PetAdjust:SetScript("OnEvent", MTH_ZH_PetAdjust_OnEvent) end local displayCount = zButtonPet.found or ZHUNTER_PET_MAX diff --git a/modules/zhunter/zButtonToys.lua b/modules/zhunter/zButtonToys.lua index ce9f386..684de43 100644 --- a/modules/zhunter/zButtonToys.lua +++ b/modules/zhunter/zButtonToys.lua @@ -249,7 +249,8 @@ end function zButtonToys_SetupSizeAndPosition() local saved = zButtonToys_GetSaved() if saved["enabled"] == false or saved["enabled"] == 0 then - if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then + if MTH_ZH_ToysAdjust then + MTH_ZH_ToysAdjust:UnregisterAllEvents() MTH_ZH_ToysAdjust:SetScript("OnEvent", nil) end if zButtonToys and zButtonToys.Hide then @@ -257,7 +258,9 @@ function zButtonToys_SetupSizeAndPosition() end return end - if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then + if MTH_ZH_ToysAdjust then + MTH_ZH_ToysAdjust:RegisterEvent("SPELLS_CHANGED") + MTH_ZH_ToysAdjust:RegisterEvent("PLAYER_ENTERING_WORLD") MTH_ZH_ToysAdjust:SetScript("OnEvent", MTH_ZH_ToysAdjust_OnEvent) end local displayCount = zButtonToys.found or 0 diff --git a/modules/zhunter/zButtonTrack.lua b/modules/zhunter/zButtonTrack.lua index a79b083..704fdeb 100644 --- a/modules/zhunter/zButtonTrack.lua +++ b/modules/zhunter/zButtonTrack.lua @@ -5,7 +5,7 @@ end local root = zButtonTrack_GetRoot() if not root["zButtonTrack"] then root["zButtonTrack"] = {} - root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} + root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} root["zButtonTrack"]["rows"] = 1 root["zButtonTrack"]["horizontal"] = nil root["zButtonTrack"]["vertical"] = nil @@ -32,7 +32,8 @@ ZHunterMod_Track_Spells = { ZHUNTER_TRACK_GIANTS, ZHUNTER_TRACK_MINERALS, ZHUNTER_TRACK_HERBS, - ZHUNTER_TRACK_TREASURE + ZHUNTER_TRACK_TREASURE, + ZHUNTER_TRACK_TREES } local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells) @@ -311,7 +312,8 @@ function zButtonTrack_SetupSizeAndPosition() zButtonTrack_EnsureConfig() local saved = zButtonTrack_GetSaved() if saved["enabled"] == false or saved["enabled"] == 0 then - if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then + if MTH_ZH_TrackAdjust then + MTH_ZH_TrackAdjust:UnregisterAllEvents() MTH_ZH_TrackAdjust:SetScript("OnEvent", nil) end if zButtonTrack and zButtonTrack.Hide then @@ -319,7 +321,12 @@ function zButtonTrack_SetupSizeAndPosition() end return end - if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then + if MTH_ZH_TrackAdjust then + MTH_ZH_TrackAdjust:RegisterEvent("MINIMAP_UPDATE_TRACKING") + MTH_ZH_TrackAdjust:RegisterEvent("PLAYER_ENTERING_WORLD") + MTH_ZH_TrackAdjust:RegisterEvent("SPELLS_CHANGED") + MTH_ZH_TrackAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED") + MTH_ZH_TrackAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB") MTH_ZH_TrackAdjust:SetScript("OnEvent", MTH_ZH_TrackAdjust_OnEvent) end local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX diff --git a/modules/zhunter/zButtonTrap.lua b/modules/zhunter/zButtonTrap.lua index 9d81671..7a829da 100644 --- a/modules/zhunter/zButtonTrap.lua +++ b/modules/zhunter/zButtonTrap.lua @@ -154,7 +154,8 @@ function zButtonTrap_SetupSizeAndPosition() zButtonTrap_EnsureConfig() local saved = zButtonTrap_GetSaved() if saved["enabled"] == false or saved["enabled"] == 0 then - if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then + if MTH_ZH_TrapAdjust then + MTH_ZH_TrapAdjust:UnregisterAllEvents() MTH_ZH_TrapAdjust:SetScript("OnEvent", nil) end if zButtonTrap and zButtonTrap.Hide then @@ -162,7 +163,12 @@ function zButtonTrap_SetupSizeAndPosition() end return end - if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then + if MTH_ZH_TrapAdjust then + MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_ENABLED") + MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_DISABLED") + MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_ENTERING_WORLD") + MTH_ZH_TrapAdjust:RegisterEvent("SPELLS_CHANGED") + MTH_ZH_TrapAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED") MTH_ZH_TrapAdjust:SetScript("OnEvent", MTH_ZH_TrapAdjust_OnEvent) end local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX