Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Very much based on Lua Table Persistence by 'Black'.
- @license MIT
- "I hope this code is useful for someone, use it as you wish, it
- is licensed under the MIT license."
- @see http://the-color-black.net/blog/article/LuaTablePersistence
- @see https://github.com/hipe/lua-table-persistence
- This 'module'* is specificity written without any dependencies on any other xs* library.
- Also, this is written to be fast (as it can be with a pure Lua implementation), lightweight and
- easy to use.
- Meant to be used with Lua 5.x or LuaJIT 1.1.x.
- LuaJIT 2.x would allow for a few lines less, while also being faster. But its C API has changed
- since 1.1.x and is therefore incompatible.
- * The word module is in quotes, because STALKER doesn't support modules, that is the
- _G.module()/require() function(s).
- ]]
- ---[ PRIVATE ]------------------------------------------------------------------
- --[[
- For anyone wondering this is a LuaJIT 1.x thing (LuaJIT 2.0 does NOT need this).
- It's here to avoid global lookups, that is lookup into the _G table. Because these are
- slower than than lookups in the current/local table (or scope).
- ]]
- local tostring, pairs, type, select, loadfile
- = tostring, pairs, type, select, loadfile
- local sprintf, push, pop, osdate, fopen, ftype
- = string.format, table.insert, table.remove, os.date, io.open, io.type
- local time_global
- = time_global
- local writers = {
- ['nil'] = function (file, item) file:write('nil') end,
- ['number'] = function (file, item) file:write(tostring(item)) end,
- ['string'] = function (file, item) file:write(sprintf('%q', item)) end,
- ['boolean'] = function (file, item) file:write(item and 'true' or 'false') end,
- ['table'] = function (file, item, level, refNameMap)
- local refIndex = refNameMap[item]
- if refIndex then
- file:write('objects[', refIndex, ']')
- else
- file:write('{\n')
- local nextLevel = level + 1
- for k, v in pairs(item) do
- indent(file, nextLevel)
- file:write('[')
- write(file, k, nextLevel, refNameMap)
- file:write('] = ')
- write(file, v, nextLevel, refNameMap)
- file:write(';\n')
- end
- indent(file, level)
- file:write('}')
- end
- end,
- ['function'] = function (file, item) file:write('nil --[[function ', tostring(item), ']]') end,
- ['thread'] = function (file, item) file:write('nil --[[thread ', tostring(item), ']]') end,
- ['userdata'] = function (file, item) file:write('nil --[[userdata ', tostring(item), ']]') end,
- }
- -- TODO: Maybe convert the currently recursive function to iterative+stack one?
- -- Keep in mind that Lua can (since 5.0) optimize tail-recursive calls by its self.
- -- See if LuaJIT supports this special case.
- -- Because countRefs is called twice, and technicality only the last countRefs call is tail-recursive.
- local function countRefs(refCountMap, item)
- if refCountMap[item] then
- refCountMap[item] = refCountMap[item] + 1
- else
- refCountMap[item] = 1
- for k, v in pairs(item) do
- countRefs(refCountMap, k)
- countRefs(refCountMap, v)
- end
- end
- end
- local function write(file, item, level, refNameMap)
- writers[type(item)](file, item, level, refNameMap)
- end
- local function indent(file, level)
- for i = 1, level do
- file:write(' ')
- end
- end
- ---[ PUBLIC ]------------------------------------------------------------------
- function save(path, ...)
- local file, e
- if ftype(path) == 'file' then
- file = path
- else
- file, e = fopen(path, 'w+')
- if not file then
- error(e, 2)
- end
- end
- file:write('-- OS Date/Time: ', osdate('%Y-%m-%d %H:%M %Z'), '\n')
- file:write('-- Game Time: ', time_global(), '\n')
- local n = select('#', ...)
- local refCountMap = {}
- for i = 1, n do
- countRefs(refCountMap, select(i, ...))
- end
- local refIndex = 0
- local refNameMap = {}
- file:write('-- Persistent Data\n')
- file:write('local objects = { ')
- for obj, count in pairs(refCountMap) do
- if count > 1 then
- refIndex = refIndex + 1
- refNameMap[obj] = refIndex
- file:write('{}; ')
- end
- end
- file:write('}\n -- objects\n')
- for obj, idx in pairs(refNameMap) do
- for k, v in pairs(obj) do
- file:write('objects[', idx, '][')
- write(file, k, 0, refNameMap)
- file:write('] = ')
- write(file, v, 0, refNameMap)
- file:write(';\n')
- end
- end
- for i = 1, n do
- file:write('local obj', i ,' = ')
- write(file, select(i, ...), 0, refNameMap)
- file:write('\n')
- end
- if n > 0 then
- file:write('return obj1')
- for i = 2, n do
- file:write(', obj', i)
- end
- file:write('\n')
- else
- file:write('return\n')
- end
- file:close()
- end
- function load(path)
- local f, e = loadfile(path)
- if f then
- return f()
- else
- return nil, e
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment