148 lines
8.2 KiB
GDScript
148 lines
8.2 KiB
GDScript
extends SceneTree
|
|
|
|
var _checks := 0
|
|
var _failures := 0
|
|
var _runtime: Variant
|
|
var _clock: Variant
|
|
var _state: Variant
|
|
var _serial := 0
|
|
var _main: Control
|
|
var _saw_trip := false
|
|
var _saw_boarded := false
|
|
var _saw_arrival := false
|
|
var _saved := false
|
|
var _preview_snapshot: Dictionary = {}
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
func _run() -> void:
|
|
_runtime = root.get_node("SimulationRuntime")
|
|
_clock = root.get_node("GameClock")
|
|
_state = root.get_node("GameState")
|
|
_clock.reset(1, 6, 0)
|
|
_state.reset()
|
|
_runtime.initialize(_clock, _state, 424242)
|
|
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
|
_clock.set_paused(true)
|
|
root.size = Vector2i(1440, 810)
|
|
_main = load("res://scenes/main/main.tscn").instantiate() as Control
|
|
_main.set("manual_save_path", "user://tests/transport_%d/manual" % OS.get_process_id())
|
|
root.add_child(_main)
|
|
await process_frame
|
|
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
|
_expect(_state.get_resource(&"gold") == 5000 and _state.get_resource(&"materials") == 50, "ordinary starting budget")
|
|
if not _build(&"guest_elevator", Vector3i(0, 0, 0)) or not _build(&"reception", Vector3i(2, 0, 0)):
|
|
_finish(); return
|
|
_clock.advance_minutes(300)
|
|
_expect(_runtime.elevators.get_report()[&"shafts"].size() == 1, "completed construction registers physical cabin")
|
|
if _runtime.elevators.get_report()[&"shafts"].is_empty(): _finish(); return
|
|
if not _build(&"guest_elevator", Vector3i(0, 2, 0)) or not _build(&"standard_room", Vector3i(2, 2, 0)):
|
|
_finish(); return
|
|
_clock.advance_minutes(300)
|
|
if not _build(&"standard_room", Vector3i(2, 3, 0)):
|
|
_finish(); return
|
|
_clock.advance_minutes(60)
|
|
var report: Dictionary = _runtime.elevators.get_report()
|
|
_expect(report[&"shafts"].size() == 1 and report[&"shafts"][0][&"stops"].size() == 4, "stacked modules share one cabin across four floors")
|
|
_expect(_state.get_resource(&"materials") == 2, "buildings fit within 50 materials")
|
|
var reception: FacilityInstance
|
|
for facility: FacilityInstance in _runtime.facility_service.get_instances():
|
|
if facility.definition_id == &"reception": reception = facility
|
|
_expect(_cmd(&"hire_staff_candidate", {&"candidate_id": &"staff_akane"}).is_success(), "hire receptionist with earned starting funds")
|
|
_expect(_cmd(&"set_staff_work_assignment", {&"staff_id": &"staff_akane", &"facility_id": reception.instance_id, &"template_id": &"DAY"}).is_success(), "assign real commute")
|
|
_expect(reception.active_staff_ids.is_empty(), "assignment alone does not open reception")
|
|
for index: int in range(250):
|
|
_clock.advance_minutes(1)
|
|
var current: Dictionary = _runtime.elevators.get_report()
|
|
if not current[&"trips"].is_empty(): _saw_trip = true
|
|
for trip: Dictionary in current[&"trips"]:
|
|
if trip[&"state"] != PathService.ELEVATOR_REQUEST_BOARDED: continue
|
|
_saw_boarded = true
|
|
if not _saved:
|
|
_saved = _verify_mid_ride()
|
|
_preview_snapshot = _runtime.create_snapshot()
|
|
for guest: GuestRuntime in _runtime.guest_service.get_guests():
|
|
if guest.current_cell.y >= 2: _saw_arrival = true
|
|
if _saw_boarded and not _main.get_meta(&"captured", false) and OS.get_environment("THE_TREE_TRANSPORT_CAPTURE") == "1":
|
|
_main.set_meta(&"captured", true)
|
|
await _capture()
|
|
if index % 30 == 0: await process_frame
|
|
if not _saw_trip:
|
|
print("TRANSPORT_DIAGNOSTIC ", _runtime.elevators.get_report(), " STAFF ", _runtime.staff_commute.get_report())
|
|
for f: FacilityInstance in _runtime.facility_service.get_instances(): print("FAC ", f.definition_id, " ", f.state, " ", f.active_staff_ids)
|
|
for g: GuestRuntime in _runtime.guest_service.get_guests(): print("GUEST ", g.guest_id, " ", g.state, " ", g.current_cell, " ", _runtime._project_guest_candidates(g.guest_id))
|
|
_expect(_saw_trip, "natural guest requests an elevator")
|
|
_expect(_saw_boarded, "natural guest boards the shared cabin")
|
|
_expect(_saw_arrival, "natural guest physically reaches an upper floor")
|
|
_expect(_saved, "mid-ride replay tested")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "current completed runtime restores")
|
|
if OS.get_environment("THE_TREE_TRANSPORT_PREVIEW") == "1" and _failures == 0:
|
|
_expect(_runtime.restore_snapshot(_preview_snapshot), "preview returns to the verified first boarding")
|
|
if _failures > 0: _finish(); return
|
|
await _capture()
|
|
DisplayServer.window_set_title("The Tree · 昇降機と通勤の試遊(保存なし)")
|
|
_clock.set_paused(true)
|
|
print("Runtime transport: %d checks, %d failures" % [_checks, _failures])
|
|
print("TRANSPORT_PREVIEW_READY Space resumes; test saves disabled")
|
|
return
|
|
_finish()
|
|
|
|
func _verify_mid_ride() -> bool:
|
|
var save_path := "user://tests/transport_%d/ride" % OS.get_process_id()
|
|
_expect(bool(_runtime.save_to_path(save_path).get(&"ok", false)), "boarded save writes isolated disk slot")
|
|
_expect(bool(_runtime.load_from_path(save_path).get(&"ok", false)), "boarded disk slot reloads")
|
|
var snapshot: Dictionary = _runtime.create_snapshot()
|
|
_expect(snapshot[&"systems"][&"runtime"][&"runtime_schema_version"] == 8, "runtime schema8 records elevator state")
|
|
_expect(_runtime.restore_snapshot(snapshot), "mid-ride Runtime snapshot restores actor/cabin/Path ownership")
|
|
var shaft: Dictionary = _runtime.elevators.get_report()[&"shafts"][0]
|
|
var busy := _cmd(&"demolish_facility", {&"instance_id": shaft[&"module_ids"][1]})
|
|
_expect(not busy.is_success() and busy.details.get(&"reason") == &"ELEVATOR_BUSY", "occupied shaft demolition rejected before spending or topology changes")
|
|
_expect(_runtime.restore_snapshot(snapshot), "snapshot resets rejected command metadata")
|
|
_clock.advance_minutes(45)
|
|
var expected: Dictionary = _runtime.create_snapshot()
|
|
_expect(_runtime.restore_snapshot(snapshot), "rewind boarded save for deterministic replay")
|
|
_clock.advance_minutes(45)
|
|
_expect(_runtime._strict_variants_equal(expected, _runtime.create_snapshot()), "mid-ride save replays all Runtime state identically")
|
|
_expect(_runtime.restore_snapshot(snapshot), "restore original ride position after replay test")
|
|
var stopped := _cmd(&"set_elevator_operation", {&"shaft_id": shaft[&"shaft_id"], &"operator_open": false})
|
|
_expect(stopped.is_success(), "player stops elevator through public command")
|
|
_expect(_runtime.elevators.get_report()[&"trips"].is_empty(), "stop releases waiting and disembarks passengers at safe floor")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "stopped elevator save restores")
|
|
_expect(_runtime.restore_snapshot(snapshot), "resume original operating snapshot")
|
|
return true
|
|
|
|
func _capture() -> void:
|
|
var preview: Control = _main.get("world_preview")
|
|
_main.call("_on_facility_selected", _runtime.elevators.get_report()[&"shafts"][0][&"module_ids"][0])
|
|
preview.call("set_zoom", 2.0)
|
|
preview.set("pan_offset", preview.get("pan_offset") + preview.size * Vector2(0.5, 0.55) - preview.call("cell_to_canvas", Vector3i(2, 1, 0)))
|
|
preview.queue_redraw()
|
|
await process_frame
|
|
await RenderingServer.frame_post_draw
|
|
for trip: Dictionary in _runtime.elevators.get_report()[&"trips"]:
|
|
if trip[&"state"] != PathService.ELEVATOR_REQUEST_BOARDED: continue
|
|
var key := String(trip[&"actor_id"]).replace("guest:", "guest/").replace("staff:", "staff/")
|
|
_expect((preview.get("_boarded_actor_ids") as Dictionary).has(key), "live rider identified in cabin rendering")
|
|
_expect(not (preview.get("_actor_tracks") as Dictionary).has(key), "live rider is not duplicated on floor")
|
|
var path := ProjectSettings.globalize_path("res://artifacts/transport/elevator-cabin.png")
|
|
root.get_texture().get_image().save_png(path)
|
|
|
|
func _build(id: StringName, origin: Vector3i) -> bool:
|
|
var result := _cmd(&"build_facility", {&"definition_id": id, &"origin": origin})
|
|
_expect(result.is_success(), "build %s at %s %s" % [id, origin, result.message])
|
|
return result.is_success()
|
|
|
|
func _cmd(kind: StringName, payload: Dictionary) -> CommandResult:
|
|
_serial += 1
|
|
return _runtime.submit_command(kind, payload, &"player", &"", 0, _clock.absolute_minute, StringName("transport.test.%d" % _serial))
|
|
|
|
func _expect(condition: bool, message: String) -> void:
|
|
_checks += 1
|
|
if not condition: _failures += 1
|
|
print("%s %s" % ["PASS" if condition else "FAIL", message])
|
|
|
|
func _finish() -> void:
|
|
print("Runtime transport: %d checks, %d failures" % [_checks, _failures])
|
|
quit(1 if _failures else 0)
|