WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Learning, need help (https://www.wowinterface.com/forums/showthread.php?t=54818)

_Max_Cavalera_ 11-11-16 02:42 PM

Learning, need help
 
Hey guys,

I started a little addon for educational purposes. I'm trying to do everything I can for my self because that's the way I usually learn best, but I just hit a strange wall.

My addon is working as intended... when it works.... because some times it just ignores the events that start it up so... it just doesn't work until one of the other events hits.

I'm sure i'm making a huge mistake somewhere, as I said, I'm just learning, it's my first ever try.

My intention isn't really for anyone to fix it, just to give me some hints on what I'm doing wrong so I can learn :)

Thank you

edit:. Oh btw, in case you use the addon to see how it looks, that's not at all how it's gonna look, I just made 2 lines of info available to test out if it was "printing" what I wanted xD This is a VERY early stage addon.

edit:. I completely forgot to say that the event that seems to be some times ignored is only the initial one, in my case the PLAYER_LOGIN.
I also tried PLAYER_ENTERING_WORLD and have the same problem, some times it works, some times it doesn't.

I've seen it happen on the PLAYER_SPECIALIZATION_CHANGED but it's VERY rare, but it's probably from the same reason.

The rest of them seem to work well every time, every time I use an artifact power item I look at the addon and it seems to always update instantly to that event.

MunkDev 11-11-16 03:38 PM

Lua Code:
  1. function frame:m4xEventHandler(self, event, ...)
  2.     if ( HasArtifactEquipped() ) then
  3.         frame:m4xArtifact_PopulateValues()
  4.     end
  5. end

Lua Code:
  1. function frame:m4xEventHandler(event, ...)
  2.     if ( HasArtifactEquipped() ) then
  3.         self:m4xArtifact_PopulateValues()
  4.     end
  5. end

Colon syntax in a function implies the first argument is self. This probably won't fix your problem though as nothing in that function actually uses the event information.

SDPhantom 11-11-16 04:10 PM

Most ArtifactUI data isn't available when PLAYER_LOGIN fires. As the ArtifactUI is built off the old socketing system, you need to attempt to socket an artifact using SocketInventoryItem() or SocketContainerItem() and wait for ARTIFACT_UPDATE to fire before you can get meaningful data.

You might want to get an error display addon like Swatter or BugSack as the Blizzard default error handler is terrible at reporting errors on login.

PS: Since 7.0, textures don't support setting them to a solid color via :SetTexture() anymore. This functionality was split off into a new function :SetColorTexture().

_Max_Cavalera_ 11-11-16 04:12 PM

I completely forgot to say that the event that seems to be some times ignored is only the initial one, in my case the PLAYER_LOGIN.
I also tried PLAYER_ENTERING_WORLD and have the same problem, some times it works, some times it doesn't.

I've seen it happen on the PLAYER_SPECIALIZATION_CHANGED but it's VERY rare, but it's probably from the same reason.

The rest of them seem to work well every time, every time I use an artifact power item I look at the addon and it seems to always update instantly to that event.

I'm gonna add this to the original post.

Quote:

Originally Posted by SDPhantom (Post 320768)
Most ArtifactUI data isn't available when PLAYER_LOGIN fires. As the ArtifactUI is built off the old socketing system, you need to attempt to socket an artifact using SocketInventoryItem() or SocketContainerItem() and wait for ARTIFACT_UPDATE to fire before you can get meaningful data.

You might want to get an error display addon like Swatter or BugSack as the Blizzard default error handler is terrible at reporting errors on login.

PS: Since 7.0, textures don't support setting them to a solid color via :SetTexture() anymore. This functionality was split off into a new function :SetColorTexture().

I am using bugsack, isn't reporting anything from that.

The strange thing about that PLAYER_LOGIN not having the ArtifactUI data is that some times it works, so how is it working those times?

Thanks for the tip on the texture thing, i'm going to check it out.

SDPhantom 11-11-16 04:25 PM

When you reload the UI, the game doesn't clear the data it caches from server inquiries, so that data would remain available through the reload. The only time this data is cleared is when you log out.

Digging through Blizzard's ArtifactWatchBar, all you really need to watch for are UNIT_INVENTORY_CHANGED (for UnitID player) and ARTIFACT_XP_UPDATE if you're just sticking with the XP system. If you're going to look into scanning traits, you'll run into the situation I explained previously.



Note artifacts can be unequipped and spec changes don't directly contribute to data being updated about the newly equipped artifact. This is still the change in player's inventory. To illustrate this, here's an example of what goes on when you switch specs.
Code:

Client: Switch Specs
Server: Switching Now (Client displays progress bar)
Server: Switching Complete
Client fires PLAYER_SPECIALIZATION_CHANGED
Client: Equip New Artifact
Server: Item Equipped
Client fires UNIT_INVENTORY_CHANGED (UnitID = player)


_Max_Cavalera_ 11-11-16 05:09 PM

I'm not counting reloads as a login, when I said it some times works I mean actual logins, going out to char select and going in again.

As for the specialization change, initially I was using UNIT_INVENTORY_CHANGED, but since that happens every time you loot something or anything changes in the inventory, in my mind it wasn't really an efficient way of doing it. It pretty much causes a memory leak, no? Not that it would ever be a problem per se, we're talking a few kb but still...

And like I said, PLAYER_SPECIALIZATION_CHANGED seems to work 99% of the time, which is why it is as strange as the PLAYER_LOGIN working some times and others not.

My mindset to having chosen PLAYER_SPECIALIZATION_CHANGED in the first place was, I'm never really going to unequip my artifact, it's the only weapon now. I also can't equip any other artifact without changing the specialization and changing it automatically changes to the correct artifact. So it seemed like the perfect solution.

SDPhantom 11-11-16 10:39 PM

UNIT_INVENTORY_CHANGED fires when you equip, swap, or unequip an item. BAG_UPDATE is the event that fires when you loot, drop, or move items around in your bags. The idea of an event firing causing a memory leak is a misconception. Code not properly releasing objects that they allocated memory for is what causes memory leaks. Lua uses a garbage collection system that runs once in a while to clear out data that's no longer in use. The problem with your data usage wasn't how frequent the code was run, but recreating expensive data structures when you didn't need to. Furthermore, with UNIT_* functions, you can use :RegisterUnitEvent() instead of :RegisterEvent() to only respond to the event firing for a specific unit rather than everyone in your party/raid. For example, this is the bare minimum for your code to function properly and efficiently.

