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.
@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, 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.
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.
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.