Thread Tools Display Modes
04/10/14, 11:24 AM   #1
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Problem Creating Map Pins ... Still

Still trying to fathom how the map pins appear on the map but so far I haven't figured it out. Perhaps someone with access to the extra information can point out where I am going wrong. I've been looking at Shinni's code as a guide and have slowly rewritten what I thought was how it should be done but as the screenshot shows no pin on the map. So I must be missing something somewhere.

Here is the code I have running at the moment. I have deliberately used the PlayerActivatedEvent instead of AddonLoaded so that I can debug my way through it. I know you probably can't give us too much information on this but a nudge into what is missing to make it work would be great.

Lua Code:
  1. -- Values used often so created variables for them
  2. local addonName = "XrysMapPins"
  3. local addonVersion = "1.0.0"
  4.  
  5. -- References to System and Manager objects
  6. local ChatMsg = CHAT_SYSTEM
  7. local EventMgr = EVENT_MANAGER
  8. local WindowMgr = WINDOW_MANAGER
  9.  
  10. ----------[[ TradeSkill Info ]]----------------
  11. local TradeSkillNames = {}
  12. local TradeSkills = {}
  13.  
  14. local function InitTradeSkillInfo()
  15.     local skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_ALCHEMY)
  16.     local skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  17.     local abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  18.     TradeSkills[CRAFTING_TYPE_ALCHEMY] = { Name = skillName, Icon = abilityIcon }
  19.  
  20.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_BLACKSMITHING)
  21.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  22.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  23.     TradeSkills[CRAFTING_TYPE_BLACKSMITHING] =  { Name = skillName, Icon = abilityIcon }
  24.  
  25.  
  26.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_CLOTHIER)
  27.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  28.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  29.     TradeSkills[CRAFTING_TYPE_CLOTHIER] =   { Name = skillName, Icon = abilityIcon }
  30.  
  31.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_ENCHANTING)
  32.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  33.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  34.     TradeSkills[CRAFTING_TYPE_ENCHANTING] =     { Name = skillName, Icon = abilityIcon }
  35.  
  36.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_PROVISIONING)
  37.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  38.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  39.     TradeSkills[CRAFTING_TYPE_PROVISIONING] =   { Name = skillName, Icon = abilityIcon }
  40.    
  41.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_WOODWORKING)
  42.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  43.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  44.     TradeSkills[CRAFTING_TYPE_WOODWORKING] =    { Name = skillName, Icon = abilityIcon }
  45.  
  46.     for i,v in ipairs(TradeSkills) do
  47.         table.insert(TradeSkillNames,v.Name)
  48.     end
  49. end
  50. --------------------------------------------------------------
  51.  
  52. -----------[[ Custom Map Pin Stuff ]]---------------------
  53. local CustomMapPins = ZO_WorldMapPins:Subclass()
  54.  
  55. function CustomMapPins:New(...)
  56.     local pinObject = ZO_WorldMapPins.New(self)
  57.     pinObject:Initialise(...)
  58.     return pinObject
  59. end
  60.  
  61. function CustomMapPins:Initialise(...)
  62.  
  63.     --Default Values
  64.     self.Type = "unspecified"
  65.     self.Name = "Unspecified"
  66.     self.TradeSkill = CRAFTING_TYPE_INVALID
  67.     self.ItemType = ITEMTYPE_NONE
  68.     self.Icon = "EsoUI/Art/MapPins/hostile_pin.dds"
  69.     self.Size = 16
  70.     self.MinSize = 10
  71.     self.Level = 20
  72.     self.IsAnimated = false
  73.     self.InsetX = 0
  74.     self.InsetY = 0
  75.  
  76.     -- Useful data
  77.     self.Info = {}
  78.     -- [pinID]
  79.     -- Type
  80.     -- Name
  81.     -- Icon
  82.  
  83.     -- Pin Data
  84.     self.Data = {}
  85.     --[pinType][zone]
  86.     -- key
  87.     -- zone
  88.     -- x
  89.     -- y
  90.     -- radius
  91.  
  92.     -- Layout Data
  93.     self.Layout = {
  94.         level = self.Level, texture = self.Icon, size = self.Size, minSize = self.MinSize,
  95.         isAnimated = self.IsAnimated, insetX = self.InsetX, insetY = self.InsetY
  96.     }
  97. end
  98.  
  99. function CustomMapPins:List(...)
  100.     local pinType, pinZone = ...
  101.     ChatMsg:AddMessage("Pin Data currently available for type "..pinType.." in zone "..pinZone)
  102.     if not self.Data[pinType] then return end
  103.     if not self.Data[pinType][pinZone] then return end
  104.     for i,v in pairs(self.Data[pinType][pinZone]) do
  105.         ChatMsg:AddMessage(v.zone.." "..tostring(v.x)..", "..tostring(v.y))
  106.     end
  107. end
  108.  
  109. --[[  No special function for this part so assumed it is dealt with by ZO_WorldMapPins version
  110. function CustomMapPins:CreateCustomPinType(...)
  111. end
  112. --]]
  113.  
  114. function CustomMapPins:CreatePin(...)
  115.     local pinType, pinKey, pinZone, pinX, pinY, pinRadius = ...
  116.     self.Data[pinType] = self.Data[pinType] or {}
  117.     self.Data[pinType][pinZone] = self.Data[pinType][pinZone] or {}
  118.     table.insert(self.Data[pinType][pinZone],{
  119.         ["key"] = pinKey,
  120.         ["zone"] = pinZone,
  121.         ["x"] = pinX,
  122.         ["y"] = pinY,
  123.         ["radius"] = pinRadius
  124.     })
  125. end
  126.  
  127. function CustomMapPins:AddCustomPin(...)
  128.     local pinType, drawCallback, resizeCallback, pinLayout, pinTooltipCreator, pinID = ...
  129.  
  130.     self.Info[pinID] = self.Info[pinID] or {}
  131.     table.insert(self.Info[pinID], {
  132.         ["Type"] = pinType,
  133.         ["Name"] = TradeSkills[pinID].Name,
  134.         ["Icon"] = TradeSkills[pinID].Icon
  135.         })
  136.  
  137.     ZO_WorldMap_AddCustomPin(pinType, drawCallback, resizeCallback, pinLayout, pinTooltipCreator)
  138.  
  139.     WORLD_MAP_FILTERS.pvePanel:AddPinFilterCheckBox(5, function() self:RefreshPins(pinType) end)       
  140.     WORLD_MAP_FILTERS.pvePanel.lastControl.label:SetText(GetString("SI_MAPFILTER",5).." ("..TradeSkills[pinID].Name..")")
  141.     WORLD_MAP_FILTERS.pvePanel.lastControl:SetState(1)
  142.     self:SetCustomPinEnabled( pinType, true )
  143.     self:RefreshCustomPins(pinType)
  144. end
  145.  
  146. --[[ No special function for this part so assumed it is dealt with by ZO_WorldMapPins version
  147. function CustomMapPins:FindPin(...)
  148. end
  149. --]]
  150.  
  151. --[[ No special function for this part so assumed it is dealt with by ZO_WorldMapPins version
  152. function CustomMapPins:MapPinLookupToPinKey(...)
  153. end
  154. --]]
  155.  
  156. function CustomMapPins:RefreshCustomPins(...)
  157.     ZO_WorldMap_RefreshCustomPinsOfType( ... )
  158. end
  159.  
  160. function CustomMapPins:RemovePins(...)
  161.     local pinType = ...
  162.     self.Data[pinType] = {}
  163.     self:RefreshPins(pinType)
  164. end
  165.  
  166. function CustomMapPins:SetCustomPinEnabled(...)
  167.     ZO_WorldMap_SetCustomPinEnabled( ... )
  168. end
  169.  
  170. --[[ No special function for this part so assumed it is dealt with by ZO_WorldMapPins version
  171. function CustomMapPins:UpdatePinsForMapSizeChange(...)
  172. end
  173. --]]
  174.  
  175. function CustomMapPins:IsCustomPinEnabled(...)
  176.     return ZO_WorldMap_IsCustomPinEnabled(...)
  177. end
  178.  
  179. function CustomMapPins:IsPinGroupShown(...)
  180.     return ZO_WorldMap_IsPinGroupShown(...)
  181. end
  182.  
  183. local XMPins = CustomMapPins:New()
  184. --------------------------------------------------------------
  185.  
  186. ------------------------[[ UI Stuff ]]------------------------
  187. local function CreateTopLevelWindow(name)
  188.     local tlw = WindowMgr:CreateTopLevelWindow(name)
  189.     tlw:SetMovable(true)
  190.     tlw:SetMouseEnabled(true)
  191.     tlw:SetDimensions(200,100)
  192.     tlw:SetAnchor(CENTER)
  193.  
  194.     tlw.BackGround = WindowMgr:CreateControlFromVirtual(nil,tlw,"ZO_DefaultBackdrop")
  195.     tlw.BackGround:SetAnchorFill(tlw)
  196.     tlw.BackGround:SetAlpha(0.8)
  197.     tlw.BackGround:SetHidden(false)
  198.  
  199.     return tlw
  200. end
  201.  
  202. local function CreateDropDown(name,parent,data,selected,callback)
  203.     local combo = WindowMgr:CreateControlFromVirtual(parent:GetName()..name,parent,"ZO_StatsDropdownRow")
  204.     combo:SetAnchor(CENTER)
  205.     combo:SetResizeToFitDescendents(true)
  206.  
  207.     combo.selected = combo.name
  208.  
  209.     combo.dropdown = combo.dropdown
  210.     combo.dropdown:SetFont("ZoFontBookScroll")
  211.     if selected then combo.dropdown:SetSelectedItem(selected) end
  212.  
  213.     combo.dropdown.SetSelectedIndex = function(self,value)
  214.         self.SelectedIndex = nil
  215.         for i = 1,#data do
  216.             if data[i] == value then
  217.                 self.SelectedIndex = i
  218.                 break
  219.             end
  220.         end
  221.     end
  222.  
  223.     combo.dropdown.GetSelectedIndex = function(self)
  224.         return self.SelectedIndex
  225.     end
  226.  
  227.     combo.dropdown.OnSelect = function(self,value)
  228.         self:SetSelectedItem(value)
  229.         self:SetSelectedIndex(value)
  230.         if callback then callback(value) end
  231.     end
  232.  
  233.     for i = 1,#data do
  234.         local entry = combo.dropdown:CreateItemEntry(data[i],combo.dropdown.OnSelect)
  235.         combo.dropdown:AddItem(entry)
  236.     end
  237.  
  238.     combo.GetSelectedInfo = function(self)
  239.         return self.dropdown:GetSelectedItem(),self.dropdown:GetSelectedIndex()
  240.     end
  241.  
  242.     combo:SetHidden(false)
  243.     return combo
  244. end
  245.  
  246. local function CreateButton(name,parent,text,callback)
  247.     local button = WindowMgr:CreateControlFromVirtual(parent:GetName()..name,parent,"ZO_DefaultButton")
  248.     button:SetAnchor(BOTTOMLEFT)
  249.     button:SetHandler("OnClicked",
  250.         function(self)
  251.             if callback then callback() end
  252.         end)
  253.     button:SetHidden(false)
  254.     return button
  255. end
  256.  
  257. local function InitUI()
  258.     local testTLW = CreateTopLevelWindow("XrysMapPins_TLW")
  259.     testTLW:SetDimensions(200,400)
  260.  
  261.     local MapPinCombo = CreateDropDown("MapPinTypes",testTLW,TradeSkillNames,nil,function(value) end)
  262.     MapPinCombo:SetDimensions(150,50)
  263.     MapPinCombo:SetAnchor(TOP)
  264.  
  265.     local PinTexture = WindowMgr:CreateControl(nil,testTLW,CT_TEXTURE)
  266.     PinTexture:SetDimensions(200,200)
  267.     PinTexture:SetAnchor(CENTER)
  268.     PinTexture:SetHidden(false)
  269.  
  270.     local PutMapPinButton = CreateButton("MapPinButton",testTLW,nil, function(value)
  271.         local pinType,pinID = MapPinCombo:GetSelectedInfo()
  272.         PinTexture:SetTexture(TradeSkills[pinID].Icon)
  273.         SetMapToPlayerLocation()
  274.         local pinZone = GetMapName()
  275.         local pinX,pinY,pinHeading = GetMapPlayerPosition("player")    
  276.         local pinTag = { ["id"] = pinID, ["type"] = pinType, ["zone"] = pinZone, ["x"] = pinX, ["y"] = pinY }
  277.         XMPins:CreatePin(pinType, pinTag, pinZone, pinX, pinY, nil)
  278.         XMPins:RefreshCustomPins(pinType)
  279.         XMPins:List(pinType,pinZone)
  280.     end )
  281.     PutMapPinButton:SetAnchor(BOTTOM)
  282.     PutMapPinButton:SetDimensions(50,50)
  283. end
  284. ------------------------------------------------------------------------
  285.  
  286. local function InitPinTypes()
  287.     for i,v in ipairs(TradeSkills) do
  288.         local pinType = v.Name
  289.         local pinID = i
  290.         local drawCallback = function() XMPins:RefreshCustomPins(pinType) end
  291.         local resizeCallback = function() XMPins:RefreshCustomPins(pinType) end    
  292.         local pinLayoutData = {}
  293.         for i,v in pairs(XMPins.Layout) do
  294.             pinLayoutData[i] = v
  295.         end
  296.         pinLayoutData.texture = TradeSkills[pinID].Icon
  297.         local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(TradeSkills[pinID].skillName) end, tooltip = InformationTooltip }
  298.         XMPins:AddCustomPin(pinType,drawCallback,resizeCallback,pinLayoutData,pinTooltipCreator,pinID)
  299.     end
  300. end
  301.  
  302. local function PlayerActivated(eventID)
  303.     EventMgr:UnregisterForEvent(addonName,eventID)
  304.     ChatMsg:AddMessage(string.format("%s %s Loaded",addonName,addonVersion))
  305.     InitTradeSkillInfo()
  306.     InitUI()
  307.     InitPinTypes()
  308. end
  309.  
  310. -- Our Addon is loaded so we can start work
  311. local function AddOnLoaded(eventID,addon)
  312.     if addon ~= addonName then return end
  313.     EventMgr:UnregisterForEvent(addonName,eventID)
  314.     InitSavedVariables()
  315.     EventMgr:RegisterForEvent( addonName ,EVENT_PLAYER_ACTIVATED , PlayerActivated )
  316. end
  317.  
  318. -- Track addons loading
  319. EventMgr:RegisterForEvent( addonName ,EVENT_ADD_ON_LOADED , AddOnLoaded )
