View Single Post
08/17/14, 01:18 AM   #11
Sasky
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 231
Originally Posted by QuadroTony View Post
nothing "not possible" for a good programmer =)
http://en.wikipedia.org/wiki/Halting_problem
More seriously, we are limited by the API. The game itself loads the whole file, so we can't change that unless we work at Zenimax and can access the game code.

Originally Posted by zgrssd View Post
I have several reasons not to do it:
First, it is alot of work and a lot of added complexity.
Second, I also propably need some sub-division (like the namespaces) so the programmer can reset part of the data without affecting others. Doing this account or even Character wide is not granular enough.
Third and most importantly: It is pretty trivial to make versionoing yourself. Once you started making your own (for more advanced cases like migrating applicable settings from previous versions), those extra checks built into the function will be a resource drain.

I might add it later. But I don't see the need to hardcode this personally.
1. If this is intended to replace, I feel it should at a minimum mimic functionality.
2. I don't see the need for namespaces, as the library doesn't try for namespaces from the API. I can't come up with a decent use case of why that'd be needed either, so guess you'd need to elaborate.
3a. If it's trivial, that seems to me more argument to put it in library to limit code re-use.
3b. It's called once on the library call which should only be done for an individual bucket once per /reloadui, so it's negligible cost on setup. If someone's calling ZO_SavedVars or this every frame update (when it would have an impact), that's bad usage and should be changed regardless.

It almost seems you're trying to build in something more advanced than the ZO_SavedVars versioning, then declaring that's too much and saying no versioning is needed.I was trying to think of how to lay it out clearer, and ended up pretty much dry-coding the whole thing...
Lua Code:
  1. --Register with LibStub
  2. local asv = LibStub:NewLibrary("LibASV-1.0", 0.1)
  3. if not asv then return end  --the same or newer version of this lib is already loaded into memory
  4.  
  5. -- Local constants
  6. local acctWide = "libASV_AccountWide"
  7. local osWide = "libASV_OS_wide"
  8.  
  9. -- Utility functions
  10. ---
  11. -- @param t - Saved variables table
  12. --      Table has reserved field t._version for current version
  13. -- @param version - expected version for the table
  14. -- @param upgradeFunction - If NIL will just copy in default values. Expected f(version, table) and upgrade in-place
  15. -- @param defaults - NOT nillable. Used to reset in case upgradeFunction is NIL
  16. --
  17. local function versionControl(t, version, upgradeFunction, defaults)
  18.     --t is passed in by reference, so it's changed in-place and no return needed
  19.     if version ~= t._version then
  20.         if upgradeFunction then
  21.             upgradeFunction(t._version, t)
  22.             --_version is reserved, so we want to make sure it's a good value
  23.             t._version = version
  24.         else
  25.             ZO_DeepTableCopy(defaults, t)
  26.         end
  27.     end
  28. end
  29.  
  30. --- Utility function to access sub-table
  31. -- @param table
  32. -- @param key
  33. local function accessNonNull(table, key)
  34.     if table[key] == nil then
  35.         table[key] = {}
  36.     end
  37.  
  38.     return table[key]
  39. end
  40.  
  41. -- API functions
  42.  
  43. ---
  44. -- @param savedVar (required) name used for the SavedVariables field in the manifest file
  45. -- @param version (required) version of the saved variable
  46. -- @param defaults (optional) defaults to use on initialization. Defaults to {}
  47. -- @param upgradeFunction (optional) what to call if different saved variable version.
  48. --           Default behavior is replace with defaults
  49. -- @return (table reference) to the OS-wide saved variables
  50. ---
  51. function asv:AccessOSUserWide(savedVar, version, defaults, upgradeFunction)
  52.     defaults = defaults or {}
  53.  
  54.     --Check if initialized
  55.     if not savedVar[osWide] then
  56.         return ZO_DeepTableCopy(defaults, savedVar[osWide])
  57.     end
  58.  
  59.     versionControl(savedVar[osWide], version, upgradeFunction, defaults)
  60.     return t
  61. end
  62.  
  63. ---
  64. -- @param savedVar (required) name used for the SavedVariables field in the manifest file
  65. -- @param version (required) version of the saved variable
  66. -- @param defaults (optional) defaults to use on initialization. Defaults to {}
  67. -- @param upgradeFunction (optional) what to call if different saved variable version.
  68. --           Default behavior is replace with defaults
  69. -- @param accountOverride (optional) which account to use. Defaults to current
  70. -- @param characterOverride (optional) which character to use. Defaults to current
  71. -- @return (table reference) to the saved variables for that character
  72. ---
  73. function asv:AccessCharacterWide(savedVar, version, defaults, upgradeFunction, accountOverride, characterOverride)
  74.     accountOverride = accountOverride or GetDisplayName() --Or the more robust 'GetDisplayName' from DisplayNameFix
  75.     characterOverride = characterOverride or GetUnitName("player")
  76.  
  77.     if not savedVar[accountOverride] then
  78.         savedVar[accountOverride] = {}
  79.     end
  80.  
  81.     local accountTable = savedVar[accountOverride]
  82.  
  83.     if not accountTable[characterOverride] then
  84.         return ZO_DeepTableCopy(defaults, accountTable[characterOverride])
  85.     end
  86.  
  87.     versionControl(accountTable[characterOverride], version, upgradeFunction, defaults)
  88.     return t
  89. end
  90.  
  91. ---
  92. -- @param savedVar (required) name used for the SavedVariables field in the manifest file
  93. -- @param version (required) version of the saved variable
  94. -- @param defaults (optional) defaults to use on initialization. Defaults to {}
  95. -- @param upgradeFunction (optional) what to call if different saved variable version.
  96. --           Default behavior is replace with defaults
  97. -- @param accountOverride (optional) which account to use. Defaults to current
  98. -- @return (table reference) to the saved variables for that account
  99. ---
  100. function asv:AccessAccountWide(savedVar, version, defaults, upgradeFunction, accountOverride)
  101.     return self:AccessCharacterWide(savedVar, version, defaults, upgradeFunction, accountOverride, acctWide)
  102. end
  103.  
  104. ---
  105. -- @param savedVar (required) name used for the SavedVariables field in the manifest file
  106. -- @param accountOverride (optional) which account to use. Defaults to current account
  107. -- @return array list of all characters with saved variables for the account
  108. ---
  109. function asv:AllCharacters(savedVar, accountOverride)
  110.     accountOverride = accountOverride or GetDisplayName() --Or the more robust 'GetDisplayName' from DisplayNameFix
  111.  
  112.     local accountTable = savedVar[accountOverride]
  113.     if not accountTable then
  114.         return {}
  115.     end
  116.  
  117.     local chars = {}
  118.     for k in pairs(accountTable) do
  119.         if k ~= acctWide then
  120.             table.append(chars, k)
  121.         end
  122.     end
  123.  
  124.     return chars
  125. end

Sample upgrade function, showing it upgrade in-place.
Lua Code:
  1. function upgrade(version, table)
  2.     if version < 2 then --Set new field foo to default
  3.         table.foo = 20
  4.     end
  5.     if version < 3 then -- Set new field bar to default
  6.         table.bar = 30   end
  7.     end
  8. end
  9.  
  10. asv:AccessOSUserWide(mySavedVar, 3, { a=1,b=2, foo=20, bar=30 }, upgrade)