Thread Tools Display Modes
05-18-14, 05:43 PM   #1
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
BNplayer Hyperlink

I am trying to create a player link for a copy-cat chat message, but I'm having trouble understanding the arguments that it needs.
Basically what the addon is supposed to do is to send a chat message when a player who is logged onto the Battle.net desktop app only logs onto a game. The message mimics the one sent when your Battle.net friends normally log on without the client ("Soandso (W Toonname) has come online.").

I found the following code in Interface\FrameXML\ChatFrame.lua:

lua Code:
  1. playerLink = "|HBNplayer:"..arg2..":"..arg13..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h"

However, I'm having issues trying to figure out what each of the arguments are and how to incorporate it into my code.

lua Code:
  1. local events = CreateFrame("Frame")
  2.       events:RegisterEvent("ADDON_LOADED")
  3.       events:RegisterEvent("PLAYER_LOGIN")
  4.       events:RegisterEvent("BN_TOON_NAME_UPDATED")
  5.       events:RegisterEvent("BN_FRIEND_TOON_ONLINE")
  6.       events:RegisterEvent("BN_FRIEND_ACCOUNT_OFFLINE")
  7.       events:SetScript("OnEvent", function(self, event, ...)
  8.           return self[event] and self[event](self, event, ...)
  9.       end)
  10.  
  11. local Friends = {}
  12.  
  13. -- Get online players.
  14. function events:ADDON_LOADED(event, addon)
  15.     if addon == "FriendsFixes" then
  16.         for x = 1, BNGetNumFriends() do
  17.             local presenceID = BNGetFriendInfo(x)
  18.             Friends[presenceID] = {BNGetFriendInfo(x)}
  19.         end
  20.     end
  21. end
  22.  
  23. function events:PLAYER_LOGIN(event, ...)
  24.     for x = 1, BNGetNumFriends() do
  25.         local presenceID = BNGetFriendInfo(x)
  26.         Friends[presenceID] = {BNGetFriendInfo(x)}
  27.     end
  28. end
  29.  
  30. -- Prevents double login spam from App.
  31. local function FilterBNLoginSpam(self, event, type, ...)
  32.     local presenceID = select(12, ...)
  33.  
  34.     if type == "FRIEND_ONLINE" and presenceID then
  35.         if Friends[presenceID][8] then
  36.             return true
  37.         else
  38.             for x = 1, BNGetNumFriends() do
  39.                 local presenceID = BNGetFriendInfo(x)
  40.                 Friends[presenceID] = {BNGetFriendInfo(x)}
  41.             end
  42.         end
  43.     end
  44. end
  45.  
  46. ChatFrame_AddMessageEventFilter("CHAT_MSG_BN_INLINE_TOAST_ALERT", FilterBNLoginSpam)
  47.  
  48. -- -- Announces login while logged into App.
  49. function events:BN_TOON_NAME_UPDATED(event, ...)
  50.     for x = 1, BNGetNumFriends() do
  51.         local friendPresenceID, friendName, friendBtag, _, friendToonName, friendToonID, friendGame, friendOnline = BNGetFriendInfo(x)
  52.         local friends = Friends[friendPresenceID]
  53.  
  54.         if friends and friends[7] ~= friendGame then
  55.             if friends[7] == "App" then
  56.                 print(BATTLENET_FONT_COLOR_CODE .. friendName .. " (" .. BNet_GetClientEmbeddedTexture(friendGame, 14) .. (friendToonName and friendToonName or "") .. ") has come online.")
  57.             end
  58.             Friends[friendPresenceID] = {BNGetFriendInfo(x)}
  59.         end
  60.     end
  61. end
  62.  
  63. events.BN_FRIEND_TOON_ONLINE = events.BN_TOON_NAME_UPDATED
  64.  
  65. function events:BN_FRIEND_ACCOUNT_OFFLINE(event, ...)
  66.     for x = 1, BNGetNumFriends() do
  67.         local presenceID = BNGetFriendInfo(x)
  68.         Friends[presenceID] = {BNGetFriendInfo(x)}
  69.     end
  70. end

Last edited by Niketa : 05-18-14 at 10:59 PM.
  Reply With Quote
05-19-14, 12:18 AM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Where the default UI uses "arg1" style names for event arguments, they're just sequentially numbered, with the first argument being arg1 and the 15th argument being arg15, etc. So just look at the list of arguments for the event you're processing, and number them from 1 on up.

For any chat message event, arg2 is the sender's name and arg11 is a line counter uniquely identifying the message (used when reporting, etc.). For a Battle.net chat event, arg13 is the sender's presence ID. You'd have to read back further in the default UI code you're looking at to see what chatGroup and chatTarget are exactly, but I'd guess they are probably identifying the channel and sender.

The code you posted doesn't seem to actually be related to the functionality you described -- did you post the wrong code, maybe? -- but rather than duplicating default UI code to reproduce default UI functionality, I'd just call the default UI's own event handler and let it do all the processing, eg. to mimic a "friend logged in" event for the friend with presenceID 5:

Code:
ChatFrame_MessageEventHandler(ChatFrame1, "CHAT_MSG_BN_INLINE_TOAST_ALERT", "FRIEND_ONLINE", "|Kf5|k00000000000000000000|k", nil, nil, nil, nil, nil, nil, nil, nil, 0, nil, 5)
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-19-14, 08:28 AM   #3
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
The code I wrote has a table of friends info and when someone logs on (BN_TOON_NAME_UPDATED) it updates info for that person and if the game has changed and is not "App" it prints a login message.

I had an awful hard time with this as it's not something I usually deal with but the whole process seemed frustrating. So if there is an easier and more efficient way I'm all ears. This is just such a pet peeve for me about the app. Anyway, with the way I'm doing it I don't think it's even possible to get all the arguments since I'm the one making the message right?

Also heading out to work so I'm not at my computer to check but if I'm understanding right the code you posted will do a real login message and the only arg needed is the presence is in 2 places?
  Reply With Quote