Lua Code:
  1. local KnowledgeMultipliers={
  2.     25, 50, 90, 140, 200,
  3.     275, 375, 500, 650, 850,
  4.     1100, 1400, 1775, 2250, 2850,
  5.     3600, 4550, 5700, 7200, 9000,
  6.     11300, 14200, 17800, 22300, 24900,
  7. };
  8.  
  9. local MainFrame=CreateFrame("Frame","M4xArtifactFrame",UIParent);
  10. local ExpText=MainFrame:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall");
  11. ExpText:SetPoint("TOPLEFT",UIParent,"TOPLEFT");--   This is the object we're anchoring everything to
  12. ExpText:SetText("Initializing...");
  13.  
  14. --  This will twist your thinking, but you can set the points of your parents to a child as long as you don't create any circular references, as in points depending on each other.
  15. MainFrame:SetAllPoints(ExpText);
  16.  
  17. local Background=MainFrame:CreateTexture(nil,"BACKGROUND");
  18. Background:SetColorTexture(0,0,0,0.2);
  19. Background:SetAllPoints(ExpText);
  20.  
  21. MainFrame:RegisterUnitEvent("UNIT_INVENTORY_CHANGED","player");
  22. MainFrame:RegisterEvent("ARTIFACT_XP_UPDATE");
  23. MainFrame:SetScript("OnEvent",function(self,event,...)
  24.     local itemid,_,_,_,exp,lvl=C_ArtifactUI.GetEquippedArtifactInfo()
  25.     if itemid then
  26.         local available,tonext=0,C_ArtifactUI.GetCostForPointAtRank(lvl);
  27.         local _,knowledge=GetCurrencyInfo(1171);
  28.         while exp>=tonext do exp,lvl,available,tonext=exp-tonext,lvl+1,available+1,C_ArtifactUI.GetCostForPointAtRank(lvl+1); end
  29.  
  30. --      %5$d and %6$d force grab integers from the 5th and 6th parameters respectively
  31.         ExpText:SetFormattedText("AP |cff00ff00%d/%d (%.0f%%)|r"..(available>0 and " (+%d)" or "").."\nAK |cff00ff00%5$d (+%6$d%%)|r",exp,tonext,100*exp/tonext,available,knowledge,KnowledgeMultipliers[knowledge]);
  32.     end
  33.  
  34.     MainFrame:SetShown(itemid and true or false);-- Typecast to boolean
  35. end);

_Max_Cavalera_ 11-12-16 07:46 AM

Quote:

Originally Posted by SDPhantom (Post 320774)
UNIT_INVENTORY_CHANGED fires when you equip, swap, or unequip an item. BAG_UPDATE is the event that fires when you loot, drop, or move items around in your bags.

Well... I completely messed that one up, was probably using BAG_UPDATE, no wonder it wasn't a good choice :p

You've been a huge help, I've learned a lot so far, thank you for that.

I'm going to study the code and apply those ideas maybe later today if I have time. In any case, when I have it working I'll post an update here.

Once again thank you for your help :D

edit:. Apparently I WAS using UNIT_INVENTORY_CHANGED and it does fire when you loot stuff :(
I even made a video to show you.

edit:. I know I'm a bother xD But I'm just like this, I NEEEED to know why stuff does one thing and then another and how it works.

So I did some testing, and apparently, the game fires some events completely randomly or whatever and that's why PLAYER_SPECIALIZATION_CHANGED some times works and other times doesn't.

Here's a pic of my test



I chose those events because they seemed to be the most important when changing spec.
As you can see, it worked when PLAYER_SPECIALIZATION_CHANGED was the last event to fire (or should I say, when it happens AFTER UNIT_INVENTORY_CHANGED), which doesn't happen always. In my test it did like 8 out of 10 times.

The spellcast succeeded ones are, one from finishing changing the spec, the other one is from the passive hidden effect that changes the artifact weapon automatically. I have no idea why some times events for the same thing fire twice, because even though two of those spellcast events aren't the same as they're doing different things, the other ones are "re-fires" of one of those two

I did exactly the same thing every time, didn't move or anything, had the spec window open, choose spec, clicked apply, let it finish, choose another spec, clicked apply, let it finish, etc etc etc... all specs have their artifact weapon in the bag available.

Lombra 11-12-16 12:16 PM

Didn't really read the thread thoroughly, but use PLAYER_EQUIPMENT_CHANGED if you want to track equipment changes.

SDPhantom 11-12-16 01:50 PM

UNIT_INVENTORY_CHANGED seems to be bugged and firing when you loot an item you don't already have or split a stack. PLAYER_EQUIPMENT_CHANGED would be interchangeable and doesn't appear to be affected by this bug.

Phanx 11-13-16 10:39 AM

Quote:

Originally Posted by SDPhantom (Post 320774)
Lua Code:
  1. MainFrame:SetShown(itemid and true or false);-- Typecast to boolean

Not specifically related to anything, but another, less verbose way to do that would be:

Lua Code:
  1. MainFrame:SetShown(not not itemid); -- Typecast to boolean

SDPhantom 11-13-16 12:21 PM

Quote:

Originally Posted by Phanx (Post 320804)
Lua Code:
  1. MainFrame:SetShown(not not itemid); -- Typecast to boolean

I saw this in Blizzard code recently and thought it harder to follow. :p

Seerah 11-13-16 12:50 PM

Quote:

Originally Posted by SDPhantom (Post 320806)
I saw this in Blizzard code recently and thought it harder to follow. :p

I think it is, too. And it doesn't save on anything other than space.

Lombra 11-13-16 02:04 PM

Unless it for some reason can be false; "itemid ~= nil".

_Max_Cavalera_ 11-13-16 09:34 PM

I haven't had any time today to implement anything but I wanted to stop by to thank you guys for the help and keeping the discussion alive :)

btw, by my limited tests, PLAYER_EQUIPMENT_CHANGED seems to be the best solution so far for my "problem"

SDPhantom 11-14-16 01:09 PM

Quote:

Originally Posted by Lombra (Post 320808)
Unless it for some reason can be false; "itemid ~= nil".

The API is consistent in returning nil if doesn't have any data. Checking for nil specifically is overboard in this case and is a waste of CPU resources on an extra operation or two.

Lombra 11-14-16 02:14 PM

Quote:

Originally Posted by SDPhantom (Post 320826)
The API is consistent in returning nil if doesn't have any data. Checking for nil specifically is overboard in this case and is a waste of CPU resources on an extra operation or two.

Sure, but since we were talking readability I prefer that expression personally.

Seerah 11-14-16 05:05 PM

But nil isn't the same as false.

SDPhantom 11-15-16 12:19 AM

Again, differentiating false in this situation is overkill. The API never returns false in place of a value that isn't normally boolean. As a matter of fact, API that returns data often doesn't provide any returns when there isn't any available, not even nil. However, when Lua attempts to assign no value to a variable, it ends up assigning nil anyway.

_Max_Cavalera_ 11-15-16 09:17 AM

ok, i've been reading the code you put up (thanks once again for that), i'm implementing it right now, have a few questions though since I'm doing this to learn, implementing without knowing why or what something does isn't really an option xD

I'll start at the end since people always like to start at the beginning ;)

Lua Code:
  1. MainFrame:SetShown(itemid and true or false);

Can you explain this line to me? I think that it's supposed to be, show frame if itemID exists?! but I don't get how the and true or false works.

Backgrounds... do I really need them? I know I had one, I made it because I was learning from a book and it listed the background as something to use when making a frame but as you know mine wasn't even working and i didn't even notice it because it was already supposed to be almost invisible at 0.2 alpha.
It works without one so I guess there's no problem in not having one? Or can it create problems?

Can you explain why %5$d and %6$d is needed to grab the 5th and 6th parameter when the position of those in the string are the 5th and 6th? Shouldn't they already pick up the right ones with just %d? Or is it \n that breaks that?
By the way, I didn't know I could do that so, thanks ;)

EDIT:. ok I understand this one now I think, it's because of the (available>0 and " (+%d)" or ""), they MIGHT or MIGHT NOT be the 5th and 6th... damn I'm dumb...

And finally,

Lua Code:
  1. (available>0 and " (+%d)" or "")

You have this on the formatted text, I guess it's supposed to be if available > 0 do the first one else do the other one?!?! So it's like an IF statement to use inside strings?

How does it work? From what you have I think it's (if condition and then or else) but the fact that the if condition is followed by and seems so strange to me xD

Lombra 11-15-16 12:27 PM

Quote:

Originally Posted by Seerah (Post 320834)
But nil isn't the same as false.

Of course, I mentioned that condition in my post. My expression only works as expected if item ID never is false.

Quote:

Originally Posted by SDPhantom (Post 320836)
Again, differentiating false in this situation is overkill. The API never returns false in place of a value that isn't normally boolean. As a matter of fact, API that returns data often doesn't provide any returns when there isn't any available, not even nil. However, when Lua attempts to assign no value to a variable, it ends up assigning nil anyway.

I already said I was talking from a readability perspective. I think mine reads better, that's it. However I went ahead and timed it and mine and Phanx expressions are actually faster when the value is truthy. Mine is a bit slower when the value is nil.

Quote:

Originally Posted by _Max_Cavalera_ (Post 320843)
Lua Code:
  1. MainFrame:SetShown(itemid and true or false);

Can you explain this line to me? I think that it's supposed to be, show frame if itemID exists?! but I don't get how the and true or false works.

In this case it works like so; the expression "itemid and true or false" evaluates to true if itemid is truthy (any value except nil and false), otherwise evaluates to false. It's essentially a way to write the following in a single expression:
Code:

if itemid then
        return true
else
        return false
end

It doesn't have to return true or false, either. Your example with the two different strings works exactly the same.

You can read more about it here:
http://www.lua.org/pil/3.3.html

_Max_Cavalera_ 11-15-16 01:40 PM

I still find it very strange like that. I get it, but just find it strange.

Definitely find the not not itemid (that was talked about a few posts before) easier to understand in that case for some reason.

Thank you for the explanation and the link :)

