Thread Tools Display Modes
04/24/14, 08:36 PM   #1
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Help with ZO_SavedVars Syntax

I need to add a single one line value to the HarvestMap.lua that I read first thing when the mod loads. I need to get a boolean value right away first thing.

Lua Code:
  1. Harvest.nodes = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 2, "nodes", { data = {} } )
  2.     if Harvest.settings.account then
  3.         Harvest.settings = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "settings",
  4.         {{{{ A bunch of stuf here }}}}
  5.     }
  6.     else
  7.         Harvest.settings = ZO_SavedVars:New("Harvest_SavedVars", 1, "settings",
  8.         {{{{ A bunch of stuf here }}}}
  9.     }
  10.     end
That is what loads so I get an exception because Lua does not know what the value of Harvest.settings.account is. Harvest settings account is defined with LAM.
Lua Code:
  1. LAM:AddHeader(panelID, "HarvestSettingsHeader", "Account Wide Settings")
  2.  
  3.     LAM:AddCheckbox(panelID, "HarvestMapSettings", "Account Wide Settings", "Enable account Wide Settings",
  4.         function()
  5.             return Harvest.settings.account
  6.         end,
  7.         function( value )
  8.             Harvest.settings.account = value
  9.             ReloadUI()
  10.         end,
  11.     false, nil)
Side question: did I define that correctly with LAM so that the UI Will reload ONLY when a player changes the value?

So what I was looking for was how to have it be something like this:
Lua Code:
  1. ???? Harvest.settings.account = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "accountWideBool", accountWideBool )  {{----The line I want to add ----}}
  2. Harvest.nodes = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 2, "nodes", { data = {} } )
  3.     if Harvest.settings.account then
  4.         Harvest.settings = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "settings",
  5.         {{{{ A bunch of stuf here }}}}
  6.     }
  7.     else
  8.         Harvest.settings = ZO_SavedVars:New("Harvest_SavedVars", 1, "settings",
  9.         {{{{ A bunch of stuf here }}}}
  10.     }
  11.     end
If I don't put any lines that will cause an exception, with LAM the boolean setting will be written to the settings file as "["account"] = false," so I know it will be there at some point. However, I want to get that value, but, if it's not there I want the default to be false. Naturally I can change the AddCheckbox routine in lam to have a different value, like Harvest.accountWidePrefs. I just don't know what to change it to so that it gets the setting right away and doesn't cause an exception.

What is the proper syntax?

Last edited by Sharlikran : 04/24/14 at 08:45 PM.
  Reply With Quote
04/24/14, 08:51 PM   #2
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Aren't you storing the results of Harvest.setting.account in your saved variables?

Are you waiting for EVENT_ADD_ON_LOADED before you actually try to grab stuff from your saved variables?
  Reply With Quote
04/24/14, 08:55 PM   #3
archpoet
Cunning Linguist
 
archpoet's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 19
I've seen several other add-on authors sorely over complicate the SavedVars process, so hopefully I can help.

Basically, what i do in my add-ons is define a master table for all the data that a) I need default values for and b) want to save after reload. Then in my init function I setup the table:

Code:
	A.saved = {
		["addon_visible"] = true,
		["addon_orientation"] = 'v',
		["open_menu_alpha"] = 0.25,
                ["super_important_data"] = {},
       }
Then I load the same object.table as the default to the ZO_SavedVars:NewAccountWide() method.

Code:
A.saved = ZO_SavedVars:NewAccountWide( "Addon_SavedVariables", A.version, "saved", A.saved )
*Then* I do lookups and processing against what might have been saved last run, without changing any of the code that would likewise check the default values, (had nothing been changed.)

Sure, granted, there are reasons to keep separate SavedVariables.. but most of our projects don't really meet the criteria for needing to.

Hope this helps!

P.S. LAM syntax looks correct on first glance to me!
  Reply With Quote
04/24/14, 09:16 PM   #4
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Originally Posted by Seerah View Post
Aren't you storing the results of Harvest.setting.account in your saved variables?

