1. Overview
OpenSROutSimData.h (Abstract)
typedef struct OutSimData {
// general info, status and flags
PacketHeader_t mPacketHeader; // size 32
PlayerRecords_t mPlayers;
MotionData_t mMotionData;
SessionData_t mSessionData;
VehicleData_t mVehicleData;
WheelData_t mWheelData;
} OutSimData; //full struct in OutData.h
static_assert(sizeof(OutSimData) == 67296/*SumOfSubs*/, "OutSimData bytes size / alignment is incorrect");
#pragma pack(pop)OpenSRInSimData.h
#pragma pack(push, 1)
//--------------------------------------
// IN PacketHeader (32 bytes aligned)
//--------------------------------------
struct INPacketHeader {
uint8_t reportAvailable; // true as soon as this struct is ready to be parsed by the manager
uint8_t majorVersion; // 1
uint8_t minorVersion; // 0
uint8_t spare[29]; // Align to 32 bytes
};
static_assert(sizeof(PacketHeader_t) == 32, "PacketHeader must be 32 bytes");
//--------------------------------------
// InSimData
//--------------------------------------
typedef struct _ReportIn {
int8_t axis[8]; // 8 axes, analog pot
uint8_t button[8]; // 64 buttons 8x8
uint8_t hat[2]; // 2 hat
uint16_t swt[8]; // 8 switch pos. 1 to 12, axis converted to switch
} ReportIn;
struct InSimData {
INPacketHeader mInPacketHeader; // usage in network protocol like UDP
ReportIn mPeportIn;
}; //full struct in inSimData.h
#pragma pack(pop)OpenSR uses a state-based data model, not an event or delta model.
- IN plugins write full telemetry state (
OutSimData) - OUT plugins read full state and optionally write input state (
InSimData) - The host guarantees coherency at frame submission time
2. OutSimData (Telemetry)
2.1 Data Nature
OutSimData is state-based (absolute).
Each submitted frame represents:
- the current full state of the simulation
- not a delta from previous frame
Implication:
- Fields may:
- remain unchanged between frames
- or be updated selectively
- The host ensures:
- the structure is considered valid as a whole at submission time
2.2 Frame Integrity
Each frame includes:
PacketHeader_t mPacketHeader;
Important fields:
frameId→ assigned by host (read-only for plugins)frameRateFromGame→ provided by pluginpacketType→ identifies data categoryreportAvailable→ signals readiness- playerSlotIndex → (IMPORTANT) slot index of local car in player records [] array
- paused → game paused true or false (player in or out car)
typedef struct PacketHeader_t {
uint8_t reportAvailable; // true as soon as this struct is ready to be parsed by the Manager
uint8_t paused; // sim paused true or false (Player in or out car)
uint64_t elapsedTime; // Seconds
uint64_t frameId; // [READ ONLY] Incrementing frame ID reference, incremented on send packet to network
uint32_t frameRateFromGame; // frame rate from game telemetry
uint8_t majorVersion; // 1
uint8_t minorVersion; // 0 (minor change is backward compatible with the existing struct)
uint8_t packetType; // Type: 0 MotionData, 1 VehicleStateData, etc. see dataType
uint8_t packetIndex; // current packet index (only used for dtPlayersData)
uint8_t playerSlotIndex; // slot index of local car in player records [] array
uint8_t _padding[5]; // padding
} PacketHeader_t; 2.3 Update Model
- Plugin fills structure progressively
- When ready:
- calls
submitFrameCallback
- calls
- Host:
- locks the frame as a valid snapshot
- distributes to OUT plugins
2.4 Key Principle
A submitted frame represents a coherent snapshot, even if only part of the data changed.
3. InSimData (Input System)
3.1 Conceptual Model
InSimData behaves like a HID input report.
It is:
- state-based
- continuous
- independent from frame timing
3.2 Structure
typedef struct _ReportIn {
int8_t axis[8];
uint8_t button[8];
uint8_t hat[2];
uint16_t swt[8];
} ReportIn;
3.3 Input Behavior
Buttons:
- Represent state (pressed / released)
- Example:
- Press → value = 1
- Hold → stays 1
- Release → value = 0
Axes:
- Analog values (range depends on implementation)
- Not strictly normalized
- Defined by device/plugin behavior
Hats:
- Directional inputs (discrete states)
Switches:
- Multi-position inputs (e.g., rotary switches)
3.4 Persistence Rule
Inputs must persist as long as active:
If a user holds a button, the plugin must continuously report it as active.
This is not event-based.
3.5 Independence from Frames
- Input updates are:
- not tied to telemetry frames
- not tied to
submitFrameCallback
- OUT plugins update inputs:
- whenever device state changes
- in their own loop
4. PacketHeader (Common Concept)
Both InSimData and OutSimData include a header:
uint8_t reportAvailable;
Meaning:
- Indicates that data is ready to be processed
Usage:
- IN: Always set the reportAvailable when your plugin is ready to process game telemetry
- OUT: Always check reportAvailable before reading the data
5. Normalization Rules
Important:
There is no strict universal normalization enforced.
Instead:
- Values are defined by:
- field type
- plugin implementation
- device characteristics
Examples:
- Axis → device-dependent range
- Button → binary (0 / 1)
- Switch → discrete positions
Recommended: all IN plugins must convert telemetry into the OpenSR standard coordinate system before writing to shared memory. This ensures OUT plugins work across all games without adaptation.
Axes definition
X > Right (positive = passenger side)
Y > Up (positive = roof)
Z > Forward (positive = nose)
Right-handed system
Units
- Position / displacement ? meters (m)
- Velocity ? meters per second (m/s)
- Acceleration ? meters per second² (m/s²)
- Angular velocity ? radians per second (rad/s)
- Angular acceleration ? radians per second² (rad/s²)
- Orientation ? quaternion
(w,x,y,z)or 3×3 rotation matrix, right-handed
World vs Local
- World-space vectors: position, world velocity, world accel (for map/overlay OUT plugins).
- Local (vehicle) vectors: velocity, acceleration, angular velocity, angular accel, all expressed in the vehicle’s canonical axes.
- Example:
accelLocal = (0,0,9.81)? driver feels +1g back into seat. - Example:
angularVelLocal = (0,0.1,0)? car yawing left.
Notes for IN plugin developers
- Most sims already use
Z forward, Y up? passthrough is fine. - BeamNG.drive (and rare others) use
Y forward? you must remap axes before filling OpenSR data. - Always normalize to OpenSR units and axes in the IN plugin.
- OUT plugins must never attempt to “guess” a game’s convention — they always assume OpenSR canonical coordinates.
6. Responsibility Split
IN Plugin:
- Produces:
OutSimData
- Must:
- reflect real game state
- submit only fresh frames
OUT Plugin:
- Consumes:
OutSimData
- Produces:
InSimData
- Must:
- reflect real device/input state
Host:
- Ensures:
- frame validity
- synchronization point
- Does NOT:
- reinterpret data semantics
- normalize values
7. Timing Model
Telemetry:
- Driven by:
- game update rate
- plugin submission logic
Inputs:
- Driven by:
- device polling
- plugin loop
Key point:
These two systems are decoupled.
8. Common Mistakes
Plugins must avoid:
- Treating inputs as events instead of states
- Resetting inputs prematurely
- Sending partial or inconsistent telemetry frames
- Assuming normalized ranges without defining them
- Linking input updates to telemetry frame rate
9. Usage Model
OutSimData= snapshot of the simulationInSimData= live input state (like HID report)- Host = synchronization boundary, not interpreter