ok, I implemented the code after doing minor changes that were needed for my personal taste.

Lua Code:
  1. local akMulti = {
  2.     0,
  3.     25, 50, 90, 140, 200,
  4.     275, 375, 500, 650, 850,
  5.     1100, 1400, 1775, 2250, 2850,
  6.     3600, 4550, 5700, 7200, 9000,
  7.     11300, 14200, 17800, 22300, 24900
  8. };
  9.  
  10. local frame = CreateFrame("Frame", "m4xArtifactFrame", UIParent);
  11. local text = frame:CreateFontString(nil, "ARTWORK");
  12. text:SetFont("Fonts\\FRIZQT__.TTF", 15, "OUTLINE");
  13. text:SetJustifyH("LEFT");
  14. text:SetTextColor(1, 0.82, 0);
  15. text:SetPoint("TOPLEFT", UIParent, "TOPLEFT");
  16.  
  17. text:SetText("Initializing...");
  18.  
  19. frame:SetAllPoints(text);
  20.  
  21. frame:RegisterEvent("PLAYER_ENTERING_WORLD");
  22. frame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  23. frame:RegisterEvent("ARTIFACT_CLOSE");
  24. frame:RegisterEvent("ARTIFACT_RESPEC_PROMPT");
  25. frame:RegisterEvent("ARTIFACT_XP_UPDATE");
  26.  
  27. frame:SetScript("OnEvent", function(self, event, ...)
  28.     local itemID, _, itemName, itemIcon, totalXP, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  29.    
  30.     if itemID then
  31.         local pointsFree, xpToNextPoint = 0, C_ArtifactUI.GetCostForPointAtRank(pointsSpent);
  32.         local _, akLevel = GetCurrencyInfo(1171);
  33.        
  34.         while totalXP >= xpToNextPoint do
  35.             totalXP, pointsSpent, pointsFree, xpToNextPoint = totalXP - xpToNextPoint, pointsSpent + 1, pointsFree + 1, C_ArtifactUI.GetCostForPointAtRank(pointsSpent + 1);
  36.         end
  37.         text:SetFormattedText("AP |cff00ff00%d/%d (%.1f%%)|r" .. (pointsFree > 0 and " (+%d)" or "") .. "\nAK |cff00ff00%5$d (+%6$d%%)|r", totalXP, xpToNextPoint, 100 * totalXP / xpToNextPoint, pointsFree, akLevel, akMulti[akLevel + 1]);
  38.     end
  39.  
  40.     frame:SetShown(itemID and true or false);
  41. end);

Changes were:
  • Obviously the variable names, I kinda have my own preference in naming scheme but that's irrelevant
  • The font was changed because I looked at all the game font options from the XML files and none were exactly what I needed, unfortunately...
  • Added 0 to the multiplier table to temporarily fix a problem I was getting where I was getting a nil value from multiplier[level] when the knowledge level was 0, and I'm going to talk about this after
  • Because of adding the 0 to the table I had to add +1 to the level in multiplier[level] obviously
  • Have some variables there not being used but i'm going to use them after :)

So, that nil because of the knowledge level 0. I totally get it why that is happening, it was trying to get multiplier[0] which doesn't exist since it starts at 1... BUT... on my original code I was doing the same mistake by accident, and it never gave me an error, not only that but it was actually working correctly, giving me on the output knowledge level 0 (+0%)... that's kinda strange, no?

SDPhantom 11-15-16 02:20 PM

Quote:

Originally Posted by _Max_Cavalera_ (Post 320843)
Lua Code:
  1. MainFrame:SetShown(itemid and true or false);
Can you explain this line to me? I think that it's supposed to be, show frame if itemID exists?! but I don't get how the and true or false works.