Attached Thumbnails
Click image for larger version

Name:	Screenshot_20140410_181239.jpg
Views:	546
Size:	312.0 KB
ID:	116  
  Reply With Quote
04/10/14, 12:01 PM   #2
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
Lua Code:
  1. ZO_WorldMap_AddCustomPin(pinType, drawCallback, resizeCallback, pinLayout, pinTooltipCreator)

pinType should be a unique name for your pin type.
eg "Xrystal_Wood" if you want this pin type to represent wood harvest nodes for your gatherer.

drawCallback is a function which receives a pin manager as argument. this function is called wenever the map is drawn. it's supposed to create your map pins eg:

Lua Code:
  1. function(pinManager)
  2.     for _, harvestNode in pairs( myHarvestNodes ) do
  3.         pinManager:CreatePin( _G["Xrystal_Wood"], harvestNode, harvestNode.x, harvestNode.y)
  4.     end
  5. end

note that zenimax's scripts internally use integers for pinTypes. the internal representation of the pin type "Xrystal_Wood" is saved in _G["Xrystal_Wood"].
the second argument of CreatePin is the pintag. you can use this to pass additional informations to later layout/tooltip functions

resizeCallback is called whenever the map size changes, eg when the player zooms in.
I always use nil as normal pins don't need to resize.
this function gets 2 arguments: the new width and height.

pinLayout is a table which represents the layout of all pins of this pin type
it needs a key called texture for the pin texture, a key called level which determines which pin is drawn above the other. it can also have an optinal key called size.
example:
Lua Code:
  1. { texture = 'MyAddon/niceTexture.dds', level = 20, size = 30 }


pinTooltipCreator is another table which handles the tooltip obviously.
example:
Lua Code:
  1. {
  2.     creator = function( pin )
  3.         InformationTooltip:AddLine( pin.m_PinTag.tooltip )
  4.     end,
  5.     tooltip = InformationTooltip
  6. }
tooltip says, which tooltip window is to be used (don't know what other there are besides of InformationTooltip)
creator is a function which receives the pin and adds text to the tooltip. remember the pinTag (2nd argument of pinManager:CreatePin)? here you can use the additional data via pin.m_PinTag


to enable a pin call
Lua Code:
  1. ZO_WorldMap_SetCustomPinEnabled(_G[pinType], bool )
remember to use _G[pinType]!

if you want to refresh the pins (because you changed layout information or something like that) call
Lua Code:
  1. ZO_WorldMap_RefreshCustomPinsOfType( _G[pinType] )
or
Lua Code:
  1. ZO_WorldMap_RefreshCustomPinsOfType()
if you want to refresh all pin types




now back to your code:
Lua Code:
  1. local pinType = v.Name
  2.             local pinID = i
  3.             local drawCallback = function() XMPins:RefreshCustomPins(pinType) end
  4.             local resizeCallback = function() XMPins:RefreshCustomPins(pinType) end    
  5.             local pinLayoutData = {}
  6.             for i,v in pairs(XMPins.Layout) do
  7.                 pinLayoutData[i] = v
  8.             end
  9.             pinLayoutData.texture = TradeSkills[pinID].Icon
  10.             local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(TradeSkills[pinID].skillName) end, tooltip = InformationTooltip }
  11.             XMPins:AddCustomPin(pinType,drawCallback,resizeCallback,pinLayoutData,pinTooltipCreator,pinID)

