savedata module
This commit is contained in:
parent
1e58e1fe80
commit
a6f17c0f2a
|
@ -47,7 +47,7 @@ if not select then
|
|||
return #arg
|
||||
else
|
||||
local values = {}
|
||||
for i = math.max(index + 1, 1), #arg do
|
||||
for i = math.max(index, 1), #arg do
|
||||
table.insert(values, arg[i])
|
||||
end
|
||||
return unpack(values)
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
local self = {}
|
||||
|
||||
local binser = require('stdlib.binser')
|
||||
require('stdlib.util')
|
||||
|
||||
local savedataName
|
||||
local savedata = {
|
||||
_lastSave = {0, 0, 0, 0, 0}
|
||||
}
|
||||
local loadedSavedata = false
|
||||
|
||||
self.saveNextFrame = false
|
||||
|
||||
---@param name string @a unique name for the entire modfile
|
||||
---@param forceIgnore boolean | nil
|
||||
--- for picking a name:
|
||||
--- please head to this link:
|
||||
--- https://www.random.org/strings/?num=1&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new
|
||||
--- and generate yourself a hash. afterwards, append it to your game name like so:
|
||||
--- savedata.initializeModule('myGameName_doAmaUOBIjiaSWyz')
|
||||
--- this helps ensure no collisions happen, breaking both of the modfiles in the process!
|
||||
--- **DON'T CHANGE THIS!!** else you'll break existing saves
|
||||
function self.initializeModule(name, forceIgnore)
|
||||
if loadedSavedata then
|
||||
error('uranium: cannot initialize savedata module after uranium.init!', 3)
|
||||
end
|
||||
if not forceIgnore then
|
||||
if #name < 16 then
|
||||
error('uranium: savedata name too short! must be at least 16 characters long', 2)
|
||||
end
|
||||
|
||||
local normalChars = 0
|
||||
local specialChars = 0
|
||||
for i = 1, #name do
|
||||
local char = string.sub(name, i, i)
|
||||
local special = string.lower(char) == string.upper(char)
|
||||
if special then
|
||||
specialChars = specialChars + 1
|
||||
else
|
||||
normalChars = normalChars + 1
|
||||
end
|
||||
end
|
||||
|
||||
if normalChars < 4 then
|
||||
error('uranium: savedata name should have at least 4 non-special characters!', 2)
|
||||
end
|
||||
if specialChars < 2 then
|
||||
error('uranium: savedata name should have at least 2 special characters!', 2)
|
||||
end
|
||||
end
|
||||
|
||||
savedataName = name
|
||||
end
|
||||
|
||||
local function checkIfInitialized()
|
||||
if not savedataName then
|
||||
error('uranium: savedata not initialized! please run savedata.initializeModule first', 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function convertSource(s)
|
||||
local pathSplit = split(s.source, '/')
|
||||
local lastTwo = pathSplit[#pathSplit - 1] .. '/' .. string.sub(pathSplit[#pathSplit], 1, -5)
|
||||
return lastTwo
|
||||
end
|
||||
|
||||
---@param data table
|
||||
---@param name string | nil
|
||||
function self.s(data, name)
|
||||
if not name then name = convertSource(debug.getinfo(2, 'S')) end
|
||||
checkIfInitialized()
|
||||
if loadedSavedata then
|
||||
error('uranium: cannot add new savedata after initializing!', 3)
|
||||
end
|
||||
if string.sub(name, 1, 1) == '_' then
|
||||
error('uranium: cannot start savedata name with an underscore', 2)
|
||||
end
|
||||
savedata[name] = data
|
||||
end
|
||||
|
||||
--- prefers tab1 with type mismatches; prefers tab2 with value mismatches
|
||||
local function mergeTable(tab1, tab2)
|
||||
local tab = {}
|
||||
for k, v1 in pairs(tab1) do
|
||||
local v2 = tab2[k]
|
||||
if type(v1) ~= type(v2) then
|
||||
tab[k] = v1
|
||||
else
|
||||
if type(v1) == 'table' then
|
||||
tab[k] = mergeTable(v1, v2)
|
||||
else
|
||||
tab[k] = v2
|
||||
end
|
||||
end
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
--- replaces tab1 with tab2, preserving pointers
|
||||
--- this sucks
|
||||
local function replaceFromRoot(tab1, tab2)
|
||||
local keys = {}
|
||||
for k in pairs(tab1) do
|
||||
if not includes(keys, k) then
|
||||
table.insert(keys, k)
|
||||
end
|
||||
end
|
||||
for k in pairs(tab2) do
|
||||
if not includes(keys, k) then
|
||||
table.insert(keys, k)
|
||||
end
|
||||
end
|
||||
|
||||
for _, key in ipairs(keys) do
|
||||
if type(tab1[key]) == type(tab2[key]) and type(tab1[key]) == 'table' then
|
||||
replaceFromRoot(tab1[key], tab2[key])
|
||||
else
|
||||
tab1[key] = tab2[key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function self.load()
|
||||
checkIfInitialized()
|
||||
print('loading...')
|
||||
local profile = PROFILEMAN:GetMachineProfile():GetSaved()
|
||||
local save = {}
|
||||
local serialized = profile[savedataName]
|
||||
|
||||
if not serialized then
|
||||
print('no savedata found')
|
||||
save = savedata
|
||||
else
|
||||
print('savedata found: ' .. serialized)
|
||||
save = binser.deserializeN(serialized, 1)
|
||||
print('deserialized: ' .. fullDump(save))
|
||||
end
|
||||
|
||||
local newSavedata = mergeTable(savedata, save)
|
||||
replaceFromRoot(savedata, newSavedata)
|
||||
print('merged: ' .. fullDump(savedata))
|
||||
end
|
||||
|
||||
---@param instant boolean | nil
|
||||
function self.save(instant)
|
||||
checkIfInitialized()
|
||||
print('saving...')
|
||||
local profile = PROFILEMAN:GetMachineProfile():GetSaved()
|
||||
savedata._lastSave = {Hour(), Minute(), DayOfMonth(), MonthOfYear(), Year()}
|
||||
print('savedata: ' .. fullDump(savedata))
|
||||
local serialized = binser.serialize(savedata)
|
||||
print('serialized: ' .. serialized)
|
||||
profile[savedataName] = serialized
|
||||
|
||||
uranium:call('save')
|
||||
if instant then
|
||||
PROFILEMAN:SaveMachineProfile()
|
||||
uranium:call('saveFinished')
|
||||
else
|
||||
self.saveNextFrame = true
|
||||
end
|
||||
end
|
||||
|
||||
function uranium.init()
|
||||
loadedSavedata = true
|
||||
if savedataName then
|
||||
self.load()
|
||||
end
|
||||
end
|
||||
|
||||
function uranium.update()
|
||||
if self.saveNextFrame then
|
||||
self.saveNextFrame = false
|
||||
PROFILEMAN:SaveMachineProfile()
|
||||
uranium:call('saveFinished')
|
||||
print('saved to profile')
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
|
@ -154,4 +154,26 @@ function clearMetatables(tab)
|
|||
clearMetatables(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param source string
|
||||
---@param sep string
|
||||
---@return string[]
|
||||
-- https://stackoverflow.com/a/42607786
|
||||
function split(source, sep)
|
||||
local result, i = {}, 1
|
||||
while true do
|
||||
local a, b = string.find(source, sep)
|
||||
if not a then break end
|
||||
local candidat = string.sub(source, 1, a - 1)
|
||||
if candidat ~= '' then
|
||||
result[i] = candidat
|
||||
end
|
||||
i = i + 1
|
||||
source = string.sub(source, b + 1)
|
||||
end
|
||||
if source ~= '' then
|
||||
result[i] = source
|
||||
end
|
||||
return result
|
||||
end
|
|
@ -11,6 +11,8 @@ GAMESTATE = {}
|
|||
PREFSMAN = {}
|
||||
---@type ScreenManager
|
||||
SCREENMAN = {}
|
||||
---@type ProfileManager
|
||||
PROFILEMAN = {}
|
||||
|
||||
---@return Quad
|
||||
--- Defines a Quad actor.
|
||||
|
|
Loading…
Reference in New Issue