Skip to content

Engine/Client Usage

The engine package provides a high-level client for interacting with SimConnect. This document covers the complete API for direct simulator communication.

See also: Configuration Options for all available options when creating a client.

Creating a Client

Using the Root Package

import "github.com/mrlm-net/simconnect"

client := simconnect.NewClient("MyApp")

Using the Engine Package Directly

import "github.com/mrlm-net/simconnect/pkg/engine"

client := engine.New("MyApp")

Connection Lifecycle

Connect

Establishes a connection to the SimConnect server.

if err := client.Connect(); err != nil {
    log.Fatal("Failed to connect:", err)
}

Disconnect

Gracefully closes the connection and releases resources.

defer client.Disconnect()

Stream

Returns a read-only channel for receiving SimConnect messages.

stream := client.Stream()
for msg := range stream {
    // Handle incoming messages
}

Data Definitions

Data definitions describe the structure of data you want to receive from or send to the simulator.

AddToDataDefinition

Adds a variable to a data definition. Call multiple times to build composite definitions.

import "github.com/mrlm-net/simconnect/pkg/types"

// Define aircraft position data
const PositionDefID = 1000

client.AddToDataDefinition(
    PositionDefID,
    "PLANE LATITUDE",
    "degrees",
    types.SIMCONNECT_DATATYPE_FLOAT64,
    0,    // epsilon (change threshold)
    0,    // datum ID
)
client.AddToDataDefinition(
    PositionDefID,
    "PLANE LONGITUDE",
    "degrees",
    types.SIMCONNECT_DATATYPE_FLOAT64,
    0, 0,
)
client.AddToDataDefinition(
    PositionDefID,
    "PLANE ALTITUDE",
    "feet",
    types.SIMCONNECT_DATATYPE_FLOAT64,
    0, 0,
)

ClearDataDefinition

Removes a previously created data definition.

client.ClearDataDefinition(PositionDefID)

RegisterDataset

Registers a pre-built dataset from the datasets package.

import "github.com/mrlm-net/simconnect/pkg/datasets/aircraft"

client.RegisterDataset(PositionDefID, aircraft.Position)

RegisterFacilityDataset

Registers a pre-built facility dataset from the datasets/facilities package. Unlike RegisterDataset which uses AddToDataDefinition, this uses AddToFacilityDefinition internally.

import "github.com/mrlm-net/simconnect/pkg/datasets/facilities"

client.RegisterFacilityDataset(AirportDefID, facilities.NewAirportFacilityDataset())
client.RegisterFacilityDataset(RunwayDefID, facilities.NewRunwayFacilityDataset())
client.RegisterFacilityDataset(ParkingDefID, facilities.NewParkingFacilityDataset())
client.RegisterFacilityDataset(FrequencyDefID, facilities.NewFrequencyFacilityDataset())

Available facility dataset constructors in pkg/datasets/facilities:

Constructor Data
NewAirportFacilityDataset() Airport info (name, ICAO, position, tower, transition)
NewRunwayFacilityDataset() Runway dimensions, heading, surface, lighting
NewParkingFacilityDataset() Parking spots, gates, ramps
NewFrequencyFacilityDataset() COM/NAV frequencies
NewTaxiPointFacilityDataset() Taxiway intersection points
NewTaxiPathFacilityDataset() Taxiway paths and routes
NewTaxiNameFacilityDataset() Taxiway names
NewHelipadFacilityDataset() Helipad locations and properties
NewJetwayFacilityDataset() Jetway data
NewDepartureFacilityDataset() SID procedures
NewApproachFacilityDataset() Approach procedures
NewVORFacilityDataset() VOR navaid data
NewNDBFacilityDataset() NDB navaid data
NewWaypointFacilityDataset() Waypoint data

Requesting Data

RequestDataOnSimObject

Requests data for a specific sim object with optional periodic updates.

const PositionReqID = 1001

// Request once
client.RequestDataOnSimObject(
    PositionReqID,
    PositionDefID,
    types.SIMCONNECT_OBJECT_ID_USER,     // User aircraft
    types.SIMCONNECT_PERIOD_ONCE,        // Single request
    types.SIMCONNECT_DATA_REQUEST_FLAG_DEFAULT,
    0, 0, 0,
)

