diff --git a/assetloader/AssetLoader.gd b/assetloader/AssetLoader.gd index a48f03c..32a15db 100644 --- a/assetloader/AssetLoader.gd +++ b/assetloader/AssetLoader.gd @@ -5,10 +5,10 @@ class_name AssetLoader #region Declaration --- # === CONST === -const DEFAULT_ASSETS_PATH = "res://mods" - ## If you want to change the mod extension. Keep in mind that it's still a json under the hood const MOD_INFOS_EXTENSION = "modinfo" +## If you want to change the localization extension. Keep in mind that it's still a json under the hood +const LOC_EXTENSION = "loc" ## Path to the mods folder : [param res://mods] by default ## [br] @@ -20,8 +20,8 @@ var dir:DirAccess var mod_folders:PackedStringArray var critical_error := false -var mod_paths : PackedStringArray -var mod_manifests : Dictionary[String,ModManifest] +var mod_manifests: Dictionary[StringName,ModManifest] +var mod_localizations: Dictionary[StringName,Dictionary] # {mod_id: {locale: {key: value}}} # === SIGNALS === signal loading_finished @@ -31,8 +31,15 @@ signal loading_finished func _init() -> void: print_verbose("------ MOD LOADING STARTED ------") - ASSETS_PATH = ProjectSettings.get_setting("game/mods/mod_path", DEFAULT_ASSETS_PATH) + # Use res://mods/ in editor, executable's mods/ folder in exported builds + if OS.has_feature("editor"): + ASSETS_PATH = "res://"+ProjectSettings.get_setting("game/mods/mod_folder_name", "mods") + else: + # fallbakc to use mods folder next to executable + ASSETS_PATH = OS.get_executable_path().get_base_dir() + "/" + ProjectSettings.get_setting("game/mods/mod_folder_name", "mods") + dir = DirAccess.open(ASSETS_PATH) + print_debug(ASSETS_PATH) if not dir: push_error("AssetLoader: Mods folder not found at '%s'" % ASSETS_PATH) push_error("AssetLoader:",DirAccess.get_open_error()) @@ -73,13 +80,8 @@ func load_mods(): if !manifest:continue if !mod_manifests.has(manifest.id): mod_manifests[manifest.id] = manifest + manifest.path = mod_path print_verbose("Mod manifest is loaded: %s" % manifest.name) - var modpacks:Array = manifest.get_mod_packs() - if manifest.packs.size() > 0: - for pack in manifest.packs: - if dir.file_exists(ASSETS_PATH + "/" + mod_name + pack + ".pck"): # variable re-usage here - pass - modpacks.append(pack) else: push_warning("Another mod as the same id:\n %s will not be loaded" % manifest_path) @@ -89,8 +91,63 @@ func load_mods(): print("Mod loaded: %s" % mod) +func load_localizations(): + if mod_manifests.size() == 0: + print_verbose("No mods to load localizations from.") + return + for mod_id in mod_manifests: + var mod_path: String = mod_manifests[mod_id]["path"] + var mod_name: String = mod_path.get_file() + mod_localizations[mod_id] = {} + dir.change_dir(mod_path) + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + if file_name.ends_with("." + LOC_EXTENSION): + var locale = file_name.get_basename().get_extension() + var loc_path = mod_path + "/" + file_name + var loc_file = FileAccess.open(loc_path, FileAccess.READ) + if loc_file: + var loc_data: Dictionary = JSON.parse_string(loc_file.get_as_text()) + if typeof(loc_data) == TYPE_DICTIONARY: + mod_localizations[mod_id][locale] = loc_data + print_verbose("Loaded localization '%s' for mod '%s'" % [locale, mod_id]) + else: + push_warning("Invalid localization file: %s" % loc_path) + else: + push_warning("Failed to open localization file: %s" % loc_path) + file_name = dir.get_next() + dir.list_dir_end() +func register_localizations(): + for mod_id in mod_localizations: + for locale in mod_localizations[mod_id]: + var translation = Translation.new() + translation.locale = locale + for key in mod_localizations[mod_id][locale]: + translation.add_message(key, mod_localizations[mod_id][locale][key]) + TranslationServer.add_translation(translation) + func load_mods_content(): - pass + if OS.has_feature("editor"): + # Assets should already be loaded/imported. + # FIXME: here we should implement something to serialize ? maybe not. + return + if mod_manifests.size() == 0: + print_verbose("No mods to load content from.") + return + for mod_id in mod_manifests: + var modpacks:Array = mod_manifests[mod_id].get_mod_packs() + for pack in modpacks: + # Load assets from the PCKs (mounted at res://) + var pck_path:StringName = mod_manifests[mod_id].path+ "/" + pack + ".pck" + if dir.file_exists(pck_path): + if ProjectSettings.load_resource_pack(pck_path): + print_verbose("Loaded PCK for mod '%s': %s" % [mod_id, pck_path]) + mod_manifests[mod_id]._validated = true + else: + push_warning("Failed to load PCK: %s" % pck_path) + else: + push_warning("PCK not found: %s" % pck_path) diff --git a/assetloader/ModManifest.gd b/assetloader/ModManifest.gd index 9a72b38..89832cc 100644 --- a/assetloader/ModManifest.gd +++ b/assetloader/ModManifest.gd @@ -13,17 +13,18 @@ var tags:= [] ## ["units", "vehicles", "buildings", "textures", "maps", "quests" var packs := [] ## Optional. [br] By default [param mod_id.pck] is loaded. var _validated = false ## true if the manifest as a correct syntax +var path:StringName ## set if the mode is loaded #endregion # === Init === # Initialization logic, if needed func _init(_id:String,_name:=_id,_desc:="",_dependencies:=[],_packs:=[],_author := "",_version:="1.0",_tags:=[]) -> void: - if id == "": + if _id == "": push_warning("Mod id cannot be null, fallback to "+_name) - self.id = _name.strip_edges() + self.id = StringName(_name.strip_edges()) else: - self.id = _id + self.id = StringName(_id) self.name= _name self.version = _version self.desc=_desc @@ -45,11 +46,18 @@ static func new_from_file(_manifest_file:FileAccess) -> ModManifest: push_warning("Invalid manifest format: %s" % _manifest_file.get_path()) return null var _id: String - if man_dic["id"]: - _id = man_dic["id"] - else: - _id = str(_manifest_file).strip_edges() # ugly. But should fallback on a generated one. - return ModManifest.new(_id, man_dic["name"],man_dic["desc"],man_dic["dependencies"],man_dic["packs"],man_dic["author"],man_dic["version"],man_dic["tags"]) + + _id = man_dic.get("id",_manifest_file.get_path().get_file().get_basename().strip_edges()) # ugly. But should fallback on a generated one. + return ModManifest.new( + _id, + man_dic.get("name", _id), + man_dic.get("desc", ""), + man_dic.get("dependencies", []), + man_dic.get("packs", []), + man_dic.get("author", ""), + str(man_dic.get("version", "1.0")), + man_dic.get("tags", []) + ) ## Check if the array is empty, if not, return the packs and the main one if it's not on the list.