2019-02-02 17:08:09 +02:00
local Global = require ' utils.global '
2019-05-26 16:18:07 +02:00
local Event = require ' utils.event '
2019-02-02 17:08:09 +02:00
local error = error
2019-02-02 17:28:22 +02:00
local pairs = pairs
2019-02-02 17:08:09 +02:00
local format = string.format
2019-05-28 21:04:30 +02:00
local tostring = tostring
local type = type
2019-05-26 16:18:07 +02:00
local raise_event = script.raise_event
2019-02-02 17:08:09 +02:00
--- Contains a set of callables that will attempt to sanitize and transform the input
2019-05-28 21:04:30 +02:00
local settings_type = require ' resources.setting_types '
local settings = { }
local memory = { }
local missing_setting = {
data_transformation = {
toScalar = function ( input )
if type ( input ) ~= ' table ' then
return input
2019-02-02 17:08:09 +02:00
end
2019-05-28 21:04:30 +02:00
return tostring ( input )
end ,
sanitizer = function ( input )
return true , input
2019-02-02 17:08:09 +02:00
end
2019-05-28 21:04:30 +02:00
}
2019-05-27 21:09:31 +02:00
}
2019-02-02 17:08:09 +02:00
Global.register ( memory , function ( tbl ) memory = tbl end )
local Public = { }
2019-05-26 16:18:07 +02:00
Public.events = {
--- Triggered when a setting is set or updated. Old value may be null if never set before
2019-05-26 20:15:05 +02:00
--- if the value hasn't changed, value_changed = false
2019-05-26 16:18:07 +02:00
-- Event {
2019-05-27 16:01:48 +02:00
-- setting_name = setting_name,
2019-05-26 16:18:07 +02:00
-- old_value = old_value,
-- new_value = new_value,
-- player_index = player_index,
2019-05-26 20:15:05 +02:00
-- value_changed = value_changed
2019-05-26 16:18:07 +02:00
-- }
on_setting_set = Event.generate_event_name ( ' on_setting_set ' ) ,
}
2019-05-29 18:52:15 +02:00
Public.types = {
fraction = ' fraction ' ,
string = ' string ' ,
boolean = ' boolean ' ,
color = ' color ' ,
chat_color = ' chat_color '
}
2019-02-04 18:37:23 +02:00
2019-02-02 17:08:09 +02:00
---Register a specific setting with a sensitization setting type.
---
--- Available setting types:
--- - fraction (number between 0 and 1) in either number or string form
--- - string a string or anything that can be cast to a string
--- - boolean, 1, 0, yes, no, true, false or an empty string for false
---
2019-02-04 18:37:23 +02:00
--- This function must be called in the control stage, i.e. not inside an event.
2019-02-02 17:08:09 +02:00
---
---@param name string
---@param setting_type string
2019-03-03 22:37:50 +02:00
---@param default any
2019-05-26 11:22:14 +02:00
---@param localisation_key|table
2019-03-03 22:37:50 +02:00
function Public . register ( name , setting_type , default , localisation_key )
2019-02-18 08:43:59 +02:00
if _LIFECYCLE ~= _STAGE.control then
2019-02-04 18:37:23 +02:00
error ( format ( ' You can only register setting names in the control stage, i.e. not inside events. Tried setting "%s" with type "%s". ' , name , setting_type ) , 2 )
2019-02-02 17:08:09 +02:00
end
if settings [ name ] then
2019-02-04 18:37:23 +02:00
error ( format ( ' Trying to register setting for "%s" while it has already been registered. ' , name ) , 2 )
2019-02-02 17:08:09 +02:00
end
2019-05-28 21:04:30 +02:00
local data_transformation = settings_type [ setting_type ]
if not data_transformation then
error ( format ( ' Trying to register data_transformation for "%s" with type "%s" while this type does not exist. ' , name , setting_type ) , 2 )
2019-02-02 17:08:09 +02:00
end
local setting = {
2019-03-03 22:37:50 +02:00
type = setting_type ,
2019-02-02 17:08:09 +02:00
default = default ,
2019-05-28 21:04:30 +02:00
data_transformation = data_transformation ,
2019-03-04 21:34:44 +02:00
localised_string = localisation_key and { localisation_key } or name ,
2019-02-02 17:08:09 +02:00
}
settings [ name ] = setting
return setting
end
2019-03-03 22:37:50 +02:00
---Validates whether a given value is valid for a given setting.
---@param name string
---@param value any
function Public . validate ( name , value )
local setting = settings [ name ]
if not setting then
return format ( ' Setting "%s" does not exist. ' , name )
end
2019-05-28 21:04:30 +02:00
local success , sanitized_value = setting.data_transformation . sanitizer ( value )
2019-03-03 22:37:50 +02:00
if not success then
return sanitized_value
end
return nil
end
2019-02-02 17:08:09 +02:00
---Sets a setting to a specific value for a player.
---
---In order to get a setting value, it has to be registered via the "register" function.
---
---@param player_index number
---@param name string
2019-03-03 22:37:50 +02:00
---@param value any
2019-02-02 17:08:09 +02:00
function Public . set ( player_index , name , value )
local setting = settings [ name ]
if not setting then
2019-05-28 21:04:30 +02:00
setting = missing_setting
2019-02-02 17:08:09 +02:00
end
2019-05-28 21:04:30 +02:00
local success , sanitized_value = setting.data_transformation . sanitizer ( value )
2019-02-02 17:08:09 +02:00
if not success then
2019-02-04 18:37:23 +02:00
error ( format ( ' Setting "%s" failed: %s ' , name , sanitized_value ) , 2 )
2019-02-02 17:08:09 +02:00
end
local player_settings = memory [ player_index ]
if not player_settings then
player_settings = { }
memory [ player_index ] = player_settings
end
2019-05-26 16:18:07 +02:00
local old_value = player_settings [ name ]
2019-02-02 17:08:09 +02:00
player_settings [ name ] = sanitized_value
2019-05-26 16:18:07 +02:00
raise_event ( Public.events . on_setting_set , {
2019-05-27 16:01:48 +02:00
setting_name = name ,
old_value = old_value ,
new_value = sanitized_value ,
player_index = player_index ,
value_changed = old_value ~= sanitized_value
2019-05-26 16:18:07 +02:00
} )
2019-02-02 17:08:09 +02:00
return sanitized_value
end
---Returns the value of a setting for this player.
---
---In order to set a setting value, it has to be registered via the "register" function.
---
---@param player_index number
---@param name string
function Public . get ( player_index , name )
local setting = settings [ name ]
if not setting then
2019-05-27 18:57:06 +02:00
return nil
2019-02-02 17:08:09 +02:00
end
local player_settings = memory [ player_index ]
if not player_settings then
return setting.default
end
local player_setting = player_settings [ name ]
2019-05-27 16:40:30 +02:00
if player_setting == nil then
return setting.default
end
return player_setting
2019-02-02 17:08:09 +02:00
end
2019-05-28 21:04:30 +02:00
---Returns the string representation of a given value based on a setting name.
---
---@param name string
---@param raw_value any
function Public . toScalar ( name , raw_value )
local setting = settings [ name ]
if not setting then
setting = missing_setting
end
return setting.data_transformation . toScalar ( raw_value )
end
2019-02-02 17:28:22 +02:00
---Returns a table of all settings for a given player in a key => value setup
---@param player_index number
function Public . all ( player_index )
local player_settings = memory [ player_index ] or { }
local output = { }
for name , data in pairs ( settings ) do
2019-05-27 16:40:30 +02:00
local setting_value = player_settings [ name ]
if setting_value == nil then
output [ name ] = data.default
else
output [ name ] = setting_value
end
2019-02-02 17:28:22 +02:00
end
2019-05-27 18:57:06 +02:00
-- not all settings might be mapped, edge-case is triggered when the
-- server contains settings that are not known in this instance
for name , value in pairs ( player_settings ) do
if output [ name ] == nil then
output [ name ] = value
end
end
2019-02-02 17:28:22 +02:00
return output
end
2019-05-27 18:57:06 +02:00
---Removes a value for a setting for a given name, giving it the default value.
---
---@param player_index number
---@param name string
function Public . unset ( player_index , name )
local player_settings = memory [ player_index ]
if not player_settings then
player_settings = { }
memory [ player_index ] = player_settings
end
local old_value = player_settings [ name ]
player_settings [ name ] = nil
raise_event ( Public.events . on_setting_set , {
setting_name = name ,
old_value = old_value ,
new_value = nil ,
player_index = player_index ,
value_changed = old_value ~= nil
} )
end
2019-03-03 22:37:50 +02:00
---Returns the full settings data, note that this is a reference, do not modify
---this data unless you know what you're doing!
function Public . get_setting_metadata ( )
return settings
end
2019-02-02 17:08:09 +02:00
return Public