-- vymdt.01.2010.10.19.0000
-- Created by: Whys -Open source
--===========================================================================
-- SaveUtils
--===========================================================================
--[[
Credits: killmeplease -- serialize() and deserialize().
Special Thanks: Thalassicus, Afforess.
]]
-----------------------------------------------------------------------------
-- Save Class
-----------------------------------------------------------------------------
--[[
Allows SetScriptData() and GetScriptData() to behave as a hash-table of
tables while maintaining seperation of individual mod data.
ie:
save( "myMod", pPlayer, key1, table );
save( "myMod", pPlayer, key2, table );
save( "someMod", pPlayer, key1, table );
save( "myMod", pPlot, ...., ..... ); --same as above.
save( "myMod", pUnit, ...., ..... ); --same as above.
load( "myMod", pPlayer, key1 );
load( "myMod", pPlayer, key2 );
load( "someMod", pPlayer, key1 );
load( "myMod", pPlot, .... ); --same as above.
load( "myMod", pUnit, .... ); --same as above.
load( nil, pPlayer ); --all data for pPlayer.
load( nil, pPlot ); --all data for pPlot.
load( nil, pUnit ); --all data for pUnit.
]]
Save = {};
function Save:new( o )
o = o or {};
setmetatable( o, self );
self.__index = self;
self:initKeys( o );
return o;
end
-------------------------------------------------
-- Save:initKeys()
-------------------------------------------------
--[[
Deep assignment of keyed values. Required for
duplication of table data assigned by key.
]]
function Save:initKeys( o )
for k,v in pairs( o ) do
self[k] = v;
if type( v ) == "table" then
self:initKeys( v );
end
end
end
-------------------------------------------------
-- Save:set()
-------------------------------------------------
--[[
Sets the given value to the given key for the
given mod.
]]
function Save:set( mod, key, value )
self[mod] = self[mod] or {};
self[mod][key] = value;
end
-------------------------------------------------
-- Save:get()
-------------------------------------------------
--[[
Returns value for given mod and key. Returns
self when mod not given.
]]
function Save:get( mod, key )
local r = self;
if mod ~= nil and self[mod] ~= nil and key ~= nil then
r = self[mod][key];
end
return r;
end
-----------------------------------------------------------------------------
--END Save Class
-----------------------------------------------------------------------------
-------------------------------------------------
-- save()
-------------------------------------------------
--[[
Saves the given value to the given key for the
given target of the given mod.
]]
function save( mod, target, key, value )
local pSave = load( mod, target );
pSave:set( mod, key, value );
target:SetScriptData(serialize( pSave ));
end
-------------------------------------------------
-- load()
-------------------------------------------------
--[[
Loads the value for the given key for the given
target of the given mod.
]]
function load( mod, target, key )
local pSave = Save:new(deserialize( target:GetScriptData() ));
return pSave:get( mod, key );
end
-------------------------------------------------
-- serialize()
-------------------------------------------------
--[[
Created by: killmeplease.
]]
function serialize( tbl )
local r = "{ ";
local num = 0;
for k,v in pairs( tbl ) do
if num > 0 then
r = r.." ";
end
r = r..k.."=";
if type( v ) == "table" then
r = r..serialize( v );
else
if v == false or v == true or type( v ) == "number" then
v = tostring( v );
else
v = v:gsub('"', "\[QUOTE\]");
v = v:gsub('{', "\[LCB\]");
v = v:gsub('}', "\[RCB\]");
v = "\""..v.."\""; -- string
end
r = r..v;
end
num = num +1;
end
return r.." }";
end
-------------------------------------------------
-- deserialize()
-------------------------------------------------
--[[
Created by: killmeplease.
]]
function deserialize( str )
local tbls = {}; -- nested tables
local topTbl = {};
repeat
topTbl = {}; -- clear variable for top tbl
-- find first top-level table position in str, its values list and key.
local strStart, strEnd, topTblKey, topTblVals = str:find("([%w]*)={%s([^{}]*)%s}");
if topTblKey == nil then
strStart, strEnd, topTblVals = str:find("{%s([^{}]*)%s}");
end
if topTblVals == nil then
topTblVals = "";
end
--print(topTblVals);
-- parse values:
-- save string values of top table to a temp table
local strings = {};
for vstr in topTblVals:gmatch('"([^"]*)"') do -- match "..." string values
vstr = vstr:gsub("%[QUOTE%]", '"');
vstr = vstr:gsub("%[LCB%]", '{');
vstr = vstr:gsub("%[RCB%]", '}');
table.insert(strings, vstr);
end
-- cut string values from top table string and replace them with "@" symbol
topTblVals = topTblVals:gsub('"[^"]*"', "@");
-- parse key=value pairs
stringNum = 1;
for k,v in topTblVals:gmatch("(%S+)=(%S+)") do
-- parse value
if v == "#" then
v = tbls[k];
-- tbls[k] = nil;
elseif v == "@" then
v = strings[stringNum];
stringNum = stringNum +1;
else
-- parse simple value, a number or a boolean
local n = tonumber(v);
if n ~= nil then
v = n;
elseif v == "true" then
v = true;
elseif v == "false" then
v = false;
end
end
-- parse key:
local n = tonumber(k);
if n ~= nil then
k = n;
end
-- add value to the table:
topTbl[k] = v;
end
if topTblKey ~= nil then -- key is nil when it is a base table
tbls[topTblKey] = topTbl;
str = str:sub(1, strStart -1)..topTblKey.."=#"..str:sub(strEnd +1);
else
str = "#";
end
--print(str);
until str == "#";
return topTbl;
end
--===========================================================================
--END SaveUtils
--===========================================================================
-- Created by: Whys -Open source