AssetLoader + Modinfo object
This commit is contained in:
parent
3cd2327edc
commit
33188c1380
8 changed files with 138 additions and 13 deletions
|
@ -1,7 +1,8 @@
|
||||||
|
@tool
|
||||||
extends Object
|
extends Object
|
||||||
class_name AssetLoader
|
class_name AssetLoader
|
||||||
|
|
||||||
#region declaration
|
#region Declaration ---
|
||||||
# === CONST ===
|
# === CONST ===
|
||||||
|
|
||||||
const DEFAULT_ASSETS_PATH = "res://mods"
|
const DEFAULT_ASSETS_PATH = "res://mods"
|
||||||
|
@ -20,12 +21,12 @@ var mod_folders:PackedStringArray
|
||||||
var critical_error := false
|
var critical_error := false
|
||||||
|
|
||||||
var mod_paths : PackedStringArray
|
var mod_paths : PackedStringArray
|
||||||
var mod_manifests : Dictionary[String,Dictionary]
|
var mod_manifests : Dictionary[String,ModManifest]
|
||||||
|
|
||||||
# === SIGNALS ===
|
# === SIGNALS ===
|
||||||
signal loading_finished
|
signal loading_finished
|
||||||
|
|
||||||
#endregion
|
#endregion ---
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
|
@ -45,6 +46,8 @@ func _init() -> void:
|
||||||
critical_error = true
|
critical_error = true
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# === PRIVATE ===
|
||||||
|
|
||||||
|
|
||||||
## This will show a native MessageBox on Windows,
|
## This will show a native MessageBox on Windows,
|
||||||
## a native dialog on macOS, and GTK/QT dialog on Linux.
|
## a native dialog on macOS, and GTK/QT dialog on Linux.
|
||||||
|
@ -52,11 +55,13 @@ func _show_error_popup(message: String) -> void:
|
||||||
OS.alert("AssetLoader:"+message, "AssetLoader:Error")
|
OS.alert("AssetLoader:"+message, "AssetLoader:Error")
|
||||||
|
|
||||||
|
|
||||||
|
# === PUBLIC ===
|
||||||
func load_all():
|
func load_all():
|
||||||
load_mods()
|
load_mods()
|
||||||
#load_mods_content()
|
load_mods_content()
|
||||||
|
|
||||||
|
|
||||||
|
## Load and unpack all .pck before serialization
|
||||||
func load_mods():
|
func load_mods():
|
||||||
for mod in mod_folders:
|
for mod in mod_folders:
|
||||||
var mod_name = mod
|
var mod_name = mod
|
||||||
|
@ -64,14 +69,28 @@ func load_mods():
|
||||||
var manifest_path = mod_path + "/" + mod_name + "." + MOD_INFOS_EXTENSION
|
var manifest_path = mod_path + "/" + mod_name + "." + MOD_INFOS_EXTENSION
|
||||||
if FileAccess.file_exists(manifest_path):
|
if FileAccess.file_exists(manifest_path):
|
||||||
var manifest_file := FileAccess.open(manifest_path, FileAccess.READ)
|
var manifest_file := FileAccess.open(manifest_path, FileAccess.READ)
|
||||||
var manifest: Dictionary = JSON.parse_string(manifest_file.get_as_text())
|
var manifest: ModManifest = ModManifest.new_from_file(manifest_file)
|
||||||
if typeof(manifest) == TYPE_DICTIONARY: # always true ?
|
if !manifest:continue
|
||||||
mod_paths.append(mod_path)
|
if !mod_manifests.has(manifest.id):
|
||||||
if manifest["id"]:
|
mod_manifests[manifest.id] = manifest
|
||||||
mod_manifests[manifest["id"]] = manifest
|
print_verbose("Mod manifest is loaded: %s" % manifest.name)
|
||||||
print_verbose("Mod 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:
|
else:
|
||||||
mod_manifests[mod_name] = manifest
|
push_warning("Another mod as the same id:\n %s will not be loaded" % manifest_path)
|
||||||
print_verbose("Mod loaded: %s" % manifest["name"])
|
|
||||||
|
else:
|
||||||
|
push_warning("No manifest found in %s" % manifest_path)
|
||||||
for mod in mod_manifests:
|
for mod in mod_manifests:
|
||||||
print("Mod loaded: %s" % mod)
|
print("Mod loaded: %s" % mod)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func load_mods_content():
|
||||||
|
pass
|
69
assetloader/ModManifest.gd
Normal file
69
assetloader/ModManifest.gd
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
extends RefCounted
|
||||||
|
class_name ModManifest
|
||||||
|
## Object for easier json manifest operations.
|
||||||
|
|
||||||
|
#region declaration
|
||||||
|
var id: StringName ## Mod unique id. Internal usage only.
|
||||||
|
var name: String ## Displayed mod name
|
||||||
|
var version: String ## Displayed mod version
|
||||||
|
var desc: String ## Displayed mod description
|
||||||
|
var author:String ## Mod Author
|
||||||
|
var dependencies := [] ## Mod dependecies, optional.
|
||||||
|
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
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
# === Init === # Initialization logic, if needed
|
||||||
|
|
||||||
|
|
||||||
|
func _init(_id:String,_name:=_id,_desc:="",_dependencies:=[],_packs:=[],_author := "",_version:="1.0",_tags:=[]) -> void:
|
||||||
|
if id == "":
|
||||||
|
push_warning("Mod id cannot be null, fallback to "+_name)
|
||||||
|
self.id = _name.strip_edges()
|
||||||
|
else:
|
||||||
|
self.id = _id
|
||||||
|
self.name= _name
|
||||||
|
self.version = _version
|
||||||
|
self.desc=_desc
|
||||||
|
self.author = _author
|
||||||
|
self.dependencies = _dependencies
|
||||||
|
self.tags= _tags
|
||||||
|
self.packs =_packs
|
||||||
|
|
||||||
|
|
||||||
|
# === PUBLIC FUNCTIONS ===
|
||||||
|
func is_valid() -> bool:
|
||||||
|
return _validated
|
||||||
|
|
||||||
|
|
||||||
|
## Return [param null] if the json is not parsed correctly
|
||||||
|
static func new_from_file(_manifest_file:FileAccess) -> ModManifest:
|
||||||
|
var man_dic:Dictionary = JSON.parse_string(_manifest_file.get_as_text())
|
||||||
|
if !man_dic:
|
||||||
|
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"])
|
||||||
|
|
||||||
|
|
||||||
|
## Check if the array is empty, if not, return the packs and the main one if it's not on the list.
|
||||||
|
func get_mod_packs() -> Array[String]:
|
||||||
|
if packs.size() > 0:
|
||||||
|
# check if the main pack is in the list
|
||||||
|
if packs.has(self.id):
|
||||||
|
return self.packs
|
||||||
|
else:
|
||||||
|
var pck = self.packs
|
||||||
|
pck.append(id)
|
||||||
|
return pck
|
||||||
|
return [id]
|
||||||
|
|
||||||
|
# === PRIVATE FUNCTIONS === # use _underscore() to make the difference between private and public functions
|
||||||
|
|
||||||
|
# ====================
|
1
assetloader/ModManifest.gd.uid
Normal file
1
assetloader/ModManifest.gd.uid
Normal file
|
@ -0,0 +1 @@
|
||||||
|
uid://5ii0g6tl4dpj
|
|
@ -10,6 +10,7 @@ func _ready() -> void:
|
||||||
return
|
return
|
||||||
loader.load_all() # TODO: Making it async
|
loader.load_all() # TODO: Making it async
|
||||||
_start_game()
|
_start_game()
|
||||||
|
loader = null
|
||||||
|
|
||||||
|
|
||||||
## This will show a native MessageBox on Windows,
|
## This will show a native MessageBox on Windows,
|
||||||
|
|
25
mods/README.md
Normal file
25
mods/README.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Modding
|
||||||
|
|
||||||
|
By default a modding system is made.
|
||||||
|
Each mods need to be in the mod folder, each folder is a mod containing at least a `mod_id.modinfo` and a `mod_id.pck` and optionnaly a `mod_id.<locale>.loc`
|
||||||
|
|
||||||
|
## modinfo example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "mod_id",
|
||||||
|
"name": "Mod Displayed Name",
|
||||||
|
"version": "1.0",
|
||||||
|
"desc": "Mod displayed description",
|
||||||
|
"author": "Mod Author",
|
||||||
|
"dependencies": [],
|
||||||
|
"tags": ["units", "vehicles", "buildings", "textures", "maps", "quests"],
|
||||||
|
"packs": ["mod_id", "addon_pack"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*id* (string) : should be the unique name of the mod. Only used internally. should be the same as the modinfo and the folder name
|
||||||
|
*name* (string) : the displayed name of the mode
|
||||||
|
*version* (string) : to keep track of the version of you mod. displayed in the mod manager
|
||||||
|
*author* (string) : you, the awesome modder
|
||||||
|
*dependecies* (array of strings) : list of ids of requiered mod. be sure to load them before this one
|
0
mods/base_content/units/soldier.json
Normal file
0
mods/base_content/units/soldier.json
Normal file
10
mods/modinfo_example.json
Normal file
10
mods/modinfo_example.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"id": "mod_id",
|
||||||
|
"name": "Mod Displayed Name",
|
||||||
|
"version": "1.0",
|
||||||
|
"desc": "Mod displayed description",
|
||||||
|
"author": "Mod Author",
|
||||||
|
"dependencies": [],
|
||||||
|
"tags": ["units", "vehicles", "buildings", "textures", "maps", "quests"],
|
||||||
|
"packs": ["mod_id", "addon_pack"]
|
||||||
|
}
|
Loading…
Reference in a new issue