-- marshal provides low-level data marshalling capabilities, but
-- for various reasons it's handy to have a higher-level interface
-- that allows us to register and retrieve data structures from
-- node or item metadata. this library provides that interface.
-- objstore consists of a single function that returns a structure
-- store. this structure-store should be saved to a variable, and
-- called upon to register or modify attributes. every node or item
-- that contains metadata contains a list of attached structures,
-- which themselves contain a list of attached records. this allows
-- structures to be extended at will without disrupting existing
-- metadata storage.
-- WARNING: this is likely incompatible with the StorageRef backend,
-- which uses json -- need to figure out how to make the marshalling
-- format compatible
local lib = sorcery.lib
local m = lib.marshal
local recpack, recunpack = m.transcoder {
recs = m.g.array(m.g.struct {
id = m.t.str;
data = m.t.blob;
});
}
return function() {
return {
structs = {};
register = function(self,id)
local struc = {
id = id;
records = {};
register_record = function(self,def)
if not records[def.id] then
records[def.id] = def
return true
else
return false
end
end;
_encode = function(self,data)
local obj = {}
for k,v in pairs(records) do
local t = m.transcoder(v.fields)
obj[#obj + 1] = {
id = k;
data = t(data[k]);
}
end
return recpack(obj)
end;
_decode = function(self,str)
end;
_meta = function(self,store)
return {
store = store;
_getall = function(iself)
return self:_decode(lib.str.meta_dearmor(iself.store:get_string('objstore:'..id),true))
end;
_save = function(iself,obj)
iself.store:set_string('objstore:'..id, lib.str.meta_armor(self:_encode(obj)))
end;
get = function(self,rec)
local recs = recunpack(lib.str.meta_dearmor(self.store:get_string('objstore:'..id),true))
for _,r in pairs(recs) do
if r.id == rec then
return r
end
end
return nil
end;
merge = function(self,obj)
-- obj should be a table of structure {
-- record_id = { record_field = value; }
-- }, e.g.:
-- sorcery.store.enchantment.merge {
-- spells = {
-- [4] = { id = 'dowse, boost = 15 }
-- }
-- }
local recs = self:_getall()
for rec,flds in pairs(obj) do
for k,v in pairs(flds) do
if not recs[rec] then recs[rec] = {} end
recs[rec][k] = v
end
end
self:_save(recs)
end;
}
end;
item = function(self,stack)
return self:_meta(stack:get_meta())
end;
node = function(self,pos)
return self:_meta(minetest.get_meta(pos))
end;
user = function(self,u)
if type(u) == 'string' then
u = minetest.get_player_by_name(u)
end
return self:_meta(u:get_meta())
end;
}
self.structs[id] = struc;
return struc;
end;
}
}