159 lines
6.8 KiB
Lua
159 lines
6.8 KiB
Lua
|
--- Operations for game settings / stats.
|
||
|
-- @module Noble.Settings
|
||
|
--
|
||
|
Noble.Settings = {} -- This is the "class" that holds methods.
|
||
|
local settings = nil -- This is the actual settings object. We keep it local to avoid direct tampering.
|
||
|
local settingsDefault = nil -- We keep track of default values so they can be reset.
|
||
|
|
||
|
local function keyChange(__dataDefault, __data)
|
||
|
local defaultKeys = {}
|
||
|
local keys = {}
|
||
|
for key, value in pairs(__dataDefault) do table.insert(defaultKeys, key) end
|
||
|
for key, value in pairs(__data) do table.insert(keys, key) end
|
||
|
for i = 1, #keys, 1 do
|
||
|
if (defaultKeys[i] ~= keys[i]) then return true end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local function settingExists(__key)
|
||
|
-- Check for valid data item.
|
||
|
for key, value in pairs(settings) do
|
||
|
if __key == key then
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
error("BONK: Setting \'" .. __key .. "\' does not exist. Maybe you spellet ti wronlgly.", 3)
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local settingsHaveBeenSetup = false
|
||
|
|
||
|
--- Sets up the settings for your game. You can only run this once, and you must run it before using other `Noble.Settings` functions. It is recommended to place it in your main.lua, before `Noble.new()`.
|
||
|
--
|
||
|
-- <strong>NOTE:</strong> You will *not* be able to add new keys via the `Noble.Settings.set` method. This means you need to specify the keys and default values of all of the settings in your game at setup.
|
||
|
-- If you need to add keys that are not known during setup, it is probably not a setting and you should consider using `Noble.GameData` instead.
|
||
|
-- @tparam table __keyValuePairs table. Your game's settings, and thier default values, as key/value pairs. <strong>NOTE:</strong> Do not use "nil" as a value.
|
||
|
-- @bool[opt=true] __saveToDisk Saves your default values immediatly to disk.
|
||
|
-- @bool[opt=true] __modifyExistingOnKeyChange Updates the existing settings object on disk if you make changes to your settings keys (not values) during development or when updating your game.
|
||
|
-- @usage
|
||
|
-- Noble.Settings.setup({
|
||
|
-- difficulty = "normal",
|
||
|
-- music = true,
|
||
|
-- sfx = true,
|
||
|
-- players = 2,
|
||
|
-- highScore = 0 -- You can store persistant stats here, too!
|
||
|
-- })
|
||
|
function Noble.Settings.setup(__keyValuePairs, __saveToDisk, __modifyExistingOnKeyChange)
|
||
|
if (settingsHaveBeenSetup) then
|
||
|
error("BONK: You can only run Noble.Settings.setup() once.")
|
||
|
return
|
||
|
else
|
||
|
settingsHaveBeenSetup = true
|
||
|
end
|
||
|
|
||
|
-- Prevent using the setup() method if there are no settings to register
|
||
|
if (__keyValuePairs == nil or table.getSize(__keyValuePairs) == 0) then
|
||
|
error("BONK: Do not use Noble.Settings.setup if you do not have any settings to register. New settings cannot be added via Noble.Settings.set and must be all declared upfront in the Noble.Settings.setup method.")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local saveToDisk = Utilities.handleOptionalBoolean(__saveToDisk, true)
|
||
|
local modifyExistingOnKeyChange = Utilities.handleOptionalBoolean(__modifyExistingOnKeyChange, true)
|
||
|
settingsDefault = __keyValuePairs
|
||
|
|
||
|
-- Get existing settings from disk, if any.
|
||
|
settings = Datastore.read("Settings")
|
||
|
|
||
|
if (settings == nil) then
|
||
|
-- No settings on disk, so we create a new settings object using default values.
|
||
|
settings = table.deepcopy(settingsDefault)
|
||
|
elseif (modifyExistingOnKeyChange and keyChange(settingsDefault, settings)) then
|
||
|
-- Found settings on disk, but key changes have been made...
|
||
|
-- ...so we start with a new default settings object...
|
||
|
local existingSettings = table.deepcopy(settings)
|
||
|
settings = table.deepcopy(settingsDefault)
|
||
|
for key, value in pairs(settings) do
|
||
|
-- ...then copy settings with unchanged keys to the new settings object,
|
||
|
-- naturally discarding keys that don't exist anymore.
|
||
|
if (existingSettings[key] ~= nil) then settings[key] = existingSettings[key] end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
if (saveToDisk) then
|
||
|
Noble.Settings.save()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Get the value of a setting.
|
||
|
-- @string __settingName The name of the setting.
|
||
|
-- @treturn any The value of the requested setting.
|
||
|
-- @see set
|
||
|
function Noble.Settings.get(__settingName)
|
||
|
if (settingExists(__settingName)) then
|
||
|
return settings[__settingName]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Set the value of a setting.
|
||
|
--
|
||
|
-- <strong>NOTE:</strong> If __settingName is not a key in the __keyValuePairs dictionary given to the `setup` method it will not be added to the Settings.
|
||
|
-- @string __settingName The name of the setting.
|
||
|
-- @tparam any __value The setting's new value
|
||
|
-- @bool[opt=true] __saveToDisk Saves to disk immediately. Set to false if you prefer to manually save (via a confirm button, etc).
|
||
|
-- @see setup
|
||
|
-- @see get
|
||
|
-- @see save
|
||
|
function Noble.Settings.set(__settingName, __value, __saveToDisk)
|
||
|
if (settingExists(__settingName)) then
|
||
|
settings[__settingName] = __value
|
||
|
local saveToDisk = Utilities.handleOptionalBoolean(__saveToDisk, true)
|
||
|
if (saveToDisk) then Noble.Settings.save() end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Resets the value of a setting to its default value defined in `setup()`.
|
||
|
-- @string __settingName The name of the setting.
|
||
|
-- @bool[opt=true] __saveToDisk Saves to disk immediately. Set to false if you prefer to manually save (via a confirm button, etc).
|
||
|
-- @see resetSome
|
||
|
-- @see resetAll
|
||
|
-- @see save
|
||
|
function Noble.Settings.reset(__settingName, __saveToDisk)
|
||
|
if (settingExists(__settingName)) then
|
||
|
settings[__settingName] = settingsDefault[__settingName]
|
||
|
local saveToDisk = Utilities.handleOptionalBoolean(__saveToDisk, true)
|
||
|
if (saveToDisk) then Noble.Settings.save() end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Resets the value of multiple settings to thier default value defined in `setup()`. This is useful if you are storing persistant stats like high scores in `Settings` and want the player to be able to reset them seperately.
|
||
|
-- @tparam table __settingNames The names of the settings, in an array-style table.
|
||
|
-- @bool[opt=true] __saveToDisk Saves to disk immediately. Set to false if you prefer to manually save (via a confirm button, etc).
|
||
|
-- @see resetAll
|
||
|
-- @see save
|
||
|
function Noble.Settings.resetSome(__settingNames, __saveToDisk)
|
||
|
for i = 1, #__settingNames, 1 do
|
||
|
Noble.Settings.reset(__settingNames[i], __saveToDisk)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Resets all settings to thier default values defined in `setup()`.
|
||
|
-- @bool[opt=true] __saveToDisk Saves to disk immediately. Set to false if you prefer to manually save (via a confirm button, etc).
|
||
|
-- @see resetSome
|
||
|
-- @see save
|
||
|
function Noble.Settings.resetAll(__saveToDisk)
|
||
|
settings = table.deepcopy(settingsDefault)
|
||
|
local saveToDisk = Utilities.handleOptionalBoolean(__saveToDisk, true)
|
||
|
if (saveToDisk) then Noble.Settings.save() end
|
||
|
end
|
||
|
|
||
|
--- Saves settings to disk.
|
||
|
-- You don't need to call this unless you set `__saveToDisk` as false when setting or resetting a setting (say that five times fast!).
|
||
|
-- @see set
|
||
|
-- @see reset
|
||
|
-- @see resetAll
|
||
|
function Noble.Settings.save()
|
||
|
Datastore.write(settings, "Settings")
|
||
|
end
|