i'd expect a buffer overflow here.
drawCallback is called when the map is refreshed but your drawCallback forces the map to refresh again.
the only reason your game didn't crash is because you didn't use _G[pinType] in the XMPins:RefreshCustomPins argument

Last edited by Shinni : 04/10/14 at 12:06 PM.
  Reply With Quote
04/10/14, 12:14 PM   #3
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Thanks Shinni,

I deliberately removed the _G[] around the pinTypes on the 2 functions that used it to see if it triggered an error but it didn't which I was quite surprised with. I will make the appropriate changes and see the result.

Admittedly at present the pinType isn't exactly unique, but it shouldn't be affecting anything else I have loaded seeing as no other pins with the basic tradeskill names seem to exist. Obviously I would prefix it to make it unique.

The pinManager part was confusing me but I will try to re-introduce it into my code and see if it improves things.

Thanks for letting me know what is in the resizeCallback function. At present all my callbacks do is refresh the pins regardless of what happened. The reason being is that at present I am throwing the data straight into the pin table as a quick test on how this all works. Obviously in the real scenario I would have the drawCallback re-read the saved variable data and place the appropriate information into the pin table for use by the pin manager.

I think I went over zealous with what looked like layout data after looking at your code comments so I set up some default values to use. Maybe not a good idea. Will revert back to level and texture and see how that works.

Other than that I think I am square with the code now and if anything the revisiting of the code and rewriting I have done has helped me see what is what.

Your help is much appreciated. I will have to make these changes later on and will report the results. Crossing fingers it will resolve my problems and I can move onto the next TODO on my list of things for my gatherer addon.
  Reply With Quote
04/10/14, 07:54 PM   #4
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Hmm,

Still not working for me ..

1. Made sure ZO_WorldMap functions used _G[pinType]
2. Made sure pinType was prefixed with something to make it unique
3. Draw Callback function now uses pinManager parameter and cycles through the pinData table and calls pinManager:CreatePin with the data it holds, and removes the RefreshCustomPins function so it doesn't get into that loop ( yes it has happened before, had to crash out a few times ).
4. Set Resize Callback function to nil for the time being
5. Pin Layout table now just has texture, level and size values
6. Added tooltip value to tag/key table to use in the tooltip part of the AddCustomPin function.

Obviously something else is missing in my code somewhere or in the wrong place.

Don't think I missed anything, and did find a few bits of code with the wrong name that clearly isn't being used at present and didn't pick up on it. Here's the updated code with the above changes, minus the code that has been commented out. From your explanation I thought these changes would resolve it but there must be something else. I have tried both MapName and GetUnitZone functions as they sometimes return different values, just in case that was the reason.

My understanding of the functionality is as follows:

1. Subclass an appropriate object ( I have tried both ZO_WorldMapPins and ZO_Object )
2. New the subclassed variable into the usable variable
3. Initialise the pin types including a callback function,texture,tooltip etc and a call to the customised AddCustomPin function to add your data via ZO_WorldMap_AddCustomPin
4. Callback function to cycle through the pin data and create the individual pins at the stored location using the pin manager passed to the function whenever the map is redrawn
5. While still in the initialisation stage initialise the equivalent filters use your customised SetCustomPinEnabled and RefreshCustomPins functions to enable and refresh your pins using the ZO_WorldMap_RefreshCustomPinsOfType(_G[pinType]) and ZO_WorldMap_SetCustomPinEnabled(_G[pinType]) functions.
6. Not got as far as seeing how the RemovePins function works to know where that fits in.

