82 lines
2.8 KiB
GDScript
82 lines
2.8 KiB
GDScript
extends Node
|
|
|
|
onready var ConsoleService = $"/root/ConsoleService"
|
|
|
|
var package_dict = {}
|
|
var package_load_order = []
|
|
|
|
# Locate all packages that can be loaded.
|
|
func discover_packages():
|
|
var dir = Directory.new()
|
|
dir.open("res://packages")
|
|
dir.list_dir_begin()
|
|
|
|
while true:
|
|
var package_name = dir.get_next()
|
|
if package_name == "": break
|
|
if not dir.current_is_dir() or package_name == "." or package_name == "..": continue
|
|
|
|
var package_script = load("res://packages/"+package_name+"/main.gd");
|
|
if !package_script: continue
|
|
|
|
var package = {
|
|
"name": package_script.package.name if package_script.package.has("name") else package_name,
|
|
"version": package_script.package.version if package_script.package.has("version") else "1.0.0",
|
|
"dependencies": package_script.package.dependencies if package_script.package.has("dependencies") else [],
|
|
"_script": package_script
|
|
}
|
|
package_dict[package.name] = package
|
|
|
|
dir.list_dir_end()
|
|
_compute_dependency_graph()
|
|
|
|
func load_packages():
|
|
for package_name in package_load_order:
|
|
var package = package_dict[package_name]
|
|
package._instance = package._script.new()
|
|
if !package._instance:
|
|
ConsoleService.log("[PackageService] Failed to load package '"+package.name+"'")
|
|
continue
|
|
|
|
func init_packages():
|
|
for package_name in package_load_order:
|
|
var package = package_dict[package_name]
|
|
if not package.has("_instance"):
|
|
ConsoleService.log("[PackageService] Package '"+package.name+"' has not been loaded. Please load before initializing.")
|
|
continue
|
|
$"/root/Main/Packages".add_child(package._instance)
|
|
if package._instance.has_method('init'):
|
|
package._instance.init()
|
|
|
|
func _compute_dependency_graph():
|
|
if package_dict.size() == 0:
|
|
ConsoleService.error("[PackageService] packages have not been preloaded (Run preload_instances first)")
|
|
return
|
|
|
|
var resolved = []; # Properly ordered package list.
|
|
for package in package_dict.values():
|
|
_resolve_dependency(package, resolved, [])
|
|
|
|
package_load_order = resolved
|
|
|
|
func _resolve_dependency(package: Dictionary, resolved: Array, unresolved: Array):
|
|
if package.name in resolved:
|
|
return
|
|
# Unresolved is used to prevent recursive lookups.
|
|
unresolved.append(package.name)
|
|
|
|
for dependency_name in package.dependencies:
|
|
if dependency_name in resolved: continue
|
|
if dependency_name in unresolved:
|
|
ConsoleService.error("[PackageService] Circular dependency between '"+package.name+"' <-> '"+dependency_name+"'")
|
|
assert(false)
|
|
if not package_dict.has(dependency_name):
|
|
ConsoleService.error("[PackageService] package '"+package.name+"' requires package '"+dependency_name+"' to be installed, but it is not")
|
|
assert(false)
|
|
|
|
var dependency = package_dict[dependency_name]
|
|
_resolve_dependency(dependency, resolved, unresolved)
|
|
|
|
resolved.append(package.name)
|
|
unresolved.erase(package.name)
|