Thread Tools Display Modes
03-25-16, 06:15 PM   #1
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Script ran too long - since 6.2.4?

Since the update rolled out, I've been having trouble with replacing masked textures in combat. Just wanted to check whether this is a random fluke on my computer or something that was actually changed in the patch. For example, I have 15 action buttons that are all based off of libactionbutton, and they all have a masked icon. Swapping the states in combat causes the "script ran too long" error at random when it's attempting to replace a masked texture just by doing:

Lua Code:
  1. self.icon:SetTexture(texture)

The same error occurs when using their built in portrait function, which I reckon also applies a mask:

Lua Code:
  1. SetPortraitToTexture(self.SpellPortrait, self.spellTexture)

Here's the actual error text for the last part and this is in a much less expensive function:
Code:
5x ConsolePort\Cursors\UnitFrames.lua:669: script ran too long
ConsolePort\Cursors\UnitFrames.lua:669: in function <ConsolePort\Cursors\UnitFrames.lua:659>
So... random fluke on my client or further restriction on amount of CPU expenditure for a single function in combat?
__________________

Last edited by MunkDev : 03-25-16 at 06:26 PM.
  Reply With Quote
03-25-16, 06:25 PM   #2
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I hardly think it's the root of the issue. I set loads of textures like that and i don't have any issues with it. In the other hand, this 6.2.4 patch is fucked up in so many ways, so it's hard to tell.

Script run too long ususally caused by when a single function call runs for way too long time before it's finished, this threshold time is shorter while you are in combat.

You need to show us the whole code of that file thats having the issue.
  Reply With Quote
03-25-16, 06:33 PM   #3
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Code is unchanged since the patch and it happens in two completely different places that perform very different actions from one another. The error always happens when trying to replace a masked texture and not in any other circumstance. Removing the mask resolves the issue.
__________________
  Reply With Quote
03-25-16, 06:38 PM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
https://github.com/seblindfors/Conso...rames.lua#L659


First of all i would advise not to use while cycle on an onupdate script like that, some systems can't handle it properly. At least it was like that way back than in Vanilla/BC.

You can use something like this:
Code:
self.Time = (self.Time or 0) + elapsed
if self.Time < 0.1 then
	return
end
self.Time = 0
You issue is almost 100% sure is calling SetPortraitToTexture way too many times in very little time. Even if it's throttled to 0.1 sec.

You should create something like this:

Lua Code:
  1. function Cursor:UpdatePortrait(portrait, texture)
  2.     if self.texture ~= texture then
  3.         SetPortraitToTexture(portrait, texture)
  4.  
  5.         self.texture = texture
  6.     end
  7. end
  8.  
  9. function Cursor:Update(elapsed)
  10.     self.Time = (self.Time or 0) + elapsed
  11.     if self.Time < 0.1 then
  12.         return
  13.     end
  14.     self.Time = 0
  15.  
  16.     if self.unit and UnitExists(self.unit) then
  17.         if self.isCasting then
  18.             local time = GetTime() * 1000
  19.             local progress = (time - self.startCast) / (self.endCast - self.startCast)
  20.             local resize = 128 - (40 * (1 - progress))
  21.             self.CastBar:SetRotation(-2 * progress * pi)
  22.             self.CastBar:SetSize(resize, resize)
  23.             --SetPortraitToTexture(self.SpellPortrait, self.spellTexture)
  24.             self:UpdatePortrait(self.SpellPortrait, self.spellTexture)
  25.         elseif self.isChanneling then
  26.             local time = GetTime() * 1000
  27.             local progress = (time - self.startChannel) / (self.endChannel - self.startChannel)
  28.             local resize = 128 - (40 * (1 - progress))
  29.             self.CastBar:SetRotation(-2 * progress * pi)
  30.             self.CastBar:SetSize(resize, resize)
  31.             --SetPortraitToTexture(self.SpellPortrait, self.spellTexture)
  32.             self:UpdatePortrait(self.SpellPortrait, self.spellTexture)
  33.         elseif self.resetPortrait then
  34.             self.resetPortrait = false
  35.             --SetPortraitTexture(self.UnitPortrait, self.unit)
  36.             self:UpdatePortrait(self.UnitPortrait, self.unit)
  37.         end
  38.     end
  39. end

You will save a lot of unnecessary calls like this.

Now i'm not familiary how should this script work, but isn't this line should be zeroing down the timer?
https://github.com/seblindfors/Conso...rames.lua#L682

Last edited by Resike : 03-25-16 at 06:49 PM.
  Reply With Quote
