WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Legion Beta archived threads (https://www.wowinterface.com/forums/forumdisplay.php?f=177)
-   -   Getting artifact perks data (https://www.wowinterface.com/forums/showthread.php?t=53472)

Rainrider 05-20-16 06:10 PM

Getting artifact perks data
 
I would like to get info about which artifact perks are currently active. So far I have the following code:

lua Code:
  1. local powers = C_ArtifactUI.GetPowers()
  2.  
  3. for i = 1, #powers do
  4.     local spellID, _, currentRank = C_ArtifactUI.GetPowerInfo(powers[i])
  5.  
  6.     if currentRank > 0 then
  7.         local name = GetSpellInfo(spellID)
  8.         -- do stuff
  9.     end
  10. end

However this only works when the ArtifactUI is open and I can't figure out how to open it programmatically. Would appreciate some help on that.

myrroddin 05-20-16 06:14 PM

As a temporary workaround, you can cache your results. Update your cache any time the Artifact UI is open, or appropriate events fire.

Rainrider 05-20-16 07:06 PM

I need the data for a spell dependency list. Like for marksmanship hunters Windburst applies Deadeye (or Vulnurable) when Mark of the Windrunner is selected. However both IsSpellKnown and IsPlayerSpell return false for Mark of the Windrunner and there is no spell added to the spell book. I can't rely on the user opening the artifact UI but I haven't found another way to get that information.

dssd 05-20-16 07:22 PM

You can open the artifact UI by requesting to socket the artifact through a call like SocketContainerItem or SocketInventoryItem. At that point you should be able to request artifact data.

Rainrider 05-20-16 07:57 PM

This is an interesting idea!

On second thought, it is probably not nice to open the artifact UI without a user interaction as it could close other UI panels. And I'll have to rescan in case the user changes their spec and equips another artifact. I really hope they'll make the whole C_ArtifactUI API usable without the artifact UI being visible.

syncrow 05-20-16 08:03 PM

Lua Code:
  1. function CollectPerkInfo()
  2.     if HasArtifactEquipped() then
  3.         local forceHide;
  4.  
  5.         -- opens (equipped) arfifact layout
  6.         if not ArtifactFrame:IsShown() then
  7.             forceHide = true
  8.             SocketInventoryItem(16)
  9.         end
  10.        
  11.         for i, powerID in ipairs(C_ArtifactUI.GetPowers()) do
  12.             local spellID, cost, currentRank, maxRank, bonusRanks, x, y, prereqsMet, isStart, isGoldMedal, isFinal = C_ArtifactUI.GetPowerInfo(powerID)
  13.  
  14.             -- you can now cache the info you want
  15.         end
  16.        
  17.         if ArtifactFrame:IsShown() and forceHide then
  18.             HideUIPanel(ArtifactFrame)
  19.         end
  20.     end
  21. end

Here is an example on how it could be used:

dssd 05-20-16 08:33 PM

Yeah, you can also just suppress the artifact UI from opening at all by doing something like unregistering the artifact open event from UIParent and then re-registering after you're done with your info.

The problem with the artifact api being available all the time is that a player could have up to 4 artifacts (druids), that's why you have to specify which one you want data on by using the socket function.

Simca 05-21-16 03:30 AM

I'm confused, can you not just call LoadAddOn for the load-on-demand Blizzard Addon in question? (Blizzard_ArtifactUI)

Rainrider 05-21-16 06:22 AM

@Simca you can load the addon, but the C_ArtifactUI API returns just nils while the ArtifactFrame is not open. Or I'm too short sighted to get it.

@dssd yes, but only one artifact can be active at a time per design. And the API could provide just that info.

@syncrow HasArtifactEquipped() returns true even if the player has respecced but hasn't changed weapons yet, meaning your code gets potentially wrong information.

syncrow 05-21-16 06:30 AM

Quote:

Originally Posted by Rainrider (Post 315070)
HasArtifactEquipped() returns true even if the player has respecced but hasn't changed weapons yet

You'll change weapon automatically when you respec?! Or am I wrong?

SDPhantom 05-21-16 12:57 PM

Quote:

Originally Posted by Simca (Post 315063)
I'm confused, can you not just call LoadAddOn for the load-on-demand Blizzard Addon in question? (Blizzard_ArtifactUI)

Loading an addon out of context doesn't magicly give access to API data and will often times cause errors.



Quote:

Originally Posted by syncrow (Post 315071)
Quote:

Originally Posted by Rainrider (Post 315070)
HasArtifactEquipped() returns true even if the player has respecced but hasn't changed weapons yet, meaning your code gets potentially wrong information.

You'll change weapon automatically when you respec?! Or am I wrong?

The game tries to swap weapons when you change spec. It'll even unequip your current one if you don't have the artifact for the new spec. Sometimes it bugs out and fails this though.

dssd 05-21-16 01:00 PM

@Simca Almost the opposite of that is what Rainrider wants I believe. When you use socket item that tells C to prepare artifact data for that artifact. When it's ready it fires the "ARTIFACT_UPDATE" event which Blizzard's Lua code looks for. That's how it knows to load the addon if it isn't already and open the UI. I believe Rainrider wants to just have C prepare the data without opening the Lua UI. That's why I recommended unregistering Blizzard's code from "ARTIFACT_UPDATE" before asking C to load the data for an artifact.

@syncrow I believe it leaves it equipped but in an "unusable" state kind of like if an equipped item reaches 0 durability.

Rainrider 05-22-16 12:45 PM

Quote:

Originally Posted by dssd (Post 315093)
[...] When you use socket item that tells C to prepare artifact data for that artifact. When it's ready it fires the "ARTIFACT_UPDATE" event which Blizzard's Lua code looks for. That's how it knows to load the addon if it isn't already and open the UI. I believe Rainrider wants to just have C prepare the data without opening the Lua UI. That's why I recommended unregistering Blizzard's code from "ARTIFACT_UPDATE" before asking C to load the data for an artifact.

@syncrow I believe it leaves it equipped but in an "unusable" state kind of like if an equipped item reaches 0 durability.

Tested with the macro:
lua Code:
  1. /run local u,e,a=UIParent,"ARTIFACT_UPDATE",C_ArtifactUI;u:UnregisterEvent(e);SocketInventoryItem(16);for i,p in ipairs(a.GetPowers()) do print(GetSpellInfo((a.GetPowerInfo(p)))) end;a.Clear();u:RegisterEvent(e)
  1. You have to do C_ArtifactUI.Clear() when ready or else the artifact item remains in a locked state (item is grayed out and Shift+Right Clicking it no longer works)
  2. Once the ArtifactFrame has been opened, this no longer prevents the artifact UI from opening. You have to unregister "ARTIFACT_UPDATE" from ArtifactFrame as well (remember checking for nil here, as the ArtifactFrame exists only after Blizzard_ArtifactUI has been loaded)

You could use GetInventoryItemQuality("player", INVSLOT_MAINHAND) == LE_ITEM_QUALITY_ARTIFACT and GetInventoryItemEquippedUnusable("player", INVSLOT_MAINHAND) to check whether the right artifact is currently equipped.

Also using just SPELLS_CHANGED for tracking changes seems to be enough, at least for my purposes, but I haven't tested this extensively yet.

kokomala 06-12-16 02:23 AM

Quote:

Originally Posted by Rainrider (Post 315070)
@dssd yes, but only one artifact can be active at a time per design. And the API could provide just that info.

You can still view the Artifact Perk UI by shift + right click for any artifact that may be in your bags. The artifact API will use whatever artifact is currently 'open', even if it is in your bags.

Pity the API didn't use specID.

Edit:
As this is something I've needed for my own project, I messed around and wrote a quick libstub library for caching artifact information (including those in your bags). Used some of the code above as a base (credit to your macro Rainrider). Data updates is handled by the library, you only need to call the data functions.

This is my first library (woo!) so code could probably be done better. Let me know if you have any issues with it: http://www.wowinterface.com/download...facts-1.0.html

liquidbase 06-12-16 04:33 PM

Quote:

Originally Posted by kokomala (Post 315698)
You can still view the Artifact Perk UI by shift + right click for any artifact that may be in your bags. The artifact API will use whatever artifact is currently 'open', even if it is in your bags.

Pity the API didn't use specID.

Edit:
As this is something I've needed for my own project, I messed around and wrote a quick libstub library for caching artifact information (including those in your bags). Used some of the code above as a base (credit to your macro Rainrider). Data updates is handled by the library, you only need to call the data functions.

This is my first library (woo!) so code could probably be done better. Let me know if you have any issues with it: http://www.wowinterface.com/download...facts-1.0.html

Nice job ! :)
Will check it out for my ArtifactBar in DuffedUI for the tooltip.

syncrow 06-12-16 05:10 PM

Quote:

Originally Posted by kokomala (Post 315698)
Let me know if you have any issues with it: http://www.wowinterface.com/download...facts-1.0.html

Once "Blizzard_ArtifactUI" is loaded, SocketInventoryItem(16) forces the UI to show the ArtifactFrame.
  • So you should use this gathering method only before the ArtifactUI was loaded
  • Afterwards its better to update your library whenever the ArtifactFrame is shown / updated while shown to avoid closing other frames...

kokomala 06-12-16 07:02 PM

Quote:

Originally Posted by syncrow (Post 315710)
Once "Blizzard_ArtifactUI" is loaded, SocketInventoryItem(16) forces the UI to show the ArtifactFrame.
  • So you should use this gathering method only before the ArtifactUI was loaded
  • Afterwards its better to update your library whenever the ArtifactFrame is shown / updated while shown to avoid closing other frames...

That's basically what I do. I have 3 primary internal functions for gathering. RefreshEquipped(), RefreshBags() handle initial gathering/search functions which has the above check (or similar) and C_ArtifactUI.Clear(). They then call RefreshPowers() function which assumes C_ArtifactUI is populated (it does a small check) and does the actual data population. This is all called during login (PLAYER_ENTERING_WORLD)

During regular gameplay, I call RefreshPowers() and that only occurs during ARTIFACT_UPDATE.

I was originally going to have a force update function, but I don't think that is necessary. Debating on writing a communication portion for sending trait information to other players, however that may be better suited for the addon itself rather than the library.

kokomala 06-13-16 08:19 AM

Small update to the library. Minor optimisations (aka removed the double caching on first load etc), couple of minor changes to the error logic. More importantly added a new public function for number of powers purchased (which is now cached) which saves overhead.

I now class it as feature complete and looks to be working without issue.

Please let me know if you break it. Gathering artifact power to test it during gameplay is rather time consuming :)

