Go to Page... |
Thread Tools | Display Modes |
06-15-21, 05:33 PM | #1 |
Saved Variables DB with a subtable: weird behaviour
Hey guys,
while developing my first greater AddOn I had several issues that I could fix myself. However, after research and testing I just can't get to the bottom of the following problem regarding some weird behaviour of a database subtable from SavedVariables. Hope you can help. And sorry for the incoming wall of text. tl;dr: the full code is posted below. I'm building a Config Dialog for my addon with AceConfigDialog and AceDBOptions. So far, everything works. My SavedVariables Database is listed in my .toc file . Lets say it's called addondb. One part of addondb is a table with several subtables, containing stats a specific class + role should not have. It looks like this: Code:
addondb = { failstats = { ["WARRIOR"] = { ["Arms"] = {"INT, "SPI", "SPW", "MP5","DEF","DDG","PAR","RES"} } } } Those "failstats" are predefined (my research, several guides etc.). I want the player to have the option to change them the way he wants with a multiline input textbox. Here is the idea: The multiline-input field get function. My code - gets the failstats from the addondb["WARRIOR"]["Arms"] table, - translates them into understandable stats ("INT" becomes "Intellect", as you see) and - creates this multiline output by concatenating the stats with a newline "\n" in between. Now to the set function of my input field. The set function - splits the content of the input field at the "\n" newlines into a table "rawInput", - removes wrong inputs like "bla bla bla", - retranslates the understandable stats back into the shortened version and - after all that, the addondb["WARRIOR"]["Arms"] table gets overwritten. For clarification, the overwrite happens like this: Code:
wipe(addondb.["WARRIOR"]["Arms"]) addondb.["WARRIOR"]["Arms"] = CopyTable(rawInput) See the above picture I posted. When I delete the last element ("Resilience Rating" here) from the input field, everything works out just well. I printed the final content of the subtables of "rawInput" and "addondb" via Code:
table.foreach("tableName",print) And it gets even more weird. When I delete "Parry Rating", then again, before reloading or exiting the game, my debug prints show, that "PAR" has been successfully removed from the addondb table. But when reloading the game or exiting, the following gets saved in my WTF/.../SavedVariables/.lua file: Code:
["failstats"] = { ["WARRIOR"] = { ["Arms"] = { [7] = "RES", } } } tl;dr. In conclusion, long stories short. It seems like the game only saves changes from the default settings in my table, but missing elements just get auto-filled with defaults? Am I missing something regarding table handling in the SavedVariables database? I hope you got the idea of my code without me posting everything. Any basic ideas on what WoW does to my subtable when reloading? And why it does this weird stuff? Here are a few more things regarding variables that get loaded. Maybe this helps. In my .toc-file, I load everything in this order: 1. embeds.xml (embeding the Ace Libraries) 2. profiles.lua (containing the definition of the default settings) 3. Data.lua (containing global addon data, like dictionaries to translate between shorts to long stats, e.g. "INT" -> "Intellect") 4. config.lua (where actually my config dialog gets build) 5. Core.lua (with all the important stuff for my addon) Thanks for any help. Have a great week! Srzm Last edited by Srzm : 06-15-21 at 06:20 PM. |
|
06-15-21, 05:48 PM | #2 |
Post your code. All of it. We appreciate the very detailed explanation of how your code works, but we can't debug code without looking at the code. It's a waste of time to try and do anything when the problem is most likely your code.
__________________
|
|
06-15-21, 06:11 PM | #3 |
Alright then. I made a minimum version of the config where you can reproduce the problem. Just checked it. To open the config, you have to type "/test".
Here is the code. The config.lua. Code:
UITestAddOn = LibStub("AceAddon-3.0"):NewAddon("UITestAddOn", "AceEvent-3.0","AceConsole-3.0","AceTimer-3.0") local AceConfigDialog = LibStub("AceConfigDialog-3.0") local AceConfig = LibStub("AceConfig-3.0") local self , UITestAddOn = UITestAddOn , UITestAddOn local UITestAddOndb local ShortStats = { ["Strength"] = "STR", ["Agility"] = "AGI", ["Stamina"] = "STA", ["Intellect"] = "INT", ["Spirit"] = "SPI", ["Attack Power"] = "ATK", ["Armor Penetration"] = "ARP", ["Expertise"] = "EXP", ["Spell Power"] = "SPW", ["Mana per 5s"] = "MP5", ["Haste Rating"] = "HST", ["Crit Rating"] = "CRI", ["Hit Rating"] = "HIT", ["Defense Rating"] = "DEF", ["Dodge Rating"] = "DDG", ["Parry Rating"] = "PAR", ["Resilience Rating"] = "RES", ["Armor"] = "ARM", } local LongStats = { ["STR"] = "Strength", ["AGI"] = "Agility", ["STA"] = "Stamina", ["INT"] = "Intellect", ["SPI"] = "Spirit", ["ATK"] = "Attack Power", ["ARP"] = "Armor Penetration", ["EXP"] = "Expertise", ["SPW"] = "Spell Power", ["MP5"] = "Mana per 5s", ["HST"] = "Haste Rating", ["CRI"] = "Crit Rating", ["HIT"] = "Hit Rating", ["DEF"] = "Defense Rating", ["DDG"] = "Dodge Rating", ["PAR"] = "Parry Rating", ["RES"] = "Resilience Rating", ["ARM"] = "Armor", } local function splitStringToTable (inputstr, seperator) if seperator == nil then seperator = "%s" end local t={} for str in string.gmatch(inputstr, "([^"..seperator.."]+)") do table.insert(t, str) end return t end function UITestAddOn:OnInitialize() self.db = LibStub("AceDB-3.0"):New("UITestAddOndb",UITestAddOn_DBdefaults, "Default"); self.db.RegisterCallback(self, "OnProfileChanged", "ChangeProfile") self.db.RegisterCallback(self, "OnProfileCopied", "ChangeProfile") self.db.RegisterCallback(self, "OnProfileReset", "ChangeProfile") UITestAddOndb = self.db.profile; self:RegisterChatCommand("test", "ShowConfig") UITestAddOn.options = { name = "UITestAddOn", desc = "Learning to code GUI", type = 'group', args = {}, } local bliz_options = CopyTable(UITestAddOn.options) bliz_options.args.load = { name = "Load configuration", desc = "Load configuration options", type = 'execute', func = "ShowConfig", handler = UITestAddOn, } LibStub("AceConfig-3.0"):RegisterOptionsTable("UITestAddOn_bliz", bliz_options) AceConfigDialog:AddToBlizOptions("UITestAddOn_bliz", "UITestAddOn") end local function initOptions() if UITestAddOn.options.args["Analysis Options"] then return end UITestAddOn:OnOptionsCreate() for k, v in UITestAddOn:IterateModules() do if type(v.OnOptionsCreate) == "function" then v:OnOptionsCreate() end end AceConfig:RegisterOptionsTable("UITestAddOn", UITestAddOn.options) end function UITestAddOn:ShowConfig() initOptions() AceConfigDialog:Open("UITestAddOn") end function UITestAddOn:ChangeProfile() UITestAddOndb = self.db.profile for k,v in UITestAddOn:IterateModules() do if type(v.ChangeProfile) == 'function' then v:ChangeProfile() end end end function UITestAddOn:AddOption(key, table) self.options.args[key] = table end function UITestAddOn:OnOptionsCreate() self:AddOption("profiles", LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)) self.options.args.profiles.order = -1 self:AddOption('Analysis Options', { type = 'group', name = "Analysis Options", desc = "Options for Character Analysis", order = 1, args = { header = { type = "header", name = "Analysis Options", order = 1, width = "full", }, optionsArea = { type = 'group', inline = true, name = "", args = { failstats = { type = "input", name = "Enter Failstats to add / remove.\nA new line for each fail stat.", set = function(info,value) local inputRaw = splitStringToTable(value,"\n"); for k,v in pairs(inputRaw) do if not (ShortStats[v]) then -- Check if player entered nonsence. And remove it. DEFAULT_CHAT_FRAME:AddMessage(v .. "is not a stat, removing.") table.remove(inputRaw,k) else inputRaw[k] = ShortStats[v] -- Transform the nice stats into short upper stats. end end wipe(UITestAddOndb["failstats"]["WARRIOR"]["Arms"]) UITestAddOndb["failstats"]["WARRIOR"]["Arms"] = CopyTable(inputRaw); end, get = function(info) local failStatsString = ""; for k,v in pairs(UITestAddOndb["failstats"]["WARRIOR"]["Arms"]) do failStatsString = failStatsString .. LongStats[UITestAddOndb["failstats"]["WARRIOR"]["Arms"][k]] .. "\n" end return failStatsString; end, multiline = 15, order = 2, }, }, }, } }) end The profiles.lua Code:
UITestAddOn_DBdefaults = { profile = { failstats = { -- Failstats on Equipment ["WARRIOR"] = { ["Arms"] = { "INT", "SPI", "SPW", "MP5", "DEF", "DDG", "PAR", "RES" }, -- Arms }, }, } } And the .toc-file: Code:
## Interface: 20500 ## Title: UITestAddOn ## Notes: Just some goofing to learn UI. ## Author: Srzm ## Version: 0.1 ## SavedVariables: UITestAddOndb embeds.xml profiles.lua config.lua Code:
<Ui xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd" xmlns="http://www.blizzard.com/wow/ui/"> <Include file="libs\AceAddon-3.0\AceAddon-3.0.xml" /> <Include file="libs\AceEvent-3.0\AceEvent-3.0.xml" /> <Include file="libs\AceTimer-3.0\AceTimer-3.0.xml" /> <Include file="libs\AceHook-3.0\AceHook-3.0.xml" /> <Include file="libs\AceDB-3.0\AceDB-3.0.xml" /> <Include file="libs\AceDBOptions-3.0\AceDBOptions-3.0.xml" /> <Include file="libs\AceLocale-3.0\AceLocale-3.0.xml" /> <Include file="libs\AceConsole-3.0\AceConsole-3.0.xml" /> <Include file="libs\AceGUI-3.0\AceGUI-3.0.xml" /> <Include file="libs\AceConfig-3.0\AceConfig-3.0.xml" /> <Include file="libs\LibSharedMedia-3.0\lib.xml" /> <Include file="libs\AceGUI-3.0-SharedMediaWidgets\widget.xml" /> <Include file="libs\LibDeformat-3.0\lib.xml" /> <Script file="libs\LibStub\LibStub.lua" /> <Script file="libs\CallbackHandler-1.0\CallbackHandler-1.0.lua" /> <Script file="libs\LibDataBroker-1.1\LibDataBroker-1.1.lua" /> </Ui> One last note: I develop this addon for patch TBC Classic 2.5.1. Greetz and thanks! Srzm Last edited by Srzm : 06-16-21 at 02:40 AM. |
|
06-15-21, 06:46 PM | #4 |
There is no 3.3.5a Patch for Wow.
Live - 9.0.5 Burning Crusade Classic - 2.5.1 World of Warcraft Classic - 1.13.7 Unless you are talking about the patch of a particular addon. So maybe telling us which addon it is and which of the official game versions it is designed for. If it isn't for one of the above official servers then we cannot help you as what you are doing falls under number 4 of the terms of use on this site. '4. Don't break WoW EULA or ToU. If you come here and post that you are selling your WoW account for real world money, offering or asking for power-levelling, in-game items or gold for real life cash, private servers or any other post that breaks WoW EULA or ToU, your post will be deleted and you will (at minimum) warned not to do it again. Repeated offenses will lead to banning from the site.'
__________________
All Level 70 Characters: Demon Warlock Resto Druid Disc Priest Resto Shaman Survival Hunter Augment Evoker Frost Mage Vengence Demon Hunter Rogue ( was subtlety ) Brewmaster Monk (TR) Prot Paladin (TR) Blood Death Knight ( TR) As you can see I am missing a warrior And .. I don't have all the allied races covered. Time Runner time when it happens again Last edited by Xrystal : 06-15-21 at 06:49 PM. |
|
06-16-21, 02:40 AM | #5 | |
Thank you for your reply.
However, I can fully understand if that hurts the rules. I edited the TOC file, the minimal addon reproducing the problem posted above should be compatible with TBC Classic since I'm not using methods of the WOW API and the stats are all there in TBC as well. Hope that sets things right without hurting any rules. Thanks in advance! Srzm |
||
06-16-21, 04:30 AM | #6 | |
Good forward planning. However, based on the api differences between Classic and TBC Classic, the addon may not be 'ready' when the next Classic version comes out as that will likely have a different API base.
If memory serves ... Classic > Legion 7.x API with Classic related changes TBC Classic > BfA 8.x API with TBC related changes Meaning the likely chance that .. WotLK Classic > Shadowlands 9.x API with WotLK related changes Cataclysm Classic > 10.x API ... etc As to your problem at hand, I unfortunately cannot help with that as I don't use any of the Ace libraries. However, my understanding of Defaults would be that the active table would first be filled with the default values and then your code would make any necessary changes .. ie, if they deleted option 7 then move option 8 to be option 7. If they set option 7 to a specific value, handle the list as a whole so that it contained the items expected in the right order. Ace may not have these actions set up as how they need to be handled may be different per addon. They likely just set up the ability to action things as they change.
__________________
All Level 70 Characters: Demon Warlock Resto Druid Disc Priest Resto Shaman Survival Hunter Augment Evoker Frost Mage Vengence Demon Hunter Rogue ( was subtlety ) Brewmaster Monk (TR) Prot Paladin (TR) Blood Death Knight ( TR) As you can see I am missing a warrior And .. I don't have all the allied races covered. Time Runner time when it happens again |
||
06-16-21, 02:00 PM | #7 |
most likely the problem is this part:
Code:
local inputRaw = splitStringToTable(value,"\n"); for k,v in pairs(inputRaw) do if not (ShortStats[v]) then -- Check if player entered nonsence. And remove it. you need to trim each line before you test it: Code:
v = v:match("^%s*(.-)%s*$") or ''; Last edited by elcius : 06-16-21 at 02:03 PM. |
|
06-18-21, 04:34 AM | #8 | |
I don't think that my enterfield string has any carriage returns, since it gets build with "\n" line breaks only, here: Code:
failStatsString = failStatsString .. LongStats[UITestAddOndb["failstats"]["WARRIOR"]["Arms"][k]] .. "\n" I think at this point I'll script the whole profile management on my own, with an own SavedVariables table and without the AceDB. I did it without AceDB in a smaller addon earlier and I had absolutely no problems with set / get from subtables there. Regardless, thanks for all your help, elcius, Xrystal, Kanegasi. From my point of view, this topic can be closed. Greetz. - Srzm |
||
WoWInterface » Developer Discussions » General Authoring Discussion » Saved Variables DB with a subtable: weird behaviour |
«
Previous Thread
|
Next Thread
»
|
Display Modes |
Linear Mode |
Switch to Hybrid Mode |
Switch to Threaded Mode |
|
|