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. |
Lua Code:
Lua Code:
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. |
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 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:
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. |
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 |
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. |
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:
|
Quote:
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. |
Didn't really read the thread thoroughly, but use PLAYER_EQUIPMENT_CHANGED if you want to track equipment changes.
|
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.
|
Quote:
Lua Code:
|
Quote:
|
Quote:
|
Unless it for some reason can be false; "itemid ~= nil".
|
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" |
Quote:
|
Quote:
|
But nil isn't the same as false.
|
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.
|
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:
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:
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 |
Quote:
Quote:
Quote:
Code:
if itemid then You can read more about it here: http://www.lua.org/pil/3.3.html |
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:
Changes were:
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? |
Quote:
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:
The background is just a visual element to make the text more readable, you can change or remove it if you wish. Quote:
This is another example of the inline conditional explained earlier. If available>0 is true then it inserts the format specifier for it. Quote:
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:
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. |
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?!?! |
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.
|
Yeah, for sure, if it's not 100% correct I'm not gonna use it for sure.
|
Quote:
|
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:
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 ;) |
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. |
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 |
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:
|
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:
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? |
Quote:
|
Quote:
Then I guess I will need it since I want to use mouse clicks after :) |
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.
|
Quote:
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 :/ |
Quote:
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 |
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: |
Quote:
|
Quote:
|
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. |
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. |
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 :/
|
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 |
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:
Quote:
|
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.
|
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 |
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:
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:
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. |
You haven't registered the UNIT_INVENTORY_CHANGED event.
Code:
frame:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player") PLAYER_LOGIN PLAYER_EQUIPMENT_CHANGED ARTIFACT_CLOSE ARTIFACT_RESPEC_PROMPT |
Quote:
|
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.
|
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. |
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.
|
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 |
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. |
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). |
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:
|
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:
So, to change the profile name my understanding is that I can do Lua Code:
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:
So, what am I doing wrong? I get an error saying "attempt to index field '?' (a nil value)" on the "addonDB[......." line |
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.
|
Quote:
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:
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