mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 01:11:44 +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.
|
||||
for modname, modvars in pairs(module_gamevars) do
|
||||
sb:addrawf("if (N==%q) then", modname)
|
||||
sb:startmod(modname)
|
||||
|
||||
-- Handle global gamevars first.
|
||||
for i=1,#modvars do
|
||||
|
@ -2088,7 +2088,7 @@ do
|
|||
end
|
||||
end
|
||||
|
||||
sb:addraw("end")
|
||||
sb:endmod()
|
||||
end
|
||||
|
||||
-- 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
|
||||
serialize into savegames. These are the following:
|
||||
|
||||
* booleans, numbers, and strings
|
||||
* tables, but with restrictions on their contents and topology described below (TODO)
|
||||
* custom Lunatic types that are labeled _serializeable_ in their documentation
|
||||
* Booleans, numbers, and strings, collectively called the _basic types_
|
||||
* 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"]
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
local string = require("string")
|
||||
local table = require("table")
|
||||
|
||||
local format = string.format
|
||||
|
||||
local assert = assert
|
||||
local getmetatable = getmetatable
|
||||
local pairs = pairs
|
||||
|
@ -31,7 +33,7 @@ local function basicSerialize(o)
|
|||
return o and "t" or "f"
|
||||
elseif (type(o) == "string") then
|
||||
-- TODO: return refname if it's shorter
|
||||
return string.format("%q", o)
|
||||
return format("%q", o)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,13 +47,52 @@ end
|
|||
-- user Lunatic environment.
|
||||
local savebuffer_mt = {
|
||||
__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
|
||||
-- <refcode> (which should be Lua code that can appear on both sides of
|
||||
-- an assignment).
|
||||
-- <lhscode> on the left hand side of an assignment.
|
||||
-- Returns 'true' if <value> cannot be serialized.
|
||||
add = function(self, refcode, value)
|
||||
add = function(self, lhscode, value)
|
||||
local valcode = basicSerialize(value)
|
||||
local havetab = false
|
||||
|
||||
if (valcode == nil) then
|
||||
-- <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
|
||||
-- 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
|
||||
-- We have a serializeable object from Lunatic
|
||||
-- (e.g. actorvar).
|
||||
|
||||
-- First, get the code necessary to create this object,
|
||||
-- usually 'require'ing a module into a local variable.
|
||||
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()
|
||||
self:getRequire(value)
|
||||
self:emitT(refcode, value:_serialize(), value)
|
||||
valcode = refcode
|
||||
|
||||
elseif (type(value)=="table") then
|
||||
-- We have a Lua table.
|
||||
havetab = true
|
||||
|
||||
-- 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
|
||||
local keystr = basicSerialize(k)
|
||||
|
@ -86,32 +123,29 @@ local savebuffer_mt = {
|
|||
return true
|
||||
end
|
||||
|
||||
if (type(v)=="table" and not isSerializeable(v)) then
|
||||
-- nested tables: NYI
|
||||
return true
|
||||
end
|
||||
|
||||
-- Generate the name under which the table element
|
||||
-- is referenced.
|
||||
local refcode2 = string.format("%s[%s]", refcode, keystr)
|
||||
local refcode2 = format("%s[%s]", refcode, keystr)
|
||||
|
||||
-- Recurse!
|
||||
self:add(refcode2, v)
|
||||
if (self:add(refcode2, v)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
valcode = refcode
|
||||
else
|
||||
-- We have anything else: can't serialize.
|
||||
return true
|
||||
end
|
||||
|
||||
self.val2ref[value] = refcode
|
||||
else
|
||||
-- Object was previously serialized, get Lua expression it
|
||||
-- can be referenced with.
|
||||
valcode = self.val2ref[value]
|
||||
end
|
||||
end
|
||||
|
||||
if (not havetab) then
|
||||
self:addraw(refcode.."="..valcode)
|
||||
end
|
||||
self:emitAssign(lhscode, valcode)
|
||||
end,
|
||||
|
||||
-- Add a single string to the buffer.
|
||||
|
@ -121,7 +155,7 @@ local savebuffer_mt = {
|
|||
|
||||
-- Add a single formatted string to the buffer.
|
||||
addrawf = function(self, fmt, ...)
|
||||
self:addraw(string.format(fmt, ...))
|
||||
self:addraw(format(fmt, ...))
|
||||
end,
|
||||
|
||||
-- Get the Lua code recreating the values as a string.
|
||||
|
@ -141,9 +175,14 @@ end
|
|||
|
||||
-- Create a new savebuffer object.
|
||||
function savebuffer()
|
||||
-- .numrefs: how many table or cdata objects we have serialized
|
||||
-- .val2ref: [<Lua object>] = <Lua code string>
|
||||
-- .havereq = [<string>] = true
|
||||
-- .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)
|
||||
end
|
||||
|
|
|
@ -4,6 +4,8 @@ local con = require("con")
|
|||
local bit = require("bit")
|
||||
local math = require("math")
|
||||
|
||||
local printf = printf
|
||||
local tostring = tostring
|
||||
local rs = con.rotatesprite
|
||||
|
||||
local gameevent = gameevent
|
||||
|
@ -19,10 +21,21 @@ local a_local_gamevar = "yes, this one too"
|
|||
|
||||
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" --==========
|
||||
|
||||
not_a_gamevar = "no"
|
||||
|
||||
printf("a_table.ATAB[4]=%s", tostring(a_table.ATAB[4]))
|
||||
a_table.ATAB[4] = "!FOUR!"
|
||||
|
||||
|
||||
local DOT1x5 = 3135
|
||||
local BAR1x5 = 3163
|
||||
|
|
Loading…
Reference in a new issue