This section provides examples of how to use the saver
module.
Saver module allows you to bind lua table references. After that, this table will be saved and loaded automatically. You should not re-create the table after loading the game state.
local saver = require("saver.saver")
local game_data = {
score = 0,
level = 1,
}
function init(self)
saver.init()
saver.bind_save_state("game", game_data)
end
The default annotation class for game state is saver.game_state
. You can add your own fields to it right before your place with saver.bind_save_state
.
function init(self)
---Add save states to annotations
---@class saver.game_state
---@field profile profile.state @The `profile.state` is your persistent data annotation class
---@field settings settings.state @The `settings.state` is your persistent data annotation class
saver.init()
saver.bind_game_state("profile", profile.state)
saver.bind_game_state("settings", settings.state)
end
You can use saver.get_game_state()
to get the current game state. It will return the table with all bound states.
function init(self)
saver.init()
saver.bind_save_state("game", game_data)
-- Inspect the game state
pprint(saver.get_game_state())
end
If you wish to make a easy-to-use integration with the Defold Saver module, you can use the following approach:
-- my_library.lua
local M = {}
-- Make an persistent state for your library, which should be saved/loaded
M.state = {
value = 0,
other_value = 0,
}
-- Other functions of your library
-- Integration in the game
local saver = require("saver.saver")
local my_library = require("my_library")
function init(self)
saver.init()
saver.bind_save_state("my_library", my_library.state)
-- After bind save state, you can use your library functions
-- The state will be loaded from the save file and will be saved automatically
my_library.init()
end
Migration is a way to update your save data when you change the structure of the save data. You can use the saver.set_migrations
function to set the list of migrations. The migration is a function that receives the save data and returns the updated save data.
The migrations can be useful if the game has been released and you need to update the save data structure.
local saver = require("saver.saver")
local migrations = {
-- First migration
function(data, logger)
-- Make some changes in the data
data.game.level = 10
data.game.score = nil
end,
-- Second migration
function(data, logger)
data.settings.ui_params = {
scale = 1,
theme = "dark",
}
end,
}
function init(data)
saver.set_migrations(migrations)
saver.init()
saver.bind_save_state("game", game_data)
saver.bind_save_state("settings", settings_data)
-- We need to call `set_migrations` before `init` to correct
-- tracking of current migration version
saver.apply_migrations()
end
Storage is a simple key-value storage. It allows you to save and load values by key. It supports string, number, and boolean values. The functions get_string
, get_number
, and get_boolean
will be useful if you are using lua annotations and want to get the value in the correct type.
local storage = require("saver.storage")
function init(self)
storage.set("key", "value")
local value = storage.get("key") -- Returns "value"
local value_str = storage.get_string("key", "default_value") -- Returns "value"
local value_num = storage.get_number("key", 0) -- Returns 0
local value_bool = storage.get_boolean("key", false) -- Returns false
end
While using Defold Saver, you can make and use a few game states. It can be useful if you have a few game modes or profiles. Or if you want to make an snapshot of the game state to debug some issues.
---@param game_state_name string @Example game_state.json
local function save_game_state(game_state_name)
-- Save the specific game state
saver.save_game_state(game_state_name)
end
---@param game_state_name string @Example game_state.json
local function load_game_state(game_state_name)
-- Reboot and load the specific game state
-- Also disable autosave to prevent overwriting the game state
sys.reboot("--config=saver.save_name=" .. game_state_name, "--config=saver.autosave_timer=0")
end
--- Usage
-- When you want to save the game state
save_game_state("game_state_1.json")
-- When you want to load the game state
load_game_state("game_state_1.json")
With Defold Saver module you also can save and load files. You able to use next functions:
-- This function will save the data inside you game save folder. You can use subfolders in the path
-- file name should contain the file name and extension
saver.save_file_by_name(data, file_name)
saver.load_file_by_name(file_name)
-- This function will save the data to the absolute path
-- file path should contain the file name and extension
saver.save_file_by_path(data, file_path)
saver.load_file_by_path(path)
I use set of init_*
function at bootstrap loader script. This is how I initialize the saver module.
---@param self scene.loader
local function init_saver(self)
---@class saver.game_state
---@field lang lang.state
---@field token token.state
---@field quest quest.state
---@field sound sound.state
saver.init()
saver.bind_save_state("lang", lang.state)
saver.bind_save_state("token", token.state)
saver.bind_save_state("quest", quest.state)
saver.bind_save_state("sound", sound.state)
end
function init_lang(self)
lang.init()
end
function init_token(self)
token.init()
end
function init_quest(self)
quest.init()
end
local function init(self)
init_saver(self)
init_lang(self)
init_token(self)
init_quest(self)
end
In case you want to use your own json.encode function, you can set it to the saver module.
Currently you should override it in saver.saver_internal
module.
local json = require("json")
local saver_internal = require("saver.saver_internal")
saver_internal.json_encode = json.sorted_encode