Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
692652c
feat: :sparkles: option to disable game version validation
KANAjetzt Jan 30, 2025
4a743cb
feat: :sparkles: added custom validation option
KANAjetzt Jan 31, 2025
8a19d72
docs: :memo: added missing doc comments
KANAjetzt Jan 31, 2025
2dc7e5a
refactor: :recycle: use ENUM
KANAjetzt Feb 2, 2025
d342385
refactor: :recycle: only pass `ml_options`
KANAjetzt Feb 2, 2025
24f723c
refactor: :recycle: move `customize_script_path` out of export group
KANAjetzt Feb 2, 2025
172e0ff
docs: :memo: added example customize script
KANAjetzt Feb 2, 2025
581684f
style: :pencil2: improved spelling
KANAjetzt Feb 2, 2025
67127e3
docs: :memo: reworked comments
KANAjetzt Feb 2, 2025
666f4c6
refactor: :recycle: `ml_options_path` as param
KANAjetzt Feb 5, 2025
00b9292
refactor: :fire: remove example script
KANAjetzt Feb 5, 2025
013b790
refactor: :recycle: removed example added `@tutorial`
KANAjetzt Feb 5, 2025
b97fab7
test: :test_tube: added custom validation test
KANAjetzt Feb 5, 2025
c354ae0
fix: :test_tube: fixed test setup
KANAjetzt Feb 5, 2025
0743144
fix: :test_tube: removed editor override
KANAjetzt Feb 5, 2025
9ef663b
fix: :bug: set `customize_script_path` outside of for loop
KANAjetzt Feb 5, 2025
df193ca
refactor: :truck: added sub dir
KANAjetzt Feb 5, 2025
8b122c3
test: :test_tube: added test for game version validation disabled
KANAjetzt Feb 5, 2025
52c582a
fix: :test_tube: updated custom script path
KANAjetzt Feb 5, 2025
8d12b7a
test: :test_tube: added `test_game_verion_validation_default`
KANAjetzt Feb 5, 2025
b8ef08a
fix: :test_tube: replace white space chars with `""`
KANAjetzt Feb 5, 2025
c26a4bf
refactor: :recycle: clean up a bit
KANAjetzt Feb 5, 2025
d136db4
test: :test_tube: added no callable set test
KANAjetzt Feb 5, 2025
b34413e
Update addons/mod_loader/resources/options_profile.gd
KANAjetzt Feb 5, 2025
7eea1d7
Update addons/mod_loader/resources/options_profile.gd
KANAjetzt Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions addons/mod_loader/mod_loader_store.gd
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ func _update_ml_options_from_options_resource() -> void:
# Update from the options in the resource
ml_options = override_options

if not ml_options.customize_script_path.is_empty():
ml_options.customize_script_instance = load(ml_options.customize_script_path).new(ml_options)


func _exit_tree() -> void:
# Save the cache to the cache file.
Expand Down
46 changes: 46 additions & 0 deletions addons/mod_loader/options/example_customize_script.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
extends RefCounted

# This is an example script for the ModLoaderOptionsProfile `customize_script_path`.
# Ideally, place this script outside the `mod_loader` directory to simplify the update process.

# This script is loaded after `mod_loader_store.ml_options` has been initialized.
# It receives `ml_options` as an argument, allowing you to apply settings
# that cannot be configured through the editor UI.
func _init(ml_options: ModLoaderOptionsProfile) -> void:
# Use OS.has_feature() to apply changes only for specific platforms,
# or create multiple customization scripts and set their paths accordingly in the option profiles.
if OS.has_feature("Steam"):
pass
elif OS.has_feature("Epic"):
pass
else:
# Set `custom_game_version_validation_callable` to use a custom validation function.
ml_options.custom_game_version_validation_callable = custom_is_game_version_compatible

# Custom validation function
# See `ModManifest._is_game_version_compatible()` for the default validation logic.
func custom_is_game_version_compatible(manifest: ModManifest) -> bool:
print("! ☞゚ヮ゚)☞ CUSTOM VALIDATION HERE ☜゚ヮ゚☜) !")

var mod_id := manifest.get_mod_id()

for version in manifest.compatible_game_version:
if not version == "pizza":
# Push a warning message displayed after manifest validation is complete.
manifest.validation_messages_warning.push_back(
"The mod \"%s\" may not be compatible with the current game version.
Enable at your own risk. (Current game version: %s, mod compatible with game versions: %s)" %
[mod_id, "MyGlobalVars.MyGameVersion", manifest.compatible_game_version]
)
return true

if not version == "pineapple":
# Push an error message displayed after manifest validation is complete.
manifest.validation_messages_error.push_back(
"The mod \"%s\" is incompatible with the current game version.
(Current game version: %s, mod compatible with game versions: %s)" %
[mod_id, "MyGlobalVars.MyGameVersion", manifest.compatible_game_version]
)
return false

return true
9 changes: 8 additions & 1 deletion addons/mod_loader/resources/mod_manifest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,14 @@ func validate(manifest: Dictionary, path: String) -> bool:
config_schema = ModLoaderUtils.get_dict_from_dict(godot_details, "config_schema")
steam_workshop_id = ModLoaderUtils.get_string_from_dict(godot_details, "steam_workshop_id")

