@@ -61,11 +61,11 @@ const REQUIRED_MANIFEST_KEYS_ROOT = [
61
61
62
62
# Required keys in manifest's `json.extra.godot`
63
63
const REQUIRED_MANIFEST_KEYS_EXTRA = [
64
- "id" ,
65
64
"incompatibilities" ,
66
65
"authors" ,
67
66
"compatible_mod_loader_version" ,
68
67
"compatible_game_version" ,
68
+ "config_defaults" ,
69
69
]
70
70
71
71
# Set to true to require using "--enable-mods" to enable them
@@ -91,6 +91,12 @@ var mod_load_order = []
91
91
# Example: --mods-path="C://path/mods"
92
92
var os_mods_path_override = ""
93
93
94
+ # Override for the path config JSONs are loaded from
95
+ # Default: "res://configs"
96
+ # Set via: --configs-path
97
+ # Example: --configs-path="C://path/configs"
98
+ var os_configs_path_override = ""
99
+
94
100
# Any mods that are missing their dependancies are added to this
95
101
# Example property: "mod_id": ["dep_mod_id_0", "dep_mod_id_2"]
96
102
var mod_missing_dependencies = {}
@@ -116,6 +122,12 @@ func _init():
116
122
os_mods_path_override = cmd_line_mod_path
117
123
mod_log ("The path mods are loaded from has been changed via the CLI arg `--mods-path`, to: " + cmd_line_mod_path , LOG_NAME )
118
124
125
+ # Check for the CLI arg that overrides the configs path
126
+ var cmd_line_configs_path = _get_cmd_line_arg ("--configs-path" )
127
+ if cmd_line_configs_path != "" :
128
+ os_configs_path_override = cmd_line_configs_path
129
+ mod_log ("The path configs are loaded from has been changed via the CLI arg `--configs-path`, to: " + cmd_line_configs_path , LOG_NAME )
130
+
119
131
# Loop over "res://mods" and add any mod zips to the unpacked virtual
120
132
# directory (UNPACKED_DIR)
121
133
_load_mod_zips ()
@@ -125,6 +137,10 @@ func _init():
125
137
# directory, which adds their data to mod_data.
126
138
_setup_mods ()
127
139
140
+ # Set up mod configs. If a mod's JSON file is found, its data gets added
141
+ # to mod_data.{mod_id}.config
142
+ _load_mod_configs ()
143
+
128
144
# Loop over all loaded mods via their entry in mod_data. Verify that they
129
145
# have all the required files (REQUIRED_MOD_FILES), load their meta data
130
146
# (from their manifest.json file), and verify that the meta JSON has all
@@ -162,7 +178,8 @@ func _init():
162
178
163
179
# Instance every mod and add it as a node to the Mod Loader
164
180
for mod in mod_load_order :
165
- mod_log (str ("Initializing -> " , mod .meta_data .extra .godot .id ), LOG_NAME )
181
+ # mod_log(str("Initializing -> ", mod.meta_data.extra.godot.id), LOG_NAME)
182
+ mod_log (str ("Initializing -> " , _get_mod_full_id (mod )), LOG_NAME )
166
183
_init_mod (mod )
167
184
168
185
dev_log (str ("mod_data: " , JSON .print (mod_data , ' ' )), LOG_NAME )
@@ -317,6 +334,53 @@ func _setup_mods():
317
334
dir .list_dir_end ()
318
335
319
336
337
+ # Load mod config JSONs from res://configs
338
+ func _load_mod_configs ():
339
+ var found_configs_count = 0
340
+ var configs_path = _get_local_folder_dir ("configs" )
341
+
342
+ # CLI override, set with `--configs-path="C://path/configs"`
343
+ # (similar to os_mods_path_override)
344
+ if (os_configs_path_override != "" ):
345
+ configs_path = os_configs_path_override
346
+
347
+ for mod_id in mod_data :
348
+ var json_path = configs_path .plus_file (mod_id + ".json" )
349
+ var mod_config = _get_json_as_dict (json_path )
350
+
351
+ dev_log (str ("Config JSON: Looking for config at path: " , json_path ), LOG_NAME )
352
+
353
+ if mod_config .size () > 0 :
354
+ found_configs_count += 1
355
+
356
+ mod_log (str ("Config JSON: Found a config file: '" , json_path , "'" ), LOG_NAME )
357
+ dev_log (str ("Config JSON: File data: " , JSON .print (mod_config )), LOG_NAME )
358
+
359
+ # Check `load_from` option. This lets you specify the name of a
360
+ # different JSON file to load your config from. Must be in the same
361
+ # dir. Means you can have multiple config files for a single mod
362
+ # and switch between them quickly. Should include ".json" extension.
363
+ # Ignored if the filename matches the mod ID, or is empty
364
+ if mod_config .has ("load_from" ):
365
+ var new_path = mod_config .load_from
366
+ if new_path != "" && new_path != str (mod_id , ".json" ):
367
+ mod_log (str ("Config JSON: Following load_from path: " , new_path ), LOG_NAME )
368
+ var new_config = _get_json_as_dict (configs_path + new_path )
369
+ if new_config .size () > 0 != null :
370
+ mod_config = new_config
371
+ mod_log (str ("Config JSON: Loaded from custom json: " , new_path ), LOG_NAME )
372
+ dev_log (str ("Config JSON: File data: " , JSON .print (mod_config )), LOG_NAME )
373
+ else :
374
+ mod_log (str ("Config JSON: ERROR - Could not load data via `load_from` for " , mod_id , ", at path: " , new_path ), LOG_NAME )
375
+
376
+ mod_data [mod_id ].config = mod_config
377
+
378
+ if found_configs_count > 0 :
379
+ mod_log (str ("Config JSON: Loaded " , str (found_configs_count ), " config(s)" ), LOG_NAME )
380
+ else :
381
+ mod_log (str ("Config JSON: No mod configs were found" ), LOG_NAME )
382
+
383
+
320
384
# Add a mod's data to mod_data.
321
385
# The mod_folder_path is just the folder name that was added to UNPACKED_DIR,
322
386
# which depends on the name used in a given mod ZIP (eg "mods-unpacked/Folder-Name")
@@ -333,6 +397,7 @@ func _init_mod_data(mod_folder_path):
333
397
mod_data [mod_id ].is_loadable = true
334
398
mod_data [mod_id ].importance = 0
335
399
mod_data [mod_id ].dir = local_mod_path
400
+ mod_data [mod_id ].config = {} # updated in _load_mod_configs
336
401
337
402
if DEBUG_ENABLE_STORING_FILEPATHS :
338
403
# Get the mod file paths
@@ -390,6 +455,13 @@ func _load_meta_data(mod_id):
390
455
# Add the meta data to the mod
391
456
mod .meta_data = meta_data
392
457
458
+ # Check that the mod ID is correct. This will fail if the mod's folder in
459
+ # "res://mods-unpacked" does not match its full ID, which is `namespace.name`
460
+ var mod_check_id = _get_mod_full_id (mod )
461
+ if mod_id != mod_check_id :
462
+ mod_log (str ("ERROR - " , mod_id , " - Mod ID does not match the data in manifest.json. Expected '" , mod_id ,"', but '{namespace} -{name} ' was '" , mod_check_id ,"'" ), LOG_NAME )
463
+ mod .is_loadable = false
464
+
393
465
394
466
# Ensure manifest.json has all required keys
395
467
func _check_meta_file (meta_data ):
@@ -489,7 +561,8 @@ func _init_mod(mod):
489
561
dev_log (str ("Loaded script -> " , mod_main_script ), LOG_NAME )
490
562
491
563
var mod_main_instance = mod_main_script .new (self )
492
- mod_main_instance .name = mod .meta_data .extra .godot .id
564
+ # mod_main_instance.name = mod.meta_data.extra.godot.id
565
+ mod_main_instance .name = _get_mod_full_id (mod )
493
566
494
567
dev_log (str ("Adding child -> " , mod_main_instance ), LOG_NAME )
495
568
add_child (mod_main_instance , true )
@@ -500,6 +573,12 @@ func _init_mod(mod):
500
573
501
574
# Util functions used in the mod loading process
502
575
576
+ func _get_mod_full_id (mod :Dictionary )-> String :
577
+ var name = mod .meta_data .name
578
+ var namespace = mod .meta_data .namespace
579
+ return str (namespace , "-" , name )
580
+
581
+
503
582
# Check if the provided command line argument was present when launching the game
504
583
func _check_cmd_line_arg (argument ) -> bool :
505
584
for arg in OS .get_cmdline_args ():
@@ -622,7 +701,6 @@ func _get_flat_view_dict(p_dir = "res://", p_match = "", p_match_is_regex = fals
622
701
return data
623
702
624
703
625
-
626
704
# Helpers
627
705
# =============================================================================
628
706
@@ -692,3 +770,66 @@ func save_scene(modified_scene, scene_path:String):
692
770
packed_scene .take_over_path (scene_path )
693
771
dev_log (str ("save_scene - taking over path - new path -> " , packed_scene .resource_path ), LOG_NAME )
694
772
_saved_objects .append (packed_scene )
773
+
774
+
775
+ # Get the config data for a specific mod. Always returns a dictionary with two
776
+ # keys: `error` and `data`.
777
+ # Data (`data`) is either the full config, or data from a specific key if one was specified.
778
+ # Error (`error`) is 0 if there were no errors, or > 0 if the setting could not be retrieved:
779
+ # 0 = No errors
780
+ # 1 = Invalid mod ID
781
+ # 2 = No custom JSON. File probably does not exist. Defaults will be used if available
782
+ # 3 = No custom JSON, and key was invalid when trying to get the default from your manifest defaults (`extra.godot.config_defaults`)
783
+ # 4 = Invalid key, although config data does exists
784
+ func get_mod_config (mod_id :String = "" , key :String = "" )-> Dictionary :
785
+ var error_num = 0
786
+ var error_msg = ""
787
+ var data = {}
788
+ var defaults = null
789
+
790
+ # Invalid mod ID
791
+ if ! mod_data .has (mod_id ):
792
+ error_num = 1
793
+ error_msg = str ("ERROR - Mod ID was invalid: " , mod_id )
794
+
795
+ # Mod ID is valid
796
+ if error_num == 0 :
797
+ var config_data = mod_data [mod_id ].config
798
+ defaults = mod_data [mod_id ].meta_data .extra .godot .config_defaults
799
+
800
+ # No custom JSON file
801
+ if config_data .size () == 0 :
802
+ error_num = 2
803
+ error_msg = str ("WARNING - No config file for " , mod_id , ".json. " )
804
+ if key == "" :
805
+ data = defaults
806
+ error_msg += "Using defaults (extra.godot.config_defaults)"
807
+ else :
808
+ if defaults .has (key ):
809
+ data = defaults [key ]
810
+ error_msg += str ("Using defaults for key '" , key , "' (extra.godot.config_defaults." , key , ")" )
811
+ else :
812
+ error_num = 3
813
+ # error_msg = str("WARNING - No config file for Invalid key '", key, "' for mod ID: ", mod_id)
814
+ error_msg += str ("Requested key '" , key , "' is not present in the defaults (extra.godot.config_defaults." , key , ")" )
815
+
816
+ # JSON file exists
817
+ if error_num == 0 :
818
+ if key == "" :
819
+ data = config_data
820
+ else :
821
+ if config_data .has (key ):
822
+ data = config_data [key ]
823
+ else :
824
+ error_num = 4
825
+ error_msg = str ("WARNING - Invalid key '" , key , "' for mod ID: " , mod_id )
826
+
827
+ # Log if any errors occured
828
+ if error_num != 0 :
829
+ dev_log (str ("Config: " , error_msg ), mod_id )
830
+
831
+ return {
832
+ "error" : error_num ,
833
+ "error_msg" : error_msg ,
834
+ "data" : data ,
835
+ }
0 commit comments