05-19-14, 12:52 PM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Niketa View Post
... the only arg needed is the presence is in 2 places?
No. Look at the code again. The first argument is a string describing what happened (in this case it's "FRIEND_ONLINE") and indicating which global string to use for the actual displayed message, the second argument is an escaped name string for the relevant player (see note below), the 11th argument is a numeric line ID (in this case there isn't a real one since it isn't a real message from the server, but the code expects a number here, so just use 0) and only the 13th argument is the presence ID.

A real event may include other args, but only those ones are actually used in that code path so you can just pass nil values for the rest.

(Note on name strings: Battle.net names are never returned or passed as text, but use a special escape sequence in which the string of zeroes is transformed into the actual name when displayed, but the actual name isn't accessible to addons. The format is "|K" to start the sequence, followed by "f" for the full name or "g" for the first name or "s" for the last name, followed by the presence ID, followed by "|k", followed by a bunch of zeroes that act as placeholders, followed by a final "|k". Extra placeholder zeroes are discarded so it's better to err on the side of too many placeholders than too few. BattleTag friends will only show the BattleTag name regardless of f/g/s, but those flags have meaning for Real ID friends.)

Originally Posted by Niketa View Post
The code I wrote has a table of friends info and when someone logs on (BN_TOON_NAME_UPDATED) it updates info for that person and if the game has changed and is not "App" it prints a login message.
If that's all you want to do, then you're vastly overcomplicating things.

Not tested, but this should probably work, and also do "logout" messages when someone logs out of a game but is still logged into the app:

Code:
local t = {}

local f = CreateFrame("Frame")
f:RegisterEvent("BN_FRIEND_ACCOUNT_OFFLINE")
f:RegisterEvent("BN_FRIEND_TOON_ONLINE")
f:RegisterEvent("BN_TOON_NAME_UPDATED")

f:SetScript("OnEvent", function()
	for i = 1, BNGetNumFriends() do
		local id, name, _, _, _, _, client, online = BNGetFriendInfo(i)
		local prev = t[id]
		if prev and prev ~= client then
			local message = prev == "App" and "FRIEND_ONLINE" or client == "App" and "FRIEND_OFFLINE"
			if message then
				for i = 1, NUM_CHAT_FRAMES do
					ChatFrame_MessageEventHandler(_G["ChatFrame"..i], "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, nil, nil, nil, nil, nil, nil, nil, 0, nil, id)
				end
			end
		end
		t[presenceID] = online and client or nil
	end
end)
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-19-14, 01:36 PM   #5
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
Ok that makes a lot more sense. I think mainly the name string was what confused me and it all just looked like nonsense at a quick glance. I also figured that there must have been an easier approach, but unfortunately at times I forget that some parts of the default UI are available to use.

I look forward to testing your code when I get home because, believe me, I get really frustrated when it doesn't announce these (I lead raids and it makes it hard to invite people if they have to switch toons).

Anyway, I've also been noticing double messages for when someone logs onto the app. I don't think it was from an addon, I will have to check again later, but I did have a part to try to get rid of the extra message with a chat filter (in the original code). Is a chat filter the best way to do it?

Thank you. I know I still have a million things to learn and I appreciate your thorough explanation.
  Reply With Quote
05-19-14, 05:56 PM   #6
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
I had to make a couple changes because of some lua errors (arg4 couldn't be nil and NUM_CHAT_FRAMES was not working).

lua Code:
  1. local events = CreateFrame("Frame")
  2.       events:RegisterEvent("BN_TOON_NAME_UPDATED")
  3.       events:RegisterEvent("BN_FRIEND_TOON_ONLINE")
  4.       events:RegisterEvent("BN_FRIEND_ACCOUNT_OFFLINE")
  5.  
  6. local t = {}
  7.  
  8. events:SetScript("OnEvent", function()
  9.     for x = 1, BNGetNumFriends() do
  10.         local id, name, _, _, _, _, client, online = BNGetFriendInfo(x)
  11.         local prev = t[id]
  12.         if prev and prev ~= client then
  13.             local message = prev == "App" and "FRIEND_ONLINE" or client == "App" and "FRIEND_OFFLINE"
  14.             if message then
  15.                 for i = 1, NUM_CHAT_WINDOWS do
  16.                     ChatFrame_MessageEventHandler(_G["ChatFrame"..i], "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, 0, nil, nil, nil, nil, nil, nil, 0, nil, id)
  17.                 end
  18.             end
  19.         end
  20.         t[id] = online and client or nil
  21.     end
  22. end)

It appears to be working so far. However, is there a way for it to display the message showing what game/character they log on? Right now this code is working in that it's outputting the message but for some reason it's showing the login like it was an app login.

For example (we'll use "A" as the app texture and "W" as the WoW texture), say my btag is Niketa and I want to log onto a toon named Rainbowcat.

I log onto the app.
Niketa (A Niketa) has come online.

I then log into WoW and onto Rainbowcat.
Niketa (A Niketa) has come online.

However, I would like it to display the message as if I wasn't logged into the app and I logged in from the normal client:

Niketa (W Rainbowcat) has come online.

Also when I first logged in it posted 12 people had "come online". Is there anything in the code that would have caused this or did 12 of my friends all happen to come online at the same time? lol
I just logged out and back in and 7 people "came online".

Last edited by Niketa : 05-19-14 at 05:58 PM.
  Reply With Quote
05-19-14, 06:19 PM   #7
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,324
Originally Posted by Niketa View Post
Also when I first logged in it posted 12 people had "come online". Is there anything in the code that would have caused this or did 12 of my friends all happen to come online at the same time? lol
I just logged out and back in and 7 people "came online".
When you're loading your addon and it does its first scan, it doesn't have any info of anyone being online. For each friend you have online at that time, it doesn't know any better and pops up messages saying they all just came online. You need to do initialize your last status table with current values when your addon loads so it has data to compare changes to.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 05-19-14 at 06:22 PM.
  Reply With Quote
05-20-14, 02:02 AM   #8
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
It should only send the "event" if the player in question was already online but with a different client. It's possible invalid info is returned while logging in; add some print statements to find out:

Code:
events:SetScript("OnEvent", function(self, event)
	print(event)
	for x = 1, BNGetNumFriends() do
		local id, name, _, _, _, _, client, online = BNGetFriendInfo(x)
		local prev = t[id]
		print(x, id, name, "| Online?", online, "| Client:", client, "| Previously:", prev)
		if prev and prev ~= client then
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-20-14, 07:53 AM   #9
cokedrivers
A Rage Talon Dragon Guard
 
cokedrivers's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2009
Posts: 325
Not sure if your trying to show this on the Battle Net Popup or in stat. You can look at nMinimap, nData, or TukUI, or ElvUI, all the previous add-ons have a friends stat that shows you who is logged in on what toon and can show any of the blizzard games. WoW, Starcraft, Diablo, or the app. Maybe the code can help you on what your looking for.

Coke,
  Reply With Quote
05-20-14, 09:05 AM   #10
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
No, that's not what the OP is looking for. The default friends list shows you which games your friends are logged into; you don't need an addon for that. What OP wants is a "PlayerX has come online" message to be shown when someone who was already logged into the Battle.net desktop app logs into WoW (or another game) since WoW itself only notifies you when someone logs into Battle.net, but not when they log into or out of a specific game while still logged in through the desktop app.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-22-14, 12:30 AM   #11
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
Finally got a chance to look at this again and I think I have it working like I want.

I solved the issue with the login spam by starting off watching only PLAYER_ENTERING_WORLD and registering the other events when that went off after adding all the friends to the table (this seemed to be what fixed it moreso than the events). I checked and BNGetFriendInfo() returns nil for client if the person is offline so there wasn't really a need for checking if they're online or anything of that sorts.

As far as the issue with the message not showing game specific login alerts, that was because we were passing in the presence id as arg13 when we actually needed to pass that the toon id instead.

I added an extra check for printing the message to make sure the chat window is supposed to display those toast alerts first (I actually have a custom window I dedicate to whispers only and it was posting there before I did this).

When a player logs off, I think the message works because it still has a player link since they are on the desktop app so you can differentiate it between a real log off and a game log off but I am not sure if I care much for the spam personally of the log off AND log on. I mainly worry about the log on because usually I will know if I'm waiting for someone to log on but it is helpful to see when they start switching too. I think for my indecisiveness it probably calls for a toggle option and personal preference of whether or not offline messages should display.

lua Code:
  1. local events = CreateFrame("Frame")
  2.       events:RegisterEvent("PLAYER_ENTERING_WORLD")
  3.  
  4. local friends = {}
  5.  
  6. events:SetScript("OnEvent", function(self, event)
  7.     if event == "PLAYER_ENTERING_WORLD" then
  8.         for x = 1, BNGetNumFriends() do
  9.             local id, _, _, _, _, _, client = BNGetFriendInfo(x)
  10.             friends[id] = client
  11.         end
  12.  
  13.         events:RegisterEvent("BN_TOON_NAME_UPDATED")
  14.         events:RegisterEvent("BN_FRIEND_TOON_ONLINE")
  15.         events:RegisterEvent("BN_FRIEND_ACCOUNT_OFFLINE")
  16.     else
  17.         for x = 1, BNGetNumFriends() do
  18.             local id, name, _, _, _, toonid, client = BNGetFriendInfo(x)
  19.             local prev = friends[id]
  20.  
  21.             if prev and prev ~= client then
  22.                 local message = prev == "App" and "FRIEND_ONLINE" or client == "App" and "FRIEND_OFFLINE"
  23.  
  24.                 if message and toonid then
  25.                     for i = 1, NUM_CHAT_WINDOWS do
  26.                         local types = {GetChatWindowMessages(i)}
  27.  
  28.                         for k, v in pairs(types) do
  29.                             if v == "BN_INLINE_TOAST_ALERT" then
  30.                                 ChatFrame_MessageEventHandler(_G["ChatFrame"..i], "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, 0, nil, nil, nil, nil, nil, nil, 0, nil, toonid)
  31.                                 break
  32.                             end
  33.                         end
  34.                     end
  35.                 end
  36.             end
  37.  
  38.             friends[id] = client
  39.         end
  40.     end
  41. end)

Now the only issue I'm having, however is if I am on the app and I log onto a toon, say Rainbowcat again, and I log off WoW and then immediately back onto Rainbowcat, no message is posted. Then, when I log off and back onto Rainbowcat and it posts.

If I started out on Rainbowcat, then logged on Niketa it would post that I logged on Niketa too but it seems that if you log on the same toon twice in a row it doesn't alert the logon.

When I was printing out some of the things, the toonid would be the same for the toon every time so I'm wondering if it's something in the Blizz code that tries to prevent double posts or something?

Anyhow, a quick fix I can think of is just if the message is "FRIEND_ONLINE" to print twice (as below) but it just seems like a workaround to me. Is there a better way to fix it or is that what it's going to come down to?

lua Code:
  1. if message == "FRIEND_ONLINE" then
  2.     ChatFrame_MessageEventHandler(_G["ChatFrame"..i], "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, 0, nil, nil, nil, nil, nil, nil, 0, nil, toonid)
  3. end
  4. ChatFrame_MessageEventHandler(_G["ChatFrame"..i], "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, 0, nil, nil, nil, nil, nil, nil, 0, nil, toonid)

Last edited by Niketa : 05-22-14 at 12:46 AM.
  Reply With Quote
05-22-14, 05:04 AM   #12
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Niketa View Post
I added an extra check for printing the message to make sure the chat window is supposed to display those toast alerts first (I actually have a custom window I dedicate to whispers only and it was posting there before I did this).
Rather than creating all those new tables and looping over all the registered message types, just check if the event is registered on the frame:

Code:
if message and toonid then
	for i = 1, NUM_CHAT_WINDOWS do
		local f = _G["ChatFrame"..i]
		if f:IsEventRegistered("CHAT_MSG_BN_INLINE_TOAST_ALERT") then
			ChatFrame_MessageEventHandler(f, "CHAT_MSG_BN_INLINE_TOAST_ALERT", message, name, nil, 0, nil, nil, nil, nil, nil, nil, 0, nil, toonid)
		end
	end
end
Also, I'd move the toonID check up with the prev check... no sense proceeding to check for a message if there's no toonID.

As for the other problems, I'll see what I can come up with.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-26-14, 06:57 PM   #13
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
Oh that seems a lot easier! lol

So I haven't had too much time to look at it more but it seems to have reverted back to its original glory of spamming upon login so I'm really not sure what to do at this point. Also I think there are times when I'm not seeing people login (I only know because it usually happens to be when someone says their switching, you know the whole reason I made this! lol). Is there another event that fires that I'm missing?
  Reply With Quote
05-26-14, 10:31 PM   #14
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
I haven't had time, either... I did set up some test code, but none of my three Battle.net friends were online at on Thursday night, and I was busy all weekend celebrating the fact that my horrible roommate and his gross girlfriend finally moved out by sitting around in my underwear watching TV. I'll let you know if I figure anything out this week.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
05-26-14, 11:13 PM   #15
Niketa
A Wyrmkin Dreamwalker
 
Niketa's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2013
Posts: 54
LOL That sounds fantastic.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » BNplayer Hyperlink


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off