Are you waiting for EVENT_ADD_ON_LOADED before you actually try to grab stuff from your saved variables?
Lua Code:
  1. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, Harvest.OnLoad)
That is at the bottom of the main file.
Lua Code:
  1. function Harvest.OnLoad(eventCode, addOnName)
  2.  
  3.     {{{{ Bunch of stuff here}}}}
  4.  
  5.     Harvest.nodes = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 2, "nodes", { data = {} } )
  6.     if Harvest.settings.account then
  7.         Harvest.settings = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "settings",
  8.         {{{{ stuf }}}}
  9.         }  
  10.     else
  11.         Harvest.settings = ZO_SavedVars:New("Harvest_SavedVars", 1, "settings",
  12.         {{{{ stuf }}}}
  13.         }  
  14.     end
That will error ^^

So I am trying to test add this feature while I have an existing HarvestMap.lua file in Saved Variables. So naturally the file exists but the value is not saved in it yet.

The entire block:
Warning: Spoiler

I don't have an ulterior motive. I'm not expecting you to like download the file and troubleshoot my entire code. However, I'll link it but I don't know how to put it so you know I'm not trying to ask for more then is allowed. Just you want to know something that I may not be doing feel free. That can't sound right but I am trying to be respectful.

What i don't get is when the EVENT_ADD_ON_LOADED fires to run OnLoad, if the value is not there I can't check for nil. If I do it will cause an exception.

Because I tried this:
Lua Code:
  1. if Harvest.settings.account == nil then
  2.     Harvest.settings.account = false
  3. end
But that didn't work.

So what I am worried about is if someone uses HarvestMap 2.3.1, and they upgrade to the new version when I am done, they won't have the setting in the file. When it does not exist how can I define it? So that maybe I can say "Harvest.settings.account = {{{{{ Some Syntax Here }}}". Because I could store the value in two places if that will make it work. I don't know where to specify the default value either.
Lua Code:
  1. if Harvest.settings.account then
  2.         Harvest.settings = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "settings",
  3.             {
  4.                 account = false,
  5.                 filters = {
Am I supposed to do that so there is a default value? And then the next time a user loads their game will it be true if they set it to true?

Last edited by Sharlikran : 04/24/14 at 09:19 PM.
  Reply With Quote
04/24/14, 09:24 PM   #5
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Originally Posted by archpoet View Post
Hope this helps!

P.S. LAM syntax looks correct on first glance to me!
You kind of ninja'd me before I posted. Does any of that help narrow down, maybe, the fact that I'm not defining the default value, or something.

EDIT: This did not work
Lua Code:
  1. defaultValues = {
  2.     ["account"] = false,
  3.         ["verbose"] = false,
  4.         ["debug"] = false,
  5.        }
  6.  
  7.     Harvest.settings = defaultValues

Last edited by Sharlikran : 04/24/14 at 09:33 PM.
  Reply With Quote
04/24/14, 09:28 PM   #6
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Originally Posted by Sharlikran View Post
Lua Code:
  1. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, Harvest.OnLoad)
That is at the bottom of the main file.
Lua Code:
  1. function Harvest.OnLoad(eventCode, addOnName)
  2.  
  3.     {{{{ Bunch of stuff here}}}}
  4.  
  5.     Harvest.nodes = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 2, "nodes", { data = {} } )
  6.     if Harvest.settings.account then
  7.         Harvest.settings = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 1, "settings",
  8.         {{{{ stuf }}}}
  9.         }  
  10.     else
  11.         Harvest.settings = ZO_SavedVars:New("Harvest_SavedVars", 1, "settings",
  12.         {{{{ stuf }}}}
  13.         }  
  14.     end
That will error ^^
Well, of course it will. You're not checking the addonName return to see if it was actually your addon that loaded and is ready.
  Reply With Quote
04/24/14, 10:05 PM   #7
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
I don't know how to do that, but I am trying...
Lua Code:
  1. function Initialize()
  2.     defaultValues = {
  3.         ["account"] = false,
  4.         ["verbose"] = false,
  5.         ["debug"] = false,
  6.        }
  7.  
  8.     Harvest.settings = defaultValues
  9. end
  10.  
  11. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function Harvest.OnLoad(eventCode, addOnName)
  12.     if addon == ""HarvestMap"" then
  13.         Initialize()
  14.     end
  15. end)
