2x2 FRONT warp at 3000G/30 materials/360 min, 15G/day and 1 Mana upkeep. Every completed warp pair is linked by one path connector, so crossing is a single step; a 3-Mana fare per rider is charged once in the step's tick. Warps close while either end is unpowered, the reserve is empty or below one fare, and blocked arrivals offer no step. Saves validate the derived links. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1860 lines
75 KiB
GDScript
1860 lines
75 KiB
GDScript
class_name FacilityInfrastructureProjector
|
|
extends RefCounted
|
|
|
|
## Atomic boundary which turns completed ConstructionService facility proxies
|
|
## into authoritative ROUTE subslots and PathService connectors. Primary World
|
|
## occupancy is deliberately outside this boundary, so the infrastructure
|
|
## projection can coexist with the completed facility occupying the same cells.
|
|
|
|
const CommandResultType = preload("res://scripts/core/command_result.gd")
|
|
const FacilityDefinitionType = preload("res://scripts/data/facility_definition.gd")
|
|
const RouteAdapterType = preload("res://scripts/world/route_subslot_path_adapter.gd")
|
|
const SpatialType = preload("res://scripts/world/spatial_subslot_service.gd")
|
|
const PathType = preload("res://scripts/world/path_service.gd")
|
|
|
|
const SNAPSHOT_SCHEMA_VERSION := 1
|
|
const MAX_REQUEST_ID_LENGTH := 96
|
|
const MAX_INSTANCE_ID_LENGTH := 96
|
|
const MAX_PROJECTIONS := 4_096
|
|
const MAX_PROCESSED_REQUESTS := 4_096
|
|
const MAX_HISTORY_CELL_REFERENCES := 262_144
|
|
const MAX_COST_ENTRIES := 32
|
|
const MAX_COORDINATE_ABS := 100_000
|
|
const MAX_SAFE_INTEGER := 9_007_199_254_740_991
|
|
const MAX_SNAPSHOT_DEPTH := 12
|
|
const MAX_CONTAINER_ITEMS := 262_144
|
|
|
|
const OPERATION_PROJECT: StringName = &"PROJECT"
|
|
const OPERATION_UNPROJECT: StringName = &"UNPROJECT"
|
|
const OPERATIONS: Array[StringName] = [OPERATION_PROJECT, OPERATION_UNPROJECT]
|
|
|
|
const KIND_GUEST_CORRIDOR: StringName = &"guest_corridor"
|
|
const KIND_SERVICE_CORRIDOR: StringName = &"service_corridor"
|
|
const KIND_STAFF_DOOR: StringName = &"staff_door"
|
|
const KIND_GUEST_ELEVATOR: StringName = &"guest_elevator"
|
|
const KIND_SERVICE_ELEVATOR: StringName = &"service_elevator"
|
|
const KIND_GUEST_STAIRS: StringName = &"guest_stairs"
|
|
const KIND_SERVICE_STAIRS: StringName = &"service_stairs"
|
|
const KIND_MANA_WARP: StringName = &"mana_warp"
|
|
const SUPPORTED_KINDS: Array[StringName] = [
|
|
KIND_GUEST_CORRIDOR,
|
|
KIND_SERVICE_CORRIDOR,
|
|
KIND_STAFF_DOOR,
|
|
KIND_GUEST_ELEVATOR,
|
|
KIND_SERVICE_ELEVATOR,
|
|
KIND_GUEST_STAIRS,
|
|
KIND_SERVICE_STAIRS,
|
|
KIND_MANA_WARP,
|
|
]
|
|
const KNOWN_KINDS: Array[StringName] = [
|
|
KIND_GUEST_CORRIDOR,
|
|
KIND_SERVICE_CORRIDOR,
|
|
KIND_STAFF_DOOR,
|
|
KIND_GUEST_ELEVATOR,
|
|
KIND_SERVICE_ELEVATOR,
|
|
KIND_GUEST_STAIRS,
|
|
KIND_SERVICE_STAIRS,
|
|
KIND_MANA_WARP,
|
|
]
|
|
|
|
const UNSUPPORTED_VERTICAL_KINDS: Array[StringName] = []
|
|
const VERTICAL_KINDS: Array[StringName] = [KIND_GUEST_ELEVATOR, KIND_SERVICE_ELEVATOR]
|
|
const STAIR_KINDS: Array[StringName] = [KIND_GUEST_STAIRS, KIND_SERVICE_STAIRS]
|
|
const CONNECTOR_KINDS: Array[StringName] = [KIND_STAFF_DOOR, KIND_GUEST_STAIRS, KIND_SERVICE_STAIRS]
|
|
const REASON_UNSUPPORTED_VERTICAL_TOPOLOGY: StringName = &"UNSUPPORTED_VERTICAL_TOPOLOGY"
|
|
const QUARANTINE_TRANSACTION_ROLLBACK: StringName = &"TRANSACTION_ROLLBACK_UNCERTAIN"
|
|
const QUARANTINE_RESTORE_ROLLBACK: StringName = &"RESTORE_ROLLBACK_UNCERTAIN"
|
|
const QUARANTINE_REASONS: Array[StringName] = [
|
|
QUARANTINE_TRANSACTION_ROLLBACK,
|
|
QUARANTINE_RESTORE_ROLLBACK,
|
|
]
|
|
|
|
const ROUTE_ENTITY_PREFIX := "infra.route:"
|
|
const CONNECTOR_PREFIX := "infra.connector:"
|
|
const SHAFT_OWNER_PREFIX := "infra.shaft:"
|
|
const ADAPTER_PROJECT_REQUEST_PREFIX := "infra.project:"
|
|
const ADAPTER_UNPROJECT_REQUEST_PREFIX := "infra.unproject:"
|
|
const STAFF_ACCESS_ID: StringName = &"staff"
|
|
const STAFF_DOOR_CONNECTOR_COST := 120
|
|
const STAIR_CONNECTOR_COST := 150
|
|
|
|
const _INSTANCE_KEYS: Array[StringName] = [
|
|
&"instance_id", &"definition_id", &"origin", &"rotation", &"layer",
|
|
&"occupied_cells", &"construction_cost", &"source_job_id", &"state", &"completed_at",
|
|
]
|
|
const _DEFINITION_INPUT_KEYS: Array[StringName] = [
|
|
&"id", &"layer", &"footprint", &"pass_through", &"tags",
|
|
]
|
|
const _PROJECT_INPUT_KEYS: Array[StringName] = [&"definition", &"instance"]
|
|
const _UNPROJECT_INPUT_KEYS: Array[StringName] = [&"instance_id"]
|
|
const _PROJECTION_KEYS: Array[StringName] = [
|
|
&"instance_id", &"definition_id", &"kind", &"route_entity_id", &"connector_id",
|
|
&"layer", &"cells", &"staff_only", &"pass_through", &"definition_tags",
|
|
&"footprint", &"source_job_id", &"origin", &"rotation", &"completed_at",
|
|
&"record_fingerprint",
|
|
]
|
|
const _DETAIL_KEYS: Array[StringName] = [
|
|
&"request_id", &"operation", &"instance_id", &"changed",
|
|
&"projection_revision", &"projection",
|
|
]
|
|
|
|
var projection_revision := 0
|
|
var last_error := ""
|
|
|
|
var _adapter: RouteSubslotPathAdapter
|
|
var _source: SpatialSubslotService
|
|
var _path: PathService
|
|
var _configured := false
|
|
var _projections: Dictionary = {}
|
|
var _processed_requests: Dictionary = {}
|
|
var _quarantined := false
|
|
var _quarantine_reason: StringName = &""
|
|
var _transaction_active := false
|
|
# Private serialized copy: equality is checked against a fresh snapshot on every
|
|
# validation. Live dependency checks remain unconditional, even on a cache hit.
|
|
var _validated_owned_snapshot: Dictionary = {}
|
|
|
|
|
|
## The explicit three-way binding is intentional: exact rollback must restore
|
|
## the adapter and both authoritative services, not merely compensate forward.
|
|
func configure(
|
|
adapter_value: Variant,
|
|
source_value: Variant,
|
|
path_value: Variant
|
|
) -> bool:
|
|
if _transaction_active:
|
|
return false
|
|
if _configured:
|
|
return _fail("Facility infrastructure projector is already configured.")
|
|
if not adapter_value is RouteSubslotPathAdapter \
|
|
or not source_value is SpatialSubslotService \
|
|
or not path_value is PathService:
|
|
return _fail("Facility infrastructure requires RouteSubslotPathAdapter, SpatialSubslotService, and PathService instances.")
|
|
var adapter_service: RouteSubslotPathAdapter = adapter_value
|
|
var source_service: SpatialSubslotService = source_value
|
|
var path_service: PathService = path_value
|
|
if not adapter_service.is_bound_to(source_service, path_service):
|
|
return _fail("Route adapter is not bound to the supplied authoritative services.")
|
|
if adapter_service.is_quarantined() or adapter_service.is_projection_stale():
|
|
return _fail("Route adapter must be fresh and available before projector configuration.")
|
|
var source_audit: Dictionary = source_service.validate_invariants()
|
|
var adapter_audit: Dictionary = adapter_service.validate_invariants()
|
|
if not bool(source_audit.get(&"ok", false)) or not bool(adapter_audit.get(&"ok", false)):
|
|
return _fail("Authoritative infrastructure invariants are invalid.")
|
|
var path_capture := _capture_path_state(path_service)
|
|
if not bool(path_capture[&"ok"]):
|
|
return _fail(String(path_capture[&"message"]))
|
|
if _has_managed_namespace_collision(source_service, path_service, {}):
|
|
return _fail("Managed infrastructure ID namespace already contains untracked state.")
|
|
_adapter = adapter_service
|
|
_source = source_service
|
|
_path = path_service
|
|
_configured = true
|
|
projection_revision = 0
|
|
_projections.clear()
|
|
_processed_requests.clear()
|
|
_quarantined = false
|
|
_quarantine_reason = &""
|
|
last_error = ""
|
|
return true
|
|
|
|
|
|
func project_facility(
|
|
request_id_value: Variant,
|
|
definition_value: Variant,
|
|
instance_value: Variant
|
|
) -> CommandResult:
|
|
if _transaction_active:
|
|
return CommandResultType.failed(
|
|
CommandResultType.Code.TRANSACTION_CLOSED,
|
|
0,
|
|
"Facility infrastructure transaction is already active."
|
|
)
|
|
if not _configured:
|
|
return _failure(CommandResultType.Code.TRANSACTION_CLOSED, "Facility infrastructure projector is not configured.")
|
|
if not _request_id_is_valid(request_id_value):
|
|
return _failure(CommandResultType.Code.INVALID_PAYLOAD, "Facility infrastructure request ID is invalid.")
|
|
var input_result := _canonicalize_live_project_input(definition_value, instance_value)
|
|
if not bool(input_result[&"ok"]):
|
|
return _failure(
|
|
CommandResultType.Code.INVALID_PAYLOAD,
|
|
String(input_result[&"message"]),
|
|
(input_result.get(&"details", {}) as Dictionary).duplicate(true)
|
|
)
|
|
var canonical_input: Dictionary = input_result[&"input"]
|
|
var definition_input: Dictionary = canonical_input[&"definition"]
|
|
var kind: StringName = definition_input[&"id"]
|
|
if kind not in SUPPORTED_KINDS:
|
|
return _failure(CommandResultType.Code.INVALID_PAYLOAD, "Facility definition is not an infrastructure proxy.")
|
|
var request_id := StringName(request_id_value)
|
|
var fingerprint := _request_fingerprint(OPERATION_PROJECT, canonical_input)
|
|
var replay: Variant = _replay_or_conflict(request_id, fingerprint)
|
|
if replay != null:
|
|
return replay
|
|
if _quarantined:
|
|
return _quarantine_failure()
|
|
if not _history_capacity_allows(canonical_input):
|
|
return _failure(CommandResultType.Code.VALIDATION_FAILED, "Facility infrastructure history capacity is exhausted.")
|
|
if _projections.size() >= MAX_PROJECTIONS:
|
|
return _failure(CommandResultType.Code.VALIDATION_FAILED, "Facility infrastructure projection capacity is exhausted.")
|
|
var instance_input: Dictionary = canonical_input[&"instance"]
|
|
var instance_id: StringName = instance_input[&"instance_id"]
|
|
if _projections.has(instance_id):
|
|
return _failure(CommandResultType.Code.DUPLICATE_COMMAND_ID, "Facility instance is already projected.")
|
|
var record := _projection_from_project_input(canonical_input)
|
|
if _source.has_entity(record[&"route_entity_id"]) \
|
|
or _path.get_vertical_walk_blockers().has(StringName(SHAFT_OWNER_PREFIX + String(instance_id))) \
|
|
or (not StringName(record[&"connector_id"]).is_empty() and _path.has_connector(record[&"connector_id"])):
|
|
return _failure(CommandResultType.Code.DUPLICATE_COMMAND_ID, "Stable infrastructure ID collides with existing authoritative state.")
|
|
if not _dependencies_match_current_state():
|
|
return _failure(CommandResultType.Code.TRANSACTION_CLOSED, "Facility infrastructure dependencies are stale or invalid.")
|
|
if kind in STAIR_KINDS and not _path.has_cell(_stair_lower_landing(record)):
|
|
return _failure(CommandResultType.Code.VALIDATION_FAILED, "Stairs require an existing passable landing directly below their origin.")
|
|
|
|
var owned_before := _capture_owned_state()
|
|
_transaction_active = true
|
|
var guard_state := _capture_owned_state()
|
|
var dependency_capture := _capture_dependencies()
|
|
if not bool(dependency_capture[&"ok"]) \
|
|
or not _owned_state_matches(guard_state) \
|
|
or not _dependency_state_matches_capture(dependency_capture):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"Facility infrastructure capture failed or was tampered with."
|
|
)
|
|
|
|
var route_result := _adapter.place_route(
|
|
StringName(ADAPTER_PROJECT_REQUEST_PREFIX + String(request_id)),
|
|
StringName(record[&"route_entity_id"]),
|
|
(record[&"cells"] as Array).duplicate()
|
|
)
|
|
if not route_result.is_success() or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"ROUTE projection failed or reentrant callback tampering was detected."
|
|
)
|
|
if kind in CONNECTOR_KINDS:
|
|
var connector := _expected_stair_connector(record) if kind in STAIR_KINDS else _expected_staff_connector(record)
|
|
var connector_ok := _path.configure_connector(
|
|
StringName(record[&"connector_id"]),
|
|
connector[&"from"],
|
|
connector[&"to"],
|
|
connector[&"cost"],
|
|
true,
|
|
connector[&"access_id"],
|
|
true
|
|
)
|
|
if not connector_ok or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"Infrastructure connector projection failed or callback tampering was detected."
|
|
)
|
|
if kind in VERTICAL_KINDS:
|
|
var shaft_cells: Array[Vector3i] = []
|
|
shaft_cells.assign(record[&"cells"])
|
|
if not _path.set_vertical_walk_blockers(StringName(SHAFT_OWNER_PREFIX + String(instance_id)), shaft_cells) or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(owned_before, dependency_capture, "Elevator shaft projection failed or callback tampering was detected.")
|
|
var candidate_projections := _projections.duplicate(true)
|
|
candidate_projections[instance_id] = record.duplicate(true)
|
|
if not _dependencies_match_projection_map(candidate_projections) \
|
|
or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"Facility infrastructure postcondition failed."
|
|
)
|
|
|
|
projection_revision += 1
|
|
_projections[instance_id] = record.duplicate(true)
|
|
var details := _result_details(
|
|
request_id,
|
|
OPERATION_PROJECT,
|
|
record,
|
|
projection_revision
|
|
)
|
|
_processed_requests[request_id] = {
|
|
&"operation": OPERATION_PROJECT,
|
|
&"instance_id": instance_id,
|
|
&"input": canonical_input.duplicate(true),
|
|
&"fingerprint": fingerprint,
|
|
&"details": details.duplicate(true),
|
|
}
|
|
_transaction_active = false
|
|
last_error = ""
|
|
return _success(details)
|
|
|
|
|
|
## Signal-friendly alias: ConstructionService.facility_completed can pass its
|
|
## completed instance Dictionary after the caller resolves the definition.
|
|
func project_completed_facility(
|
|
request_id_value: Variant,
|
|
definition_value: Variant,
|
|
instance_value: Variant
|
|
) -> CommandResult:
|
|
return project_facility(request_id_value, definition_value, instance_value)
|
|
|
|
|
|
func unproject_facility(request_id_value: Variant, instance_id_value: Variant) -> CommandResult:
|
|
if _transaction_active:
|
|
return CommandResultType.failed(
|
|
CommandResultType.Code.TRANSACTION_CLOSED,
|
|
0,
|
|
"Facility infrastructure transaction is already active."
|
|
)
|
|
if not _configured:
|
|
return _failure(CommandResultType.Code.TRANSACTION_CLOSED, "Facility infrastructure projector is not configured.")
|
|
if not _request_id_is_valid(request_id_value) or not _instance_id_is_valid(instance_id_value):
|
|
return _failure(CommandResultType.Code.INVALID_PAYLOAD, "Facility infrastructure request or instance ID is invalid.")
|
|
var request_id := StringName(request_id_value)
|
|
var instance_id := StringName(instance_id_value)
|
|
var canonical_input := {&"instance_id": instance_id}
|
|
var fingerprint := _request_fingerprint(OPERATION_UNPROJECT, canonical_input)
|
|
var replay: Variant = _replay_or_conflict(request_id, fingerprint)
|
|
if replay != null:
|
|
return replay
|
|
if _quarantined:
|
|
return _quarantine_failure()
|
|
if not _history_capacity_allows(canonical_input):
|
|
return _failure(CommandResultType.Code.VALIDATION_FAILED, "Facility infrastructure history capacity is exhausted.")
|
|
if not _projections.has(instance_id):
|
|
return _failure(CommandResultType.Code.NOT_FOUND, "Facility infrastructure projection was not found.")
|
|
if not _dependencies_match_current_state():
|
|
return _failure(CommandResultType.Code.TRANSACTION_CLOSED, "Facility infrastructure dependencies are stale or invalid.")
|
|
var record: Dictionary = _projections[instance_id]
|
|
|
|
var owned_before := _capture_owned_state()
|
|
_transaction_active = true
|
|
var guard_state := _capture_owned_state()
|
|
var dependency_capture := _capture_dependencies()
|
|
if not bool(dependency_capture[&"ok"]) \
|
|
or not _owned_state_matches(guard_state) \
|
|
or not _dependency_state_matches_capture(dependency_capture):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"Facility infrastructure capture failed or was tampered with."
|
|
)
|
|
var connector_id: StringName = record[&"connector_id"]
|
|
if not connector_id.is_empty():
|
|
if not _path.remove_connector(connector_id) or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"Infrastructure connector removal failed or callback tampering was detected."
|
|
)
|
|
if record[&"kind"] in VERTICAL_KINDS:
|
|
if not _path.remove_vertical_walk_blockers(StringName(SHAFT_OWNER_PREFIX + String(instance_id))) or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(owned_before, dependency_capture, "Elevator shaft unprojection failed or callback tampering was detected.")
|
|
var route_result := _adapter.remove_route(
|
|
StringName(ADAPTER_UNPROJECT_REQUEST_PREFIX + String(request_id)),
|
|
StringName(record[&"route_entity_id"])
|
|
)
|
|
if not route_result.is_success() or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(
|
|
owned_before,
|
|
dependency_capture,
|
|
"ROUTE unprojection failed or callback tampering was detected."
|
|
)
|
|
var candidate_projections := _projections.duplicate(true)
|
|
candidate_projections.erase(instance_id)
|
|
if _source.has_entity(record[&"route_entity_id"]) \
|
|
or (not connector_id.is_empty() and _path.has_connector(connector_id)) \
|
|
or not _dependencies_match_projection_map(candidate_projections) \
|
|
or not _owned_state_matches(guard_state):
|
|
return _rollback_failure(owned_before, dependency_capture, "Facility infrastructure unprojection postcondition failed.")
|
|
|
|
projection_revision += 1
|
|
_projections.erase(instance_id)
|
|
var details := _result_details(
|
|
request_id,
|
|
OPERATION_UNPROJECT,
|
|
record,
|
|
projection_revision
|
|
)
|
|
_processed_requests[request_id] = {
|
|
&"operation": OPERATION_UNPROJECT,
|
|
&"instance_id": instance_id,
|
|
&"input": canonical_input.duplicate(true),
|
|
&"fingerprint": fingerprint,
|
|
&"details": details.duplicate(true),
|
|
}
|
|
_transaction_active = false
|
|
last_error = ""
|
|
return _success(details)
|
|
|
|
|
|
func is_configured() -> bool:
|
|
return _configured
|
|
|
|
|
|
func is_quarantined() -> bool:
|
|
return _quarantined
|
|
|
|
|
|
func get_quarantine_reason() -> StringName:
|
|
return _quarantine_reason
|
|
|
|
|
|
func has_projection(instance_id: StringName) -> bool:
|
|
return _projections.has(instance_id)
|
|
|
|
|
|
func get_projection(instance_id: StringName) -> Dictionary:
|
|
if not _projections.has(instance_id):
|
|
return {}
|
|
return (_projections[instance_id] as Dictionary).duplicate(true)
|
|
|
|
|
|
func get_projection_ids() -> Array[StringName]:
|
|
return _sorted_names(_projections)
|
|
|
|
|
|
## Before removing a ROUTE/base cell, the owner can reject demolition that
|
|
## would leave a staircase without a lower landing. Overlapping remaining
|
|
## passable sources may still keep that landing valid.
|
|
func get_stair_dependents(cells: Array[Vector3i]) -> Array[StringName]:
|
|
var selected: Dictionary = {}
|
|
for cell: Vector3i in cells:
|
|
selected[cell] = true
|
|
var result: Array[StringName] = []
|
|
for instance_id: StringName in _sorted_names(_projections):
|
|
var record: Dictionary = _projections[instance_id]
|
|
if record[&"kind"] in STAIR_KINDS and selected.has(_stair_lower_landing(record)):
|
|
result.append(instance_id)
|
|
return result
|
|
|
|
|
|
func get_processed_request_ids() -> Array[StringName]:
|
|
return _sorted_names(_processed_requests)
|
|
|
|
|
|
func is_projection_stale() -> bool:
|
|
return not _dependencies_match_current_state()
|
|
|
|
|
|
func get_status() -> Dictionary:
|
|
return {
|
|
&"configured": _configured,
|
|
&"quarantined": _quarantined,
|
|
&"quarantine_reason": _quarantine_reason,
|
|
&"projection_revision": projection_revision,
|
|
&"projection_count": _projections.size(),
|
|
&"stale": not _dependencies_match_current_state(),
|
|
}.duplicate(true)
|
|
|
|
|
|
func create_snapshot() -> Dictionary:
|
|
if not _configured:
|
|
return {}
|
|
var projection_rows: Array[Dictionary] = []
|
|
for instance_id: StringName in _sorted_names(_projections):
|
|
projection_rows.append(_serialize_projection(_projections[instance_id]))
|
|
var request_rows: Array[Dictionary] = []
|
|
for request_id: StringName in _sorted_names(_processed_requests):
|
|
var request: Dictionary = _processed_requests[request_id]
|
|
request_rows.append({
|
|
&"request_id": String(request_id),
|
|
&"operation": String(request[&"operation"]),
|
|
&"instance_id": String(request[&"instance_id"]),
|
|
&"input": _serialize_request_input(request[&"operation"], request[&"input"]),
|
|
&"fingerprint": String(request[&"fingerprint"]),
|
|
&"details": _serialize_details(request[&"details"]),
|
|
})
|
|
return {
|
|
&"schema_version": SNAPSHOT_SCHEMA_VERSION,
|
|
&"projection_revision": projection_revision,
|
|
&"projections": projection_rows,
|
|
&"processed_requests": request_rows,
|
|
&"quarantined": _quarantined,
|
|
&"quarantine_reason": String(_quarantine_reason),
|
|
}
|
|
|
|
|
|
## Restores projector-owned metadata after the caller restores Spatial, Path,
|
|
## and RouteAdapter snapshots. The three dependencies are captured and
|
|
## crosslinked in the same atomic boundary so a hostile callback cannot turn a
|
|
## rejected restore into a partial dependency mutation.
|
|
func restore_snapshot(snapshot: Dictionary) -> bool:
|
|
if _transaction_active:
|
|
return false
|
|
if not _configured:
|
|
return _fail("Facility infrastructure projector must be configured before restore.")
|
|
var parsed := _parse_snapshot(snapshot)
|
|
if not bool(parsed[&"ok"]):
|
|
return _fail(String(parsed[&"message"]))
|
|
var owned_before := _capture_owned_state()
|
|
_transaction_active = true
|
|
var guard_state := _capture_owned_state()
|
|
var dependency_capture := _capture_dependencies()
|
|
if not bool(dependency_capture[&"ok"]) \
|
|
or not _owned_state_matches(guard_state) \
|
|
or not _dependency_state_matches_capture(dependency_capture):
|
|
return _restore_failure(owned_before, dependency_capture, "Snapshot dependency capture failed or was tampered with.")
|
|
if not bool(parsed[&"quarantined"]) \
|
|
and not _dependencies_match_projection_map(parsed[&"projections"]):
|
|
return _restore_failure(owned_before, dependency_capture, "Snapshot projection metadata does not match live infrastructure.")
|
|
if not _owned_state_matches(guard_state) \
|
|
or not _dependency_state_matches_capture(dependency_capture):
|
|
return _restore_failure(owned_before, dependency_capture, "Snapshot validation callback tampered with projector state.")
|
|
projection_revision = int(parsed[&"projection_revision"])
|
|
_projections = (parsed[&"projections"] as Dictionary).duplicate(true)
|
|
_processed_requests = (parsed[&"processed_requests"] as Dictionary).duplicate(true)
|
|
_quarantined = bool(parsed[&"quarantined"])
|
|
_quarantine_reason = parsed[&"quarantine_reason"]
|
|
_transaction_active = false
|
|
last_error = ""
|
|
return true
|
|
|
|
|
|
func is_bound_to(adapter: RouteSubslotPathAdapter, source: SpatialSubslotService, path: PathService) -> bool:
|
|
return _configured and _adapter == adapter and _source == source and _path == path
|
|
|
|
|
|
func validate_invariants() -> Dictionary:
|
|
var errors: Array[String] = []
|
|
if not _configured or _adapter == null or _source == null or _path == null:
|
|
errors.append("Facility infrastructure projector is not configured.")
|
|
return {&"ok": false, &"errors": errors}
|
|
var owned_snapshot := create_snapshot()
|
|
if owned_snapshot != _validated_owned_snapshot:
|
|
var parsed := _parse_snapshot(owned_snapshot)
|
|
if not bool(parsed[&"ok"]):
|
|
errors.append(String(parsed[&"message"]))
|
|
else:
|
|
# create_snapshot allocates every container; no caller or live state
|
|
# retains a mutable reference to this successful validation input.
|
|
_validated_owned_snapshot = owned_snapshot
|
|
if not _quarantined and not _dependencies_match_current_state():
|
|
errors.append("Facility infrastructure live crosslinks are stale.")
|
|
return {&"ok": errors.is_empty(), &"errors": errors}
|
|
|
|
|
|
func _canonicalize_live_project_input(definition_value: Variant, instance_value: Variant) -> Dictionary:
|
|
if not definition_value is FacilityDefinition:
|
|
return {&"ok": false, &"message": "Infrastructure projection requires a FacilityDefinition resource."}
|
|
if not instance_value is Dictionary or not _keys_match(instance_value, _INSTANCE_KEYS):
|
|
return {&"ok": false, &"message": "Completed facility instance fields are not canonical."}
|
|
var definition: FacilityDefinition = definition_value
|
|
if not definition.is_valid():
|
|
return {&"ok": false, &"message": "Facility definition is invalid."}
|
|
if not _name_is_valid(definition.id, MAX_INSTANCE_ID_LENGTH) or definition.id not in KNOWN_KINDS:
|
|
return {&"ok": false, &"message": "Facility definition ID is not a recognized infrastructure proxy."}
|
|
var schema := _kind_schema(definition.id)
|
|
var tags_result := _normalize_names(definition.tags, false, 16, "Facility definition tags")
|
|
if not bool(tags_result[&"ok"]):
|
|
return tags_result
|
|
var canonical_tags: Array[StringName] = tags_result[&"names"]
|
|
if (
|
|
definition.layer != int(schema[&"layer"])
|
|
or definition.footprint != schema[&"footprint"]
|
|
or definition.pass_through != bool(schema[&"pass_through"])
|
|
or canonical_tags != schema[&"tags"]
|
|
or (definition.id in STAIR_KINDS and definition.allowed_rotations != [0])
|
|
):
|
|
return {&"ok": false, &"message": "Facility definition layer, footprint, pass-through flag, or tags diverge from its infrastructure schema."}
|
|
var canonical_definition := {
|
|
&"id": definition.id,
|
|
&"layer": definition.layer,
|
|
&"footprint": definition.footprint,
|
|
&"pass_through": definition.pass_through,
|
|
&"tags": canonical_tags,
|
|
}
|
|
var instance_result := _canonicalize_live_instance(
|
|
instance_value,
|
|
canonical_definition,
|
|
definition.allowed_rotations
|
|
)
|
|
if not bool(instance_result[&"ok"]):
|
|
return instance_result
|
|
return {
|
|
&"ok": true,
|
|
&"input": {
|
|
&"definition": canonical_definition,
|
|
&"instance": instance_result[&"instance"],
|
|
},
|
|
}
|
|
|
|
|
|
func _canonicalize_live_instance(
|
|
value: Dictionary,
|
|
definition: Dictionary,
|
|
allowed_rotations: Array[int]
|
|
) -> Dictionary:
|
|
for key: StringName in [&"instance_id", &"definition_id", &"source_job_id", &"state"]:
|
|
if typeof(value.get(key, null)) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
|
return {&"ok": false, &"message": "Completed facility identifier/state types are invalid."}
|
|
var instance_id := StringName(value[&"instance_id"])
|
|
var definition_id := StringName(value[&"definition_id"])
|
|
var source_job_id := StringName(value[&"source_job_id"])
|
|
var state := StringName(value[&"state"])
|
|
if not _instance_id_is_valid(instance_id) \
|
|
or not _name_is_valid(source_job_id, MAX_INSTANCE_ID_LENGTH) \
|
|
or definition_id != definition[&"id"] \
|
|
or state != &"ACTIVE":
|
|
return {&"ok": false, &"message": "Completed facility IDs, definition crosslink, or ACTIVE state are invalid."}
|
|
if not value[&"origin"] is Vector3i \
|
|
or typeof(value[&"rotation"]) != TYPE_INT \
|
|
or typeof(value[&"layer"]) != TYPE_INT \
|
|
or typeof(value[&"completed_at"]) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Completed facility coordinate or integer field types are invalid."}
|
|
var origin: Vector3i = value[&"origin"]
|
|
var rotation := int(value[&"rotation"])
|
|
var layer := int(value[&"layer"])
|
|
var completed_at := int(value[&"completed_at"])
|
|
if not _cell_is_valid(origin) \
|
|
or rotation not in [0, 90, 180, 270] \
|
|
or rotation not in allowed_rotations \
|
|
or (definition[&"id"] in STAIR_KINDS and (rotation != 0 or not _cell_is_valid(origin + Vector3i(0, -1, 0)))) \
|
|
or layer != int(definition[&"layer"]) \
|
|
or origin.z != layer \
|
|
or completed_at < 0 \
|
|
or completed_at > MAX_SAFE_INTEGER:
|
|
return {&"ok": false, &"message": "Completed facility origin, rotation, layer, or completion time is invalid."}
|
|
var cells_result := _normalize_cells(value[&"occupied_cells"], false, SpatialType.MAX_CELLS_PER_ENTITY, "Completed facility cells")
|
|
if not bool(cells_result[&"ok"]):
|
|
return cells_result
|
|
var cells: Array[Vector3i] = cells_result[&"cells"]
|
|
if value[&"occupied_cells"] != cells:
|
|
return {&"ok": false, &"message": "Completed facility cells must be in canonical order."}
|
|
var expected_cells := _footprint_cells(origin, definition[&"footprint"], rotation)
|
|
if cells != expected_cells:
|
|
return {&"ok": false, &"message": "Completed facility cells do not match the rotated definition footprint."}
|
|
var cost_result := _normalize_cost(value[&"construction_cost"])
|
|
if not bool(cost_result[&"ok"]):
|
|
return cost_result
|
|
return {
|
|
&"ok": true,
|
|
&"instance": {
|
|
&"instance_id": instance_id,
|
|
&"definition_id": definition_id,
|
|
&"origin": origin,
|
|
&"rotation": rotation,
|
|
&"layer": layer,
|
|
&"occupied_cells": cells,
|
|
&"construction_cost": cost_result[&"cost"],
|
|
&"source_job_id": source_job_id,
|
|
&"state": state,
|
|
&"completed_at": completed_at,
|
|
},
|
|
}
|
|
|
|
|
|
static func _kind_schema(kind: StringName) -> Dictionary:
|
|
match kind:
|
|
KIND_GUEST_STAIRS, KIND_SERVICE_STAIRS:
|
|
var staff_only := kind == KIND_SERVICE_STAIRS
|
|
var tags: Array[StringName] = [&"movement", &"route_subslot", &"schema_facility_proxy", &"stairs", &"vertical_connector"]
|
|
tags.append(&"staff_only" if staff_only else &"guest_access")
|
|
return {
|
|
&"layer": PathType.BACK if staff_only else PathType.FRONT,
|
|
&"footprint": Vector2i.ONE,
|
|
&"pass_through": true,
|
|
&"staff_only": staff_only,
|
|
&"tags": _sorted_name_array(tags),
|
|
}
|
|
KIND_GUEST_CORRIDOR:
|
|
return {
|
|
&"layer": PathType.FRONT,
|
|
&"footprint": Vector2i.ONE,
|
|
&"pass_through": true,
|
|
&"staff_only": false,
|
|
&"tags": _sorted_name_array([
|
|
&"corridor", &"guest_access", &"movement", &"route_subslot", &"schema_facility_proxy",
|
|
]),
|
|
}
|
|
KIND_SERVICE_CORRIDOR:
|
|
return {
|
|
&"layer": PathType.BACK,
|
|
&"footprint": Vector2i.ONE,
|
|
&"pass_through": true,
|
|
&"staff_only": true,
|
|
&"tags": _sorted_name_array([
|
|
&"corridor", &"movement", &"route_subslot", &"schema_facility_proxy", &"staff_only",
|
|
]),
|
|
}
|
|
KIND_STAFF_DOOR:
|
|
return {
|
|
&"layer": PathType.BACK,
|
|
&"footprint": Vector2i.ONE,
|
|
&"pass_through": true,
|
|
&"staff_only": true,
|
|
&"tags": _sorted_name_array([
|
|
&"cross_layer_connector", &"movement", &"schema_facility_proxy", &"staff_only",
|
|
]),
|
|
}
|
|
KIND_GUEST_ELEVATOR:
|
|
return {
|
|
&"layer": PathType.FRONT,
|
|
&"footprint": Vector2i(2, 2),
|
|
&"pass_through": true,
|
|
&"staff_only": false,
|
|
&"tags": _sorted_name_array([
|
|
&"guest_access", &"movement", &"schema_facility_proxy", &"vertical_connector",
|
|
]),
|
|
}
|
|
KIND_MANA_WARP:
|
|
# Walkable FRONT cells; WarpService links every warp pair (A07).
|
|
return {
|
|
&"layer": PathType.FRONT,
|
|
&"footprint": Vector2i(2, 2),
|
|
&"pass_through": true,
|
|
&"staff_only": false,
|
|
&"tags": _sorted_name_array([
|
|
&"guest_access", &"movement", &"schema_facility_proxy", &"warp",
|
|
]),
|
|
}
|
|
KIND_SERVICE_ELEVATOR:
|
|
return {
|
|
&"layer": PathType.BACK,
|
|
&"footprint": Vector2i(3, 2),
|
|
&"pass_through": true,
|
|
&"staff_only": true,
|
|
&"tags": _sorted_name_array([
|
|
&"movement", &"schema_facility_proxy", &"staff_only", &"vertical_connector",
|
|
]),
|
|
}
|
|
return {}
|
|
|
|
|
|
static func _projection_from_project_input(input: Dictionary) -> Dictionary:
|
|
var definition: Dictionary = input[&"definition"]
|
|
var instance: Dictionary = input[&"instance"]
|
|
var kind: StringName = definition[&"id"]
|
|
var instance_id: StringName = instance[&"instance_id"]
|
|
var record := {
|
|
&"instance_id": instance_id,
|
|
&"definition_id": kind,
|
|
&"kind": kind,
|
|
&"route_entity_id": StringName(ROUTE_ENTITY_PREFIX + String(instance_id)),
|
|
&"connector_id": StringName(CONNECTOR_PREFIX + String(instance_id)) if kind in CONNECTOR_KINDS else &"",
|
|
&"layer": int(definition[&"layer"]),
|
|
&"cells": (instance[&"occupied_cells"] as Array).duplicate(),
|
|
&"staff_only": bool(_kind_schema(kind)[&"staff_only"]),
|
|
&"pass_through": bool(definition[&"pass_through"]),
|
|
&"definition_tags": (definition[&"tags"] as Array).duplicate(),
|
|
&"footprint": definition[&"footprint"],
|
|
&"source_job_id": instance[&"source_job_id"],
|
|
&"origin": instance[&"origin"],
|
|
&"rotation": int(instance[&"rotation"]),
|
|
&"completed_at": int(instance[&"completed_at"]),
|
|
&"record_fingerprint": "",
|
|
}
|
|
record[&"record_fingerprint"] = _projection_fingerprint(record)
|
|
return record
|
|
|
|
|
|
static func _projection_fingerprint(record: Dictionary) -> String:
|
|
var canonical := "projection|"
|
|
for key: StringName in [&"instance_id", &"definition_id", &"kind", &"route_entity_id", &"connector_id", &"source_job_id"]:
|
|
var text := String(record[key])
|
|
canonical += "%d:%s|" % [text.length(), text]
|
|
canonical += "layer=%d|staff=%d|pass=%d|footprint=%d,%d|rotation=%d|completed=%d|" % [
|
|
int(record[&"layer"]), int(bool(record[&"staff_only"])), int(bool(record[&"pass_through"])),
|
|
(record[&"footprint"] as Vector2i).x, (record[&"footprint"] as Vector2i).y,
|
|
int(record[&"rotation"]), int(record[&"completed_at"]),
|
|
]
|
|
var origin: Vector3i = record[&"origin"]
|
|
canonical += "origin=%d,%d,%d|tags=" % [origin.x, origin.y, origin.z]
|
|
for tag: StringName in record[&"definition_tags"]:
|
|
canonical += "%d:%s;" % [String(tag).length(), String(tag)]
|
|
canonical += "|cells="
|
|
for cell: Vector3i in record[&"cells"]:
|
|
canonical += "%d,%d,%d;" % [cell.x, cell.y, cell.z]
|
|
return canonical.sha256_text()
|
|
|
|
|
|
static func _request_fingerprint(operation: StringName, input: Dictionary) -> String:
|
|
var canonical := "%s|" % String(operation)
|
|
if operation == OPERATION_UNPROJECT:
|
|
var instance_text := String(input[&"instance_id"])
|
|
canonical += "%d:%s" % [instance_text.length(), instance_text]
|
|
return canonical.sha256_text()
|
|
var definition: Dictionary = input[&"definition"]
|
|
var instance: Dictionary = input[&"instance"]
|
|
canonical += "definition=%s|layer=%d|footprint=%d,%d|pass=%d|tags=" % [
|
|
String(definition[&"id"]), int(definition[&"layer"]),
|
|
(definition[&"footprint"] as Vector2i).x, (definition[&"footprint"] as Vector2i).y,
|
|
int(bool(definition[&"pass_through"])),
|
|
]
|
|
for tag: StringName in definition[&"tags"]:
|
|
canonical += "%d:%s;" % [String(tag).length(), String(tag)]
|
|
canonical += "|instance="
|
|
for key: StringName in [&"instance_id", &"definition_id", &"source_job_id", &"state"]:
|
|
var text := String(instance[key])
|
|
canonical += "%d:%s|" % [text.length(), text]
|
|
var origin: Vector3i = instance[&"origin"]
|
|
canonical += "origin=%d,%d,%d|rotation=%d|layer=%d|completed=%d|cells=" % [
|
|
origin.x, origin.y, origin.z, int(instance[&"rotation"]), int(instance[&"layer"]),
|
|
int(instance[&"completed_at"]),
|
|
]
|
|
for cell: Vector3i in instance[&"occupied_cells"]:
|
|
canonical += "%d,%d,%d;" % [cell.x, cell.y, cell.z]
|
|
canonical += "|cost="
|
|
for key: StringName in _sorted_names(instance[&"construction_cost"]):
|
|
canonical += "%d:%s=%d;" % [String(key).length(), String(key), int(instance[&"construction_cost"][key])]
|
|
return canonical.sha256_text()
|
|
|
|
|
|
func _replay_or_conflict(request_id: StringName, fingerprint: String) -> Variant:
|
|
if not _processed_requests.has(request_id):
|
|
return null
|
|
var previous: Dictionary = _processed_requests[request_id]
|
|
if String(previous[&"fingerprint"]) != fingerprint:
|
|
return _failure(
|
|
CommandResultType.Code.DUPLICATE_IDEMPOTENCY_KEY,
|
|
"Facility infrastructure request ID conflicts with earlier input."
|
|
)
|
|
var result := _success((previous[&"details"] as Dictionary).duplicate(true))
|
|
result.is_replay = true
|
|
return result
|
|
|
|
|
|
static func _result_details(
|
|
request_id: StringName,
|
|
operation: StringName,
|
|
record: Dictionary,
|
|
revision: int
|
|
) -> Dictionary:
|
|
return {
|
|
&"request_id": request_id,
|
|
&"operation": operation,
|
|
&"instance_id": record[&"instance_id"],
|
|
&"changed": true,
|
|
&"projection_revision": revision,
|
|
&"projection": record.duplicate(true),
|
|
}
|
|
|
|
|
|
func _capture_owned_state() -> Dictionary:
|
|
return {
|
|
&"adapter": _adapter,
|
|
&"source": _source,
|
|
&"path": _path,
|
|
&"configured": _configured,
|
|
&"projection_revision": projection_revision,
|
|
&"projections": _projections.duplicate(true),
|
|
&"processed_requests": _processed_requests.duplicate(true),
|
|
&"quarantined": _quarantined,
|
|
&"quarantine_reason": _quarantine_reason,
|
|
&"transaction_active": _transaction_active,
|
|
&"last_error": last_error,
|
|
}
|
|
|
|
|
|
func _owned_state_matches(capture: Dictionary) -> bool:
|
|
return (
|
|
_adapter == capture[&"adapter"]
|
|
and _source == capture[&"source"]
|
|
and _path == capture[&"path"]
|
|
and _configured == bool(capture[&"configured"])
|
|
and projection_revision == int(capture[&"projection_revision"])
|
|
and _projections == capture[&"projections"]
|
|
and _processed_requests == capture[&"processed_requests"]
|
|
and _quarantined == bool(capture[&"quarantined"])
|
|
and _quarantine_reason == capture[&"quarantine_reason"]
|
|
and _transaction_active == bool(capture[&"transaction_active"])
|
|
and last_error == String(capture[&"last_error"])
|
|
)
|
|
|
|
|
|
func _restore_owned_state(capture: Dictionary) -> void:
|
|
_adapter = capture[&"adapter"]
|
|
_source = capture[&"source"]
|
|
_path = capture[&"path"]
|
|
_configured = bool(capture[&"configured"])
|
|
projection_revision = int(capture[&"projection_revision"])
|
|
_projections = (capture[&"projections"] as Dictionary).duplicate(true)
|
|
_processed_requests = (capture[&"processed_requests"] as Dictionary).duplicate(true)
|
|
_quarantined = bool(capture[&"quarantined"])
|
|
_quarantine_reason = capture[&"quarantine_reason"]
|
|
_transaction_active = bool(capture[&"transaction_active"])
|
|
last_error = String(capture[&"last_error"])
|
|
|
|
|
|
func _capture_dependencies() -> Dictionary:
|
|
if _adapter == null or _source == null or _path == null:
|
|
return {&"ok": false, &"message": "Facility infrastructure dependencies are unavailable."}
|
|
var source_snapshot := _source.create_snapshot()
|
|
var adapter_snapshot := _adapter.create_snapshot()
|
|
var path_capture := _capture_path_state(_path)
|
|
if source_snapshot.is_empty() or adapter_snapshot.is_empty() or not bool(path_capture[&"ok"]):
|
|
return {
|
|
&"ok": false,
|
|
&"message": String(path_capture.get(&"message", "Facility infrastructure dependency snapshot is unavailable.")),
|
|
}
|
|
return {
|
|
&"ok": true,
|
|
&"source_snapshot": source_snapshot.duplicate(true),
|
|
&"adapter_snapshot": adapter_snapshot.duplicate(true),
|
|
&"path_capture": path_capture,
|
|
}
|
|
|
|
|
|
func _rollback_failure(
|
|
owned_before: Dictionary,
|
|
dependency_capture: Dictionary,
|
|
message: String
|
|
) -> CommandResult:
|
|
var rollback_ok := bool(dependency_capture.get(&"ok", false)) \
|
|
and _restore_dependencies_exact(dependency_capture)
|
|
_restore_owned_state(owned_before)
|
|
if not rollback_ok:
|
|
_quarantine(QUARANTINE_TRANSACTION_ROLLBACK)
|
|
return _failure(
|
|
CommandResultType.Code.TRANSACTION_CLOSED,
|
|
"%s Exact rollback is uncertain; projector was quarantined." % message,
|
|
{
|
|
&"rollback_ok": false,
|
|
&"quarantined": true,
|
|
&"quarantine_reason": _quarantine_reason,
|
|
}
|
|
)
|
|
return _failure(
|
|
CommandResultType.Code.TRANSACTION_APPLY_FAILED,
|
|
"%s Adapter, Spatial, and Path state were restored exactly." % message,
|
|
{&"rollback_ok": true, &"quarantined": false}
|
|
)
|
|
|
|
|
|
func _restore_failure(
|
|
owned_before: Dictionary,
|
|
dependency_capture: Dictionary,
|
|
message: String
|
|
) -> bool:
|
|
var rollback_ok := bool(dependency_capture.get(&"ok", false)) \
|
|
and _restore_dependencies_exact(dependency_capture)
|
|
_restore_owned_state(owned_before)
|
|
if not rollback_ok:
|
|
_quarantine(QUARANTINE_RESTORE_ROLLBACK)
|
|
return _fail("%s Exact rollback is uncertain; projector was quarantined." % message)
|
|
return _fail(message)
|
|
|
|
|
|
func _restore_dependencies_exact(capture: Dictionary) -> bool:
|
|
var source_snapshot: Dictionary = capture[&"source_snapshot"]
|
|
var adapter_snapshot: Dictionary = capture[&"adapter_snapshot"]
|
|
var path_capture: Dictionary = capture[&"path_capture"]
|
|
for _attempt: int in range(2):
|
|
_source.restore_snapshot(source_snapshot.duplicate(true))
|
|
_restore_path_once(_path, path_capture)
|
|
_adapter.restore_snapshot(adapter_snapshot.duplicate(true))
|
|
if (
|
|
_source.create_snapshot() == source_snapshot
|
|
and _path_state_matches_capture(_path, path_capture)
|
|
and _adapter.create_snapshot() == adapter_snapshot
|
|
):
|
|
return true
|
|
return false
|
|
|
|
|
|
func _dependency_state_matches_capture(capture: Dictionary) -> bool:
|
|
if not bool(capture.get(&"ok", false)):
|
|
return false
|
|
return (
|
|
_source.create_snapshot() == capture[&"source_snapshot"]
|
|
and _adapter.create_snapshot() == capture[&"adapter_snapshot"]
|
|
and _path_state_matches_capture(_path, capture[&"path_capture"])
|
|
)
|
|
|
|
|
|
static func _capture_path_state(path_service: PathService) -> Dictionary:
|
|
var snapshot := path_service.create_snapshot()
|
|
var cells_result := _path_cells_from_snapshot(snapshot)
|
|
if not bool(cells_result[&"ok"]):
|
|
return cells_result
|
|
for cell: Vector3i in cells_result[&"cells"]:
|
|
if not path_service.has_cell(cell):
|
|
return {&"ok": false, &"message": "Path snapshot topology is not materialized in the live graph."}
|
|
return {
|
|
&"ok": true,
|
|
&"snapshot": snapshot.duplicate(true),
|
|
&"cells": (cells_result[&"cells"] as Array).duplicate(),
|
|
}
|
|
|
|
|
|
static func _path_cells_from_snapshot(snapshot: Dictionary) -> Dictionary:
|
|
var rows: Variant = snapshot.get(&"cell_traffic", null)
|
|
if not rows is Array or rows.size() > RouteAdapterType.MAX_PROJECTED_CELLS:
|
|
return {&"ok": false, &"message": "Path snapshot does not expose a bounded cell topology."}
|
|
var cells: Array[Vector3i] = []
|
|
var seen: Dictionary = {}
|
|
for raw_row: Variant in rows:
|
|
if not raw_row is Dictionary:
|
|
return {&"ok": false, &"message": "Path snapshot topology row is malformed."}
|
|
var raw_cell: Variant = raw_row.get(&"cell", raw_row.get("cell", null))
|
|
if not _cell_is_valid(raw_cell) or seen.has(raw_cell):
|
|
return {&"ok": false, &"message": "Path snapshot contains an invalid or duplicate cell."}
|
|
seen[raw_cell] = true
|
|
cells.append(raw_cell)
|
|
cells.sort_custom(_cell_less)
|
|
return {&"ok": true, &"cells": cells}
|
|
|
|
|
|
static func _restore_path_once(path_service: PathService, capture: Dictionary) -> void:
|
|
var cells: Array = capture[&"cells"]
|
|
var snapshot: Dictionary = capture[&"snapshot"]
|
|
path_service.rebuild_graph(cells.duplicate())
|
|
path_service.restore_snapshot(snapshot.duplicate(true))
|
|
path_service.rebuild_graph(cells.duplicate())
|
|
|
|
|
|
static func _path_state_matches_capture(path_service: PathService, capture: Dictionary) -> bool:
|
|
if path_service.create_snapshot() != capture[&"snapshot"]:
|
|
return false
|
|
var current := _capture_path_state(path_service)
|
|
return bool(current[&"ok"]) and current[&"cells"] == capture[&"cells"]
|
|
|
|
|
|
func _dependencies_match_current_state() -> bool:
|
|
return _configured \
|
|
and not _quarantined \
|
|
and _dependencies_match_projection_map(_projections)
|
|
|
|
|
|
func _dependencies_match_projection_map(projections: Dictionary) -> bool:
|
|
if _adapter == null or _source == null or _path == null:
|
|
return false
|
|
if not _adapter.is_bound_to(_source, _path) \
|
|
or _adapter.is_quarantined():
|
|
return false
|
|
# For this exact, non-quarantined binding, adapter validation also checks
|
|
# projection staleness. Keep the independent source invariant audit, but
|
|
# avoid repeating the same live projection scan through is_projection_stale().
|
|
if not bool(_source.validate_invariants().get(&"ok", false)) \
|
|
or not bool(_adapter.validate_invariants().get(&"ok", false)):
|
|
return false
|
|
for instance_id: StringName in _sorted_names(projections):
|
|
var record: Dictionary = projections[instance_id]
|
|
if record[&"instance_id"] != instance_id or not _projection_live_matches(record):
|
|
return false
|
|
return not _has_managed_namespace_collision(_source, _path, projections)
|
|
|
|
|
|
func _projection_live_matches(record: Dictionary) -> bool:
|
|
var route_entity_id: StringName = record[&"route_entity_id"]
|
|
if not _source.has_entity(route_entity_id) \
|
|
or _source.get_entity_category(route_entity_id) != _source.CATEGORY_ROUTE \
|
|
or _source.get_entity_cells(route_entity_id) != record[&"cells"]:
|
|
return false
|
|
var connector_id: StringName = record[&"connector_id"]
|
|
if record[&"kind"] in STAIR_KINDS:
|
|
return _path.has_cell(_stair_lower_landing(record)) \
|
|
and not connector_id.is_empty() \
|
|
and _path.has_connector(connector_id) \
|
|
and _path.get_connector(connector_id) == _expected_stair_connector(record)
|
|
if record[&"kind"] == KIND_STAFF_DOOR:
|
|
if connector_id.is_empty() or not _path.has_connector(connector_id):
|
|
return false
|
|
return _path.get_connector(connector_id) == _expected_staff_connector(record)
|
|
if record[&"kind"] in VERTICAL_KINDS:
|
|
var blockers := _path.get_vertical_walk_blockers()
|
|
var owner_id := StringName(SHAFT_OWNER_PREFIX + String(record[&"instance_id"]))
|
|
if not blockers.has(owner_id):
|
|
return false
|
|
var cells: Array = (blockers[owner_id] as Array).duplicate()
|
|
cells.sort_custom(_cell_less)
|
|
return connector_id.is_empty() and cells == record[&"cells"]
|
|
return connector_id.is_empty()
|
|
|
|
|
|
static func _expected_staff_connector(record: Dictionary) -> Dictionary:
|
|
var back_cell: Vector3i = record[&"cells"][0]
|
|
return {
|
|
&"id": record[&"connector_id"],
|
|
&"from": Vector3i(back_cell.x, back_cell.y, PathType.FRONT),
|
|
&"to": back_cell,
|
|
&"cost": STAFF_DOOR_CONNECTOR_COST,
|
|
&"bidirectional": true,
|
|
&"access_id": STAFF_ACCESS_ID,
|
|
&"enabled": true,
|
|
&"movement_type": PathType.MOVEMENT_CONNECTOR,
|
|
&"dynamic_cost": 0,
|
|
&"operational_state": PathType.CONNECTOR_OPERATIONAL,
|
|
&"cabin_capacity": 8,
|
|
&"queue_capacity": 256,
|
|
&"cabin_state": PathType.CABIN_IDLE,
|
|
&"current_floor": back_cell.y,
|
|
&"travel_minutes_per_floor": 1,
|
|
&"request_queue": [],
|
|
}
|
|
|
|
|
|
static func _stair_lower_landing(record: Dictionary) -> Vector3i:
|
|
return (record[&"origin"] as Vector3i) + Vector3i(0, -1, 0)
|
|
|
|
|
|
static func _expected_stair_connector(record: Dictionary) -> Dictionary:
|
|
var connector := _expected_staff_connector(record)
|
|
var upper_cell: Vector3i = record[&"origin"]
|
|
connector[&"from"] = upper_cell
|
|
connector[&"to"] = _stair_lower_landing(record)
|
|
connector[&"cost"] = STAIR_CONNECTOR_COST
|
|
connector[&"access_id"] = STAFF_ACCESS_ID if record[&"kind"] == KIND_SERVICE_STAIRS else &""
|
|
connector[&"current_floor"] = upper_cell.y
|
|
return connector
|
|
|
|
|
|
static func _has_managed_namespace_collision(
|
|
source_service: SpatialSubslotService,
|
|
path_service: PathService,
|
|
projections: Dictionary
|
|
) -> bool:
|
|
var expected_routes: Dictionary = {}
|
|
var expected_connectors: Dictionary = {}
|
|
var expected_shafts: Dictionary = {}
|
|
for record_value: Variant in projections.values():
|
|
if not record_value is Dictionary:
|
|
return true
|
|
var record: Dictionary = record_value
|
|
expected_routes[record[&"route_entity_id"]] = true
|
|
if record[&"kind"] in VERTICAL_KINDS:
|
|
expected_shafts[StringName(SHAFT_OWNER_PREFIX + String(record[&"instance_id"]))] = true
|
|
if not StringName(record[&"connector_id"]).is_empty():
|
|
expected_connectors[record[&"connector_id"]] = true
|
|
for entity_id: StringName in source_service.get_entity_ids(source_service.CATEGORY_ROUTE):
|
|
if String(entity_id).begins_with(ROUTE_ENTITY_PREFIX) and not expected_routes.has(entity_id):
|
|
return true
|
|
for owner_id: Variant in path_service.get_vertical_walk_blockers():
|
|
if String(owner_id).begins_with(SHAFT_OWNER_PREFIX) and not expected_shafts.has(owner_id):
|
|
return true
|
|
var path_snapshot := path_service.create_snapshot()
|
|
var connector_rows: Variant = path_snapshot.get(&"connectors", null)
|
|
if not connector_rows is Array:
|
|
return true
|
|
for raw_connector: Variant in connector_rows:
|
|
if not raw_connector is Dictionary:
|
|
return true
|
|
var connector_id_value: Variant = raw_connector.get(&"id", raw_connector.get("id", null))
|
|
if typeof(connector_id_value) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
|
return true
|
|
var connector_id := StringName(connector_id_value)
|
|
if String(connector_id).begins_with(CONNECTOR_PREFIX) and not expected_connectors.has(connector_id):
|
|
return true
|
|
return false
|
|
|
|
|
|
func _quarantine(reason: StringName) -> void:
|
|
_quarantined = true
|
|
_quarantine_reason = reason
|
|
_transaction_active = false
|
|
|
|
|
|
func _quarantine_failure() -> CommandResult:
|
|
return _failure(
|
|
CommandResultType.Code.TRANSACTION_CLOSED,
|
|
"Facility infrastructure projector is quarantined until an exact snapshot is restored.",
|
|
{&"quarantine_reason": _quarantine_reason}
|
|
)
|
|
|
|
|
|
static func _serialize_projection(record: Dictionary) -> Dictionary:
|
|
var tags: Array[String] = []
|
|
for tag: StringName in record[&"definition_tags"]:
|
|
tags.append(String(tag))
|
|
return {
|
|
&"instance_id": String(record[&"instance_id"]),
|
|
&"definition_id": String(record[&"definition_id"]),
|
|
&"kind": String(record[&"kind"]),
|
|
&"route_entity_id": String(record[&"route_entity_id"]),
|
|
&"connector_id": String(record[&"connector_id"]),
|
|
&"layer": int(record[&"layer"]),
|
|
&"cells": (record[&"cells"] as Array).duplicate(),
|
|
&"staff_only": bool(record[&"staff_only"]),
|
|
&"pass_through": bool(record[&"pass_through"]),
|
|
&"definition_tags": tags,
|
|
&"footprint": record[&"footprint"],
|
|
&"source_job_id": String(record[&"source_job_id"]),
|
|
&"origin": record[&"origin"],
|
|
&"rotation": int(record[&"rotation"]),
|
|
&"completed_at": int(record[&"completed_at"]),
|
|
&"record_fingerprint": String(record[&"record_fingerprint"]),
|
|
}
|
|
|
|
|
|
static func _serialize_request_input(operation: StringName, input: Dictionary) -> Dictionary:
|
|
if operation == OPERATION_UNPROJECT:
|
|
return {&"instance_id": String(input[&"instance_id"])}
|
|
var definition: Dictionary = input[&"definition"]
|
|
var instance: Dictionary = input[&"instance"]
|
|
var tags: Array[String] = []
|
|
for tag: StringName in definition[&"tags"]:
|
|
tags.append(String(tag))
|
|
var cost: Dictionary = {}
|
|
for cost_key: StringName in _sorted_names(instance[&"construction_cost"]):
|
|
cost[String(cost_key)] = int(instance[&"construction_cost"][cost_key])
|
|
return {
|
|
&"definition": {
|
|
&"id": String(definition[&"id"]),
|
|
&"layer": int(definition[&"layer"]),
|
|
&"footprint": definition[&"footprint"],
|
|
&"pass_through": bool(definition[&"pass_through"]),
|
|
&"tags": tags,
|
|
},
|
|
&"instance": {
|
|
&"instance_id": String(instance[&"instance_id"]),
|
|
&"definition_id": String(instance[&"definition_id"]),
|
|
&"origin": instance[&"origin"],
|
|
&"rotation": int(instance[&"rotation"]),
|
|
&"layer": int(instance[&"layer"]),
|
|
&"occupied_cells": (instance[&"occupied_cells"] as Array).duplicate(),
|
|
&"construction_cost": cost,
|
|
&"source_job_id": String(instance[&"source_job_id"]),
|
|
&"state": String(instance[&"state"]),
|
|
&"completed_at": int(instance[&"completed_at"]),
|
|
},
|
|
}
|
|
|
|
|
|
static func _serialize_details(details: Dictionary) -> Dictionary:
|
|
return {
|
|
&"request_id": String(details[&"request_id"]),
|
|
&"operation": String(details[&"operation"]),
|
|
&"instance_id": String(details[&"instance_id"]),
|
|
&"changed": bool(details[&"changed"]),
|
|
&"projection_revision": int(details[&"projection_revision"]),
|
|
&"projection": _serialize_projection(details[&"projection"]),
|
|
}
|
|
|
|
|
|
func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
|
|
if not _variant_depth_is_valid(snapshot, 0):
|
|
return {&"ok": false, &"message": "Facility infrastructure snapshot depth or capacity is exceeded."}
|
|
if not _keys_match(snapshot, [
|
|
&"schema_version", &"projection_revision", &"projections", &"processed_requests",
|
|
&"quarantined", &"quarantine_reason",
|
|
]):
|
|
return {&"ok": false, &"message": "Facility infrastructure snapshot root fields are not canonical."}
|
|
if typeof(snapshot.get(&"schema_version", null)) != TYPE_INT \
|
|
or int(snapshot[&"schema_version"]) != SNAPSHOT_SCHEMA_VERSION:
|
|
return {&"ok": false, &"message": "Unsupported FacilityInfrastructureProjector snapshot version."}
|
|
if typeof(snapshot.get(&"projection_revision", null)) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Facility infrastructure projection revision must be an integer."}
|
|
var next_revision := int(snapshot[&"projection_revision"])
|
|
if next_revision < 0 or next_revision > MAX_SAFE_INTEGER:
|
|
return {&"ok": false, &"message": "Facility infrastructure projection revision is outside supported bounds."}
|
|
if typeof(snapshot.get(&"quarantined", null)) != TYPE_BOOL \
|
|
or typeof(snapshot.get(&"quarantine_reason", null)) != TYPE_STRING:
|
|
return {&"ok": false, &"message": "Facility infrastructure quarantine fields have invalid types."}
|
|
var next_quarantined := bool(snapshot[&"quarantined"])
|
|
var next_quarantine_reason := StringName(snapshot[&"quarantine_reason"])
|
|
if not _quarantine_state_is_valid(next_quarantined, next_quarantine_reason):
|
|
return {&"ok": false, &"message": "Facility infrastructure quarantine fields are inconsistent."}
|
|
var raw_projections: Variant = snapshot.get(&"projections", null)
|
|
var raw_requests: Variant = snapshot.get(&"processed_requests", null)
|
|
if not raw_projections is Array \
|
|
or raw_projections.size() > MAX_PROJECTIONS \
|
|
or not raw_requests is Array \
|
|
or raw_requests.size() > MAX_PROCESSED_REQUESTS:
|
|
return {&"ok": false, &"message": "Facility infrastructure snapshot collections are invalid or exceed capacity."}
|
|
|
|
var next_projections: Dictionary = {}
|
|
var prior_instance := ""
|
|
for raw_projection: Variant in raw_projections:
|
|
var parsed_projection := _parse_projection(raw_projection)
|
|
if not bool(parsed_projection[&"ok"]):
|
|
return parsed_projection
|
|
var record: Dictionary = parsed_projection[&"projection"]
|
|
var instance_text := String(record[&"instance_id"])
|
|
if not prior_instance.is_empty() and instance_text <= prior_instance:
|
|
return {&"ok": false, &"message": "Facility infrastructure projections are not in lexical order."}
|
|
prior_instance = instance_text
|
|
next_projections[record[&"instance_id"]] = record
|
|
|
|
var next_requests: Dictionary = {}
|
|
var requests_by_revision: Dictionary = {}
|
|
var prior_request := ""
|
|
var history_cells := 0
|
|
for raw_request: Variant in raw_requests:
|
|
var parsed_request := _parse_processed_request(raw_request, next_revision)
|
|
if not bool(parsed_request[&"ok"]):
|
|
return parsed_request
|
|
var request_id: StringName = parsed_request[&"request_id"]
|
|
var request_text := String(request_id)
|
|
if not prior_request.is_empty() and request_text <= prior_request:
|
|
return {&"ok": false, &"message": "Facility infrastructure request history is not in lexical order."}
|
|
prior_request = request_text
|
|
var request: Dictionary = parsed_request[&"request"]
|
|
var detail_revision := int(request[&"details"][&"projection_revision"])
|
|
if requests_by_revision.has(detail_revision):
|
|
return {&"ok": false, &"message": "Facility infrastructure history contains duplicate revisions."}
|
|
requests_by_revision[detail_revision] = request
|
|
history_cells += (request[&"details"][&"projection"][&"cells"] as Array).size()
|
|
if history_cells > MAX_HISTORY_CELL_REFERENCES:
|
|
return {&"ok": false, &"message": "Facility infrastructure history cell budget is exceeded."}
|
|
next_requests[request_id] = request
|
|
if next_revision != next_requests.size():
|
|
return {&"ok": false, &"message": "Facility infrastructure revision does not match successful history length."}
|
|
for revision: int in range(1, next_revision + 1):
|
|
if not requests_by_revision.has(revision):
|
|
return {&"ok": false, &"message": "Facility infrastructure history revisions are not contiguous."}
|
|
|
|
var simulated: Dictionary = {}
|
|
for revision: int in range(1, next_revision + 1):
|
|
var request: Dictionary = requests_by_revision[revision]
|
|
var instance_id: StringName = request[&"instance_id"]
|
|
var record: Dictionary = request[&"details"][&"projection"]
|
|
match request[&"operation"]:
|
|
OPERATION_PROJECT:
|
|
if simulated.has(instance_id):
|
|
return {&"ok": false, &"message": "Facility infrastructure history projects an already-live instance."}
|
|
simulated[instance_id] = record.duplicate(true)
|
|
OPERATION_UNPROJECT:
|
|
if not simulated.has(instance_id) or simulated[instance_id] != record:
|
|
return {&"ok": false, &"message": "Facility infrastructure unprojection history crosslink is invalid."}
|
|
simulated.erase(instance_id)
|
|
if simulated != next_projections:
|
|
return {&"ok": false, &"message": "Facility infrastructure current projections diverge from request history."}
|
|
return {
|
|
&"ok": true,
|
|
&"projection_revision": next_revision,
|
|
&"projections": next_projections,
|
|
&"processed_requests": next_requests,
|
|
&"quarantined": next_quarantined,
|
|
&"quarantine_reason": next_quarantine_reason,
|
|
}
|
|
|
|
|
|
static func _parse_projection(raw: Variant) -> Dictionary:
|
|
if not raw is Dictionary or not _keys_match(raw, _PROJECTION_KEYS):
|
|
return {&"ok": false, &"message": "Facility infrastructure projection fields are invalid."}
|
|
for key: StringName in [
|
|
&"instance_id", &"definition_id", &"kind", &"route_entity_id", &"connector_id",
|
|
&"source_job_id", &"record_fingerprint",
|
|
]:
|
|
if typeof(raw.get(key, null)) != TYPE_STRING:
|
|
return {&"ok": false, &"message": "Facility infrastructure projection identifier types are invalid."}
|
|
if typeof(raw.get(&"layer", null)) != TYPE_INT \
|
|
or typeof(raw.get(&"rotation", null)) != TYPE_INT \
|
|
or typeof(raw.get(&"completed_at", null)) != TYPE_INT \
|
|
or typeof(raw.get(&"staff_only", null)) != TYPE_BOOL \
|
|
or typeof(raw.get(&"pass_through", null)) != TYPE_BOOL \
|
|
or not raw.get(&"footprint", null) is Vector2i \
|
|
or not raw.get(&"origin", null) is Vector3i:
|
|
return {&"ok": false, &"message": "Facility infrastructure projection scalar types are invalid."}
|
|
var instance_id := StringName(raw[&"instance_id"])
|
|
var kind := StringName(raw[&"kind"])
|
|
var definition_id := StringName(raw[&"definition_id"])
|
|
var route_entity_id := StringName(raw[&"route_entity_id"])
|
|
var connector_id := StringName(raw[&"connector_id"])
|
|
var source_job_id := StringName(raw[&"source_job_id"])
|
|
if not _instance_id_is_valid(instance_id) \
|
|
or kind not in SUPPORTED_KINDS \
|
|
or definition_id != kind \
|
|
or route_entity_id != StringName(ROUTE_ENTITY_PREFIX + String(instance_id)) \
|
|
or connector_id != (StringName(CONNECTOR_PREFIX + String(instance_id)) if kind in CONNECTOR_KINDS else &"") \
|
|
or not _name_is_valid(source_job_id, MAX_INSTANCE_ID_LENGTH):
|
|
return {&"ok": false, &"message": "Facility infrastructure projection stable-ID crosslink is invalid."}
|
|
var schema := _kind_schema(kind)
|
|
var tags_result := _normalize_snapshot_names(raw[&"definition_tags"], false, 16, "Projection definition tags")
|
|
if not bool(tags_result[&"ok"]):
|
|
return tags_result
|
|
var cells_result := _normalize_cells(raw[&"cells"], false, SpatialType.MAX_CELLS_PER_ENTITY, "Projection cells")
|
|
if not bool(cells_result[&"ok"]) or raw[&"cells"] != cells_result[&"cells"]:
|
|
return {&"ok": false, &"message": "Facility infrastructure projection cells are invalid or unordered."}
|
|
var origin: Vector3i = raw[&"origin"]
|
|
var rotation := int(raw[&"rotation"])
|
|
var completed_at := int(raw[&"completed_at"])
|
|
var record := {
|
|
&"instance_id": instance_id,
|
|
&"definition_id": definition_id,
|
|
&"kind": kind,
|
|
&"route_entity_id": route_entity_id,
|
|
&"connector_id": connector_id,
|
|
&"layer": int(raw[&"layer"]),
|
|
&"cells": cells_result[&"cells"],
|
|
&"staff_only": bool(raw[&"staff_only"]),
|
|
&"pass_through": bool(raw[&"pass_through"]),
|
|
&"definition_tags": tags_result[&"names"],
|
|
&"footprint": raw[&"footprint"],
|
|
&"source_job_id": source_job_id,
|
|
&"origin": origin,
|
|
&"rotation": rotation,
|
|
&"completed_at": completed_at,
|
|
&"record_fingerprint": String(raw[&"record_fingerprint"]),
|
|
}
|
|
if (
|
|
record[&"layer"] != schema[&"layer"]
|
|
or record[&"footprint"] != schema[&"footprint"]
|
|
or record[&"staff_only"] != schema[&"staff_only"]
|
|
or record[&"pass_through"] != schema[&"pass_through"]
|
|
or record[&"definition_tags"] != schema[&"tags"]
|
|
or not _cell_is_valid(origin)
|
|
or origin.z != int(record[&"layer"])
|
|
or rotation not in [0, 90, 180, 270]
|
|
or (kind in STAIR_KINDS and (rotation != 0 or not _cell_is_valid(origin + Vector3i(0, -1, 0))))
|
|
or completed_at < 0
|
|
or completed_at > MAX_SAFE_INTEGER
|
|
or record[&"cells"] != _footprint_cells(origin, record[&"footprint"], rotation)
|
|
or record[&"record_fingerprint"] != _projection_fingerprint(record)
|
|
):
|
|
return {&"ok": false, &"message": "Facility infrastructure projection semantic crosslink is invalid."}
|
|
return {&"ok": true, &"projection": record}
|
|
|
|
|
|
static func _parse_processed_request(raw: Variant, current_revision: int) -> Dictionary:
|
|
if not raw is Dictionary or not _keys_match(raw, [
|
|
&"request_id", &"operation", &"instance_id", &"input", &"fingerprint", &"details",
|
|
]):
|
|
return {&"ok": false, &"message": "Facility infrastructure processed-request fields are invalid."}
|
|
for key: StringName in [&"request_id", &"operation", &"instance_id", &"fingerprint"]:
|
|
if typeof(raw.get(key, null)) != TYPE_STRING:
|
|
return {&"ok": false, &"message": "Facility infrastructure processed-request identifier types are invalid."}
|
|
var request_id := StringName(raw[&"request_id"])
|
|
var operation := StringName(raw[&"operation"])
|
|
var instance_id := StringName(raw[&"instance_id"])
|
|
if not _request_id_is_valid(request_id) \
|
|
or operation not in OPERATIONS \
|
|
or not _instance_id_is_valid(instance_id):
|
|
return {&"ok": false, &"message": "Facility infrastructure processed-request ID or operation is invalid."}
|
|
var input_result := (
|
|
_parse_snapshot_project_input(raw[&"input"])
|
|
if operation == OPERATION_PROJECT
|
|
else _parse_snapshot_unproject_input(raw[&"input"])
|
|
)
|
|
if not bool(input_result[&"ok"]):
|
|
return input_result
|
|
var input: Dictionary = input_result[&"input"]
|
|
if input[&"instance"][&"instance_id"] != instance_id if operation == OPERATION_PROJECT else input[&"instance_id"] != instance_id:
|
|
return {&"ok": false, &"message": "Facility infrastructure request input instance crosslink is invalid."}
|
|
var expected_fingerprint := _request_fingerprint(operation, input)
|
|
if String(raw[&"fingerprint"]) != expected_fingerprint:
|
|
return {&"ok": false, &"message": "Facility infrastructure request fingerprint is not derived from canonical input."}
|
|
var details_result := _parse_details(
|
|
raw[&"details"],
|
|
request_id,
|
|
operation,
|
|
instance_id,
|
|
current_revision
|
|
)
|
|
if not bool(details_result[&"ok"]):
|
|
return details_result
|
|
var details: Dictionary = details_result[&"details"]
|
|
if operation == OPERATION_PROJECT:
|
|
var expected_record := _projection_from_project_input(input)
|
|
if details[&"projection"] != expected_record:
|
|
return {&"ok": false, &"message": "Facility infrastructure project result diverges from canonical input."}
|
|
return {
|
|
&"ok": true,
|
|
&"request_id": request_id,
|
|
&"request": {
|
|
&"operation": operation,
|
|
&"instance_id": instance_id,
|
|
&"input": input,
|
|
&"fingerprint": expected_fingerprint,
|
|
&"details": details,
|
|
},
|
|
}
|
|
|
|
|
|
static func _parse_details(
|
|
raw: Variant,
|
|
request_id: StringName,
|
|
operation: StringName,
|
|
instance_id: StringName,
|
|
current_revision: int
|
|
) -> Dictionary:
|
|
if not raw is Dictionary or not _keys_match(raw, _DETAIL_KEYS):
|
|
return {&"ok": false, &"message": "Facility infrastructure result fields are invalid."}
|
|
if typeof(raw.get(&"request_id", null)) != TYPE_STRING \
|
|
or typeof(raw.get(&"operation", null)) != TYPE_STRING \
|
|
or typeof(raw.get(&"instance_id", null)) != TYPE_STRING \
|
|
or typeof(raw.get(&"changed", null)) != TYPE_BOOL \
|
|
or typeof(raw.get(&"projection_revision", null)) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Facility infrastructure result types are invalid."}
|
|
var detail_revision := int(raw[&"projection_revision"])
|
|
if StringName(raw[&"request_id"]) != request_id \
|
|
or StringName(raw[&"operation"]) != operation \
|
|
or StringName(raw[&"instance_id"]) != instance_id \
|
|
or not bool(raw[&"changed"]) \
|
|
or detail_revision < 1 \
|
|
or detail_revision > current_revision:
|
|
return {&"ok": false, &"message": "Facility infrastructure result crosslink is invalid."}
|
|
var projection_result := _parse_projection(raw[&"projection"])
|
|
if not bool(projection_result[&"ok"]):
|
|
return projection_result
|
|
var record: Dictionary = projection_result[&"projection"]
|
|
if record[&"instance_id"] != instance_id:
|
|
return {&"ok": false, &"message": "Facility infrastructure result projection belongs to another instance."}
|
|
return {
|
|
&"ok": true,
|
|
&"details": {
|
|
&"request_id": request_id,
|
|
&"operation": operation,
|
|
&"instance_id": instance_id,
|
|
&"changed": true,
|
|
&"projection_revision": detail_revision,
|
|
&"projection": record,
|
|
},
|
|
}
|
|
|
|
|
|
static func _parse_snapshot_project_input(raw: Variant) -> Dictionary:
|
|
if not raw is Dictionary or not _keys_match(raw, _PROJECT_INPUT_KEYS):
|
|
return {&"ok": false, &"message": "Facility infrastructure project input fields are invalid."}
|
|
var raw_definition: Variant = raw[&"definition"]
|
|
var raw_instance: Variant = raw[&"instance"]
|
|
if not raw_definition is Dictionary \
|
|
or not _keys_match(raw_definition, _DEFINITION_INPUT_KEYS) \
|
|
or not raw_instance is Dictionary \
|
|
or not _keys_match(raw_instance, _INSTANCE_KEYS):
|
|
return {&"ok": false, &"message": "Facility infrastructure project definition/instance input is malformed."}
|
|
if typeof(raw_definition.get(&"id", null)) != TYPE_STRING \
|
|
or typeof(raw_definition.get(&"layer", null)) != TYPE_INT \
|
|
or not raw_definition.get(&"footprint", null) is Vector2i \
|
|
or typeof(raw_definition.get(&"pass_through", null)) != TYPE_BOOL:
|
|
return {&"ok": false, &"message": "Facility infrastructure project definition input types are invalid."}
|
|
var definition_id := StringName(raw_definition[&"id"])
|
|
if definition_id not in SUPPORTED_KINDS:
|
|
return {&"ok": false, &"message": "Snapshot request history contains an unsupported infrastructure kind."}
|
|
var schema := _kind_schema(definition_id)
|
|
var tags_result := _normalize_snapshot_names(raw_definition[&"tags"], false, 16, "Snapshot definition tags")
|
|
if not bool(tags_result[&"ok"]):
|
|
return tags_result
|
|
var definition := {
|
|
&"id": definition_id,
|
|
&"layer": int(raw_definition[&"layer"]),
|
|
&"footprint": raw_definition[&"footprint"],
|
|
&"pass_through": bool(raw_definition[&"pass_through"]),
|
|
&"tags": tags_result[&"names"],
|
|
}
|
|
if definition[&"layer"] != schema[&"layer"] \
|
|
or definition[&"footprint"] != schema[&"footprint"] \
|
|
or definition[&"pass_through"] != schema[&"pass_through"] \
|
|
or definition[&"tags"] != schema[&"tags"]:
|
|
return {&"ok": false, &"message": "Snapshot definition input diverges from its infrastructure schema."}
|
|
for key: StringName in [&"instance_id", &"definition_id", &"source_job_id", &"state"]:
|
|
if typeof(raw_instance.get(key, null)) != TYPE_STRING:
|
|
return {&"ok": false, &"message": "Snapshot completed-facility identifier/state types are invalid."}
|
|
if not raw_instance.get(&"origin", null) is Vector3i \
|
|
or typeof(raw_instance.get(&"rotation", null)) != TYPE_INT \
|
|
or typeof(raw_instance.get(&"layer", null)) != TYPE_INT \
|
|
or typeof(raw_instance.get(&"completed_at", null)) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Snapshot completed-facility scalar types are invalid."}
|
|
var instance_id := StringName(raw_instance[&"instance_id"])
|
|
var instance_definition_id := StringName(raw_instance[&"definition_id"])
|
|
var source_job_id := StringName(raw_instance[&"source_job_id"])
|
|
var state := StringName(raw_instance[&"state"])
|
|
var origin: Vector3i = raw_instance[&"origin"]
|
|
var rotation := int(raw_instance[&"rotation"])
|
|
var layer := int(raw_instance[&"layer"])
|
|
var completed_at := int(raw_instance[&"completed_at"])
|
|
if not _instance_id_is_valid(instance_id) \
|
|
or instance_definition_id != definition_id \
|
|
or not _name_is_valid(source_job_id, MAX_INSTANCE_ID_LENGTH) \
|
|
or state != &"ACTIVE" \
|
|
or not _cell_is_valid(origin) \
|
|
or origin.z != layer \
|
|
or layer != int(definition[&"layer"]) \
|
|
or rotation not in [0, 90, 180, 270] \
|
|
or (definition_id in STAIR_KINDS and (rotation != 0 or not _cell_is_valid(origin + Vector3i(0, -1, 0)))) \
|
|
or completed_at < 0 \
|
|
or completed_at > MAX_SAFE_INTEGER:
|
|
return {&"ok": false, &"message": "Snapshot completed-facility semantic fields are invalid."}
|
|
var cells_result := _normalize_cells(raw_instance[&"occupied_cells"], false, SpatialType.MAX_CELLS_PER_ENTITY, "Snapshot completed-facility cells")
|
|
if not bool(cells_result[&"ok"]) \
|
|
or raw_instance[&"occupied_cells"] != cells_result[&"cells"] \
|
|
or cells_result[&"cells"] != _footprint_cells(origin, definition[&"footprint"], rotation):
|
|
return {&"ok": false, &"message": "Snapshot completed-facility cells do not crosslink to the footprint."}
|
|
var cost_result := _normalize_snapshot_cost(raw_instance[&"construction_cost"])
|
|
if not bool(cost_result[&"ok"]):
|
|
return cost_result
|
|
return {
|
|
&"ok": true,
|
|
&"input": {
|
|
&"definition": definition,
|
|
&"instance": {
|
|
&"instance_id": instance_id,
|
|
&"definition_id": definition_id,
|
|
&"origin": origin,
|
|
&"rotation": rotation,
|
|
&"layer": layer,
|
|
&"occupied_cells": cells_result[&"cells"],
|
|
&"construction_cost": cost_result[&"cost"],
|
|
&"source_job_id": source_job_id,
|
|
&"state": state,
|
|
&"completed_at": completed_at,
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
static func _parse_snapshot_unproject_input(raw: Variant) -> Dictionary:
|
|
if not raw is Dictionary \
|
|
or not _keys_match(raw, _UNPROJECT_INPUT_KEYS) \
|
|
or typeof(raw.get(&"instance_id", null)) != TYPE_STRING:
|
|
return {&"ok": false, &"message": "Facility infrastructure unproject input is malformed."}
|
|
var instance_id := StringName(raw[&"instance_id"])
|
|
if not _instance_id_is_valid(instance_id):
|
|
return {&"ok": false, &"message": "Facility infrastructure unproject instance ID is invalid."}
|
|
return {&"ok": true, &"input": {&"instance_id": instance_id}}
|
|
|
|
|
|
func _history_capacity_allows(input: Dictionary) -> bool:
|
|
if _processed_requests.size() >= MAX_PROCESSED_REQUESTS:
|
|
return false
|
|
var added_cells := 0
|
|
if input.has(&"instance"):
|
|
added_cells = (input[&"instance"][&"occupied_cells"] as Array).size()
|
|
return _history_cell_reference_count(_processed_requests) <= MAX_HISTORY_CELL_REFERENCES - added_cells
|
|
|
|
|
|
static func _history_cell_reference_count(requests: Dictionary) -> int:
|
|
var total := 0
|
|
for request_value: Variant in requests.values():
|
|
if not request_value is Dictionary:
|
|
continue
|
|
var details: Variant = request_value.get(&"details", {})
|
|
if details is Dictionary:
|
|
var projection: Variant = details.get(&"projection", {})
|
|
if projection is Dictionary:
|
|
var cells: Variant = projection.get(&"cells", [])
|
|
if cells is Array:
|
|
total += cells.size()
|
|
return total
|
|
|
|
|
|
static func _normalize_cost(value: Variant) -> Dictionary:
|
|
if not value is Dictionary or value.size() > MAX_COST_ENTRIES:
|
|
return {&"ok": false, &"message": "Completed facility construction cost is not a bounded Dictionary."}
|
|
var result: Dictionary = {}
|
|
for raw_key: Variant in value:
|
|
if typeof(raw_key) not in [TYPE_STRING, TYPE_STRING_NAME] \
|
|
or not _name_is_valid(raw_key, MAX_INSTANCE_ID_LENGTH) \
|
|
or typeof(value[raw_key]) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Completed facility construction-cost key/value types are invalid."}
|
|
var key := StringName(raw_key)
|
|
var amount := int(value[raw_key])
|
|
if result.has(key) or amount < 0 or amount > MAX_SAFE_INTEGER:
|
|
return {&"ok": false, &"message": "Completed facility construction cost contains a duplicate or invalid amount."}
|
|
result[key] = amount
|
|
return {&"ok": true, &"cost": _sorted_dictionary_by_name(result)}
|
|
|
|
|
|
static func _normalize_snapshot_cost(value: Variant) -> Dictionary:
|
|
if not value is Dictionary or value.size() > MAX_COST_ENTRIES:
|
|
return {&"ok": false, &"message": "Snapshot construction cost is not a bounded Dictionary."}
|
|
var result: Dictionary = {}
|
|
var prior := ""
|
|
for raw_key: Variant in value:
|
|
if typeof(raw_key) != TYPE_STRING or typeof(value[raw_key]) != TYPE_INT:
|
|
return {&"ok": false, &"message": "Snapshot construction-cost types are invalid."}
|
|
var key_text := String(raw_key)
|
|
var key := StringName(key_text)
|
|
var amount := int(value[raw_key])
|
|
if not prior.is_empty() and key_text <= prior:
|
|
return {&"ok": false, &"message": "Snapshot construction-cost keys are not lexical."}
|
|
if not _name_is_valid(key, MAX_INSTANCE_ID_LENGTH) \
|
|
or amount < 0 \
|
|
or amount > MAX_SAFE_INTEGER:
|
|
return {&"ok": false, &"message": "Snapshot construction-cost key or amount is invalid."}
|
|
prior = key_text
|
|
result[key] = amount
|
|
return {&"ok": true, &"cost": result}
|
|
|
|
|
|
static func _normalize_names(
|
|
value: Variant,
|
|
allow_empty: bool,
|
|
maximum: int,
|
|
label: String
|
|
) -> Dictionary:
|
|
if not value is Array or value.size() > maximum or (not allow_empty and value.is_empty()):
|
|
return {&"ok": false, &"message": "%s have an invalid collection shape or capacity." % label}
|
|
var seen: Dictionary = {}
|
|
var names: Array[StringName] = []
|
|
for raw_name: Variant in value:
|
|
if typeof(raw_name) not in [TYPE_STRING, TYPE_STRING_NAME] \
|
|
or not _name_is_valid(raw_name, MAX_INSTANCE_ID_LENGTH):
|
|
return {&"ok": false, &"message": "%s contain an invalid name." % label}
|
|
var name := StringName(raw_name)
|
|
if seen.has(name):
|
|
return {&"ok": false, &"message": "%s contain a duplicate name." % label}
|
|
seen[name] = true
|
|
names.append(name)
|
|
names.sort_custom(_name_less)
|
|
return {&"ok": true, &"names": names}
|
|
|
|
|
|
static func _normalize_snapshot_names(
|
|
value: Variant,
|
|
allow_empty: bool,
|
|
maximum: int,
|
|
label: String
|
|
) -> Dictionary:
|
|
if not value is Array or value.size() > maximum or (not allow_empty and value.is_empty()):
|
|
return {&"ok": false, &"message": "%s have an invalid collection shape or capacity." % label}
|
|
var names: Array[StringName] = []
|
|
var prior := ""
|
|
for raw_name: Variant in value:
|
|
if typeof(raw_name) != TYPE_STRING or not _name_is_valid(raw_name, MAX_INSTANCE_ID_LENGTH):
|
|
return {&"ok": false, &"message": "%s contain an invalid string name." % label}
|
|
var text := String(raw_name)
|
|
if not prior.is_empty() and text <= prior:
|
|
return {&"ok": false, &"message": "%s are not in lexical order." % label}
|
|
prior = text
|
|
names.append(StringName(text))
|
|
return {&"ok": true, &"names": names}
|
|
|
|
|
|
static func _normalize_cells(
|
|
value: Variant,
|
|
allow_empty: bool,
|
|
maximum: int,
|
|
label: String
|
|
) -> Dictionary:
|
|
if not value is Array or value.size() > maximum or (not allow_empty and value.is_empty()):
|
|
return {&"ok": false, &"message": "%s have an invalid collection shape or capacity." % label}
|
|
var seen: Dictionary = {}
|
|
var cells: Array[Vector3i] = []
|
|
for raw_cell: Variant in value:
|
|
if not _cell_is_valid(raw_cell) or seen.has(raw_cell):
|
|
return {&"ok": false, &"message": "%s contain an invalid or duplicate cell." % label}
|
|
seen[raw_cell] = true
|
|
cells.append(raw_cell)
|
|
cells.sort_custom(_cell_less)
|
|
return {&"ok": true, &"cells": cells}
|
|
|
|
|
|
static func _footprint_cells(origin: Vector3i, footprint: Vector2i, rotation: int) -> Array[Vector3i]:
|
|
var dimensions := footprint
|
|
if rotation in [90, 270]:
|
|
dimensions = Vector2i(footprint.y, footprint.x)
|
|
var cells: Array[Vector3i] = []
|
|
for y_offset: int in range(dimensions.y):
|
|
for x_offset: int in range(dimensions.x):
|
|
cells.append(origin + Vector3i(x_offset, y_offset, 0))
|
|
cells.sort_custom(_cell_less)
|
|
return cells
|
|
|
|
|
|
static func _sorted_dictionary_by_name(source: Dictionary) -> Dictionary:
|
|
var result: Dictionary = {}
|
|
for key: StringName in _sorted_names(source):
|
|
result[key] = source[key]
|
|
return result
|
|
|
|
|
|
static func _sorted_name_array(source: Array) -> Array[StringName]:
|
|
var result: Array[StringName] = []
|
|
for value: Variant in source:
|
|
result.append(StringName(value))
|
|
result.sort_custom(_name_less)
|
|
return result
|
|
|
|
|
|
static func _sorted_names(source: Dictionary) -> Array[StringName]:
|
|
var result: Array[StringName] = []
|
|
for raw_name: Variant in source:
|
|
result.append(StringName(raw_name))
|
|
result.sort_custom(_name_less)
|
|
return result
|
|
|
|
|
|
static func _name_less(left: StringName, right: StringName) -> bool:
|
|
return String(left) < String(right)
|
|
|
|
|
|
static func _cell_less(left: Vector3i, right: Vector3i) -> bool:
|
|
if left.y != right.y:
|
|
return left.y < right.y
|
|
if left.x != right.x:
|
|
return left.x < right.x
|
|
return left.z < right.z
|
|
|
|
|
|
static func _cell_is_valid(value: Variant) -> bool:
|
|
if not value is Vector3i:
|
|
return false
|
|
var cell: Vector3i = value
|
|
return (
|
|
cell.z in [PathType.FRONT, PathType.BACK]
|
|
and cell.x >= -MAX_COORDINATE_ABS
|
|
and cell.x <= MAX_COORDINATE_ABS
|
|
and cell.y >= -MAX_COORDINATE_ABS
|
|
and cell.y <= MAX_COORDINATE_ABS
|
|
)
|
|
|
|
|
|
static func _request_id_is_valid(value: Variant) -> bool:
|
|
return _name_is_valid(value, MAX_REQUEST_ID_LENGTH)
|
|
|
|
|
|
static func _instance_id_is_valid(value: Variant) -> bool:
|
|
return _name_is_valid(value, MAX_INSTANCE_ID_LENGTH)
|
|
|
|
|
|
static func _name_is_valid(value: Variant, maximum_length: int) -> bool:
|
|
if typeof(value) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
|
return false
|
|
var text := String(value)
|
|
if text.is_empty() or text.length() > maximum_length:
|
|
return false
|
|
for index: int in range(text.length()):
|
|
var code := text.unicode_at(index)
|
|
var allowed := (
|
|
code >= 48 and code <= 57
|
|
or code >= 65 and code <= 90
|
|
or code >= 97 and code <= 122
|
|
or code in [45, 46, 58, 64, 95]
|
|
)
|
|
if not allowed:
|
|
return false
|
|
return true
|
|
|
|
|
|
static func _keys_match(source: Dictionary, expected: Array) -> bool:
|
|
if source.size() != expected.size():
|
|
return false
|
|
var seen: Dictionary = {}
|
|
for raw_key: Variant in source:
|
|
if typeof(raw_key) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
|
return false
|
|
var key := StringName(raw_key)
|
|
if seen.has(key) or not expected.has(key):
|
|
return false
|
|
seen[key] = true
|
|
return seen.size() == expected.size()
|
|
|
|
|
|
static func _variant_depth_is_valid(value: Variant, depth: int) -> bool:
|
|
if depth > MAX_SNAPSHOT_DEPTH:
|
|
return false
|
|
if value is Array:
|
|
if value.size() > MAX_CONTAINER_ITEMS:
|
|
return false
|
|
for child: Variant in value:
|
|
if not _variant_depth_is_valid(child, depth + 1):
|
|
return false
|
|
elif value is Dictionary:
|
|
if value.size() > MAX_CONTAINER_ITEMS:
|
|
return false
|
|
for key: Variant in value:
|
|
if not _variant_depth_is_valid(key, depth + 1) \
|
|
or not _variant_depth_is_valid(value[key], depth + 1):
|
|
return false
|
|
elif typeof(value) in [TYPE_OBJECT, TYPE_CALLABLE, TYPE_SIGNAL, TYPE_RID]:
|
|
return false
|
|
return true
|
|
|
|
|
|
static func _quarantine_state_is_valid(value: bool, reason: StringName) -> bool:
|
|
return (value and reason in QUARANTINE_REASONS) or (not value and reason.is_empty())
|
|
|
|
|
|
func _success(details: Dictionary = {}) -> CommandResult:
|
|
last_error = ""
|
|
return CommandResultType.succeeded(0, details)
|
|
|
|
|
|
func _failure(code: CommandResult.Code, message: String, details: Dictionary = {}) -> CommandResult:
|
|
last_error = message
|
|
return CommandResultType.failed(code, 0, message, details)
|
|
|
|
|
|
func _fail(message: String) -> bool:
|
|
last_error = message
|
|
return false
|