-
Notifications
You must be signed in to change notification settings - Fork 37
feat: ✨ Advanced Mod Configs #237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: ✨ Advanced Mod Configs #237
Conversation
With it `_handle_mod_config()` | `_get_config_default_data()` generates the `config_default`s from the `config_schema` default keys | `get_config_default_data_as_string()` | `get_config_schema_as_string()` | `is_config_valid()` validates the config based on the schema using the `JSON_Schema_Validator` Addon
If there is no json file for this mod config yet
With this change, the config data of the `config_defaults` defined in the `config_schema` is available in the first run.
used in `ModManifest` to get `config_schema`
Only returning the full config data without the key parameter, as it only allowed retrieving top-level properties. | Removing the distinction between user config and default config. The default config is now generated based on the default key of the config_schema and saved to the mod config file. This ensures that there is always a user config. - To revert to the default config, simply delete the config JSON file.
remove `not` from if statement, and removed the call to the original `_load_mod_configs()` function
3d906d8
to
9661d5b
Compare
added `name` and `Is_valid` prop | Added `_init()` function to validate on init.
Added `current_config` to `mod_list` if the mod has a config file
Reworked the config loading in *mod_manifest.gd* and *mod_data.gd* | The `current_config` for each mod is now stored in the user profiles.
Removed `mod` from functions in `config.gd` to maintain uniformity with other functions within this class. | Configurations are now stored inside a dictionary instead of an array in `ModData`, where the key represents the config name. This change makes it much easier to access and locate the appropriate config based on its name.
added `get_path_to_mod_configs()` in `_ModLoaderPath`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exquisite job on this one. Thank you!
Only a few smaller things to remark, overall approved. I'll let the others have a look at it as well though
to make it more intuitive
3fa2529
to
274fcd6
Compare
`load_mod_config_defaults()` is now called in `load_configs()` in `mod_data.gd` to allow skipping the config loading if the default values in the schema are invalid. Additionally, the `default.json` file is now validated, so the default config is regenerated if the schema has changed and the defaults are no longer valid.
Implemented `_ModLoaderCache` to store the MD5s of the config schema in `"user://ModLoaderCache.json"`. This enables checking if the config schema has changed since the last start, allowing the regeneration of the default config only if a change is detected.
to align with the other methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice.
Looks like the others won't really get around to add their review, so take this approval!
Fixed an error that occurred when the `default.json` config file existed, but the cache had been deleted.
Advanced Mod Configs -
ModLoaderConfig
andModConfig
TLDR
This PR introduces a comprehensive rework of the Mod Config setup, addressing the requirements outlined in issue #178. Key changes include the addition of
JSONSchema
Validation and the implementation of a newResource
Class calledModConfig
, which defines the structure of the Config Data. The existingModLoaderConfig
has been completely rewritten, offering new API methods that cater to the various needs of creating a UI for editing Mod Configs and integrating them within a Mod Project.Example Config Editor UI Mod Download
Example Config Editor UI Mod Repo
PR for User Profile UI Update
JSON-Shema-validator Fork
New API Methods
ModLoaderConfig
create_config(mod_id: String, config_name: String, config_data: Dictionary) -> ModConfig
Creates a new configuration for a mod, stores it in the mod's
ModData
and saves it to a new config JSON file in the mod's config directory.update_config(config: ModConfig) -> ModConfig
Updates an existing
ModConfig
and saves it to disk.delete_config(config: ModConfig) -> bool
Deletes a
ModConfig
, removes the Object from the mod'sModData
and deletes the corresponding JSON file.set_current_config(config: ModConfig) -> void
Sets the current configuration of a mod to the specified configuration.
get_config_schema(mod_id: String) -> Dictionary
Returns the schema for the specified mod id.
If no configuration file exists for the mod, an empty dictionary is returned.
get_schema_for_prop(config: ModConfig, prop: String) -> Dictionary
Retrieves the schema for a specific property key.
The property key is specified as a string using the
.
notation:"parentProp.childProp.nthChildProp"
or"propKey"
_traverse_schema(schema_prop: Dictionary, prop_key_array: Array) -> Dictionary
Recursively traverses the schema dictionary based on the provided
prop_key_array
and returns the corresponding schema for the target property.Used internally by
get_schema_for_prop()
get_mods_with_config() -> Array
Retrieves an Array of mods that have configuration files.
get_configs(mod_id: String) -> Dictionary
Retrieves the configurations dictionary for a given mod ID.
get_config(mod_id: String, config_name: String) -> ModConfig
Retrieves the configuration for a specific mod and configuration name.
get_default_config(mod_id: String) -> ModConfig
Retrieves the default configuration for a specified mod ID.
get_current_config(mod_id: String) -> ModConfig
Retrieves the currently active configuration for a specific mod.
get_current_config_name(mod_id: String) -> String
Retrieves the name of the current configuration for a specific mod.
New Resource
ModConfig
Properties
name: String
Name of the config - must be unique
mod_id: String
The mod_id this config belongs to
schema: Dictionary
The JSON-Schema this config uses for validation
data: Dictionary
The data this config holds
save_path: String
The path where the JSON file for this config is stored
is_valid := false
False if any data is invalid
Methods
get_data_as_string() -> String
Returns the config data as a JSON String
get_schema_as_string() -> String
Returns the schema as a JSON String
validate() -> String
Performs the JSON-Schema validation and returns an empty string if the data is valid, or an error message if there are validation errors.
is_valid() -> bool
Runs the JSON-Schema validation and returns true if valid.
save_to_disc() -> bool
Saves the config data to the
save_path
.remove_from_disc() -> bool
Removes the config data from the
save_path
.New Internal Class
_ModLoaderCache
Consts
CACHE_FILE_PATH
Path to the cache file - by the time of writing this is
"user://ModLoaderCache.json"
Methods
init_cache(_ModLoaderStore) -> void
Creates a new cache file or loads the existing one.
ModLoaderStore is passed as parameter so the cache data can be loaded on ModLoaderStore._init()
add_data(key: String, data: Dictionary) -> void
Adds data to the cache
get_data(key: String) -> Dictionary
Get data from a specific key
get_cache() -> Dictionary
Get the entire cache dictionary
has_key(key: String) -> bool
Check if the key exists in the cache data
update_data(key: String, data: Dictionary) -> Dictionary
Updates or adds data to the cache
remove_data(key: String) -> void
Remove data from the cache
save_to_file() -> void
Save the cache to the cache file
_load_file(_ModLoaderStore = ModLoaderStore) -> void
Load the cache file data and store it in ModLoaderStore
_init_cache_file() -> void
Create an empty cache file
Changes to
ModLoader
New Signal
current_config_changed(config)
Emitted when the current config of a mod has changed.
This signal can be used by mod authors to apply config changes to their mod.
Maybe there is a way for a mod to receive a signal specific to its config?
This way, a mod would only be notified if its own
current_config
has changed.Changes and Additions to
ModLoaderUserProfile
The mod_list is now a Dictionary of Dictionaries.
The
current_config
for each mod is stored in the User Profilemod_list
.New Methods
set_mod_current_config(mod_id: String, config_name: String, profile_name := ModLoaderStore.current_user_profile) -> bool
Sets the current config for a mod in a user profiles mod_list.
_update_mod_list(mod_list: Dictionary, mod_data := ModLoaderStore.mod_data) -> Dictionary
Updates the mod list by checking the validity of each mod entry and making necessary modifications.
_generate_mod_list() -> Dictionary
Generates a dictionary with data to be stored for each mod.
_generate_mod_list_entry(mod_id: String, is_active: bool) -> Dictionary
Generates a mod list entry dictionary with the given mod ID and active status.
If the mod has a config schema, sets the 'current_config' key to the current_config stored in the Mods ModData.
Changes to
ModData
New Properties
configs := {}
Stores all
ModConfig
Objectscurrent_config: ModConfig setget _set_current_config
Stores the currently active
ModConfig
New Methods
load_configs() -> void
Load each mod config json from the mods config directory.
_load_config(config_file_path: String) -> void
Creates a new
ModConfig
instance for each Config JSON and add it to the configs dictionary._set_current_config(new_current_config: ModConfig) -> void
Seter function for
current_config
to update the User ProfileChanges to
ModManifest
Properties
config_schema
instead ofconfig_defaults
Methods
load_mod_config_defaults() -> void
Loads the default configuration for a mod.
By loading the
default.json
config file or using_generate_default_config_from_schema()
_generate_default_config_from_schema(property: Dictionary, current_prop := {}) -> Dictionary
Generates the default config from the
default
keys inside the Config JSON-Schema.Added Utilities
_ModLoaderFile
remove_file(file_path: String) -> bool
Removes a file from the given path.
ModLoaderUtils
get_dict_from_dict(dict: Dictionary, key: String) -> Dictionary
Returns an empty Dictionary if the key does not exist or is not type of Dictionary.
_ModLoaderPath
get_dir_paths_in_dir(src_dir_path: String) -> Array
Returns an array of directory paths inside the src dir.
get_file_paths_in_dir(src_dir_path: String) -> Array
Returns an array of file paths inside the src dir.
get_path_to_mod_configs_dir(mod_id: String) -> String
Get the path to a mods config folder.
Returns an empty string if there is no config dir for this
mod_id
.get_path_to_mod_config_file(mod_id: String, config_name: String) -> String
Get the path to a mods config file.
Returns an empty string if the config file does not exist.
Known issues
However, this is not a major issue right now because a game restart is required anyway to apply the active state of a mod.
closes #178