This is basically a hack to implement inline conditions in Lua since there isn't a native method provided. frame:SetShown() either shows or hides a frame depending on the boolean value you pass to it. It shows the frame on true and hides it on false. The expression passed to it is the inline condition in question. The idea is if you have an expression A and B or C, it returns B if A is a true condition or C if not. There is an inherent bug in this expression though. If B evaluates to a false condition, C will always be returned no matter what A is. Keep this in mind if you decide to play around with it.


Quote:

Originally Posted by _Max_Cavalera_ (Post 320843)
Backgrounds... do I really need them? I know I had one, I made it because I was learning from a book and it listed the background as something to use when making a frame but as you know mine wasn't even working and i didn't even notice it because it was already supposed to be almost invisible at 0.2 alpha.
It works without one so I guess there's no problem in not having one? Or can it create problems?

The background is just a visual element to make the text more readable, you can change or remove it if you wish.



Quote:

Originally Posted by _Max_Cavalera_ (Post 320843)
Lua Code:
  1. (available>0 and " (+%d)" or "")
You have this on the formatted text, I guess it's supposed to be if available > 0 do the first one else do the other one?!?! So it's like an IF statement to use inside strings?

This is another example of the inline conditional explained earlier. If available>0 is true then it inserts the format specifier for it.


Quote:

Originally Posted by _Max_Cavalera_ (Post 320843)
Can you explain why %5$d and %6$d is needed to grab the 5th and 6th parameter when the position of those in the string are the 5th and 6th? Shouldn't they already pick up the right ones with just %d? Or is it \n that breaks that?
By the way, I didn't know I could do that so, thanks ;)

This is a modification to string.format() made by the WoW API and isn't normal for Lua itself. I needed to explain the inline condition used here before explaining this so you get the idea. The inline condition decided whether or not to insert the 4th arg into the string, making the identifiers for the 5th and 6th args prone to shifting. Manually selecting which arg the identifier references fixes this problem.


Quote:

Originally Posted by _Max_Cavalera_ (Post 320850)
So, that nil because of the knowledge level 0. I totally get it why that is happening, it was trying to get multiplier[0] which doesn't exist since it starts at 1... BUT... on my original code I was doing the same mistake by accident, and it never gave me an error, not only that but it was actually working correctly, giving me on the output knowledge level 0 (+0%)... that's kinda strange, no?

An alternate fix would've been to define 0 at key 0 in your table. This is done by specifying key = value in a line of your table. If you use square brackets, it evaluates the key as an expression rather than trying to register it as a string. Using this, [0] = 0 writes 0 at index 0 in the table.
Lua Code:
  1. local akMulti = {
  2.     [0] = 0,
  3.     25, 50, 90, 140, 200,
  4.     275, 375, 500, 650, 850,
  5.     1100, 1400, 1775, 2250, 2850,
  6.     3600, 4550, 5700, 7200, 9000,
  7.     11300, 14200, 17800, 22300, 24900
  8. };

You can use another inline conditional to hide the AK display if you don't have any.
Lua Code:
  1. text:SetFormattedText("AP |cff00ff00%d/%d (%.1f%%)|r" .. (pointsFree > 0 and " (+%d)" or "") .. (akLevel > 0 and "\nAK |cff00ff00%5$d (+%d%%)|r" or ""), totalXP, xpToNextPoint, 100 * totalXP / xpToNextPoint, pointsFree, akLevel, akMulti[akLevel]);
I also trimmed %6$d since the previous identifier would make it select the 6th arg anyway. This is an undocumented feature, so many of the internal processes are unknown. I initially found Blizzard using it in the localization strings and poked around with it in my own testing.



Another alternative would be to implement a fallback by using akMulti[akLevel] or 0. The or operator will make sure if the table returns nil, it'll use 0 instead.

_Max_Cavalera_ 11-15-16 03:21 PM

Damn, you guys are too awesome... I'm learning more these last few days than I did these last few weeks xD

The %5$d stuff I eventually understood the logic, I edited my post, but thanks for validating what I thought was happening :)

Those alternative fixes are great, my fix was really just temporary anyway, I was testing it and had to do something to just check if the values were fine, was the first thing that came to me xD

But why would my original code not give me any problems on that same variable when I'm not using any kind of fix to make it 0 when nil?!?!

SDPhantom 11-15-16 04:31 PM

I'm guessing it's something new involving Blizzard's formatting code, but without extensive testing to validate it, I'd avoid depending on it.

_Max_Cavalera_ 11-15-16 04:58 PM

Yeah, for sure, if it's not 100% correct I'm not gonna use it for sure.

Torhal 11-15-16 07:19 PM

Quote:

Originally Posted by SDPhantom (Post 320851)
This is a modification to string.format() made by the WoW API and isn't normal for Lua itself. I needed to explain the inline condition used here before explaining this so you get the idea. The inline condition decided whether or not to insert the 4th arg into the string, making the identifiers for the 5th and 6th args prone to shifting. Manually selecting which arg the identifier references fixes this problem.

This is actually an upstream port from Lua 4.0 to WoW's version of Lua 5.1 - no idea why it was removed from Lua after 4.0, but it's obviously useful for localization purposes.

_Max_Cavalera_ 11-15-16 07:45 PM

So, I'm already adding functionality, made a tooltip so that when I add more info I won't get it 100% of the time on the screen.

Lua Code:
  1. local function OnEnter(self)
  2.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
  3.     GameTooltip:SetText("Artifact Weapon name going here");
  4.     GameTooltip:AddLine("Move Artifact Knowledge info here and only keep one line on main frame");
  5.     GameTooltip:Show();
  6. end
  7.  
  8. local function OnLeave(self)
  9.     GameTooltip:Hide();
  10. end
  11.  
  12. frame:SetScript("OnEnter", OnEnter);
  13. frame:SetScript("OnLeave", OnLeave);

It's working as it is, easy enough. Now I wonder, since I need to use variables I already have inside the frame:SetScript("OnEvent", function(self, event, ...), should I put the tooltip code inside? Return the variables from that one so I can use them outside? Or just remake new ones outside?

What would be the correct way of doing it? The proper, efficient code way xD

I think I should return them and put it outside just because adding more and more stuff to that frame:SetScript("OnEvent", function(self, event, ...) isn't probably a good idea? But on the other hand, the info that goes in the tooltip needs to be up to date with those Events.

I donno... that's why I'm learning ;)

Lombra 11-15-16 08:56 PM

Getting that info shouldn't be terribly CPU intensive (ie not at all), so it's fine to just get it anew when you show the tooltip. You don't wanna put the SetScript("OnEnter") inside the OnEvent, if that's what you meant. You could, but that will create a new function every time you set the script which, while equally insignificant of a performance hit, is just not something you want to get into the habit of doing.

Storing the values collected in the event handler and reusing them in the tooltip is certainly not bad. Personally I would prefer not to clutter the main scope with upvalues for such a minuscule gain, but others probably would, and strictly speaking it should be the most efficient approach. If you do choose to just get the values again in the tooltip, you might want to consider making a function for it. Writing the same code more than once (except for very small amounts) should be avoided if at all possible.

