2025-01-01 14:43:18 +01:00
|
|
|
local modname = core.get_current_modname()
|
|
|
|
local modpath = core.get_modpath(modname)
|
|
|
|
local S = core.get_translator(modname)
|
|
|
|
local storage = core.get_mod_storage()
|
2024-05-30 13:36:22 +02:00
|
|
|
local mod = {}
|
|
|
|
vl_tuning = mod
|
|
|
|
|
2024-11-17 14:06:03 +01:00
|
|
|
local DEBUG = false
|
|
|
|
|
2024-05-31 04:04:37 +02:00
|
|
|
-- All registered tunable parameters
|
2025-01-01 14:43:18 +01:00
|
|
|
--- @type table<string, vl_tuning.Setting>
|
2024-05-30 13:36:22 +02:00
|
|
|
local tunables = {}
|
2024-06-22 02:28:02 +02:00
|
|
|
vl_tuning.registered_settings = tunables
|
2024-05-30 13:36:22 +02:00
|
|
|
|
2024-05-31 01:23:47 +02:00
|
|
|
-- Supported variable types
|
|
|
|
local tunable_types = {
|
|
|
|
bool = {
|
|
|
|
to_string = tostring,
|
|
|
|
from_string = function(value)
|
|
|
|
return (value == "true")
|
|
|
|
end
|
|
|
|
},
|
|
|
|
number = {
|
|
|
|
to_string = tostring,
|
|
|
|
from_string = tonumber,
|
|
|
|
},
|
|
|
|
string = {
|
|
|
|
to_string = function(v) return v end,
|
|
|
|
from_string = function(v) return v end,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Tunable metatable functions
|
2025-01-01 14:43:18 +01:00
|
|
|
---@class (exact) vl_tuning.Setting
|
|
|
|
---@field name string
|
|
|
|
---@field setting_type "string"|"number"|"bool"
|
|
|
|
---@field description string
|
|
|
|
---@field default? string|integer|boolean
|
|
|
|
---@field set fun(self : vl_tuning.Setting, value, no_hook : boolean?)
|
|
|
|
---@field setter fun(value)
|
|
|
|
---@field getter fun() : string|boolean|number
|
|
|
|
---@field from_string fun(value : string)
|
|
|
|
---@field to_string fun(value : any)
|
|
|
|
---@field on_change? fun(self : vl_tuning.Setting)
|
|
|
|
---@field getter fun()
|
2024-05-31 01:23:47 +02:00
|
|
|
local tunable_class = {}
|
2025-01-01 14:43:18 +01:00
|
|
|
|
|
|
|
---@param self vl_tuning.Setting
|
|
|
|
---@param value any
|
|
|
|
---@param no_hook? boolean
|
2024-06-01 01:53:13 +02:00
|
|
|
function tunable_class:set(value, no_hook)
|
2024-05-31 01:23:47 +02:00
|
|
|
if type(value) == "string" then
|
2025-01-01 14:43:18 +01:00
|
|
|
local new_value = self.from_string(value)
|
2024-05-31 04:36:16 +02:00
|
|
|
if new_value == nil then new_value = self.default end
|
|
|
|
|
2024-11-17 14:06:03 +01:00
|
|
|
self.setter(new_value)
|
2024-05-31 01:23:47 +02:00
|
|
|
else
|
2024-11-17 14:06:03 +01:00
|
|
|
self.setter(value)
|
2024-05-31 01:23:47 +02:00
|
|
|
end
|
|
|
|
|
2024-11-17 14:06:03 +01:00
|
|
|
if DEBUG then
|
2025-01-01 14:43:18 +01:00
|
|
|
core.log("action", "[vl_tuning] Set "..self.name.." to "..dump(self.getter()))
|
2024-11-17 14:06:03 +01:00
|
|
|
end
|
2024-06-01 01:53:13 +02:00
|
|
|
|
|
|
|
-- Call on_change hook
|
|
|
|
if not no_hook then
|
|
|
|
local hook = self.on_change
|
|
|
|
if hook then hook(self) end
|
2024-05-31 01:23:47 +02:00
|
|
|
end
|
2024-06-01 01:53:13 +02:00
|
|
|
|
|
|
|
-- Persist value
|
2025-01-01 14:43:18 +01:00
|
|
|
storage:set_string(self.name,self.to_string(self.getter()))
|
2024-05-31 01:23:47 +02:00
|
|
|
end
|
|
|
|
function tunable_class:get_string()
|
2025-01-01 14:43:18 +01:00
|
|
|
return self.to_string(self.getter())
|
2024-05-31 01:23:47 +02:00
|
|
|
end
|
|
|
|
|
2025-01-01 14:43:18 +01:00
|
|
|
---@class vl_tuning.SettingDef
|
|
|
|
---@field set fun(value : any)
|
|
|
|
---@field get fun(): string|boolean|number
|
|
|
|
---@field default any
|
|
|
|
---@field description? string
|
|
|
|
|
|
|
|
---@param name string
|
|
|
|
---@param p_type? "bool"|"number"|"string"
|
|
|
|
---@param def? vl_tuning.SettingDef
|
|
|
|
---@return vl_tuning.Setting?
|
|
|
|
function mod.setting(name, p_type, def )
|
2024-05-31 04:04:37 +02:00
|
|
|
-- return the existing setting if it was previously registered. Don't update the definition
|
2025-01-01 14:43:18 +01:00
|
|
|
local tunable = tunables[name]
|
2024-05-31 01:23:47 +02:00
|
|
|
if tunable then return tunable end
|
2025-01-01 14:43:18 +01:00
|
|
|
assert(p_type)
|
2024-06-10 04:29:01 +02:00
|
|
|
assert(def)
|
2024-11-17 14:06:03 +01:00
|
|
|
assert(type(def.set) == "function", "Tunable requires set method")
|
|
|
|
assert(type(def.get) == "function", "Tunable required get method")
|
2024-05-31 01:23:47 +02:00
|
|
|
|
2024-05-31 04:04:37 +02:00
|
|
|
-- Setup the tunable data
|
2025-01-01 14:43:18 +01:00
|
|
|
---@type vl_tuning.Setting
|
|
|
|
tunable = {
|
|
|
|
name = name,
|
|
|
|
setting_type = p_type,
|
|
|
|
description = def.description or "",
|
|
|
|
setter = def.set,
|
|
|
|
getter = def.get,
|
|
|
|
set = tunable_class.set,
|
|
|
|
get_string = tunable_class.get_string,
|
|
|
|
from_string = tunable_types[p_type].from_string,
|
|
|
|
to_string = tunable_types[p_type].to_string,
|
|
|
|
}
|
|
|
|
if def.default then
|
|
|
|
tunable:set(def.default)
|
2024-11-17 14:06:03 +01:00
|
|
|
end
|
2024-05-31 01:23:47 +02:00
|
|
|
setmetatable(tunable, {__index=tunable_class})
|
2024-05-31 04:04:37 +02:00
|
|
|
|
|
|
|
-- Load the setting value from mod storage
|
2025-01-01 14:43:18 +01:00
|
|
|
local setting_value = storage:get_string(name)
|
2024-05-31 04:04:37 +02:00
|
|
|
if setting_value and setting_value ~= "" then
|
2024-06-01 01:53:13 +02:00
|
|
|
tunable:set(setting_value, true)
|
2024-11-17 14:06:03 +01:00
|
|
|
if DEBUG then
|
2025-01-01 14:43:18 +01:00
|
|
|
core.log("action", "[vl_tuning] Loading "..name.." = "..dump(setting_value).." ("..dump(tunable.getter())..")")
|
2024-11-17 14:06:03 +01:00
|
|
|
end
|
2024-05-30 13:36:22 +02:00
|
|
|
end
|
2024-05-31 04:04:37 +02:00
|
|
|
|
|
|
|
-- Add to the list of all available settings
|
2025-01-01 14:43:18 +01:00
|
|
|
tunables[name] = tunable
|
2024-05-31 04:04:37 +02:00
|
|
|
|
2025-01-01 14:43:18 +01:00
|
|
|
-- Provide it so that the current value can be retrieved from result.getter()
|
2024-05-31 01:23:47 +02:00
|
|
|
return tunable
|
2024-05-30 13:36:22 +02:00
|
|
|
end
|
|
|
|
|
2025-01-01 14:43:18 +01:00
|
|
|
core.register_chatcommand("set_setting", {
|
2024-05-30 13:36:22 +02:00
|
|
|
description = S("Admin tool to tune settings and game rules"),
|
|
|
|
params = S("<setting> <value>"),
|
|
|
|
privs = { debug = true },
|
|
|
|
func = function(name, params_raw)
|
|
|
|
-- Split apart the params
|
|
|
|
local params = {}
|
|
|
|
for str in string.gmatch(params_raw, "([^ ]+)") do
|
|
|
|
params[#params + 1] = str
|
|
|
|
end
|
|
|
|
|
|
|
|
if #params ~= 2 then
|
|
|
|
return false, S("Usage: /tune <setting> <value>")
|
|
|
|
end
|
2024-05-31 01:23:47 +02:00
|
|
|
|
|
|
|
local tunable = tunables[params[1]]
|
2024-05-31 04:04:37 +02:00
|
|
|
if not tunable then
|
2024-05-31 01:23:47 +02:00
|
|
|
return false, S("Setting @1 doesn't exist", params[1])
|
|
|
|
end
|
2024-05-31 04:04:37 +02:00
|
|
|
|
2024-11-17 14:06:03 +01:00
|
|
|
if DEBUG then
|
2025-01-01 14:43:18 +01:00
|
|
|
core.log("action", "[vl_tuning] "..name.." set ".. params[1] .." to "..params[2])
|
2024-11-17 14:06:03 +01:00
|
|
|
end
|
2024-05-31 04:04:37 +02:00
|
|
|
tunable:set(params[2])
|
|
|
|
return true
|
2024-05-31 01:23:47 +02:00
|
|
|
end
|
|
|
|
})
|
2025-01-01 14:43:18 +01:00
|
|
|
core.register_chatcommand("get_setting", {
|
2024-05-31 01:23:47 +02:00
|
|
|
description = S("Admin tool to view settings and game rules"),
|
|
|
|
params = S("<setting>"),
|
|
|
|
privs = { debug = true },
|
2025-01-01 14:43:18 +01:00
|
|
|
func = function(_, param)
|
2024-05-31 01:23:47 +02:00
|
|
|
local tunable = tunables[param]
|
|
|
|
if tunable then
|
|
|
|
return true, tunable:get_string()
|
|
|
|
else
|
|
|
|
return false, S("Setting @1 doesn't exist", param)
|
|
|
|
end
|
2024-05-30 13:36:22 +02:00
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2025-01-01 14:43:18 +01:00
|
|
|
core.register_chatcommand("gamerule", {
|
2024-05-31 04:04:37 +02:00
|
|
|
description = S("Display or set customizable options"),
|
|
|
|
params = S("<rule> [<value>]"),
|
|
|
|
privs = { server = true },
|
2025-01-01 14:43:18 +01:00
|
|
|
func = function(_, params_raw)
|
2024-05-31 04:04:37 +02:00
|
|
|
-- Split apart the params
|
|
|
|
local params = {}
|
|
|
|
for str in string.gmatch(params_raw, "([^ ]+)") do
|
|
|
|
params[#params + 1] = str
|
|
|
|
end
|
|
|
|
|
|
|
|
if #params < 1 or #params > 2 then
|
|
|
|
return false, S("Usage: /gamerule <rule> [<value>]")
|
|
|
|
end
|
|
|
|
|
|
|
|
local tunable = tunables["gamerule:"..params[1]]
|
|
|
|
if not tunable then
|
|
|
|
return false, S("Game rule @1 doesn't exist", params[1])
|
|
|
|
end
|
|
|
|
|
|
|
|
local value = params[2]
|
|
|
|
if value then
|
2024-11-17 14:06:03 +01:00
|
|
|
if DEBUG then
|
2025-01-01 14:43:18 +01:00
|
|
|
core.log("action", "[vl_tuning] Setting game rule "..params[1].." to "..params[2])
|
2024-11-17 14:06:03 +01:00
|
|
|
end
|
2024-05-31 04:04:37 +02:00
|
|
|
tunable:set(params[2])
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return true, tunable:get_string()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2024-06-10 04:29:01 +02:00
|
|
|
dofile(modpath.."/settings.lua")
|
2024-06-22 02:28:02 +02:00
|
|
|
dofile(modpath.."/gui.lua")
|
2024-11-17 14:06:03 +01:00
|
|
|
|
|
|
|
mod.setting("debug:vl_tuning:report_value_changes", "bool", {
|
|
|
|
default = false,
|
|
|
|
set = function(val) DEBUG = val end,
|
|
|
|
get = function() return DEBUG end,
|
|
|
|
})
|