Rainrider 06-13-16 01:55 PM

The way you uploaded it, it won't load at all (no ToC file).

You need a way to tell users when data changed. You could use CallbackHandler for this.

Your RefreshEquipped() and RefreshBags() are double dipping as SocketInventoryItem and SocketContainerItem will issue ARTIFACT_UPDATE and your event handler will call RefreshPowers() again.

As long as you call RefreshEquipped() and RefreshBags() only at PLAYER_ENTERING_WORLD (PEW) you could spare the checks for ArtifactFrame. Your first call to SocketInventoryItem will load the ArtifactUI and from then on you actually open and close ArtifactFrame for every artifact in the player's inventory. This is probably not a problem as the user won't have any open UI panels during PEW. If you change this (by adding a forced update), you will have to consider that the ArtifactFrame listens for ARTIFACT_UPDATE as well.

GetPowerPurchased actually returns the number of purchased traits. Maybe GetNumTraitsPurchased would be a better name. Same goes for GetPowers and the like. I know you follow Blizzard's own naming here, but they probably coded that before the UI wording was set in place and didn't care to update the API to reflect that. Also prepending Lib to your addon name would be nice, but this is just my personal taste.

As for features, you could also provide the knowledge level and multiplier as those are only available when the ArtifactFrame is shown. They are shared between artifacts. The API for them is C_ArtifactUI.GetArtifactKnowledgeLevel() and C_ArtifactUI.GetArtifactKnowledgeMultiplier().

