I was wondering if anyone knew a way to save and load tables? Since they are not supported by saveLocalData, etc.
Yep, you need to flatten (“serialise”) them into a string, then you can save them into local data.
I do it in this game tutorial to create an undo function (see “multiple undo” heading)
http://coolcodea.wordpress.com/2013/03/31/19-lessons-from-a-simple-board-game-part-2/
I do it the lazy way and use json but thats overkill. Check out ignatz’s tutorial on debugging there is a dump class that i bet could be setup to decode a string then write an encoder.
I literally just finished the code for this in my game and was thinking about posting it. I’ll post it tomorrow.
@Zoyt, awesome
@JakAttak - All right, Here we go:
Here is my function I altered from the Programming in Lua book for converting a table to an executable string:
function tToS (name, value, saved) local function basicSerialize (o) if type(o) == "number" then return tostring(o) else -- assume it is a string return string.format("%q", o) end end saved = saved or {} local returnStr = name.." = " if type(value) == "number" or type(value) == "string" then returnStr = returnStr..basicSerialize(value).."\ " elseif type(value) == "table" then if saved[value] then returnStr = returnStr..saved[value].."\ " else saved[value] = name returnStr = returnStr.."{}\ " for k,v in pairs(value) do local fieldname = string.format("%s[%s]", name, basicSerialize(k)) returnStr = returnStr..tToS(fieldname, v, saved) end end else error("Cannot save a " .. type(value)) end return returnStr end ``` Then, to store the table, I say:table.insert(table,value) saveProjectData("table",tToS("table",table)) ``` Finally, to read and set the table, I say:table = readProjectData("table","table = {}") assert(loadstring(table))() ``` Threre you have it. It uses the horrible loadString function, but it works well. I've looked into adding more data storage types like nils, vec2, touches, collisions, etc, but I haven't had the need for it yet. If anyone wants me to do that, just let me know. Thanks! P.S. @Ignatz - You migh suggest including this method somewhere in your tutorials. Lots of people use more than 2D tables. I use tables of all shapes and sizes.
@Zoyt thanks! This should be perfect for what I want
@JakAttak - No problem…
@Zoyt, having a little trouble getting it to work:
Here is the code I’m using to test it:
--# Main
-- String Table
-- Use this function to perform your initial setup
function setup()
jo = {{1,2,3},{2,3,5}}
saveProjectData("table",tToS("table",jo))
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
table = readProjectData("table")
assert(loadstring(table))()
if table == jo then
print("It Worked")
end
end
function tToS(name, value, saved)
local function basicSerialize (o)
if type(o) == "number" then
return tostring(o)
else -- assume it is a string
return string.format("%q", o)
end
end
saved = saved or {}
local returnStr = name.." = "
if type(value) == "number" or type(value) == "string" then
returnStr = returnStr..basicSerialize(value).."\
"
elseif type(value) == "table" then
if saved[value] then
returnStr = returnStr..saved[value].."\
"
else
saved[value] = name
returnStr = returnStr.."{}\
"
for k,v in pairs(value) do
local fieldname = string.format("%s[%s]", name, basicSerialize(k))
returnStr = returnStr..tToS(fieldname, v, saved)
end
end
else
error("Cannot save a " .. type(value))
end
return returnStr
end
The first argument in tToS is the name of the table you’re putting in. So it should be “saveProjectData(“jo”,tToS(“jo”,jo))”. Hope that helps.
@Zoyt It still doesn’t work… Does it ever change the string back into a table?
Did you change the key to read the data to “Jo”? If so, can you post your code?
@Zoyt sure here it is:
--# Main
-- String Table
-- Use this function to perform your initial setup
function setup()
jo = {{1,2,3},{2,3,5}}
saveProjectData("jo",tToS("jo",jo))
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
table = readProjectData("jo", "jo = {}")
assert(loadstring(table))()
if table == jo then
print("It Worked")
end
end
function tToS(name, value, saved)
local function basicSerialize (o)
if type(o) == "number" then
return tostring(o)
else -- assume it is a string
return string.format("%q", o)
end
end
saved = saved or {}
local returnStr = name.." = "
if type(value) == "number" or type(value) == "string" then
returnStr = returnStr..basicSerialize(value).."\
"
elseif type(value) == "table" then
if saved[value] then
returnStr = returnStr..saved[value].."\
"
else
saved[value] = name
returnStr = returnStr.."{}\
"
for k,v in pairs(value) do
local fieldname = string.format("%s[%s]", name, basicSerialize(k))
returnStr = returnStr..tToS(fieldname, v, saved)
end
end
else
error("Cannot save a " .. type(value))
end
return returnStr
end
@JakAttak - Right… My bad. I forgot that the tables have different identifiers. If you look at the individual values, you’ll see that they’re the same.
Hope that helps!
@Zoyt, actually I tried that
if table[1][1] == jo[1][1]
But I get an error: attempting to index a nil value
I finally had the time to copy over your code. So sorry about that. The first field you pass into tTooS should be “table”, not “jo”. Also, it’s not a good technique to override Lua libraries, like the table one. Hope that works.
@Zoyt, so saveProjectData(“jo”, tToS(“table”, “jo”)?
function setup() jo = {{1,2,3},{2,3,5}} saveProjectData("jo",tToS("t",jo)) end function draw() background(40, 40, 50) t = readProjectData("jo", "t = {}") assert(loadstring(t))() if t[1][1] == jo[1][1] then print("It Worked") end end function tToS(name, value, saved) local function basicSerialize (o) if type(o) == "number" then return tostring(o) else -- assume it is a string return string.format("%q", o) end end saved = saved or {} local returnStr = name.." = " if type(value) == "number" or type(value) == "string" then returnStr = returnStr..basicSerialize(value).."\ " elseif type(value) == "table" then if saved[value] then returnStr = returnStr..saved[value].."\ " else saved[value] = name returnStr = returnStr.."{}\ " for k,v in pairs(value) do local fieldname = string.format("%s[%s]", name, basicSerialize(k)) returnStr = returnStr..tToS(fieldname, v, saved) end end else error("Cannot save a " .. type(value)) end return returnStr end ```
I got it working. The “t = {}” doesn’t appear to be necessary
@JakAttak - That is correct, but when I store project data, I read it before I write anything to it.