Thread Tools Display Modes
01-03-15, 05:28 PM   #1
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 275
Bugs with AddOn - Lua Scripts

Hi, I recently created and uploaded an AddOn as a beta version and need help.

There seems to be many bugs but the one I am having great difficulties solving is the mystery of why my OnUpdate script will not run instantly like it is suppose to.

When you login, a frame's "GROUP_ROSTER_UPDATE" event is triggered which sets up the OnUpdate script but it does not run until much much later and no clue why. I also tried using many other events which definitely do trigger as well, such as "PLAYER_ENTERING_WORLD".

There are many other bugs, including disappearing bars etc.. but really lost as to why those problems happen so for now, one bug at a time and I can try dealing with those later.

Here is the entire code (the events are at the bottom with the OnUpdate script which does not fire correctly):

Lua Code:
  1. --[[ Created by Mayron - Twisting Nether (EU) ]]--
  2.  
  3. --[[ USER OPTIONS BELOW ]]--
  4. ----------------------------
  5.  
  6. local options = {
  7.  
  8.     ["Bar Texture"] = "Interface\\AddOns\\EarthShieldTracker\\EST_StatusBarTexture.tga",
  9.     ["Gap Between Bars"] = 2,
  10.     ["Bar Height"] = 20,
  11.     ["Window Width"] = 210,
  12.     ["Caster Text Color"] = { 1.0, 1.0, 1.0 }, -- red, green, blue (0.0 - 1.0 )
  13.    
  14. }
  15.  
  16. --[[ END OF USER OPTIONS ]]--
  17. -----------------------------
  18.  
  19. local ES = GetSpellInfo(974); -- "Earth Shield"
  20. local tracking = {} -- Holds the Tracking info
  21.  
  22. -- Setup Display Window:
  23. local window = CreateFrame("Frame", "EST_Window", UIParent, "HelpPlateBox");
  24. window:SetWidth(options["Window Width"]);
  25. window:SetFrameStrata("HIGH");
  26. if (not EST_DB) then
  27.     window:SetPoint("CENTER", UIParent, "CENTER");
  28. else
  29.     window:SetPoint(EST_DB[1], UIParent, EST_DB[3], EST_DB[4], EST_DB[5]);
  30. end
  31.    
  32. for i = 1, #window.Textures do
  33.     window.Textures[i]:SetVertexColor( 0, 0, 0 );
  34. end
  35.  
  36. -- Make Movable:
  37. window:SetMovable(true);
  38. window:EnableMouse(true)
  39. window:SetClampedToScreen(true);
  40. window:RegisterForDrag("LeftButton")
  41. window:SetScript("OnDragStart", function(self)
  42.     self:StartMoving();
  43. end)
  44. window:SetScript("OnDragStop", function(self)
  45.     self:StopMovingOrSizing();
  46.     EST_DB = { self:GetPoint("CENTER") };  
  47. end)
  48.  
  49. -- Setup Font Strings for Window:
  50. window.dest = window:CreateFontString(nil, "ARTWORK", "GameFontHighlight");
  51. window.dest:SetPoint("TOPLEFT", window, "TOPLEFT", 5, -4)
  52. window.dest:SetJustifyH("LEFT");
  53. window.dest:SetText("Target (stacks)");
  54. window.source = window:CreateFontString(nil, "ARTWORK", "GameFontHighlight");
  55. window.source:SetPoint("TOPRIGHT", window, "TOPRIGHT", -5, -5)
  56. window.source:SetJustifyH("RIGHT");
  57. window.source:SetText("Caster");
  58.  
  59. local popBar, pushBar; -- "static" functions
  60. do 
  61.     local stack = {};
  62.     local activeBars = 0;
  63.     local createdBars = 0;
  64.     function popBar(tracker) -- Returns a bar to be used.
  65.         --[[if (tracker.bar and tracking[tracker.sourceName]) then
  66.             return -- This unfortunately did not stop bars from being duplicated
  67.         end]]
  68.         local bar;
  69.         activeBars = activeBars + 1;       
  70.         for id, b in next, stack do
  71.             if (b and b.id) then
  72.                 bar = b;
  73.                 stack[bar.id] = nil;                   
  74.                 break;
  75.             end
  76.         end
  77.         if (not bar) then
  78.             -- if no bars have been created yet then create a new one      
  79.             createdBars = createdBars + 1;         
  80.             bar = CreateFrame("StatusBar", "EST_Bar"..createdBars, EST_Window, "TrackingBarTemplate");
  81.            
  82.             bar.id = createdBars;
  83.             bar:SetMinMaxValues(0, 9);
  84.             bar.barFlash:Hide()
  85.             bar.border:Hide();
  86.             bar.barSpark:Hide();
  87.             -- User preferences:
  88.             bar.source:SetTextColor(options["Caster Text Color"][1], options["Caster Text Color"][2], options["Caster Text Color"][3]);
  89.         end
  90.        
  91.         if (bar.id == 1) then              
  92.             bar:SetPoint("BOTTOMLEFT", EST_Window, "BOTTOMLEFT", 2, 2);
  93.             bar:SetPoint("BOTTOMRIGHT", EST_Window, "BOTTOMRIGHT", -2, 2);
  94.         else
  95.             bar:SetPoint("BOTTOMLEFT", _G["EST_Bar"..(bar.id - 1)], "TOPLEFT", 0, options["Gap Between Bars"]);
  96.             bar:SetPoint("BOTTOMRIGHT", _G["EST_Bar"..(bar.id - 1)], "TOPRIGHT", 0, options["Gap Between Bars"]);
  97.         end
  98.         window:SetHeight(2 + (activeBars * (options["Bar Height"] + options["Gap Between Bars"])) + 20);
  99.         return bar;
  100.     end
  101.    
  102.     function pushBar(bar)
  103.         activeBars = activeBars - 1;
  104.         stack[bar.id] = bar;
  105.         window:SetHeight(2 + (activeBars * (options["Bar Height"] + options["Gap Between Bars"])) + 20);
  106.     end
  107. end
  108.  
  109. --[[
  110.     When a bar is removed, bars ontop of it should be moved down by removing the tracker from the bar
  111.     and readding the tracker object to the bar below rather than using SetPoint to move the bars position in the list.
  112. --]]
  113. local reordering;
  114. local function ReorderTrackers(removedBarID)
  115.     reordering = true;
  116.     if (not next(tracking)) then
  117.         window:Hide();
  118.         reordering = nil;
  119.         return;
  120.     end
  121.     local newOrder = {};       
  122.     for sourceName, tracker in pairs(tracking) do
  123.         if (tracker.bar) then -- only remove ones above! --(tracker.bar.id > removedBarID)
  124.             --if (tracker.bar.id and (tracker.bar.id > removedBarID)) then -- this did not stop the problem either
  125.                 tracker:RemoveBar(); -- remove all active bars         
  126.                 table.insert(newOrder, tracker);
  127.             --end
  128.         else
  129.             tracking[sourceName] = nil; -- Should be removed
  130.         end
  131.     end
  132.     for id, tracker in ipairs(newOrder) do         
  133.         tracker.bar = popBar(tracker);
  134.         tracker:SetTrackingInfo();
  135.     end
  136.     reordering = nil;
  137. end
  138.  
  139. -- Creating Trackers:
  140. local trackerPrototype = {} -- metatable for Tracker objects to inherit
  141. trackerPrototype.__index = trackerPrototype;
  142.  
  143. --[[
  144.     Removes the Bar from the tracker object and pushes it back onto the stack for later use
  145. --]]
  146. function trackerPrototype:RemoveBar()
  147.     -- reset bar:
  148.     if (self.bar) then
  149.         self.bar:Hide();
  150.         self.bar:SetStatusBarColor(0, 0, 0, 0);
  151.         self.bar.dest:SetText(""); 
  152.         self.bar.source:SetText("");
  153.         self.bar:SetValue(0);      
  154.         pushBar(self.bar);
  155.         self.bar = nil;
  156.     end
  157. end
  158.  
  159. --[[
  160.     Checks all Raid members for ES and returns a table of found source/dest pairs
  161. --]]
  162. local function ScanRaid()  
  163.     local prefix = (IsInRaid() and "raid") or (IsInGroup() and "party");
  164.    
  165.     local tbl = {};
  166.    
  167.     -- Scans to check if a group member has ES applied:
  168.     if (prefix and GetNumGroupMembers() > 0) then
  169.         for i = 1, GetNumGroupMembers() do
  170.             local hasES = UnitBuff(prefix..i, ES);
  171.             if (hasES) then
  172.                 local destGUID = UnitGUID(prefix..i);
  173.                 local sourceID = (select(8, UnitBuff(prefix..i, ES)));
  174.                 if (sourceID) then
  175.                     local sourceGUID = UnitGUID(sourceID); -- Gets the ES Caster (the Shaman)
  176.                     tbl[sourceGUID] = destGUID;
  177.                 end
  178.             end
  179.         end
  180.     -- for testing only:
  181.     --[[else
  182.         local hasES = UnitBuff("player", ES);
  183.         if (hasES) then
  184.             local destGUID = UnitGUID("player");
  185.             local sourceGUID = UnitGUID( (select(8, UnitBuff("player", ES))) ); -- Gets the ES Caster (the Shaman)
  186.             tbl[sourceGUID] = destGUID;
  187.         end]]
  188.     end
  189.     return tbl;
  190. end
  191.  
  192. do
  193.     local function Tracker_OnUpdate(self)
  194.         if (self and tracking[self.sourceName]) then           
  195.             self:SetTrackingInfo();
  196.             if (IsInRaid() or IsInGroup()) then
  197.                 C_Timer.After(2, function() Tracker_OnUpdate(self) end)
  198.             end
  199.         end    
  200.     end
  201.    
  202.     --[[
  203.         Returns the UnitID of the destination player (the player who has ES on them) within the group
  204.     --]]
  205.     function trackerPrototype:GetUnitID(destName)
  206.         -- If the unitID has not changed then there is no need to recalculate it!
  207.         if (self.destUnitID) then
  208.             local foundName = UnitName(self.destUnitID);
  209.             if (foundName and foundName == destName) then
  210.                 return self.destUnitID;
  211.             end
  212.         end
  213.        
  214.         if (destName == UnitName("player")) then
  215.             return "player";
  216.         end
  217.  
  218.         local prefix = (IsInRaid() and "raid") or (IsInGroup() and "party");
  219.         if (GetNumGroupMembers() > 0) then
  220.             for i = 1, GetNumGroupMembers() do
  221.                 local foundName = UnitName(prefix..i);
  222.                 if (foundName and foundName == destName) then
  223.                     return (prefix..i);
  224.                 end
  225.             end
  226.         end
  227.     end
  228.    
  229.     --[[
  230.         Updates the destGUID or remove tracker if not found.
  231.     --]]
  232.     function trackerPrototype:GetNewDest()
  233.         local foundPairs = ScanRaid();
  234.         if (foundPairs[self.sourceGUID]) then -- source Shaman has ES on new target
  235.             self.destGUID = foundPairs[self.sourceGUID];
  236.             _, self.destClass, _, _, _, self.destName, _ = GetPlayerInfoByGUID(self.destGUID);                 
  237.             local destUnitID = self:GetUnitID(self.destName);
  238.             _, _, _, self.stacks = UnitBuff(destUnitID, ES);
  239.             return true;
  240.         else
  241.             if (self.bar) then
  242.                 local removedBarID = self.bar.id;
  243.                 self:RemoveBar();          
  244.                 tracking[self.sourceName] = nil;
  245.                 ReorderTrackers(removedBarID);
  246.             end
  247.             return false;
  248.         end
  249.     end
  250.    
  251.     --[[
  252.         Refreshes/Generates the details required and attaches a StatusBar to represent the
  253.         details of the tracker objects and sets up the bar to then be displayed on the window.
  254.     --]]
  255.     function trackerPrototype:SetTrackingInfo(firstTime)
  256.         if (reordering) then return end
  257.         _, self.sourceClass, _, _, _, self.sourceName, _ = GetPlayerInfoByGUID(self.sourceGUID);       
  258.         _, self.destClass, _, _, _, self.destName, _ = GetPlayerInfoByGUID(self.destGUID);
  259.        
  260.         local destUnitID = self:GetUnitID(self.destName);
  261.         local stacks, sourceUnitID;
  262.         if (destUnitID) then
  263.             _, _, _, stacks, _, _, _, sourceUnitID = UnitBuff(destUnitID, ES);
  264.         end
  265.        
  266.         if (stacks and sourceUnitID) then -- if ES found
  267.             local sourceGUID = UnitGUID(sourceUnitID);
  268.             if (self.sourceGUID == sourceGUID) then -- if same shaman applied it
  269.                 self.stacks = stacks;
  270.             else -- different shaman has ES on same dest
  271.                 local successful = self:GetNewDest();
  272.                 if (not successful) then return end
  273.             end    
  274.         else
  275.             local successful = self:GetNewDest();
  276.             if (not successful) then return end
  277.         end
  278.        
  279.         -- continue once stacks, dest info and sourc info is correct:  
  280.         if (not self.bar) then     
  281.             self.bar = popBar(self);
  282.             -- User Appearance Preferences:
  283.             self.bar:SetStatusBarTexture(options["Bar Texture"]);
  284.             self.bar:SetHeight(options["Bar Height"]);
  285.         end
  286.  
  287.         local c = (CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS)[self.destClass];
  288.         self.bar:SetStatusBarColor(c.r, c.g, c.b, 1);
  289.        
  290.         self.bar.dest:SetText( (self.destName)..' ('..(self.stacks)..')' );
  291.         self.bar.source:SetText(self.sourceName);
  292.         self.bar:SetValue(self.stacks);
  293.        
  294.         self.bar:Show();
  295.         window:Show(); 
  296.  
  297.         if (firstTime) then
  298.             C_Timer.After(2, function() Tracker_OnUpdate(self) end)
  299.         end
  300.     end
  301. end
  302.  
  303. --[[
  304.     Constructor: Constructs the Tracker Object which inherits trackerPrototype functions.
  305.     Fills out details of Tracker into the tracking table.
  306. --]]
  307. local function CreateTracker(sourceGUID, destGUID)
  308.     local sourceName = select(6, GetPlayerInfoByGUID(sourceGUID)); 
  309.     if (not sourceName) then return end -- source/caster is not a player!
  310.     local destName = select(6, GetPlayerInfoByGUID(destGUID));
  311.     if (not destName) then return end -- destination/target is not a player!
  312.  
  313.     -- If found already in the tracking table then the Shaman has applied ES onto a new target
  314.     local skip;
  315.     if (not tracking[sourceName]) then
  316.         tracking[sourceName] = setmetatable({}, trackerPrototype);
  317.     else
  318.         skip = true;
  319.     end
  320.    
  321.     local self = tracking[sourceName];
  322.     self.sourceGUID = self.sourceGUID or sourceGUID;
  323.     self.destGUID = destGUID;
  324.     if (not skip) then self:SetTrackingInfo(true); end
  325. end
  326.  
  327. --[[
  328.     Scripts and Event:
  329. --]]
  330. local function Window_OnUpdate(self)   
  331.     local tbl = ScanRaid();
  332.     for sourceGUID, destGUID in pairs(tbl) do
  333.         CreateTracker(sourceGUID, destGUID);
  334.     end
  335.     if ( IsInRaid() or IsInGroup() ) then
  336.         C_Timer.After(1, function() Window_OnUpdate(self) end);
  337.     end
  338. end
  339.  
  340. window:SetScript("OnEvent", function(self, event, _, subevent, _, sourceGUID, sourceName, _, _, destGUID, destName, _, _, ...) 
  341.     if ( event == "COMBAT_LOG_EVENT_UNFILTERED" ) then
  342.         if (subevent == "SPELL_AURA_REFRESH" or subevent == "SPELL_AURA_APPLIED") then
  343.             if ( not ( UnitInRaid(sourceName) or UnitInParty(sourceName) ) ) then return end
  344.             if ( not ( UnitInRaid(destName) or UnitInParty(destName) ) ) then return end       
  345.                    
  346.             local spellName = GetSpellInfo((...));
  347.             if (spellName == ES) then
  348.                 CreateTracker(sourceGUID, destGUID);
  349.             end        
  350.         elseif(subevent == "SPELL_AURA_REMOVED") then
  351.             if (tracking[sourceName]) then
  352.                 tracking[sourceName]:SetTrackingInfo();
  353.             end
  354.         end
  355.     elseif ( IsInRaid() or IsInGroup() ) then
  356.         Window_OnUpdate(window);
  357.     else
  358.         window:Hide();
  359.     end
  360. end)
  361. window:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
  362. window:RegisterEvent("GROUP_ROSTER_UPDATE");
  363. window:RegisterEvent("GROUP_JOINED");

