LibGroupInSpecT
Summary
A small library which keeps track of group members and keeps an up-to-date cache of their specialization and talents.
It's similar to the old LibGroupTalents/LibTalentQuery and the LibRaidInspect libraries, but unlike the former it's actually working on 7.0, and unlike the latter it works properly in Battlegrounds. Additionally it has the feature where it communicates spec/talent updates to other LibGroupInSpecT users. This is an important point as of the writing of this there is no way to detect when another player re-specs/talents.
This library started out as a part of RaidChecklist as replacement for LibGroupTalents, but has since been split off into its own project as its usefulness increases the more widespread it is.
To make use of this library you'll need to also have the usual LibStub and LibCallbackHandler libs.
For a real usage example, take a look at the RaidChecklist project.
Events
These events can be registered for using the regular CallbackHandler ways.
Reference
event | args |
---|---|
"GroupInSpecT_Update" | guid, unit, info |
"GroupInSpecT_Remove" | guid |
"GroupInSpecT_InspectReady" | guid, unit |
Description
-
"GroupInSpecT_Update"
- Fires when info is ready or has been modified.
-
"GroupInSpecT_Remove"
- Fires when a member leaves the group.
-
"GroupInSpecT_InspectReady"
- Fires during INSPECT_READY so that clients can perform supplemental inspection handling (as of r78).
Example
local LGIST = LibStub:GetLibrary("LibGroupInSpecT-1.1") LGIST.RegisterCallback(addonObject, "GroupInSpecT_Remove", "UnitRemoved") function addonObject:UnitRemoved(event, guid) -- unit with guid removed end
API
Functions for external use:
-
lib:Rescan (guid or nil)
- Force a fresh inspection of all group members. As of r76 it accepts an optional guid parameter, to rescan only a particular GUID rather than all group members.
-
lib:QueuedInspections ()
- Returns an array of GUIDs of outstanding inspects.
-
lib:StaleInspections ()
- Returns an array of GUIDs for which the data has been deemed stale and is awaiting an update (no action required, the refresh happens internally).
-
lib:GetCachedInfo (guid)
- Returns the cached info for the given GUID, if available, nil otherwise. Information is cached for current group members only.
-
lib:GuidToUnit (guid)
- Returns the unit id for the given GUID, provided said GUID represents a current group member, else nil.
info table structure
The fields of the table passed as an argument for "GroupInSpecT_Update" callback or returned by one of the API functions (eg. :GetCachedInfo(guid) ). A list of all the global specialization IDs is available here.
Note: Not all fields may be available at all times due to the Blizz API not returning the info at that point. Incremental updates will be sent, so coding with the possibility of nil in mind is highly advised.
Info structure
.guid .name .realm .race .race_localized .class .class_localized .class_id .gender -- 2 = male, 3 = female .global_spec_id .spec_index .spec_name_localized .spec_description .spec_icon .spec_background .spec_role .spec_role_detailed -- "tank", "melee", "ranged" or "healer" (introduced in 1.0.2) .spec_group -- active spec group (1/2/nil), introduced in 1.1 .talents = { [<talent_id>] = { -- Note: Since 1.1 this is a talent_id, not a spell_id .talent_id -- Introduced in 1.1. This replaces the old 1.0.x .idx entry .tier .column .name_localized .icon .spell_id } ... }
.pvp_talents = {
[<talent_id>] = {
.talent_id
.name_localized
.icon
.spell_id
}
...
} .lku -- last known unit id
Usage
Typical usage example.
.pkgmeta
Libs/LibGroupInSpecT-1.1: svn://svn.wowace.com/wow/libgroupinspect/mainline/trunk
.toc
## X-Embeds: LibGroupInSpecT-1.1 ## OptionalDeps: LibGroupInSpecT-1.1 #@no-lib-strip@ Libs\LibStub\LibStub.lua Libs\CallbackHandler-1.0\CallbackHandler-1.0.lua Libs\LibGroupInSpecT-1.1\LibGroupInSpecT-1.1.lua #@end-no-lib-strip@
alternatively embeds.xml (referenced in .toc)
<ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> <!--@no-lib-strip@--> <script file="Libs\LibStub\LibStub.lua"/> <include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/> <include file="Libs\LibGroupInSpecT-1.1\lib.xml"/> <!--@end-no-lib-strip@--> </ui>
.lua
local LGIST=LibStub:GetLibrary("LibGroupInSpecT-1.1") LGIST.RegisterCallback(addonObject, "GroupInSpecT_Update", "UpdateHandler") LGIST.Registercallback(addonObject, "GroupInSpecT_Remove", "RemoveHandler") function addonObject:UpdateHandler(event, guid, unit, info) if info.class and info.class == "DEATHKNIGHT" and info.spec_role and info.spec_role == "TANK" then print(UnitName(unit).." is now "..info.spec_name_localized) -- info.name may also be available end end function addonObject:RemoveHandler(event, guid) -- guid no longer a group member end local info = LGIST:GetCachedInfo(guid) local hasFocusingShot = info and next(info.talents) and info.talents[21729] -- focusing shot talent_id
<sub>Main page formatting by Dridzt. Much obliged!</sub>
this caused huge stutters for me every time I exited combat - I don't really need this I think, so I just got rid of it - but maybe worth looking into
a hope for update
can you update to 9.0.5?? THANKS
any chance to update to 9.01? ty dev.
Any plan of updating this lib for Legion?
If yes, are you planing on having Artifact talent data available?
Is it possible to have this addon cache a list of items as well? I am trying to make a loot council addon which prints a list of eligible raid members and the item they currently have equipped in that slot.
This needs release tagging. It's not being pushed to curse client.
Take a look at LibSpecRoster here on WowAce, and see how they deal with the spell ID of the talent. Isn't that what is trying to be done here via the tooltip scanning method? Is there a reason to go with one method vs. the other?
Also, in answer to someone's question about differences between the two libraries, and since I was trying to figure that out myself, I posted what I saw after quick, cursory looks at them both. Given the quick look and lack of experience with either, and in general, I would be interested in feedback from those who've had more experience. I don't want to steer myself or others wrong :)
When this has hit its first release, you'd probably want to give it its forum thread here:
http://forums.wowace.com/forumdisplay.php?f=48 (Libraries section)
The Summary part of the project page, maybe the current info table and a link to the project page for further details should be sufficient :-)
@oscarucb: As Dridzt said, the 'sender' argument is unfortunately the unqualified character name (i.e. without realm information), so it cannot be reliably used to get the UUID from.
@Dridzt: I'll have a look at thew new version after work tonight, or tomorrow, with a view of getting this stuff into mainline sooner rather than later.
@oscarucb
Sender is a name not unitid afaik, I'm not sure it always resolves to a guid if for example the sender is in an instance and you're not, or half across the world.
Not sure and not very easy to test atm (for me).
In any case I'm almost done with the new alpha, and transmitting the guid doesn't remotely push the message length near the limit.
Edit: r27 cloned is in.
Seeing as I've already sunk several hours in this overall, I'm giving it a rest, any improvements or changes be my guest :-p
- unitguid (need this or no way to assign the transmitted info to a unit)
Wait, why is that? The CHAT_MSG_ADDON event already provides a sender argument that is sent with the message envelope, so isn't this field always equal to UnitGUID(sender)? Sending it explicitly should be redundant..
Sorry to be picky, just trying to help us come up with the best possible library.
The argument about pulling in extra libraries could be used about everything tbh, but libraries only get loaded once, don't think a few extra kb of disk space is an issue at the benefit of being lazy
It's not an issue of disk space, it's a matter of favoring laziness for the library CLIENT rather than the library WRITER. As an addon author, I dislike using a library that has a bunch of external dependencies and requires me to also suck in a bunch of additional libraries I don't need before the library can do its job. It means additional work for the addon writer to adopt your library and do the packaging correctly (and additional opportunities to get it wrong), and also additional places where version incompatibilities can arise and cause problems. Eg if the API for libgroupinspect changes in some version (or some version-specific bug arises), the addon writer is the direct client of that interface and can ensure he's embedding the working version and using the right call or workaround for the right version. If the API for libcompress were to change (or some version-specific bug arises), the addon writer knows nothing about the calls to that lib or what specific version he should be embedding in order to make libgroupinspect work.
Speaking of versioning issues, it may be wise to include a (single-digit) comm format version number in the addon comm, in case a future version of libgroupinspect needs to expand or change the format of that comm. Receivers should ignore messages with version numbers higher than what they know how to parse.
A typical full infotable compressed is around 1337 bytes.
Apart from the comedy value of getting a Leet number on my first test, I think I'll take your advice and commit a version at the clone with a custom serializer sending the minimum necessary data and building the full table with API + local lookups upon receipt :-)
@oscarucb
The minimum comms would need (speaking about r25 data structure)
- unitguid (need this or no way to assign the transmitted info to a unit)
- global_spec_id
- glyph_spell_id_1
- ...
- glyph_spell_id_6
- talent_spell_id_1
- ...
- talent_spell_id_6
With the caveat emptor that missing data is "easily synthesized by the library on the receiver" as you mentioned it's certainly a valid implementation; light on the comms but still full on the info the library user can get.
The argument about pulling in extra libraries could be used about everything tbh, but libraries only get loaded once, don't think a few extra kb of disk space is an issue at the benefit of being lazy :-)
My comparison was not with this proposed implementation (which I haven't seen yet).
Was with the mainline custom serializer that has at least 'some' overhead
I'll post back with some metrics for a full info table sent in a bit and look at committing a version with a custom serializer as you propose and no libs. (options are good to have).
Sending the entire info structure seems wasteful ...I deliberately opted against them as the actual info that had to be transmitted was fairly minimal (most of it can be synthesized on the receiver end).
I think I agree with Anyia here - there's no reason the library should be sending things across addon comms that can be easily synthesized by the library on the receiver. If I understand correctly, the sending library only has to send 13 numbers (global_spec_id, 6 glyph spellids, 6 talent idx 1..3) to completely describe a character, and everything else can be re-constructed using tables or queries on the reciever. Given the range of talent indexes, all six talents could easily be represented in 32 bits, so generously assuming 32 bits for the spec_id and 32 bits for each glyph spellid, that's 32 bytes of data total. I find it difficult to believe that libcompress could do anything close to that with a serialized table containing several long strings. 32 bytes should never require fragmentation or re-assembly, and can accomplish everything using a single SendAddonMessage without sucking in a bunch of additional libraries (which is MUCH nicer from the client perspective). Even if it means a few extra lines of code in the library, I think the savings in comm bandwidth and sub-library requirements is worthwhile.
EDIT: even if you represent all 13 numbers as comma-delimited textual numbers (where each number is up to 7 digits in length), thats still under 100 characters, which is well under the 254 character limit for a single message.
r25 of the clone has the fix for talent caching and spell_id as key for both talents/glyphs.
@Anyia3
@ talent/glyphs having spell_id as key.
No reason not to.
@ sending the entire structure, hitting message length limit.
Generally speaking oscarucb convinced me that code that would have to be duplicated in some addon using the library, makes more sense to be in the library itself for convenience to addon authors.
That means that basically all info returned from the api should/can be stored (static memory is really no big deal and it's not much to begin with) as that means in many cases a quick local table lookup vs calling functions.
The benefit of acecomm/serializer/compress is three-fold
- Message limit is handled automatically, acecomm automatically sends a message multipart if it exceeds message limit and ensures it is received and assembled in the correct order.
- You can feed a table directly to the serializer and get a table back at the other end automatically. No need to provide your own serialization and de-serialization.
- I'm pretty sure you'll find that the length of the actual message transmitted with the new structure (texture paths and all) using the lib combo with compress is comparable if not shorter than the message transmitted with the previous implementation, libcompress does a pretty good job with string data.
Overall, it's just simpler: here feed this table to the comm -> get it on the other side no fuss no muss.
@ talent_idx_to_spell_id: Ooops! :-/
That was just me being stupid, I will fix in a moment (and switch the indexes around to spell_id for both talents/glyphs)
So apparently you don't get automatically subscribed to updates on your own project. Live and learn...
.
I've had a look at Dridzt's clone, and overall I like it. I'd totally forgotten about the GameTooltip being usable in that manner!
A few questions/counter-proposals before I consider merging this into mainline though:
Also:
For any other users or developers that might stumble upon this discussion and wouldn't readily check tickets, there's an implementation of what we've been discussing at a cloned repository here:
http://www.wowace.com/addons/libgroupinspect/repositories/experimental/
Despite the 'experimental' tag, it's pretty stable afaik.
In no way recommended for use in released addons,
until we know if Anyia3 approves of the changes and would merge into the mainline.
If someone wants to help test it though go right ahead.