Connect paid food purchasing, kitchen production, and porter deliveries
This commit is contained in:
@@ -15,7 +15,8 @@ const CONSTRUCTION_EXPENSE_ACCOUNT := &"CONSTRUCTION_EXPENSE"
|
||||
const OPERATING_EXPENSE_ACCOUNT := &"OPERATING_EXPENSE"
|
||||
const AUTHORITY_FINE_ACCOUNT := &"AUTHORITY_FINE_EXPENSE"
|
||||
const WAGE_EXPENSE_ACCOUNT := &"WAGE_EXPENSE"
|
||||
const RUNTIME_SNAPSHOT_VERSION := 6
|
||||
const RUNTIME_SNAPSHOT_VERSION := 7
|
||||
const INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION := 6
|
||||
const LEGACY_RUNTIME_SNAPSHOT_VERSION := 1
|
||||
const DEFENSE_RUNTIME_SNAPSHOT_VERSION := 2
|
||||
const PATH_TRAFFIC_RUNTIME_SNAPSHOT_VERSION := 3
|
||||
@@ -86,6 +87,9 @@ var operating_resource_state: LedgerBackedResourceState
|
||||
var inventory_service := InventoryService.new()
|
||||
var logistics_dispatcher := LogisticsDispatcher.new()
|
||||
var logistics_requests: Dictionary = {}
|
||||
var kitchen_production := KitchenProductionService.new()
|
||||
var supply_management := SupplyManagementService.new()
|
||||
var supply_logistics := SupplyLogisticsBridge.new()
|
||||
var facility_service := FacilityService.new()
|
||||
var guest_service := GuestService.new()
|
||||
var staff_service := StaffService.new()
|
||||
@@ -227,6 +231,8 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
|
||||
latest_save_operation_result.clear()
|
||||
latest_restore_safety_report.clear()
|
||||
_initialize_rng_streams()
|
||||
supply_logistics = SupplyLogisticsBridge.new()
|
||||
supply_logistics.configure(self)
|
||||
_executors.clear()
|
||||
register_command_executor(&"change_resources", Callable(self, "_execute_change_resources"))
|
||||
register_command_executor(&"spend_resources", Callable(self, "_execute_spend_resources"))
|
||||
@@ -240,6 +246,8 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
|
||||
register_command_executor(&"update_progression_metrics", Callable(self, "_execute_update_progression_metrics"))
|
||||
register_command_executor(&"complete_progression_quest", Callable(self, "_execute_complete_progression_quest"))
|
||||
register_command_executor(&"acknowledge_operations_pause", Callable(self, "_execute_acknowledge_operations_pause"))
|
||||
register_command_executor(&"purchase_supplies", Callable(self, "_execute_purchase_supplies"))
|
||||
register_command_executor(&"set_kitchen_production", Callable(self, "_execute_set_kitchen_production"))
|
||||
register_command_executor(&"add_inventory_stack", Callable(self, "_execute_add_inventory_stack"))
|
||||
register_command_executor(&"create_logistics_request", Callable(self, "_execute_create_logistics_request"))
|
||||
register_command_executor(&"dispatch_logistics", Callable(self, "_execute_dispatch_logistics"))
|
||||
@@ -452,6 +460,7 @@ func create_snapshot() -> Dictionary:
|
||||
&"mana": mana_network_service.create_snapshot(),
|
||||
&"economy": economy_service.create_snapshot(),
|
||||
&"inventory": inventory_service.create_snapshot(),
|
||||
&"kitchen_production": kitchen_production.create_snapshot(),
|
||||
&"logistics_dispatcher": logistics_dispatcher.create_snapshot(),
|
||||
&"logistics_requests": _serialize_logistics_requests(),
|
||||
&"facilities": facility_service.create_snapshot(),
|
||||
@@ -515,13 +524,14 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
PATH_TRAFFIC_RUNTIME_SNAPSHOT_VERSION,
|
||||
CONTENT_RUNTIME_SNAPSHOT_VERSION,
|
||||
OPERATIONS_RUNTIME_SNAPSHOT_VERSION,
|
||||
INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION,
|
||||
RUNTIME_SNAPSHOT_VERSION,
|
||||
]:
|
||||
return false
|
||||
if runtime_schema_version < OPERATIONS_RUNTIME_SNAPSHOT_VERSION \
|
||||
and not _legacy_operations_history_is_absent(runtime_data):
|
||||
return false
|
||||
if runtime_schema_version < RUNTIME_SNAPSHOT_VERSION \
|
||||
if runtime_schema_version < INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION \
|
||||
and not _legacy_infrastructure_history_is_absent(runtime_data):
|
||||
return false
|
||||
if runtime_schema_version >= OPERATIONS_RUNTIME_SNAPSHOT_VERSION:
|
||||
@@ -537,11 +547,13 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
&"operations", &"relationships", &"event_definitions", &"events",
|
||||
&"authority", &"defense", &"construction",
|
||||
]
|
||||
if runtime_schema_version == RUNTIME_SNAPSHOT_VERSION:
|
||||
if runtime_schema_version >= INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION:
|
||||
runtime_current_keys.append_array([
|
||||
&"excavation", &"spatial_subslots", &"route_projection",
|
||||
&"facility_infrastructure",
|
||||
])
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION:
|
||||
runtime_current_keys.append(&"kitchen_production")
|
||||
if not _dictionary_has_exact_canonical_keys(runtime_data, runtime_current_keys) \
|
||||
or typeof(runtime_data.get(&"runtime_schema_version", null)) != TYPE_INT \
|
||||
or typeof(runtime_data.get(&"world_seed", null)) != TYPE_INT \
|
||||
@@ -562,13 +574,17 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
if runtime_schema_version >= OPERATIONS_RUNTIME_SNAPSHOT_VERSION \
|
||||
and not runtime_data.get(&"operations", null) is Dictionary:
|
||||
return false
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION:
|
||||
if runtime_schema_version >= INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION:
|
||||
for infrastructure_key: StringName in [
|
||||
&"excavation", &"spatial_subslots", &"route_projection",
|
||||
&"facility_infrastructure",
|
||||
]:
|
||||
if not runtime_data.get(infrastructure_key, null) is Dictionary:
|
||||
return false
|
||||
if runtime_schema_version < RUNTIME_SNAPSHOT_VERSION and runtime_data.has(&"kitchen_production"):
|
||||
return false
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION and not runtime_data.get(&"kitchen_production", null) is Dictionary:
|
||||
return false
|
||||
var restored_catalog := MvpContentCatalog.new()
|
||||
var restored_catalog_report := restored_catalog.rebuild()
|
||||
if not bool(restored_catalog_report.get(&"valid", false)):
|
||||
@@ -642,7 +658,7 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
var restored_spatial := SpatialSubslotService.new()
|
||||
var restored_route_adapter := RouteSubslotPathAdapter.new()
|
||||
var restored_infrastructure_projector := FacilityInfrastructureProjector.new()
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION:
|
||||
if runtime_schema_version >= INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION:
|
||||
# Configure against an empty Spatial source before any managed namespace is
|
||||
# present. Then restore the source, rebuild the base+ROUTE topology, and
|
||||
# finally restore Path traffic/actors and the two metadata owners.
|
||||
@@ -959,7 +975,7 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
var restored_excavation := ExcavationService.new(
|
||||
restored_world, restored_construction_resource
|
||||
)
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION:
|
||||
if runtime_schema_version >= INFRASTRUCTURE_RUNTIME_SNAPSHOT_VERSION:
|
||||
if not restored_excavation.restore_snapshot(runtime_data[&"excavation"]):
|
||||
return false
|
||||
else:
|
||||
@@ -1002,6 +1018,15 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
restored_infrastructure_projector
|
||||
):
|
||||
return false
|
||||
var restored_kitchen := KitchenProductionService.new()
|
||||
restored_kitchen.configure(restored_inventory, restored_facilities, definition_registry, restored_runtime_domain_minute)
|
||||
if runtime_schema_version >= RUNTIME_SNAPSHOT_VERSION:
|
||||
if not restored_kitchen.restore_snapshot(runtime_data[&"kitchen_production"]):
|
||||
return false
|
||||
if restored_kitchen.current_minute != restored_runtime_domain_minute or not restored_kitchen.validate_crosslinks():
|
||||
return false
|
||||
if not SupplyLogisticsBridge.validate_crosslinks(restored_logistics, restored_staff, restored_inventory, restored_facilities):
|
||||
return false
|
||||
var restored_world_seed := int(runtime_data.get(&"world_seed", DEFAULT_WORLD_SEED))
|
||||
var restored_streams := {}
|
||||
var saved_streams: Dictionary = runtime_data[&"rng_streams"]
|
||||
@@ -1044,11 +1069,13 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
|
||||
mana_network_service = restored_mana
|
||||
economy_service = restored_economy
|
||||
inventory_service = restored_inventory
|
||||
kitchen_production = restored_kitchen
|
||||
logistics_dispatcher = restored_dispatcher
|
||||
logistics_requests = restored_logistics
|
||||
facility_service = restored_facilities
|
||||
guest_service = restored_guests
|
||||
staff_service = restored_staff
|
||||
supply_logistics.configure(self)
|
||||
mvp_content_catalog = restored_catalog
|
||||
mvp_content_report = restored_catalog_report.duplicate(true)
|
||||
progression_service = restored_progression
|
||||
@@ -1652,6 +1679,7 @@ func _build_operations_external_state() -> Dictionary:
|
||||
&"next_command_id": _next_command_id,
|
||||
&"economy": economy_service.create_snapshot(),
|
||||
&"inventory": inventory_service.create_snapshot(),
|
||||
&"kitchen_production": kitchen_production.create_snapshot(),
|
||||
&"facilities": facility_service.create_snapshot(),
|
||||
&"guests": guest_service.create_snapshot(),
|
||||
&"staff": staff_service.create_snapshot(),
|
||||
@@ -1687,12 +1715,13 @@ func _operations_external_committed_minute() -> int:
|
||||
|
||||
func _runtime_aggregate_committed_minute() -> int:
|
||||
if facility_service == null or guest_service == null or inventory_service == null \
|
||||
or staff_service == null:
|
||||
or staff_service == null or kitchen_production == null:
|
||||
return -1
|
||||
var minute := facility_service.current_minute
|
||||
if minute < 0 or guest_service.current_minute != minute \
|
||||
or inventory_service.current_minute != minute \
|
||||
or staff_service.current_minute != minute:
|
||||
or staff_service.current_minute != minute \
|
||||
or kitchen_production.current_minute != minute:
|
||||
return -1
|
||||
return minute
|
||||
|
||||
@@ -1703,7 +1732,7 @@ func _restore_operations_external_state(token: Variant) -> bool:
|
||||
return false
|
||||
var saved: Dictionary = token
|
||||
var required_dictionary_keys: Array[StringName] = [
|
||||
&"game_state", &"command_queue", &"economy", &"inventory", &"facilities", &"guests",
|
||||
&"game_state", &"command_queue", &"economy", &"inventory", &"kitchen_production", &"facilities", &"guests",
|
||||
&"staff", &"relationships", &"events", &"authority", &"world", &"path",
|
||||
&"excavation", &"spatial_subslots", &"route_projection",
|
||||
&"facility_infrastructure",
|
||||
@@ -1743,6 +1772,7 @@ func _restore_operations_external_state(token: Variant) -> bool:
|
||||
var economy_ok := economy_service.restore_snapshot(saved[&"economy"])
|
||||
var inventory_ok := inventory_service.restore_snapshot(saved[&"inventory"])
|
||||
var facilities_ok := facility_service.restore_snapshot(saved[&"facilities"])
|
||||
var kitchen_ok := kitchen_production.restore_snapshot(saved[&"kitchen_production"])
|
||||
var guests_ok := guest_service.restore_snapshot(saved[&"guests"])
|
||||
var staff_ok := staff_service.restore_snapshot(saved[&"staff"])
|
||||
var relationships_ok := relationship_service.restore_snapshot(saved[&"relationships"])
|
||||
@@ -1791,7 +1821,7 @@ func _restore_operations_external_state(token: Variant) -> bool:
|
||||
rng_ok = false
|
||||
|
||||
_discard_operations_domain_events()
|
||||
var participants_ok := state_ok and command_queue_ok and economy_ok and inventory_ok \
|
||||
var participants_ok := state_ok and command_queue_ok and economy_ok and inventory_ok and kitchen_ok \
|
||||
and facilities_ok and guests_ok and staff_ok and relationships_ok \
|
||||
and events_ok and authority_ok and world_ok and spatial_ok and path_ok \
|
||||
and route_ok and infrastructure_ok and excavation_ok \
|
||||
@@ -1845,6 +1875,7 @@ func _operations_external_state_matches(saved: Dictionary) -> bool:
|
||||
or _next_command_id != int(saved[&"next_command_id"]) \
|
||||
or not _strict_variants_equal(economy_service.create_snapshot(), saved[&"economy"]) \
|
||||
or not _strict_variants_equal(inventory_service.create_snapshot(), saved[&"inventory"]) \
|
||||
or not _strict_variants_equal(kitchen_production.create_snapshot(), saved[&"kitchen_production"]) \
|
||||
or not _strict_variants_equal(facility_service.create_snapshot(), saved[&"facilities"]) \
|
||||
or not _strict_variants_equal(guest_service.create_snapshot(), saved[&"guests"]) \
|
||||
or not _strict_variants_equal(staff_service.create_snapshot(), saved[&"staff"]) \
|
||||
@@ -4679,6 +4710,8 @@ func _initialize_s2_operations() -> void:
|
||||
facility_service.current_minute = _clock.absolute_minute
|
||||
_configure_facility_boundaries()
|
||||
_connect_facility_signals()
|
||||
kitchen_production = KitchenProductionService.new()
|
||||
kitchen_production.configure(inventory_service, facility_service, definition_registry, _clock.absolute_minute)
|
||||
|
||||
func _initialize_s3_actors() -> void:
|
||||
guest_service = GuestService.new()
|
||||
@@ -5354,7 +5387,11 @@ func _execute_dispatch_logistics(command: SimulationCommand) -> CommandResult:
|
||||
var carriers: Variant = command.payload.get(&"carriers", command.payload.get("carriers", null))
|
||||
if not carriers is Dictionary:
|
||||
return CommandResult.failed(CommandResult.Code.INVALID_PAYLOAD, command.command_id, "carriers must be a Dictionary.")
|
||||
var assignments := logistics_dispatcher.dispatch(_sorted_logistics_requests(), carriers, _runtime_event_minute())
|
||||
var manual_requests: Array[LogisticsRequest] = []
|
||||
for request: LogisticsRequest in _sorted_logistics_requests():
|
||||
if not String(request.request_id).begins_with(SupplyLogisticsBridge.REQUEST_PREFIX):
|
||||
manual_requests.append(request)
|
||||
var assignments := logistics_dispatcher.dispatch(manual_requests, carriers, _runtime_event_minute())
|
||||
return CommandResult.succeeded(command.command_id, {
|
||||
&"assignments": assignments,
|
||||
&"report": logistics_dispatcher.last_report.duplicate(true),
|
||||
@@ -5362,6 +5399,8 @@ func _execute_dispatch_logistics(command: SimulationCommand) -> CommandResult:
|
||||
|
||||
func _execute_advance_logistics_request(command: SimulationCommand) -> CommandResult:
|
||||
var request_id := StringName(command.payload.get(&"request_id", command.payload.get("request_id", "")))
|
||||
if command.command_id > 0 and String(request_id).begins_with(SupplyLogisticsBridge.REQUEST_PREFIX):
|
||||
return CommandResult.failed(CommandResult.Code.VALIDATION_FAILED, command.command_id, "Supply deliveries advance only after the porter arrives.", {&"reason": &"SUPPLY_DRIVER_REQUIRED"})
|
||||
if not logistics_requests.has(request_id):
|
||||
return CommandResult.failed(CommandResult.Code.NOT_FOUND, command.command_id, "Logistics request was not found.")
|
||||
var request: LogisticsRequest = logistics_requests[request_id]
|
||||
@@ -6844,6 +6883,9 @@ func _execute_demolish_facility(command: SimulationCommand) -> CommandResult:
|
||||
"A Facility assigned to a non-terminal Defense Raid cannot be demolished.",
|
||||
{&"raid_id": defense_owner}
|
||||
)
|
||||
var supply_guard: Dictionary = supply_management.validate_demolition(self, instance_id)
|
||||
if not bool(supply_guard.get(&"ok", false)):
|
||||
return _staff_assignment_failure(command.command_id, StringName(supply_guard.get(&"reason", &"SUPPLY_IN_USE")), "Facility still owns supply stock, a production plan, or an active delivery.")
|
||||
for assignment: Dictionary in staff_service.get_work_assignments():
|
||||
if StringName(assignment[&"facility_id"]) == instance_id:
|
||||
return _staff_assignment_failure(command.command_id, &"STAFF_ASSIGNED", "Unassign scheduled Staff before demolishing this facility.")
|
||||
@@ -6905,6 +6947,8 @@ func _execute_demolish_facility(command: SimulationCommand) -> CommandResult:
|
||||
return demolished
|
||||
var result := construction_service.demolish_facility(instance_id)
|
||||
result.command_id = command.command_id
|
||||
if result.is_success():
|
||||
kitchen_production.remove_plan(instance_id)
|
||||
return result
|
||||
|
||||
|
||||
@@ -7527,11 +7571,14 @@ func _advance_inventory_and_logistics(absolute_minute: int) -> void:
|
||||
return
|
||||
inventory_service.current_minute = absolute_minute
|
||||
inventory_service.process_expired(absolute_minute, &"inventory.waste")
|
||||
supply_management.ensure_deliveries(self, absolute_minute)
|
||||
supply_logistics.tick(absolute_minute)
|
||||
|
||||
func _advance_facilities(absolute_minute: int) -> void:
|
||||
if _operations_tick_blocked:
|
||||
return
|
||||
facility_service.advance_one_minute(absolute_minute)
|
||||
kitchen_production.advance_one_minute(absolute_minute)
|
||||
|
||||
func _advance_guest_vitals(absolute_minute: int) -> void:
|
||||
if _operations_tick_blocked:
|
||||
@@ -7763,7 +7810,8 @@ func _advance_runtime_path_traffic(absolute_minute: int) -> void:
|
||||
continue
|
||||
var task := staff_service.get_task(staff.current_task_id)
|
||||
if task != null and task.state == StaffTask.State.MOVING \
|
||||
and task.assigned_staff_id == staff.staff_id:
|
||||
and task.assigned_staff_id == staff.staff_id \
|
||||
and supply_logistics.can_move_task(task.task_id):
|
||||
_advance_staff_task_travel(task, actor_id, absolute_minute)
|
||||
else:
|
||||
_record_expected_actor_wait(actor_id, staff.current_cell, absolute_minute)
|
||||
@@ -8056,13 +8104,14 @@ func _recover_stuck_actor(
|
||||
elif kind == &"staff":
|
||||
var staff := staff_service.get_staff(entity_id)
|
||||
if staff != null and not staff.current_task_id.is_empty():
|
||||
var cancelled := staff_service.cancel_task(
|
||||
staff.current_task_id,
|
||||
&"PATH_STUCK",
|
||||
absolute_minute
|
||||
)
|
||||
action_ok = cancelled.is_success()
|
||||
action = &"STAFF_TASK_CANCELLED" if action_ok else &"STAFF_TASK_CANCEL_FAILED"
|
||||
if supply_logistics.owns_task(staff.current_task_id):
|
||||
var recovery: Dictionary = supply_logistics.handle_path_stuck(staff.current_task_id, absolute_minute)
|
||||
action_ok = bool(recovery.get(&"ok", false))
|
||||
action = StringName(recovery.get(&"action", &"SUPPLY_RECOVERY_FAILED"))
|
||||
else:
|
||||
var cancelled := staff_service.cancel_task(staff.current_task_id, &"PATH_STUCK", absolute_minute)
|
||||
action_ok = cancelled.is_success()
|
||||
action = &"STAFF_TASK_CANCELLED" if action_ok else &"STAFF_TASK_CANCEL_FAILED"
|
||||
if not action_ok:
|
||||
path_service.restore_snapshot(path_before)
|
||||
guest_service.restore_snapshot(guests_before)
|
||||
@@ -11112,3 +11161,19 @@ func _publish_snapshot(_absolute_minute: int) -> void:
|
||||
latest_snapshot = create_snapshot()
|
||||
latest_digest = SimulationDigest.compute(latest_snapshot)
|
||||
snapshot_published.emit(latest_snapshot, latest_digest)
|
||||
|
||||
|
||||
func _execute_purchase_supplies(command: SimulationCommand) -> CommandResult:
|
||||
return supply_management.purchase(self, command)
|
||||
|
||||
|
||||
func _execute_set_kitchen_production(command: SimulationCommand) -> CommandResult:
|
||||
return supply_management.set_production(self, command)
|
||||
|
||||
|
||||
func get_supply_management_report() -> Dictionary:
|
||||
return supply_management.get_report(self)
|
||||
|
||||
|
||||
func preview_supply_purchase(warehouse_id: StringName, item_id: StringName, quantity: int) -> Dictionary:
|
||||
return supply_management.preview_purchase(self, warehouse_id, item_id, quantity)
|
||||
|
||||
Reference in New Issue
Block a user