_is_game_version_compatible(mod_id)
if ModLoaderStore.ml_options.game_version_validation == ModLoaderOptionsProfile.VERSION_VALIDATION.DEFAULT:
_is_game_version_compatible(mod_id)

if ModLoaderStore.ml_options.game_version_validation == ModLoaderOptionsProfile.VERSION_VALIDATION.CUSTOM:
if ModLoaderStore.ml_options.custom_game_version_validation_callable:
ModLoaderStore.ml_options.custom_game_version_validation_callable.call(self)
else:
ModLoaderLog.error("No custom game version validation callable detected. Please provide a valid validation callable.", LOG_NAME)

is_mod_id_array_valid(mod_id, dependencies, "dependency")
is_mod_id_array_valid(mod_id, incompatibilities, "incompatibility")
Expand Down
75 changes: 73 additions & 2 deletions addons/mod_loader/resources/options_profile.gd
Original file line number Diff line number Diff line change
@@ -1,18 +1,74 @@
class_name ModLoaderOptionsProfile
extends Resource
##
## Class to define and store Mod Loader Options.


## Settings for game version validation.
enum VERSION_VALIDATION {
## Uses the default semantic versioning (semver) validation.
DEFAULT,

## Disables validation of the game version specified in [member semantic_version]
## and the mod's [member ModManifest.compatible_game_version].
DISABLED,

## Enables custom game version validation.
## Use [member customize_script_path] to specify a script that customizes the Mod Loader options.
## In this script, you must set [member custom_game_version_validation_callable]
## to a custom validation [Callable].
##
## Example:
## [codeblock]
## extends RefCounted
##
## func _init(ml_options: ModLoaderOptionsProfile) -> void:
## # Assign a custom validation function.
## # Use `OS.has_feature(feature_tag)` to apply different validations for different platforms.
## ml_options.custom_game_version_validation_callable = custom_is_game_version_compatible
##
## func custom_is_game_version_compatible(manifest: ModManifest) -> bool:
## print("! ☞゚ヮ゚)☞ CUSTOM VALIDATION HERE ☜゚ヮ゚☜) !")
##
## var mod_id := manifest.get_mod_id()
##
## for version in manifest.compatible_game_version:
## if not version == "pizza":
## manifest.validation_messages_warning.push_back(
## "The mod \"%s\" may not be compatible with the current game version.
## Enable at your own risk. (current game version: %s, mod compatible with game versions: %s)" %
## [mod_id, MyGlobalVars.MyGameVersion, manifest.compatible_game_version]
## )
## return false
##
## return true
## [/codeblock]
##
## Using a customization script allows you to keep your custom code outside the addon directory,
## making it easier to update the mod loader without affecting your modifications.
##
CUSTOM,
}

## Can be used to disable mods for specific plaforms by using feature overrides
@export var enable_mods: bool = true
## List of mod ids that can't be turned on or off
@export var locked_mods: Array[String] = []

## List of mods that will not be loaded
@export var disabled_mods: Array[String] = []
## Disables the requirement for the mod loader autoloads to be first
@export var allow_modloader_autoloads_anywhere: bool = false

## This script is loaded after [member ModLoaderStore.ml_options] has been initialized.
## It is instantiated with [member ModLoaderStore.ml_options] as an argument.
## Use this script to apply settings that cannot be configured through the editor UI.
##
## For an example, see [enum VERSION_VALIDATION] [code]CUSTOM[/code] or
## [code]res://addons/mod_loader/options/example_customize_script.gd[/code].
@export_file var customize_script_path: String

@export_group("Logging")
## Sets the logging verbosity level.
## Refer to [enum ModLoaderLog.VERBOSITY_LEVEL] for more details.
@export var log_level := ModLoaderLog.VERBOSITY_LEVEL.DEBUG
## Stops the mod loader from logging any deprecation related errors.
@export var ignore_deprecated_errors: bool = false
Expand Down Expand Up @@ -42,6 +98,7 @@ extends Resource
## Path to a folder containing mods [br]
## Mod zips should be directly in this folder
@export_dir var override_path_to_mods = ""
## Use this option to override the default path where configs are stored.
@export_dir var override_path_to_configs = ""
## Path to a folder containing workshop items.[br]
## Mods zips are placed in another folder, usually[br]
Expand All @@ -61,3 +118,17 @@ extends Resource
@export_dir var restart_notification_scene_path := "res://addons/mod_loader/restart_notification.tscn"
## Can be used to disable the mod loader's restart logic. Use the [signal ModLoader.new_hooks_created] to implement your own restart logic.
@export var disable_restart := false

@export_group("Mod Validation")
## Defines how the game version should be validated.
## This setting controls validation for the game version specified in [member semantic_version]
## and the mod's [member ModManifest.compatible_game_version].
@export var game_version_validation := VERSION_VALIDATION.DEFAULT

## Callable that is executed during [ModManifest] validation
## if [member game_version_validation] is set to [enum VERSION_VALIDATION] [code]CUSTOM[/code].
## See the example under [enum VERSION_VALIDATION] [code]CUSTOM[/code] to learn how to set this up.
var custom_game_version_validation_callable: Callable

## Stores the instance of the script specified in [member customize_script_path].
var customize_script_instance: RefCounted