Reply
Thread Tools Display Modes
Unread 10-29-14, 05:09 PM   #1
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
Unable detect interrupts caused by silence effects

I've been working on some addon-related code to detect spell interrupts for me and have run into kind of a major problem.

I noticed that it was working fine when I would pummel a spell, but if I had Gag Order glyphed it failed.

The problem was that it changes it from an interrupt to a silence. Normally, pummel triggers a SPELL_INTERRUPT event in COMBAT_LOG_UNFILTERED. However, as it turns out, silence effects don't appear to produce *anything*. Like, at all.


From what I'm seeing, the mob starts casting (SPELL_CAST_START), I apply a silence and see SPELL_AURA_APPLIED for the silence as expected. Then... nothing. There is no SPELL_CAST_STOP, SPELL_CAST_FAILED, or SPELL_INTERRUPT to catch. The inconsistency is really driving me nuts.

Is there any way at all to detect when a spell has been interrupted because of a silence effect?

Edit: Derped the title. Unable *TO* detect interrupts...
Sargeant is offline   Reply With Quote
Unread 10-29-14, 05:47 PM   #2
Tonyleila
A Scalebane Royal Guard
 
Tonyleila's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 414
Maybe SPELL_AURA_APPLIED can only happen if you interrupt the enemy?
As far as I know since the patch the enemy dosen't get a debuff so all interrupts are without a length.
__________________
Author of: LeilaUI and Aurora: Missing Textures
__________________
Tonyleila is offline   Reply With Quote
Unread 10-29-14, 07:18 PM   #3
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
Originally Posted by Tonyleila View Post
Maybe SPELL_AURA_APPLIED can only happen if you interrupt the enemy?
As far as I know since the patch the enemy dosen't get a debuff so all interrupts are without a length.
Sadly, no. Unfortunately, the aura gets applied to the target whether they are casting at the time or not.

I tried checking the unit's casting info at the time of the aura being applied, but it appears that by the time I can catch the event in the combat log, the silence has already kicked in and the unit is no longer casting.

Hm.. Maybe UNIT_AURA would trigger early enough?
Sargeant is offline   Reply With Quote
Unread 10-29-14, 08:36 PM   #4
Phanx
A Pyroguard Emberseer
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 4,591
Use /etrace, and try not to do too many unrelated actions if you value your sanity.
__________________
Author/maintainer of Grid, PhanxChat, ShieldsUp, and many more.
Troubleshoot an addonTurn any code into an addonMore addon resources
Need help with your code? Post all of your actual code! Attach or paste your files.
Please don’t PM me about addon bugs or code questions. Post a comment or forum thread instead!
Phanx is offline   Reply With Quote
Unread 10-29-14, 09:34 PM   #5
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
Originally Posted by Phanx View Post
Use /etrace, and try not to do too many unrelated actions if you value your sanity.
I can't believe I didn't know about that - wow, that helps a ton (assuming you can keep the spam down)!

Turns out the magic event was UNIT_SPELLCAST_FAILED_QUIET. Thanks!

Edit: Or, apparently, just UNIT_SPELLCAST_INTERRUPTED. Can't believe I didn't do that already. Note to self: COMBAT_LOG_EVENT_UNFILTERED is not very useful for this kind of thing.

Edit2 : And... just realized there's no way to figure out which unit *caused* the interrupt from that event.. =\

Last edited by Sargeant : 10-30-14 at 02:29 AM.
Sargeant is offline   Reply With Quote
Unread 10-29-14, 09:38 PM   #6
Phanx
A Pyroguard Emberseer
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 4,591
I've been meaning to write an addon to make the /etrace window more user-friendly, but I generally reduce the spam a bit by opening it, doing some irrelevant actions (open the map, mouse over some units, press a modifier key, etc.) and then removing all the events they generated from the window (hover and press the "X"). It's tedious, but fortunately not required that often... which is also why I've never gotten around to writing that addon.
__________________
Author/maintainer of Grid, PhanxChat, ShieldsUp, and many more.
Troubleshoot an addonTurn any code into an addonMore addon resources
Need help with your code? Post all of your actual code! Attach or paste your files.
Please don’t PM me about addon bugs or code questions. Post a comment or forum thread instead!
Phanx is offline   Reply With Quote
Unread 10-29-14, 10:33 PM   #7
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
The point of this thing was to get proper interrupt announcement for my warrior's Gag Order silence. I simply wanted to announce when a spell was interrupted by my Gag Order's silence debuff.

