Connect physical elevators and staff commutes to construction, saves, and cutaway UI

This commit is contained in:
Takeshi
2026-09-09 12:58:40 +09:00
parent 4d72de8973
commit 0f12c748e9
46 changed files with 3267 additions and 165 deletions
+9 -6
View File
@@ -2,6 +2,7 @@ extends SceneTree
const POST_V2_RUNTIME_KEYS := [
&"kitchen_production",
&"elevators",
&"movement_credits",
&"catalog_manifest",
&"progression",
@@ -302,11 +303,11 @@ func _test_current_snapshot_crosslinks_and_legacy_v2() -> void:
_clock.advance_one_minute()
var snapshot: Dictionary = _runtime.create_snapshot()
var runtime_data: Dictionary = snapshot[&"systems"][&"runtime"]
_expect(int(runtime_data[&"runtime_schema_version"]) == 7, "Runtime snapshot advertises schema v7")
_expect(int(runtime_data[&"runtime_schema_version"]) == 8, "Runtime snapshot advertises schema v8")
_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 v7 snapshot restores")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == digest, "mid-move v7 save/load is exact")
_expect(_runtime.restore_snapshot(snapshot), "valid mid-move v8 snapshot restores")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == digest, "mid-move v8 save/load is exact")
var corruptions: Array[Dictionary] = []
var bad_actor := snapshot.duplicate(true)
@@ -342,6 +343,8 @@ func _test_current_snapshot_crosslinks_and_legacy_v2() -> void:
var legacy_data: Dictionary = legacy_v2[&"systems"][&"runtime"]
legacy_data[&"runtime_schema_version"] = 2
_strip_post_v2_runtime_state(legacy_data)
legacy_data[&"path"][&"schema_version"] = 3
legacy_data[&"path"].erase(&"vertical_walk_blockers")
legacy_data[&"path"][&"actor_cells"] = []
legacy_data[&"path"][&"actor_progress"] = []
for traffic: Dictionary in legacy_data[&"path"][&"cell_traffic"]:
@@ -350,16 +353,16 @@ func _test_current_snapshot_crosslinks_and_legacy_v2() -> void:
traffic[&"temporary_block"] = true
_expect(
_is_true_runtime_v2_shape(legacy_data),
"legacy fixture removes every v3-v7 aggregate and dedicated history instead of relabelling v7"
"legacy fixture removes every v3-v8 aggregate and dedicated history instead of relabelling v8"
)
_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"]) == 7
int(migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 8
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 v7 ownership while preserving blocked traffic state"
"legacy migration emits canonical v8 ownership while preserving blocked traffic state"
)
+16 -3
View File
@@ -156,7 +156,7 @@ func _test_runtime_assignment_boundary() -> void:
_expect(_runtime.submit_command(&"hire_staff_candidate", {&"candidate_id": id}).is_success(), "catalog employee is hired: %s" % id)
var money_before: int = _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT)
_expect(_assign(&"staff_akane", west, &"DAY").is_success(), "new command assigns hired receptionist")
_expect(buildings[0].active_staff_ids == [&"staff_akane"] and buildings[0].state == FacilityInstance.State.OPEN, "paused assignment immediately opens the facility")
_expect(buildings[0].active_staff_ids.is_empty() and _runtime.staff_service.get_staff(&"staff_akane").state == StaffRuntime.State.COMMUTING, "paused assignment waits for the receptionist to physically arrive")
var old_cell: Vector3i = _runtime.staff_service.get_staff(&"staff_akane").current_cell
var before: Dictionary = _runtime.staff_service.create_snapshot()
for row: Array in [
@@ -174,8 +174,10 @@ func _test_runtime_assignment_boundary() -> void:
_expect(_runtime.staff_service.create_snapshot() == before, "route failure preserves the old assignment")
_runtime.path_service.set_cell_temporary_block(old_cell, false)
_clock.advance_minutes(20)
_expect(buildings[0].active_staff_ids == [&"staff_akane"] and buildings[0].state == FacilityInstance.State.OPEN, "real commute arrival opens the first reception")
old_cell = _runtime.staff_service.get_staff(&"staff_akane").current_cell
_expect(_assign(&"staff_akane", east, &"DAY").is_success(), "employee can move to another compatible facility")
_expect(buildings[0].active_staff_ids.is_empty() and buildings[1].active_staff_ids == [&"staff_akane"], "reassignment removes the old service staffing and activates the new facility")
_expect(buildings[0].active_staff_ids.is_empty() and buildings[1].active_staff_ids.is_empty(), "reassignment removes old staffing while the new commute is in progress")
_expect(_runtime.staff_service.get_staff(&"staff_akane").current_cell == old_cell, "Runtime assignment leaves Path position intact")
_expect(_runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT) == money_before, "assignment and shift changes charge no second signing fee")
var report: Dictionary = _runtime.get_staff_management_report()
@@ -206,7 +208,7 @@ func _test_runtime_assignment_boundary() -> void:
var applied: Dictionary = _runtime.staff_service.get_work_assignment(&"staff_akane")
var applied_shift: ShiftInstance = _runtime.staff_service.get_shift(_runtime.staff_service.get_staff(&"staff_akane").shift_id)
_expect(int(applied[&"changed_at"]) == queued_at + 1 and int(applied[&"effective_from"]) == queued_at + 1, "queued assignment uses the execution minute, not the previous Staff tick")
_expect(applied_shift.worked_minutes == 1, "command and AI phases record the execution minute only once")
_expect(applied_shift.worked_minutes == 0, "queued reassignment cannot record work before arriving at its new workplace")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "queued assignment leaves a coherent save at the end of its tick")
_test_active_service_reassignment(west, east)
_test_busy_staff_and_capacity(west)
@@ -214,6 +216,7 @@ func _test_runtime_assignment_boundary() -> void:
func _test_active_service_reassignment(west: StringName, east: StringName) -> void:
_expect(_assign(&"staff_akane", east, &"DAY").is_success(), "service test keeps receptionist on DAY")
_wait_for_attendance(&"staff_akane", east)
var spawned = _runtime.submit_command(&"spawn_guest", {
&"guest_id": &"reassignment_guest", &"guest_type_id": &"traveler", &"gold": 100,
&"options": {&"state": GuestRuntime.State.DECIDING, &"current_cell": Vector3i.ZERO},
@@ -236,6 +239,7 @@ func _test_active_service_reassignment(west: StringName, east: StringName) -> vo
_expect(service.state == ServiceInstance.State.WAITING_FOR_STAFF, "existing service enters the normal staff-replacement grace period")
_expect(_runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT) == balance_before, "waiting service posts no phantom revenue")
_expect(_assign(&"staff_akane", east, &"DAY").is_success(), "replacement can return during grace period")
_wait_for_attendance(&"staff_akane", east)
_clock.advance_one_minute()
_expect(service.state == ServiceInstance.State.ACTIVE, "staff return resumes the same service instead of duplicating it")
_expect(_assign(&"staff_akane", &"", &"DAY").is_success(), "employee can be unassigned during service")
@@ -247,6 +251,7 @@ func _test_active_service_reassignment(west: StringName, east: StringName) -> vo
func _test_busy_staff_and_capacity(west: StringName) -> void:
_expect(_assign(&"staff_akane", west, &"DAY").is_success(), "busy-task test starts with a working employee")
_wait_for_attendance(&"staff_akane", west)
var task = _runtime.submit_command(&"create_staff_task", {
&"task_id": &"assignment_guard_task", &"task_type": &"reception", &"priority": 99,
&"options": {&"target_cell": Vector3i.ZERO, &"required_role_tags": [&"receptionist"],
@@ -270,6 +275,14 @@ func _test_busy_staff_and_capacity(west: StringName) -> void:
_expect(_assign(&"capacity_overflow", west, &"NIGHT").is_success(), "opposite shift has its own staffing capacity")
func _wait_for_attendance(staff_id: StringName, facility_id: StringName) -> void:
for minute in range(40):
if _runtime.facility_service.get_instance(facility_id).active_staff_ids.has(staff_id):
return
_clock.advance_one_minute()
_expect(false, "employee reaches the assigned workplace through the real route")
func _assign(staff_id: StringName, facility_id: StringName, template_id: StringName) -> CommandResult:
return _runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": staff_id, &"facility_id": facility_id, &"template_id": template_id})