unit AssettoCorsa.SharedMemory; interface type AC_STATUS = Integer; TACStatus = AC_STATUS; const { AC_STATUS } AC_OFF = 0; AC_REPLAY = 1; AC_LIVE = 2; AC_PAUSE = 3; type AC_SESSION_TYPE = Integer; TACSessionType = AC_SESSION_TYPE; const { AC_SESSION_TYPE } AC_UNKNOWN = -1; AC_PRACTICE = 0; AC_QUALIFY = 1; AC_RACE = 2; AC_HOTLAP = 3; AC_TIME_ATTACK = 4; AC_DRIFT = 5; AC_DRAG = 6; type AC_FLAG_TYPE = Integer; TACFlagType = AC_FLAG_TYPE; const { AC_FLAG_TYPE } AC_NO_FLAG = 0; AC_BLUE_FLAG = 1; AC_YELLOW_FLAG = 2; AC_BLACK_FLAG = 3; AC_WHITE_FLAG = 4; AC_CHECKERED_FLAG = 5; AC_PENALTY_FLAG = 6; type TACSMPhysics = packed record packetId: Integer; gas: Single; brake: Single; fuel: Single; gear: Integer; rpms: Integer; steerAngle: Single; speedKmh: Single; velocity: array[0..2] of Single; accG: array[0..2] of Single; wheelSlip: array[0..3] of Single; wheelLoad: array[0..3] of Single; wheelsPressure: array[0..3] of Single; wheelAngularSpeed: array[0..3] of Single; tyreWear: array[0..3] of Single; tyreDirtyLevel: array[0..3] of Single; tyreCoreTemperature: array[0..3] of Single; camberRAD: array[0..3] of Single; suspensionTravel: array[0..3] of Single; drs: Single; tc: Single; heading: Single; pitch: Single; roll: Single; cgHeight: Single; carDamage: array[0..4] of Single; umberOfTyresOut: Integer; pitLimiterOn: Integer; abs: Single; kersCharge: Single; kersInput: Single; autoShifterOn: Integer; rideHeigh: Single; turboBoost: Single; ballast: Single; airDensity: Single; airTemp: Single; roadTemp: Single; localAngularVelocity: array[0..2] of Single; finalFF: Single; performanceMeter: Single; engineBrake: Integer; ersRecoveryLevel: Integer; ersPowerLevel: Integer; ersHeatCharging: Integer; ersIsCharging: Integer; kersCurrentKJ: Single; drsAvailable: Integer; drsEnabled: Integer; brakeTemp: array[0..3] of Single; clutch: Single; tyreTempI: array[0..3] of Single; tyreTempM: array[0..3] of Single; tyreTempO: array[0..3] of Single; isAIControlled: Integer; tyreContactPoint: array[0..3, 0..2] of Single; tyreContactNormal: array[0..3, 0..2] of Single; tyreContactHeading: array[0..3, 0..2] of Single; brakeBias: Single; end; PACSMPhysics = ^TACSMPhysics; TACSMGraphic = packed record packetId: Integer; status: TACStatus; session: TACSessionType; currentTime: array[0..14] of WideChar; lastTime: array[0..14] of WideChar; bestTime: array[0..14] of WideChar; split: array[0..14] of WideChar; completedLaps: Integer; position: Integer; iCurrentTime: Integer; iLastTime: Integer; iBestTime: Integer; sessionTimeLeft: Single; distanceTraveled: Single; isInPit: Integer; currentSectorIndex: Integer; lastSectorTime: Integer; numberOfLaps: Integer; tyreCompound: array[0..32] of WideChar; replayTimeMultiplier: Single; normalizedCarPosition: Single; carCoordinates: array[0..2] of Single; penaltyTime: Single; flag: TACFlagType; idealLineOn: Integer; isInPitLane: Integer; surfaceGrip: Single; end; PACSMGraphic = ^TACSMGraphic; TACSMStatic = packed record smVersion: array[0..14] of WideChar; acVersion: array[0..14] of WideChar; // Session static info numberOfSessions: Integer; numCars: Integer; carModel: array[0..32] of WideChar; track: array[0..32] of WideChar; playerName: array[0..32] of WideChar; playerSurname: array[0..32] of WideChar; playerNick: array[0..32] of WideChar; sectorCount: Integer; // Car static info maxTorque: Single; maxPower: Single; maxRpm: Integer; maxFuel: Single; suspensionMaxTravel: array[0..3] of Single; tyreRadius: array[0..3] of Single; maxTurboBoost: Single; deprecated_1: Single; deprecated_2: Single; penaltiesEnabled: Integer; aidFuelRate: Single; aidTireRate: Single; aidMechanicalDamage: Single; aidAllowTyreBlankets: Integer; aidStability: Single; aidAutoClutch: Integer; aidAutoBlip: Integer; hasDRS: Integer; hasERS: Integer; hasKERS: Integer; kersMaxJ: Single; engineBrakeSettingsCount: Integer; ersPowerControllerCount: Integer; trackSPlineLength: Single; trackConfiguration: array[0..32] of WideChar; ersMaxJ: Single; end; PACSMStatic = ^TACSMStatic; const ACSM_PHYSICS = 'Local\acpmf_physics'; ACSM_GRAPHICS = 'Local\acpmf_graphics'; ACSM_STATIC = 'Local\acpmf_static'; type IAssettoCorsaSharedMemory = interface ['{D7C0E678-CB11-4C34-81EB-4AAD5737C44F}'] function GetPhysics(out APhysics: TACSMPhysics): Boolean; function GetGraphic(out AGraphic: TACSMGraphic): Boolean; function GetStatic(out AStatic: TACSMStatic): Boolean; end; function GetAssettoCorsaSharedMemory(): IAssettoCorsaSharedMemory; implementation uses WinApi.Windows, System.SysUtils, System.Classes; type TACSMMapping = record Handle: THandle; Buffer: Pointer; end; TAssettoCorsaSharedMemory = class(TInterfacedObject, IAssettoCorsaSharedMemory) private FPhysicsMapping: TACSMMapping; FGraphicMapping: TACSMMapping; FStaticMapping: TACSMMapping; protected function OpenMapping(const AName: string; var AMapping: TACSMMapping; ASize: Integer): Boolean; procedure CloseMapping(var AMapping: TACSMMapping); public destructor Destroy; override; { IACSM } function GetPhysics(out APhysics: TACSMPhysics): Boolean; function GetGraphic(out AGraphic: TACSMGraphic): Boolean; function GetStatic(out AStatic: TACSMStatic): Boolean; end; function GetAssettoCorsaSharedMemory(): IAssettoCorsaSharedMemory; begin Result := TAssettoCorsaSharedMemory.Create; end; { TACSM } destructor TAssettoCorsaSharedMemory.Destroy; begin CloseMapping(FPhysicsMapping); CloseMapping(FGraphicMapping); CloseMapping(FStaticMapping); inherited; end; function TAssettoCorsaSharedMemory.GetPhysics(out APhysics: TACSMPhysics): Boolean; begin Result := OpenMapping(ACSM_PHYSICS, FPhysicsMapping, SizeOf(TACSMPhysics)); if Result then APhysics := PACSMPhysics(FPhysicsMapping.Buffer)^; end; function TAssettoCorsaSharedMemory.GetGraphic(out AGraphic: TACSMGraphic): Boolean; begin Result := OpenMapping(ACSM_GRAPHICS, FGraphicMapping, SizeOf(TACSMGraphic)); if Result then AGraphic := PACSMGraphic(FGraphicMapping.Buffer)^; end; function TAssettoCorsaSharedMemory.GetStatic(out AStatic: TACSMStatic): Boolean; begin Result := OpenMapping(ACSM_STATIC, FStaticMapping, SizeOf(TACSMStatic)); if Result then AStatic := PACSMStatic(FStaticMapping.Buffer)^; end; function TAssettoCorsaSharedMemory.OpenMapping(const AName: string; var AMapping: TACSMMapping; ASize: Integer): Boolean; var handle: THandle; buffer: Pointer; begin if AMapping.Handle <> 0 then begin Result := True; exit; end; Result := False; handle := OpenFileMapping(FILE_MAP_READ, False, PChar(AName)); if handle = 0 then Exit; buffer := MapViewOfFile(handle, FILE_MAP_READ, 0, 0, ASize); if Assigned(buffer) then begin AMapping.Handle := handle; AMapping.Buffer := buffer; Result := True; end else begin CloseHandle(handle); RaiseLastOSError; end; end; procedure TAssettoCorsaSharedMemory.CloseMapping(var AMapping: TACSMMapping); begin if AMapping.Handle <> 0 then begin UnmapViewOfFile(AMapping.Buffer); CloseHandle(AMapping.Handle); end; end; end.