add game&rawdata

This commit is contained in:
Vasily Petrov 2026-06-17 23:06:51 +03:00
parent 0133cd976c
commit 49b34b5546
45731 changed files with 709831 additions and 0 deletions

View file

@ -0,0 +1,218 @@
--[[
This script handles the serialization of data using the marshal library and the saving of this data to disk depending
on save game name. What this means is that you can save entire tables to disk instead of saving to object packet.
This script was created to alleviate issues with using packets to save dynamic data (pstor) which lead to save corruption.
Also it removes some restrictions on what you can save.
*only store valid lua types such as numbers, strings, boolean, functions or tables that contain these valid types. Userdata needs to have a special
__persist function defined in it's metatable. See how it is done for CTime in _G.script
*Supposedly you can save userdata if you write a proper __persist method for the metatable but I have failed to achieve proper results with serializing CTime.
*You must register for 'save_state' and 'load_state' and add your own table to m_data for it to be encoded then stored in *.scoc
*Although marshal is pretty fast, keep in mind that encoding/decoding a ton of data, saves will start to noticeablely take longer to save/load.
*For testing/debugging you can uncomment the print_table calls in save_state and load_state. It will save the before and after tables to print_table.txt in your main directory.
by: Alundaio
--]]
local m_data = {}
-- store stuff that you want to persist even offline
m_data.se_object = {}
-- store stuff only for online objects. When object goes offline this table is purged.
m_data.game_object = {}
-- PDA known contacts
-- m_data.actor_contacts = {}
saved_game_extension_ex = save_extension() .. "_data"
local function on_pstor_load_all(obj,packet)
local id = obj:id()
local state = get_game_object_state(obj,false)
if (state and db.storage[id]) then
if (state.pstor_all) then
db.storage[id].pstor = state.pstor_all
state.pstor_all = nil
end
if (state.pstor_ctime) then
db.storage[id].pstor_ctime = state.pstor_ctime
state.pstor_ctime = nil
end
end
end
function on_game_start()
if not isMarshal then
return
end
--RegisterScriptCallback("on_pstor_load_all",on_pstor_load_all)
end
-- called from engine!
function CALifeStorageManager_before_save(fname)
if not isMarshal then
return
end
--printf("CALifeStorageManager_before_save BEFORE callback")
m_data.GAME_VERSION = GAME_VERSION
SendScriptCallback("save_state",m_data)
--printf("CALifeStorageManager_before_save AFTER callback")
-- save pstor
for id,t in pairs(db.storage) do
if (m_data.game_object[id]) then
if (t.pstor and not is_empty(t.pstor)) then
m_data.game_object[id].pstor_all = t.pstor
end
-- serialization with game.CTime.__persist
if (t.pstor_ctime and not is_empty(t.pstor_ctime)) then
m_data.game_object[id].pstor_ctime = t.pstor_ctime
end
end
end
--ProcessEventQueueState(m_data,true)
-- clean out game_object table of empty sub tables
for id,tbl in pairs(m_data.game_object) do
for k,v in pairs(tbl) do
if (type(v) == "table" and is_empty(v)) then
m_data.game_object[id][k] = nil
end
end
end
local data = marshal.encode(m_data)
if not (data) then
return
end
local path = getFS():update_path('$game_saves$', '')
lfs.mkdir(path) -- incase savegame folder doesn't exist yet
path = path .. fname:sub(0,-6):lower() .. saved_game_extension_ex
local savegame = io.open(path,"wb")
if not (io.type(savegame) == "file") then
printf("Error: Unable to write to %s",path)
return
end
--printf("axr_main: saving custom data %s",path)
savegame:write(data)
savegame:close()
--printf("CALifeStorageManager_before_save FINISHED")
end
-- called from engine!
function CALifeStorageManager_after_save(fname)
if ffx_path_utils then
fname = ffx_path_utils.get_file_name(fname, false)
end
local _path = getFS():update_path('$game_saves$', '')
SendScriptCallback("save_file_created", _path, fname)
end
-- called from engine!
function CALifeStorageManager_new_game(fname)
if ffx_path_utils then
fname = ffx_path_utils.get_file_name(fname, false)
end
local _path = getFS():update_path('$game_saves$', '')
SendScriptCallback("new_game_created", _path, fname)
end
-- called from engine!
function CALifeStorageManager_save(fname)
--printf("CALifeStorageManager_save START FINISHED")
end
-- called from engine
function CALifeStorageManager_load(fname)
if not isMarshal then
return
end
local path = fname:sub(0,-6) .. saved_game_extension_ex
--alun_utils.debug_write(strformat("CALifeStorageManager_load %s",path))
local savegame = io.open(path,"rb")
if not (io.type(savegame) == "file") then
return
end
local data = savegame:read("*all")
savegame:close()
if not (data and data ~= "") then
printf("Error: Failed to read %s",path)
return
end
m_data = marshal.decode(data)
--ProcessEventQueueState(m_data,false)
-- For debugging save state
--alun_utils.print_table(m_data,"m_data_on_load ("..path..")")
SendScriptCallback("load_state",m_data)
if ffx_path_utils then
fname = ffx_path_utils.get_file_name(fname, false)
end
local _path = getFS():update_path('$game_saves$', '')
SendScriptCallback("save_file_loaded", _path, fname)
--alun_utils.debug_write(strformat("CALifeStorageManager_load END"))
end
function get_state()
return m_data
end
function decode(t)
return marshal.decode(t)
end
-- storage based on ID but verified by object name
function get_game_object_state(obj,create_if_dont_exist)
local id = obj:id()
local name = obj:name()
if not (m_data.game_object[id]) then
if not (create_if_dont_exist) then
return
end
m_data.game_object[id] = {}
m_data.game_object[id].name = name
end
return m_data.game_object[id]
end
function get_se_obj_state(se_obj,create_if_dont_exist)
local id = se_obj.id
local name = se_obj:name()
if not (m_data.se_object[id]) then
if not (create_if_dont_exist) then
return
end
m_data.se_object[id] = {}
m_data.se_object[id].name = name
end
return m_data.se_object[id]
end