1. I am working on an Ace3 addon, which has OnInitialize(). In my defaults, which are before that, I have a table of random sayings that are output to chat, numbering 26. One of the options in OnInit() allows a user to remove any number of sayings, including ones the user has added. After OnInit(), the saved variables compares the number of entries with the default number, and adds back sayings until there are 26 again.

    Removing entries works correctly.

    For example, say the user does not add any to the table, and removes #18 and # 20; the table then has 24 entries, finishes OnInit(), and adds 2 back in because the defaults have 26 entries. Obviously, this is not intended. Therefore, after OnInit(), I am writing a local function FixRandTable() that will see if self.db.profile.randChatTbl needs adjusting. I use the variable N = #self.db.profile.randChatTbl to get the actual number of entries.

     local function FixRandTable()
        if N < 26 then
            for i, 26 in pairs(self.db.profile.randChatTbl) do
            end
        end
     end
    

    I'd continue this, but it doesn't look right.

    I'm not quite sure of your question, but is there any particular reason you need to have 26 different sayings? It seems to me if the user wants 10 sayings, without your defaults, they should be able to do this. It also seems like that would make the code a bit easier.

    Mainly I would suggest NOT putting the sayings in the 'defaults' table, and instead just adding them in OnProfileNew or whatever the callback is. It should fire even when the addon is first installed and then you can drop your defaults back in place. You can add a button to the addon that will 'fill it back up' if you'd like.

    The automatic stuff seems a bit not right to me, but that's just IMO.

    OK, that makes sense, but that still puts me in "how to" mode. Without all the extra stuff found in my OnInitialize() which is irrelevant, here is the pertinent part. I left the N = part in, but that is easily removed.

    http://pastey.net/137134

    And here is the OnProfileChanged() callback function.

     function SmartRes2:OnProfileChanged()
        db = self.db
     end
    

    Finally, this is the relevant defaults table, before changes.

    http://pastey.net/137136

    The problem I'm facing with my existing code is that if the user removes entries from self.db.randChatTbl, and the remaining entry count is less than 26 (the number of default entries) then as soon as OnInit() is done, it brings the count back up to 26, pulling data from the defaults. This also happens on console reload, logout, exit, etc.

    Your method removes the entries from the defaults, and puts it in OnProfileChanged() correct? That way the user can remove remove as many as she/he wants, do a reload, and self.db.profile.randChatTbl won't back fill from defaults?

    Adding entries doesn't seem to be an issue.

    I thought quoting Xinhuan regarding my current code, before using your suggestion, would be a better explanation:

    However, if the user ever deletes entries to less than 26 entries, then the defaults will regenerate the missing ones back up to 26 because the first 26 entries are defined.

    I'll give you an example. Default has 26 entries. User deletes entry 20 and 22, so there are only 24 entries left in the table. On the next login or reloadui, those 24 options get saved and loaded (with the appropriate ones deleted as expected), but entry [25] and [26] will be regenerated from the defaults, so the user will see [25] and [26] repeated twice over the last 4 entries in the table.

    You would actually need to save another variable N indicating how many entries are in the table so if it falls less than 26, you know how many there are actually, and delete the extras that are regenerated after OnInit()

    -- my reply

    Originally Posted by myrroddin View Post Interesting, thanks for the tip on the regenerate, Xinhuan. Is that because AceDB only populates the SVs when something changes, or is it a WoW thing even without Ace?

    -- Xinhuan's reply

    If a value in the db is nil, AceDB essentially checks the defaults to see if it is defined there. If it is, that value is initialized equal to the default value.

    (That is, defaults work exactly as advertised, you as a programmer can add options in the future and give them default values, and when users upgrade their addons, those missing values in the saved db will be initialized to the defaults on loading the new version)

    Given that I wrote AceDB, I know quite well how it works. This is why I've suggested a different way of doing things, because it's not designed for something like this. If you have something that you want to add to a profile but expect the user will change what is there, then you want to do it when the profile is created, not when in the defaults. Defaults never go away unless you set a new value on top of them.

    They're really designed for settings, which is not what these are.

    Your method removes the entries from the defaults, and puts it in OnProfileChanged() correct? That way the user can remove remove as many as she/he wants, do a reload, and self.db.profile.randChatTbl won't back fill from defaults?

    Using defaults for this is precisely your problems, so just don't do it =)

    Apologies sir. I did not realize you wrote AceDB. OK, I changed thus:

    http://pastey.net/137140

    And commented out the table in defaults. Loaded game, got no errors. Saved variables file has the table, as expected. However, the options is blank; nothing to delete, as if it isn't pulling information from self.db.profile.randChatTabl

    Do I need another callback, like OnNewProfile, or am I missing something else?

    I wasn't saying that because I was offended, just to let you know that I'm aware how AceDB works =). You don't really want or need to do any checks, just register for OnNewProfile and then iterate over your table and add those messages. Don't try to set the table directly, that just has the potential to get a but confusing. Rather, just:

     if not self.db.profile.randChatTbl then
       self.db.profile.randChatTbl = {}
     end
    
     for idx, message in ipairs(randomMessages) do
       table.insert(self.db.profile.randChatTbl, msg)
     end
    

    Should be more than sufficient!

    Much cleaner. I tried it, and strangest thing: default had 26 entries, but Myrroddin - Llane had 52!! Then I tried

     if not self.db.profile.randChatTbl then
        self.db.profile.randChatTbl = {}
     else
        for idx, message in ipairs(randChatTbl) do
            tinsert(self.db.profile.randChatTbl, message)
        end
     end
    

    That only worked after I switched profiles. Well, at least I know my original worked:

     if self.db.profile.randChatTbl == nil then
         self.db.profile.randChatTbl = randChatTbl
     else
         self.db.profile.randChatTbl = self.db.profile.randChatTbl
     end
    

    Er, scratch that. Both of them only work on profile switch. All profiles, including default, are blank until I switch, then all profiles contain the data.

    I'm missing something... and I bet it is obvious, knowing me.

    Your code is probably not registered for the callback at the point where it is fired. Are you using OnProfileChanged? Your original code says yes, and that's not what you should be using for 'new' profiles.