Thread Tools Display Modes
09/16/20, 07:08 PM   #1
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
Setting Unique Sizes for Group Member Map Pins

I'm attempting to make an addon that lets you change a specific group members pin to make them more distinguishable. I used Votan's Map Pins as a base and from what I've gathered, you can access ZO_MapPin.PIN_DATA and filter by crown, group, and players. What I don't understand is there is a function for choosing a icon and tint, and I was able to customize it so a specific player could have a unique one. However, for size and level, I tried setting them to a function which acted similarly and I get errors (I'm assuming because those two fields only accept an integer that effects all pins of that category). So since it doesn't look like I can change the level and size through a similar means as texture and tint, how else can I change those two values on a per pin basis? Here is a sample of the relevant code:

Lua Code:
  1. function addon.IconFromName(pin)
  2.     if not pin then return "" end
  3.     local unitTag = GetUnitTag(pin)
  4.     if not unitTag then return "" end
  5.  
  6.     AddOverlayIcon(pin, unitTag)
  7.     local name = GetUnitDisplayName(unitTag)
  8.     local info = addon.account.name[name]
  9.     if info ~= nil then
  10.         return info.icon
  11.     end
  12.     return "/esoui/art/mappins/ui-worldmapgrouppip.dds"
  13. end
  14.  
  15. local leader = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
  16. local group = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP]
  17.  
  18. leader.texture = addon.IconFromName
  19. group.texture = addon.IconFromName
  20. leader.tint = addon.TintFromName
  21. group.tint = addon.TintFromName
  22.  
  23. group.size = addon.SizeFromName -- Doesn't work. Only accepts integers
  Reply With Quote
09/17/20, 02:03 PM   #2
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
<emperor>Welcome on the dark side</emperor>

You are right, size is used as a value, only. By default. But by the power of Lua you can intercept accessing properties like "size" to change the returned value dynamically.
For example:
Lua Code:
  1. function addon:HookPOIPins()
  2.     local GetCurrentMapIndex = GetCurrentMapIndex
  3.     local function HookPinSize(data)
  4.         local orgMetaTable = getmetatable(data)
  5.         local orgSize = data.size or 40
  6.         data.size = nil -- Force to ask the metatable
  7.  
  8.         local newMetaTable = {}
  9.         setmetatable(newMetaTable, orgMetaTable)
  10.         local alter = {}
  11.         alter.size = function()
  12.             return GetCurrentMapIndex() == 1 and 1 or orgSize
  13.         end
  14.                 -- more alternates here
  15.  
  16.         newMetaTable.__index = function(data, key)
  17.             return alter[key] and alter[key](data) or newMetaTable[key] -- if alternate exists, call it
  18.         end
  19.         newMetaTable.__newindex = function(data, key, value)
  20.             if key == "size" then
  21.                 orgSize = value
  22.                 return -- Do not set value within table to keep using metatable
  23.             end
  24.             return rawset(data, key, value)
  25.         end
  26.         setmetatable(data, newMetaTable)
  27.     end
  28.     HookPinSize(ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE])
  29.     HookPinSize(ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE_CURRENT_LOC])
  30. end
Of course you have to adapt this to your needs.

Last edited by votan : 09/18/20 at 09:00 AM.
  Reply With Quote
09/22/20, 04:17 PM   #3
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
Originally Posted by votan View Post
<emperor>Welcome on the dark side</emperor>

You are right, size is used as a value, only. By default. But by the power of Lua you can intercept accessing properties like "size" to change the returned value dynamically.
For example:
Lua Code:
  1. function addon:HookPOIPins()
  2.     local GetCurrentMapIndex = GetCurrentMapIndex
  3.     local function HookPinSize(data)
  4.         local orgMetaTable = getmetatable(data)
  5.         local orgSize = data.size or 40
  6.         data.size = nil -- Force to ask the metatable
  7.  
  8.         local newMetaTable = {}
  9.         setmetatable(newMetaTable, orgMetaTable)
  10.         local alter = {}
  11.         alter.size = function()
  12.             return GetCurrentMapIndex() == 1 and 1 or orgSize
  13.         end
  14.                 -- more alternates here
  15.  
  16.         newMetaTable.__index = function(data, key)
  17.             return alter[key] and alter[key](data) or newMetaTable[key] -- if alternate exists, call it
  18.         end
  19.         newMetaTable.__newindex = function(data, key, value)
  20.             if key == "size" then
  21.                 orgSize = value
  22.                 return -- Do not set value within table to keep using metatable
  23.             end
  24.             return rawset(data, key, value)
  25.         end
  26.         setmetatable(data, newMetaTable)
  27.     end
  28.     HookPinSize(ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE])
  29.     HookPinSize(ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE_CURRENT_LOC])
  30. end
Of course you have to adapt this to your needs.
How could I get the players unit tag from this? In your addon you set the texture and color to a function that takes the pin as the parameter and gets the unit tag from that. Is there a similar way to achieve this with the hook?
  Reply With Quote
09/22/20, 04:35 PM   #4
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Wouldn't this just be MAP_PIN_TYPE_PLAYER, MAP_PIN_TYPE_GROUP_LEADER or MAP_PIN_TYPE_GROUP again?

