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)