That didn't quite work.

Then I tried this
Lua Code:
  1. function Initialize()
  2.     defaultValues = {
  3.         ["account"] = false,
  4.         ["verbose"] = false,
  5.         ["debug"] = false,
  6.        }
  7.  
  8.     Harvest.settings = defaultValues
  9. end
  10.  
  11. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode, addOnName)
  12.     if addon == "HarvestMap" then
  13.         Initialize()
  14.         OnLoad(eventCode, addOnName)
  15.     end
  16. end)

Then I tried and this
Lua Code:
  1. function Initialize()
  2.     defaultValues = {
  3.         ["account"] = false,
  4.         ["verbose"] = false,
  5.         ["debug"] = false,
  6.        }
  7.  
  8.     Harvest.settings = defaultValues
  9. end
  10.  
  11. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode, addOnName)
  12.     if addon == "HarvestMap" then
  13.         Initialize()
  14.         Harvest.OnLoad(eventCode, addOnName)
  15.     end
  16. end)
May I pretty please with sugar on top ask what I am missing? The last one I get no error but when I go to settings after my char loads, the mod does not show up anymore.

This is what it looks like in game.

HarvestMap is gone

EDIT: LOL! If I specify "addOnName" I can't use "addon"

Last edited by Sharlikran : 04/24/14 at 10:20 PM.
  Reply With Quote
04/24/14, 10:18 PM   #8
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Lua Code:
  1. function Initialize()
  2.     defaultValues = {
  3.         ["account"] = false,
  4.         ["verbose"] = false,
  5.         ["debug"] = false,
  6.        }
  7.  
  8.     Harvest.settings = defaultValues
  9. end
  10.  
  11. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode, addOnName)
  12.     if addOnName == "HarvestMap" then
  13.         Initialize()
  14.         Harvest.OnLoad(eventCode, addOnName)
  15.     end
  16. end)
Wait, that worked!

So is it
EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode, addOnName)

OR

EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function Harvest.OnLoad(eventCode, addOnName)

OR

EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function OnLoad(eventCode, addOnName)

Some of those gave me errors about an "(" expected near "Harvest...

Last edited by Sharlikran : 04/24/14 at 10:21 PM.
  Reply With Quote
04/24/14, 10:52 PM   #9
archpoet
Cunning Linguist
 
archpoet's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 19
The first one should work:
Code:
EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode,addOnName)
    if addOnName == "HarvestMap" then
        Initialize()
        Harvest.OnLoad(eventCode, addOnName)
    end
end)
Basically you're only passing a reference to the RegisterForEvent() method, it doesn't *require* a name for the function.. and you definitely don't want to re-define Harvest.OnLoad() if you want it to call the other one inside the reference.

Looking good tho!

Last edited by archpoet : 04/24/14 at 10:52 PM. Reason: code blocks
  Reply With Quote
04/25/14, 03:52 AM   #10
Iyanga
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 183
Originally Posted by Sharlikran View Post
Lua Code:
  1. EVENT_MANAGER:RegisterForEvent("HarvestMap", EVENT_ADD_ON_LOADED, function (eventCode, addOnName)
  2.     if addOnName == "HarvestMap" then
  3.         Initialize()
  4.         Harvest.OnLoad(eventCode, addOnName)
  5.     end
  6. end)

Anonymous functions will just make your debugging life harder, because if you have an error in that part of the code, the backtrace won't tell you where it happened.
  Reply With Quote
04/25/14, 02:21 PM   #11
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Anonymous functions are fine. If you're just doing a little bit in the function and you only need it that one time, why not? Besides, the error's backtrace will give you a line number and say the error was "in anonymous function".
  Reply With Quote
05/01/14, 02:18 AM   #12
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Still having issues creating a new section now. I want a list of item ID numbers, indexed by the itemID.

