new renderer persistence class to save options and configuration easier per renderer

This commit is contained in:
Lera Elvoé 2023-12-13 14:29:25 +03:00
parent a421535f11
commit 1ebcef1d0e
No known key found for this signature in database

View file

@ -0,0 +1,137 @@
class_name RendererPersistence
## An interface for per-renderer persistent data.
##
## Allows renderers to store key/value data, split into namespaces (usually the renderer name)
## and channels (files on a filesystem). For every namespace, a folder is created,
## and populated with JSON files named after the channel name.
const _BASE_PATH := "user://renderer_persistence/"
const _FILE_TEMPLATE := "{namespace}/{channel}.json"
# Dictionary[String -> namespace, Dictionary[String -> channel, Variant]]
static var _data: Dictionary
#region API
## Initializes a namespace. Returns [code]false[/code] if the folder for the namespace didn't exist
## before, useful for initializing defaults.
static func init_namespace(name_space: String) -> bool:
var n := name_space.validate_filename()
if _data.get(n) != null:
return true
var err := _create_namespace_folder(n)
if err != OK:
print("Could not create namespace: error %s" % err)
return false
_data[name_space] = {}
return false
## Returns the corresponding value for the given [param key] in the [param channel] storage.
## If the key does not exist, returns [param default], or [code]null[/code] if the parameter is omitted.
static func get_value(name_space: String, channel: String, key: String, default: Variant) -> Variant:
_lazy_load_channel(name_space, channel)
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
return (_data[validated_name][validated_channel] as Dictionary).get(key, default)
## Sets the value in the [param channel] storage at [param key] to [param value].
static func set_value(name_space: String, channel: String, key: String, value: Variant) -> void:
_lazy_load_channel(name_space, channel)
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
_data[validated_name][validated_channel][key] = value
## Returns the corresponding value for the given [param key] in the [param channel] storage.
## If the key does not exist, creates it in the storage, initializes it to [param default]
## and returns it.
static func get_or_create(name_space: String, channel: String, key: String, default: Variant) -> Variant:
_lazy_load_channel(name_space, channel)
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
var channel_data: Dictionary = _data[validated_name][validated_channel]
return _get_or_create(channel_data, key, default)
## Erases an entry in the store by [param key] and returns its previous value,
## or [code]null[/code] if it didn't exist.
static func erase(name_space: String, channel: String, key: String) -> Variant:
_lazy_load_channel(name_space, channel)
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
var channel_data: Dictionary = _data[validated_name][validated_channel]
var ret = channel_data.get(key)
channel_data.erase(key)
return ret
## Commits the [param channel] to the filesystem. If [param channel] is empty,
## commits all channels in the [param name_space].
static func commit(name_space: String, channel: String = "") -> void:
if !channel.is_empty():
_commit_channel(name_space, channel)
else:
for c: String in _data[name_space]:
_commit_channel(name_space, c)
#endregion
static func _get_or_create(d: Dictionary, key: String, default: Variant) -> Variant:
var r = d.get(key)
if r == null:
r = default
d[key] = r
return r
static func _create_namespace_folder(name_space: String) -> Error:
return DirAccess.make_dir_recursive_absolute(_BASE_PATH.path_join(name_space))
static func _lazy_load_channel(name_space: String, channel: String) -> void:
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
if !_data.has(validated_name):
print("Namespace %s is not initialized" % name_space)
return
if (_data[validated_name] as Dictionary).has(validated_channel):
return
var path := _BASE_PATH.path_join(_FILE_TEMPLATE.format(
{
"namespace": validated_name,
"channel": validated_channel
}))
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
_data[validated_name][validated_channel] = {}
return
var data = JSON.parse_string(f.get_as_text())
_data[validated_name][validated_channel] = data
static func _commit_channel(name_space: String, channel: String) -> void:
_lazy_load_channel(name_space, channel)
var validated_name := name_space.validate_filename()
var validated_channel := channel.validate_filename()
var path := _BASE_PATH.path_join(_FILE_TEMPLATE.format(
{
"namespace": validated_name,
"channel": validated_channel
}))
var f := FileAccess.open(path, FileAccess.WRITE)
f.store_string(JSON.stringify(_data[validated_name][validated_channel], "\t", false))