XML file just to remove as much confusion as possible:
xml Code:
  1. <Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
  2. ..\FrameXML\UI.xsd">
  3.     <Script file="EarthShieldTracker.lua"/>
  4.     <StatusBar name="TrackingBarTemplate" virtual="true" hidden="true" inherits="CastingBarFrameTemplate">
  5.         <Size x="0" y="20"/>
  6.         <Layers>
  7.             <Layer level="ARTWORK">
  8.                 <FontString parentKey="dest" justifyH="LEFT" inherits="GameFontHighlight">
  9.                     <Anchors>
  10.                         <Anchor point="LEFT" relativePoint="LEFT" x="5" y="0" />
  11.                     </Anchors>
  12.                 </FontString>
  13.                 <FontString parentKey="source" justifyH="RIGHT" inherits="GameFontHighlight">
  14.                     <Anchors>
  15.                         <Anchor point="RIGHT" relativePoint="RIGHT" x="-5" y="0" />
  16.                     </Anchors>
  17.                 </FontString>
  18.             </Layer>
  19.         </Layers>
  20.         <Scripts>
  21.             <OnLoad />
  22.             <OnShow />
  23.             <OnEvent />
  24.             <OnUpdate />
  25.         </Scripts>
  26.     </StatusBar>
  27. </Ui>

