Skip to content

feat(target): tar.availableVessels + tar.switchVessel — list and fly to vessels#89

Open
jonpepler wants to merge 4 commits into
TeaGuild:mainfrom
jonpepler:telemachus/tar-available-vessels
Open

feat(target): tar.availableVessels + tar.switchVessel — list and fly to vessels#89
jonpepler wants to merge 4 commits into
TeaGuild:mainfrom
jonpepler:telemachus/tar-available-vessels

Conversation

@jonpepler
Copy link
Copy Markdown
Contributor

Summary

Two new keys in the tar.* family that finally make tar.setTargetVessel usable and add a flight-scene "fly to vessel":

Key Kind Returns
tar.availableVessels read [{ index, name, type, situation, body, position }, …] — every vessel except the active vessel and the Flag / EVA / Debris / Unknown types
tar.switchVessel[index] action Flies the player to the given vessel — the same operation as the Tracking Station "Fly" button, callable from a flight scene

tar.setTargetVessel[index] already worked, but it had no companion key to enumerate the indices it expects, so in practice it was unusable without an external source of indices. tar.availableVessels closes that loop — both keys share the same index space, and the new position field gives a client enough to sort the list by distance.

Wire shape

{
  "tar.availableVessels": [
    {
      "index": 13,
      "name": "Munar Orbiter",
      "type": "Probe",
      "situation": "ORBITING",
      "body": "Mun",
      "position": [184523.4, 12055.2, -3217.8]
    }
  ]
}
  • index — the exact FlightGlobals.Vessels[index] slot. Non-contiguous once filtered vessels punch holes in the array.
  • typeVessel.vesselType: Ship, Probe, Lander, Plane, Rover, Station, Base, Relay, SpaceObject, …
  • situationVessel.Situations: LANDED / SPLASHED / PRELAUNCH / FLYING / SUB_ORBITAL / ORBITING / ESCAPING / DOCKED.
  • body — name of the orbited body. Sun-orbiting vessels report "Sun".
  • position — vector in the active vessel's local frame (transform.InverseTransformPoint); its magnitude tracks the in-game distance readout. Omitted when there is no active vessel, so the key is flight-scene only.

Design notes

  • Walks FlightGlobals.Vessels without re-sorting, so the indices match KSP's internal addressing one-for-one and stay aligned with tar.setTargetVessel. A client that wants distance order sorts on position itself.
  • Filter is deliberately minimal. Flag / EVA / Debris / Unknown covers everything a client shouldn't normally target. SpaceObject (asteroids and comets) is kept — it's a legitimate target.
  • tar.switchVessel saves state before switching. HighLogic.CurrentGame.Updated() + GamePersistence.SaveGame preserves the current vessel's mid-flight pose, fuel, and heat so they're restored on switch-back. This mirrors what the Tracking Station's "Fly" button does internally. The args/range/HighLogic.CurrentGame guards return early before any scene change is attempted.

Validation

dotnet build clean. OpenAPI and docs/api-schema.json regenerated to include both keys. Exercised live against a running KSP install on 2026-05-15: the array carries every documented field with the active vessel correctly absent and indices non-contiguous; tar.setTargetVessel and tar.switchVessel both act on the right vessel by index; position magnitude tracks tar.distance; switching away and back restores the saved pose and fuel; and an out-of-range index returns false with no scene change. The Flag / EVA / Debris / Unknown filter holds while SpaceObject rows pass through.

Behavioural notes

  • Like the other annotated IsAction keys, the HTTP response body returns false even on success. The action is queued onto the Unity main thread and the state change echoes back over the WebSocket stream, not the HTTP response.
  • tar.availableVessels indices can shift when the active vessel changes (KSP reshuffles FlightGlobals.Vessels on focus change), so clients should treat them as per-snapshot selectors, not stable identifiers.

jonpepler added 4 commits May 28, 2026 20:46
Add a new TelemetryAPI handler that walks FlightGlobals.Vessels and
emits per-vessel records keyed by the integer index that
`tar.setTargetVessel` expects. Without this enumeration the action's
index argument is unobservable to any client; this closes that loop.

Per-row payload:
  index     — exact arg for tar.setTargetVessel[index]
  name      — Vessel.GetName()
  type      — Vessel.vesselType.ToString()
  situation — Vessel.Situations.ToString()
  body      — mainBody.bodyName (or "")
  position  — active vessel local frame [x,y,z]
              (transform.InverseTransformPoint)

Server-side filter: skip Flag, EVA, Debris, Unknown, and the active
vessel itself. Clients derive distance / bearing from the local-frame
position vector — saves CPU on the server and keeps the math
one-sided.

Returns List<Dictionary<string, object>>; MiniJSON's
generic-collection encoder handles serialisation without a dedicated
formatter.
Companion to tar.availableVessels + tar.setTargetVessel: lets a
client switch active vessel directly without going through the
Tracking Station scene. Same operation as the in-game 'Fly' button
under the hood.

[TelemetryAPI("tar.switchVessel", IsAction = true)]
takes an integer vesselIndex matching tar.availableVessels.index,
saves the current vessel's mid-flight state to the persistent slot
(so switching back later restores it), then calls
FlightDriver.StartAndFocusVessel — the same internal entry point
the Tracking Station uses for 'Fly'.

Useful for dashboard widgets that want to provide a switch-active-
vessel control without the user navigating menus. Pairs with the
existing tar.availableVessels enumeration so the client knows what
indices are live.

Out-of-range and unparsable indices return false; the actual scene
change happens asynchronously (standard FlightDriver semantics).
@jonpepler jonpepler marked this pull request as ready for review May 29, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant