magicciv/engine/src/autoloads/data_loader_worlds.gd
Claude Code 554ed62ca3 refactor(data-loader): ♻️ Restructure data loading logic with lazy loading and caching for improved efficiency
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-03-31 05:43:29 -07:00

105 lines
3.8 KiB
GDScript

extends RefCounted
## World loading delegate for DataLoader.
## Reads world manifests from engine/src/worlds/, loads biome/substrate collections,
## and registers runtime biomes into BiomeRegistry.
const WORLDS_BASE: String = "res://resources/worlds"
const BIOMES_BASE: String = "res://resources/biomes"
const EVENTS_BASE: String = "res://resources/events"
var manifest: Dictionary = {}
var active_world: String = ""
## Physics raw data loaded from world path (climate_params, climate_spec, hydrology_params).
## DataLoader merges these into _raw after calling load_world().
var physics: Dictionary = {}
## Capability flags from manifest.physics_features — explicit per-subsystem on/off.
var physics_features: Dictionary = {}
const PHYSICS_FILES: Array[String] = [
"climate_params", "climate_spec", "hydrology_params"
]
func load_world(world_id: String, ecology: Variant) -> void:
active_world = world_id
physics = {}
physics_features = {}
var world_path: String = "%s/%s" % [WORLDS_BASE, world_id]
# Load manifest
manifest = _load_json("%s/manifest.json" % world_path)
if manifest.is_empty():
push_error("DataLoader: Cannot load world manifest for '%s'" % world_id)
return
physics_features = manifest.get("physics_features", {})
# Load physics parameter files
for key: String in PHYSICS_FILES:
var data: Dictionary = _load_json("%s/%s.json" % [world_path, key])
if not data.is_empty():
physics[key] = data
# Load subscribed events
var events: Dictionary = {}
for event_id: Variant in manifest.get("subscribes_events", []):
var event_path: String = "%s/%s.json" % [EVENTS_BASE, str(event_id)]
var entry: Dictionary = _load_json(event_path)
if entry.is_empty():
push_warning("DataLoader: Missing event '%s'" % event_id)
continue
events[str(event_id)] = entry
if not events.is_empty():
physics["events"] = events
# Load subscribed biome collections
var biome_count: int = 0
for collection_id: Variant in manifest.get("subscribes_biomes", []):
var entries: Array = _load_collection_entries(str(collection_id), "biomes")
for entry: Dictionary in entries:
ecology.register_collection_biome(entry)
biome_count += 1
# Load subscribed substrate collections
var substrate_count: int = 0
for collection_id: Variant in manifest.get("subscribes_substrates", []):
var entries: Array = _load_collection_entries(str(collection_id), "substrates")
for entry: Dictionary in entries:
ecology.register_collection_substrate(entry)
substrate_count += 1
# Load runtime biomes
var runtime_data: Dictionary = _load_json("%s/runtime_biomes.json" % world_path)
for entry: Variant in runtime_data.get("runtime_biomes", []):
if entry is Dictionary and entry.has("id"):
var rt_tags: Array[String] = []
for tag: Variant in entry.get("tags", []):
rt_tags.append(str(tag))
BiomeRegistry.register_runtime_biome(str(entry["id"]), rt_tags)
BiomeRegistry.rebuild_from_data()
print("DataLoader: World '%s' — %d biomes, %d substrates, %d physics files" % [
world_id, biome_count, substrate_count, physics.size()])
func _load_collection_entries(collection_id: String, key: String) -> Array:
var path: String = "%s/%s/%s.json" % [BIOMES_BASE, collection_id, key]
var data: Dictionary = _load_json(path)
var entries: Array = data.get(key, [])
if entries.is_empty():
push_warning("DataLoader: Empty or missing collection %s/%s" % [collection_id, key])
return entries
func _load_json(path: String) -> Dictionary:
if not FileAccess.file_exists(path):
return {}
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
if file == null:
return {}
var json: JSON = JSON.new()
if json.parse(file.get_as_text()) != OK:
push_warning("DataLoader: JSON error in %s: %s" % [path, json.get_error_message()])
return {}
if json.data is Dictionary:
return json.data
return {}