Let me know if I have uploaded too much code and should change something.

AddOn description:
It sets up bars to track Earth Shield on Raid Members and shows which Shaman applied the buff on the destination. It shows status bars with the stack number and counts down when stacks are lost.

Image:


The AddOn can also be downloaded here: http://www.wowinterface.com/download...ldTracker.html

Last edited by Mayron : 01-07-15 at 08:18 PM.
  Reply With Quote
01-03-15, 07:09 PM   #2
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
Originally Posted by Mayron View Post
When you login, a frame's "GROUP_ROSTER_UPDATE" event is triggered which sets up the OnUpdate script but it does not run until much much later and no clue why. I also tried using many other events which definitely do trigger as well, such as "PLAYER_ENTERING_WORLD".
An OnUpdate script will not run if the frame is not shown.
  Reply With Quote
01-04-15, 05:41 AM   #3
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 275
I came to this conclusion while half a sleep in bed haha, yeah the Blizzard frame I chose to inherit is hidden by default which made me confused. I guess I should have slept on it rather than getting frustrated.

Thank you

I think I will rewrite most of what I have done because I do not like how the OnUpdate script runs as well as how bars need to be re-positioned. A better approach would be to keep the bars where they are and swap the data around and refreshing their appearance.
  Reply With Quote
01-04-15, 03:41 PM   #4
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 275
I've updated the code and the script definitely works but my main bug is that I get bars overlapping but I might be able to fix this with time. Definitely seems more challenging than I thought it would be.

EDIT: Also going to replace OnUpdate scripts with C_Timer

Last edited by Mayron : 01-05-15 at 02:20 PM.
  Reply With Quote
01-07-15, 08:14 PM   #5
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 275
I rewrote all the code and I am now using C_Timer which works great (rather than OnUpdate).

The AddOn works very well except when multiple Resto Shamans are casting ES at once then there are issues with bars being created more than once so 2 bars displaying the same info and I cannot fix this.

Been trying to fix it but no clue how and not sure how to make an experimental testing/debugging function so I've been entering LFR a ton and its sucking the life out of me. If anyone wanted to help with this project they are more than welcome but I think I give up hehe.

Thanks anyway!
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Bugs with AddOn - Lua Scripts


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