348 lines
22 KiB
GDScript
348 lines
22 KiB
GDScript
extends SceneTree
|
|
|
|
## Real construction, hired porter and purchased stock; failure injection is
|
|
## limited to route closures, capacity pressure and expired cargo.
|
|
var _checks := 0
|
|
var _failures := 0
|
|
var _runtime: Variant
|
|
var _clock: Variant
|
|
var _state: Variant
|
|
var _source: StringName
|
|
var _destination: StringName
|
|
var _loaded: Dictionary
|
|
var _reserved: Dictionary
|
|
const REQUEST := &"supply.bridge_test"
|
|
const PORTER := &"staff_gina"
|
|
|
|
|
|
class LateFailInventory extends InventoryService:
|
|
var fail_delivery := true
|
|
|
|
func transfer_available(source_inventory_id: StringName, destination_inventory_id: StringName,
|
|
item_id: StringName, quantity: int, operation_id: StringName = &"", absolute_minute: int = -1) -> Dictionary:
|
|
var result := super.transfer_available(source_inventory_id, destination_inventory_id, item_id, quantity, operation_id, absolute_minute)
|
|
if fail_delivery and String(source_inventory_id).begins_with("cargo:") and result[&"ok"]:
|
|
return {&"ok": false, &"code": &"INJECTED_LATE_FAILURE"}
|
|
return result
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
|
|
func _run() -> void:
|
|
print("Supply bridge: real movement, cargo conservation and recovery")
|
|
_runtime = root.get_node("SimulationRuntime")
|
|
_clock = root.get_node("GameClock")
|
|
_state = root.get_node("GameState")
|
|
_clock.reset(1, 6, 0)
|
|
_state.reset()
|
|
_expect(_runtime.initialize(_clock, _state, 653322)[&"valid"], "Runtime initializes")
|
|
_clock.set_paused(true)
|
|
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
|
for row: Array in [[&"warehouse", Vector3i(-8, 0, 1)], [&"kitchen", Vector3i(2, 0, 1)], [&"staff_door", Vector3i(0, 0, 1)]]:
|
|
_expect(_command(&"build_facility", {&"definition_id": row[0], &"origin": row[1]}), "build %s" % row[0])
|
|
_clock.advance_minutes(180)
|
|
for facility: FacilityInstance in _runtime.facility_service.get_instances():
|
|
if facility.definition_id == &"warehouse": _source = facility.instance_id
|
|
if facility.definition_id == &"kitchen": _destination = facility.instance_id
|
|
if _source.is_empty() or _destination.is_empty():
|
|
_expect(false, "normal construction completes")
|
|
_finish()
|
|
return
|
|
_expect(_command(&"hire_staff_candidate", {&"candidate_id": PORTER}), "hire the catalogue porter")
|
|
_expect(_command(&"set_staff_work_assignment", {&"staff_id": PORTER, &"facility_id": _source, &"template_id": &"DAY"}), "assign porter to a repeating real shift")
|
|
_expect(_command(&"purchase_supplies", {&"warehouse_id": _source, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 8}), "purchase the source stock through the ledger")
|
|
_expect(_command(&"create_logistics_request", {&"request_id": REQUEST, &"source_inventory_id": _inventory(_source), &"destination_inventory_id": _inventory(_destination), &"item_requirements": {SupplyCatalog.RAW_FOOD: 8}}), "create the reserved supply request")
|
|
_expect(_quantity(_inventory(_destination)) == 0, "request creation does not deliver anything")
|
|
_test_manual_dispatch_boundary()
|
|
_reserved = _runtime.create_snapshot()
|
|
_clock.advance_minutes(1)
|
|
_expect(_request().assigned_carrier_id == PORTER and _worker().current_cell.distance_to(Vector3i.ZERO) <= 1.0, "dispatcher selects the actual employee without teleporting")
|
|
var start := _worker().current_cell
|
|
_wait_for(LogisticsRequest.State.DELIVERING, 40)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _worker().current_cell != start, "porter walks to the source before pickup")
|
|
if _request().state != LogisticsRequest.State.DELIVERING:
|
|
_finish()
|
|
return
|
|
_expect(_quantity(_inventory(_source)) == 0 and _quantity(_cargo()) == 8 and _quantity(_inventory(_destination)) == 0, "pickup moves all eight units into owned cargo only")
|
|
_expect(_crosslinks(), "loaded Request, Task, reservations and cargo agree")
|
|
_loaded = _runtime.create_snapshot()
|
|
_expect(_runtime.restore_snapshot(_loaded), "mid-delivery Runtime snapshot restores")
|
|
_test_ownership_and_replay()
|
|
_test_capacity_wait()
|
|
_test_route_recovery()
|
|
_test_unavailable_and_expiry()
|
|
_test_restore_guards()
|
|
_test_pickup_retry()
|
|
_test_source_closes_after_assignment()
|
|
_test_source_closes_after_loading()
|
|
_test_unavailable_before_pickup()
|
|
_test_partial_expiry_return()
|
|
_test_shift_boundary()
|
|
_test_late_delivery_failure()
|
|
_finish()
|
|
|
|
|
|
func _test_ownership_and_replay() -> void:
|
|
var owned := _owned_snapshot()
|
|
var manual: CommandResult = _runtime.submit_command(&"advance_logistics_request", {&"request_id": REQUEST})
|
|
_expect(not manual.is_success() and manual.details.get(&"reason") == &"SUPPLY_DRIVER_REQUIRED", "external advance cannot bypass real arrival")
|
|
_expect(_owned_snapshot() == owned, "rejected manual advance leaves inventory, Task and carrier ownership unchanged")
|
|
_expect(_runtime.restore_snapshot(_loaded), "rewind the rejected command audit before deterministic replay")
|
|
var task_id := _worker().current_task_id
|
|
_expect(not _runtime.staff_service.cancel_task(task_id).is_success(), "ordinary cancellation cannot orphan loaded cargo")
|
|
_expect(not _runtime.staff_service.remove_staff(PORTER).is_success(), "loaded porter cannot be removed")
|
|
_expect(not _runtime.staff_service.retire_staff(PORTER).is_success() and not _worker().is_retiring, "retirement rejects atomically while hauling")
|
|
_expect(not _runtime.staff_service.progress_task(task_id, 1, _clock.absolute_minute + 2).is_success(), "generic Task progress cannot bypass delivery")
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED and _quantity(_inventory(_destination)) == 8, "arrival transfers the purchased stock into kitchen storage")
|
|
_expect(_quantity(_cargo()) == 0 and _worker().current_task_id.is_empty() and _worker().carried_inventory_id.is_empty(), "completion clears cargo and employee ownership together")
|
|
_expect(_runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "completion releases exact dispatcher weight")
|
|
var completed: Dictionary = _runtime.create_snapshot()
|
|
var end_minute: int = _clock.absolute_minute
|
|
_expect(_runtime.restore_snapshot(_loaded), "rewind to a loaded employee")
|
|
_clock.advance_minutes(end_minute - _clock.absolute_minute)
|
|
_expect(_runtime.create_snapshot() == completed, "loaded save replay produces identical inventory, Tasks, positions and accounts")
|
|
|
|
|
|
func _test_manual_dispatch_boundary() -> void:
|
|
var owned := _owned_snapshot()
|
|
var manual: CommandResult = _runtime.submit_command(&"dispatch_logistics", {&"carriers": {&"synthetic_porter": {&"capacity": 100, &"current_load": 0, &"path_minutes": 0, &"role": &"logistics"}}})
|
|
_expect(manual.is_success() and manual.details[&"assignments"].is_empty(), "external synthetic carrier cannot claim a managed supply request")
|
|
_expect(_owned_snapshot() == owned, "manual dispatch does not change reserved stock, Staff Task or request ownership")
|
|
|
|
|
|
func _owned_snapshot() -> Dictionary:
|
|
return {&"inventory": _runtime.inventory_service.create_snapshot(), &"staff": _runtime.staff_service.create_snapshot(), &"dispatcher": _runtime.logistics_dispatcher.create_snapshot(), &"request": _request().create_snapshot()}
|
|
|
|
|
|
func _test_capacity_wait() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore capacity scenario")
|
|
_runtime.inventory_service.add_stack(_inventory(_destination), SupplyCatalog.BASIC_MEAL, 40, 100, -1, _clock.absolute_minute)
|
|
_clock.advance_minutes(30)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _request().state_reason == "DESTINATION_FULL", "capacity becoming full after pickup pauses delivery")
|
|
_expect(_quantity(_cargo()) == 8 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 8, "full destination retains all cargo and weight ownership")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "waiting loaded cargo is restorable")
|
|
_runtime.inventory_service.transfer_available(_inventory(_destination), &"test.capacity_sink", SupplyCatalog.BASIC_MEAL, 40, &"", _clock.absolute_minute)
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 10)
|
|
_expect(_quantity(_inventory(_destination)) == 8 and _quantity(_cargo()) == 0, "freeing storage resumes once without losing or duplicating stock")
|
|
|
|
|
|
func _test_route_recovery() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore route scenario")
|
|
var target := _task().target_cell
|
|
_runtime.path_service.set_cell_temporary_block(target, true)
|
|
_clock.advance_minutes(40)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _quantity(_cargo()) == 8, "blocked delivery route never releases carried stock")
|
|
_expect(_worker().current_task_id == _task().task_id and _crosslinks(), "stuck recovery keeps employee and Task linked")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "route-blocked cargo saves and restores")
|
|
_runtime.path_service.set_cell_temporary_block(target, false)
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED and _quantity(_inventory(_destination)) == 8, "restoring the real route resumes delivery")
|
|
|
|
|
|
func _test_unavailable_and_expiry() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore unavailable scenario")
|
|
_worker().health = 0
|
|
_worker().transition_to(StaffRuntime.State.INCAPACITATED, &"TEST", _clock.absolute_minute)
|
|
var cell := _worker().current_cell
|
|
_clock.advance_minutes(3)
|
|
_expect(_worker().current_cell == cell and _quantity(_cargo()) == 8, "incapacitated porter does not move or lose cargo")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "incapacitated cargo owner is restorable")
|
|
_worker().health = 100
|
|
_worker().transition_to(StaffRuntime.State.MOVING_TO_TASK, &"TEST_RECOVERED", _clock.absolute_minute)
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED, "employee recovery resumes the retained delivery")
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore spoilage scenario")
|
|
_worker().health = 0
|
|
_worker().transition_to(StaffRuntime.State.INCAPACITATED, &"TEST", _clock.absolute_minute)
|
|
var inventory_snapshot: Dictionary = _runtime.inventory_service.create_snapshot()
|
|
for owner: Dictionary in inventory_snapshot[&"inventories"]:
|
|
if owner[&"owner_inventory_id"] == String(_cargo()):
|
|
for stack: Dictionary in owner[&"stacks"]:
|
|
stack[&"expires_at"] = _clock.absolute_minute + 1
|
|
_expect(_runtime.inventory_service.restore_snapshot(inventory_snapshot), "inject a cargo expiry boundary")
|
|
_clock.advance_minutes(1)
|
|
_expect(_request().state == LogisticsRequest.State.CANCELLED and _quantity(_cargo()) == 0, "expired cargo enters inventory waste and closes the impossible delivery")
|
|
_expect(_worker().state == StaffRuntime.State.INCAPACITATED and _worker().current_task_id.is_empty(), "spoilage cleanup preserves incapacitation while releasing the Task")
|
|
_expect(_runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "spoilage releases weight without a ghost assignment")
|
|
|
|
|
|
func _test_restore_guards() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore crosslink scenario")
|
|
var stable: Dictionary = _runtime.create_snapshot()
|
|
var bad := stable.duplicate(true)
|
|
for task: Dictionary in bad[&"systems"][&"runtime"][&"staff"][&"tasks"]:
|
|
if task[&"task_type"] == String(SupplyLogisticsBridge.DELIVERY_TYPE):
|
|
task[&"target_cell"] = [99, 99, 1]
|
|
_expect(not _runtime.restore_snapshot(bad) and _runtime.create_snapshot() == stable, "restore rejects a remote delivery target atomically")
|
|
var worker := _worker()
|
|
worker.carried_inventory_id = &"cargo:somebody_else"
|
|
_expect(not _crosslinks(), "crosslink validator rejects stolen cargo ownership")
|
|
worker.carried_inventory_id = _cargo()
|
|
var task := _task()
|
|
var saved_type := task.task_type
|
|
task.task_type = SupplyLogisticsBridge.PICKUP_TYPE
|
|
_expect(not _crosslinks(), "crosslink validator rejects pickup Task paired with loaded request")
|
|
task.task_type = saved_type
|
|
_expect(_crosslinks(), "valid ownership survives rejected candidates")
|
|
|
|
|
|
func _test_pickup_retry() -> void:
|
|
_expect(_runtime.restore_snapshot(_reserved), "restore before pickup dispatch")
|
|
_clock.advance_minutes(1)
|
|
var old_task := _worker().current_task_id
|
|
var stopped: Dictionary = _runtime.supply_logistics.handle_path_stuck(old_task, _clock.absolute_minute)
|
|
_expect(stopped[&"ok"] and _request().state == LogisticsRequest.State.BLOCKED, "unloaded route failure blocks the request and cancels the approach")
|
|
_expect(_runtime.inventory_service.available_quantity(_inventory(_source), SupplyCatalog.RAW_FOOD) == 8 and _worker().current_task_id.is_empty(), "failed approach releases source reservation and employee together")
|
|
_expect(_runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "failed approach retains no dispatcher load")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "blocked unloaded request restores")
|
|
_wait_for(LogisticsRequest.State.DELIVERING, 40)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _worker().current_task_id != old_task, "retries reserve stock again and create a fresh attempt Task")
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_quantity(_inventory(_destination)) == 8 and _quantity(_cargo()) == 0, "retry delivers the same stock exactly once")
|
|
|
|
|
|
func _test_source_closes_after_assignment() -> void:
|
|
_expect(_runtime.restore_snapshot(_reserved), "restore source-closure approach scenario")
|
|
_clock.advance_minutes(1)
|
|
var old_task := _worker().current_task_id
|
|
_expect(_request().state == LogisticsRequest.State.ASSIGNED and not old_task.is_empty(), "source closure begins after assigning the real pickup Task")
|
|
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": false}}), "close the source while its porter approaches")
|
|
_wait_for(LogisticsRequest.State.BLOCKED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.BLOCKED and _request().state_reason == "SOURCE_CLOSED", "arrival at a newly closed source blocks before loading")
|
|
_expect(_quantity(_inventory(_source)) == 8 and _quantity(_cargo()) == 0 and _quantity(_inventory(_destination)) == 0, "closed source retains every purchased unit without transfer")
|
|
_expect(_runtime.inventory_service.available_quantity(_inventory(_source), SupplyCatalog.RAW_FOOD) == 8 and _worker().current_task_id.is_empty(), "blocked pickup releases both source stock and employee reservations")
|
|
_expect(_runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "closed-source cleanup retains no dispatcher or Task ghost")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "blocked closed-source state passes strict Runtime restore")
|
|
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": true}}), "reopen the source for a retry")
|
|
_wait_for(LogisticsRequest.State.DELIVERING, 40)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _worker().current_task_id != old_task and _quantity(_cargo()) == 8, "reopening retries with a fresh Task and physical pickup")
|
|
var loaded_cell := _worker().current_cell
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED and _worker().current_cell != loaded_cell and _quantity(_inventory(_destination)) == 8, "reopened source stock reaches the kitchen by actual porter movement")
|
|
_expect(_quantity(_inventory(_source)) == 0 and _quantity(_cargo()) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "reopened source delivery consumes and releases ownership exactly once")
|
|
|
|
|
|
func _test_source_closes_after_loading() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore loaded source-closure scenario")
|
|
_expect(_command(&"set_facility_policy", {&"facility_id": _source, &"patch": {&"business_open": false}}), "close the source after loading")
|
|
var cell := _worker().current_cell
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED and _worker().current_cell != cell and _quantity(_inventory(_destination)) == 8, "already-loaded porter can finish delivery to an open destination")
|
|
_expect(_quantity(_cargo()) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "delivery after source closure clears cargo and carrier ownership")
|
|
|
|
|
|
func _test_unavailable_before_pickup() -> void:
|
|
_expect(_runtime.restore_snapshot(_reserved), "restore unloaded health failure")
|
|
_clock.advance_minutes(1)
|
|
_worker().health = 0
|
|
_worker().transition_to(StaffRuntime.State.INCAPACITATED, &"TEST", _clock.absolute_minute)
|
|
_clock.advance_minutes(1)
|
|
_expect(_request().state == LogisticsRequest.State.BLOCKED and _worker().current_task_id.is_empty(), "incapacitation before pickup releases approach ownership")
|
|
_expect(_worker().state == StaffRuntime.State.INCAPACITATED and _runtime.inventory_service.available_quantity(_inventory(_source), SupplyCatalog.RAW_FOOD) == 8, "unloaded health failure preserves health state and releases reserved food")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()) and _crosslinks(), "unloaded health failure saves without expired reservation links")
|
|
|
|
|
|
func _test_partial_expiry_return() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore partial-spoilage scenario")
|
|
var inventory: Dictionary = _runtime.inventory_service.create_snapshot()
|
|
for owner: Dictionary in inventory[&"inventories"]:
|
|
if owner[&"owner_inventory_id"] == String(_cargo()):
|
|
owner[&"stacks"][0][&"quantity"] = 4
|
|
_expect(_runtime.inventory_service.restore_snapshot(inventory), "split loaded cargo into two expiry lots")
|
|
_runtime.inventory_service.add_stack(_cargo(), SupplyCatalog.RAW_FOOD, 4, 100, _clock.absolute_minute + 1, _clock.absolute_minute)
|
|
_clock.advance_minutes(1)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _task().task_type == SupplyLogisticsBridge.RETURN_TYPE and _quantity(_cargo()) == 4, "partial expiry retargets the surviving cargo to its source")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "returning cargo saves its destination in the existing Task")
|
|
_worker().health = 0
|
|
_worker().transition_to(StaffRuntime.State.INCAPACITATED, &"TEST", _clock.absolute_minute)
|
|
_clock.advance_minutes(1)
|
|
_expect(_crosslinks(), "unavailability reason cannot erase return destination")
|
|
_worker().health = 100
|
|
_worker().transition_to(StaffRuntime.State.MOVING_TO_TASK, &"RECOVERED", _clock.absolute_minute)
|
|
_wait_for(LogisticsRequest.State.CANCELLED, 40)
|
|
_expect(_request().state_reason == "CARGO_EXPIRED_RETURNED" and _quantity(_inventory(_source)) == 4 and _quantity(_inventory(_destination)) == 0, "return unloads only unspoiled stock at the original warehouse")
|
|
_expect(_quantity(_cargo()) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and _crosslinks(), "partial-expiry return releases all cargo ownership")
|
|
|
|
|
|
func _test_shift_boundary() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore end-of-shift scenario")
|
|
var target := _task().target_cell
|
|
_runtime.path_service.set_cell_temporary_block(target, true)
|
|
_clock.advance_minutes(1081 - _clock.absolute_minute)
|
|
_expect(_worker().is_overtime and not _worker().current_task_id.is_empty() and _quantity(_cargo()) == 8, "18:00 shift end retains loaded non-interruptible work")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "overtime delivery is restorable")
|
|
_runtime.path_service.set_cell_temporary_block(target, false)
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 40)
|
|
_clock.advance_minutes(1)
|
|
_expect(_worker().state == StaffRuntime.State.OFF_DUTY and _worker().current_task_id.is_empty() and _quantity(_inventory(_destination)) == 8, "employee ends the shift after safe unloading")
|
|
|
|
|
|
func _test_late_delivery_failure() -> void:
|
|
_expect(_runtime.restore_snapshot(_loaded), "restore delivery transaction failure")
|
|
var fault := LateFailInventory.new()
|
|
_expect(fault.restore_snapshot(_runtime.inventory_service.create_snapshot()), "install failure after inventory transfer has already mutated")
|
|
_runtime.inventory_service = fault
|
|
_clock.advance_minutes(30)
|
|
_expect(_request().state == LogisticsRequest.State.DELIVERING and _request().state_reason == "DELIVERY_RETRY", "late inventory failure rolls the request back to owned delivery")
|
|
_expect(_quantity(_cargo()) == 8 and _quantity(_inventory(_destination)) == 0 and _runtime.logistics_dispatcher.get_reserved_load(PORTER) == 8, "failed delivery reverses all physical transfer and dispatcher changes")
|
|
_expect(_crosslinks() and not _worker().current_task_id.is_empty(), "failed delivery preserves the employee and Task pair")
|
|
fault.fail_delivery = false
|
|
_wait_for(LogisticsRequest.State.COMPLETED, 10)
|
|
_expect(_request().state == LogisticsRequest.State.COMPLETED and _quantity(_inventory(_destination)) == 8 and _quantity(_cargo()) == 0, "clearing transient failure retries the same operation exactly once")
|
|
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "transaction retry leaves a restorable Runtime")
|
|
|
|
|
|
func _wait_for(state: int, minutes: int) -> void:
|
|
for index: int in minutes:
|
|
if _request().state == state: return
|
|
_clock.advance_minutes(1)
|
|
|
|
|
|
func _command(type: StringName, payload: Dictionary) -> bool:
|
|
var result: CommandResult = _runtime.submit_command(type, payload)
|
|
if not result.is_success(): print(result.message, result.details)
|
|
return result.is_success()
|
|
|
|
|
|
func _inventory(id: StringName) -> StringName:
|
|
return _runtime.facility_service.get_instance(id).local_inventory_id
|
|
|
|
|
|
func _request() -> LogisticsRequest:
|
|
return _runtime.logistics_requests[REQUEST]
|
|
|
|
|
|
func _worker() -> StaffRuntime:
|
|
return _runtime.staff_service.get_staff(PORTER)
|
|
|
|
|
|
func _task() -> StaffTask:
|
|
return _runtime.staff_service.get_task(_worker().current_task_id)
|
|
|
|
|
|
func _cargo() -> StringName:
|
|
return StringName("cargo:%s" % PORTER)
|
|
|
|
|
|
func _quantity(inventory_id: StringName) -> int:
|
|
return _runtime.inventory_service.total_quantity(inventory_id, SupplyCatalog.RAW_FOOD)
|
|
|
|
|
|
func _crosslinks() -> bool:
|
|
return SupplyLogisticsBridge.validate_crosslinks(_runtime.logistics_requests, _runtime.staff_service, _runtime.inventory_service, _runtime.facility_service)
|
|
|
|
|
|
func _expect(condition: bool, message: String) -> void:
|
|
_checks += 1
|
|
if not condition:
|
|
_failures += 1
|
|
push_error(message)
|
|
|
|
|
|
func _finish() -> void:
|
|
print("%s: %d checks / %d failures" % ["PASS" if _failures == 0 else "FAIL", _checks, _failures])
|
|
quit(_failures)
|