Skip to content

Instantly share code, notes, and snippets.

@gro-ove
Last active May 17, 2025 15:31
Show Gist options
  • Save gro-ove/11489f32b3eb3c9e3df1e7819bb3008e to your computer and use it in GitHub Desktop.
Save gro-ove/11489f32b3eb3c9e3df1e7819bb3008e to your computer and use it in GitHub Desktop.
Example of custom AI for Assetto Corsa
/*
This is the most basic example of reading and writing of those shared memory files. Resources are not being freed here
to keep things simple.
For more details, see:
https://github.com/ac-custom-shaders-patch/acc-extension-config/wiki/Other-Things-%E2%80%93-Custom-AI
*/
public struct Vec3 {
public float X, Y, Z;
public static Vec3 operator +(Vec3 a, Vec3 b){
return new Vec3{ X = a.X + b.X, Y = a.Y + b.Y, Z = a.Z + b.Z };
}
}
public class SimControl {
private readonly MemoryMappedViewAccessor _view;
public SimControl() {
_view = MemoryMappedFile.CreateOrOpen("AcTools.CSP.NewBehaviour.CustomAI.SimState.v0", 4).CreateViewAccessor();
}
public bool Pause {
get { return _view.ReadByte(0) != 0; }
set { _view.Write(0, (byte)(value ? 1 : 0)); }
}
}
public class DebugLines {
private struct LineData {
public Vec3 From;
public Vec3 To;
public int Color;
}
private readonly MemoryMappedViewAccessor _view;
private int _count;
private LineData[] _lines;
public DebugLines() {
_view = MemoryMappedFile.CreateOrOpen("AcTools.CSP.NewBehaviour.CustomAI.DebugLines.v0", 16 * 1024).CreateViewAccessor();
_lines = new LineData[512];
}
public void AddLine(Vec3 From, Vec3 To, Color Color) {
if (_count < 512) {
_lines[_count++] = new LineData { From = From, To = To, Color = Color.ToArgb() };
}
}
public void SubmitLines() {
_view.Write(0, 0);
if (_count > 0) {
_view.WriteArray(4, _lines, 0, _count);
_view.Write(0, _count);
}
_count = 0;
}
}
public class CarHelper {
private readonly MemoryMappedViewAccessor _state;
private readonly MemoryMappedViewAccessor _controls;
public CarHelper(int carIndex) {
_state = MemoryMappedFile.CreateOrOpen($"AcTools.CSP.NewBehaviour.CustomAI.Car{carIndex}.v0", 672).CreateViewAccessor();
_controls = MemoryMappedFile.CreateOrOpen($"AcTools.CSP.NewBehaviour.CustomAI.CarControls{carIndex}.v0", 72).CreateViewAccessor();
}
public float PacketID {
get { return _state.ReadInt32(0); }
}
public float Gas {
get { return _controls.ReadSingle(0); }
set { _controls.Write(0, value); }
}
public float Brake {
get { return _controls.ReadSingle(4); }
set { _controls.Write(4, value); }
}
public float Clutch {
get { return _controls.ReadSingle(8); }
set { _controls.Write(8, value); }
}
public float Steer {
get { return _controls.ReadSingle(12); }
set { _controls.Write(12, value); }
}
public float Handbrake {
get { return _controls.ReadSingle(16); }
set { _controls.Write(16, value); }
}
public bool AutoShift {
get { return _controls.ReadByte(68) != 0; }
set { _controls.Write(68, (byte)(value ? 1 : 0)); }
}
public int Gear {
get { return _state.ReadInt32(28); }
}
public float SpeedKmh {
get { return _state.ReadSingle(36); }
}
public Vec3 Velocity {
get { return new Vec3 { X = _state.ReadSingle(40), Y = _state.ReadSingle(44), Z = _state.ReadSingle(48) }; }
}
public Vec3 Look {
get { return new Vec3 { X = _state.ReadSingle(64), Y = _state.ReadSingle(68), Z = _state.ReadSingle(72) }; }
}
public Vec3 Up {
get { return new Vec3 { X = _state.ReadSingle(76), Y = _state.ReadSingle(80), Z = _state.ReadSingle(84) }; }
}
public Vec3 Position {
get { return new Vec3 { X = _state.ReadSingle(88), Y = _state.ReadSingle(92), Z = _state.ReadSingle(96) }; }
}
}
void Main() {
var sim = new SimControl();
var lines = new DebugLines();
var car = new CarHelper(1);
car.AutoShift = true;
car.Clutch = 1f;
while (true) {
// Any logic you might need
car.Gas = 1f - car.Gas;
car.Brake = 1f - car.Brake;
car.Handbrake = 1f - car.Handbrake;
car.Steer = 0.1f - car.Steer;
// Some random lines for a test:
lines.AddLine(car.Position, new Vec3 { X = 0, Y = 0, Z = 0 }, Color.Cyan);
lines.AddLine(car.Position, car.Position + car.Velocity, Color.White);
lines.SubmitLines();
// Make sure to alter surfaces.ini with `[_EXTRA_PERMISSIONS] ALLOW_CUSTOM_AI_MANIPULATION=1` for this thing to work:
// sim.Pause = !sim.Pause;
Thread.Sleep(1000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment