FSBar.Hub Namespace
| Type/Module | Description |
|
Hub-side orchestrator for the autohost AdminChannel. Serializes outbound admin commands onto the channel, de-duplicates rapid-fire same-kind submits within a short quiet window (research.md §R5), maintains hub-visible status, and publishes every transition through IHubEventSink. Callers submit intents; the host decides when/whether they reach the socket (feature 039). |
|
|
|
|
|
Resolves the user's BAR installation — data directory, installed engine versions, the active engine per user override, and the skirmish AIs registered under the active engine. Every path this module returns is verified at resolution time; callers can hand the result to downstream modules (proxy installer, session launcher) without re-checking existence. Wraps `FSBar.Client.EngineDiscovery` — no filesystem logic is duplicated — but adds a data-model vocabulary (`EngineVersionEntry`, `BarInstall`) and structured error reporting tuned for the hub's Settings / First-Run UI. |
|
Locates and validates the HighBarV2 skirmish-AI proxy that the hub
installs into a user's BAR data dir (FR-006 / FR-006a).
On-disk layout (repo-relative):
proxy/
├── bundled/
│ └──
|
|
|
Which cap in FR-026 was exceeded. Mapped to the wire `PutLayerResponse.exceeded_cap` string in `ScriptingHub`. |
|
|
Coordinate space for an overlay primitive. `World` is transformed by the current `ViewerCamera`; `Screen` is viewport pixels and bypasses the camera. |
|
|
Opaque per-RPC correlation identifier (feature 042 FR-009 / FR-009a). Flows across `await` boundaries via `AsyncLocal<_>`; read by `HubLog.emit` on every log entry; set by the gRPC server interceptor on every unary and streaming RPC entering `FSBar.Hub.ScriptingHub.ScriptingService`. Hub-assigned form: `Guid.NewGuid().ToString("N")`. Client-supplied form: any non-empty UTF-8 string ≤ 64 bytes, carried on the request metadata header `x-fsbar-correlation-id`. The effective ID is echoed back on the response trailer `x-fsbar-correlation-id` so clients can assert on it without a schema change to every existing response message (R3). |
|
|
Feature 042 FR-004a — Debug-level RPC dispatch tracer. Emits a single `ScriptingHub` Debug entry when an RPC handler is entered and another when it completes (with elapsed ms). Attach to the same Kestrel gRPC pipeline as `CorrelationId.ServerInterceptor`; register AFTER the correlation-ID interceptor so log entries inherit the active correlation scope. |
|
|
Pure predicate + helpers for the Units-tab encyclopedia filter (feature 044). Stateless — one source of truth for both render and tests. |
|
|
|
|
|
Encyclopedia tab filter + selection combined. All filter sets are empty = "pass all" by convention; `SearchText` is trimmed and length-capped at 128 chars by `HubStateStore.setEncyclopedia`. Session-scoped: lives on `HubState` for the Hub process lifetime and is NOT persisted to disk (feature 044 FR-008). |
|
|
Faction groups used for filtering the Units-tab encyclopedia. Membership is set-valued (empty = "all factions"). |
|
|
Off-screen render pipeline for the Viewer tab. Reads the current `SessionManager` game state + `HubStateStore` camera + `HubStateStore.VizConfig` every tick, calls `SceneBuilder.buildSceneHeadlessView`, rasterizes into an off-screen SKSurface (raster backend — the GPU backend segfaults in this environment per CLAUDE.md), encodes PNG/JPEG, and fans out to per-subscriber bounded channels (capacity 16, DropOldest). |
|
|
Central event bus for hub diagnostics and lifecycle signals. The hub publishes discrete events (session-state transitions, engine-speed adjustments, proxy-install step outcomes, scripting-client attach/detach, plain diagnostic lines). Consumers — the status bar, settings diagnostics pane, gRPC `GetSessionStatus` response assembly — observe the `IObservable` projection. Implementation is a single `System.Threading.Channels` pump with a list of subscribed `IObserver`s: the publish side enqueues without blocking, a background task drains the channel and fans out, and a slow observer cannot wedge the producer. No `System.Reactive` dependency. |
|
|
Canonical in-process log-emit surface for the Hub. Multi-subscriber
bidi gRPC stream (`StreamHubLog`) is layered on top in
`ScriptingHub`; local GUI diagnostics continue to flow through the
`HubEventBus` via the per-call-site bridging documented in
research.md §R8.
Zero-overhead when no subscriber is attached: `emit` gates on a
single `Volatile.Read` of the subscriber count before any
`LogEntry` allocation, timestamp read, or message formatting (R1).
Subscriber fan-out mirrors the `ScriptingHub` pattern: per-
subscriber `BoundedChannel |
|
|
Hub-wide user-editable settings. Persisted as a single JSON document under the XDG config home. **Phase 2 scope note**: the planning sketch included a `LastLobby` field of type `LobbyConfig option` for persisting the user's most recent lobby. That field is deferred to Phase 3 (task T027, when `LobbyConfig` lands); the current JSON schema reserves room for it via a forward-compatible `SchemaVersion` field but does not yet emit / consume it. |
|
|
Aggregate UI-state owned by `HubStateStore`. Every top-level tab and the Viewer camera is represented here. Mutations go through the store's mutator helpers (LWW + event emission); direct reads use `HubStateStore.current`. |
|
|
Central, authoritative state store for the Hub UI (feature 040). Every user-facing action — active-tab swap, Viewer camera pan/zoom, lobby edit, `VizConfig` change, encyclopedia selection, preset list invalidation, settings change — routes through this module. Both the local GUI (tab files under `FSBar.Hub.App`) and the gRPC handlers (`ScriptingHub`) read and write the same cell, so the two surfaces can never drift. Every successful mutation publishes exactly one `HubEvent` through the supplied `IHubEventSink`, powering both local redraw and the remote `StreamHubStateEvents` fan-out. Concurrency model: single `HubState` reference updated via `Interlocked.CompareExchange`. Under contention the loser re-reads and retries up to 3 times before returning `Rejected "write contention"`. This matches the FR-015 / data-model.md §HubStateStore atomic-LWW guarantee. |
|
|
Hub-UI-facing data types referenced by both the event bus (`HubEvents`) and the authoritative state store (`HubStateStore`). Split out from `HubStateStore` because `HubEvents` carries these values in its event payloads (so it must compile *before* `HubStateStore`), while `HubStateStore` itself depends on `HubEvents.IHubEventSink` to publish mutations. Without this split the two modules form a cycle. No module or behaviour lives here — only the shapes. Which top-level tab is currently shown in the Hub GUI. |
|
|
Encoded-image format the render-frame pipeline produces. |
|
|
Lobby builder types + validation + projection onto the existing FSBar.Client.EngineConfig / ScriptGenerator path. The hub lets users configure arbitrary team counts, mixed AI / human / spectator seats, and game modes (Skirmish / FFA / Team). The data model here is richer than what ScriptGenerator currently emits — the existing generator produces a fixed two-team AI-vs-AI skirmish script. `toEngineConfig` collapses a validated lobby down to that shape, and enforces any excess structure via a Phase-3 restriction documented on the `toEngineConfig` signature below. US4 / US-Team / US-FFA expansions widen the adapter as the generator learns to emit more elaborate scripts. |
|
|
Mobility chip keys for the encyclopedia filter. Empty set = "all mobilities". |
|
|
A named layer owned by one scripting client. Layers are atomic: a `PutLayer` with an existing name replaces the whole primitive list. |
|
|
Summary of an overlay layer — everything but the primitive payload. Returned by `listLayers` and the `ListLayers` RPC. |
|
|
Immutable per-frame projection used by `HeadlessRenderer` — entries are pre-sorted by `(ownerId, zHint ascending, uploadedAt ascending)` so the renderer can composite without touching the store state. |
|
|
Per-client, name-keyed overlay layer store (feature 040 US6). Phase 2 ships a skeleton — no validation, no cap enforcement — so downstream wiring can take shape. US6 task T060 adds the FR-026 cap matrix + primitive validation; US6 T061 wires the disconnect-cleanup subscription. Every mutator is keyed on the caller's `clientId`. Clients cannot read or mutate each other's layers; a client disconnect drops all of its layers atomically (wired via `wireDisconnectCleanup`). |
|
|
2D point in either world or screen coordinates (disambiguated by the owning `OverlayPrimitive`'s `CoordinateSpace`). |
|
|
Declarative overlay primitive. One case per supported Skia draw call. |
|
|
Stroke + fill + opacity description shared by every overlay primitive. |
|
|
One verb in a path primitive. `MoveTo` MUST be the first verb in any path; downstream validation (US6 T060) enforces this. |
|
Installs (and re-verifies) the bundled HighBarV2 skirmish AI into
the user's BAR data directory (feature 035-central-gui-hub US2).
Three discrete steps, each idempotent and independently observable
via `HubEvents.ProxyInstallProgress`:
1. `CopyAiFiles` → copy `libSkirmishAI.so` + `AIInfo.lua` +
`AIOptions.lua` from the repo's `proxy/bundled/
|
|
|
Typed error from `putLayer`. Validation failures and cap violations produce distinct gRPC status codes upstream. |
|
|
One rendered + encoded frame of the Viewer tab as image bytes. `RenderedAtUnixMs` stamps the instant the scene was rasterized; `EncodedAtUnixMs` stamps the instant the encode completed. Both are populated by `HeadlessRenderer` on the server side and forwarded in the gRPC `RenderFrameMessage` envelope. |
|
|
One active subscription's reader handle. The worker writes every rendered+encoded frame into `Channel`; the caller reads and forwards to its gRPC stream. `Dispose` stops the worker and closes the channel. |
|
|
Caller-visible subscription parameters. |
|
The hub's gRPC scripting service — fans `SessionManager.Frames` out to every connected client on an independent bounded channel, isolates slow / dead clients, and exposes unary RPCs for command submission, status queries, and UnitDef lookups (feature 035-central-gui-hub US7). Fan-out design (research.md R3): * One internal subscriber to `SessionManager.Frames`. * Per-client `System.Threading.Channels.BoundedChannel |
|
|
Owns the hub's at-most-one live BAR session: lobby → engine launch → BarClient lifecycle → frame stream → clean teardown. Publishes every lifecycle transition onto a supplied `IHubEventSink` so the status bar, diagnostics pane, and gRPC `GetSessionStatus` response assembler all see a consistent view. |
|
|
Return type for every mutating operation on the state stores. Mirrors the gRPC `MutationResult` wire shape. |
|
|
Outcome of a `subscribe` call. |
|
|
Horizontal alignment for a `Text` primitive. |
|
|
Tier chip keys for the encyclopedia filter. Empty set = "all tiers". |
|
|
Explicit on/off/flip request for a toggle-style mutation. |
|
|
|
|
|
Viewer-tab camera state. Pan + zoom are expressed as an origin in world coordinates and a scale factor. `AutoFit = true` makes the Viewer tab re-fit the scene to the viewport on each redraw; the Viewer UI flips it to `false` the first time the user manually pans or zooms. |
FSBarV1_Archived