03-25-16, 06:53 PM   #5
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by MunkDev View Post
Code is unchanged since the patch and it happens in two completely different places that perform very different actions from one another. The error always happens when trying to replace a masked texture and not in any other circumstance. Removing the mask resolves the issue.
Blizzard is actively watching addon function calls that use server resources too hard and adjust their throttle values patch by patch sometimes. You might run into something like this.
  Reply With Quote
03-25-16, 06:57 PM   #6
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
I removed the texture update from the update script, since it wasn't really necessary. Just lazy coding that wasn't problematic at the time of inception. Moved it to events instead.

Here's another place in which it happens:
https://github.com/seblindfors/Conso...tton.lua#L1153

This is a modified libactionbutton (used in Bartender) and the masked texture causes the same error here. This texture update only happens on 15 out of 60 action buttons.
__________________
  Reply With Quote
03-25-16, 07:21 PM   #7
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by MunkDev View Post
I removed the texture update from the update script, since it wasn't really necessary. Just lazy coding that wasn't problematic at the time of inception. Moved it to events instead.

Here's another place in which it happens:
https://github.com/seblindfors/Conso...tton.lua#L1153

This is a modified libactionbutton (used in Bartender) and the masked texture causes the same error here. This texture update only happens on 15 out of 60 action buttons.
I'm not sure about that. It should not get triggered for 15 updates.

The only thing i could found is:
https://github.com/seblindfors/Conso...apper.lua#L200

Shouldn't this be %s instead of "%s"?

Anyway it's 3am here so i'll check back tomorrow if noone can help you untill.

Last edited by Resike : 03-25-16 at 07:25 PM.
  Reply With Quote
03-25-16, 07:27 PM   #8
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Originally Posted by Resike View Post
I'm not sure about that. It should not get triggered for 15 updates.

The only thing i could found is:
https://github.com/seblindfors/Conso...apper.lua#L200

Shouldn't this be %s instead of "%s"?
That's completely unrelated, since this happens when the buttons are created or their actions are changed due to a config update. And nope, I'm formatting a long string and passing another string into it. The resulting snippet looks like this (when id == "shift" for example):

Lua Code:
  1. self:RunAttribute("UpdateState", "shift")
  2. self:CallMethod("UpdateAction")
__________________
  Reply With Quote
03-25-16, 07:30 PM   #9
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Originally Posted by Resike View Post
Anyway it's 3am here so i'll check back tomorrow if noone can help you untill.
Thanks for the help anyway.
__________________
  Reply With Quote
03-26-16, 06:22 AM   #10
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Can i trigger this issue without a controller? I've tried but did not succeeded.
  Reply With Quote
03-26-16, 09:58 AM   #11
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Maybe. Here's the code that's relevant to the update:

Lua Code:
  1. -- Bar snippets in relevant order
  2. local Bar = CreateFrame("Frame", "Bar", UIParent, "SecureHandlerStateTemplate, SecureHandlerEnterLeaveTemplate")
  3. -- state driver
  4. RegisterStateDriver(Bar, "modifier", "[mod:ctrl,mod:shift] ctrlsh; [mod:ctrl] ctrl; [mod:shift] shift; action")
  5. -- when modifier changes
  6. Bar:SetAttribute("_onstate-modifier", [[
  7.     self:SetAttribute("state", newstate)
  8.     control:ChildUpdate("state", newstate)
  9. ]])

Lua Code:
  1. -- Button snippets in relevant order
  2. button:SetAttribute("_childupdate-state", [[
  3.     if self:GetAttribute("mainbutton") then -- this is only true for 15 / 60 buttons
  4.         self:RunAttribute("UpdateState", message)
  5.         self:CallMethod("UpdateAction")
  6.     end
  7. ]])
  8.  
  9. button:SetAttribute("UpdateState", [[
  10.     local state = ...
  11.     self:SetAttribute("state", state)
  12.     local type, action = (self:GetAttribute(format("labtype-%s", state)) or "empty"), self:GetAttribute(format("labaction-%s", state))
  13.  
  14.     self:SetAttribute("type", type)
  15.     if type ~= "empty" and type ~= "custom" then
  16.         local action_field = (type == "pet") and "action" or type
  17.         self:SetAttribute(action_field, action)
  18.         self:SetAttribute("action_field", action_field)
  19.     end
  20.     local onStateChanged = self:GetAttribute("OnStateChanged")
  21.     if onStateChanged then
  22.         self:Run(onStateChanged, state, type, action)
  23.     end
  24. ]])
  25.  
  26. function Generic:UpdateAction(force)
  27.     local type, action = self:GetAction()
  28.     if force or type ~= self._state_type or action ~= self._state_action then
  29.         -- type changed, update the metatable
  30.         if force or self._state_type ~= type then
  31.             local meta = type_meta_map[type] or type_meta_map.empty
  32.             setmetatable(self, meta)
  33.             self._state_type = type
  34.         end
  35.         self._state_action = action
  36.         Update(self)
  37.     end
  38. end
  39.  
  40. function Update(self)
  41.     if self:HasAction() then
  42.         ActiveButtons[self] = true
  43.         if self._state_type == "action" then
  44.             ActionButtons[self] = true
  45.             NonActionButtons[self] = nil
  46.         else
  47.             ActionButtons[self] = nil
  48.             NonActionButtons[self] = true
  49.         end
  50.     --  self:SetAlpha(1.0)
  51.         UpdateButtonState(self)
  52.         UpdateUsable(self)
  53.         UpdateCooldown(self)
  54.         UpdateFlash(self)
  55.     else
  56.         ActiveButtons[self] = nil
  57.         ActionButtons[self] = nil
  58.         NonActionButtons[self] = nil
  59.         if gridCounter == 0 and not self.config.showGrid then
  60.     --      self:SetAlpha(0.0)
  61.         end
  62.         self.cooldown:Hide()
  63.         self:SetChecked(false)
  64.  
  65.         if self.chargeCooldown then
  66.             EndChargeCooldown(self.chargeCooldown)
  67.         end
  68.     end
  69.  
  70.     -- Add a green border if button is an equipped item
  71.     if self:IsEquipped() and not self.config.hideElements.equipped then
  72.         self.Border:SetVertexColor(0, 1.0, 0, 0.35)
  73.         self.Border:Show()
  74.     else
  75.         self.Border:Hide()
  76.     end
  77.  
  78.     -- Update Action Text
  79.     if not self:IsConsumableOrStackable() then
  80.         self.Name:SetText(self:GetActionText())
  81.     else
  82.         self.Name:SetText("")
  83.     end
  84.  
  85.     -- Update icon and hotkey
  86.     local texture = self:GetTexture()
  87.  
  88.     -- Draenor zone button handling
  89.     self.draenorZoneDisabled = false
  90.     self.icon:SetDesaturated(false)
  91.     if self._state_type == "action" then
  92.         local action_type, id = GetActionInfo(self._state_action)
  93.         if ((action_type == "spell" or action_type == "companion") and DraenorZoneAbilityFrame and DraenorZoneAbilityFrame.baseName and not HasDraenorZoneAbility()) then
  94.             local name = GetSpellInfo(DraenorZoneAbilityFrame.baseName)
  95.             local abilityName = GetSpellInfo(id)
  96.             if name == abilityName then
  97.                 texture = GetLastDraenorSpellTexture()
  98.                 self.draenorZoneDisabled = true
  99.                 self.icon:SetDesaturated(true)
  100.             end
  101.         end
  102.     end
  103.  
  104.     if texture and texture ~= self.cachedTexture then
  105.         self.cachedTexture = texture
  106.         self.icon:SetTexture(texture) -- where it breaks down when icons are masked
  107.         self.icon:Show()
  108.         self.rangeTimer = - 1
  109.     elseif not texture then
  110.         self.cachedTexture = nil
  111.         self.icon:Hide()
  112.         self.cooldown:Hide()
  113.         self.rangeTimer = nil
  114.     end
  115.  
  116.     UpdateCount(self)
  117.  
  118.     UpdateFlyout(self)
  119.  
  120.     UpdateOverlayGlow(self)
  121.  
  122.     UpdateNewAction(self)
  123.  
  124.     if GameTooltip:GetOwner() == self then
  125.         UpdateTooltip(self)
  126.     end
  127.  
  128.     -- this could've been a spec change, need to call OnStateChanged for action buttons, if present
  129.     if not InCombatLockdown() and self._state_type == "action" then
  130.         local onStateChanged = self:GetAttribute("OnStateChanged")
  131.         if onStateChanged then
  132.             self.header:SetFrameRef("updateButton", self)
  133.             self.header:Execute(([[
  134.                 local frame = self:GetFrameRef("updateButton")
  135.                 control:RunFor(frame, frame:GetAttribute("OnStateChanged"), %s, %s, %s)
  136.             ]]):format(formatHelper(self:GetAttribute("state")), formatHelper(self._state_type), formatHelper(self._state_action)))
  137.         end
  138.     end
  139.     lib.callbacks:Fire("OnButtonUpdate", self)
  140. end

Like I said, this is based on LibActionButton-1.0, which means it should be possible to reproduce with that library while using masked icons, although I haven't tried it myself. Maybe it's possible through swapping pages in Bartender if a mask is applied to all the buttons?
__________________

