mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
Lunatic: allow serialization of tables in more general cases.
git-svn-id: https://svn.eduke32.com/eduke32@3908 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
bb71052cb7
commit
7cb94070e1
4 changed files with 94 additions and 38 deletions
|
@ -2051,7 +2051,7 @@ do
|
||||||
|
|
||||||
-- XXX: System gamevars? Most of them ought to be saved with C data.
|
-- XXX: System gamevars? Most of them ought to be saved with C data.
|
||||||
for modname, modvars in pairs(module_gamevars) do
|
for modname, modvars in pairs(module_gamevars) do
|
||||||
sb:addrawf("if (N==%q) then", modname)
|
sb:startmod(modname)
|
||||||
|
|
||||||
-- Handle global gamevars first.
|
-- Handle global gamevars first.
|
||||||
for i=1,#modvars do
|
for i=1,#modvars do
|
||||||
|
@ -2088,7 +2088,7 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
sb:addraw("end")
|
sb:endmod()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the whole code as a string.
|
-- Get the whole code as a string.
|
||||||
|
|
|
@ -177,9 +177,13 @@ also be *`local`*.
|
||||||
Game variables may take on only values of types that Lunatic knows how to
|
Game variables may take on only values of types that Lunatic knows how to
|
||||||
serialize into savegames. These are the following:
|
serialize into savegames. These are the following:
|
||||||
|
|
||||||
* booleans, numbers, and strings
|
* Booleans, numbers, and strings, collectively called the _basic types_
|
||||||
* tables, but with restrictions on their contents and topology described below (TODO)
|
* Custom Lunatic types that are labeled _serializeable_ in their documentation
|
||||||
* custom Lunatic types that are labeled _serializeable_ in their documentation
|
* Tables, but with the following restrictions on their contents:
|
||||||
|
** A table key may only be of basic type.
|
||||||
|
** A table value may be (a reference to) any serializeable object, but tables
|
||||||
|
or Lunatic objects that are so referenced *must* have originated in the
|
||||||
|
same module. Beyond that, there are no restrictions on the table topology.
|
||||||
|
|
||||||
// [icon="icons/din_w_collapse.png"]
|
// [icon="icons/din_w_collapse.png"]
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
local string = require("string")
|
local string = require("string")
|
||||||
local table = require("table")
|
local table = require("table")
|
||||||
|
|
||||||
|
local format = string.format
|
||||||
|
|
||||||
local assert = assert
|
local assert = assert
|
||||||
local getmetatable = getmetatable
|
local getmetatable = getmetatable
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
|
@ -31,7 +33,7 @@ local function basicSerialize(o)
|
||||||
return o and "t" or "f"
|
return o and "t" or "f"
|
||||||
elseif (type(o) == "string") then
|
elseif (type(o) == "string") then
|
||||||
-- TODO: return refname if it's shorter
|
-- TODO: return refname if it's shorter
|
||||||
return string.format("%q", o)
|
return format("%q", o)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,13 +47,52 @@ end
|
||||||
-- user Lunatic environment.
|
-- user Lunatic environment.
|
||||||
local savebuffer_mt = {
|
local savebuffer_mt = {
|
||||||
__index = {
|
__index = {
|
||||||
|
-- Called on starting processing one module.
|
||||||
|
startmod = function(self, modname)
|
||||||
|
self:addrawf("if (N==%q) then", modname)
|
||||||
|
-- Will contain all tables and cdata refs of this module, indexed
|
||||||
|
-- by number.
|
||||||
|
self:addraw("local T={}")
|
||||||
|
self:resetRefs()
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Called on finishing processing one module.
|
||||||
|
endmod = function(self)
|
||||||
|
self:addraw("end")
|
||||||
|
end,
|
||||||
|
|
||||||
|
--== vvv INTERNAL vvv ===---
|
||||||
|
resetRefs = function(self)
|
||||||
|
self.numrefs = 0
|
||||||
|
self.val2ref = {}
|
||||||
|
self.havereq = {}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Get the code necessary to create this object, usually 'require'ing a
|
||||||
|
-- module into a local variable.
|
||||||
|
getRequire = function(self, value)
|
||||||
|
local reqcode = value:_get_require()
|
||||||
|
if (self.havereq[reqcode] == nil) then
|
||||||
|
self.havereq[reqcode] = true
|
||||||
|
self.strbuf[#self.strbuf+1] = reqcode
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
emitT = function(self, refcode, valcode, obj)
|
||||||
|
self:addrawf("%s=%s", refcode, valcode)
|
||||||
|
self.val2ref[obj] = refcode
|
||||||
|
end,
|
||||||
|
|
||||||
|
emitAssign = function(self, lhscode, refcode)
|
||||||
|
self:addrawf("%s=%s", lhscode, refcode)
|
||||||
|
end,
|
||||||
|
--== ^^^ INTERNAL ^^^ ===---
|
||||||
|
|
||||||
-- Add an entry of Lua object <value> that can be referenced by
|
-- Add an entry of Lua object <value> that can be referenced by
|
||||||
-- <refcode> (which should be Lua code that can appear on both sides of
|
-- <lhscode> on the left hand side of an assignment.
|
||||||
-- an assignment).
|
|
||||||
-- Returns 'true' if <value> cannot be serialized.
|
-- Returns 'true' if <value> cannot be serialized.
|
||||||
add = function(self, refcode, value)
|
add = function(self, lhscode, value)
|
||||||
local valcode = basicSerialize(value)
|
local valcode = basicSerialize(value)
|
||||||
local havetab = false
|
|
||||||
|
|
||||||
if (valcode == nil) then
|
if (valcode == nil) then
|
||||||
-- <value> is a not a 'basic' Lua object, but one passed by
|
-- <value> is a not a 'basic' Lua object, but one passed by
|
||||||
|
@ -59,26 +100,22 @@ local savebuffer_mt = {
|
||||||
if (not self.val2ref[value]) then
|
if (not self.val2ref[value]) then
|
||||||
-- Object is being serialized for the first time.
|
-- Object is being serialized for the first time.
|
||||||
|
|
||||||
|
-- Create a slot in 'T' for this object by which we can
|
||||||
|
-- refer to it in the following.
|
||||||
|
self.numrefs = self.numrefs+1
|
||||||
|
local refcode = format("T[%d]", self.numrefs)
|
||||||
|
|
||||||
if (isSerializeable(value)) then
|
if (isSerializeable(value)) then
|
||||||
-- We have a serializeable object from Lunatic
|
-- We have a serializeable object from Lunatic
|
||||||
-- (e.g. actorvar).
|
-- (e.g. actorvar).
|
||||||
|
self:getRequire(value)
|
||||||
-- First, get the code necessary to create this object,
|
self:emitT(refcode, value:_serialize(), value)
|
||||||
-- usually 'require'ing a module into a local variable.
|
valcode = refcode
|
||||||
local reqcode = value:_get_require()
|
|
||||||
if (self.havereq[reqcode] == nil) then
|
|
||||||
self.havereq[reqcode] = true
|
|
||||||
self.strbuf[#self.strbuf+1] = reqcode
|
|
||||||
end
|
|
||||||
|
|
||||||
valcode = value:_serialize()
|
|
||||||
|
|
||||||
elseif (type(value)=="table") then
|
elseif (type(value)=="table") then
|
||||||
-- We have a Lua table.
|
|
||||||
havetab = true
|
|
||||||
|
|
||||||
-- Create a new table for this gamevar.
|
-- Create a new table for this gamevar.
|
||||||
self:addrawf("%s={}", refcode)
|
-- TODO: emit table initializations where possible.
|
||||||
|
self:emitT(refcode, "{}", value)
|
||||||
|
|
||||||
for k,v in pairs(value) do
|
for k,v in pairs(value) do
|
||||||
local keystr = basicSerialize(k)
|
local keystr = basicSerialize(k)
|
||||||
|
@ -86,32 +123,29 @@ local savebuffer_mt = {
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if (type(v)=="table" and not isSerializeable(v)) then
|
|
||||||
-- nested tables: NYI
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Generate the name under which the table element
|
-- Generate the name under which the table element
|
||||||
-- is referenced.
|
-- is referenced.
|
||||||
local refcode2 = string.format("%s[%s]", refcode, keystr)
|
local refcode2 = format("%s[%s]", refcode, keystr)
|
||||||
|
|
||||||
-- Recurse!
|
-- Recurse!
|
||||||
self:add(refcode2, v)
|
if (self:add(refcode2, v)) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
valcode = refcode
|
||||||
else
|
else
|
||||||
-- We have anything else: can't serialize.
|
-- We have anything else: can't serialize.
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
self.val2ref[value] = refcode
|
|
||||||
else
|
else
|
||||||
|
-- Object was previously serialized, get Lua expression it
|
||||||
|
-- can be referenced with.
|
||||||
valcode = self.val2ref[value]
|
valcode = self.val2ref[value]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (not havetab) then
|
self:emitAssign(lhscode, valcode)
|
||||||
self:addraw(refcode.."="..valcode)
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- Add a single string to the buffer.
|
-- Add a single string to the buffer.
|
||||||
|
@ -121,7 +155,7 @@ local savebuffer_mt = {
|
||||||
|
|
||||||
-- Add a single formatted string to the buffer.
|
-- Add a single formatted string to the buffer.
|
||||||
addrawf = function(self, fmt, ...)
|
addrawf = function(self, fmt, ...)
|
||||||
self:addraw(string.format(fmt, ...))
|
self:addraw(format(fmt, ...))
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- Get the Lua code recreating the values as a string.
|
-- Get the Lua code recreating the values as a string.
|
||||||
|
@ -141,9 +175,14 @@ end
|
||||||
|
|
||||||
-- Create a new savebuffer object.
|
-- Create a new savebuffer object.
|
||||||
function savebuffer()
|
function savebuffer()
|
||||||
|
-- .numrefs: how many table or cdata objects we have serialized
|
||||||
-- .val2ref: [<Lua object>] = <Lua code string>
|
-- .val2ref: [<Lua object>] = <Lua code string>
|
||||||
-- .havereq = [<string>] = true
|
-- .havereq = [<string>] = true
|
||||||
-- .strbuf: array of Lua code pieces
|
-- .strbuf: array of Lua code pieces
|
||||||
local sb = { val2ref={}, havereq={}, strbuf=sb_get_initial_strbuf() }
|
local sb = {
|
||||||
|
numrefs=0, val2ref={}, havereq={},
|
||||||
|
strbuf=sb_get_initial_strbuf()
|
||||||
|
}
|
||||||
|
|
||||||
return setmetatable(sb, savebuffer_mt)
|
return setmetatable(sb, savebuffer_mt)
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,8 @@ local con = require("con")
|
||||||
local bit = require("bit")
|
local bit = require("bit")
|
||||||
local math = require("math")
|
local math = require("math")
|
||||||
|
|
||||||
|
local printf = printf
|
||||||
|
local tostring = tostring
|
||||||
local rs = con.rotatesprite
|
local rs = con.rotatesprite
|
||||||
|
|
||||||
local gameevent = gameevent
|
local gameevent = gameevent
|
||||||
|
@ -19,10 +21,21 @@ local a_local_gamevar = "yes, this one too"
|
||||||
|
|
||||||
test_gamevar2 = 'qwe'
|
test_gamevar2 = 'qwe'
|
||||||
|
|
||||||
|
a_table = { ELT1='ELT1!', ELT2=4444, ATAB={ q=333, [4]="!four!", w=444, ["true"]=false } }
|
||||||
|
local ref_to_a_table = a_table
|
||||||
|
ref_to_tabtab = ref_to_a_table.ATAB
|
||||||
|
local l_ref_to_tabtab = ref_to_tabtab
|
||||||
|
|
||||||
|
ref_to_a_table.selfref = a_table
|
||||||
|
a_table[false] = { 1,2,3,con.actorvar(512) }
|
||||||
|
|
||||||
require "end_gamevars" --==========
|
require "end_gamevars" --==========
|
||||||
|
|
||||||
not_a_gamevar = "no"
|
not_a_gamevar = "no"
|
||||||
|
|
||||||
|
printf("a_table.ATAB[4]=%s", tostring(a_table.ATAB[4]))
|
||||||
|
a_table.ATAB[4] = "!FOUR!"
|
||||||
|
|
||||||
|
|
||||||
local DOT1x5 = 3135
|
local DOT1x5 = 3135
|
||||||
local BAR1x5 = 3163
|
local BAR1x5 = 3163
|
||||||
|
|
Loading…
Reference in a new issue