Engine API Reference
This document covers Engine client APIs added after the core reference was written. It is a companion to Engine/Client Usage, which covers connection lifecycle, data definitions, sim object requests, events, AI traffic, and facilities. Read that document first before using this one.
The APIs documented here are:
- Client Data Area — named shared memory regions for inter-add-on communication
- Input Event API — read and write MSFS 2024 input events by hash (MSFS 2024 only)
- SimObject and Livery Enumeration — list available aircraft models and their liveries
Client Data Area API
Client data areas are named shared memory regions that SimConnect clients use to exchange arbitrary binary data with each other. One add-on creates and owns the area; any other connected client can subscribe to updates. This is the standard SimConnect mechanism for inter-add-on communication.
See also: Client Data Areas for a full conceptual guide, field-by-field parameter tables, types reference, and a complete annotated example. This section summarises the API surface and provides a self-contained writer + reader example.
Interface note:
CreateClientData,AddToClientDataDefinition,RequestClientData, andSetClientDataare methods on*engine.Engine(returned byengine.New()). They are not part of theengine.Clientinterface returned bysimconnect.NewClient(). Useengine.New()directly when you need the Client Data Area API.
Setup workflow
A client data area is set up in four steps:
- Map name to ID — both writer and reader call
MapClientDataNameToIDwith the same string name. - Create the area — the writer calls
CreateClientDatato register the area size and access flags. Readers skip this step. - Define fields — both sides call
AddToClientDataDefinitionto describe the data layout. - Exchange data — the writer calls
SetClientDatato write; the reader callsRequestClientDatato subscribe.
MapClientDataNameToID
Associates a human-readable name with a numeric client data ID. The name must match on both sides.
err := client.MapClientDataNameToID("com.myaddon.channel", clientDataID)
Signature: MapClientDataNameToID(clientDataName string, clientDataID uint32) error
CreateClientData
Registers the area with SimConnect. Call only from the owning (writer) client.
err := client.CreateClientData(
clientDataID,
16, // size in bytes, max 8192
types.SIMCONNECT_CREATE_CLIENT_DATA_FLAG_DEFAULT,
)
Signature: CreateClientData(clientDataID uint32, dwSize uint32, flags types.SIMCONNECT_CREATE_CLIENT_DATA_FLAG) error
| Flag constant | Value | Meaning |
|---|---|---|
SIMCONNECT_CREATE_CLIENT_DATA_FLAG_DEFAULT |
0 |
Any client can write |
SIMCONNECT_CREATE_CLIENT_DATA_FLAG_READ_ONLY |
1 |
Only the creator can write |
The maximum area size is 8192 bytes. SimConnect returns an HRESULT error for any value outside the range 1–8192.
AddToClientDataDefinition
Adds a data field to a definition. Call multiple times to build composite layouts. Both the writer and the reader call this with the same defineID and offsets.
err := client.AddToClientDataDefinition(
defineID,
0, // byte offset within the area
uint32(types.SIMCONNECT_CLIENTDATATYPE_FLOAT64), // 8-byte float64
0, // epsilon: 0 = notify on any change
0, // datum ID: 0 for default mode
)
Signature: AddToClientDataDefinition(defineID uint32, dwOffset uint32, dwSizeOrType uint32, epsilon float32, datumID uint32) error
The dwSizeOrType parameter accepts either a raw byte count or one of the SIMCONNECT_CLIENTDATATYPE_* typed constants. The constants occupy the 0xFFFFFFFA–0xFFFFFFFF range; SimConnect distinguishes them from byte counts. Always cast the constant to uint32.
| Constant | Go type |
|---|---|
SIMCONNECT_CLIENTDATATYPE_INT8 |
int8 |
SIMCONNECT_CLIENTDATATYPE_INT16 |
int16 |
SIMCONNECT_CLIENTDATATYPE_INT32 |
int32 |
SIMCONNECT_CLIENTDATATYPE_INT64 |
int64 |
SIMCONNECT_CLIENTDATATYPE_FLOAT32 |
float32 |
SIMCONNECT_CLIENTDATATYPE_FLOAT64 |
float64 |
RequestClientData
Subscribes to updates. Use this on the reader side.
err := client.RequestClientData(
clientDataID,
requestID,
defineID,
types.SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET,
types.SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_DEFAULT,
0, 0, 0, // origin, interval, limit — 0 for defaults
)
Signature: RequestClientData(clientDataID uint32, requestID uint32, defineID uint32, period types.SIMCONNECT_CLIENT_DATA_PERIOD, flags types.SIMCONNECT_CLIENT_DATA_REQUEST_FLAG, origin uint32, interval uint32, limit uint32) error
Incoming data arrives as SIMCONNECT_RECV_ID_CLIENT_DATA. Cast with msg.AsClientData() and read the payload with engine.CastDataAs.
SetClientData
Writes data to the area. Use this on the writer side.
value := MyStruct{Field1: 15.5, Field2: 1013.25}
err := client.SetClientData(
clientDataID,
defineID,
0, // flags — always 0; SimConnect defines no enum for this
0, // dwReserved — must be 0
uint32(unsafe.Sizeof(value)),
unsafe.Pointer(&value),
)
Signature: SetClientData(clientDataID uint32, defineID uint32, flags uint32, dwReserved uint32, cbUnitSize uint32, data unsafe.Pointer) error
Note: The
flagsparameter is a plainuint32. SimConnect does not define a typed enum for it. Always pass0. ThedwReservedparameter must also always be0.
Complete example
The example below shows both sides of a shared data channel. The writer creates and populates a 16-byte area; the reader subscribes and prints values when they change.
//go:build windows
package main
import (
"fmt"
"os"
"os/signal"
"unsafe"
"github.com/mrlm-net/simconnect/pkg/engine"
"github.com/mrlm-net/simconnect/pkg/types"
)
// SharedData is the layout both sides agree on.
// 16 bytes total: two float64 fields at explicit offsets 0 and 8.
type SharedData struct {
TemperatureC float64 // offset 0
PressureHPa float64 // offset 8
}
const (
AreaID uint32 = 1000
DefID uint32 = 1001
ReqID uint32 = 1002
)
// writerSetup creates and writes the area.
// Call this from the add-on that owns the data.
func writerSetup(client *engine.Engine) {
client.MapClientDataNameToID("com.example.weather", AreaID)
client.CreateClientData(AreaID, uint32(unsafe.Sizeof(SharedData{})),
types.SIMCONNECT_CREATE_CLIENT_DATA_FLAG_DEFAULT)
client.AddToClientDataDefinition(DefID, 0,
uint32(types.SIMCONNECT_CLIENTDATATYPE_FLOAT64), 0, 0)
client.AddToClientDataDefinition(DefID, 8,
uint32(types.SIMCONNECT_CLIENTDATATYPE_FLOAT64), 0, 0)
data := SharedData{TemperatureC: 15.5, PressureHPa: 1013.25}
client.SetClientData(AreaID, DefID, 0, 0,
uint32(unsafe.Sizeof(data)), unsafe.Pointer(&data))
}
// readerSetup subscribes to the area.
// Call this from the add-on that reads the data.
func readerSetup(client *engine.Engine) {
client.MapClientDataNameToID("com.example.weather", AreaID)
client.AddToClientDataDefinition(DefID, 0,
uint32(types.SIMCONNECT_CLIENTDATATYPE_FLOAT64), 0, 0)
client.AddToClientDataDefinition(DefID, 8,
uint32(types.SIMCONNECT_CLIENTDATATYPE_FLOAT64), 0, 0)
client.RequestClientData(
AreaID, ReqID, DefID,
types.SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET,
types.SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_DEFAULT,
0, 0, 0,
)
}
func main() {
client := engine.New("WeatherReader")
if err := client.Connect(); err != nil {
panic(err)
}
defer client.Disconnect()
readerSetup(client)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
for {
select {
case <-sigChan:
return
case msg, ok := <-client.Stream():
if !ok {
return
}
switch types.SIMCONNECT_RECV_ID(msg.DwID) {
case types.SIMCONNECT_RECV_ID_CLIENT_DATA:
cd := msg.AsClientData()
if cd == nil || cd.DwRequestID != ReqID {
continue
}
data := engine.CastDataAs[SharedData](&cd.DwData)
fmt.Printf("Temperature: %.1f°C Pressure: %.1f hPa\n",
data.TemperatureC, data.PressureHPa)
case types.SIMCONNECT_RECV_ID_EXCEPTION:
if ex := msg.AsException(); ex != nil {
fmt.Printf("SimConnect exception: %d\n", ex.DwException)
}
}
}
}
}
Input Event API (MSFS 2024 only)
MSFS 2024 exclusive. The Input Event API requires Microsoft Flight Simulator 2024. All functions in this section will return HRESULT errors or produce undefined behaviour when called against MSFS 2020.
Input events are named simulator actions identified by a 64-bit hash. They replace the legacy key event model for cockpit and aircraft interactions in MSFS 2024. You query available events by name, then read or write their values using the hash.
Input events carry one of two value types, identified by SIMCONNECT_INPUT_EVENT_TYPE:
| Constant | Meaning |
|---|---|
SIMCONNECT_INPUT_EVENT_TYPE_DOUBLE |
Numeric value; read and written as float64 |
SIMCONNECT_INPUT_EVENT_TYPE_STRING |
Text value; up to 259 bytes, null-terminated |
EnumerateInputEvents
Requests a list of all available input events. Responses arrive as one or more SIMCONNECT_RECV_ID_ENUMERATE_INPUT_EVENTS messages; cast with msg.AsEnumerateInputEvents().
err := client.EnumerateInputEvents(requestID)
Signature: EnumerateInputEvents(requestID uint32) error
Each response message contains a RgData array of SIMCONNECT_INPUT_EVENT_DESCRIPTOR elements:
if recv := msg.AsEnumerateInputEvents(); recv != nil {
// DwArraySize tells you how many descriptors are in this batch
count := recv.DwArraySize
_ = count
// Access descriptors at &recv.RgData[0] through &recv.RgData[count-1]
name := engine.BytesToString(recv.RgData[0].Name[:])
fmt.Println("Event:", name)
}
SIMCONNECT_INPUT_EVENT_DESCRIPTOR fields:
| Field | Type | Description |
|---|---|---|
Name |
[64]byte |
Human-readable event name, null-terminated |
Hash |
DWORD |
32-bit hash (use GetInputEvent/SetInputEvent with the full uint64 hash from subscription) |
Type |
SIMCONNECT_DATATYPE |
Data type of the event value |
NodeNames |
[1024]byte |
Associated node names, null-separated |
GetInputEvent
Requests the current value of a single input event identified by its 64-bit hash. The response arrives as SIMCONNECT_RECV_ID_GET_INPUT_EVENT; cast with msg.AsGetInputEvent().
err := client.GetInputEvent(requestID, hash)
Signature: GetInputEvent(requestID uint32, hash uint64) error
Read the response value using the engine helpers:
if recv := msg.AsGetInputEvent(); recv != nil && recv.RequestID == requestID {
if f, ok := engine.InputEventValueAsFloat64(recv); ok {
fmt.Printf("Value: %f\n", f)
}
if s, ok := engine.InputEventValueAsString(recv); ok {
fmt.Printf("Value: %s\n", s)
}
}
| Helper | Signature | Returns |
|---|---|---|
InputEventValueAsFloat64 |
(recv *types.SIMCONNECT_RECV_GET_INPUT_EVENT) (float64, bool) |
Value and true when type is DOUBLE; (0, false) otherwise |
InputEventValueAsString |
(recv *types.SIMCONNECT_RECV_GET_INPUT_EVENT) (string, bool) |
Value and true when type is STRING; ("", false) otherwise |
SetInputEvent
Writes a value to an input event. Two typed variants exist:
// Write a numeric value
err := client.SetInputEventDouble(hash, 1.0)
// Write a string value (truncated to 259 bytes if longer)
err := client.SetInputEventString(hash, "some-value")
Signatures:
SetInputEventDouble(hash uint64, value float64) errorSetInputEventString(hash uint64, value string) error
There is no response message for SetInputEvent. HRESULT errors are returned directly.
SubscribeInputEvent
Subscribes to change notifications for a specific input event identified by hash. Notifications arrive as SIMCONNECT_RECV_ID_SUBSCRIBE_INPUT_EVENT messages; cast with msg.AsSubscribeInputEvent().
err := client.SubscribeInputEvent(hash)
Signature: SubscribeInputEvent(hash uint64) error
Read subscription notifications using the engine helpers:
if recv := msg.AsSubscribeInputEvent(); recv != nil {
eventHash := engine.SubscribeInputEventHash(recv)
if f, ok := engine.SubscribeInputEventValueAsFloat64(recv); ok {
fmt.Printf("Hash %d changed to %f\n", eventHash, f)
}
if s, ok := engine.SubscribeInputEventValueAsString(recv); ok {
fmt.Printf("Hash %d changed to %s\n", eventHash, s)
}
}
Note:
SIMCONNECT_RECV_SUBSCRIBE_INPUT_EVENT.HashBytesis stored as[8]byterather thanuint64to avoid Go alignment padding at wire offset 12. Useengine.SubscribeInputEventHash(recv)rather than readingHashBytesdirectly.
| Helper | Signature | Returns |
|---|---|---|
SubscribeInputEventHash |
(recv *types.SIMCONNECT_RECV_SUBSCRIBE_INPUT_EVENT) uint64 |
Event hash |
SubscribeInputEventValueAsFloat64 |
(recv *types.SIMCONNECT_RECV_SUBSCRIBE_INPUT_EVENT) (float64, bool) |
Value and true when type is DOUBLE |
SubscribeInputEventValueAsString |
(recv *types.SIMCONNECT_RECV_SUBSCRIBE_INPUT_EVENT) (string, bool) |
Value and true when type is STRING |
UnsubscribeInputEvent
Cancels a previous subscription.
err := client.UnsubscribeInputEvent(hash)
Signature: UnsubscribeInputEvent(hash uint64) error
Input Event example
//go:build windows
package main
import (
"fmt"
"os"
"os/signal"
"github.com/mrlm-net/simconnect/pkg/engine"
"github.com/mrlm-net/simconnect/pkg/types"
)
const EnumReqID uint32 = 2000
func main() {
client := engine.New("InputEventDemo")
if err := client.Connect(); err != nil {
panic(err)
}
defer client.Disconnect()
// Step 1: enumerate all available input events
if err := client.EnumerateInputEvents(EnumReqID); err != nil {
panic(err)
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
var subscribedHash uint64
for {
select {
case <-sigChan:
if subscribedHash != 0 {
client.UnsubscribeInputEvent(subscribedHash)
}
return
case msg, ok := <-client.Stream():
if !ok {
return
}
switch types.SIMCONNECT_RECV_ID(msg.DwID) {
case types.SIMCONNECT_RECV_ID_ENUMERATE_INPUT_EVENTS:
recv := msg.AsEnumerateInputEvents()
if recv == nil {
continue
}
name := engine.BytesToString(recv.RgData[0].Name[:])
fmt.Printf("Found input event: %s\n", name)
// Subscribe to the first event found
if subscribedHash == 0 {
// hash stored as uint32 in descriptor; cast for subscribe call
subscribedHash = uint64(recv.RgData[0].Hash)
client.SubscribeInputEvent(subscribedHash)
}
case types.SIMCONNECT_RECV_ID_SUBSCRIBE_INPUT_EVENT:
recv := msg.AsSubscribeInputEvent()
if recv == nil {
continue
}
hash := engine.SubscribeInputEventHash(recv)
if f, ok := engine.SubscribeInputEventValueAsFloat64(recv); ok {
fmt.Printf("Event hash %d changed: %f\n", hash, f)
}
if s, ok := engine.SubscribeInputEventValueAsString(recv); ok {
fmt.Printf("Event hash %d changed: %s\n", hash, s)
}
}
}
}
}
SimObject and Livery Enumeration
EnumerateSimObjectsAndLiveries requests a list of available aircraft models (or other object types) and their installed liveries. This is useful for building traffic injection tools or aircraft selection UIs that need to know what models the simulator has loaded.
EnumerateSimObjectsAndLiveries
err := client.EnumerateSimObjectsAndLiveries(requestID, types.SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT)
Signature: EnumerateSimObjectsAndLiveries(requestID uint32, objectType types.SIMCONNECT_SIMOBJECT_TYPE) error
objectType constant |
Description |
|---|---|
SIMCONNECT_SIMOBJECT_TYPE_USER |
The user aircraft |
SIMCONNECT_SIMOBJECT_TYPE_ALL |
All object types |
SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT |
Fixed-wing aircraft |
SIMCONNECT_SIMOBJECT_TYPE_HELICOPTER |
Helicopters and rotorcraft |
SIMCONNECT_SIMOBJECT_TYPE_BOAT |
Boats |
SIMCONNECT_SIMOBJECT_TYPE_GROUND |
Ground vehicles |
Responses arrive as one or more SIMCONNECT_RECV_ID_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST messages. Cast each message with msg.AsSimObjectAndLiveryEnumeration().
AsSimObjectAndLiveryEnumeration
if recv := msg.AsSimObjectAndLiveryEnumeration(); recv != nil {
for _, item := range recv.RgData {
title := engine.BytesToString(item.AircraftTitle[:])
livery := engine.BytesToString(item.LiveryName[:])
fmt.Printf("Model: %s Livery: %s\n", title, livery)
}
}
SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST embeds SIMCONNECT_RECV_LIST_TEMPLATE, which provides pagination fields:
| Field | Type | Description |
|---|---|---|
DwRequestID |
DWORD |
Matches the requestID passed to EnumerateSimObjectsAndLiveries |
DwArraySize |
DWORD |
Number of entries in this response batch |
DwEntryNumber |
DWORD |
Zero-based index of the first entry in this batch |
DwOutOf |
DWORD |
Total number of entries across all batches |
RgData |
[]SIMCONNECT_ENUMERATE_SIMOBJECT_LIVERY |
Entry slice for this batch |
Each SIMCONNECT_ENUMERATE_SIMOBJECT_LIVERY element has two fields:
| Field | Type | Description |
|---|---|---|
AircraftTitle |
[256]byte |
Container title (matches the title in aircraft.cfg) |
LiveryName |
[256]byte |
Livery name, or empty if the model has no separate liveries |
Use engine.BytesToString to convert the null-terminated byte arrays to Go strings.
Enumeration example
//go:build windows
package main
import (
"fmt"
"os"
"os/signal"
"github.com/mrlm-net/simconnect/pkg/engine"
"github.com/mrlm-net/simconnect/pkg/types"
)
const EnumReqID uint32 = 3000
func main() {
client := engine.New("LiveryEnum")
if err := client.Connect(); err != nil {
panic(err)
}
defer client.Disconnect()
if err := client.EnumerateSimObjectsAndLiveries(
EnumReqID,
types.SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT,
); err != nil {
panic(err)
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
for {
select {
case <-sigChan:
return
case msg, ok := <-client.Stream():
if !ok {
return
}
if types.SIMCONNECT_RECV_ID(msg.DwID) != types.SIMCONNECT_RECV_ID_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST {
continue
}
recv := msg.AsSimObjectAndLiveryEnumeration()
if recv == nil || recv.DwRequestID != EnumReqID {
continue
}
for _, item := range recv.RgData {
title := engine.BytesToString(item.AircraftTitle[:])
livery := engine.BytesToString(item.LiveryName[:])
fmt.Printf("%-60s %s\n", title, livery)
}
// Stop after receiving the last batch
if recv.DwEntryNumber+recv.DwArraySize >= recv.DwOutOf {
fmt.Printf("Total: %d entries\n", recv.DwOutOf)
return
}
}
}
}
Message Helpers Reference
Every incoming Message from client.Stream() carries a DwID field identifying the message type. The helper methods on Message cast the raw pointer to a typed struct. All helpers return nil when DwID does not match the expected SIMCONNECT_RECV_ID.
| Method | SIMCONNECT_RECV_ID checked |
Return type |
|---|---|---|
AsOpen() |
SIMCONNECT_RECV_ID_OPEN |
*types.SIMCONNECT_RECV_OPEN |
AsException() |
SIMCONNECT_RECV_ID_EXCEPTION |
*types.SIMCONNECT_RECV_EXCEPTION |
AsEvent() |
SIMCONNECT_RECV_ID_EVENT |
*types.SIMCONNECT_RECV_EVENT |
AsEventFrame() |
SIMCONNECT_RECV_ID_EVENT_FRAME |
*types.SIMCONNECT_RECV_EVENT_FRAME |
AsEventFilename() |
SIMCONNECT_RECV_ID_EVENT_FILENAME |
*types.SIMCONNECT_RECV_EVENT_FILENAME |
AsEventObjectAddRemove() |
SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE |
*types.SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE |
AsSimObjectData() |
SIMCONNECT_RECV_ID_SIMOBJECT_DATA |
*types.SIMCONNECT_RECV_SIMOBJECT_DATA |
AsSimObjectDataBType() |
SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE |
*types.SIMCONNECT_RECV_SIMOBJECT_DATA_BTYPE |
AsClientData() |
SIMCONNECT_RECV_ID_CLIENT_DATA |
*types.SIMCONNECT_RECV_CLIENT_DATA |
AsAssignedObjectID() |
SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID |
*types.SIMCONNECT_RECV_ASSIGNED_OBJECT_ID |
AsFacilityData() |
SIMCONNECT_RECV_ID_FACILITY_DATA |
*types.SIMCONNECT_RECV_FACILITY_DATA |
AsFacilityDataEnd() |
SIMCONNECT_RECV_ID_FACILITY_DATA_END |
*types.SIMCONNECT_RECV_FACILITY_DATA_END |
AsFacilityList() |
AIRPORT_LIST, VOR_LIST, NDB_LIST, or WAYPOINT_LIST |
*types.SIMCONNECT_RECV_FACILITIES_LIST |
AsAirportList() |
SIMCONNECT_RECV_ID_AIRPORT_LIST |
*types.SIMCONNECT_RECV_AIRPORT_LIST |
AsNDBList() |
SIMCONNECT_RECV_ID_NDB_LIST |
*types.SIMCONNECT_RECV_NDB_LIST |
AsVORList() |
SIMCONNECT_RECV_ID_VOR_LIST |
*types.SIMCONNECT_RECV_VOR_LIST |
AsWaypointList() |
SIMCONNECT_RECV_ID_WAYPOINT_LIST |
*types.SIMCONNECT_RECV_WAYPOINT_LIST |
AsSimObjectAndLiveryEnumeration() |
SIMCONNECT_RECV_ID_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST |
*types.SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST |
AsEnumerateInputEvents() |
SIMCONNECT_RECV_ID_ENUMERATE_INPUT_EVENTS |
*types.SIMCONNECT_RECV_ENUMERATE_INPUT_EVENTS |
AsGetInputEvent() |
SIMCONNECT_RECV_ID_GET_INPUT_EVENT |
*types.SIMCONNECT_RECV_GET_INPUT_EVENT |
AsSubscribeInputEvent() |
SIMCONNECT_RECV_ID_SUBSCRIBE_INPUT_EVENT |
*types.SIMCONNECT_RECV_SUBSCRIBE_INPUT_EVENT |
AsFlowEvent() |
SIMCONNECT_RECV_ID_FLOW_EVENT |
*types.SIMCONNECT_RECV_FLOW_EVENT |
Note:
AsEnumerateInputEvents(),AsGetInputEvent(),AsSubscribeInputEvent(), andAsFlowEvent()are MSFS 2024 only. Calling them against MSFS 2020 will always returnnilbecause the simulator never sends the correspondingDwIDvalues.
See Also
- Engine/Client Usage — Core client API: connection, data definitions, sim object requests, events, facilities, and AI traffic
- Client Data Areas — Full conceptual guide and parameter reference for the Client Data Area API
- Manager Usage — Automatic connection lifecycle management with auto-reconnect