Last edited by MunkDev : 03-26-16 at 10:05 AM.
  Reply With Quote
03-26-16, 02:26 PM   #12
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
No luck i can't reproduce it. Could it be because a modifier key from a controller gets treated differently then from the keyboard for some reason?
  Reply With Quote
03-26-16, 04:29 PM   #13
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Originally Posted by Resike View Post
No luck i can't reproduce it. Could it be because a modifier key from a controller gets treated differently then from the keyboard for some reason?
Nope, they're translated to shift/ctrl through Windows API. Only one down event and one up event, no modifier spam that could account for the script error.

It's also strange in the sense that it only happens very infrequently. I can't reliably reproduce it without running a whole dungeon where it might happen just once, whereas the states are being changed all the time.
__________________
  Reply With Quote
03-26-16, 05:31 PM   #14
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
For anyone interested, I ran a few tests using an infinite loop to measure the time we have before this error comes up. The error does not trigger at all when out of combat as indicated by all tests completely freezing the game in this case. However, when in combat, we have about 200ms to do everything we need to do and return execution back to the game engine before this error triggers.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
03-26-16, 05:35 PM   #15
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
I've noticed a stutter that happens every now and then, but I can't seem to nail down what causes it. Also, I removed the application/removal of desaturation on the icon and I was unable to trigger the error in a couple of dungeon runs. There was also no stuttering.

This is the part I removed. Maybe desaturating / resaturating masked icons isn't a good idea, or this might be another logical fallacy.
Lua Code:
  1. self.icon:SetDesaturated(false)

Edit: Error still occurs. I was just unlucky (lucky?) and didn't manage to trigger it. Even though I've made multiple changes to the code, it STILL breaks in the same place, which further supports my theory that it has something to do with the mask on the texture.

I recorded myself and tried to reproduce the error, and it might be caused by a long trail of function calls rather than just the update script, since it seemingly happens when changing a modifier and tab targeting at the same time? Here's the video, and the error happens at 03:12.
__________________

Last edited by MunkDev : 03-26-16 at 06:49 PM.
  Reply With Quote
03-27-16, 05:53 AM   #16
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by MunkDev View Post
Nope, they're translated to shift/ctrl through Windows API. Only one down event and one up event, no modifier spam that could account for the script error.

It's also strange in the sense that it only happens very infrequently. I can't reliably reproduce it without running a whole dungeon where it might happen just once, whereas the states are being changed all the time.
Now that you said i know there is a bug in the game, where in combat in some dungeons the encounter shifts you into a vehicle tpye unit, and the action bars gets stuck, and you get into an infinite loop stuck where your action bar cannot decide if you are in a vehicle or not due some broken events, that could potentionally cause soemthing like this. It's just a wild guess tho.

I'm pretty sure on the last boss of Drak'Tharon Keep there is a pretty big chance of this happening:
http://www.wowhead.com/npc=26632/the-prophet-tharonja

Last edited by Resike : 03-27-16 at 05:57 AM.
  Reply With Quote
03-27-16, 05:56 AM   #17
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by SDPhantom View Post
For anyone interested, I ran a few tests using an infinite loop to measure the time we have before this error comes up. The error does not trigger at all when out of combat as indicated by all tests completely freezing the game in this case. However, when in combat, we have about 200ms to do everything we need to do and return execution back to the game engine before this error triggers.
Is it limited for one function? Lets say if you break things down to multiple functions maybe you could dodge this bullet?
  Reply With Quote
03-27-16, 01:55 PM   #18
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
The time only resets when the frame handler itself is called. This means you can't extend this just by repeatedly calling functions. Not even running them through pcall() would work. However, with clever coding, you can have multiple frames do a chunk of the work to extend the time you have. For example, you can have 5 frames put in a total of a full second of work combined to complete a task.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 03-27-16 at 02:05 PM.
  Reply With Quote
03-27-16, 03:39 PM   #19
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by SDPhantom View Post
The time only resets when the frame handler itself is called. This means you can't extend this just by repeatedly calling functions. Not even running them through pcall() would work. However, with clever coding, you can have multiple frames do a chunk of the work to extend the time you have. For example, you can have 5 frames put in a total of a full second of work combined to complete a task.
Intresting, to be honest i run into issue like that, with some very hard resource eating functions. But i probably just won't allow the frame creation to be called in combat.
  Reply With Quote
03-28-16, 05:40 AM   #20
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
One more thing came to my mind, it might be useless tho. Have you tried to kill the mask, set the new texture then apply the mask again? For some dumb (Blizzard) reason it might be faster then changing a masked texture.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Script ran too long - since 6.2.4?

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