View Single Post
  #7  
Unread 05-20-2013, 11:36 PM
Thurallor's Avatar
Thurallor Thurallor is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: May 2013
Posts: 202
Post

I implemented a slightly different solution for my plugin.

Basically, before I call Turbine.PluginData.Save(), I serialize my settings table (and subtables) into a string. The string is simply a snippet of Lua code that, when executed, returns my settings table. Then I save that single string with Turbine.PluginData.Save().

After I get the string back from Turbine.PluginData.Load(), I use the built-in loadstring() function to parse it back into a table.

Vindar's fix didn't work for me, because my settings table contains tables that look like this:

Code:
t = { "a", "b", "c" }
and Vindar's loader was returning them like this:

Code:
t = {
   ["1"] = "a",
   ["2"] = "b",
   ["3"] = "c"
}
Unfortunately, there is a difference. I hacked Vindar's code for a while, but I couldn't get it to work. So I implemented my alternative. Here's the source code:
Code:
function SaveSettings(settings)
    -- Serialize (workaround for Turbine localization bug)
    local saveStr = "return " .. Serialize(settings);
    Turbine.PluginData.Save(Turbine.DataScope.Character, "Stuff", saveStr, function()
        -- Finished saving
    end);
end

function LoadSettings()
    Turbine.PluginData.Load(Turbine.DataScope.Character, "Stuff", function(saveStr)
        if (saveStr) then
            -- Unserialize (workaround for Turbine localization bug)
            settings = assert(loadstring(saveStr))();
            if (not settings) then
                Turbine.Shell.WriteLine("Failed to parse Stuff.plugindata!");
            end
        end
    end);
end

function Serialize(obj)
    if (type(obj) == "nil") then
        return "nil";
    elseif (type(obj) == "boolean") then
        if (obj) then
            return "true";
        else
            return "false";
        end
    elseif (type(obj) == "number") then
        local text = tostring(obj);
        -- Change floating-point numbers to English format
        return string.gsub(text, ",", ".");
    elseif (type(obj) == "string") then
        return string.format("%q", obj);
    elseif (type(obj) == "table") then
        local text = "{";
        for i, v in pairs(obj) do
            local index = Serialize(i);
            local value = Serialize(v);
            if (value ~= nil) then
                local item = "[" .. index .. "]=" .. value .. ",";
                text = text .. item;
            end
        end
        text = string.gsub(text, ",$", "");
        text = text .. "}";
        return text;
    else
        return nil;
    end
end
You may notice the only escaping I'm doing for strings is replacing " with \" and \ with \\. I'm not sure if there's anything else I need to do, such as for strange foreign characters. Can anyone advise me?

Last edited by Thurallor : 05-25-2013 at 09:16 PM. Reason: Now using the built-in string.format("%q", ...) facility
Reply With Quote