Or what unitTag do you need, and whatfor do you need it?
The unittag for your (the player) is always "player". And the unitTags of the group members will be always the prefix "group" with the suffix n (number 1 to n, where n = GetGroupSize()).
The group leader's tag can be read via GetGroupLeaderUnitTag()

Last edited by Baertram : 09/22/20 at 04:41 PM.
  Reply With Quote
09/22/20, 04:44 PM   #5
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
Originally Posted by Baertram View Post
Wouldn't this just be MAP_PIN_TYPE_PLAYER, MAP_PIN_TYPE_GROUP_LEADER or MAP_PIN_TYPE_GROUP again?

Or what unitTag do you need, and whatfor do you need it?
The unittag for your (the player) is always "player". And the unitTags of the group members will be always the suffix "group" with the suffix n (number 1 to n where n = GetGroupSize()).
The group leader's tag can be achieve via GetGroupLeaderUnitTag()
Ideally the unit tag for group[n] so I can get the display name of that unit. For the functions for texture and color I was getting the users display name from the pins unit tag and checking if a table had that username as a key with custom textures and colors. I'm trying to do something similar for size.

Lua Code:
  1. local function GetUnitTag(pin)
  2.     local unitTag = pin:GetUnitTag()
  3.     if unitTag then g_activeGroupPins[unitTag] = pin end
  4.     return unitTag
  5. end
  6.  
  7. function addon:ApplySettings()
  8.     local group = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP]
  9.  
  10.     group.texture = addon.IconFromNamee
  11.     group.tint = addon.TintFromName
  12.  
  13.     self:ColorUpdate(true)
  14. end
  15.  
  16.  
  17. function addon.IconFromName(pin)
  18.     if not pin then return "" end
  19.     local unitTag = GetUnitTag(pin)
  20.     if not unitTag then return "" end
  21.  
  22.     AddOverlayIcon(pin, unitTag)
  23.     local name = GetUnitDisplayName(unitTag)
  24.     local info = addon.account.name[name]
  25.     if info ~= nil then
  26.         return info.icon
  27.     end
  28.     return "/esoui/art/mappins/ui-worldmapgrouppip.dds"
  29. end
  Reply With Quote
09/22/20, 04:51 PM   #6
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
I'm essentially trying to figure out where the pin parameter passed to IconFromName comes from and how I can access it in my hook for size

Lua Code:
  1. function addon:HookPOIPins()
  2.     local function HookPinSize(data)
  3.         local orgMetaTable = getmetatable(data)
  4.         local orgSize = data.size or 32
  5.         local orgLevel = data.level or 150
  6.         data.size = nil -- Force to ask the metatable
  7.         -- data.level = nil
  8.  
  9.         local newMetaTable = {}
  10.         setmetatable(newMetaTable, orgMetaTable)
  11.         local alter = {}
  12.  
  13.         alter.size = function(pin)
  14.                         -- Ideally I'd like to do a similar check here as in IconFromName
  15.             if nil then
  16.                 return 60
  17.             end
  18.             return orgSize
  19.         end
  20.  
  21.         newMetaTable.__index = function(data, key)
  22.             return alter[key] and alter[key](data) or newMetaTable[key] -- if alternate exists, call it
  23.         end
  24.  
  25.  
  26.         setmetatable(data, newMetaTable)
  27.     end
  28.     HookPinSize(ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP])
  29. end
  Reply With Quote
09/22/20, 05:00 PM   #7
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Code:
Ideally the unit tag for group[n]
Read my last answer then?

And maybe check the ESOUIDocumentationPxx.txt for current "Stonethorn" API:
https://www.esoui.com/forums/attachm...5&d=1598294293

There exist several GetUnit and Displayname etc. functions you are able to use.


And if I understand the code corectly "pin" is a mappin, so pin will be e.g. something like
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
So pin:GetUnitTag() would be something like
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]:GetUnitTag()

But this should also return the same as GetGroupLeaderUnitTag() then, imo


Edit:
After checking votan's addon code:

Lua Code:
  1. addon.IconMemberSimple = function(pin) GetUnitTag(pin) return iconMember end
This is a function accepting a pin as parameter.
The function is assigned in the settings to e.g.
Lua Code:
  1. if settings.pveIcon == const.Simple then
  2.             leader.texture = addon.IconLeaderSimple

So leader.texture will be the function accepting the pin.
You need to search where leader.texture is used then and where the pin parameter comes from.

eh voila:
Lua Code:
  1. local leader = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
As I though above, this ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER] should be the "pin".
Whenever this pin (leader, or ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]) will update it's texture it will call the function assigned to it (addon.IconLeaderSimple) passing in itsself (the "pin" parameter).
At least this is what I understood.


Try to use the addon merTorchbug or zgoo to inspect ingame the variable
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
via e.g.
/tbug ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
You'll see the possible functions and variables of it then in a table grid view, and below __index you see other functions etc. which are from "parent classes" of this variable/table, and so on.

You'll understand more easily what function belongs where and what value is updated when this way, at least this is what I did :-)

