Last active
May 17, 2025 15:31
-
-
Save gro-ove/11489f32b3eb3c9e3df1e7819bb3008e to your computer and use it in GitHub Desktop.
Example of custom AI for Assetto Corsa
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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