From 0f23d34e9f958c7835b7f4a683ac351941ebe247 Mon Sep 17 00:00:00 2001 From: Takeshi Date: Tue, 20 Oct 2026 15:12:47 +0900 Subject: [PATCH] Path: Apply "!id" access to layer-crossing and no-route diagnostics A stopped guest warp now reports CONNECTOR_UNAVAILABLE instead of GOAL_UNREACHABLE (P14-02 review r2 follow-up). Co-Authored-By: Claude Opus 5.5 --- scripts/world/path_service.gd | 21 +++++++++++---------- tests/transport/test_runtime_warp.gd | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/world/path_service.gd b/scripts/world/path_service.gd index cd6d8f8..a33207a 100644 --- a/scripts/world/path_service.gd +++ b/scripts/world/path_service.gd @@ -2097,13 +2097,16 @@ func _edge_meets_vertical_policy(from_cell: Vector3i, edge: Dictionary) -> bool: or not StringName(edge[&"connector_id"]).is_empty() or edge[&"movement_type"] != MOVEMENT_WALK -func _edge_is_accessible(edge: Dictionary, allowed_access_ids: Array[StringName]) -> bool: - var required_access: StringName = edge[&"access_id"] - # "!id" is open to everyone except actors that carry id (guest-only warp). +## "" is public, "id" needs id, and "!id" is open to everyone except actors +## that carry id (guest-only warp). +static func _access_id_permits(required_access: StringName, allowed_access_ids: Array[StringName]) -> bool: if String(required_access).begins_with("!"): - if StringName(String(required_access).substr(1)) in allowed_access_ids: - return false - elif not required_access.is_empty() and required_access not in allowed_access_ids: + return StringName(String(required_access).substr(1)) not in allowed_access_ids + return required_access.is_empty() or required_access in allowed_access_ids + + +func _edge_is_accessible(edge: Dictionary, allowed_access_ids: Array[StringName]) -> bool: + if not _access_id_permits(edge[&"access_id"], allowed_access_ids): return false var connector_id: StringName = edge[&"connector_id"] if connector_id.is_empty(): @@ -2190,8 +2193,7 @@ func _cell_is_temporarily_blocked(cell: Vector3i) -> bool: ## Only the absence of any permitted directed crossing proves unreachable. func _has_permitted_layer_crossing(from_layer: int, to_layer: int, allowed_access_ids: Array[StringName]) -> bool: for connector: Dictionary in _connectors.values(): - var access_id: StringName = connector[&"access_id"] - if not access_id.is_empty() and access_id not in allowed_access_ids: + if not _access_id_permits(connector[&"access_id"], allowed_access_ids): continue var from_cell: Vector3i = connector[&"from"] var to_cell: Vector3i = connector[&"to"] @@ -2257,8 +2259,7 @@ func _route_exists_with_overrides( neighbor_set[neighbor] = true for connector_id: StringName in connector_ids: var connector: Dictionary = _connectors[connector_id] - var required_access: StringName = connector[&"access_id"] - if not required_access.is_empty() and required_access not in allowed_access_ids: + if not _access_id_permits(connector[&"access_id"], allowed_access_ids): continue if not allow_unavailable_connectors and not _connector_is_operational(connector): continue diff --git a/tests/transport/test_runtime_warp.gd b/tests/transport/test_runtime_warp.gd index 0eb2d95..9056a0a 100644 --- a/tests/transport/test_runtime_warp.gd +++ b/tests/transport/test_runtime_warp.gd @@ -104,6 +104,7 @@ func _write() -> void: _clock.advance_minutes(1) _expect(_runtime.path_service.get_connector(ids[0])[&"operational_state"] == PathService.CONNECTOR_OUTAGE, "reserve outage stops the warp") _expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)).is_empty(), "stopped warp offers no route") + _expect(_runtime.path_service.find_path_report(Vector3i(0, 0, 0), Vector3i(0, 2, 0))[&"reason"] == PathService.ROUTE_CONNECTOR_UNAVAILABLE, "guest sees the stopped warp as an unavailable connector") ManaOutage.release(_runtime, _state, Warp.MANA_PER_TRIP - 1) _clock.advance_minutes(1) _expect(_runtime.path_service.get_connector(ids[0])[&"operational_state"] == PathService.CONNECTOR_OUTAGE, "reserve below one fare keeps the warp closed")