Last edited by Baertram : 09/22/20 at 05:09 PM.
  Reply With Quote
09/22/20, 05:18 PM   #8
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
Originally Posted by Baertram View Post
Code:
Ideally the unit tag for group[n]
Read my last answer then?

And maybe check the ESOUIDocumentationPxx.txt for current "Stonethorn" API:
https://www.esoui.com/forums/attachm...5&d=1598294293

There exist several GetUnit and Displayname etc. functions you are able to use.


And if I understand the code corectly "pin" is a mappin, so pin will be e.g. something like
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
So pin:GetUnitTag() would be something like
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]:GetUnitTag()

But this should also return the same as GetGroupLeaderUnitTag() then, imo


Edit:
After checking votan's addon code:

Lua Code:
  1. addon.IconMemberSimple = function(pin) GetUnitTag(pin) return iconMember end
This is a function accepting a pin as parameter.
The function is assigned in the settings to e.g.
Lua Code:
  1. if settings.pveIcon == const.Simple then
  2.             leader.texture = addon.IconLeaderSimple

So leader.texture will be the function accepting the pin.
You need to search where leader.texture is used then and where the pin parameter comes from.

eh voila:
Lua Code:
  1. local leader = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
As I though above, this ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER] should be the "pin".
Whenever this pin (leader, or ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]) will update it's texture it will call the function assigned to it (addon.IconLeaderSimple) passing in itsself (the "pin" parameter).
At least this is what I understood.


Try to use the addon merTorchbug or zgoo to inspect ingame the variable
ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
via e.g.
/tbug ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]
You'll see the possible functions and variables of it then in a table grid view, and below __index you see other functions etc. which are from "parent classes" of this variable/table, and so on.

You'll understand more easily what function belongs where and what value is updated when this way, at least this is what I did :-)
But this would work for the pin type of group leader because there is only 1, right? When I set a variable in my addons namespace to what is received as pin in IconFromName I get a table that seems to mimic the object in mappins.lua. When I do the same for what is passed to the hook (ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP]), I get a table containing only 4 items (size, level, texture, and tint) which brings me back to the issue of I can't change that size since it doesn't accept a callback. I can only change the size for all group member pins, not a specific player.
  Reply With Quote
09/22/20, 05:24 PM   #9
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32


groupPin and leaderPin are the result of:
Lua Code:
  1. addon.groupPin = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP]
  2. addon.leaderPin = ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP_LEADER]

pinData is the result of doing the same thing in IconFromName with the pin parameter. I'm essentially trying to figure out how to get the entire pin object from my hooks size function so I can adjust it individually. If I were to randomly generate a size, each players pin would be a different size and that removes the issue of the global change if I did it from ZO_MapPin.PIN_DATA[MAP_PIN_TYPE_GROUP]. But how could I do it for a specific player as opposed to a random number? The most direct approach I thought of was figuring out how to access the pin parameter from the hook and calling GetUnitTag() of that pin. If it isn't possible, how else could I change the size for a specfic player's pin?

Last edited by QuantumPie : 09/22/20 at 05:27 PM.
  Reply With Quote
09/22/20, 06:37 PM   #10
QuantumPie
AddOn Author - Click to view addons
Join Date: Sep 2019
Posts: 32
I guess a better approach to figuring this out is I know where PIN_DATA is declared. Looking at various keys, MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE takes a function for the texture and tint and MAP_PIN_TYPE_FAST_TRAVEL_WAYSHRINE takes its level as a function (which I didn't realize was possible but I now have the level being set per player working). But from the looks of it nothing takes a function for size and if I try to do so myself, I get an error. As for the PIN_DATA structure, how can I determine where its being told which fields can and cannot accept a function, and where the parameters are being passed? If I can figure out where that is, I then know where the pin object is coming from
  Reply With Quote
09/22/20, 06:49 PM   #11
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Try this function if you maybe got the ZO_MapPin's control
https://github.com/esoui/esoui/blob/...ppin.lua#L1683

Else try merTorchbug as I said as it's more easy to see the metatables and "parent class" functions and values in it (at the __index line), at least for me, then within zgoo.

Or wait for Votan to help you as he is more in the code of this stuff
  Reply With Quote
09/23/20, 09:21 AM   #12
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
Ok. The next hint:
You have to pre-hook ZO_MapPin.UpdateSize(self)

Lua Code:
  1. function ZO_MapPin:UpdateSize()
  2. -- here your pre-hook saved the last use pin: lastPin = self (lastPin is declared outside the hook function, like orgSize
  3.         local singlePinData = ZO_MapPin.PIN_DATA[self.m_PinType]
  4.         if singlePinData ~= nil then
  5.             -- There are two passes on setting the size...it could also be set when SetLocation is called because that takes a pin radius.
  6.             local control = self:GetControl()
  7.             local hasNonZeroRadius = self.radius and self.radius > 0
  8.             local baseSize = singlePinData.size or CONSTANTS.DEFAULT_PIN_SIZE -- here the altered "size" uses lastPin to return a value based on lastPin:GetUnitTag().
  9. ...
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » Setting Unique Sizes for Group Member Map Pins

Thread Tools
Display Modes

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