Did I miss anything out ? I hate it when something so apparently simple causes me no end of problems. Especially when I took this week off in the hopes of getting this fixed and catching up with the levelling by actually playing.

Lua Code:
  1. -- Values used often so created variables for them
  2. local addonName = "XrysMapPins"
  3. local addonVersion = "1.0.0"
  4. local addonPrefix = "XMP"
  5.  
  6. -- References to System and Manager objects
  7. local ChatMsg = CHAT_SYSTEM
  8. local EventMgr = EVENT_MANAGER
  9. local WindowMgr = WINDOW_MANAGER
  10.  
  11. --------------------------------------------------------------
  12. local TradeSkillNames = {}
  13. local TradeSkills = {}
  14.  
  15. local function InitTradeSkillInfo()
  16.     local skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_ALCHEMY)
  17.     local skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  18.     local abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  19.     TradeSkills[CRAFTING_TYPE_ALCHEMY] = { Name = skillName, Icon = abilityIcon }
  20.  
  21.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_BLACKSMITHING)
  22.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  23.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  24.     TradeSkills[CRAFTING_TYPE_BLACKSMITHING] =  { Name = skillName, Icon = abilityIcon }
  25.  
  26.  
  27.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_CLOTHIER)
  28.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  29.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  30.     TradeSkills[CRAFTING_TYPE_CLOTHIER] =   { Name = skillName, Icon = abilityIcon }
  31.  
  32.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_ENCHANTING)
  33.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  34.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  35.     TradeSkills[CRAFTING_TYPE_ENCHANTING] =     { Name = skillName, Icon = abilityIcon }
  36.  
  37.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_PROVISIONING)
  38.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  39.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  40.     TradeSkills[CRAFTING_TYPE_PROVISIONING] =   { Name = skillName, Icon = abilityIcon }
  41.    
  42.     skillType,skillIndex = GetCraftingSkillLineIndices(CRAFTING_TYPE_WOODWORKING)
  43.     skillName,skillRank  = GetSkillLineInfo(skillType, skillIndex)
  44.     abilityName,abilityIcon = GetSkillAbilityInfo(skillType, skillIndex, 1)
  45.     TradeSkills[CRAFTING_TYPE_WOODWORKING] =    { Name = skillName, Icon = abilityIcon }
  46.  
  47.     for i,v in ipairs(TradeSkills) do
  48.         table.insert(TradeSkillNames,v.Name)
  49.     end
  50. end
  51. --------------------------------------------------------------
  52.  
  53. --------------------------------------------------------------
  54. local CustomMapPins = ZO_WorldMapPins:Subclass()
  55.  
  56. function CustomMapPins:New(...)
  57.     local pinObject = ZO_WorldMapPins.New(self)
  58.     pinObject:Initialise(...)
  59.     return pinObject
  60. end
  61.  
  62. function CustomMapPins:Initialise(...)
  63.  
  64.     --Default Values
  65.     self.Type = addonPrefix.."_Unspecified"
  66.     self.Name = "Unspecified"
  67.     self.TradeSkill = CRAFTING_TYPE_INVALID
  68.     self.ItemType = ITEMTYPE_NONE
  69.     self.Icon = "EsoUI/Art/MapPins/hostile_pin.dds"
  70.     self.Size = 16
  71.     self.Level = 20
  72.  
  73.     -- Useful data
  74.     self.Info = {}
  75.  
  76.     -- Pin Data
  77.     self.Data = {}
  78.  
  79.     -- Layout Data
  80.     self.Layout = { level = self.Level, texture = self.Icon, size = self.Size }
  81. end
  82.  
  83. function CustomMapPins:List(...)
  84.     local pinType, pinZone = ...
  85.     ChatMsg:AddMessage("Pin Data currently available for type "..pinType.." in zone "..pinZone)
  86.     if not self.Data[pinType] then return end
  87.     if not self.Data[pinType][pinZone] then return end
  88.     for i,v in pairs(self.Data[pinType][pinZone]) do
  89.         ChatMsg:AddMessage(v.zone.." "..tostring(v.x)..", "..tostring(v.y))
  90.     end
  91. end
  92.  
  93. function CustomMapPins:CreatePin(...)
  94.     local pinType, pinKey, pinZone, pinX, pinY, pinRadius = ...
  95.     self.Data[pinType] = self.Data[pinType] or {}
  96.     self.Data[pinType][pinZone] = self.Data[pinType][pinZone] or {}
  97.     table.insert(self.Data[pinType][pinZone],{
  98.         ["key"] = pinKey,
  99.         ["zone"] = pinZone,
  100.         ["x"] = pinX,
  101.         ["y"] = pinY,
  102.         ["radius"] = pinRadius
  103.     })
  104. end
  105.  
  106.  
  107. function CustomMapPins:AddCustomPin(...)
  108.     local pinType, drawCallback, resizeCallback, pinLayout, pinTooltipCreator, pinID = ...
  109.  
  110.     self.Info[pinID] = self.Info[pinID] or {}
  111.     table.insert(self.Info[pinID], {
  112.         ["Type"] = pinType,
  113.         ["Name"] = TradeSkills[pinID].Name,
  114.         ["Icon"] = TradeSkills[pinID].Icon
  115.         })
  116.  
  117.     ZO_WorldMap_AddCustomPin(pinType, drawCallback, resizeCallback, pinLayout, pinTooltipCreator)
  118.  
  119.     WORLD_MAP_FILTERS.pvePanel:AddPinFilterCheckBox(5, function() self:RefreshCustomPins(pinType) end)     
  120.     WORLD_MAP_FILTERS.pvePanel.lastControl.label:SetText(GetString("SI_MAPFILTER",5).." ("..TradeSkills[pinID].Name..")")
  121.     WORLD_MAP_FILTERS.pvePanel.lastControl:SetState(1)
  122.     self:SetCustomPinEnabled( pinType, true )
  123.     self:RefreshCustomPins(pinType)
  124. end
  125.  
  126. function CustomMapPins:RemovePins(...)
  127.     local pinType = ...
  128.     self.Data[pinType] = {}
  129.     self:RefreshCustomPins(pinType)
  130. end
  131.  
  132. function CustomMapPins:RefreshCustomPins(pinType)
  133.     ZO_WorldMap_RefreshCustomPinsOfType(_G[pinType])
  134. end
  135.  
  136. function CustomMapPins:SetCustomPinEnabled(pinType)
  137.     ZO_WorldMap_SetCustomPinEnabled(_G[pinType])
  138. end
  139.  
  140. function CustomMapPins:IsCustomPinEnabled(pinType)
  141.     return ZO_WorldMap_IsCustomPinEnabled(_G[pinType])
  142. end
  143.  
  144. function CustomMapPins:IsPinGroupShown(pinType)
  145.     return ZO_WorldMap_IsPinGroupShown(_G[pinType])
  146. end
  147.  
  148. local XMPins = CustomMapPins:New()
  149. --------------------------------------------------------------
  150.  
  151. -----------------------------------------------------------------------
  152. local function CreateTopLevelWindow(name)
  153.     local tlw = WindowMgr:CreateTopLevelWindow(name)
  154.     tlw:SetMovable(true)
  155.     tlw:SetMouseEnabled(true)
  156.     tlw:SetDimensions(200,100)
  157.     tlw:SetAnchor(CENTER)
  158.  
  159.     tlw.BackGround = WindowMgr:CreateControlFromVirtual(nil,tlw,"ZO_DefaultBackdrop")
  160.     tlw.BackGround:SetAnchorFill(tlw)
  161.     tlw.BackGround:SetAlpha(0.8)
  162.     tlw.BackGround:SetHidden(false)
  163.  
  164.     return tlw
  165. end
  166.  
  167. local function CreateDropDown(name,parent,data,selected,callback)
  168.     local combo = WindowMgr:CreateControlFromVirtual(parent:GetName()..name,parent,"ZO_StatsDropdownRow")
  169.     combo:SetAnchor(CENTER)
  170.     combo:SetResizeToFitDescendents(true)
  171.  
  172.     combo.selected = combo.name
  173.  
  174.     combo.dropdown = combo.dropdown
  175.     combo.dropdown:SetFont("ZoFontBookScroll")
  176.     if selected then combo.dropdown:SetSelectedItem(selected) end
  177.  
  178.     combo.dropdown.SetSelectedIndex = function(self,value)
  179.         self.SelectedIndex = nil
  180.         for i = 1,#data do
  181.             if data[i] == value then
  182.                 self.SelectedIndex = i
  183.                 break
  184.             end
  185.         end
  186.     end
  187.  
  188.     combo.dropdown.GetSelectedIndex = function(self)
  189.         return self.SelectedIndex
  190.     end
  191.  
  192.     combo.dropdown.OnSelect = function(self,value)
  193.         self:SetSelectedItem(value)
  194.         self:SetSelectedIndex(value)
  195.         if callback then callback(value) end
  196.     end
  197.  
  198.     for i = 1,#data do
  199.         local entry = combo.dropdown:CreateItemEntry(data[i],combo.dropdown.OnSelect)
  200.         combo.dropdown:AddItem(entry)
  201.     end
  202.  
  203.     combo.GetSelectedInfo = function(self)
  204.         return self.dropdown:GetSelectedItem(),self.dropdown:GetSelectedIndex()
  205.     end
  206.  
  207.     combo:SetHidden(false)
  208.     return combo
  209. end
  210.  
  211. local function CreateButton(name,parent,text,callback)
  212.     local button = WindowMgr:CreateControlFromVirtual(parent:GetName()..name,parent,"ZO_DefaultButton")
  213.     button:SetAnchor(BOTTOMLEFT)
  214.     button:SetHandler("OnClicked",
  215.         function(self)
  216.             if callback then callback() end
  217.         end)
  218.     button:SetHidden(false)
  219.     return button
  220. end
  221.  
  222. local function InitUI()
  223.     local testTLW = CreateTopLevelWindow("XrysMapPins_TLW")
  224.     testTLW:SetDimensions(200,400)
  225.  
  226.     local MapPinCombo = CreateDropDown("MapPinTypes",testTLW,TradeSkillNames,nil,function(value) end)
  227.     MapPinCombo:SetDimensions(150,50)
  228.     MapPinCombo:SetAnchor(TOP)
  229.  
  230.     local PinTexture = WindowMgr:CreateControl(nil,testTLW,CT_TEXTURE)
  231.     PinTexture:SetDimensions(200,200)
  232.     PinTexture:SetAnchor(CENTER)
  233.     PinTexture:SetHidden(false)
  234.  
  235.     local PutMapPinButton = CreateButton("MapPinButton",testTLW,nil, function(value)
  236.         local pinType,pinID = MapPinCombo:GetSelectedInfo()
  237.         pinType = addonPrefix.."_"..pinType
  238.         PinTexture:SetTexture(TradeSkills[pinID].Icon)
  239.         SetMapToPlayerLocation()
  240.         local pinZone = GetMapName()
  241.         local pinX,pinY,pinHeading = GetMapPlayerPosition("player")    
  242.         local pinTooltip = TradeSkills[pinID].Name
  243.         local pinTag = { ["id"] = pinID, ["type"] = pinType, ["zone"] = pinZone, ["x"] = pinX, ["y"] = pinY, ["tooltip"] = pinTooltip }
  244.         XMPins:CreatePin(pinType, pinTag, pinZone, pinX, pinY, nil)
  245.         XMPins:RefreshCustomPins(pinType)
  246.         XMPins:List(pinType,pinZone)
  247.     end )
  248.     PutMapPinButton:SetAnchor(BOTTOM)
  249.     PutMapPinButton:SetDimensions(50,50)
  250. end
  251. ------------------------------------------------------------------------
  252.  
  253. local function InitPinTypes()
  254.     for i,v in ipairs(TradeSkills) do
  255.         local pinType = addonPrefix.."_"..v.Name
  256.         local pinID = i
  257.         local drawCallback = function(pinManager)
  258.             SetMapToPlayerLocation()
  259.             local pinZone = GetMapName()
  260.             local harvestData = self.Data[pinType][pinZone]
  261.             for i,v in pairs(harvestData) do
  262.                 pinManager:CreatePin(_G[pinType], v.key, v.zone, v.x, v.y, v.radius)
  263.             end
  264.         end
  265.         local resizeCallback = nil --function(width,height) XMPins:RefreshCustomPins(pinType) end      
  266.         local pinLayoutData = {}
  267.         for i,v in pairs(XMPins.Layout) do
  268.             pinLayoutData[i] = v
  269.         end
  270.         pinLayoutData.texture = TradeSkills[pinID].Icon
  271.         local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(pin.key.tooltip) end, tooltip = InformationTooltip }
  272.         XMPins:AddCustomPin(pinType,drawCallback,resizeCallback,pinLayoutData,pinTooltipCreator,pinID)
  273.     end
  274. end
  275.  
  276. local function PlayerActivated(eventID)
  277.     EventMgr:UnregisterForEvent(addonName,eventID)
  278.     ChatMsg:AddMessage(string.format("%s %s Loaded",addonName,addonVersion))
  279.     InitTradeSkillInfo()
  280.     InitUI()
  281.     InitPinTypes()
  282. end
  283.  
  284. -- Our Addon is loaded so we can start work
  285. local function AddOnLoaded(eventID,addon)
  286.     if addon ~= addonName then return end
  287.     EventMgr:UnregisterForEvent(addonName,eventID)
  288.     EventMgr:RegisterForEvent( addonName ,EVENT_PLAYER_ACTIVATED , PlayerActivated )
  289. end
  290.  
  291. -- Track addons loading
  292. EventMgr:RegisterForEvent( addonName ,EVENT_ADD_ON_LOADED , AddOnLoaded )
  Reply With Quote
