mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
* ONLY SKYRAT CHANGES * ACTUALLY SKYRAT CHANGES * yolo, revert later * Update alternate_byond_versions.txt Co-authored-by: AnturK <AnturK@users.noreply.github.com>
306 lines
10 KiB
Plaintext
306 lines
10 KiB
Plaintext
#define VALUE_MODE_NUM 0
|
|
#define VALUE_MODE_TEXT 1
|
|
#define VALUE_MODE_FLAG 2
|
|
|
|
#define KEY_MODE_TEXT 0
|
|
#define KEY_MODE_TYPE 1
|
|
|
|
/datum/config_entry
|
|
/// Read-only, this is determined by the last portion of the derived entry type
|
|
var/name
|
|
/// The configured value for this entry. This shouldn't be initialized in code, instead set default
|
|
var/config_entry_value
|
|
/// Read-only default value for this config entry, used for resetting value to defaults when necessary. This is what config_entry_value is initially set to
|
|
var/default
|
|
/// The file which this was loaded from, if any
|
|
var/resident_file
|
|
/// Set to TRUE if the default has been overridden by a config entry
|
|
var/modified = FALSE
|
|
/// The config name of a configuration type that depricates this, if it exists
|
|
var/deprecated_by
|
|
/// The /datum/config_entry type that supercedes this one
|
|
var/protection = NONE
|
|
/// Do not instantiate if type matches this
|
|
var/abstract_type = /datum/config_entry
|
|
/// Force validate and set on VV. VAS proccall guard will run regardless.
|
|
var/vv_VAS = TRUE
|
|
/// Controls if error is thrown when duplicate configuration values for this entry type are encountered
|
|
var/dupes_allowed = FALSE
|
|
/// Stores the original protection configuration, used for set_default()
|
|
var/default_protection
|
|
|
|
/datum/config_entry/New()
|
|
if(type == abstract_type)
|
|
CRASH("Abstract config entry [type] instatiated!")
|
|
name = lowertext(type2top(type))
|
|
default_protection = protection
|
|
set_default()
|
|
|
|
/datum/config_entry/Destroy()
|
|
config.RemoveEntry(src)
|
|
return ..()
|
|
|
|
/**
|
|
* Returns the value of the configuration datum to its default, used for resetting a config value. Note this also sets the protection back to default.
|
|
*/
|
|
/datum/config_entry/proc/set_default()
|
|
if ((protection & CONFIG_ENTRY_LOCKED) && IsAdminAdvancedProcCall())
|
|
log_admin_private("[key_name(usr)] attempted to reset locked config entry [type] to its default")
|
|
return
|
|
if (islist(default))
|
|
var/list/L = default
|
|
config_entry_value = L.Copy()
|
|
else
|
|
config_entry_value = default
|
|
protection = default_protection
|
|
resident_file = null
|
|
modified = FALSE
|
|
|
|
/datum/config_entry/can_vv_get(var_name)
|
|
. = ..()
|
|
if(var_name == NAMEOF(src, config_entry_value) || var_name == NAMEOF(src, default))
|
|
. &= !(protection & CONFIG_ENTRY_HIDDEN)
|
|
|
|
/datum/config_entry/vv_edit_var(var_name, var_value)
|
|
var/static/list/banned_edits = list(NAMEOF_STATIC(src, name), NAMEOF_STATIC(src, vv_VAS), NAMEOF_STATIC(src, default), NAMEOF_STATIC(src, resident_file), NAMEOF_STATIC(src, protection), NAMEOF_STATIC(src, abstract_type), NAMEOF_STATIC(src, modified), NAMEOF_STATIC(src, dupes_allowed))
|
|
if(var_name == NAMEOF(src, config_entry_value))
|
|
if(protection & CONFIG_ENTRY_LOCKED)
|
|
return FALSE
|
|
if(vv_VAS)
|
|
. = ValidateAndSet("[var_value]")
|
|
if(.)
|
|
datum_flags |= DF_VAR_EDITED
|
|
return
|
|
else
|
|
return ..()
|
|
if(var_name in banned_edits)
|
|
return FALSE
|
|
return ..()
|
|
|
|
/datum/config_entry/proc/VASProcCallGuard(str_val)
|
|
. = !((protection & CONFIG_ENTRY_LOCKED) && IsAdminAdvancedProcCall())
|
|
if(!.)
|
|
log_admin_private("[key_name(usr)] attempted to set locked config entry [type] to '[str_val]'")
|
|
|
|
/datum/config_entry/proc/ValidateAndSet(str_val)
|
|
VASProcCallGuard(str_val)
|
|
CRASH("Invalid config entry type!")
|
|
|
|
/datum/config_entry/proc/ValidateListEntry(key_name, key_value)
|
|
return TRUE
|
|
|
|
/datum/config_entry/proc/DeprecationUpdate(value)
|
|
return
|
|
|
|
/datum/config_entry/string
|
|
default = ""
|
|
abstract_type = /datum/config_entry/string
|
|
var/auto_trim = TRUE
|
|
/// whether the string will be lowercased on ValidateAndSet or not.
|
|
var/lowercase = FALSE
|
|
|
|
/datum/config_entry/string/vv_edit_var(var_name, var_value)
|
|
return var_name != NAMEOF(src, auto_trim) && ..()
|
|
|
|
/datum/config_entry/string/ValidateAndSet(str_val)
|
|
if(!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
config_entry_value = auto_trim ? trim(str_val) : str_val
|
|
if(lowercase)
|
|
config_entry_value = lowertext(config_entry_value)
|
|
return TRUE
|
|
|
|
/datum/config_entry/number
|
|
default = 0
|
|
abstract_type = /datum/config_entry/number
|
|
var/integer = TRUE
|
|
var/max_val = INFINITY
|
|
var/min_val = -INFINITY
|
|
|
|
/datum/config_entry/number/ValidateAndSet(str_val)
|
|
if(!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
var/temp = text2num(trim(str_val))
|
|
if(!isnull(temp))
|
|
config_entry_value = clamp(integer ? round(temp) : temp, min_val, max_val)
|
|
if(config_entry_value != temp && !(datum_flags & DF_VAR_EDITED))
|
|
log_config("Changing [name] from [temp] to [config_entry_value]!")
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/config_entry/number/vv_edit_var(var_name, var_value)
|
|
var/static/list/banned_edits = list(NAMEOF_STATIC(src, max_val), NAMEOF_STATIC(src, min_val), NAMEOF_STATIC(src, integer))
|
|
return !(var_name in banned_edits) && ..()
|
|
|
|
/datum/config_entry/flag
|
|
default = FALSE
|
|
abstract_type = /datum/config_entry/flag
|
|
|
|
/datum/config_entry/flag/ValidateAndSet(str_val)
|
|
if(!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
config_entry_value = text2num(trim(str_val)) != 0
|
|
return TRUE
|
|
|
|
/// List config entry, used for configuring a list of strings
|
|
/datum/config_entry/str_list
|
|
abstract_type = /datum/config_entry/str_list
|
|
default = list()
|
|
dupes_allowed = TRUE
|
|
/// whether the string elements will be lowercased on ValidateAndSet or not.
|
|
var/lowercase = FALSE
|
|
|
|
/datum/config_entry/str_list/ValidateAndSet(str_val)
|
|
if (!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
str_val = trim(str_val)
|
|
if (str_val != "")
|
|
config_entry_value += lowercase ? lowertext(str_val) : str_val
|
|
return TRUE
|
|
|
|
/datum/config_entry/number_list
|
|
abstract_type = /datum/config_entry/number_list
|
|
default = list()
|
|
|
|
/datum/config_entry/number_list/ValidateAndSet(str_val)
|
|
if(!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
str_val = trim(str_val)
|
|
var/list/new_list = list()
|
|
var/list/values = splittext(str_val," ")
|
|
for(var/I in values)
|
|
var/temp = text2num(I)
|
|
if(isnull(temp))
|
|
return FALSE
|
|
new_list += temp
|
|
if(!new_list.len)
|
|
return FALSE
|
|
config_entry_value = new_list
|
|
return TRUE
|
|
|
|
/datum/config_entry/keyed_list
|
|
abstract_type = /datum/config_entry/keyed_list
|
|
default = list()
|
|
dupes_allowed = TRUE
|
|
vv_VAS = FALSE //VAS will not allow things like deleting from lists, it'll just bug horribly.
|
|
var/key_mode
|
|
var/value_mode
|
|
var/splitter = " "
|
|
/// whether the key names will be lowercased on ValidateAndSet or not.
|
|
var/lowercase_key = TRUE
|
|
|
|
/datum/config_entry/keyed_list/New()
|
|
. = ..()
|
|
if(isnull(key_mode) || isnull(value_mode))
|
|
CRASH("Keyed list of type [type] created with null key or value mode!")
|
|
|
|
/datum/config_entry/keyed_list/ValidateAndSet(str_val)
|
|
if(!VASProcCallGuard(str_val))
|
|
return FALSE
|
|
|
|
str_val = trim(str_val)
|
|
|
|
var/list/new_entry = parse_key_and_value(str_val)
|
|
|
|
var/new_key = new_entry["config_key"]
|
|
var/new_value = new_entry["config_value"]
|
|
|
|
if(!isnull(new_value) && !isnull(new_key) && ValidateListEntry(new_key, new_value))
|
|
config_entry_value[new_key] = new_value
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/config_entry/keyed_list/proc/parse_key_and_value(option_string)
|
|
// Blank or null option string? Bad mojo!
|
|
if(!option_string)
|
|
log_config("ERROR: Keyed list config tried to parse with no key or value data.")
|
|
return null
|
|
|
|
var/list/config_entry_words = splittext(option_string, splitter)
|
|
var/config_value
|
|
var/config_key
|
|
var/is_ambiguous = FALSE
|
|
|
|
// If this config entry's value mode is flag, the value can either be TRUE or FALSE.
|
|
// However, the config supports implicitly setting a config entry to TRUE by omitting the value.
|
|
// This value mode should also support config overrides disabling it too.
|
|
// The following code supports config entries as such:
|
|
// Implicitly enable the config entry: CONFIG_ENTRY config key goes here
|
|
// Explicitly enable the config entry: CONFIG_ENTRY config key goes here 1
|
|
// Explicitly disable the config entry: CONFIG_ENTRY config key goes here 0
|
|
if(value_mode == VALUE_MODE_FLAG)
|
|
var/value = peek(config_entry_words)
|
|
config_value = TRUE
|
|
|
|
if(value == "0")
|
|
config_key = jointext(config_entry_words, splitter, length(config_entry_words) - 1)
|
|
config_value = FALSE
|
|
is_ambiguous = (length(config_entry_words) > 2)
|
|
else if(value == "1")
|
|
config_key = jointext(config_entry_words, splitter, length(config_entry_words) - 1)
|
|
is_ambiguous = (length(config_entry_words) > 2)
|
|
else
|
|
config_key = option_string
|
|
is_ambiguous = (length(config_entry_words) > 1)
|
|
// Else it has to be a key value pair and we parse it under that assumption.
|
|
else
|
|
// If config_entry_words only has 1 or 0 words in it and isn't value_mode == VALUE_MODE_FLAG then it's an invalid config entry.
|
|
if(length(config_entry_words) <= 1)
|
|
log_config("ERROR: Could not parse value from config entry string: [option_string]")
|
|
return null
|
|
|
|
config_value = pop(config_entry_words)
|
|
config_key = jointext(config_entry_words, splitter)
|
|
|
|
if(lowercase_key)
|
|
config_key = lowertext(config_key)
|
|
|
|
is_ambiguous = (length(config_entry_words) > 2)
|
|
|
|
config_key = validate_config_key(config_key)
|
|
config_value = validate_config_value(config_value)
|
|
|
|
// If there are multiple splitters, it's definitely ambiguous and we'll warn about how we parsed it. Helps with debugging config issues.
|
|
if(is_ambiguous)
|
|
log_config("WARNING: Multiple splitter characters (\"[splitter]\") found. Using \"[config_key]\" as config key and \"[config_value]\" as config value.")
|
|
|
|
return list("config_key" = config_key, "config_value" = config_value)
|
|
|
|
/// Takes a given config key and validates it. If successful, returns the formatted key. If unsuccessful, returns null.
|
|
/datum/config_entry/keyed_list/proc/validate_config_key(key)
|
|
switch(key_mode)
|
|
if(KEY_MODE_TEXT)
|
|
return key
|
|
if(KEY_MODE_TYPE)
|
|
if(ispath(key))
|
|
return key
|
|
|
|
var/key_path = text2path(key)
|
|
if(isnull(key_path))
|
|
log_config("ERROR: Invalid KEY_MODE_TYPE typepath. Is not a valid typepath: [key]")
|
|
return
|
|
|
|
return key_path
|
|
|
|
|
|
/// Takes a given config value and validates it. If successful, returns the formatted key. If unsuccessful, returns null.
|
|
/datum/config_entry/keyed_list/proc/validate_config_value(value)
|
|
switch(value_mode)
|
|
if(VALUE_MODE_FLAG)
|
|
return value
|
|
if(VALUE_MODE_NUM)
|
|
if(isnum(value))
|
|
return value
|
|
|
|
var/value_num = text2num(value)
|
|
if(isnull(value_num))
|
|
log_config("ERROR: Invalid VALUE_MODE_NUM number. Could not parse a valid number: [value]")
|
|
return
|
|
|
|
return value_num
|
|
if(VALUE_MODE_TEXT)
|
|
return value
|
|
|
|
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
|
|
return var_name != NAMEOF(src, splitter) && ..()
|