WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Wish List (https://www.wowinterface.com/forums/forumdisplay.php?f=15)
-   -   Faction from GetPlayerInfoByGUID() (https://www.wowinterface.com/forums/showthread.php?t=44151)

SDPhantom 09-04-12 11:28 AM

Faction from GetPlayerInfoByGUID()
 
It would be nice to have faction as a return from GetPlayerInfoByGUID(). Currently, lack of this information hinders the default language set support for addons that add custom languages. For now, this specifically applies to Pandaren since both factions share the same racial language.

myrroddin 09-04-12 07:58 PM

http://wowprogramming.com/docs/api/UnitFactionGroup

Converting between GUID and unit is up to you.

Phanx 09-05-12 02:13 AM

If you're using GetPlayerInfoByGUID, it's probably because you're dealing with people who are talking in chat, or doing something else where no UnitID is available.

If a UnitID was available, there'd be no reason to use GetPlayerInfoByGUID, because all of the information it provides -- class, race, gender, name, server -- is available through other, more specific, UnitID-based API functions.

Billtopia 11-30-12 08:37 AM

I remember asking for this ability during the beta... One of my addons needs to be able to tell if a person is of the same faction from only the guid... and there is no way for me that doesn't introduce some sort of lag... I could try a search but then I have to make the addon wait for the who list update event... and then users would see I did it... If SendAddonChatMessage had a return value instead of printing the error to chat that could help too

Phanx 11-30-12 05:14 PM

If you're getting GUIDs from chat (the usual reason for calling GetPlayerInfoByGUID) then you can determine the faction based on the message language.

SDPhantom 11-30-12 05:51 PM

Quote:

Originally Posted by Phanx (Post 262433)
If you're using GetPlayerInfoByGUID, it's probably because you're dealing with people who are talking in chat, or doing something else where no UnitID is available.

Yes, this is for code responding to chat events where there are no valid UnitIDs. An example is for a custom language addon like Tongues to be able to tell an Alliance Pandaren from a Horde one and act accordingly. Both factions use the [Pandaren] language tag for their racial languages. More specifically, this request was to add faction-specific icons for ChatLinkIcons in order to differentiate the same problem with the same race being available to both factions. Even though the character creation screen shows one button for Pandaren, there are actually two icons in the game files (one set of texcoords is the horizontal flipped image of the other set).

Phanx 12-01-12 01:55 AM

Can't you use ChatFrame_AddMessageEventFilter and just catch the language argument (arg3) passed with the chat message? I can't recall the last time I saw anyone /say or /yell anything in a language other than their faction's default language, so just checking for Orcish or Common should catch 99% of cases.

Another option would be to do what BadBoy_Levels does to check levels, and attempt to add the player to your friends list and catch the result message. If it's successful, the player is part of your faction; if it failed, the player is of the opposing faction. This wouldn't work for cross-realm players, but I think the chances of someone of the opposite faction from another server /saying or /yelling anything in a non-default language are pretty slim.

Finally, SendAddonMessage doesn't need a return value, as it's trivial to catch the message printed to the chat frame when sending fails, and hide it from the user.

Billtopia 12-01-12 10:31 AM

I, myself, am using the guid from achievements and as such, I get no information that can tell me what faction besides race... now with the Pandaren, I am out of luck... There is no valid unit for me to check the affiliation with... I mean if Blizz is going to classify them as 3 different races then they should return 3 different race returns or supply some method for distinguishing from guid or something besides by units.

SDPhantom 12-01-12 10:31 AM

Quote:

Originally Posted by Phanx (Post 269950)
Can't you use ChatFrame_AddMessageEventFilter and just catch the language argument (arg3) passed with the chat message? I can't recall the last time I saw anyone /say or /yell anything in a language other than their faction's default language, so just checking for Orcish or Common should catch 99% of cases.

As mentioned, even with the slim chance of it ever happening, the language passed isn't specific enough when dealing with the Pandaren racial language. This was one of the first solutions I checked out previously.



Quote:

Originally Posted by Phanx (Post 269950)
Another option would be to do what BadBoy_Levels does to check levels, and attempt to add the player to your friends list and catch the result message. If it's successful, the player is part of your faction; if it failed, the player is of the opposing faction. This wouldn't work for cross-realm players, but I think the chances of someone of the opposite faction from another server /saying or /yelling anything in a non-default language are pretty slim.

This method is similar to what GAOA does to check if a player is online, the only difference is it uses the addon channel to ping the chat server (not the player, resulting in an addon that works one-sided). If the server comes back with a player offline message, the addon reacts accordingly. Otherwise, it waits a timeout period before assuming the player is online. There may be better methods for that addon, but that's irrelevant at this moment.

As for the other addon examples, this may be an option, but for ChatLinkIcons, requesting additional data from the servers costs additional time that doesn't fit the time restraint I feel is appropriate.



Quote:

Originally Posted by Phanx (Post 269950)
Finally, SendAddonMessage doesn't need a return value, as it's trivial to catch the message printed to the chat frame when sending fails, and hide it from the user.

Did this get posted on the wrong thread? :confused:

Billtopia 12-01-12 10:44 AM

As for the SendAddonChatMessage() needing a return, what I meant was that if it had a return value then it could be used for a opposing faction test without needing to wait for another event to fire. I get person's name from the guid, send an addon whisper, and if it failed with a return code then I wouldn't need faction from the GUID. I could also do the same thing with who-s but again I would have to wait for another event to continue on in the program( which I am guessing is my best bet to filter out the horde achievements )

I chose SendAddonChatMessage() as it would be invisible to the person receiving the message for my example...

Phanx 12-01-12 01:39 PM

Quote:

Originally Posted by SDPhantom (Post 269972)
Did this get posted on the wrong thread? :confused:

No. See Billtopia's previous post:

If SendAddonChatMessage had a return value instead of printing the error to chat that could help too.

Also, the delay between you trying to send an addon message and the client printing a "player not found" or similar error message to the chat frame is so infinitesimally small that I can't imagine it being unacceptable for something that is really just cosmetic, especially since you'd only "need" to do it for pandaren in /say and /yell. How often does that really happen, anyway?

Billtopia 12-01-12 07:32 PM

what I am doing is trying to filter out non same faction achievements out from my addon... who wants a popup asking if you want to congratulate a person of the opposing faction when they get an achievement? my problem is that the addon can work for people near you as well as people in your group and guild that nearby opposing pandaren can trigger the frame to appear. I can rewrite my faction test to treat them differently but what I was hoping for was some way to test within that event cycle instead of having to wait for another event to fire...

I looked through the events that I can register for the chat frame but http://www.wowwiki.com/Events/Communication has no listing for an error event... does anyone know what event fires when the SendAddonChatMessage fails to find its whisper target?

I figure I will just put the Pandaren achievements into a queue for a second and send the message... if a error pops on the name the chat filter can remove them from the queue... if they still exist the onupdate handler can send them off to continue on their way to the grat frame.

I looked into using the SendWho but it says that the WHO_LIST_UPDATED event only fires when the who list is open so that is a no go

I already broke my achievement processing function into 2 pieces so it can now wait for a response from SendAddonChatMessage without freezing the computer. (I also rewrote my SameFaction function so it can call one of two passed functions to continue the processing if they match or not so it can handle waiting on pandaren)

pelf 12-01-12 09:30 PM

Wow Instant Messenger tries to look up the guild, class and level of whatever name you whisper. It appears to be using LibWho-2.0 for that. The call is made in Modules/Filters.lua. Maybe you can use that or its methodologies?

Phanx 12-02-12 06:58 AM

Quote:

Originally Posted by Billtopia (Post 270015)
what event fires when the SendAddonChatMessage fails to find its whisper target?

CHAT_MSG_SYSTEM is the event that fires, and the message argument should match a global string. Get the exact message in-game and then find it in your locale's GlobalStrings listing to get the global name. If it just says "Player not found." then it's probably ERR_FRIEND_NOT_FOUND.

However, you'd want to use ChatFrame_AddMessageEventFilter to catch and hide the message instead of registering your frame for the CHAT_MSG_SYSTEM event:

Code:

-- Have a filter function ready:
local CatchSystemMessage = function(frame, event, message)
    -- Remove the filter:
    ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM", CatchSystemMessage)
    -- Check the message:
    if message == ERR_FRIEND_NOT_FOUND then
        -- Sending the message failed.
        -- Do something here if needed.
        -- Hide the message from the user:
        return true
    end
end

-- When you try to send a message, register the filter first:
ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", CheckSystemMessage)
SendAddonMessage("TEST", "faction test", "WHISPER", nil, "Someguy")

This will catch the next system message after you send a message. If you wanted to be really fancy, you could add a timeout to remove the filter after some amount of time (probably 1 second would be more than enough). Otherwise you run the minor risk of catching the next system message even if it's not related to your event, and if the message is "Player not found." then it will get hidden.

Quote:

Originally Posted by nazrhyn (Post 270020)
Wow Instant Messenger ... appears to be using LibWho-2.0 for that. The call is made in Modules/Filters.lua. Maybe you can use that or its methodologies?

LibWho-2.0 is just a wrapper around the /who query system, which is slow, and interferes with the user's ability to /who query people. It also doesn't work very well for players with short names. For example, if you are trying to /who someone named Pat, the results will include every name that includes the letters "pat" in that order at any position, and since it's limited to 49 results, you may not even get the Pat you were looking for. Using /who in an addon to find information about a specific player should be the absolute last resort.

semlar 12-02-12 08:56 AM

Here'a a "quick" and dirty method for getting the faction from a unit's GUID using its tooltip:
Lua Code:
  1. local guidCache = {}
  2. local _, myFaction = UnitFactionGroup('player')
  3. local utip = CreateFrame("GameTooltip", "uTip", UIParent, "GameTooltipTemplate")
  4.  
  5. local function DoSomething(guid)
  6.     local faction = guidCache[guid]
  7.     if faction then
  8.         print(guid, faction, faction == myFaction)
  9.     end
  10. end
  11.  
  12. utip:SetScript("OnTooltipSetUnit", function(self)
  13.     if guidCache[self.guid] then return end
  14.     local tipName, numLines = self:GetName()..'TextLeft', self:NumLines()
  15.     local faction = _G[tipName..numLines]:GetText() == PVP and _G[tipName..(numLines-1)]:GetText() or _G[tipName..numLines]:GetText()
  16.     guidCache[self.guid] = faction
  17.     DoSomething(self.guid)
  18. end)
  19.  
  20. function ScanFaction(guid)
  21.     if guid and tonumber(guid:sub(5,5), 16) % 8 == 0 then
  22.         if guidCache[guid] then
  23.             DoSomething(guid)
  24.         else
  25.             utip.guid = guid
  26.             utip:SetHyperlink('unit:'..guid)
  27.         end
  28.     end
  29. end
Usage: ScanFaction(UnitGUID('example')), calls DoSomething when it's finished.

Probably not the best solution but maybe it'll help somebody.

pelf 12-02-12 11:04 AM

Quote:

Originally Posted by Phanx (Post 270037)
LibWho-2.0 is just a wrapper around the /who query system, which is slow, and interferes with the user's ability to /who query people. It also doesn't work very well for players with short names. For example, if you are trying to /who someone named Pat, the results will include every name that includes the letters "pat" in that order at any position, and since it's limited to 49 results, you may not even get the Pat you were looking for. Using /who in an addon to find information about a specific player should be the absolute last resort.

From your back-and-forth, though, it looks like in the situation where he detects that he doesn't know whether they're a hostile or friendly panda, he might need to use it. I was mostly responding to him thinking that the who window needed to be up to use the who API :).

Quote:

Originally Posted by semlar
Here'a a "quick" and dirty method for getting the faction from a unit's GUID using its tooltip:

That won't still work if someone is using a custom tooltip, will it?

endx7 12-02-12 12:29 PM

Quote:

Originally Posted by nazrhyn (Post 270054)
That won't still work if someone is using a custom tooltip, will it?

It should work, because it's using a privately created tooltip, not the normal GameTooltip (not to be confused the GameTooltip object type).

pelf 12-02-12 12:54 PM

Quote:

Originally Posted by endx7 (Post 270058)
It should work, because it's using a privately created tooltip, not the normal GameTooltip (not to be confused the GameTooltip object type).

Cool! Well, I'd definitely prefer creating an ad-hoc tooltip to doing a who query, for sure. That's a slick idea.

Phanx 12-02-12 01:21 PM

Quote:

Originally Posted by semlar (Post 270048)
Here'a a "quick" and dirty method for getting the faction from a unit's GUID using its tooltip:

Looks promising, though if you're going to make the ScanFaction function a global, I'd suggest giving a less generic name, like GetPlayerFactionFromGUID or something. Also not sure about speed of waiting for the server to send a tooltip vs. waiting for the server to tell you sending a message failed, but I guess it's faster than waiting on a timeout to assume a message succeeded.

semlar 12-02-12 02:50 PM

I left it as a global so I could test it directly in-game, if you're going to use it then it should probably be localized.

I should mention that the reason I had it cache the results wasn't for faster lookups but because sometimes OnTooltipSetUnit would fire more than once and I didn't want it calling the function again.

I actually have to make a slight edit because unit GUIDs on the PTR (which was where I was testing this) are not the same as they are on live, which I didn't realize when I posted it. It's just the check that the GUID belongs to a player-type unit, which isn't strictly necessary anyway.

Using debugprofilestop and scanning a handful of units it takes anywhere between 0.1 and 0.3 milliseconds for the first lookup. For reference, 60 fps is one frame every ~16 milliseconds, so I don't think it'll be too much of a problem.

I did notice one caveat while scanning for players in the combat log to test it: if they're sufficiently higher level than you the tooltip doesn't say what faction they are, just their name and "Level ?? Race Class (Player)". I don't know how much this matters because as long as it doesn't match your faction string it's probably not your faction.

An alternative might be to compare the :GetTextColor of the first line of the tooltip (the name) since it appears to be colored based on reaction.

edit: I don't think it actually does change the color of the text unless it has a unit id or something, so that won't work.

SDPhantom 12-03-12 12:31 AM

Quote:

Originally Posted by Phanx (Post 269991)
No. See Billtopia's previous post:

If SendAddonChatMessage had a return value instead of printing the error to chat that could help too.

Ok, I just ran a find command for SendAddonMessage as per your post and it found nothing when it was actually SendAddonChatMessage. :D



Quote:

Originally Posted by Phanx (Post 269991)
Also, the delay between you trying to send an addon message and the client printing a "player not found" or similar error message to the chat frame is so infinitesimally small that I can't imagine it being unacceptable for something that is really just cosmetic, especially since you'd only "need" to do it for pandaren in /say and /yell. How often does that really happen, anyway?

How often an error happens is irrelevant to a glitch existing in any form. Also, I would like to know how much of a delay you would consider "infinitesimally small". The time for any data request to reach the servers and come back with a reply will always be at least the user's ping time. Depending on the connection, this would vary, but should not be easily dismissed as a negligible amount. Note observed ping rates have been in the range of 200-1000+ ms. This is pretty much the range of 1/5 of a second to a full second delay.

Billtopia 12-03-12 12:06 PM

so... thanks for the help on this. The string constant is ERR_CHAT_PLAYER_NOT_FOUND_S and my filter is designed so I don't have to remove it as it will only filter exact matches to pandaren I am looking for. I think I will try out the tooltip method now as that is an instant answer and seems to be a smaller solution in both coding and in table usage.

Phanx 12-03-12 03:31 PM

Quote:

Originally Posted by SDPhantom (Post 270100)
How often an error happens is irrelevant to a glitch existing in any form.

This isn't an "error" or "glitch" though. You're trying to get information Blizzard doesn't want you to have, or at least doesn't feel is important enough for you to have that it's worth their time to give it to you through the API. I think it's very relevant to consider how often a situation where you "need" to use a hack/workaround to get information that's not directly available really comes up in actual gameplay.

Quote:

Originally Posted by SDPhantom (Post 270100)
Also, I would like to know how much of a delay you would consider "infinitesimally small".

I consider it infinitesimally small when I can do /run SendAddonChatMessage("test", "test", "WHISPER", Someguy") and the "Player not found" message appears immediately according to my human perception of time.

If you have 1000 ms ping, there is either something wrong with your connection or you're bringing it on yourself by playing on a server far outside of your region, but in any case it's hardly the end of the world if you delay showing chat messages from/about opposite faction panadren anyway. It's not like it's actually relevant information.

SDPhantom 12-03-12 09:28 PM

Quote:

Originally Posted by Phanx (Post 270131)
This isn't an "error" or "glitch" though. You're trying to get information Blizzard doesn't want you to have, or at least doesn't feel is important enough for you to have that it's worth their time to give it to you through the API.

The topic of the "error or glitch" was in perspective of an addon and not the game client. This discussion is about a suggestion to add more data to a function to continue the consistent functionality of an addon. Not all absence of information is either forbidden or decidedly unimportant. Some lack of data happens because nobody thinks of adding access to it.



Quote:

Originally Posted by Phanx (Post 270131)
I consider it infinitesimally small when I can do /run SendAddonChatMessage("test", "test", "WHISPER", Someguy") and the "Player not found" message appears immediately according to my human perception of time.

If you have 1000 ms ping, there is either something wrong with your connection or you're bringing it on yourself by playing on a server far outside of your region ...

Even though Blizzard doesn't recommend it, people do play on high-latency connections like dial-up, satellite, and cell data cards. Mostly because of limited or lack of access to any low-latency broadband connections. Being someone stuck on either of these high-latency connections is a major pain and I curse it every day, but for now, it's all I could ever get access to from home.



Quote:

Originally Posted by Phanx (Post 270131)
... in any case it's hardly the end of the world if you delay showing chat messages from/about opposite faction panadren anyway. It's not like it's actually relevant information.

This subforum is a "Wish List". Everything here is a suggestion for what we would like Blizzard to consider. I don't maintain Tongues or any other custom language addon, but I anticipated Pandarens as bringing difficulty to those addons. As for as my ChatLinkIcons addon, this is more of a luxury than necessity. I can just as easily use the single icon featured in the character creation screen for both factions. This is what my current version does already. My mention of the other addons was to add examples of where this would be helpful and possibly add their respective authors' support in petitioning this suggestion.



There is an entire history of various data Blizzard granted access to over the years. In vanilla WoW, HP values for any unit other than the player were strictly provided as an integer percent. This changed in BC because of addons that calculated mob HP from how much damage they took before dying, then applied that to exact copies of the same mob. At one time, GUIDs weren't available to addons. The same time Blizzard overhauled the Combat Log system, they added this as a way to track info about a specific entity. Up until LK, Blizzard didn't provide information about mob threat levels. Addons like Omen had to calculate this themselves by taking in damage and healing info from the combat log. There are more examples, but this is all I can think of at the moment. All of which fall into different categories of necessity and luxury, things people suggested and things people worked on to obtain themselves.

Phanx 12-04-12 12:23 AM

Quote:

Originally Posted by SDPhantom (Post 270156)
In vanilla WoW, HP values for any unit other than the player were strictly provided as an integer percent. This changed in BC because of addons that calculated mob HP from how much damage they took before dying, then applied that to exact copies of the same mob. At one time, GUIDs weren't available to addons. The same time Blizzard overhauled the Combat Log system, they added this as a way to track info about a specific entity. Up until LK, Blizzard didn't provide information about mob threat levels. Addons like Omen had to calculate this themselves by taking in damage and healing info from the combat log. There are more examples, but this is all I can think of at the moment. All of which fall into different categories of necessity and luxury, things people suggested and things people worked on to obtain themselves.

I was around for all of those changes, and they all have one thing in common -- they allowed addons (or the default UI) to give players new access to information directly relevant to real-time gameplay decisions. There's just no situation where (a) it's relevant to your immediate gameplay to know which faction a player belongs to but (b) that information isn't already available through some existing API.

If you think eliminating a one-second-at-most delay to determine someone's faction in the one-in-a-million event of them being an enemy pandaren /saying or /yelling something in Pandaren instead of their faction default language is really so critical Blizzard needs to spend time adding to the API, I guess we just have radically different ideas about what is important. I'd much rather they spend time fixing actual bugs instead, and there are certainly plenty of those for them to work on.

SDPhantom 12-04-12 10:22 AM

Quote:

Originally Posted by Phanx (Post 270165)
If you think eliminating a one-second-at-most delay to determine someone's faction in the one-in-a-million event of them being an enemy pandaren /saying or /yelling something in Pandaren instead of their faction default language is really so critical Blizzard needs to spend time adding to the API, I guess we just have radically different ideas about what is important.

They already link the internal data from UnitClass(), UnitRace(), and even UnitSex() to GetPlayerInfoByGUID(). How much more time do you think it would take to link to UnitFactionGroup()'s internal data too? The least it would be is copy/paste existing code and change which data field it pulls from, push the extra LuaString on the stack, and increase the int return of the C function by 1.

If you don't believe me, check the links.



Quote:

Originally Posted by Phanx (Post 270165)
I'd much rather they spend time fixing actual bugs instead, and there are certainly plenty of those for them to work on.

So you're suggesting for the WoWI staff to close down the entire Wish List subforum because you don't want Blizzard to be bothered with what some other addon authors would like implemented in the API?

If I'm not mistaking, this is the entire purpose of this subforum. Description of Developer Discussions Wish List taken from the main forum page.
Quote:

A place for AUTHORS to post their requests to Blizzard about api functions/interface features for possible inclusion.

Billtopia 12-04-12 11:05 AM

so this is currently what I have the tooltip down to and it works fine (well it did as I made some changes here and have yet to test them)... you call it and it returns true if they are the same faction and false if not. I still think an added return to for GetPlayerInfoByGUID would be a better solution... and since this is a WISH LIST... I can wish all I want lol

Lua Code:
  1. local guidCache = {}
  2. local utip = CreateFrame("GameTooltip", "uTip", UIParent, "GameTooltipTemplate")
  3. utip:SetOwner( WorldFrame, "ANCHOR_NONE")
  4.  
  5. SameFaction = function (guid)
  6.      if IsPlayerNeutral() then
  7.          return true
  8.      end
  9.      local _, myFaction = UnitFactionGroup('player')
  10.      uTip:ClearLines()
  11.      if guid and tonumber(guid:sub(5,5), 16) % 8 == 0 then
  12.          if not( guidCache[guid] ) then
  13.              utip:SetHyperlink('unit:'..guid)
  14.              local tipName, numLines = "uTipTextLeft", _G["uTip"]:NumLines()
  15.              local faction = _G[tipName..tostring(numLines)]:GetText() == PVP and _G[tipName..tostring(numLines-1)]:GetText() or _G[tipName..tostring(numLines)]:GetText()
  16.              if faction ~= FACTION_ALLIANCE or faction ~= FACTION_HORDE then
  17.                  if myFaction == FACTION_ALLIANCE then
  18.                           faction = FACTION_HORDE
  19.                  else
  20.                      faction = FACTION_ALLIANCE
  21.                  end
  22.               end
  23.              guidCache[guid] = faction
  24.         end
  25.         return guidCache[guid] == myFaction
  26.      end
  27. end

SDPhantom 12-04-12 01:46 PM

I'll have to do some further tests with the tooltips for the unit hyperlink. Previously, I've noticed it only returns useful data if the player in question is within the game client's visible range. If it does still work past that range, I might take a look into it and already have some optimizations in mind for the code.

Lua Code:
  1. local guidCache={};
  2. local ttframe=CreateFrame("GameTooltip","FactionIdentifierTooltip",nil,"GameTooltipTemplate");
  3. ttframe:SetOwner(WorldFrame,"ANCHOR_NONE");
  4.  
  5. function FactionGroupFromGUID(guid)
  6.     if guid and tonumber(guid:sub(5,5),16)%8==0 then
  7.         local faction=guidCache[guid];
  8.         if faction then return faction; end
  9.  
  10.         ttframe:ClearLines();
  11.         ttframe:SetHyperlink('unit:'..guid);
  12.         local lines=ttframe:NumLines();
  13.         local faction=_G["FactionIdentifierTooltipTextLeft"..tostring(lines)]:GetText();
  14.         if faction==PVP then faction=_G["FactionIdentifierTooltipTextLeft"..tostring(lines-1)]:GetText();
  15.  
  16.         if faction==FACTION_ALLIANCE or faction==FACTION_HORDE then
  17.             return faction==FACTION_ALLIANCE and "Alliance" or "Horde",faction;
  18.             guidCache[guid]=faction;--  Faction can change from Neutral to either of these
  19.         else
  20.             return "Neutral","";
  21.         end
  22.     else
  23.         return nil,nil;
  24.     end
  25. end

Assuming the tooltip works beyond the game client's visual range and no addons hook into the global metatable for tooltips, this modification should function in the same way UnitFactionGroup() does, but operate on GUIDs instead.

semlar 12-04-12 02:55 PM

Okay, I didn't take into account that the faction might change, so you probably should avoid caching it if it's neutral. However, I warn you against skipping OnTooltipSetUnit, I've had issues before making the assumption that a tooltip's text is going to be available immediately after I set it.

Also, don't assume that it's neutral because it doesn't match the alliance or horde string because sometimes the faction isn't mentioned in the tooltip, which I believe always means it's not your faction, but could be either neutral or the opposing faction.

SDPhantom 12-04-12 04:13 PM

I'm not sure if Tooltip:SetHyperlink() fires OnTooltipSetUnit on unit hyperlinks. Again, all this is pending results of a series of tests I need to do and unfortunately, I can't perform them at work right now. The "Neutral" handling is just a fall through in case it's unable to identify a specific faction. With lack of other options, I don't see any harm in letting it do that as long as it doesn't throw them into either of the Alliance or Horde category blindly. If you insist, you can have it pass nil,nil instead as that's the default response of UnitFactionGroup() for neutral NPCs.

Billtopia 12-04-12 05:13 PM

That is why I used IsPlayerNeutral() in my function first as if you are neutral, so every other char near you will be too. Also if it doesn't come back with a faction for a player then it is safe to assume that the player is of the opposing faction (as I did). I suppose that since a clear is issued before the set you could test to make sure that numlines is greater than 0 to make sure that the tooltip has been set... and possibly loop until it is but who knows how long that could hang you up for...

semlar 12-04-12 05:25 PM

OnTooltipSetUnit fires when it's populated with unit information whether it's from SetUnit or SetHyperlink.

I don't know for sure that you need to wait for it, but I would be careful.

Billtopia 12-04-12 05:28 PM

sure beats the following... this is what I was doing before, modified for the SendAddonMessage and to catch the thrown error if it happens

if it is passed just a GUID it will return true if the person is part of your faction or if you are a panda

if you pass a GUID, and a function to run if true / false and char name and unlimited args for the passed functions ... if a non panda it will automatically call the proper function (if it exists) and return true/false depending... if a panda it queues up the required info in a table, sends the addon message and waits up to 1 second for the error. if the error is thrown, it will call the ifFalse function and remove the panda from the queue... after the 1 second, the addon calls the ifTrue function if supplied and then removes the panda from the queue

it will call ifTrue/ifFalse with GUID, unpack(...)

Lua Code:
  1. local pandaQueue = {}
  2. local pandaE = 0
  3. local pandaDelay = 1
  4.  
  5. local pandaCheckFrame = CreateFrame("Frame","pandaCheckFrame", UIParent)
  6. pandaCheckFrame:SetScript("onUpdate",function( self, elapsed )
  7.     pandaE = pandaE + elapsed
  8.     if pandaE < 1/10 then
  9.         return
  10.     end
  11.     local e = pandaE
  12.     local count = #pandaQueue
  13.     pandaE = 0
  14.     if count == 0 then
  15.         return
  16.     end
  17.     for x = count, 1, -1 do
  18.         pandaQueue[x].time = pandaQueue[x].time + e
  19.         if pandaQueue[x].time > pandaDelay then
  20.             if type( pandaQueue[x].ifTrue ) == "function" then
  21.                 pandaQueue[x].ifTrue( pandaQueue[x].GUID, pandaQueue[x].event, unpack( pandaQueue[x] ) )
  22.             end
  23.             table.remove( pandaQueue, x )
  24.             return true
  25.         end
  26.     end
  27. end)
  28.  
  29. local pandaFilter = function( self, event, ... )
  30.     if #pandaQueue == 0 then
  31.         return false
  32.     end
  33.    
  34.     local arg = {...}
  35.     for x = #pandaQueue, 1, -1 do
  36.         if arg[1] == string.format(ERR_CHAT_PLAYER_NOT_FOUND_S, pandaQueue[x].name ) then
  37.             if type( pandaQueue[x].ifFalse ) == "function" then
  38.                 pandaQueue[x].ifFalse( pandaQueue[x].GUID, unpack( pandaQueue[x] ) )
  39.             end
  40.             table.remove( pandaQueue, x )
  41.             return true
  42.         end
  43.     end
  44.     return false
  45. end
  46.  
  47. ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", pandaFilter)
  48.  
  49. SameFaction = function( GUID, ifTrue, ifFalse, name, ... )
  50.     local isSame = false
  51.     local _, _, _, CompRace = GetPlayerInfoByGUID( GUID )
  52.     CompRace = string.lower(CompRace)
  53.    
  54.     if IsPlayerNeutral() then
  55.         isSame = true
  56.     elseif CompRace == "pandaren" then
  57.         if type( ifTrue ) == "function" or type( ifFalse ) == "function" then
  58.             local index = #pandaQueue + 1
  59.             pandaQueue[index] = { unpack(...) }
  60.             pandaQueue[index].GUID = GUID
  61.             pandaQueue[index].ifTrue = ifTrue
  62.             pandaQueue[index].ifFalse = ifFalse
  63.             pandaQueue[index].name = name
  64.             pandaQueue[index].time = 0
  65.             SendAddonMessage("FactionTest", "Pandaren Faction Test", "whisper", name)
  66.             return true
  67.         else
  68.             isSame = true
  69.         end
  70.     else
  71.         local PlayerIsAlliance = UnitFactionGroup("player") == "Alliance"
  72.         local Allies = { ["worgen"] = true, ["draenei"] = true, ["dwarf"] = true, ["gnome"] = true, ["human"] = true, ["nightelf"] = true }
  73.         local CompIsAlliance = Allies[CompRace] and true or false
  74.         if PlayerIsAlliance == CompIsAlliance then
  75.             isSame = true
  76.         end
  77.     end
  78.     if isSame then
  79.         if type( ifTrue ) == "function" then
  80.             ifTrue( GUID, unpack(...))
  81.         end
  82.         return true
  83.     end
  84.     if type( ifFalse ) == "function" then
  85.         ifFalse( GUID, unpack(...))
  86.     end
  87.     return false
  88. end

SDPhantom 12-04-12 05:44 PM

Quote:

Originally Posted by semlar (Post 270202)
OnTooltipSetUnit fires when it's populated with unit information whether it's from SetUnit or SetHyperlink.

I don't know for sure that you need to wait for it, but I would be careful.

One problem would be if you're to call a function and need a return from it, you can't halt execution to wait for a script to fire. The game only allows a single thread to run the Lua engine, so the resulting script would never run since the thread is occupied in the function. In essence, you'd run yourself into an infinite loop and freeze the entire game client.

The only way around this is to recode the entire thing into a request-and-callback code style, which would add another layer of complexity to it.

semlar 12-04-12 06:16 PM

I was scraping the tooltip for spell information and can say with absolute certainty that attempting to do it soon after loading/zoning and possibly other situations would result in the tooltip being empty.

Dridzt 12-04-12 06:22 PM

Quote:

Originally Posted by SDPhantom (Post 270206)
The game only allows a single thread to run the Lua engine

That is not entirely true. :)

Well technically it is but you get my point. (Routes and Weakauras - that I know off - use coroutines to simulate multi-threaded execution)

SDPhantom 12-04-12 06:32 PM

A coroutine represents a thread, but isn't a real one. If you have a coroutine run an infinite loop in the game client, it'll freeze it the same way as if you had code in the main stack do so. This is because the coroutine needs to yield in order for the main stack to continue running. If it never yields, the thread it's running on (the only thread the Lua engine is given) gets stuck. Since MoP though, the game client has a WatchDog thread that activates while in combat and monitors how long the Lua engine thread runs. If the Lua thread exceeds a specific amount of time, the WatchDog thread interrupts it by forcing a Lua error.

Note WatchDog is an old term for a program or circuit specifically designed to detect when another critical program/component freezes and restarts it as necessary.

Billtopia 12-09-12 01:08 PM

OK... So here is what I have now. It will return Neutral when the player is neutral, as you can only run into neutral players then, it tests the race of all chars and figures out by that, faction, except for pandas which it uses the tooltip. I combined how I was originally testing and incorporated the tooltip for scanning pandas only.

Lua Code:
  1. -- Faction tooltip settings
  2.     local guidCache = {}
  3.     local utip = CreateFrame("GameTooltip", "uTip", UIParent, "GameTooltipTemplate")
  4.     utip:SetOwner( WorldFrame, "ANCHOR_NONE")
  5.  
  6.  
  7. -- Returns a faction from a given GUID for a player character
  8.     FactionByGUID = function(GUID)
  9.         uTip:ClearLines()
  10.         utip:SetHyperlink('unit:'..GUID)
  11.         if IsPlayerNeutral() then
  12.             return "Neutral"
  13.         end
  14.         if guidCache[GUID] then
  15.             return guidCache[GIUD]
  16.         end
  17.         local _, _, _, CompRace = GetPlayerInfoByGUID( GUID )
  18.         if CompRace ~= "Pandaren" then
  19.             local Alliance = { ["Worgen"] = true, ["Draenei"] = true, ["Dwarf"] = true, ["Gnome"] = true, ["Human"] = true, ["NightElf"] = true }
  20.             guidCache[GUID] = Alliance[CompRace] and FACTION_ALLIANCE or FACTION_HORDE
  21.             return guidCache[GUID]
  22.         end
  23.        
  24.         if GUID and tonumber(GUID:sub(5,5), 16) % 8 == 0 then
  25.             local tipName, numLines = "uTipTextLeft", _G["uTip"]:NumLines()
  26.             local faction = _G[tipName..tostring(numLines)]:GetText() == PVP and _G[tipName..tostring(numLines-1)]:GetText() or _G[tipName..tostring(numLines)]:GetText()
  27.             if faction ~= FACTION_ALLIANCE and faction ~= FACTION_HORDE then
  28.                 --compares level is too high so just invert our faction
  29.                 local _, myFaction = UnitFactionGroup('player')
  30.                 faction = myFaction == FACTION_ALLIANCE and FACTION_HORDE or FACTION_ALLIANCE
  31.             end
  32.             guidCache[GUID] = faction
  33.             return guidCache[GUID]
  34.         end
  35.     end

SDPhantom 12-09-12 05:53 PM

From some of my testing, the same conclusion happens that I had observed earlier pre-MoP. Tooltips from the unit hyperlink only displays useful information past race/class only if said unit is within the game client's visual range. As soon as a unit leaves this range, existing information is discarded and is no longer available.


All times are GMT -6. The time now is 11:23 AM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2019 MMOUI