04/11/14, 06:32 AM   #5
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
only read the code, didn't test it. i noticed the following:

line 262
pinManager:CreatePin(_G[pinType], v.key, v.zone, v.x, v.y, v.radius)
should be
pinManager:CreatePin(_G[pinType], v.key, v.x, v.y, v.radius)


line 271
local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(pin.key.tooltip) end, tooltip = InformationTooltip }
should be
local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(pin.m_PinTag.tooltip) end, tooltip = InformationTooltip }
  Reply With Quote
04/11/14, 06:41 AM   #6
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Ah, those values are fixed to a specific variable.

I'm guessing then that the pinManager automatically places the co-ords in the correct zone ?

Okay thanks, I'll give those 2 changes a try ..... *crosses fingers for when server comes back up*

Last edited by Xrystal : 04/11/14 at 06:44 AM.
  Reply With Quote
04/11/14, 07:27 AM   #7
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
Originally Posted by Xrystal View Post
I'm guessing then that the pinManager automatically places the co-ords in the correct zone ?
the callback is called everytime a different zone is displayed. you have to handle the zone by yourself.
though you have done that already:
Lua Code:
  1. local drawCallback = function(pinManager)
  2.     SetMapToPlayerLocation()
  3.     local pinZone = GetMapName()
  4.     local harvestData = self.Data[pinType][pinZone]
  5.     for i,v in pairs(harvestData) do
  6.        pinManager:CreatePin(_G[pinType], v.key, v.zone, v.x, v.y, v.radius)
  7.     end
  8. end
