Files
TheTree_mock/tests/s1/test_weighted_resize_runtime.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

189 lines
18 KiB
GDScript

extends SceneTree
const Preview = preload("res://scripts/construction/facility_resize_preview.gd")
var checks := 0
var failures := 0
func expect(ok: bool, message: String) -> void:
checks += 1
if not ok: failures += 1; push_error(message)
func _initialize() -> void: call_deferred("run")
func run() -> void:
var world := WorldService.new()
world.reset({&"min_x":-10,&"max_x":10,&"min_y":-5,&"max_y":10})
var origin := Vector3i(0,-3,0)
var cells := world.cells_for_footprint(origin,Vector2i(3,2))
world.occupy(&"market",cells);world.occupy(&"heavy",[Vector3i(0,-4,0)])
world.set_support(origin,10)
for cell: Vector3i in world.cells_for_footprint(origin,Vector2i(4,2)): world.set_excavated(cell,true)
var item := {&"instance_id":&"market",&"definition_id":&"black_market",&"origin":origin,&"rotation":0,&"occupied_cells":cells}
var weights := {&"market":1,&"heavy":3}
expect(world.validate_support(cells,1,weights)[&"ok"], "original occupied structure fits exact capacity")
expect(Preview.inspect(world,item,1)[&"geometry_ok"], "generic occupant weights alone miss the overload")
var before := world.create_snapshot()
var preview := Preview.inspect(world,item,1,weights)
expect(not preview[&"geometry_ok"] and &"TARGET_UNSUPPORTED" in preview[&"errors"], "exact neighboring definition weight rejects overloaded expansion")
expect(world.create_snapshot()==before, "weighted validation does not mutate world")
expect(not world.validate_support(cells,1,{&"missing":2})[&"ok"] and not world.validate_support(cells,1,{&"heavy":-1})[&"ok"], "unknown and negative weight overrides reject")
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
clock.reset(1,6,0);state.reset();runtime.initialize(clock,state,424242);clock.set_paused(true)
var paths: Array[String] = FacilityCatalog.FACILITY_PATHS + FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS + FacilityCatalog.RESCUE_FACILITY_PATHS
paths.append("res://tests/fixtures/legacy_premium_room.tres")
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"], "fixture explicitly registers archived legacy-size definition")
expect(runtime.submit_command(&"build_facility",{&"definition_id":&"reception",&"origin":Vector3i(-6,0,0)}).is_success(), "build supporting reception at ground level")
clock.advance_minutes(120)
var built: CommandResult = runtime.submit_command(&"build_facility",{&"definition_id":&"premium_room",&"origin":Vector3i(-6,2,0)})
expect(built.is_success(), "build above-ground old-size room: " + built.message)
if not built.is_success():
runtime.free();clock.free();state.free();quit(failures);return
var active_id: StringName = &""
for job: ConstructionJob in runtime.construction_service.get_jobs():
if job.definition_id == &"premium_room" and not job.is_terminal(): active_id = job.job_id
paths.erase("res://tests/fixtures/legacy_premium_room.tres")
paths.append("res://data/facilities/expansion/premium_room.tres")
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"], "current original-size registry replaces legacy fixture after reservation")
clock.advance_minutes(7)
var active_before: Dictionary = runtime.create_snapshot()
var original_job: Dictionary = runtime.construction_service.get_job(active_id).create_snapshot()
var active_path := "user://saves/active_resize_%d" % Time.get_ticks_usec()
expect(SaveService.save_snapshot(active_path,active_before)[&"ok"], "save partially built legacy job")
var active_migration: Dictionary=runtime.migrate_facility_dimensions_at_path(active_path)
expect(active_migration[&"ok"] and active_migration.get(&"backup_created",false), "batch migrates partial job with verified backup")
var migrated_job_save := SaveService.load_snapshot(active_path)
expect(migrated_job_save[&"ok"] and runtime.restore_snapshot(migrated_job_save[&"snapshot"]), "full Runtime restores migrated construction reservation")
var current_job: ConstructionJob=runtime.construction_service.get_job(active_id)
expect(current_job.reserved_cells.size()==4 and current_job.progress==original_job[&"progress"] and current_job.construction_cost==original_job[&"construction_cost"], "full Runtime migration preserves job progress and paid cost")
clock.advance_minutes(150)
var finished_job: ConstructionJob=runtime.construction_service.get_job(active_id)
expect(finished_job.state==ConstructionJob.State.COMPLETED and runtime.facility_service.get_instance(finished_job.facility_instance_id).occupied_cells.size()==4, "migrated partial job completes as original-size operational room")
expect(runtime.restore_snapshot(runtime.create_snapshot()), "completion after full job migration remains saveable")
expect(SaveService.load_snapshot(active_path+SaveService.MIGRATION_BACKUP_SUFFIX)[&"snapshot"]==active_before and runtime.restore_snapshot(active_before), "original job backup remains intact and legacy fixture can resume")
SaveService.delete_save(active_path);SaveService.delete_save(active_path+SaveService.MIGRATION_BACKUP_SUFFIX)
var candidate := Preview.prepare_construction_candidate(runtime.world_service, runtime.construction_service, active_id, 2)
expect(candidate[&"ok"] and not candidate[&"ready_to_apply"], "active construction has a validated candidate, not a Runtime commit")
if candidate[&"ok"]:
var active_row: Dictionary = {}
for row: Dictionary in candidate[&"construction"][&"jobs"]:
if StringName(row[&"job_id"]) == active_id: active_row = row
expect(active_row[&"reserved_cells"].size() == 4 and active_row[&"progress"] == original_job[&"progress"] and active_row[&"progress"] > 0, "partially built job converts without advancing paid work")
var resumed_world := WorldService.new()
expect(resumed_world.restore_snapshot(candidate[&"world"]), "candidate world restores for partial-job continuation")
var resumed := ConstructionService.new(resumed_world)
expect(resumed.restore_snapshot(candidate[&"construction"]), "partial job restores through production validator")
var job_before := resumed.get_job(active_id).create_snapshot()
var replay := resumed.progress_job(active_id, ConstructionJob.NORMAL_WORK_RATE, resumed.current_minute)
expect(replay.is_success() and replay.is_replay and resumed.get_job(active_id).create_snapshot() == job_before, "last saved construction minute is not charged as work twice")
var completion_count := [0]
resumed.facility_completed.connect(func(_facility: Dictionary): completion_count[0] += 1)
for minute in range(resumed.current_minute + 1, resumed.current_minute + 201): resumed.advance_one_minute(minute)
var finished := resumed.get_job(active_id)
expect(finished.state == ConstructionJob.State.COMPLETED and completion_count[0] == 1, "resized partial job completes exactly once")
var finished_room := resumed.get_facility(finished.facility_instance_id)
expect(finished_room[&"occupied_cells"].size() == 4 and resumed_world.get_entity_cells(finished.facility_instance_id) == finished_room[&"occupied_cells"], "completion occupies original-spec footprint with new facility ownership")
expect(finished.construction_cost == original_job[&"construction_cost"] and finished.build_minutes == original_job[&"build_minutes"] and finished.started_at == original_job[&"started_at"], "migration and completion retain paid cost, duration and start time")
var completed_restore := ConstructionService.new(resumed_world)
expect(completed_restore.restore_snapshot(resumed.create_snapshot()), "completed migrated source job and facility remain save-compatible")
expect(runtime.create_snapshot() == active_before, "active candidate leaves source world, jobs and money unchanged")
clock.advance_minutes(150)
var id: StringName = &""
for facility: Dictionary in runtime.construction_service.get_facilities():
if facility[&"definition_id"] == &"premium_room": id = facility[&"instance_id"]
expect(not id.is_empty(), "above-ground expansion completes")
if id.is_empty():
runtime.free();clock.free();state.free();quit(failures);return
var full_before: Dictionary = runtime.create_snapshot()
var disk_path := "user://saves/resize_disk_%d" % Time.get_ticks_usec()
expect(SaveService.save_snapshot(disk_path, full_before)[&"ok"], "write isolated legacy-size disk fixture")
var disk_migration: Dictionary = runtime.migrate_facility_dimensions_at_path(disk_path, id)
expect(disk_migration[&"ok"] and disk_migration.get(&"backup_created",false), "disk migration verifies candidate and creates backup before promotion")
var disk_loaded := SaveService.load_snapshot(disk_path)
var disk_backup := SaveService.load_snapshot(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX)
expect(disk_backup[&"ok"] and disk_backup[&"snapshot"] == full_before, "pre-migration disk backup retains original full snapshot")
var backup_bytes := FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin"))
expect(runtime.migrate_facility_dimensions_at_path(disk_path,id)[&"ok"] and FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin")) == backup_bytes, "repeated migration preserves original backup")
var alternate: Dictionary = full_before.duplicate(true)
alternate[&"clock"][&"absolute_minute"] += 1
var stale := SaveService.replace_snapshot_with_backup(disk_path, full_before, alternate)
expect(not stale[&"ok"] and stale[&"code"] == &"MIGRATION_SOURCE_CHANGED" and SaveService.load_snapshot(disk_path)[&"snapshot"] == disk_loaded[&"snapshot"], "stale source rejects before overwriting migrated save")
var rejected_invalid := SaveService.replace_snapshot_with_backup(disk_path, disk_loaded[&"snapshot"], {&"invalid":true})
expect(not rejected_invalid[&"ok"] and rejected_invalid[&"code"] == &"MIGRATION_INVALID_SNAPSHOT" and SaveService.load_snapshot(disk_path)[&"snapshot"] == disk_loaded[&"snapshot"], "invalid candidate preserves formal package")
expect(FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin")) == backup_bytes, "failed migration preserves original backup bytes")
expect(runtime.create_snapshot() == full_before, "disk migration does not alter live Runtime")
var full_candidate: Dictionary = runtime.prepare_facility_dimension_snapshot(id)
expect(full_candidate[&"ok"] and runtime.create_snapshot() == full_before, "full snapshot candidate preserves live Runtime")
var isolated: Variant = load("res://autoload/simulation_runtime.gd").new()
var isolated_clock: Variant = load("res://autoload/game_clock.gd").new()
var isolated_state: Variant = load("res://autoload/game_state.gd").new()
isolated_clock.reset(1,6,0);isolated_state.reset();isolated.initialize(isolated_clock,isolated_state,424242)
isolated.definition_registry.rebuild_from_paths(paths)
expect(isolated.restore_snapshot(full_candidate[&"snapshot"]), "full migrated snapshot passes Runtime crosslinks in isolated instance")
expect(isolated.restore_snapshot(disk_loaded[&"snapshot"]) and isolated.facility_service.get_instance(id).occupied_cells.size() == 4, "migrated disk package restores original footprint in separate Runtime")
SaveService.delete_save(disk_path)
SaveService.delete_save(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX)
expect(isolated.facility_service.get_instance(id).occupied_cells.size() == 4, "operating facility restores original-spec footprint")
var route_report := preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
expect(route_report[&"ok"] and route_report[&"checked_routes"] == 1, "isolated Runtime route comparison preserves existing entrance reachability")
# Controlled topology fixture for the route comparator, separate from the
# valid full-snapshot acceptance above. Upper-floor-only access is lost.
var old_graph: Array[Vector3i] = [Vector3i(-9,3,0), Vector3i(-8,3,0), Vector3i(-7,3,0)]
runtime.path_service.rebuild_graph(old_graph); isolated.path_service.rebuild_graph(old_graph)
var guest_type: StringName = runtime.get_mvp_guest_definition_ids()[0]
var observer := GuestRuntime.new().configure(&"route_observer", guest_type, {&"current_cell":old_graph[0], &"state":GuestRuntime.State.MOVING, &"target_facility_id":id, &"path_handle":{&"target_cell":old_graph[-1]}})
expect(runtime.guest_service.register_guest(observer, false) and isolated.guest_service.register_guest(GuestRuntime.from_snapshot(observer.create_snapshot()), false), "route fixture registers matching moving guests")
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
expect(not route_report[&"ok"] and route_report[&"errors"].any(func(error: Variant): return error is Dictionary and error[&"code"] == &"GUEST_ACCESS_LOST"), "shrinking upper row detects loss of guest access even with unchanged path graph")
# A replacement lower access remains reachable, but saved target needs update.
old_graph.append_array([Vector3i(-9,2,0),Vector3i(-8,2,0),Vector3i(-7,2,0)])
runtime.path_service.rebuild_graph(old_graph);isolated.path_service.rebuild_graph(old_graph)
expect(runtime.path_service.add_connector(&"resize_stair",Vector3i(-9,3,0),Vector3i(-9,2,0)) and isolated.path_service.add_connector(&"resize_stair",Vector3i(-9,3,0),Vector3i(-9,2,0)), "fixture explicitly connects floors through a vertical connector")
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
expect(route_report[&"errors"].is_empty() and route_report[&"guest_replans"].size() == 1 and not route_report[&"ok"], "reachable replacement still requires explicit moving-guest retargeting")
var source_guest: Dictionary = runtime.guest_service.get_guest(&"route_observer").create_snapshot()
var candidate_guest: Dictionary = isolated.guest_service.get_guest(&"route_observer").create_snapshot()
var invalid_batch: Dictionary = route_report.duplicate(true)
invalid_batch[&"guest_replans"].append({&"id":&"missing", &"old_target":Vector3i.ZERO, &"target":Vector3i.ZERO})
var rejected := preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, invalid_batch)
expect(not rejected[&"ok"] and isolated.guest_service.get_guest(&"route_observer").create_snapshot() == candidate_guest, "invalid later replan leaves earlier guest unchanged")
var applied := preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, route_report)
expect(applied[&"ok"] and applied[&"changed"] == [&"route_observer"], "retarget batch applies reachable entrance to isolated guest")
var after_guest: Dictionary = isolated.guest_service.get_guest(&"route_observer").create_snapshot()
after_guest[&"path_handle"] = candidate_guest[&"path_handle"]
expect(after_guest == candidate_guest and runtime.guest_service.get_guest(&"route_observer").create_snapshot() == source_guest, "retarget preserves position, wallet, service state and source guest")
expect(not preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, route_report)[&"ok"], "stale original destination cannot overwrite an already updated route")
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
expect(route_report[&"ok"], "corrected moving target passes route comparison")
var moving: GuestRuntime = isolated.guest_service.get_guest(&"route_observer")
var actor_id: StringName = isolated._guest_path_actor_id(moving.guest_id)
expect(isolated.path_service.project_actor_position(actor_id, moving.current_cell, isolated_clock.absolute_minute), "project candidate guest for actual movement")
for offset in range(1, 21):
isolated._advance_guest_path_travel(moving, actor_id, isolated_clock.absolute_minute + offset)
if moving.current_cell.y == 2: break
expect(moving.current_cell == Vector3i(-9,2,0), "production movement follows retargeted lower entrance instead of old upper entrance")
expect(runtime.restore_snapshot(full_before), "restore valid source after controlled topology fixture")
isolated.free();isolated_clock.free();isolated_state.free()
expect(runtime.submit_command(&"register_staff",{&"staff_id":&"resize_observer",&"role_id":&"clerk",&"options":{&"current_cell":Vector3i.ZERO}}).is_success(), "register diagnostic worker on an existing corridor")
# Diagnostic legacy-position input only; no claim of normal navigation to an
# upper decorative cell. Preview must report it, never relocate it silently.
runtime.staff_service.get_staff(&"resize_observer").current_cell = Vector3i(-6,3,0)
expect(not runtime.prepare_facility_dimension_snapshot(id)[&"ok"], "removed-cell actor requires explicit relocation before preparing full snapshot")
var completed_before: Dictionary = runtime.create_snapshot()
candidate = Preview.prepare_construction_candidate(runtime.world_service, runtime.construction_service, id, 2)
expect(candidate[&"ok"], "completed facility and source job migrate together")
if candidate[&"ok"]:
var migrated_world := WorldService.new()
migrated_world.restore_snapshot(candidate[&"world"])
var migrated := ConstructionService.new(migrated_world)
expect(migrated.restore_snapshot(candidate[&"construction"]) and migrated.get_facility(id)[&"occupied_cells"].size() == 4, "candidate restores under production construction crosslink validation")
var retry := Preview.prepare_construction_candidate(migrated_world, migrated, id, 2)
expect(retry[&"ok"] and retry[&"construction"] == candidate[&"construction"] and retry[&"world"] == candidate[&"world"], "already migrated candidate is idempotent")
expect(runtime.create_snapshot() == completed_before, "completed candidate leaves source state untouched")
var snapshot: Dictionary = runtime.create_snapshot()
preview=runtime.preview_facility_dimension_migration(id)
expect(preview[&"construction_candidate"][&"ok"], "Runtime preview exposes validated construction candidate")
expect(preview[&"target_cells"].size()==4 and preview[&"definition_weights"][id]==2, "Runtime preview uses original dimension and live definition weight")
expect(preview[&"actors_on_removed_cells"].size()==1 and preview[&"actors_on_removed_cells"][0][&"id"]==&"resize_observer", "Runtime preview identifies actual worker requiring relocation")
expect(not preview[&"ready_to_apply"] and runtime.create_snapshot()==snapshot, "Runtime preview preserves all authoritative simulation state")
expect(not runtime.preview_facility_dimension_migration(&"missing")[&"ready_to_apply"], "unknown completed facility rejected")
runtime.free();clock.free();state.free()
print("Weighted resize Runtime: %d checks, %d failures" % [checks,failures]);quit(failures)