Data Semantics (InSimData & OutSimData)

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 plugin
  • packetType → identifies data category
  • reportAvailable → 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
  • 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 simulation
  • InSimData = live input state (like HID report)
  • Host = synchronization boundary, not interpreter