The FRONT Mana warp is guest-only: its connectors carry the "!staff" access, which path access checks treat as open to everyone except staff. A new 2x2 BACK service warp links only to other service warps for staff, with A07 values. Registry and palette now hold 25 definitions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1873 lines
75 KiB
GDScript
1873 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 KIND_SERVICE_WARP: StringName = &"service_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,
|
|
KIND_SERVICE_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,
|
|
KIND_SERVICE_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_WARP:
|
|
return {
|
|
&"layer": PathType.BACK,
|
|
&"footprint": Vector2i(2, 2),
|
|
&"pass_through": true,
|
|
&"staff_only": true,
|
|
&"tags": _sorted_name_array([
|
|
&"movement", &"schema_facility_proxy", &"staff_only", &"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
|