I did it, but... I had to do some things I'm not proud of.

I could catch silences with UNIT_SPELLCAST_INTERRUPTED - but I couldn't tell WHO silenced the spell or HOW - the spellcast is interrupted before the silence aura is ever actually applied to the mob. Hence, this wasn't every useful - I can't tell if I interrupted it with Gag Order, or if the Rogue beside me kicked it.

I can look at UNIT_AURA and then check for my silence debuff - but, by then it's too late. The spell has already been interrupted. I have no way to tell what it was casting before the debuff was applied.

I... I could use a macro so that, just before I cast Pummel, I check the spell my silence target is casting (and whether it's interruptible) with UnitCastingInfo and save it to a global variable. And then, when I catch UNIT_AURA, I check for my silence debuff and, if I find it, I look to see if the global variable is set and, if it is, then I know that the silence debuff caused a spell to be interrupted.

But.. eww... it feels so dirty.

But, wait, I can't make a spell link to announce with with just the spell name... and UnitCastingInfo doesn't return the spellId, so I can't make one. Unless I also catch UNIT_SPELLCAST_INTERRUPTED, see if the casting unit was the unit that I cast my Pummel upon from my macro, and whether the previous global variable was set... then I can set ANOTHER global variable with the real spell id taken from the parameters passed to the event. Then, I could use the spell ID in my UNIT_AURA hook to form a proper spell link.

Ughh... I think I just threw up a little. It's a tremendously dirty hack and it makes me feel bad.

Last edited by Sargeant : 10-30-14 at 02:31 AM.
Sargeant is offline   Reply With Quote
Unread 10-30-14, 12:07 AM   #8
Phanx
A Pyroguard Emberseer
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 4,591
That's not really a hack, though it is a bit inefficient. You really only need to keep track of the unique ID for the cast. Assuming that the relevant UNIT_SPELLCAST_INTERRUPTED event always fires after the UNIT_SPELLCAST_SUCCEEDED event for your Pummel, something like this is fairly straightforward and should get the job done:

Code:
local pummelCast

local f = CreateFrame("Frame")
f:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
f:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", "target")

f:SetScript("OnEvent", function(self, event, ...)
     if event == "UNIT_SPELLCAST_SUCCEEDED" then
          -- You cast Pummel
          local _, _, _, _, _, _, _, castID, interruptible = UnitCastingInfo("target")
          if castID and interruptible then
               pummelCast = castID
          else
               castID = nil
          end
     else
          -- Your target's spellcast was interrupted
          local _, _, _, castID, spellID = ...
          if castID = pummelCast then
              print("Interrupted", GetSpellLink(spellID))
          end
          knownCastID = nil
     end
end)
If you're using Pummel on units other than your target, you'll need to make some minor modifications to avoid using a hardcoded "target" unit, but you don't need to keep track of the target between events, because two units won't ever share a castID.
__________________
Author/maintainer of Grid, PhanxChat, ShieldsUp, and many more.
Troubleshoot an addonTurn any code into an addonMore addon resources
Need help with your code? Post all of your actual code! Attach or paste your files.
Please don’t PM me about addon bugs or code questions. Post a comment or forum thread instead!
Phanx is offline   Reply With Quote
Unread 10-30-14, 02:11 AM   #9
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
Tried to make it work with focus as well as target, but try as I might I couldnt manage to get the unitId of the pummel target. UNIT_SPELLCAST_SENT can get you the name (i.e., the full name of the mob), but that's ambiguous - doesn't seem like we can determine whether the target of the successful interrupt is a target or focus. You could look at both units and make an educated guess, but nothing that I can think of will work 100% of the time.

Regardless, I extended it a little, fixed a couple small oversights, and it seems to work great.

This is my new event handler:

Code:
function(event, sourceUnit, spellName, _, castId, spellId)
    if event == "UNIT_SPELLCAST_SUCCEEDED" then
        -- You cast Pummel or Heroic Throw
        if sourceUnit == "player" then
            if spellName == "Pummel" or spellName == "Heroic Throw" then
                local _, _, _, _, _, _, _, targetCastId, interruptible = UnitCastingInfo("target")
                if targetCastId and not interruptible then
                    interruptedCast = targetCastId
                else
                    interruptedCast = nil
                end
            end
        end
    else
        -- Your target's spellcast was interrupted
        if castId == interruptedCast then
            
            local announceStr = "Interrupted "..UnitName(sourceUnit).."'s "..GetSpellLink(spellId)
            
            local chatType = nil;
            local _, _, difficulty = GetInstanceInfo();
            if difficulty ~= 0 then 
                chatType = "INSTANCE_CHAT"
            elseif IsInRaid() then
                chatType = "RAID"
            elseif IsInGroup() then
                chatType = "PARTY"
            --else
                --chatType = "SAY"
            end
            
            if chatType ~= nil then
                SendChatMessage(announceStr, chatType)
            end
            
        end
    end
end
The only complication I see is that if you DON'T have Gag Order glyphed, you Heroic Throw on a casting mob and then someone else interrupts it, then you'll announce as if you interrupted it yourself. I could use GetGlyphSocketInfo and actually check for this, but it seems like a lot of overhead. I'll just make sure this is only loaded when I'm in my spec that uses this glyph. =p

If you happen to think of a way to handle focus targets, I'd love to hear it.

Thanks for the pointers, this is much more elegant than my previous iteration.

Last edited by Sargeant : 10-30-14 at 02:38 AM.
Sargeant is offline   Reply With Quote
Unread 10-30-14, 02:53 AM   #10
Phanx
A Pyroguard Emberseer
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 4,591
This is probably the easiest way to get the actual unit token for your spellcast target:

Code:
hooksecurefunc("CastSpellByName", function(spellName, unit)
     -- check the spell, store the unit in a variable
end)
While CastSpellByName is totally off-limits for use by addons, you can still use a secure hook to observe it. You could only use this hook instead of listening for UNIT_SPELLCAST_SUCCEEDED, but that would cause issues if you tried to cast but were unable to do so for any reason, so I'd recommend keeping the event; the order of things that happen will then be:

1. CastSpellByName - check spell name, store unit
2. UNIT_SPELLCAST_SUCCEEDED "player" - check spell name, store cast ID
3. UNIT_SPELLCAST_INTERRUPTED - check unit and cast ID

Originally Posted by Sargeant View Post
if sourceUnit == "player" then
This check is not necessary. When you use RegisterUnitEvent instead of RegisterEvent, your frame only recieves the event if the unit matches what you registered.

Additionally, using the CastSpellByName hook to catch the unit, you'd want to register for UNIT_SPELLCAST_INTERRUPTED this way:

Code:
frame:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", "target", "focus")
If you ever switched to a macro that could cast on other units (eg. mouseover, targettarget, party1target) you'd have to just use RegisterEvent, but since it sounds like target/focus are the only options, I'd stick with RegisterUnitEvent to reduce overhead.

Originally Posted by Sargeant View Post
The only complication I see is that if you DON'T have Gag Order glyphed, you Heroic Throw on a casting mob and then someone else interrupts it, then you'll announce as if you interrupted it yourself. I could use GetGlyphSocketInfo and actually check for this, but it seems like a lot of overhead.
The overhead would be negligible. Glyphs really don't change that often.

Code:
addon:RegisterForEvent("PLAYER_LOGIN")
addon:RegisterForEvent("PLAYER_SPECIALIZATION_CHANGED")

    elseif event == "UNIT_SPELLCAST_INTERRUPTED" then
        -- ^ have to explicitly check this now
        -- your interrupt code goes here
    else
        -- check glyphs on login, when glyphs change, and when switching specs
        for i = 1, GetNumGlyphSockets() do
            local _, _, _, spellID = GetGlyphSocketInfo(i)
            if spellID == 58357 then
                -- register other events here
                return
            end
        end
        -- unregister other events here
end
__________________
Author/maintainer of Grid, PhanxChat, ShieldsUp, and many more.
Troubleshoot an addonTurn any code into an addonMore addon resources
Need help with your code? Post all of your actual code! Attach or paste your files.
Please don’t PM me about addon bugs or code questions. Post a comment or forum thread instead!
Phanx is offline   Reply With Quote
Unread 10-30-14, 09:52 PM   #11
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
I'm using the hook to CastSpellByName to figure out what the target of my interrupt is and it's working like a charm. Thanks a ton for all the help.

(Can you tell I'm not too familiar with the WoW API? =p )
Sargeant is offline   Reply With Quote
Unread 10-30-14, 11:43 PM   #12
Sargeant
A Murloc Raider
 
Sargeant's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 8
Well crap.

Just discovered a major flaw while running some randoms tonight.

Sometimes, the castId just comes back as zero for whatever reason when logically it shouldn't. When this happens, you can wind up announcing every time a mob with your last interrupt's unitId has a cast fail for *any* reason - including other player's interrupts and the mob's death.

The only way I can find to work around it is to add in another event handler for UNIT_AURA and start looking for the silence debuff again. Oh well.

Now it looks something more like:

CastSpellByName Hook:
Code:
function(spellName, unit)
        if spellName == "Pummel" or spellName == "Heroic Throw" then
            silence_target = unit
        end
end

UNIT_SPELLCAST_ Handler:
Code:
function(event, sourceUnit, spellName, _, castId, spellId)
    if event == "UNIT_SPELLCAST_SUCCEEDED" then
        -- You cast Pummel or Heroic Throw
          if spellName == "Pummel" or spellName == "Heroic Throw" then
              if silence_target ~= nil then
                  local _, _, _, _, _, _, _, targetCastId, uninterruptible = UnitCastingInfo(silence_target)
                  if targetCastId and not uninterruptible then
                      interruptedCast = targetCastId
                  else
                      interruptedCast = nil
                      silence_spellId = nil
                  end
              end
          end
    else
        -- Your target's spellcast was interrupted
        if castId == interruptedCast then
            silence_spellId = spellId
        end
    end
end
UNIT_AURA Handler:
Code:
function(event, unit)
    if unit == wa_silence_target then
        local name, _ = UnitAura(silence_target, "Silenced - Gag Order", nil, "PLAYER|HARMFUL")
        if name ~= nil then
            local announceStr = "Interrupted "..UnitName(unit).."'s "..GetSpellLink(silence_spellId)
            
            local chatType = nil;
            local _, _, difficulty = GetInstanceInfo();
            if difficulty ~= 0 then 
                chatType = "INSTANCE_CHAT"
            elseif IsInRaid() then
                chatType = "RAID"
            elseif IsInGroup() then
                chatType = "PARTY"
            else
                chatType = "SAY"
            end
            
            if chatType ~= nil then
                SendChatMessage(announceStr, chatType)
            end
            
        end
    end
end
Not as nice as it was, but at least it works correctly.

Last edited by Sargeant : 10-31-14 at 12:47 AM.
Sargeant is offline   Reply With Quote
Reply

Go BackWoWInterface » Developer Discussions » General Authoring Discussion » Unable detect interrupts caused by silence effects

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off