// Request every second
client.RequestDataOnSimObject(
    PositionReqID,
    PositionDefID,
    types.SIMCONNECT_OBJECT_ID_USER,
    types.SIMCONNECT_PERIOD_SECOND,
    types.SIMCONNECT_DATA_REQUEST_FLAG_CHANGED,  // Only when changed
    0, 0, 0,
)

RequestDataOnSimObjectType

Requests data for all objects of a specific type within a radius.

// Get all aircraft within 50 nautical miles
client.RequestDataOnSimObjectType(
    TrafficReqID,
    TrafficDefID,
    50 * 1852,  // Radius in meters (50nm)
    types.SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT,
)

SetDataOnSimObject

Sends data to the simulator to modify object state.

type AircraftPosition struct {
    Latitude  float64
    Longitude float64
    Altitude  float64
}

pos := AircraftPosition{
    Latitude:  47.4647,
    Longitude: -122.3078,
    Altitude:  10000,
}

client.SetDataOnSimObject(
    PositionDefID,
    types.SIMCONNECT_OBJECT_ID_USER,
    types.SIMCONNECT_DATA_SET_FLAG_DEFAULT,
    0,
    unsafe.Sizeof(pos),
    &pos,
)

Processing Messages

Message Structure

The Stream() channel returns Message structs containing the raw SimConnect data.

type Message struct {
    DwSize    uint32  // Size of the message
    DwVersion uint32  // Protocol version
    DwID      uint32  // Message type (SIMCONNECT_RECV_ID)
    Raw       []byte  // Raw message data
}

Casting Message Data

Use CastDataAs to convert raw data to typed structs:

type AircraftPosition struct {
    Latitude  float64
    Longitude float64
    Altitude  float64
}

for msg := range client.Stream() {
    switch types.SIMCONNECT_RECV_ID(msg.DwID) {
    case types.SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
        data := msg.AsSimObjectData()
        if data.DwRequestID == PositionReqID {
            pos := engine.CastDataAs[AircraftPosition](&data.DwData)
            fmt.Printf("Position: %.4f, %.4f @ %.0fft\n",
                pos.Latitude, pos.Longitude, pos.Altitude)
        }
    }
}

Signature: func CastDataAs[T any](dwData *types.DWORD) *T

The struct layout must exactly match the SimConnect data definition order and types. Use float64 for SIMCONNECT_DATATYPE_FLOAT64, int32/uint32 for INT32, and fixed-size byte arrays for strings ([256]byte for STRING256).

Message Type Methods

The Message struct provides helper methods to cast to specific types:

Method Returns Use Case
AsOpen() Connection open data Initial connection info
AsQuit() Quit notification Simulator shutdown
AsException() Exception details Error handling
AsEvent() Event data System events
AsEventEx1() Extended event data Extended event info
AsSimObjectData() Object data Data definition responses
AsSimObjectDataByType() Object type data Type-based queries
AsFacilityData() Facility data Airport/waypoint info
AsFacilitiesList() Facilities list Facility enumerations
AsAssignedObjectId() Assigned ID AI object creation

Parsing Strings

SimConnect returns null-terminated strings. Use ParseNullTerminatedString to convert:

title := engine.ParseNullTerminatedString(data.SzTitle[:])

System State

RequestSystemState

Requests simulator system state information.

client.RequestSystemState(
    StateReqID,
    types.SIMCONNECT_SYSTEM_STATE_SIM,  // Simulation running state
)

Response arrives as SIMCONNECT_RECV_ID_SYSTEM_STATE message.

Events

SubscribeToSystemEvent

Subscribes to simulator system events.

const PauseEventID = 2000

client.SubscribeToSystemEvent(PauseEventID, "Pause")
client.SubscribeToSystemEvent(2001, "Sim")
client.SubscribeToSystemEvent(2002, "SimStart")
client.SubscribeToSystemEvent(2003, "SimStop")

UnsubscribeFromSystemEvent

Removes a system event subscription.

client.UnsubscribeFromSystemEvent(PauseEventID)

MapClientEventToSimEvent

Maps a client event ID to a simulator event name.

const GearToggleEventID = 3000

client.MapClientEventToSimEvent(GearToggleEventID, "GEAR_TOGGLE")

TransmitClientEvent

Sends an event to the simulator.

// Toggle landing gear
client.TransmitClientEvent(
    types.SIMCONNECT_OBJECT_ID_USER,
    GearToggleEventID,
    0,  // Event data
    types.SIMCONNECT_GROUP_PRIORITY_HIGHEST,
    types.SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY,
)

