232 lines
9.1 KiB
GDScript
232 lines
9.1 KiB
GDScript
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
|