From 8248e4ed91b117ad532bc085a0036b7307e6e6f4 Mon Sep 17 00:00:00 2001 From: Meow <30401521+me0wg4ming@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:45:07 +0100 Subject: [PATCH] possible fix for healpredicts with queued casting possible fix for healpredicts with queued casting --- libs/libdebuff.lua | 25 +++++++++++++++++++++++++ libs/libpredict.lua | 40 +++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index b71101f1..fd0ffe03 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -193,6 +193,12 @@ local AURA_CAST_DEDUPE_WINDOW = 0.1 -- Ignore duplicates within 100ms -- SPELL_CAST_EVENT fires BEFORE UnitAura updates, so GetComboPoints() still works local capturedCP = nil +-- Pending cast info for libpredict (heal prediction target tracking) +-- SPELL_CAST_EVENT fires with targetGuid BEFORE SPELLCAST_START, +-- which allows libpredict to know the correct target for queued casts. +-- Fields: { spellId, spellName, targetGuid, time } +pfUI.libpredict_pending_cast = pfUI.libpredict_pending_cast or {} + -- ============================================================================ -- STATIC POPUP DIALOGS -- ============================================================================ @@ -1296,6 +1302,8 @@ if hasNampower then -- This event fires when YOU cast a spell (before server processes it) local success = arg1 local spellId = arg2 + local castType = arg3 + local targetGuid = arg4 if success ~= 1 or not spellId then return end @@ -1309,6 +1317,23 @@ if hasNampower then spellName = SpellInfo(spellId) end + -- Store pending cast info for libpredict (heal prediction target tracking) + -- This allows libpredict to resolve the correct target for Nampower queued casts, + -- where CastSpellByName hook fires while current_cast is set and spell_queue + -- cannot be updated. SPELL_CAST_EVENT fires right before SPELLCAST_START. + if spellName and targetGuid and targetGuid ~= "" and targetGuid ~= "0x0000000000000000" then + pfUI.libpredict_pending_cast.spellId = spellId + pfUI.libpredict_pending_cast.spellName = spellName + pfUI.libpredict_pending_cast.targetGuid = targetGuid + pfUI.libpredict_pending_cast.time = GetTime() + else + -- No explicit target - clear pending so libpredict falls back to spell_queue + pfUI.libpredict_pending_cast.spellId = nil + pfUI.libpredict_pending_cast.spellName = nil + pfUI.libpredict_pending_cast.targetGuid = nil + pfUI.libpredict_pending_cast.time = nil + end + -- Only capture CPs for combo-point abilities if spellName and IsComboPointAbility(spellName) then capturedCP = GetComboPoints() or 0 diff --git a/libs/libpredict.lua b/libs/libpredict.lua index bc52fff0..141d405b 100644 --- a/libs/libpredict.lua +++ b/libs/libpredict.lua @@ -936,13 +936,39 @@ libpredict.sender:SetScript("OnEvent", function() elseif event == "SPELLCAST_START" then local spell, time = arg1, arg2 + -- Resolve target from SPELL_CAST_EVENT (via libdebuff) for Nampower queued casts. + -- SPELL_CAST_EVENT fires right before SPELLCAST_START with the actual targetGuid, + -- solving the problem where spell_queue[3] is stale because CastSpellByName hook + -- could not update it while current_cast was set (Nampower spell queuing). + local pending = pfUI.libpredict_pending_cast + local pendingTarget = nil + if pending and pending.spellName == spell and pending.targetGuid + and pending.time and (GetTime() - pending.time) < 1 then + pendingTarget = UnitName(pending.targetGuid) + -- Validate: must be a friendly unit for heal prediction + if pendingTarget and pendingTarget ~= UNKNOWNOBJECT and pendingTarget ~= UKNOWNBEING then + if libpredict.debug then + DEFAULT_CHAT_FRAME:AddMessage(string.format( + "|cff00ffff[libpredict]|r SPELL_CAST_EVENT target: %s (guid: %s) for %s", + pendingTarget, pending.targetGuid, spell)) + end + else + pendingTarget = nil + end + -- Clear pending after consumption + pending.spellId = nil + pending.spellName = nil + pending.targetGuid = nil + pending.time = nil + end + -- Speichere aktuellen Cast (wird nicht von Instant-Hooks überschrieben) this.current_cast = spell - this.current_cast_target = senttarget or spell_queue[3] + this.current_cast_target = pendingTarget or senttarget or spell_queue[3] if spell_queue[1] == spell and cache[spell_queue[2]] then local sender = player - local target = senttarget or spell_queue[3] + local target = pendingTarget or senttarget or spell_queue[3] local amount = cache[spell_queue[2]][1] local casttime = time @@ -953,10 +979,10 @@ libpredict.sender:SetScript("OnEvent", function() local rankNum = rankStr and tonumber(rankStr) or nil if this.regrowth_timer then - this.regrowth_target_next = spell_queue[3] + this.regrowth_target_next = pendingTarget or spell_queue[3] this.regrowth_rank_next = rankNum else - this.regrowth_target = spell_queue[3] + this.regrowth_target = pendingTarget or spell_queue[3] this.regrowth_rank = rankNum end end @@ -978,7 +1004,7 @@ libpredict.sender:SetScript("OnEvent", function() libpredict.sender.healing = true elseif spell_queue[1] == spell and L["resurrections"][spell] then - local target = senttarget or spell_queue[3] + local target = pendingTarget or senttarget or spell_queue[3] libpredict:Ress(player, target) libpredict.sender:SendHealCommMsg("Resurrection/" .. target .. "/start/") libpredict.sender:SendResCommMsg("RES " .. target) @@ -995,7 +1021,7 @@ libpredict.sender:SetScript("OnEvent", function() libpredict.sender:SendHealCommMsg("HealStop") libpredict.sender.healing = nil elseif libpredict.sender.resurrecting then - local target = senttarget or spell_queue[3] + local target = this.current_cast_target or senttarget or spell_queue[3] libpredict:RessStop(player) libpredict.sender:SendHealCommMsg("Resurrection/stop/") libpredict.sender:SendResCommMsg("RESNO " .. target) @@ -1024,7 +1050,7 @@ libpredict.sender:SetScript("OnEvent", function() libpredict.sender:SendHealCommMsg("HealStop") libpredict.sender.healing = nil elseif libpredict.sender.resurrecting then - local target = senttarget or spell_queue[3] + local target = this.current_cast_target or senttarget or spell_queue[3] libpredict:RessStop(player) libpredict.sender:SendHealCommMsg("Resurrection/stop/") libpredict.sender:SendResCommMsg("RESNO " .. target)