class_name SystemIndex ## Shared, cached system data loader for implant apps (#844, T-949). ## ## T-949: replaces the direct star_map_data.json FileAccess read with a ## StarMapRequest over the bridge (D-010 — the client never reads game data ## files directly). A static cache so every caller (AtlasApp's Reach screen, ## the economics OverviewScreen) shares one fetch instead of each re-asking. ## ## Usage per caller: ## 1. Call request_refresh() once (e.g. in _ready()/on_install()) — idempotent, ## no-op once loaded or already in flight. ## 2. Connect to SimBridge.star_map_received and, in the handler, re-pull ## get_sorted_systems() to refresh with the now-populated list. ## The Atlas can open before the bridge finishes its handshake — ## SimBridge.request_star_map() remembers the request and fires it ## automatically the instant the connection reaches CONNECTED, so callers ## never need to poll or retry themselves. static var _cache: Array = [] static var _loaded: bool = false static var _requested: bool = false ## Sorted node list (by proper_name, falling back to system_id), or [] if the ## star map has not arrived yet. Callers should re-pull this after ## SimBridge.star_map_received fires. static func get_sorted_systems() -> Array: return _cache static func is_loaded() -> bool: return _loaded ## True while a StarMapRequest is considered in flight — the test-observable ## counterpart of the retry bookkeeping (see ingest()'s Error path). static func has_pending_request() -> bool: return _requested ## Test-only: clear the process-global static cache. Statics leak across ## gdUnit suites in one process — the same class as the ## SimBridge._star_map_wanted leak fixed in this PR (review H2/T1). ## SimBridge.reset_test_state() calls this, so every suite already using it ## gets both resets. static func reset_test_state() -> void: _cache = [] _loaded = false _requested = false ## Ask the bridge for the star map if it hasn't been fetched yet. Safe to call ## from every screen's _ready()/on_install() — idempotent once loaded or a ## request is already in flight. static func request_refresh() -> void: if _loaded or _requested: return _requested = true SimBridge.request_star_map() ## Feed a decoded StarMapResponse (from a SimBridge.star_map_received handler) ## into the cache. Sorts once here so every caller gets the same order for free. ## Only a "Ready" status is trusted — an Error response (protocol.gd's ## star_map_response_from_raw already reduces it to status/error/nodes=[]) ## must NOT mark the cache _loaded, and must clear _requested so a later ## request_refresh() retries instead of treating the failed fetch as ## permanently done. static func ingest(response: Dictionary) -> void: if str(response.get("status", "")) != "Ready": _requested = false return var nodes: Array = response.get("nodes", []) var sorted: Array = [] for node: Dictionary in nodes: var sid: String = node.get("system_id", "") if not sid.is_empty(): sorted.append(node) sorted.sort_custom( func(a: Dictionary, b: Dictionary) -> bool: var na: String = a.get("proper_name", a.get("system_id", "")) var nb: String = b.get("proper_name", b.get("system_id", "")) return na < nb ) _cache = sorted _loaded = true