_Max_Cavalera_ 11-15-16 09:46 PM

So, just to see if I got it.

Putting it inside the OnEvent isn't a good idea like I imagined.

Returning the values from the OnEvent so I can use them outside on another function (which was what I thought to be the best way), you're saying you wouldn't do?

Doing the same code since it's not much doesn't seem bad but since some info needs to update on Events wouldn't that mean I would need to do like 90% of the OnEvent again? I would end up with OnEnter inside the OnEvent anyway?! Or maybe I'm not seeing it right, it's like 4 AM, I'll look at it tomorrow :)

Thanks for the input.

Edit:. Yeah..... As soon as I lay down in bed I was like "wtf did I say"

The tooltip doesn't need the events to update the info, it updates at least every time I put the mouse over the frame, right?

I'm going to sleep, this is lack of it xD

SDPhantom 11-16-16 04:47 AM

You can try this. Be sure to add frame:EnableMouse(true) up where the frame is being set up to have it respond to mouse events.

Lua Code:
  1. frame:SetScript("OnEvent", function(self, event, ...)
  2.     local itemID, _, itemName, itemIcon, totalXP, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  3.  
  4.     if itemID then
  5.         local pointsFree, xpToNextPoint = 0, C_ArtifactUI.GetCostForPointAtRank(pointsSpent);
  6.  
  7.         while totalXP >= xpToNextPoint do
  8.             totalXP, pointsSpent, pointsFree, xpToNextPoint = totalXP - xpToNextPoint, pointsSpent + 1, pointsFree + 1, C_ArtifactUI.GetCostForPointAtRank(pointsSpent + 1);
  9.         end
  10.         text:SetFormattedText("AP |cff00ff00%d/%d (%.1f%%)|r" .. (pointsFree > 0 and " (+%d)" or ""), totalXP, xpToNextPoint, 100 * totalXP / xpToNextPoint, pointsFree);
  11.     end
  12.  
  13.     frame:SetShown(itemID and true or false);
  14. end);
  15.  
  16. frame:SetScript("OnEnter", function(self)
  17.     local _, _, itemName = C_ArtifactUI.GetEquippedArtifactInfo()
  18.     local _, akLevel = GetCurrencyInfo(1171);
  19.  
  20.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
  21.     GameTooltip:SetText(itemName);
  22.     if akLevel > 0 then
  23.         GameTooltip:AddLine(string.format("Artifact Knowledge |cff00ff00%d (+%d%%)|r",akLevel,akMulti[akLevel] or 0));
  24.     end
  25.     GameTooltip:Show();
  26. end);
  27.  
  28. frame:SetScript("OnLeave", function(self) GameTooltip:Hide(); end);

_Max_Cavalera_ 11-16-16 02:24 PM

After my "epiphany" yesterday when going to bed, I got to think that Lombra was most probably right when saying the best way in this case would be to just do those 1 or 2 lines again since it was just that pretty much.

I did this before I saw your post.

Lua Code:
  1. local akMulti = {
  2.     25, 50, 90, 140, 200,
  3.     275, 375, 500, 650, 850,
  4.     1100, 1400, 1775, 2250, 2850,
  5.     3600, 4550, 5700, 7200, 9000,
  6.     11300, 14200, 17800, 22300, 24900
  7. };
  8.  
  9. local frame = CreateFrame("Frame", "m4xArtifactFrame", UIParent);
  10. local text = frame:CreateFontString(nil, "ARTWORK");
  11. text:SetFont("Fonts\\FRIZQT__.TTF", 15, "OUTLINE");
  12. text:SetJustifyH("LEFT");
  13. text:SetTextColor(1, 0.82, 0);
  14. text:SetPoint("TOPLEFT", UIParent, "TOPLEFT");
  15.  
  16. text:SetText("Initializing...");
  17.  
  18. frame:SetAllPoints(text);
  19.  
  20. frame:RegisterEvent("PLAYER_ENTERING_WORLD");
  21. frame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  22. frame:RegisterEvent("ARTIFACT_CLOSE");
  23. frame:RegisterEvent("ARTIFACT_RESPEC_PROMPT");
  24. frame:RegisterEvent("ARTIFACT_XP_UPDATE");
  25.  
  26. frame:SetScript("OnEvent", function(self, event, ...)
  27.     local itemID, _, _, _, totalXP, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  28.    
  29.     if itemID then
  30.         local pointsFree, xpToNextPoint = 0, C_ArtifactUI.GetCostForPointAtRank(pointsSpent);
  31.        
  32.         while totalXP >= xpToNextPoint do
  33.             totalXP, pointsSpent, pointsFree, xpToNextPoint = totalXP - xpToNextPoint, pointsSpent + 1, pointsFree + 1, C_ArtifactUI.GetCostForPointAtRank(pointsSpent + 1);
  34.         end
  35.  
  36.         text:SetFormattedText("AP |cff00ff00%d/%d (%.1f%%)|r" .. (pointsFree > 0 and " (+%d)" or ""), totalXP, xpToNextPoint, 100 * totalXP / xpToNextPoint, pointsFree);
  37.  
  38.     end
  39.  
  40.     frame:SetShown(itemID and true or false);
  41. end);
  42.  
  43. local function OnEnter(self)
  44.     local _, akLevel = GetCurrencyInfo(1171);
  45.     local _, _, itemName, itemIcon, _, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  46.     local _, effectiveStat = UnitStat("player", 3);
  47.  
  48.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
  49.     GameTooltip:SetText(itemName);
  50.     GameTooltip:AddLine(" ");
  51.     GameTooltip:AddLine(string.format("Artifact Knowledge Level: |cff00ff00%d (+%d%%)|r", akLevel, akMulti[akLevel] or 0));
  52.     GameTooltip:AddLine(string.format("Next Artifact Knowledge: |cff00ff00%d (+%d%%)|r", akLevel + 1, akMulti[akLevel + 1]));
  53.     GameTooltip:AddLine(" ");
  54.     GameTooltip:AddLine(string.format("Stamina from points: |cff00ff00+%g%% (+%d)|r", pointsSpent * 0.75, effectiveStat - (effectiveStat / ((pointsSpent * 0.75 / 100) + 1))));
  55.     GameTooltip:Show();
  56. end
  57.  
  58. local function OnLeave(self)
  59.     GameTooltip:Hide();
  60. end
  61.  
  62. frame:SetScript("OnEnter", OnEnter);
  63. frame:SetScript("OnLeave", OnLeave);

You think it's not as "correct" as your example?

It's working perfectly as it is.


This is with mouseover obviously, mouse just doesn't show on the screenshot.

Don't have that frame:EnableMouse(true), you think it's just enabled by default now or something?

Lombra 11-16-16 03:17 PM

Quote:

Originally Posted by _Max_Cavalera_ (Post 320878)
Don't have that frame:EnableMouse(true), you think it's just enabled by default now or something?

You only need it to respond to mouse clicks, I think.

_Max_Cavalera_ 11-16-16 04:52 PM

Quote:

Originally Posted by Lombra (Post 320881)
You only need it to respond to mouse clicks, I think.

oh, ok
Then I guess I will need it since I want to use mouse clicks after :)

SDPhantom 11-16-16 07:06 PM

You might want to take note that the stat bonuses from spending points in your artifact is different for each one. Some scale differently and some boost a completely different stat.

_Max_Cavalera_ 11-16-16 08:59 PM

Quote:

Originally Posted by SDPhantom (Post 320885)
You might want to take note that the stat bonuses from spending points in your artifact is different for each one. Some scale differently and some boost a completely different stat.

I have 5 110's and never seen anything other than Stamina :/ Have to check it more carefully.
What some have that I've noticed is, on healing and tank spec for example they get bonus damage on top of the stamina.

edit:. Just checked a bunch of chars and multiple spec weapons on each and the 0.75% stamina per point seems to be consistent. Even though between those chars and specs, the artifact weapon development of each was different, so it was a good test group so to say.

Then the tank specs seem to have on top of that, 0.5% damage per point, and healers 1% damage per point, but those I don't know if I had different because it was tank and healer or because the healer was further ahead in artifact weapon development. But I would bet it's also static 0.5 for tanks and 1 for healers.

edit:. Just found this on WoWHead

Trait Perks

The amount of total trait ranks you have purchased increases the amount of Stamina +/- Damage Dealt (up to point #34 on your Artifact tree).
Healer and Tank Specs gain 0.75% Stamina + 1% Damage Dealt for every trait unlocked (25.5% increased Stamina and 34% increased Damage Dealt for a fully maxed Artifact Weapon).
Discipline Sacerdotes, as a hybrid DPS/Healer gains 0.75% Stamina and 0.5% Damage Dealt for every trait unlocked (25.5% increased Stamina and 17% increased Damage Dealt for a fully maxed Artifact Weapon).
DPS Specs gain 0.75% Stamina for every trait unlocked (25.5% increased Stamina for a fully maxed Artifact Weapon).

They say tanks also get 1% like healers but my tanks had 0.5 :/

Phanx 11-17-16 11:39 PM

Quote:

Originally Posted by Seerah (Post 320807)
I think it is, too. And it doesn't save on anything other than space.

Not quite true -- it's applicable to other languages that don't have a ternary syntax (or at least a sensible one) like Python. Also, even for languages that do have some kind of (sensible) ternary syntax, "not not X" or "!!X" looks and works pretty much the same way in every language where it works at all, meaning you have to shift fewer gears when you move between a Lua project and a project in another language. Even if I found "not not X" harder to follow at first glance than "X and true or false", I'd still favor "not not X" for that reason.

Plus, when I see "not not X" there's only one possible intention -- to typecast to a boolean. When I see "X and A or B" there are a lot of possibilities, and I find it's more mental effort to read. :p

SDPhantom 11-18-16 01:22 AM

Lua doesn't have ternary syntax either. It's two binary logic operators taking advantage of shortcuts Lua takes in evaluating them. It's literally a hack to implement.

When I quickly scan through code to try to understand what it's doing, my mind has a hard time registering not not and only sees one of them, which throws in a bit of confusion requiring a couple more looks over finally catch it.

Feel free to use it in your own code, but I reserve the right to respectfully disagree. :rolleyes:

Seerah 11-18-16 12:48 PM

Quote:

Originally Posted by Phanx (Post 320916)
Not quite true -- it's applicable to other languages...

I don't think that counts. :p :)

Phanx 11-18-16 11:47 PM

Quote:

Originally Posted by Seerah (Post 320923)
I don't think that counts. :p :)

Depends on what you're counting towards/against, I guess.

_Max_Cavalera_ 11-20-16 08:28 AM

Been full of work lately.
I'm gonna try to add some more functionality to the addon, click to open the artifactUI, slash commands, unlock/lock to move the frame, maybe a right click menu to change the info shown on the main frame.
I'm gonna do these over time and post the code here as I do for review and notes from you guys, if you can obviously :)

I do have a question about something that I've been trying.

One thing C_ArtifactUI.GetEquippedArtifactInfo() returns is (I think) the icon from the artifact, I've tried returning it and it gives me a number and not the usual string with the icon path, I'm assuming that's the icon id?!?!
How can I get the actual icon from that? Can't find how to do it anywhere.

I'm also wondering your opinion on the way I did the tooltip, is directly making a function for OnEnter not as good or efficient as doing it on a SetScript like SDPhantom did on his example solution?

Thank you guys for all your help, when I first came here I actually wasn't expecting so much help, this is a great community.

Lombra 11-20-16 09:12 AM

Yes, those are something like texture IDs. You can use them directly with SetTexture, though. Do you actually need the texture path for something?

The SetScript procedure is the same. The only difference is in your version you may reuse the OnEnter function elsewhere if you like. That's a good idea if you need to use the same script for more than one frame, but in this case I would set it directly.

_Max_Cavalera_ 11-20-16 08:17 PM

I don't know how it works, but usually with the texture path I can just put the path inside a SetText and get the icon next to the text, right? Pretty sure I've seen people do that, but can't really find it right now :/

SDPhantom 11-20-16 11:10 PM

You can type in the number in place of the path and it'll work. For example, this shows the icon for the Marksman Hunter artifact.
Code:

|T1137849:0|t
See UI escape sequences - Textures.

_Max_Cavalera_ 11-21-16 05:37 AM

ok I see, I was missing the "escape sequence", I actually thought I would have to do something like that, like I do with colors using |c |r, but I didn't know how that's called so searching for it was pretty difficult to get any results.
Thanks for the link, covers a bunch of those and now I know what to look for ;)

edit:. I'm currently trying to make a click work and can't make it work for the love of me, is it just not possible to have a click work on a Frame frame? Do I actually need to make a Button frame for it to work?