you only draw the pins in the current zone.

edit:
i think you have to remove SetMapToPlayerLocation().
if the player changes the currently displayed map (eg right click) the drawCallback is called and immediatly sets the map back to the player's position.
  Reply With Quote
04/11/14, 07:29 AM   #8
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Good spot, still crossing fingers.


edit:
Removed SetMapToPlayerLocation() call in drawCallback
Revised CreatePin and TooltipCreator as per your comments

*sigh* Still no pins. Are you sure I didn't miss anything vital out ?


edit2:
Moved the Filter creation into a separate function and called it before AddCustomPin just in case. I also changed it to

WORLD_MAP_FILTERS.pvePanel:AddPinFilterCheckBox(_G[pinType], function() self:RefreshCustomPins(pinType) end)

so that it would use my pin type rather than the '5' resource reference, just in case that was causing the problem. But nada. Still no pins being displayed.

edit3:
Had to remove above change as it reported an error saying a table didn't exist when you click on the buttons. So now the question arises as to whether it is the filters that are messing things up if changing to my pinType instead of 5.

New filter code as follows, I am assuming the callback function is called when refreshing the filter option so I refreshed the pins there.:

Lua Code:
  1. function CustomMapPins:AddFilter(...)
  2.  
  3.     local pinType,pinID,enable = ...
  4.  
  5.     WORLD_MAP_FILTERS.pvePanel:AddPinFilterCheckBox(5, function() self:RefreshCustomPins(pinType) end)     
  6.     WORLD_MAP_FILTERS.pvePanel.lastControl.label:SetText(GetString("SI_MAPFILTER",5).." ("..TradeSkills[pinID].Name..")")
  7.     WORLD_MAP_FILTERS.pvePanel.lastControl:SetState(1)
  8.     self:SetCustomPinEnabled( pinType, enable )
  9.     self:RefreshCustomPins(pinType)
  10.  
  11. end
  12.  
  13. local function InitPinTypes()
  14.     for i,v in ipairs(TradeSkills) do
  15.         local pinType = addonPrefix.."_"..v.Name
  16.         local pinID = i
  17.         local drawCallback = function(pinManager)
  18.             --SetMapToPlayerLocation()
  19.             local pinZone = GetUnitZone("player") --GetMapName()
  20.             local harvestData = self.Data[pinType][pinZone]
  21.             for i,v in pairs(harvestData) do
  22.                 pinManager:CreatePin(_G[pinType], v.key, v.x, v.y, v.radius)
  23.             end
  24.         end
  25.         local resizeCallback = nil --function(width,height) XMPins:RefreshCustomPins(pinType) end      
  26.         local pinLayoutData = {}
  27.         for i,v in pairs(XMPins.Layout) do
  28.             pinLayoutData[i] = v
  29.         end
  30.         pinLayoutData.texture = TradeSkills[pinID].Icon
  31.         local pinTooltipCreator = { creator = function(pin) InformationTooltip:AddLine(pin.m_PinTag.tooltip) end, tooltip = InformationTooltip }
  32.  
  33.         XMPins:AddFilter(pinType,pinID,true)
  34.         XMPins:AddCustomPin(pinType,drawCallback,resizeCallback,pinLayoutData,pinTooltipCreator,pinID)
  35.     end
  36. end