TransmitClientEventEx1

Extended version with additional data parameters.

client.TransmitClientEventEx1(
    types.SIMCONNECT_OBJECT_ID_USER,
    eventID,
    types.SIMCONNECT_GROUP_PRIORITY_HIGHEST,
    types.SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY,
    data0, data1, data2, data3, data4,
)

Notification Groups

AddClientEventToNotificationGroup

Groups events for priority-based handling.

const FlightControlsGroup = 4000

client.AddClientEventToNotificationGroup(
    FlightControlsGroup,
    GearToggleEventID,
    false,  // maskable
)

SetNotificationGroupPriority

Sets the priority for a notification group.

client.SetNotificationGroupPriority(
    FlightControlsGroup,
    types.SIMCONNECT_GROUP_PRIORITY_HIGHEST,
)

ClearNotificationGroup

Removes all events from a notification group.

client.ClearNotificationGroup(FlightControlsGroup)

AI Traffic

AICreateParkedATCAircraft

Creates an AI aircraft parked at an airport.

client.AICreateParkedATCAircraft(
    "Airbus A320 Neo Asobo",
    "N12345",
    "KSEA",      // ICAO code
    CreateReqID,
)

AICreateEnrouteATCAircraft

Creates an AI aircraft following a flight plan.

client.AICreateEnrouteATCAircraft(
    "Boeing 747-8 Asobo",
    "UAL123",
    0,                    // Flight number
    "KSEA_KLAX.pln",      // Flight plan file
    0.5,                  // Progress (0.0-1.0)
    false,                // Ground clamped
    CreateReqID,
)

AISetAircraftFlightPlan

Assigns a flight plan to an existing AI aircraft.

client.AISetAircraftFlightPlan(
    objectID,
    "KSEA_KLAX.pln",
    FlightPlanReqID,
)

AIRemoveObject

Removes an AI object from the simulation.

client.AIRemoveObject(objectID, RemoveReqID)

AIReleaseControl

Releases control of an AI object back to the simulator.

client.AIReleaseControl(objectID, ReleaseReqID)

AICreateNonATCAircraft

Creates a non-ATC-controlled aircraft at a specific position.

initPos := types.SIMCONNECT_DATA_INITPOSITION{
    Latitude:  47.4502,
    Longitude: -122.3088,
    Altitude:  5000,
    Pitch:     0,
    Bank:      0,
    Heading:   270,
    OnGround:  0,
    Airspeed:  120,
}
client.AICreateNonATCAircraft("Cessna Skyhawk Asobo", "N12345", initPos, CreateReqID)

AICreateSimulatedObject

Creates a non-aircraft simulated object (ground vehicle, boat, etc.).

client.AICreateSimulatedObject("Generic Ground Vehicle", initPos, CreateReqID)

EX1 Variants (Livery Selection)

The EX1 variants of AI creation methods add a livery parameter:

client.AICreateParkedATCAircraftEX1("Boeing 787-10 Asobo", "House", "N12345", "KSEA", ReqID)
client.AICreateEnrouteATCAircraftEX1("Airbus A320 Neo Asobo", "Asobo", "UAL123", 0, "plan.pln", 0.5, false, ReqID)
client.AICreateNonATCAircraftEX1("Cessna Skyhawk Asobo", "Blue", "N12345", initPos, ReqID)

EnumerateSimObjectsAndLiveries

Lists available aircraft/objects and their liveries.

client.EnumerateSimObjectsAndLiveries(EnumReqID, types.SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT)

Facilities

RequestFacilitiesList

Requests a list of facilities (airports, waypoints, etc.).

client.RequestFacilitiesList(
    types.SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT,
    FacilitiesReqID,
)

RequestFacilityData

Requests detailed data for a specific facility.

client.RequestFacilityData(
    FacilityDefID,
    FacilityDataReqID,
    "KSEA",
    "",  // Region (optional)
    types.SIMCONNECT_FACILITY_DATA_AIRPORT,
)

RequestFacilityDataEX1

Extended version that explicitly specifies the facility type.

client.RequestFacilityDataEX1(
    FacilityDefID,
    FacilityDataReqID,
    "KSEA",
    "",                                        // Region (optional)
    types.SIMCONNECT_FACILITY_DATA_AIRPORT,    // Explicit facility type
)

RequestJetwayData

Requests jetway data for a specific airport.