I declared my save variable table or whatever it's called
Lua Code:
  1. Harvest.items = ZO_SavedVars:NewAccountWide("Harvest_SavedVars", 2, "items", { data = {} } )

This is what I wrote to insert into that table
Lua Code:
  1. function Harvest.saveItem( nodeName, itemName, itemID )
  2.  
  3.     if Harvest.itemAlreadyFound( nodeName, itemName, itemID ) then
  4.         return
  5.     end
  6.  
  7.     if not Harvest.nodes.data[itemID] then
  8.         Harvest.nodes.data[itemID] = {}
  9.     end
  10.  
  11.     if Harvest.settings.debug then
  12.         d("Save data!")
  13.     end
  14.  
  15.     table.insert( Harvest.items.data[itemID], { nodeName, itemName, } )
  16. end

Here is what I expect it to look like:
Lua Code:
  1. HarvestMap_SavedVariables =
  2. {
  3.     ["Default"] =
  4.     {
  5.         ["@Sharlikran"] =
  6.         {
  7.             ["$AccountWide"] =
  8.             {
  9.                 ["items"] =
  10.                 {
  11.                     ["version"] = 2,
  12.                     ["data"] =
  13.                     {
  14.                         [45853] =
  15.                         {
  16.                             [1] = [[Aspect Rune]],
  17.                             [2] = [[Rekuta]],
  18.                         },
  19.                         [45834] =
  20.                         {
  21.                             [1] = [[Essence Rune]],
  22.                             [2] = [[Okoma]],
  23.                         },

This is what it looks like so far
Warning: Spoiler


Here is the routine to check for duplicate itemID numbers.
Lua Code:
  1. function Harvest.itemAlreadyFound( nodeName, itemName, itemID )
  2.  
  3.     if not Harvest.items.data[itemID] then
  4.         return false
  5.     end
  6.  
  7.     local node, item
  8.     node = Harvest.items.data[itemID][1]
  9.     item = Harvest.items.data[itemID][2]
  10.     if (node == nodeName) or (item == itemName) then
  11.         if Harvest.settings.debug then
  12.             d("Node : " .. node .. " Item : " .. item .. " already found!")
  13.         end
  14.         return true
  15.     end
  16.     return false
  17. end

This is the error I am getting. How can I change the syntax to make it work? As you can see in the screen shot I do have the itemID, Item Name, and node name so I can pass those as arguments.
  Reply With Quote
05/01/14, 03:42 AM   #13
lyravega
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 93
Have you tried using table.pack()? Just to be sure.
  Reply With Quote
05/01/14, 08:07 AM   #14
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Lua Code:
  1. function Harvest.saveItem( nodeName, itemName, itemID )
The first thing I just noticed is that in the above function, which I want to reference "Harvest.items.data" I was using Harvest.nodes.data when I was assigining the empty set prior to inserting into the table.
Lua Code:
  1. if not Harvest.nodes.data[itemID] then
  2.         Harvest.nodes.data[itemID] = {}
  3.     end
  Reply With Quote
05/01/14, 09:01 AM   #15
Sharlikran
 
Sharlikran's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 645
Lua Code:
  1. function Harvest.saveItem( nodeName, itemName, itemID )
  2.  
  3.     if not Harvest.items.data[itemID] then
  4.         Harvest.items.data[itemID] = {}
  5.         table.insert( Harvest.items.data[itemID], { nodeName, itemName} )
  6.         if Harvest.settings.debug then
  7.             d("Item Data Saved!")
  8.         end
  9.     end
  10.  
  11. end
I completely got rid of Harvest.itemAlreadyFound() and consolidated it to this. My issue was that I was using "Harvest.nodes.data[itemID]" instead of "Harvest.items.data[itemID]"
Lua Code:
  1. ["items"] =
  2.                 {
  3.                     ["data"] =
  4.                     {
  5.                         [27058] =
  6.                         {
  7.                             [1] =
  8.                             {
  9.                                 [2] = [[Red Wheat]],
  10.                                 [1] = [[Barrels]],
  11.                             },
  12.                         },
  13.                         [26976] =
  14.                         {
  15.                             [1] =
  16.                             {
  17.                                 [1] = [[Barrels]],
  18.                                 [2] = [[Lard]],
  19.                             },
  20.                         },
  21.                     },
  22.                     ["version"] = 2,
  23.                 },
It is saving like that. My question is now, how do I reference that? Say I was going to print that out using d(Print something here). Would it be Harvest.items.data[itemID][1].1 or Would it be Harvest.items.data[itemID][1][1] and Harvest.items.data[itemID][1][2]. How do I reference the fields [1] and [2] to print or get at the node name and the item name of the given ItemID?
  Reply With Quote
05/01/14, 10:53 AM   #16
Iyanga
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 183
Originally Posted by Sharlikran View Post
It is saving like that. My question is now, how do I reference that? Say I was going to print that out using d(Print something here). Would it be Harvest.items.data[itemID][1].1 or Would it be Harvest.items.data[itemID][1][1] and Harvest.items.data[itemID][1][2]. How do I reference the fields [1] and [2] to print or get at the node name and the item name of the given ItemID?

Harvest["items"]["data"][27058][1][2] will be "Red Wheat"
  Reply With Quote
05/01/14, 11:39 AM   #17
Wykkyd
Are you Wykkyd Gaming?
 
Wykkyd's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 107
You guys may or may not be aware of this so I'm sharing it here, because it seems appropriate:

The ZO_SavedVariables inserts and retrieves saved data from inside of an @Accountname sub table. If your user is on the Overflow server, or if your user is experiencing issues with the game client, or if they disable Guild & Friend features for maintenance or a hotfix (which they have done nearly once per week since launch)... your user will fail to load their saved variables as the active account the game client will be loading them under will be the value: ""

For this reason, and to support a feature I'm planning to add to my addons, I have CHANGED GEARS and am using my OWN character-name tabling of saved variable data without using ZO_SavedVariables.

## SavedVariables: mySaves

^^ that kind of line in your .txt file.

Then I basically just do the following on startup:

local defaults = {
var1 = "",
var2 = true,
var3 = 3,
}
local charName = GetUnitName( "player" )
if not mySaves then mySaves = {} end
if not mySaves[ savedVariableVersionNumber] then mySaves[ savedVariableVersionNumber] = {} end
if not mySaves[ savedVariableVersionNumber][ "global" ] then mySaves[ savedVariableVersionNumber][ "global" ] = defaults end
if not mySaves[ savedVariableVersionNumber][ charName ] then mySaves[ savedVariableVersionNumber][ charName ] = defaults end
myAddonGlobal.Settings = mySaves[ savedVariableVersionNumber][ charName ]
myAddonGlobal.GlobalSettings = mySaves[ savedVariableVersionNumber][ "global" ]


That's it. LOOKS more complex than it is. It's fairly simple, really. Still partitions saved variables by version and toon but doesn't include the account name (which is pointless at this point anyway) or any profile name (which you could easily add if you wished).

To read settings out I have a GetOrDefault method like:

myAddonGlobal.GetOrDefault = function( default, varToCheck ) if varToCheck == nil then return default else return varToCheck end end

And then I consume that like this:

control:SetWidth( myAddonGlobal.GetOrDefault( 250, myAddonGlobal.Settings[ "control width" ] ) )

And if you change the value of myAddonGlobal.Settings[ "control width" ] it does indeed save down to the SavedVariables file just as you should expect... automatically.


Basically this cleans up saved variable usage while at the same time CODING AROUND a relatively hurtful (to the user experience) game bug.



EDIT: This is the process I am shifting to with my suite-wide rewrite & overhaul. You won't find examples in my currently published addons, as of 5/1/2014. My overhaul is about halfway done and after that these kind of changes will be "live" and you'll be able to see them in action.
  Reply With Quote
05/01/14, 01:13 PM   #18
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Hmm interesting Wykkyd. May have to consider something similar if this sort of thing causes a headache with gatherer. But urgh .. another data fix routine I was hoping to avoid.
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Help with ZO_SavedVars Syntax


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