Last edited by Xrystal : 04/11/14 at 08:54 AM.
  Reply With Quote
04/12/14, 02:46 AM   #9
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
I dont know how the filter worked anymore. Have you tried commenting that out? I cant find anything wrong so i guess its the filters.
Otherwise could you upload the complete addon? Its easier to debug code if i can test it.
  Reply With Quote
04/12/14, 07:02 AM   #10
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Thanks, will tidy up the code and turn off the filter side of things and see if that makes a difference and will sort out something to post up the zip here on this thread rather than as a proper addon. It's only a test addon at the moment that will ultimately go into the gatherer addon once it's up and running.

I'm glad that you can't see anything wrong functionally as it means I at least had the idea right, just that somewhere something is going wrong, probably something silly that doesn't cause an error like my infamous = instead of == rofl. But that was the first thing I checked.

edit: Okay, tidied up code, fixed a couple of visual glitches .. here's the code in its entirety.

Everything seems to work except the drawing of the pin itself. Probably something so simple we'll kick ourselves. Me especially.
Attached Files
File Type: zip XrysMapPins.zip (4.2 KB, 337 views)

Last edited by Xrystal : 04/12/14 at 10:03 AM.
  Reply With Quote
04/13/14, 10:08 AM   #11
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
you called
Lua Code:
  1. self:SetCustomPinEnabled( pinType, true )
but defined
Lua Code:
  1. function CustomMapPins:RefreshCustomPins(pinType)
  2.     ZO_WorldMap_RefreshCustomPinsOfType(_G[pinType])
  3. end

this should be
Lua Code:
  1. function CustomMapPins:RefreshCustomPins(pinType, bool)
  2.     ZO_WorldMap_RefreshCustomPinsOfType(_G[pinType], bool)
  3. end

which then results in an attempt to index nil value error in
Lua Code:
  1. local drawCallback = function(pinManager)
  2.            
  3.             -- Get the zone the player is in
  4.             -- this is how the gatherer addon gets it so hopefully it is correct
  5.             local pinZone = GetUnitZone("player") --GetMapName()
  6.            
  7.             -- Get the existing pin data for the current type and zone
  8.             -- And recreate the pins as we have just redrawn the map
  9.             local harvestData = XMPins.Data[pinType][pinZone]
  10.             for i,v in pairs(harvestData) do
  11.                 pinManager:CreatePin(_G[pinType], v.key, v.x, v.y, v.radius)
  12.             end
  13.         end
as XMPins.Data is still an empty table.
you probably want to iterate over SVData.
  Reply With Quote
04/13/14, 11:08 AM   #12
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Hmm, quite possibly, it's not erroring out. But will investigate those code areas.
  Reply With Quote
04/13/14, 11:51 AM   #13
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Thanks a lot Shinni, that worked.



The problem was that I wasn't validating whether any pin data had been added to the custom pin object before trying to traverse it. Plus the enable function not having its call also use the enable flag.

I knew it must have been something silly once you couldn't see why it wasn't working.
Attached Thumbnails
Click image for larger version

Name:	Screenshot_20140413_184441.jpg
Views:	415
Size:	303.0 KB
ID:	129  
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Problem Creating Map Pins ... Still

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