Files
TheTree_mock/tests/s3/test_runtime_path_traffic.gd
T
Takeshi 5dde0c5ec2 Record original-alignment implementation and traceability checkpoint
Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
2026-09-30 23:52:24 +09:00

642 lines
27 KiB
GDScript

extends SceneTree
const POST_V2_RUNTIME_KEYS := [
&"kitchen_production",
&"elevators",
&"legacy_stairs",
&"movement_credits",
&"catalog_manifest",
&"progression",
&"hired_staff_candidate_ids",
&"operations",
&"excavation",
&"spatial_subslots",
&"route_projection",
&"facility_infrastructure",
]
const POST_V2_EVENT_TYPES := [
&"PATH_ACTOR_STUCK",
&"WORLD_TREE_RANK_ADVANCED",
&"STAFF_CANDIDATE_HIRED",
&"GUEST_AUTO_ARRIVED",
&"FACILITY_INFRASTRUCTURE_PROJECTED",
&"EXCAVATION_COMPLETED",
]
const POST_V2_COMMAND_TYPES := [
&"set_world_tree_rank",
&"update_progression_metrics",
&"complete_progression_quest",
&"hire_staff_candidate",
&"acknowledge_operations_pause",
&"start_excavation",
&"pause_excavation",
&"resume_excavation",
]
var _checks := 0
var _failures := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
print("S3: Runtime Path traffic integration")
_test_namespaced_lifecycle_and_density()
_test_congestion_credit_and_alternate_route()
_test_occupied_cell_graph_rebuild_is_rejected()
_test_stuck_guest_and_staff_recovery()
_test_event_recovery_path_transaction()
_test_current_snapshot_crosslinks_and_legacy_v2()
_test_dispatcher_request_ownership_crosslinks()
_test_twenty_four_hour_projection_integrity()
_cleanup()
if _failures == 0:
print("PASS: %d checks" % _checks)
else:
push_error("FAIL: %d of %d checks failed" % [_failures, _checks])
quit(_failures)
func _reset_runtime(seed: int) -> void:
_cleanup()
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
var report: Dictionary = _runtime.initialize(_clock, _state, seed)
_clock.set_paused(true)
_expect(bool(report.get(&"valid", false)), "Runtime initializes for Path traffic fixture %d" % seed)
func _cleanup() -> void:
if _runtime != null:
_runtime.free()
if _clock != null:
_clock.free()
if _state != null:
_state.free()
_runtime = null
_clock = null
_state = null
func _test_namespaced_lifecycle_and_density() -> void:
_reset_runtime(8_101)
var cell := Vector3i(-4, 0, WorldService.LAYER_FRONT)
_expect(_spawn_moving_guest(&"shared", cell, Vector3i(4, 0, 0)), "Guest with shared raw id spawns")
_expect(_register_idle_staff(&"shared", cell), "Staff with the same raw id registers")
_expect(
_runtime.path_service.has_actor_projection(&"guest:shared")
and _runtime.path_service.has_actor_projection(&"staff:shared"),
"Guest and Staff use collision-free namespaced Path actor ids"
)
_expect(
_runtime.path_service.get_current_density(cell) == 2,
"spawn/register projects both actors into the authoritative cell density"
)
var guest: GuestRuntime = _runtime.guest_service.get_guest(&"shared")
_runtime.guest_service.begin_leaving(&"shared", _clock.absolute_minute, &"TEST_EXIT")
_runtime.guest_service.despawn_guest(&"shared", _clock.absolute_minute)
_expect(guest != null and not _runtime.path_service.has_actor_projection(&"guest:shared"), "Guest despawn removes only its namespaced projection")
_expect(
_runtime.path_service.has_actor_projection(&"staff:shared")
and _runtime.path_service.get_current_density(cell) == 1,
"Guest despawn preserves the colliding raw Staff id and lowers density once"
)
_expect(_runtime.get_actor_movement_credit(&"guest:shared").is_empty(), "Guest despawn removes movement credit")
_runtime.staff_service.remove_staff(&"shared", &"TEST_REMOVE", true, _clock.absolute_minute)
_expect(
not _runtime.path_service.has_actor_projection(&"staff:shared")
and _runtime.path_service.get_current_density(cell) == 0,
"Staff removal cleans projection and density without going negative"
)
var invalid_spawn: CommandResult = _runtime.submit_command(
&"spawn_guest",
{
&"guest_id": &"invalid_cell",
&"guest_type_id": &"traveler",
&"options": {&"current_cell": Vector3i(0, 2, 0)},
},
&"world", &"invalid_cell", 10, -1, &"path.invalid.spawn"
)
_expect(
not invalid_spawn.is_success()
and not _runtime.guest_service.has_guest(&"invalid_cell")
and not _runtime.path_service.has_actor_projection(&"guest:invalid_cell")
and _runtime.get_actor_movement_credit(&"guest:invalid_cell").is_empty()
and not _has_recent_event(&"GUEST_SPAWNED", &"invalid_cell"),
"failed spawn leaves Actor, Path, credit, and lifecycle events uncommitted"
)
func _test_congestion_credit_and_alternate_route() -> void:
_reset_runtime(8_102)
var origin := Vector3i(-8, 0, WorldService.LAYER_FRONT)
var target := Vector3i(8, 0, WorldService.LAYER_FRONT)
_runtime.path_service.configure_cell_traffic(origin, 1, 0, false)
for index in range(5):
_expect(
_spawn_moving_guest(StringName("slow_%02d" % index), origin, target),
"congestion Guest %d spawns" % index
)
_expect(_runtime.path_service.get_current_density(origin) == 5, "five same-route actors create over-capacity density")
_clock.advance_one_minute()
var after_one: Array[Vector3i] = _guest_cells_with_prefix("slow_")
_expect(after_one.all(func(cell: Vector3i) -> bool: return cell == origin), "over-capacity speed credit prevents a first-minute burst")
_expect(
int(_runtime.get_actor_movement_credit(&"guest:slow_00").get(&"credit", -1)) == 500,
"Path speed multiplier is stored as deterministic fixed-point credit"
)
_clock.advance_minutes(1)
var after_two: Array[Vector3i] = _guest_cells_with_prefix("slow_")
_expect(after_two.all(func(cell: Vector3i) -> bool: return cell != origin), "half speed guarantees progress by the second congested minute")
_expect(_runtime.path_service.get_current_density(origin) == 0, "sequential committed movement lowers source density exactly")
_reset_runtime(8_103)
for x in range(0, 3):
var definition_id: StringName = &"guest_corridor" if x == 1 else &"guest_stairs"
var built: CommandResult = _runtime.submit_command(
&"build_facility", {&"definition_id": definition_id, &"origin": Vector3i(x, 1, WorldService.LAYER_FRONT)},
&"manager", &"", 0, -1, StringName("path.parallel.build.%d" % x)
)
_expect(built.is_success(), "parallel lane uses normal %s construction at x=%d" % [definition_id, x])
if not built.is_success():
return
_clock.advance_minutes(10)
_expect(_runtime.construction_service.get_job(built.details[&"job_id"]).state == ConstructionJob.State.COMPLETED, "parallel lane construction completes")
_expect(_runtime.path_service.get_vertical_walk_requires_connector(), "parallel lane retains strict floor policy")
var congested := Vector3i(1, 0, WorldService.LAYER_FRONT)
_runtime.path_service.configure_cell_traffic(congested, 1, 0, false)
# Two 150-cost stairs make the upper route 500; six occupants make the
# direct two-cell lane 575, so the stair detour remains strictly cheaper.
for blocker_index in range(6):
_expect(
_register_idle_staff(StringName("blocker_%d" % blocker_index), congested),
"alternate-route blocker %d registers" % blocker_index
)
_expect(
_spawn_moving_guest(&"route_picker", Vector3i(0, 0, 0), Vector3i(2, 0, 0)),
"route-selection Guest spawns"
)
var planned: Array[Vector3i] = _runtime.path_service.find_path(
Vector3i(0, 0, 0), Vector3i(2, 0, 0)
)
_expect(
planned.size() > 1 and planned[1] == Vector3i(0, 1, 0),
"congestion-aware A* selects the parallel lane before Runtime movement (%s)" % [planned]
)
_clock.advance_one_minute()
var picker: GuestRuntime = _runtime.guest_service.get_guest(&"route_picker")
_expect(picker.current_cell == Vector3i(0, 0, 0) and _runtime.get_actor_movement_credit(&"guest:route_picker")[&"credit"] == 1000, "first stair minute preserves incomplete movement credit")
_clock.advance_one_minute()
picker = _runtime.guest_service.get_guest(&"route_picker")
_expect(
picker != null and picker.current_cell == Vector3i(0, 1, 0),
"live congestion makes Runtime choose the cheaper parallel lane (actual %s)" % (
picker.current_cell if picker != null else "missing"
)
)
_expect(
_runtime.path_service.get_actor_projected_cell(&"guest:route_picker") == picker.current_cell,
"alternate-route movement commits Actor and Path projection together"
)
func _test_occupied_cell_graph_rebuild_is_rejected() -> void:
_reset_runtime(8_110)
var occupied := Vector3i(0, 0, WorldService.LAYER_FRONT)
_expect(_register_idle_staff(&"rebuild_guard", occupied), "graph-rebuild guard fixture registers")
var path_before: Dictionary = _runtime.path_service.create_snapshot()
_expect(_runtime.world_service.set_walkable(occupied, false), "fixture removes an occupied World cell")
_expect(
not _runtime.rebuild_path_graph_from_world(),
"Runtime rejects a graph rebuild that would evict a live actor projection"
)
_expect(
_runtime.path_service.create_snapshot() == path_before
and _runtime.path_service.get_actor_projected_cell(&"staff:rebuild_guard") == occupied
and not _runtime.get_actor_movement_credit(&"staff:rebuild_guard").is_empty(),
"rejected graph rebuild preserves Path projection, progress, density, and credit"
)
_expect(_runtime.world_service.set_walkable(occupied, true), "fixture restores the occupied World cell")
_expect(_runtime.rebuild_path_graph_from_world(), "safe topology rebuild succeeds after World repair")
func _test_stuck_guest_and_staff_recovery() -> void:
_reset_runtime(8_104)
_expect(
_spawn_moving_guest(&"stuck_guest", Vector3i(0, 0, 0), Vector3i(2, 0, 0)),
"stuck Guest fixture spawns"
)
_runtime.path_service.set_cell_temporary_block(Vector3i(1, 0, 0), true)
_clock.advance_minutes(PathService.STUCK_THRESHOLD_MINUTES - 1)
var guest: GuestRuntime = _runtime.guest_service.get_guest(&"stuck_guest")
_expect(guest != null and guest.state == GuestRuntime.State.MOVING, "Guest remains in movement recovery window before 30 minutes")
_clock.advance_one_minute()
guest = _runtime.guest_service.get_guest(&"stuck_guest")
_expect(guest != null and guest.state == GuestRuntime.State.LEAVING, "30-minute Path report enters existing Guest safe recovery")
_expect(
guest != null and guest.current_cell == Vector3i.ZERO,
"stuck recovery proposes a safe target without implicit teleport"
)
_expect(_has_recent_event(&"PATH_ACTOR_STUCK", &"guest:stuck_guest"), "Guest stuck recovery emits a structured Path DomainEvent")
_reset_runtime(8_105)
_expect(_register_idle_staff(&"stuck_staff", Vector3i(0, 0, 0)), "stuck Staff fixture registers")
var created: CommandResult = _runtime.staff_service.create_task(
&"inspect", 90, _clock.absolute_minute,
{&"target_cell": Vector3i(2, 0, 0), &"estimated_minutes": 5},
&"stuck_task"
)
var task: StaffTask = _runtime.staff_service.get_task(&"stuck_task")
var member: StaffRuntime = _runtime.staff_service.get_staff(&"stuck_staff")
var reserved: bool = created.is_success() \
and task.reserve(&"stuck_staff", [], _clock.absolute_minute) \
and member.reserve_task(&"stuck_task", _clock.absolute_minute) \
and task.begin_moving(_clock.absolute_minute)
_expect(reserved, "StaffTask enters a consistent MOVING ownership fixture")
_runtime.path_service.set_cell_temporary_block(Vector3i(1, 0, 0), true)
_clock.advance_minutes(PathService.STUCK_THRESHOLD_MINUTES)
task = _runtime.staff_service.get_task(&"stuck_task")
member = _runtime.staff_service.get_staff(&"stuck_staff")
_expect(task != null and task.state == StaffTask.State.CANCELLED, "30-minute Staff stall cancels its owned task safely")
_expect(member != null and member.current_task_id.is_empty(), "Staff stuck recovery releases task ownership")
_expect(_has_recent_event(&"PATH_ACTOR_STUCK", &"staff:stuck_staff"), "Staff stuck cancellation emits a structured Path DomainEvent")
func _test_event_recovery_path_transaction() -> void:
_reset_runtime(8_109)
_expect(
_spawn_moving_guest(&"event_mover", Vector3i(-2, 0, 0), Vector3i(2, 0, 0)),
"Event recovery movement fixture spawns"
)
var actor_before: Dictionary = _runtime.guest_service.create_snapshot()
var path_before: Dictionary = _runtime.path_service.create_snapshot()
var credit_before: Dictionary = _runtime.get_actor_movement_credit(&"guest:event_mover")
var events_before: Dictionary = _runtime.domain_events.create_snapshot()
var action: EventAction = EventAction.new().configure(
&"recovery_move",
EventAction.Type.TELEPORT_ENTITY_FOR_RECOVERY,
{&"entity_id": &"event_mover", &"cell": Vector3i(-1, 0, 0)}
)
var applied: Dictionary = _runtime._execute_event_action_boundary(
action, &"apply", {&"event_instance_id": &"event.fixture"}, null
)
var moved: GuestRuntime = _runtime.guest_service.get_guest(&"event_mover")
_expect(
bool(applied.get(&"ok", false))
and moved.current_cell == Vector3i(-1, 0, 0)
and _runtime.path_service.get_actor_projected_cell(&"guest:event_mover") == moved.current_cell
and int(_runtime.get_actor_movement_credit(&"guest:event_mover")[&"credit"]) == 0,
"explicit Event recovery commits Actor, Path, and credit together"
)
var rolled_back: Dictionary = _runtime._execute_event_action_boundary(
action, &"rollback", {}, applied.get(&"token", null)
)
_expect(
bool(rolled_back.get(&"ok", false))
and _runtime.guest_service.create_snapshot() == actor_before
and _runtime.path_service.create_snapshot() == path_before
and _runtime.get_actor_movement_credit(&"guest:event_mover") == credit_before
and _runtime.domain_events.create_snapshot() == events_before,
"Event rollback restores Actor, Path, credit, and DomainEvents atomically"
)
func _test_current_snapshot_crosslinks_and_legacy_v2() -> void:
_reset_runtime(8_106)
var origin := Vector3i(-3, 0, 0)
_runtime.path_service.configure_cell_traffic(origin, 1, 0, false)
for index in range(2):
_spawn_moving_guest(StringName("save_%d" % index), origin, Vector3i(3, 0, 0))
_clock.advance_one_minute()
var snapshot: Dictionary = _runtime.create_snapshot()
var runtime_data: Dictionary = snapshot[&"systems"][&"runtime"]
_expect(int(runtime_data[&"runtime_schema_version"]) == 13, "Runtime snapshot advertises schema v13")
_expect(not runtime_data[&"movement_credits"].is_empty(), "mid-move snapshot persists fixed-point movement credits")
var digest := SimulationDigest.compute(snapshot)
_expect(_runtime.restore_snapshot(snapshot), "valid mid-move v9 snapshot restores")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == digest, "mid-move v9 save/load is exact")
var corruptions: Array[Dictionary] = []
var bad_actor := snapshot.duplicate(true)
bad_actor[&"systems"][&"runtime"][&"path"][&"actor_cells"][0][&"cell"] = Vector3i(0, 0, 0)
corruptions.append({&"label": "actor cell", &"snapshot": bad_actor})
var bad_density := snapshot.duplicate(true)
for cell_entry: Dictionary in bad_density[&"systems"][&"runtime"][&"path"][&"cell_traffic"]:
if cell_entry[&"cell"] == origin:
cell_entry[&"current_density"] = int(cell_entry[&"current_density"]) + 1
break
corruptions.append({&"label": "density", &"snapshot": bad_density})
var bad_progress := snapshot.duplicate(true)
bad_progress[&"systems"][&"runtime"][&"path"][&"actor_progress"][0][&"last_cell"] = Vector3i(1, 0, 0)
corruptions.append({&"label": "progress", &"snapshot": bad_progress})
var bad_credit := snapshot.duplicate(true)
bad_credit[&"systems"][&"runtime"][&"movement_credits"][0][&"credit"] = 1_000
corruptions.append({&"label": "movement credit range", &"snapshot": bad_credit})
var bad_credit_time := snapshot.duplicate(true)
bad_credit_time[&"systems"][&"runtime"][&"movement_credits"][0][&"updated_at"] = _clock.absolute_minute + 1
corruptions.append({&"label": "movement credit time", &"snapshot": bad_credit_time})
var missing_path_cell := snapshot.duplicate(true)
missing_path_cell[&"systems"][&"runtime"][&"path"][&"cell_traffic"].pop_back()
corruptions.append({&"label": "Path/world cell-set", &"snapshot": missing_path_cell})
for corruption: Dictionary in corruptions:
var live_before: Dictionary = _runtime.create_snapshot()
_expect(
not _runtime.restore_snapshot(corruption[&"snapshot"])
and _runtime.create_snapshot() == live_before,
"corrupt %s crosslink is rejected atomically" % corruption[&"label"]
)
var legacy_v2 := snapshot.duplicate(true)
var legacy_data: Dictionary = legacy_v2[&"systems"][&"runtime"]
legacy_data[&"runtime_schema_version"] = 2
_strip_post_v2_runtime_state(legacy_data)
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(legacy_data)
legacy_data[&"path"][&"schema_version"] = 3
legacy_data[&"path"].erase(&"vertical_walk_blockers")
legacy_data[&"path"].erase(&"vertical_walk_requires_connector")
legacy_data[&"path"].erase(&"transit_actor_ids")
legacy_data[&"path"][&"actor_cells"] = []
legacy_data[&"path"][&"actor_progress"] = []
for traffic: Dictionary in legacy_data[&"path"][&"cell_traffic"]:
traffic[&"current_density"] = 0
if traffic[&"cell"] == origin:
traffic[&"temporary_block"] = true
_expect(
_is_true_runtime_v2_shape(legacy_data),
"legacy fixture removes every v3-v9 aggregate and dedicated history instead of relabelling v9"
)
_expect(_runtime.restore_snapshot(legacy_v2), "legacy Runtime v2 deterministically rebuilds Path actors and credits")
var migrated: Dictionary = _runtime.create_snapshot()
_expect(
int(migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 13
and migrated[&"systems"][&"runtime"][&"path"][&"actor_cells"].size() == 2
and migrated[&"systems"][&"runtime"][&"movement_credits"].size() == 2
and bool(_runtime.path_service.get_cell_traffic(origin)[&"temporary_block"]),
"legacy migration emits canonical v9 ownership while preserving blocked traffic state"
)
func _test_dispatcher_request_ownership_crosslinks() -> void:
_reset_runtime(8_107)
var stock: CommandResult = _runtime.submit_command(
&"add_inventory_stack",
{&"owner_inventory_id": &"supplier", &"item_id": &"item/ore", &"quantity": 2, &"unit_weight": 3},
&"manager", &"supplier", 10, -1, &"path.runtime.dispatch.stock"
)
_expect(stock.is_success(), "dispatcher crosslink fixture stocks weighted items")
var requested: CommandResult = _runtime.submit_command(
&"create_logistics_request",
{
&"request_id": &"ownership_request",
&"source_inventory_id": &"supplier",
&"destination_inventory_id": &"destination",
&"item_requirements": {&"item/ore": 2},
},
&"manager", &"ownership_request", 10, -1, &"path.runtime.dispatch.request"
)
_expect(requested.is_success(), "dispatcher crosslink fixture creates a reserved request")
var dispatched: CommandResult = _runtime.submit_command(
&"dispatch_logistics",
{&"carriers": {
&"carrier_a": {&"capacity": 10, &"current_load": 0, &"path_minutes": 1},
}},
&"manager", &"ownership_request", 10, -1, &"path.runtime.dispatch.assign"
)
_expect(dispatched.is_success(), "dispatcher assigns request-ID ownership")
var snapshot: Dictionary = _runtime.create_snapshot()
_expect(_runtime.restore_snapshot(snapshot), "active dispatcher ownership snapshot restores")
var ownership_tamper: Dictionary = snapshot.duplicate(true)
ownership_tamper[&"systems"][&"runtime"][&"logistics_dispatcher"][&"assignment_ownership"][0][&"carrier_id"] = "carrier_b"
var live_before: Dictionary = _runtime.create_snapshot()
_expect(
not _runtime.restore_snapshot(ownership_tamper) and _runtime.create_snapshot() == live_before,
"request-level carrier tamper is rejected despite unchanged aggregate load"
)
var coherent_dispatcher_tamper: Dictionary = snapshot.duplicate(true)
var tampered_dispatcher: Dictionary = coherent_dispatcher_tamper[&"systems"][&"runtime"][&"logistics_dispatcher"]
tampered_dispatcher[&"assignment_ownership"][0][&"carrier_id"] = "carrier_b"
tampered_dispatcher[&"carrier_loads"][0][&"carrier_id"] = "carrier_b"
tampered_dispatcher[&"assignment_history"][0][&"carrier_id"] = "carrier_b"
_expect(
not _runtime.restore_snapshot(coherent_dispatcher_tamper)
and _runtime.create_snapshot() == live_before,
"Runtime rejects internally coherent Dispatcher carrier ownership that conflicts with its request"
)
var state_tamper: Dictionary = snapshot.duplicate(true)
state_tamper[&"systems"][&"runtime"][&"logistics_requests"][0][&"state"] = "COMPLETED"
_expect(
not _runtime.restore_snapshot(state_tamper) and _runtime.create_snapshot() == live_before,
"terminal-state tamper cannot retain active Dispatcher ownership"
)
var history_tamper: Dictionary = snapshot.duplicate(true)
history_tamper[&"systems"][&"runtime"][&"logistics_dispatcher"][&"assignment_history"][0][&"weight"] = 3
_expect(
not _runtime.restore_snapshot(history_tamper) and _runtime.create_snapshot() == live_before,
"request-level history weight tamper is rejected atomically"
)
func _test_twenty_four_hour_projection_integrity() -> void:
_reset_runtime(8_108)
_expect(_register_idle_staff(&"day_guard", Vector3i(0, 0, 0)), "24-hour Staff projection registers")
_clock.advance_minutes(1_440)
var snapshot: Dictionary = _runtime.create_snapshot()
_expect(
_runtime.path_service.has_actor_projection(&"staff:day_guard")
and _runtime.path_service.get_actor_projected_cell(&"staff:day_guard") == Vector3i.ZERO,
"24-hour idle processing leaves no Path actor orphan"
)
_expect(_runtime.restore_snapshot(snapshot), "24-hour Path/credit snapshot passes strict crosslink restore")
_expect(_runtime.create_snapshot() == snapshot, "24-hour Path traffic state restores exactly")
func _spawn_moving_guest(guest_id: StringName, cell: Vector3i, target: Vector3i) -> bool:
var result: CommandResult = _runtime.submit_command(
&"spawn_guest",
{
&"guest_id": guest_id,
&"guest_type_id": &"traveler",
&"gold": 100,
&"options": {
&"current_cell": cell,
&"state": GuestRuntime.State.MOVING,
&"state_entered_at": _clock.absolute_minute - 1,
&"planned_exit_at": _clock.absolute_minute + 2_000,
&"path_handle": {&"target_cell": target},
},
},
&"world", guest_id, 10, -1, StringName("path.spawn.%s" % guest_id)
)
return result.is_success()
func _register_idle_staff(staff_id: StringName, cell: Vector3i) -> bool:
var result: CommandResult = _runtime.submit_command(
&"register_staff",
{
&"staff_id": staff_id,
&"role_id": &"worker",
&"options": {
&"state": StaffRuntime.State.AVAILABLE,
&"current_cell": cell,
&"role_tags": [&"worker"],
&"permitted_task_tags": [&"work"],
},
},
&"manager", staff_id, 10, -1, StringName("path.staff.%s" % staff_id)
)
return result.is_success()
func _guest_cells_with_prefix(prefix: String) -> Array[Vector3i]:
var cells: Array[Vector3i] = []
for guest: GuestRuntime in _runtime.guest_service.get_guests():
if String(guest.guest_id).begins_with(prefix):
cells.append(guest.current_cell)
return cells
func _has_recent_event(event_type: StringName, actor_id: StringName) -> bool:
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.event_type == event_type and actor_id in event.entity_ids:
return true
return false
func _strip_post_v2_runtime_state(runtime_data: Dictionary) -> void:
for key: StringName in POST_V2_RUNTIME_KEYS:
runtime_data.erase(key)
runtime_data.erase(String(key))
_strip_post_v2_event_history(runtime_data)
_strip_post_v2_pending_commands(runtime_data)
func _strip_post_v2_event_history(runtime_data: Dictionary) -> void:
var stream_value: Variant = runtime_data.get(&"domain_events", null)
if not stream_value is Dictionary:
return
var stream: Dictionary = stream_value
var recent_value: Variant = stream.get("recent_events", null)
var published_value: Variant = stream.get("published_ids", null)
if not recent_value is Array or not published_value is Array:
return
var removed_event_ids: Dictionary = {}
var retained_events: Array = []
for raw_event: Variant in recent_value:
if raw_event is Dictionary and StringName(
(raw_event as Dictionary).get("event_type", "")
) in POST_V2_EVENT_TYPES:
removed_event_ids[StringName((raw_event as Dictionary).get("event_id", ""))] = true
continue
retained_events.append(raw_event)
var retained_published_ids: Array = []
for raw_event_id: Variant in published_value:
if not removed_event_ids.has(StringName(raw_event_id)):
retained_published_ids.append(raw_event_id)
stream["recent_events"] = retained_events
stream["published_ids"] = retained_published_ids
func _strip_post_v2_pending_commands(runtime_data: Dictionary) -> void:
var queue_value: Variant = runtime_data.get(&"command_queue", null)
if not queue_value is Dictionary:
return
var queue: Dictionary = queue_value
var removed_command_ids: Dictionary = {}
for queue_key: String in ["pending", "in_flight"]:
var commands_value: Variant = queue.get(queue_key, null)
if not commands_value is Array:
continue
var retained_commands: Array = []
for raw_command: Variant in commands_value:
if raw_command is Dictionary and StringName(
(raw_command as Dictionary).get("command_type", "")
) in POST_V2_COMMAND_TYPES:
removed_command_ids[int((raw_command as Dictionary).get("command_id", -1))] = true
continue
retained_commands.append(raw_command)
queue[queue_key] = retained_commands
if removed_command_ids.is_empty():
return
var accepted_value: Variant = queue.get("accepted", null)
if accepted_value is Array:
var retained_accepted: Array = []
for raw_metadata: Variant in accepted_value:
if not raw_metadata is Dictionary or not removed_command_ids.has(
int((raw_metadata as Dictionary).get("command_id", -1))
):
retained_accepted.append(raw_metadata)
queue["accepted"] = retained_accepted
var idempotency_value: Variant = queue.get("idempotency", null)
if idempotency_value is Dictionary:
var idempotency: Dictionary = idempotency_value
for key: Variant in idempotency.keys():
if removed_command_ids.has(int(idempotency[key])):
idempotency.erase(key)
func _is_true_runtime_v2_shape(runtime_data: Dictionary) -> bool:
if typeof(runtime_data.get(&"runtime_schema_version", null)) != TYPE_INT \
or int(runtime_data[&"runtime_schema_version"]) != 2:
return false
for key: StringName in POST_V2_RUNTIME_KEYS:
if runtime_data.has(key) or runtime_data.has(String(key)):
return false
var stream_value: Variant = runtime_data.get(&"domain_events", null)
if not stream_value is Dictionary:
return false
var recent_value: Variant = (stream_value as Dictionary).get("recent_events", null)
if not recent_value is Array:
return false
for raw_event: Variant in recent_value:
if raw_event is Dictionary and StringName(
(raw_event as Dictionary).get("event_type", "")
) in POST_V2_EVENT_TYPES:
return false
var queue_value: Variant = runtime_data.get(&"command_queue", null)
if not queue_value is Dictionary:
return false
for queue_key: String in ["pending", "in_flight"]:
var commands_value: Variant = (queue_value as Dictionary).get(queue_key, null)
if not commands_value is Array:
return false
for raw_command: Variant in commands_value:
if raw_command is Dictionary and StringName(
(raw_command as Dictionary).get("command_type", "")
) in POST_V2_COMMAND_TYPES:
return false
var staff_value: Variant = runtime_data.get(&"staff", null)
if staff_value is Dictionary:
var payroll_value: Variant = (staff_value as Dictionary).get(
&"payroll_settlements", []
)
if payroll_value is Array and not payroll_value.is_empty():
return false
var economy_value: Variant = runtime_data.get(&"economy", null)
if economy_value is Dictionary:
var entries_value: Variant = (economy_value as Dictionary).get(&"entries", [])
if entries_value is Array:
for raw_entry: Variant in entries_value:
if raw_entry is Dictionary and StringName(
(raw_entry as Dictionary).get(&"category", "")
) == &"WAGE":
return false
return true
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
return
_failures += 1
push_error(" ✗ %s" % label)