extends SceneTree const WorldSimulation = preload("res://src/simulation/world_simulation.gd") func _initialize() -> void: var failures: Array[String] = [] var reports: Dictionary = {} reports["no_mana"] = _capture_no_mana() reports["missing_input"] = _capture_missing_input() reports["waiting_input"] = _capture_waiting_input() reports["working"] = _capture_working() reports["outputting"] = _capture_outputting() reports["blocked_output"] = _capture_blocked_output() reports["charger_no_mana"] = _capture_charger_no_mana() for status in [ &"no_mana", &"missing_input", &"waiting_input", &"working", &"outputting", &"blocked_output", ]: if not reports.has(status): failures.append("Missing inspection capture for %s." % String(status)) continue var capture: Dictionary = reports[status] if not bool(capture.get("ok", false)): failures.append( "Could not reach status %s (got %s)." % [ String(status), String(capture.get("status", &"")), ] ) continue failures.append_array(_validate_payload(status, capture["report"], capture["unchanged"])) var charger_capture: Dictionary = reports["charger_no_mana"] if not bool(charger_capture.get("ok", false)): failures.append("Charger did not emit a second-stage no_mana status.") else: var charger_report: Dictionary = charger_capture["report"] var recipe: Dictionary = charger_report.get("recipe", {}) if recipe.get("id", &"") != WorldSimulation.RECIPE_CHARGE: failures.append("Charger inspection did not expose the charge recipe.") if recipe.get("input_kind", &"") != WorldSimulation.ITEM_REFINED: failures.append("Charger recipe input was not refined crystal.") if recipe.get("output_kind", &"") != WorldSimulation.ITEM_CHARGED: failures.append("Charger recipe output was not charged crystal.") failures.append_array( _validate_payload(&"no_mana", charger_report, charger_capture["unchanged"]) ) if failures.is_empty(): print("INSPECTION_SMOKE_OK statuses=%s" % ",".join([ "no_mana", "missing_input", "waiting_input", "working", "outputting", "blocked_output", "charger_no_mana", ])) quit(0) else: for failure in failures: push_error(failure) quit(1) func _validate_payload(status: StringName, report: Dictionary, unchanged: bool) -> Array[String]: var failures: Array[String] = [] if report.is_empty(): failures.append("Inspection returned an empty payload for %s." % String(status)) return failures for key in ["recipe", "progress", "inventory", "mana", "reason"]: if not report.has(key): failures.append("Inspection for %s missing field %s." % [String(status), key]) var recipe: Dictionary = report.get("recipe", {}) if recipe.is_empty() or not recipe.has("id"): failures.append("Inspection for %s missing recipe id." % String(status)) var progress: Dictionary = report.get("progress", {}) if not progress.has("ratio") or not progress.has("remaining_ticks"): failures.append("Inspection for %s missing progress fields." % String(status)) var inventory: Dictionary = report.get("inventory", {}) if not inventory.has("input_count") or not inventory.has("output_buffer"): failures.append("Inspection for %s missing inventory fields." % String(status)) var mana: Dictionary = report.get("mana", {}) if not mana.has("powered") or not mana.has("network"): failures.append("Inspection for %s missing mana fields." % String(status)) if status != &"working" and String(report.get("reason", "")).is_empty(): failures.append("Inspection for %s had an empty stop reason." % String(status)) if not unchanged: failures.append("Inspection for %s mutated tick, inventory, or fingerprint." % String(status)) return failures func _inspect_without_mutation(simulation: WorldSimulation, building_id: int) -> Dictionary: var before := { "tick": simulation.tick_index, "fingerprint": simulation.state_fingerprint(), "sink": simulation.sink_inventory.duplicate(), } var input_count := -1 if simulation.buildings.has(building_id): input_count = int(simulation.buildings[building_id].get("input_count", -1)) var report := simulation.inspect_building(building_id) var unchanged: bool = ( int(before["tick"]) == simulation.tick_index and String(before["fingerprint"]) == simulation.state_fingerprint() and before["sink"] == simulation.sink_inventory and ( input_count < 0 or input_count == int(simulation.buildings[building_id].get("input_count", -2)) ) ) return { "report": report, "unchanged": unchanged, "status": report.get("status", &""), "ok": not report.is_empty(), } func _capture_no_mana() -> Dictionary: var simulation := WorldSimulation.new() var machine_id := simulation.place_building(WorldSimulation.KIND_MACHINE, Vector2i(0, 0), 0) simulation.step() var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "no_mana" return capture func _capture_missing_input() -> Dictionary: var simulation := WorldSimulation.new() var machine_id := simulation.place_building(WorldSimulation.KIND_MACHINE, Vector2i(0, 0), 0) simulation.place_building(WorldSimulation.KIND_MANA_SOURCE, Vector2i(0, 1), 0) simulation.step() var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "missing_input" return capture func _capture_waiting_input() -> Dictionary: var simulation := WorldSimulation.new() var machine_id := simulation.place_building(WorldSimulation.KIND_MACHINE, Vector2i(0, 0), 0) simulation.place_building(WorldSimulation.KIND_MANA_SOURCE, Vector2i(0, 1), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(-1, 0), 0) simulation.step() var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "waiting_input" return capture func _capture_working() -> Dictionary: var simulation := _powered_line() var machine_id := _find_kind(simulation, WorldSimulation.KIND_MACHINE) for _tick in range(400): simulation.step() if String(simulation.buildings[machine_id]["status"]) == "working": var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "working" return capture return {"ok": false, "status": simulation.buildings[machine_id]["status"], "report": {}, "unchanged": true} func _capture_outputting() -> Dictionary: var simulation := _powered_line() var machine_id := _find_kind(simulation, WorldSimulation.KIND_MACHINE) var source_cell := Vector2i(-3, 0) for _tick in range(400): simulation.step() if int(simulation.buildings[_find_kind(simulation, WorldSimulation.KIND_SOURCE)].get("produced", 0)) >= 1: break simulation.remove_building(source_cell) for _tick in range(400): simulation.step() if String(simulation.buildings[machine_id]["status"]) == "outputting": var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "outputting" return capture return {"ok": false, "status": simulation.buildings[machine_id]["status"], "report": {}, "unchanged": true} func _capture_blocked_output() -> Dictionary: var simulation := WorldSimulation.new() simulation.place_building(WorldSimulation.KIND_SOURCE, Vector2i(-3, 0), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(-2, 0), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(-1, 0), 0) var machine_id := simulation.place_building(WorldSimulation.KIND_MACHINE, Vector2i(0, 0), 0) simulation.place_building(WorldSimulation.KIND_MANA_SOURCE, Vector2i(0, 1), 0) for _tick in range(400): simulation.step() if String(simulation.buildings[machine_id]["status"]) == "blocked_output": var capture := _inspect_without_mutation(simulation, machine_id) capture["ok"] = String(capture["status"]) == "blocked_output" return capture return {"ok": false, "status": simulation.buildings[machine_id]["status"], "report": {}, "unchanged": true} func _capture_charger_no_mana() -> Dictionary: var simulation := WorldSimulation.new() var charger_id := simulation.place_building(WorldSimulation.KIND_CHARGER, Vector2i(2, 0), 0) simulation.step() var capture := _inspect_without_mutation(simulation, charger_id) capture["ok"] = String(capture["status"]) == "no_mana" return capture func _powered_line() -> WorldSimulation: var simulation := WorldSimulation.new() simulation.place_building(WorldSimulation.KIND_SOURCE, Vector2i(-3, 0), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(-2, 0), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(-1, 0), 0) simulation.place_building(WorldSimulation.KIND_MACHINE, Vector2i(0, 0), 0) simulation.place_building(WorldSimulation.KIND_MANA_SOURCE, Vector2i(0, 2), 0) simulation.place_building(WorldSimulation.KIND_MANA_PIPE, Vector2i(0, 1), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(1, 0), 0) simulation.place_building(WorldSimulation.KIND_BELT, Vector2i(2, 0), 0) simulation.place_building(WorldSimulation.KIND_SINK, Vector2i(3, 0), 0) return simulation func _find_kind(simulation: WorldSimulation, kind: StringName) -> int: for id_variant in simulation.get_building_ids(): var id := int(id_variant) if simulation.buildings[id]["kind"] == kind: return id return -1