Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ccd5e6b
feat: vessel topology + per-part resource & thermal lookups
jonpepler May 14, 2026
9a37788
docs: regen openapi for parts topology handlers
jonpepler May 14, 2026
eb17f4e
docs: README — document parts topology + per-part lookups
jonpepler May 14, 2026
4d1252c
fix: topology — invalidate on onVesselChange too
jonpepler May 14, 2026
e5a5c19
feat: v.partState[flightID] per-part deployable/behavioural state
jonpepler May 14, 2026
a37b01e
docs: regen openapi for v.partState
jonpepler May 14, 2026
b24fdc6
docs: README — document v.partState[flightID]
jonpepler May 14, 2026
44fa0cf
feat(resource): r.resourceFor — flow + nominalFlow per resource
jonpepler May 14, 2026
c46e304
fix(resource): engine flow in units/sec, not units/frame
jonpepler May 14, 2026
b21aa4f
fix(topology): drop onVesselWasModified from seq bumps
jonpepler May 15, 2026
3feba2f
feat(resource): expand r.resourceFor flow dispatch
jonpepler May 15, 2026
7a9a9d5
fix(resource): alternator gates on sibling engine state
jonpepler May 15, 2026
35c0bcf
feat(topology): emit per-part up vector
jonpepler May 15, 2026
45561d3
feat(topology): emit fuelLineTarget for fuel-line parts
jonpepler May 15, 2026
73a74ea
feat(topology): emit per-part bounds.center
jonpepler May 16, 2026
d5b00d6
fix(partState): return "unknown" for unrecognised wheel states
jonpepler May 28, 2026
dea9ad9
docs: README parts table: add up, bounds.center, fuelLineTarget
jonpepler May 28, 2026
522b63b
fix(build): strip absolute sourceFile paths from generated schema
jonpepler May 28, 2026
1d46704
docs: regen openapi for topology up / bounds.center / fuelLineTarget
jonpepler May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,87 @@ A machine-readable [OpenAPI 3.1 spec](docs/openapi.yaml) is auto-generated from

</details>

<details><summary>Vessel topology</summary>

Structural snapshot of the active vessel — parts, parent links, modules, and
assembled-space positions. Cached and event-invalidated, so `v.topology` only
recomputes when staging / docking / decoupling / part-death events fire.
Subscribe to `v.topologySeq` and refetch `v.topology` when the seq changes
rather than streaming the topology key directly.

| Key | Description | Type |
|-----|-------------|------|
| `v.topologySeq` | Monotonic counter — bumps on every vessel structural change | int |
| `v.topology` | `{ topologySeq, rootFlightId, parts: [...] }` (see below) | object |

Each entry in `parts[]`:

| Field | Description |
|-------|-------------|
| `flightId` | Stable runtime id within a flight — use for live-lookup keys (`r.resourceFor`, `therm.part`) |
| `persistentId` | Cross-flight id (survives save/load) |
| `parentFlightId` | `flightId` of the parent part, or `null` for the root |
| `name` | Internal part name (e.g. `liquidEngine2`) |
| `title` | Display name (e.g. "LV-T45 'Swivel' Liquid Fuel Engine") |
| `manufacturer` | Display manufacturer |
| `category` | `PartCategories` enum as string |
| `inverseStage` | Stage at which this part separates |
| `crewCapacity` | Max crew |
| `maxTemp` | Internal thermal limit (K) |
| `crashTolerance` | Impact tolerance |
| `dryMass` | `Part.mass` |
| `orgPos` | `[x, y, z]` — vessel-local, as-assembled |
| `bounds.size` | `{ x, y, z }` — prefab renderer bounds in metres |
| `bounds.center` | `{ x, y, z }` — prefab renderer bounds centre offset in metres |
| `up` | `[x, y, z]` — part-local up vector in assembled-space orientation |
| `fuelLineTarget` | `flightId` of the fuel line's destination part; `null` for non-fuel-line parts |
| `modules` | Raw `PartModule.moduleName` strings (passthrough, no filtering) |

</details>

<details><summary>Part behavioural state</summary>

Live deployable / activation state for a single part, keyed by `flightID`
(same id `v.topology` emits). Intended for UI that reflects whether a panel
is extended, an engine is firing, a parachute is armed, etc. — not for
high-frequency telemetry.

| Key | Description | Type |
|-----|-------------|------|
| `v.partState[flightId]` | `{ seq, modules: [...] }` — see below | object |

The response carries a vessel-level `seq` that bumps whenever the cache is
invalidated. Consumers can dedup unchanged pushes by comparing `seq` rather
than walking the modules array.

Each entry in `modules[]` has a `type` (semantic, not the raw KSP module
name) and a `state` from the standard vocabulary. Type-specific extras
(e.g. `tracking` on solar panels, `flameout` on engines) are included
inline when present.

Supported semantic types and their KSP-module sources:

| `type` | Source module | State vocabulary used |
|---|---|---|
| `solarPanel` | `ModuleDeployableSolarPanel` | extended / retracted / deploying / retracting / broken — plus `tracking: bool` |
| `radiator` | `ModuleDeployableRadiator` | extended / retracted / deploying / retracting / broken |
| `antenna` | `ModuleDeployableAntenna` | extended / retracted / deploying / retracting / broken |
| `parachute` | `ModuleParachute` | stowed / armed / deploying / extended / broken |
| `engine` | `ModuleEngines` (incl. `ModuleEnginesFX`) | active / inactive — plus `flameout: true` when out of fuel |
| `drill` | `ModuleResourceHarvester` | active / inactive |
| `cargoBay` | `ModuleCargoBay` (paired with `ModuleAnimateGeneric`) | extended / retracted / deploying / retracting |
| `landingGear` | `ModuleWheels.ModuleWheelDeployment` | extended / retracted / deploying / retracting / broken |

Invalidation hooks: `onStageActivate`, `onVesselWasModified`, `onPartCouple`,
`onPartUndock`, `onPartDie`, `onPartActionUIDismiss`. A 10s backstop covers
player interactions that don't fire a global event (right-click → Extend
Solar Panel, the G key for landing gear, custom action groups). Worst-case
staleness is therefore ~10 seconds for non-event-triggered transitions —
mid-animation transitions like "deploying → extended" may also lag up to
that bound if no other event fires in the interim.

</details>

### `o.*` — Orbit

<details><summary>Keplerian elements & apsides</summary>
Expand Down Expand Up @@ -680,8 +761,9 @@ All body queries take a body index parameter: `b.name[0]` (Kerbol), `b.name[1]`
| `r.resourceCurrent[name]` | Resource amount in current stage |
| `r.resourceCurrentMax[name]` | Resource max in current stage |
| `r.resourceNameList` | List of all resource names |
| `r.resourceFor[flightId]` | Live resources for a single part — `{ resourceName: { amount, maxAmount }, … }`; empty object if the flightId isn't found |

Example: `r.resource[ElectricCharge]`, `r.resource[LiquidFuel]`, `r.resource[Oxidizer]`
Example: `r.resource[ElectricCharge]`, `r.resource[LiquidFuel]`, `r.resource[Oxidizer]`, `r.resourceFor[12345]`

### `s.*` — Sensors

Expand Down Expand Up @@ -1020,6 +1102,7 @@ Each burn object contains `{ tangent, normal, binormal, initial_time, duration }
| `therm.heatShieldTemp` | Heat shield temperature | K |
| `therm.heatShieldTempCelsius` | Heat shield temperature | C |
| `therm.heatShieldFlux` | Heat shield thermal flux | kW |
| `therm.part[flightId]` | Per-part thermal state — `{ temperature, maxTemperature, temperatureK, maxTemperatureK }`; `null` if the flightId isn't found. Core part temperature only — skin temp not exposed | object |

### `sci.*` / `career.*` / `comm.*` — Science, career & comms *(WIP — in testing)*

Expand Down
1 change: 1 addition & 0 deletions Telemachus/AfterBuild.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ if [ -n "$schemaFile" ]; then
| grep -v 'SCHEMA_JSON' \
| sed 's/.*internal const string Json = @"//;s/";//' \
| sed 's/""/"/g' \
| sed "s|${ProjectDir%/}/||g" \
> "$ProjectDir/../publish/api-schema.json"
echo "Extracted API schema to publish/api-schema.json"
else
Expand Down
2 changes: 2 additions & 0 deletions Telemachus/src/KSPAPIBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public KSPAPI(FormatterProvider formatters, VesselChangeDetector vesselChangeDet
APIHandlers.Add(new KerbalismDataLinkHandler(formatters));
APIHandlers.Add(new LandingDataLinkHandler(formatters));
APIHandlers.Add(new ThermalDataLinkHandler(formatters));
APIHandlers.Add(new PartsTopologyDataLinkHandler(formatters));
APIHandlers.Add(new PartStateDataLinkHandler(formatters));
APIHandlers.Add(new ScienceCareerDataLinkHandler(formatters));
APIHandlers.Add(new TimeWarpDataLinkHandler(formatters));
APIHandlers.Add(new TargetDataLinkHandler(formatters));
Expand Down
Loading
Loading