From f44a32830045d2384f3541a23fea75729f6cce09 Mon Sep 17 00:00:00 2001 From: autocommit Date: Wed, 15 Apr 2026 21:38:35 -0700 Subject: [PATCH] =?UTF-8?q?feat(city):=20=E2=9C=A8=20Add=20missing=20exten?= =?UTF-8?q?sion=20validation=20and=20production=20gating=20for=20city=20en?= =?UTF-8?q?tities=20with=20tech/race/school=20prerequisites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/game/engine/src/entities/city.gd | 57 +++++++++++++--------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/game/engine/src/entities/city.gd b/src/game/engine/src/entities/city.gd index 981cb36c..bda894ec 100644 --- a/src/game/engine/src/entities/city.gd +++ b/src/game/engine/src/entities/city.gd @@ -90,7 +90,10 @@ var _warned_missing_extension: bool = false func _init(city_id: String = "", starting_buildings: Array[String] = []) -> void: id = city_id buildings = starting_buildings.duplicate() - _gd_city = _instantiate_gd_city() + if ClassDB.class_exists("GdCity"): + _gd_city = ClassDB.instantiate("GdCity") as RefCounted + else: + _warn_missing_extension() if _gd_city != null: var b_arr: PackedStringArray = PackedStringArray() for b in buildings: @@ -321,24 +324,33 @@ func heal(amount: int) -> void: # ── Building / unit production queue (GDScript-side) ──────────────── -## These manage the legacy single production queue for buildings and units. -## Item production uses the Rust per-building queues (enqueue_item / tick_building). +## Tech/race/school/prereq gate; mirrors Rust QueueError::TechLocked. +func can_build(item_id: String, p: RefCounted) -> bool: + if p == null or item_id.is_empty(): + return false + var PF: GDScript = load("res://engine/src/modules/management/production_filter.gd") + if PF == null: + return true + if not DataLoader.get_unit(item_id).is_empty(): + return PF.is_unit_buildable(item_id, p) + if not DataLoader.get_building(item_id).is_empty(): + return PF.is_building_buildable(item_id, self, p) + return true -## Add a building or unit to the production queue. -func add_to_queue(type: String, item_id: String) -> void: +## Enqueue a building/unit. Returns false if gated. +func add_to_queue(type: String, item_id: String) -> bool: + if player != null and not can_build(item_id, player): + return false var cost: int = 0 if type == "building": - var bdata: Dictionary = DataLoader.get_building(item_id) - cost = int(bdata.get("cost", 0)) + cost = int(DataLoader.get_building(item_id).get("cost", 0)) elif type == "unit": - var udata: Dictionary = DataLoader.get_unit(item_id) - cost = int(udata.get("cost", 0)) + cost = int(DataLoader.get_unit(item_id).get("cost", 0)) production_queue.append({"type": type, "id": item_id, "cost": cost}) + return true - -## Apply production to the building/unit queue. Returns true if the -## current item completed this tick. +## Apply production; true if current item completed this tick. func apply_production(production: int) -> bool: if production_queue.is_empty(): return false @@ -470,29 +482,14 @@ func _sync_from_rust() -> void: position = _gd_city.call("get_position") # Sync buildings list var rust_json: String = _gd_city.call("to_json") - var parsed: Dictionary = _parse_json_dict(rust_json) - if not parsed.is_empty(): - var raw_buildings: Array = parsed.get("buildings", []) + var parsed_json: JSON = JSON.new() + if parsed_json.parse(rust_json) == OK and parsed_json.data is Dictionary: + var raw_buildings: Array = (parsed_json.data as Dictionary).get("buildings", []) buildings.clear() for b in raw_buildings: buildings.append(str(b)) -func _parse_json_dict(json: String) -> Dictionary: - var result: Dictionary = {} - var parsed_json: JSON = JSON.new() - if parsed_json.parse(json) == OK and parsed_json.data is Dictionary: - result = parsed_json.data - return result - - -func _instantiate_gd_city() -> RefCounted: - if not ClassDB.class_exists("GdCity"): - _warn_missing_extension() - return null - return ClassDB.instantiate("GdCity") as RefCounted - - func _warn_missing_extension() -> void: if _warned_missing_extension: return