I've tried with and without frame:EnableMouse(true), with and without frame:RegisterForClicks("AnyUp"), and all combinations of both (with one without the other, with both).
Tried that with function OnClick(self) and with frame:SetScript("OnClick", function(self) nothing seems to work.

On the tests where I used frame:RegisterForClicks("AnyUp") I get
Quote:

attempt to call method 'RegisterForClicks' (a nil value)
and on frame:SetScript("OnClick", function(self) I get
Quote:

m4xArtifactFrame doesn't have a "OnClick" script
Doing this with a Button seems to work but if it's possible to do with just the Frame it would be better since it would be one less thing to create and have on the screen (even if "invisible").

Lombra 11-21-16 11:45 AM

You can just make your frame a button instead. No need to make an extra frame. Buttons support everything that frames do. Or you can use the "OnMouseUp" frame script, which gives you practically the same behavior as "OnClick". In that case, you also need EnableMouse and RegisterForClicks, I think. For buttons those come by default.

SDPhantom 11-21-16 01:03 PM

There shouldn't be any reason not to make your frame as a button if you want to respond to clicks. The advantages of buttons are that they innately support clicking and you can set textures to illustrate the various button states (up, down, highlight, and disabled). You can make a frame do this, but it's a lot of work to get it to do so and honestly isn't worth the effort.

UI objects in WoW form a hierarchy in which more specialized objects inherit methods of the generic ones. For example, Buttons inherit everything a Frame has and adds more features while a CheckButton inherits from Buttons (and Frames indirectly) and adds its own stuff on top of that.

There's an illustration of this here: Widget API

_Max_Cavalera_ 11-21-16 01:59 PM

ok, yeah that seems like a good idea, it's not like I'm using the Frame specifically for anything other than to define a space/anchor for everything else, right? So making it a button would allow me to use the OnClick and continue to do everything I'm already using it for.

edit:. ok..... i'm stupid..... damn....

After trying a million things before and after Lombra's post and not getting any results I realized it was actually working, what wasn't working was what I made it do, I made it open the artifact weapon window and that wasn't working, but the click was being registered and working, I just added a chat message to test (yes I should have done this in the first place xD) and the chat message shows.

edit:. ok, making the frame a button like Lombra first suggested and then doing

Lua Code:
  1. frame:SetScript("OnMouseUp", function(self, button)
  2.     if button == "LeftButton" then
  3.         ArtifactFrame_LoadUI()
  4.         if (ArtifactFrame:IsVisible()) then
  5.             HideUIPanel(ArtifactFrame)
  6.         else
  7.             SocketInventoryItem(16);
  8.         end
  9.     end
  10. end);

Seems to be enough, didn't even need the registerforclicks, tries with and without, seems to be the same.

Here's my full code so far.

Lua Code:
  1. local akMulti = {
  2.     25, 50, 90, 140, 200,
  3.     275, 375, 500, 650, 850,
  4.     1100, 1400, 1775, 2250, 2850,
  5.     3600, 4550, 5700, 7200, 9000,
  6.     11300, 14200, 17800, 22300, 24900
  7. };
  8.  
  9. local frame = CreateFrame("Button", "m4xArtifactFrame", UIParent);
  10. local text = frame:CreateFontString(nil, "ARTWORK");
  11. text:SetFont("Fonts\\FRIZQT__.TTF", 15, "OUTLINE");
  12. text:SetJustifyH("LEFT");
  13. text:SetTextColor(1, 0.82, 0);
  14. text:SetPoint("TOPLEFT", UIParent, "TOPLEFT");
  15.  
  16. frame:SetAllPoints(text);
  17.  
  18. frame:RegisterEvent("PLAYER_LOGIN");
  19. frame:RegisterEvent("PLAYER_ENTERING_WORLD");
  20. frame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  21. frame:RegisterEvent("ARTIFACT_CLOSE");
  22. frame:RegisterEvent("ARTIFACT_RESPEC_PROMPT");
  23. frame:RegisterEvent("ARTIFACT_XP_UPDATE");
  24.  
  25. frame:SetScript("OnEvent", function(self, event, ...)
  26.     local itemID, _, _, _, totalXP, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  27.    
  28.     if itemID then
  29.         local pointsFree, xpToNextPoint = 0, C_ArtifactUI.GetCostForPointAtRank(pointsSpent);
  30.        
  31.         while totalXP >= xpToNextPoint do
  32.             totalXP, pointsSpent, pointsFree, xpToNextPoint = totalXP - xpToNextPoint, pointsSpent + 1, pointsFree + 1, C_ArtifactUI.GetCostForPointAtRank(pointsSpent + 1);
  33.         end
  34.  
  35.         text:SetFormattedText("AP |cff00ff00%d/%d (%.1f%%)|r" .. (pointsFree > 0 and " (+%d)" or ""), totalXP, xpToNextPoint, 100 * totalXP / xpToNextPoint, pointsFree);
  36.     end
  37.  
  38.     frame:SetShown(itemID and true or false);
  39. end);
  40.  
  41. local function OnEnter(self)
  42.     local _, akLevel = GetCurrencyInfo(1171);
  43.     local _, _, itemName, itemIcon, _, pointsSpent = C_ArtifactUI.GetEquippedArtifactInfo()
  44.     local _, effectiveStat = UnitStat("player", 3);
  45.  
  46.     GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
  47.     GameTooltip:SetText(string.format("|T%d:0|t %s", itemIcon, itemName));
  48.     GameTooltip:AddLine(" ");
  49.     GameTooltip:AddLine(string.format("Artifact Knowledge Level: |cff00ff00%d (+%d%%)|r", akLevel, akMulti[akLevel] or 0));
  50.     GameTooltip:AddLine(string.format("Next Artifact Knowledge: |cff00ff00%d (+%d%%)|r", akLevel + 1, akMulti[akLevel + 1]));
  51.     GameTooltip:AddLine(" ");
  52.     GameTooltip:AddLine(string.format("Stamina from points: |cff00ff00+%g%% (+%d)|r", pointsSpent * 0.75, effectiveStat - (effectiveStat / ((pointsSpent * 0.75 / 100) + 1))));
  53.     GameTooltip:Show();
  54. end
  55.  
  56. local function OnLeave(self)
  57.     GameTooltip:Hide();
  58. end
  59.  
  60. frame:SetScript("OnMouseUp", function(self, button)
  61.     if button == "LeftButton" then
  62.         if ArtifactFrame and ArtifactFrame:IsVisible() then
  63.             HideUIPanel(ArtifactFrame);
  64.         else
  65.             SocketInventoryItem(16);
  66.         end
  67.     end
  68. end);
  69.  
  70. frame:SetScript("OnEnter", OnEnter);
  71. frame:SetScript("OnLeave", OnLeave);

I'm still trying out events for the initial load, because I have a few times that the text wasn't becoming visible with PLAYER_ENTERING_WORLD, we talked about this, I think it was SDPhantom that said the addon didn't have the artifact info available at that point.
I donno, is there any other events that happen once at start bu after that one? The PLAYER_LOGIN one is probably not doing anything tbh.
I just need to get this to load at start every time and for some reason, some times it doesn't, it IS rare but it happens.

Fizzlemizz 11-21-16 09:14 PM

You haven't registered the UNIT_INVENTORY_CHANGED event.
Code:

frame:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player")
You can get rid of:

PLAYER_LOGIN
PLAYER_EQUIPMENT_CHANGED
ARTIFACT_CLOSE
ARTIFACT_RESPEC_PROMPT

_Max_Cavalera_ 11-22-16 06:15 AM

Quote:

Originally Posted by Fizzlemizz (Post 320949)
You haven't registered the UNIT_INVENTORY_CHANGED event.
Code:

frame:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player")
You can get rid of:

PLAYER_LOGIN
PLAYER_EQUIPMENT_CHANGED
ARTIFACT_CLOSE
ARTIFACT_RESPEC_PROMPT

We already talked about that.

Fizzlemizz 11-22-16 10:22 AM

Indeed, doesn't mean you don't need the event. If you think it's overkill, you can always unregister it after it has done the job.

_Max_Cavalera_ 11-22-16 05:24 PM

Yeah, i guess...

I'm gonna keep trying to find another way, it's not like I have a deadline on this or anything, it's just a learning tool.

Fizzlemizz 11-22-16 06:16 PM

If you're going for a "real world" addon example, any method will also have to take into consideration the possibility of starting the game with a non artifact weapon and at some later stage equiping one, unless the artifact system is loaded when any weapon is equiped.

_Max_Cavalera_ 11-22-16 08:08 PM

Doesn't PLAYER_EQUIPMENT_CHANGED already take care of that?

I use it to update when we change specialization (change weapon) and it works fine for that at least.

As it was talked about, the problem for me with UNIT_INVENTORY_CHANGED is that is fires way too much and I don't think that's a good implementation. I know it won't really do anything harmful in an addon this size, but since I'm doing this to learn I don't think learning bad ways to do something is a good idea.

That's why I started to look for events that were more specific to what this addon does, so that the addon only updates when it's actually relevant.

I know I probably have too much now but that's just because I'm still testing them, I probably have that part different every day xD

Fizzlemizz 11-22-16 09:31 PM

The vagaries of the WoW login system.

Getting into the game:

PLAYER_EQUIPMENT_CHANGED appears to fire only when you login from the launcher but not on logout/login or /reload. It is also when the artifact information is available.

UNIT_INVENTORY_CHANGED fires after PLAYER_EQUIPMENT_CHANGED and also when loging out/in.

I'm currently testing with both events registerd and unregistering UNIT_INVENTORY_CHANGED after the first time it fires, this "should" cover login in with an artifact weapon equiped.

_Max_Cavalera_ 11-23-16 06:07 AM

If you checked the posts where we talked about it you probably know this.

Initially I started by using UNIT_INVENTORY_CHANGED, then i realized my mega tiny addon went from the initial 4kb memory to like 30kb (not instantly, I wasn't paying attention to it), I thought it was strange so I checked what was going on and it was UNIT_INVENTORY_CHANGED that was firing every time I mined and since I was farming mines, every mine it would go up and up and up.
Sure, eventually the garbage collection kicks in and down to 4 it goes, and yes, on something this size that's irrelevant but to me using something that fires for everything and their cousin instead of specific events that are in some way connected to what the addon does makes it bad practice.

This is probably Blizzard's mistake though, from everything said to me here and what I've read online, UNIT_INVENTORY_CHANGED shouldn't be firing for something like looting.

But yes, i think what you said about using it at start and unregister it is most probably the best solution, at least unless I find something I had no idea about (which wouldn't be strange xD).

SDPhantom 11-23-16 06:41 AM

The frequency in which code is run doesn't automatically make it bad at memory management. It just makes it more important to watch what you do in your code. First of all is limiting dynamic creation of functions and tables in code that runs repeatedly. These are the most memory-expensive objects in Lua and their misuse can cause your memory usage to skyrocket.

To a lesser extent, but nonetheless does contribute to memory issues are string operations. Strings as a data type are handled internally in a unique way in which strings containing the same sequence of bytes share the same memory space. This means 100 strings of "something" takes up the same space as a few of them. However, when you start concatenating numbers and other data to them, they suddenly have different contents and are reallocated to a new space in memory.

For example:
Lua Code:
  1. for i=1,100 local str="Something"; end-- Generates only one string in memory containing "Something"
  2. for i=1,100 local str="Something"..i; end-- Generates 100 strings in memory containing "Something1" through "Something100"

_Max_Cavalera_ 11-28-16 02:21 PM

So, I've been trying to find out how to do something and after a few days of trying in my free time I'm going crazy.

I have this array of tables (I think that's how you call it), and I'm trying to change a specific value in it, this is the example

Character in this example is Trololo-Moonglade

Lua Code:
  1. addonDB= {
  2.     ["chars"] = {
  3.         ["Moonglade Trololo"] = {
  4.             ["profile"] = "profilename",
  5.         },
  6.     },
  7. };

So, to change the profile name my understanding is that I can do

Lua Code:
  1. addonDB["chars"]["Moonglade Trololo"]["profile"] = "anotherprofilename"

Right? (maybe it's not right and that's the problem right there xD)

And following the same logic, to create a new one I could do

Lua Code:
  1. local name, _ = UnitName("player");
  2. local realm = GetRealmName();
  3.  
  4. addonDB["chars"][realm .. " " .. name]["profile"] = "newprofilename"

So, what am I doing wrong? I get an error saying "attempt to index field '?' (a nil value)" on the "addonDB[......." line

Lombra 11-28-16 02:48 PM

Well, your 'C' in chars is capitalised differently. I don't think it's possible to make out any other errors from the information given.

_Max_Cavalera_ 11-28-16 03:32 PM

Quote:

Originally Posted by Lombra (Post 321054)
Well, your 'C' in chars is capitalised differently. I don't think it's possible to make out any other errors from the information given.

lol xD i edited it, but that's not the problem, that error was just here when i wrote it again, on the actual addon it's fine.
Also had an error on "profile", wrote "profiles", but again, that error isn't present on the code.

The addon doesn't really do anything else, this is literally the entire code.

Lua Code:
  1. local button = CreateFrame("Button", "m4xConfigButton", UIParent, "UIPanelButtonTemplate");
  2. local text = button:CreateFontString(nil, "ARTWORK");
  3.  
  4. text:SetFont("Fonts\\FRIZQT__.TTF", 15, "OUTLINE");
  5. text:SetTextColor(1, 0.82, 0);
  6. text:SetPoint("CENTER");
  7. text:SetText("Create Profile");
  8.  
  9. button:SetFrameStrata("HIGH");
  10. button:SetPoint("CENTER");
  11. button:SetWidth(160);
  12. button:SetHeight(40);
  13.  
  14. button:SetScript("OnClick", function(self)
  15.  
  16. local name, _ = UnitName("player");
  17. local realm = GetRealmName();
  18.  
  19. if not addonDB["chars"][realm .. " " .. name] then
  20. addonDB["chars"][realm .. " " .. name]["profile"] = "default"

Aaaannnd..... maybe I should have the variable name and realm done outside the function?!?!?! I'm going to try that. If that's it I'm going to kill my self.


All times are GMT -6. The time now is 07:03 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI