Repository navigation
GameCode
Most mods never need this page: the FH2 classes read the game for you. It's for when you go lower, with your own hooks and addresses.
In C++, a mod can wrap a risky read in __try and carry on if the memory isn't there. .NET can't: an access violation can't be caught, and the runtime ends the game. Game data you didn't get from the game just now may be gone: an area that streamed out, a car that left, the HUD after a teleport. Read anything like that with the safe reads below.
Data the game hands you in a hook (its arguments, the object it's working on) is alive while the hook runs: read that directly, it's faster.
New in 0.10.0. Each is a copy through the operating system, so a bad address gives you "not readable" instead of a crash.
| Member | What it does |
|---|---|
GameCode.TryRead(nint address, byte[] into) |
Copies the bytes; false (nothing read) if any of them isn't readable. A Span<byte> overload too. |
GameCode.TryRead<T>(nint address, out T value) |
A value of type T (C#). |
GameCode.ReadSafe<T>(nint address) |
The value, or 0 / null if it isn't readable (C#). |
GameCode.ReadPointerSafe(nint address, int offset = 0) |
A pointer, or 0. |
GameCode.ReadInt32Safe(nint address, int offset = 0) |
An Integer, or 0. |
GameCode.ReadSingleSafe(nint address, int offset = 0) |
A Single, or 0. |
GameCode.IsReadable(nint address, int size = 8) |
True if that much memory is there right now. |
GameCode.ReadStdString(nint address) |
The text of one of the game's std::strings, or "" if it isn't readable. |
GameCode.NewStdString(string text) → nint
|
A new std::string in the game's layout, for a game function that takes const std::string*. Never freed (the game may keep it): make one per name and keep it. New in 0.12.0.
|
nint car = ...; // remembered from an earlier frame: may be gone now
if (GameCode.TryRead<int>(car + 0x4D08, out var kind) && kind == 0)
Log("still the player's car");Dim car As IntPtr = ... ' remembered from an earlier frame: may be gone now
If GameCode.ReadInt32Safe(car, &H4D08) = 0 Then Log("still the player's car")These cost a system call each. Use them for pointers you kept, not for every read in a hot loop.
Before hooking or calling the game's code, check its first bytes, so that on another build of the game your mod switches itself off instead of crashing:
| Member | What it does |
|---|---|
GameCode.Matches(nint address, byte[] expected) |
The bytes in memory are expected. |
GameCode.MatchesBuild(nint address, byte[] expected) |
The same, but still true where another mod has hooked that code first: it then reads the game's exe on disk. New in 0.10.0. |
GameCode.SlotMatchesBuild(nint slot, nint function) |
A function pointer (a vtable entry) is function, or another mod has hooked it and the exe on disk has function there. New in 0.10.0.
|
GameCode.ShippedBytes(nint address, Span<byte> into) |
The bytes as the exe on disk has them. New in 0.10.0. |
GameCode.Hex("48 8B C4") |
Bytes from text, for the checks above. |
Use MatchesBuild for code other mods hook too: with Matches, your mod would refuse to start whenever another one was loaded first.
nint b = ModPlatform.WaitForCode();
if (!GameCode.MatchesBuild(b + 0x384C00, GameCode.Hex("48 8B C4 55 56 57 41 54 41 55")))
{
Log("not the game build this mod was made for; off");
return;
}HookFunction, HookPointer, HookInstruction and PatchBytes only get the change ready, and platform.log says "hooked". Nothing happens in the game until you call EnableHooks(): for all your hooks at once, or EnableHooks(hook) for one. Make them all, check that none came back null, then switch them on together:
Dim h = PatchBytes("my limit", b + &H2E7809, newBytes, oldBytes)
If h IsNot Nothing AndAlso EnableHooks() Then Log("on")Playing
Getting started
Writing mods
- Hosted or NativeAOT?
- Threads
- Reloading and debugging
- Reading game memory safely
- Pop-ups, tips and message boxes
- Translations
The FH2 classes
- Game
- Player
- Vehicle
- World
- Garage, CarCatalog, Profile
- UI and Hud
- Camera
- Audio
- ANNA
- Skills
- Radio
- Livery
- GameDb
- DebugOverlay
- Controller
- GameInput
- GameWindow
- Menus and UiElement
- SettingsTile
- ButtonIcons and Picture
- MapView, PhotoCamera, GarageCamera
More