kokomala 06-14-16 01:21 AM

Quote:

Originally Posted by Rainrider (Post 315714)
*snip*

Nice feedback. First library I've written, so a small learning curve - but everything helps :)

The library will work fine if it's embedded and your addon is reacting to events to pull data. I can make it standalone enabled and implement CallBackHandler to fire a cache update event, which will make this a little more friendly for UI display updates.

Feature wise, this was more intended towards caching just the traits. However thinking on it, it might be better to simply expand it to cache more of the data provided by C_ArtifactUI API (saves future requests). I'll need to look at the API listing again and see how best to manage what options there are. I don't want the library to take up too much UI time if I can help it. A fair bit of the functions will likely not be needed.

Naming wise was to keep it the somewhat similar to Blizzard's, as this partially turns the library into a cached alias for C_ArtifactUI, which is why I've opted to return information in the same format. I did totally do a goof on PowersPurchased (should have used GetTotalPurchasedRanks) :P

Quote:

Your RefreshEquipped() and RefreshBags() are double dipping as SocketInventoryItem and SocketContainerItem will issue ARTIFACT_UPDATE and your event handler will call RefreshPowers() again.
This was the case on the first release and should be fixed in the 1.1 version. I basically shifted f:RegisterEvent('ARTIFACT_UPDATE') into the PEW event code, and then unregistered the PEW event to avoid rescanning whenever you hit a load screen.

--
One thing I've been debating on is if I should add bank inventory scanning - I'm leaning towards yes, regardless of how unlikely it is for an unscanned artifact to be equipped and used prior to caching that specific artifact. However this is entirely dependant if I can code it such that it doesn't intrude on the user - part of the issue is you can't 'socket' an item whilst it's in the bank.

Thanks again. Will keep the update discussion in this thread as I progress :)

edit:
Quote:

As long as you call RefreshEquipped() and RefreshBags() only at PLAYER_ENTERING_WORLD (PEW) you could spare the checks for ArtifactFrame.
Initially I was going to keep this in, but after playing around with bag scanning after closing the bank it's far simpler to simply register/unregister both the UI and my controller for ARTIFACT_UPDATE during the scan. This avoids multiple triggers and it's fast enough.

The only issue is that if you have the artifact frame open, then close the bank - the artifact frame will close due to the data caching. I'd rather not have the library do this, but there's no other way to cache a new artifact. Something to muse over.


All times are GMT -6. The time now is 04:32 PM.

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