indexes := []int32{0, 1, 2}
client.RequestJetwayData("KSEA", uint32(len(indexes)), &indexes[0])

RequestAllFacilities

Requests all facilities of a specific type.

client.RequestAllFacilities(
    types.SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT,
    AllFacilitiesReqID,
)

SubscribeToFacilitiesEX1

Extended subscription with separate request IDs for facilities entering and leaving range.

client.SubscribeToFacilitiesEX1(
    types.SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT,
    NewInRangeReqID,
    OldOutRangeReqID,
)

AddFacilityDataDefinitionFilter

Filters facility data requests.

client.AddFacilityDataDefinitionFilter(
    FacilityDefID,
    "filterPath",
    filterDataPtr,
    filterDataSize,
)

ClearAllFacilityDataDefinitionFilters

Removes all filters from a facility definition.

client.ClearAllFacilityDataDefinitionFilters(FacilityDefID)

SubscribeToFacilities

Subscribes to facility updates within a radius.

client.SubscribeToFacilities(
    types.SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT,
    FacilitySubReqID,
)

AddToFacilityDefinition

Defines the data fields to receive for facilities.

client.AddToFacilityDefinition(FacilityDefID, "OPEN AIRPORT")
client.AddToFacilityDefinition(FacilityDefID, "NAME")
client.AddToFacilityDefinition(FacilityDefID, "LATITUDE")
client.AddToFacilityDefinition(FacilityDefID, "LONGITUDE")

Flight Operations

FlightLoad

Loads a saved flight file.

client.FlightLoad("C:/Users/Pilot/Flights/MyFlight.flt")

FlightPlanLoad

Loads a flight plan file.

client.FlightPlanLoad("C:/Users/Pilot/FlightPlans/KSEA_KLAX.pln")

FlightSave

Saves the current flight state.

client.FlightSave(
    "C:/Users/Pilot/Flights/SavedFlight.flt",
    "My Saved Flight",
    "Saved at KSEA runway 16L",
)

Example: Complete Data Loop

package main

import (
    "fmt"
    "os"
    "os/signal"

    "github.com/mrlm-net/simconnect/pkg/engine"
    "github.com/mrlm-net/simconnect/pkg/types"
)

type AircraftData struct {
    Latitude  float64
    Longitude float64
    Altitude  float64
    Heading   float64
}

const (
    DataDefID = 1000
    DataReqID = 1001
)

func main() {
    client := engine.New("DataLoop")

    if err := client.Connect(); err != nil {
        panic(err)
    }
    defer client.Disconnect()

    // Define data structure
    client.AddToDataDefinition(DataDefID, "PLANE LATITUDE", "degrees", types.SIMCONNECT_DATATYPE_FLOAT64, 0, 0)
    client.AddToDataDefinition(DataDefID, "PLANE LONGITUDE", "degrees", types.SIMCONNECT_DATATYPE_FLOAT64, 0, 0)
    client.AddToDataDefinition(DataDefID, "PLANE ALTITUDE", "feet", types.SIMCONNECT_DATATYPE_FLOAT64, 0, 0)
    client.AddToDataDefinition(DataDefID, "PLANE HEADING DEGREES TRUE", "degrees", types.SIMCONNECT_DATATYPE_FLOAT64, 0, 0)

    // Request periodic updates
    client.RequestDataOnSimObject(
        DataReqID, DataDefID,
        types.SIMCONNECT_OBJECT_ID_USER,
        types.SIMCONNECT_PERIOD_SECOND,
        types.SIMCONNECT_DATA_REQUEST_FLAG_CHANGED,
        0, 0, 0,
    )

    // Handle shutdown
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, os.Interrupt)

    stream := client.Stream()
    for {
        select {
        case <-sigChan:
            fmt.Println("Shutting down...")
            return
        case msg, ok := <-stream:
            if !ok {
                return
            }
            if types.SIMCONNECT_RECV_ID(msg.DwID) == types.SIMCONNECT_RECV_ID_SIMOBJECT_DATA {
                data := msg.AsSimObjectData()
                if data.DwRequestID == DataReqID {
                    aircraft := engine.CastDataAs[AircraftData](&data.DwData)
                    fmt.Printf("Pos: %.4f, %.4f | Alt: %.0fft | Hdg: %.1f°\n",
                        aircraft.Latitude, aircraft.Longitude,
                        aircraft.Altitude, aircraft.Heading)
                }
            }
        }
    }
}

See Also