extends Node
## Manages loading/unloading PCK resource packs at runtime.
## Each pack must contain a manifest.json describing its contents.
signal pack_loaded(pack_name: String, manifest: Dictionary)
signal pack_load_failed(path: String, reason: String)
var _loaded_packs: Dictionary = {} # name -> {path, manifest, active_scene}
## Load a .pck file and register it by manifest name.
func load_pack(pck_path: String) -> Dictionary:
if not FileAccess.file_exists(pck_path):
pack_load_failed.emit(pck_path, "File not found")
return {}
if not ProjectSettings.load_resource_pack(pck_path):
pack_load_failed.emit(pck_path, "Failed to load resource pack")
return {}
# Read manifest from inside the loaded PCK
var manifest := _read_manifest("res://manifest.json")
if manifest.is_empty():
pack_load_failed.emit(pck_path, "No manifest.json found in pack")
return {}
var pack_name: String = manifest.get("name", pck_path.get_file())
_loaded_packs[pack_name] = {
"path": pck_path,
"manifest": manifest,
"active_scene": null
}
pack_loaded.emit(pack_name, manifest)
return manifest
## Load a pack from a project directory (pre-MVP: no .pck packaging needed).
func load_from_dir(dir_path: String) -> Dictionary:
var manifest_path := dir_path.path_join("manifest.json")
var manifest := _read_manifest(manifest_path)
if manifest.is_empty():
pack_load_failed.emit(dir_path, "No manifest.json found")
return {}
var pack_name: String = manifest.get("name", dir_path.get_file())
_loaded_packs[pack_name] = {
"path": dir_path,
"manifest": manifest,
"active_scene": null
}
pack_loaded.emit(pack_name, manifest)
return manifest
## Get all loaded packs.
func get_loaded_packs() -> Dictionary:
return _loaded_packs
## Instantiate the entry scene for a loaded pack.
func instantiate_entry(pack_name: String) -> Node:
var info: Dictionary = _loaded_packs.get(pack_name, {})
var manifest: Dictionary = info.get("manifest", {})
var entry: String = manifest.get("entry_scene", "")
if entry.is_empty():
return null
var scene := load(entry) as PackedScene
if not scene:
return null
return scene.instantiate()
func _read_manifest(path: String) -> Dictionary:
var f := FileAccess.open(path, FileAccess.READ)
if not f:
return {}
var text := f.get_as_text()
var data = JSON.parse_string(text)
if data is Dictionary:
return data
return {}