Xetrill

xs_storage.script

Oct 18th, 2013
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.67 KB | None | 0 0
  1. --[[
  2.     Very much based on Lua Table Persistence by 'Black'.
  3.  
  4.     @license MIT
  5.         "I hope this code is useful for someone, use it as you wish, it
  6.          is licensed under the MIT license."
  7.     @see http://the-color-black.net/blog/article/LuaTablePersistence
  8.     @see https://github.com/hipe/lua-table-persistence
  9.  
  10.     This 'module'* is specificity written without any dependencies on any other xs* library.
  11.  
  12.     Also, this is written to be fast (as it can be with a pure Lua implementation), lightweight and
  13.     easy to use.
  14.     Meant to be used with Lua 5.x or LuaJIT 1.1.x.
  15.     LuaJIT 2.x would allow for a few lines less, while also being faster. But its C API has changed
  16.     since 1.1.x and is therefore incompatible.
  17.  
  18.     * The word module is in quotes, because STALKER doesn't support modules, that is the
  19.     _G.module()/require() function(s).
  20. ]]
  21.  
  22. ---[ PRIVATE ]------------------------------------------------------------------
  23.  
  24. --[[
  25.     For anyone wondering this is a LuaJIT 1.x thing (LuaJIT 2.0 does NOT need this).
  26.     It's here to avoid global lookups, that is lookup into the _G table. Because these are
  27.     slower than than lookups in the current/local table (or scope).
  28. ]]
  29. local tostring, pairs, type, select, loadfile
  30.     = tostring, pairs, type, select, loadfile
  31. local sprintf, push, pop, osdate, fopen, ftype
  32.     = string.format, table.insert, table.remove, os.date, io.open, io.type
  33. local time_global
  34.     = time_global
  35.  
  36. local writers = {
  37.     ['nil']     = function (file, item) file:write('nil') end,
  38.     ['number']  = function (file, item) file:write(tostring(item)) end,
  39.     ['string']  = function (file, item) file:write(sprintf('%q', item)) end,
  40.     ['boolean'] = function (file, item) file:write(item and 'true' or 'false') end,
  41.     ['table']   = function (file, item, level, refNameMap)
  42.         local refIndex = refNameMap[item]
  43.         if refIndex then
  44.             file:write('objects[', refIndex, ']')
  45.         else
  46.             file:write('{\n')
  47.             local nextLevel = level + 1
  48.             for k, v in pairs(item) do
  49.                 indent(file, nextLevel)
  50.                 file:write('[')
  51.                 write(file, k, nextLevel, refNameMap)
  52.                 file:write('] = ')
  53.                 write(file, v, nextLevel, refNameMap)
  54.                 file:write(';\n')
  55.             end
  56.             indent(file, level)
  57.             file:write('}')
  58.         end
  59.     end,
  60.     ['function'] = function (file, item) file:write('nil --[[function ', tostring(item), ']]') end,
  61.     ['thread']   = function (file, item) file:write('nil --[[thread ',   tostring(item), ']]') end,
  62.     ['userdata'] = function (file, item) file:write('nil --[[userdata ', tostring(item), ']]') end,
  63. }
  64.  
  65. -- TODO: Maybe convert the currently recursive function to iterative+stack one?
  66. -- Keep in mind that Lua can (since 5.0) optimize tail-recursive calls by its self.
  67. -- See if LuaJIT supports this special case.
  68. -- Because countRefs is called twice, and technicality only the last countRefs call is tail-recursive.
  69. local function countRefs(refCountMap, item)
  70.     if refCountMap[item] then
  71.         refCountMap[item] = refCountMap[item] + 1
  72.     else
  73.         refCountMap[item] = 1
  74.         for k, v in pairs(item) do
  75.             countRefs(refCountMap, k)
  76.             countRefs(refCountMap, v)
  77.         end
  78.     end
  79. end
  80.  
  81. local function write(file, item, level, refNameMap)
  82.     writers[type(item)](file, item, level, refNameMap)
  83. end
  84.  
  85. local function indent(file, level)
  86.     for i = 1, level do
  87.         file:write('    ')
  88.     end
  89. end
  90.  
  91.  
  92. ---[ PUBLIC ]------------------------------------------------------------------
  93.  
  94. function save(path, ...)
  95.     local file, e
  96.     if ftype(path) == 'file' then
  97.         file = path
  98.     else
  99.         file, e = fopen(path, 'w+')
  100.         if not file then
  101.             error(e, 2)
  102.         end
  103.     end
  104.  
  105.     file:write('-- OS Date/Time: ', osdate('%Y-%m-%d %H:%M %Z'), '\n')
  106.     file:write('-- Game Time: ', time_global(), '\n')
  107.  
  108.     local n = select('#', ...)
  109.     local refCountMap = {}
  110.     for i = 1, n do
  111.         countRefs(refCountMap, select(i, ...))
  112.     end
  113.  
  114.     local refIndex   = 0
  115.     local refNameMap = {}
  116.     file:write('-- Persistent Data\n')
  117.  
  118.     file:write('local objects = { ')
  119.     for obj, count in pairs(refCountMap) do
  120.         if count > 1 then
  121.             refIndex = refIndex + 1
  122.             refNameMap[obj] = refIndex
  123.             file:write('{}; ')
  124.         end
  125.     end
  126.  
  127.     file:write('}\n -- objects\n')
  128.     for obj, idx in pairs(refNameMap) do
  129.         for k, v in pairs(obj) do
  130.             file:write('objects[', idx, '][')
  131.             write(file, k, 0, refNameMap)
  132.             file:write('] = ')
  133.             write(file, v, 0, refNameMap)
  134.             file:write(';\n')
  135.         end
  136.     end
  137.  
  138.     for i = 1, n do
  139.         file:write('local obj', i ,' = ')
  140.         write(file, select(i, ...), 0, refNameMap)
  141.         file:write('\n')
  142.     end
  143.  
  144.     if n > 0 then
  145.         file:write('return obj1')
  146.         for i = 2, n do
  147.             file:write(', obj', i)
  148.         end
  149.         file:write('\n')
  150.     else
  151.         file:write('return\n')
  152.     end
  153.  
  154.     file:close()
  155. end
  156.  
  157. function load(path)
  158.     local f, e = loadfile(path)
  159.     if f then
  160.         return f()
  161.     else
  162.         return nil, e
  163.     end
  164. end
Advertisement
Add Comment
Please, Sign In to add comment