spaceship/PlanetSetups.gd
Loïc Wisniewski 5326852807 Add planet setups as authored resources (#42)
PlanetSetup/PlanetSetupSpawn define a curated capture-point/enemy
layout for a surface profile; PlanetSetups scans res://PlanetSetups/
at first use (not a hardcoded preload table) so dropping in a new
.tres is the only step needed to add one, and resolves the same
setup for the same planet deterministically, same pattern as
WorldGen.planet_data_at_chunk. PlanetSurfaceController composes a
PlanetSetupHost onto the landed surface alongside the existing
resource-provider feature scene.

Ships two starter setups (rocky_default, gas_default) with
placeholder capture-point markers; #43 replaces the markers with the
real CapturePoint scene through the same apply_setup() entry point.

Part of the #40 conquest-mechanic breakdown.
2026-08-15 14:41:37 +02:00

69 lines
2.2 KiB
GDScript

class_name PlanetSetups
extends RefCounted
# Registry of authored PlanetSetup resources. Deliberately scans
# res://PlanetSetups/ at first use instead of a hardcoded preload
# dictionary (contrast PlanetDefinitions.gd), so dropping a new .tres in
# that folder is the only step needed to add a setup - the map editor
# (#48) writes there directly.
const SETUPS_DIR: String = "res://PlanetSetups"
# Compared against get_script() rather than an `is PlanetSetup` check - the
# same load-order hazard as PlanetSurfaceController's setup_host: a global
# class_name identifier can be looked up before an import pass has
# registered it, while a direct script preload never depends on that cache.
const PLANET_SETUP_SCRIPT: Script = preload("res://PlanetSetup.gd")
static var _all: Array = []
static var _scanned: bool = false
static func _ensure_scanned() -> void:
if _scanned:
return
_scanned = true
var dir: DirAccess = DirAccess.open(SETUPS_DIR)
if dir == null:
return
dir.list_dir_begin()
var file_name: String = dir.get_next()
while file_name != "":
if not dir.current_is_dir() and file_name.ends_with(".tres"):
var res: Resource = load(SETUPS_DIR + "/" + file_name)
if res != null and res.get_script() == PLANET_SETUP_SCRIPT:
_all.append(res)
file_name = dir.get_next()
dir.list_dir_end()
static func rescan() -> void:
# The map editor calls this after saving so a freshly written setup is
# visible without restarting the process.
_all = []
_scanned = false
_ensure_scanned()
static func all() -> Array:
_ensure_scanned()
return _all
static func setups_for_profile(profile_id: String) -> Array:
var result: Array = []
for setup in all():
if setup.surface_profile_id == profile_id:
result.append(setup)
return result
static func setup_for_planet(planet_id: String, profile_id: String) -> Resource:
# Same pattern as WorldGen.planet_data_at_chunk: seeded purely from the
# planet's own stable id, so the same planet always resolves to the
# same setup from anywhere, with nothing stored.
var candidates: Array = setups_for_profile(profile_id)
if candidates.is_empty():
return null
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
rng.seed = hash(planet_id)
return candidates[rng.randi() % candidates.size()]