|
| 1 | +extends SceneTree |
| 2 | + |
| 3 | +const LOG_NAME := "ModLoader:Setup" |
| 4 | + |
| 5 | +const settings := { |
| 6 | + "IS_LOADER_SETUP_APPLIED": "application/run/is_loader_setup_applied", |
| 7 | + "IS_LOADER_SET_UP": "application/run/is_loader_set_up", |
| 8 | + "MOD_LOADER_AUTOLOAD": "autoload/ModLoader", |
| 9 | +} |
| 10 | + |
| 11 | +# see: [method ModLoaderUtils.register_global_classes_from_array] |
| 12 | +const new_global_classes := [ |
| 13 | + { |
| 14 | + "base": "Resource", |
| 15 | + "class": "ModData", |
| 16 | + "language": "GDScript", |
| 17 | + "path": "res://addons/mod_loader/mod_data.gd" |
| 18 | + }, { |
| 19 | + "base": "Node", |
| 20 | + "class": "ModLoaderUtils", |
| 21 | + "language": "GDScript", |
| 22 | + "path": "res://addons/mod_loader/mod_loader_utils.gd" |
| 23 | + }, { |
| 24 | + "base": "Resource", |
| 25 | + "class": "ModManifest", |
| 26 | + "language": "GDScript", |
| 27 | + "path": "res://addons/mod_loader/mod_manifest.gd" |
| 28 | + } |
| 29 | +] |
| 30 | + |
| 31 | +# IMPORTANT: use the ModLoaderUtils via this variable within this script! |
| 32 | +# Otherwise, script compilation will break on first load since the class is not defined. |
| 33 | +var modloaderutils: Node = load("res://addons/mod_loader/mod_loader_utils.gd").new() |
| 34 | + |
| 35 | + |
| 36 | +func _init() -> void: |
| 37 | + try_setup_modloader() |
| 38 | + change_scene(ProjectSettings.get_setting("application/run/main_scene")) |
| 39 | + |
| 40 | + |
| 41 | +# Set up the ModLoader, if it hasn't been set up yet |
| 42 | +func try_setup_modloader() -> void: |
| 43 | + # Avoid doubling the setup work |
| 44 | + if is_loader_setup_applied(): |
| 45 | + modloaderutils.log_info("ModLoader is available, mods can be loaded!", LOG_NAME) |
| 46 | + OS.set_window_title("%s (Modded)" % ProjectSettings.get_setting("application/config/name")) |
| 47 | + return |
| 48 | + |
| 49 | + setup_modloader() |
| 50 | + |
| 51 | + # If the loader is set up, but the override is not applied yet, |
| 52 | + # prompt the user to quit and restart the game. |
| 53 | + if is_loader_set_up() and not is_loader_setup_applied(): |
| 54 | + modloaderutils.log_info("ModLoader is set up, but the game needs to be restarted", LOG_NAME) |
| 55 | + OS.alert("The Godot ModLoader has been set up. Restart the game to apply the changes. Confirm to quit.") |
| 56 | + ProjectSettings.set_setting(settings.IS_LOADER_SETUP_APPLIED, true) |
| 57 | + ProjectSettings.save_custom(modloaderutils.get_override_path()) |
| 58 | + quit() |
| 59 | + |
| 60 | + |
| 61 | +# Set up the ModLoader as an autoload and register the other global classes. |
| 62 | +# Saved as override.cfg besides the game executable to extend the existing project settings |
| 63 | +func setup_modloader() -> void: |
| 64 | + modloaderutils.log_info("Setting up ModLoader", LOG_NAME) |
| 65 | + |
| 66 | + # Register all new helper classes as global |
| 67 | + modloaderutils.register_global_classes_from_array(new_global_classes) |
| 68 | + |
| 69 | + # Add ModLoader autoload (the * marks the path as autoload) |
| 70 | + ProjectSettings.set_setting(settings.MOD_LOADER_AUTOLOAD, "*res://addons/mod_loader/mod_loader.gd") |
| 71 | + ProjectSettings.set_setting(settings.IS_LOADER_SET_UP, true) |
| 72 | + |
| 73 | + # The game needs to be restarted first, bofore the loader is truly set up |
| 74 | + # Set this here and check it elsewhere to prompt the user for a restart |
| 75 | + ProjectSettings.set_setting(settings.IS_LOADER_SETUP_APPLIED, false) |
| 76 | + |
| 77 | + ProjectSettings.save_custom(ModLoaderUtils.get_override_path()) |
| 78 | + modloaderutils.log_info("ModLoader setup complete", LOG_NAME) |
| 79 | + |
| 80 | + |
| 81 | +func is_loader_set_up() -> bool: |
| 82 | + return is_project_setting_true(settings.IS_LOADER_SET_UP) |
| 83 | + |
| 84 | + |
| 85 | +func is_loader_setup_applied() -> bool: |
| 86 | + if not root.get_node_or_null("/root/ModLoader") == null: |
| 87 | + if not is_project_setting_true(settings.IS_LOADER_SETUP_APPLIED): |
| 88 | + modloaderutils.log_info("ModLoader is already set up. No self setup required.", LOG_NAME) |
| 89 | + return true |
| 90 | + return false |
| 91 | + |
| 92 | + |
| 93 | +static func is_project_setting_true(project_setting: String) -> bool: |
| 94 | + return ProjectSettings.has_setting(project_setting) and\ |
| 95 | + ProjectSettings.get_setting(project_setting) |
| 96 | + |
| 97 | + |
| 98 | + |
0 commit comments