Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
147 lines
10 KiB
GDScript
147 lines
10 KiB
GDScript
extends SceneTree
|
|
const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd")
|
|
var checks:=0
|
|
var failures:=0
|
|
var runtime: Variant
|
|
var clock: Variant
|
|
func expect(ok: bool,label: String)->void:
|
|
checks+=1
|
|
if not ok:failures+=1;push_error(label)
|
|
func _initialize()->void:call_deferred("run")
|
|
func active_job(id: StringName)->StaffTask:
|
|
for task: StaffTask in runtime.staff_service.get_tasks():
|
|
if task.task_type==&"facility_clean" and task.target_entity_id==id and not task.is_terminal():return task
|
|
return null
|
|
func cleaner_id() -> StringName: return &"staff_eri"
|
|
func work_ticks() -> int: return 8
|
|
func hire_cleaner(main: Control) -> void:
|
|
main.staff_candidate_buttons[cleaner_id()].pressed.emit()
|
|
func run()->void:
|
|
runtime=root.get_node("SimulationRuntime");clock=root.get_node("GameClock")
|
|
var state: Variant=root.get_node("GameState")
|
|
clock.reset(1,6,0);state.reset()
|
|
expect(runtime.initialize(clock,state,42631)[&"valid"],"initialize normal cleaning catalog")
|
|
clock.set_paused(true)
|
|
var main: Control=load("res://scenes/main/main.tscn").instantiate();root.add_child(main)
|
|
runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false})
|
|
await process_frame;await process_frame
|
|
expect(main.MVP_FACILITY_IDS.has(&"cleaning_room"),"normal palette contains cleaning room")
|
|
for build: Array in [[&"cleaning_room",Vector3i(-6,0,1)],[&"reception",Vector3i(1,0,0)]]:
|
|
main.call("_select_build_definition",build[0]);main.call("_on_map_cell_clicked",build[1]);clock.advance_minutes(runtime.definition_registry.get_facility(build[0]).build_minutes)
|
|
var room: FacilityInstance
|
|
var reception: FacilityInstance
|
|
for facility: FacilityInstance in runtime.facility_service.get_instances():
|
|
if facility.definition_id==&"cleaning_room":room=facility
|
|
if facility.definition_id==&"reception":reception=facility
|
|
expect(room!=null and reception!=null,"normal UI builds both completed facilities")
|
|
if room==null or reception==null:
|
|
var early_room_cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main)
|
|
if not bool(early_room_cleanup.get(&"passed", false)):
|
|
push_error("Cleaning ordinary owner cleanup failed: %s" % str(early_room_cleanup))
|
|
quit(97)
|
|
return
|
|
quit(failures);return
|
|
var preview: WorldPreview=main.world_preview
|
|
var room_id:=room.instance_id
|
|
var id:=reception.instance_id
|
|
expect(room.customer_capacity==0 and room.state==FacilityInstance.State.NO_STAFF,"cleaning room excludes customers and waits for cleaner")
|
|
var panel: StaffManagementPanel=main.find_child("StaffManagementPanel",true,false)
|
|
for assignment: Array in [[cleaner_id(),room_id],[&"staff_akane",id]]:
|
|
if assignment[0]==cleaner_id(): hire_cleaner(main)
|
|
else: main.staff_candidate_buttons[assignment[0]].pressed.emit()
|
|
panel.refresh();panel.select_staff(assignment[0])
|
|
for i in panel.facility_option.item_count:
|
|
if panel.facility_option.get_item_metadata(i)==assignment[1]:panel.facility_option.select(i);panel.facility_option.item_selected.emit(i)
|
|
panel.apply_button.pressed.emit()
|
|
clock.advance_minutes(30)
|
|
expect(room.operation_state==FacilityInstance.OperationState.OPERATING and reception.operation_state==FacilityInstance.OperationState.OPERATING,"actual cleaner and receptionist commute to assigned workplaces")
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()),"staffed cleaning room save/load")
|
|
expect(preview._staff_work_animation(runtime.staff_service.get_staff(cleaner_id()))==&"idle","cleaner at staffed base does not mime cleaning")
|
|
var count:=0
|
|
for batch in 4:
|
|
var size:=8 if batch<3 else 1
|
|
for index in size:
|
|
var guest:=StringName("cleaning_payer_%d"%count)
|
|
expect(runtime.submit_command(&"register_guest_wallet",{&"guest_id":guest,&"gold":100}).is_success(),"fund controlled visit")
|
|
expect(runtime.submit_command(&"create_service_request",{&"request_id":StringName("cleaning_visit_%d"%count),&"facility_id":id,&"guest_ids":[guest],&"service_type":&"check_in"}).is_success(),"request real reception service")
|
|
count+=1
|
|
for minute in 25:
|
|
clock.advance_one_minute()
|
|
if int(runtime.facility_cleanliness.get_facility(id)["current"])==100-count:break
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]==75,"25 completed defined visits reach cleaning threshold")
|
|
var task:=active_job(id)
|
|
expect(task!=null,"threshold schedules an actual staff task")
|
|
if task==null:
|
|
var early_task_cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main)
|
|
if not bool(early_task_cleanup.get(&"passed", false)):
|
|
push_error("Cleaning ordinary owner cleanup failed: %s" % str(early_task_cleanup))
|
|
quit(97)
|
|
return
|
|
quit(failures);return
|
|
var task_id:=task.task_id
|
|
var walking_seen:=false
|
|
for minute in 80:
|
|
clock.advance_one_minute();task=runtime.staff_service.get_task(task_id)
|
|
if task.state==StaffTask.State.MOVING:
|
|
walking_seen=true
|
|
expect(preview._staff_work_animation(runtime.staff_service.get_staff(cleaner_id()))!=&"clean","moving cleaner does not mop before arrival")
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]==75,"walking does not clean")
|
|
if task.state==StaffTask.State.WORKING:break
|
|
expect(walking_seen and task.state==StaffTask.State.WORKING,"assigned cleaner physically reaches work site")
|
|
var worker: StaffRuntime=runtime.staff_service.get_staff(cleaner_id())
|
|
expect(worker.current_cell==task.target_cell and task.progress_minutes==0,"arrival starts work with zero elapsed minutes")
|
|
expect(runtime.facility_service.get_instance(room_id).operation_state==FacilityInstance.OperationState.OPERATING,"deployed cleaner continues staffing cleaning room")
|
|
if work_ticks() < 8:
|
|
expect(runtime.cleaning_bridge.status(id).contains("3倍速・残り3分"),"cleaning UI describes real remaining time at triple rate")
|
|
var working: Dictionary=runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(working),"cleaner away from room and working task restore together")
|
|
expect(preview._staff_work_animation(runtime.staff_service.get_staff(cleaner_id()))==&"clean","restored on-site active task selects mop animation")
|
|
expect(not runtime.submit_command(&"progress_staff_task",{&"task_id":task_id,&"minutes":8}).is_success(),"manual progress cannot bypass actual work time")
|
|
# Save this command receipt too, so both replay paths have identical command history.
|
|
working=runtime.create_snapshot()
|
|
clock.advance_minutes(work_ticks()-1)
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]==75 and runtime.staff_service.get_task(task_id).progress_minutes==(work_ticks()-1)*FacilityCleaningBridge.work_units_per_minute(runtime.staff_service.get_staff(cleaner_id())),"work before final tick is insufficient")
|
|
clock.advance_one_minute()
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]==100 and runtime.staff_service.get_task(task_id).state==StaffTask.State.COMPLETED,"final tick completes one25-point recovery")
|
|
expect(preview._staff_work_animation(runtime.staff_service.get_staff(cleaner_id()))!=&"clean","completed job stops mop animation")
|
|
var finished: Dictionary=runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(working),"rewind actual cleaning work")
|
|
clock.advance_minutes(work_ticks())
|
|
expect(runtime.create_snapshot()==finished,"cleaning replay matches all Runtime state")
|
|
# Stop an in-progress job through normal business controls. No partial recovery.
|
|
expect(runtime.restore_snapshot(working),"rewind for closed cleaning room")
|
|
clock.advance_minutes(work_ticks()-1)
|
|
expect(runtime.submit_command(&"set_facility_policy",{&"facility_id":room_id,&"patch":{&"business_open":false}}).is_success(),"close cleaning room through business policy")
|
|
clock.advance_minutes(10)
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]<=75 and runtime.staff_service.get_task(task_id).state==StaffTask.State.CANCELLED,"closed source cancels partial work without recovery")
|
|
expect(preview._staff_work_animation(runtime.staff_service.get_staff(cleaner_id()))!=&"clean","closed base cancels visible cleaning")
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()),"cancelled work plus waiting replacement job restore")
|
|
expect(runtime.restore_snapshot(working),"rewind for power interruption")
|
|
clock.advance_minutes(work_ticks()-1)
|
|
state.set_resource(&"mana",0);clock.advance_minutes(10)
|
|
expect(runtime.facility_cleanliness.get_facility(id)["current"]<=75 and runtime.staff_service.get_task(task_id).state==StaffTask.State.CANCELLED,"power loss stops cleaning without recovery")
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()),"unpowered cleaning checkpoint restores")
|
|
expect(runtime.restore_snapshot(finished),"completed cleaning receipt restores")
|
|
clock.advance_minutes(5)
|
|
var cleaning_receipts:=0
|
|
for receipt: Dictionary in runtime.facility_cleanliness.create_snapshot()["receipts"]:
|
|
if receipt["kind"]=="clean" and StringName(receipt["source_id"])==task_id:cleaning_receipts+=1
|
|
expect(cleaning_receipts==1 and active_job(id)==null,"completion is not repeated; later normal guest visits may soil again")
|
|
main.navigation_buttons[&"business"].pressed.emit()
|
|
var business: BusinessManagementPanel=main.find_child("BusinessManagementPanel",true,false);business.refresh()
|
|
for i in business.facility_option.item_count:
|
|
if business.facility_option.get_item_metadata(i)==id:business.facility_option.select(i);business.facility_option.item_selected.emit(i)
|
|
expect(business.facility_status_label.text.contains("清潔度 %d / 100" % runtime.facility_cleanliness.get_facility(id)["current"]),"normal business UI shows actual cleanliness")
|
|
business.select_facility(room_id)
|
|
expect(business.business_open_button.text=="清掃業務を有効にする" and business.facility_status_label.text.contains("顧客利用なし") and not business.effect_label.text.contains("受付"),"cleaning room controls describe staff work rather than customer reception")
|
|
if OS.get_environment("THE_TREE_CLEANING_CAPTURE")=="1":
|
|
root.size=Vector2i(1280,720)
|
|
await process_frame;await process_frame;await RenderingServer.frame_post_draw
|
|
expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path("res://artifacts/cleanliness-runtime-2026-09-29/cleaning-gameplay.png"))==OK,"capture actual cleaning UI")
|
|
var cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main)
|
|
if not bool(cleanup.get(&"passed", false)):
|
|
push_error("Cleaning ordinary owner cleanup failed: %s" % str(cleanup))
|
|
quit(97)
|
|
return
|
|
print("Cleaning gameplay: %d checks, %d failures"%[checks,failures]);quit(failures)
|