Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
#include "VehicleExtensions.hpp"
#include "NativeMemory.hpp"
#include "Versions.h"
#include "Offsets.hpp"
#include "../Util/Logger.hpp"
#include <inc/main.h>
#include <vector>
#include <functional>
// <= b1493: 8 (Top gear = 7)
// >= b1604: 11 (Top gear = 10)
uint8_t g_numGears = 8;
eGameVersion g_gameVersion = getGameVersion();
namespace {
template <typename T> T Sign(T val) {
return static_cast<T>((T{} < val) - (val < T{}));
}
int rocketBoostActiveOffset = 0;
int rocketBoostChargeOffset = 0;
int hoverTransformRatioOffset = 0;
int hoverTransformRatioLerpOffset = 0;
int fuelLevelOffset = 0;
int lightsBrokenOffset = 0;
int lightsBrokenVisuallyOffset = 0;
int nextGearOffset = 0;
int currentGearOffset = 0;
int topGearOffset = 0;
int gearRatiosOffset = 0;
int driveForceOffset = 0;
int initialDriveMaxFlatVelOffset = 0;
int driveMaxFlatVelOffset = 0;
int currentRPMOffset = 0;
int clutchOffset = 0;
int throttleOffset = 0;
int turboOffset = 0;
int arenaBoostOffset = 0;
int handlingOffset = 0;
int lightStatesOffset = 0;
int indicatorTimingOffset = 0;
int steeringAngleInputOffset = 0;
int steeringAngleOffset = 0;
int throttlePOffset = 0;
int brakePOffset = 0;
int handbrakeOffset = 0;
int dirtLevelOffset = 0;
int engineTempOffset = 0;
int dashSpeedOffset = 0;
int wheelsPtrOffset = 0;
int numWheelsOffset = 0;
int modelTypeOffset = 0;
int vehicleModelInfoOffset = 0x020;
int vehicleFlagsOffset = 0;
int wheelSteerMultOffset = 0;
int gravityOffset = 0;
// Wheel stuff
int wheelHealthOffset = 0;
int wheelSuspensionCompressionOffset = 0;
int wheelSteeringAngleOffset = 0;
int wheelAngularVelocityOffset = 0;
int wheelOverheatOffset = 0;
int wheelTractionVectorLengthOffset = 0;
int wheelTractionVectorYOffset = 0;
int wheelTractionVectorXOffset = 0;
int wheelPowerOffset = 0;
int wheelBrakeOffset = 0;
int wheelFlagsOffset = 0;
int wheelDownforceOffset = 0;
int wheelLoadOffset = 0;
int wheelMatTyreGripOffset = 0;
int wheelMatWetGripOffset = 0;
int wheelMatTyreDragOffset = 0;
int wheelMatTopSpeedMultOffset = 0;
int wheelMatTypeOffset = 0;
}
void VehicleExtensions::SetVersion(int version) {
g_gameVersion = static_cast<eGameVersion>(version);
if (g_gameVersion >= G_VER_1_0_1604_0_STEAM) {
g_numGears = 11;
}
}
uint8_t VehicleExtensions::GearsAvailable() {
return g_numGears;
}
/*
* Offsets/patterns done by me might need revision, but they've been checked
* against b1180.2 and b877.1 and are okay.
*/
void VehicleExtensions::Init() {
mem::init();
// Figuring out indicator timing: LieutenantDan
uintptr_t addr = mem::FindPattern("\x44\x0F\xB7\x91\xDC\x00\x00\x00\x0F\xB7\x81\xB0\x0A\x00\x00\x41\xB9\x01\x00\x00\x00\x44\x03\x15\x8C\x63\xDF\x01",
"xxxx????xxx????xxxxxxxxx????");
indicatorTimingOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(indicatorTimingOffset == 0 ? WARN : DEBUG, "Indicator timing offset: 0x%03X", indicatorTimingOffset);
addr = mem::FindPattern("3A 91 ? ? ? ? 74 ? 84 D2");
rocketBoostActiveOffset = addr == 0 ? 0 : *(int*)(addr + 2);
logger.Write(rocketBoostActiveOffset == 0 ? WARN : DEBUG, "Rocket Boost Active Offset: 0x%X", rocketBoostActiveOffset);
addr = mem::FindPattern("\x48\x8B\x47\x00\xF3\x44\x0F\x10\x9F\x00\x00\x00\x00", "xxx?xxxxx????");
rocketBoostChargeOffset = addr == 0 ? 0 : *(int*)(addr + 9);
logger.Write(rocketBoostChargeOffset == 0 ? WARN : DEBUG, "Rocket Boost Charge Offset: 0x%X", rocketBoostChargeOffset);
// Unknown
addr = mem::FindPattern("\xF3\x0F\x11\xB3\x00\x00\x00\x00\x44\x88\x00\x00\x00\x00\x00\x48\x85\xC9",
"xxxx????xx?????xxx");
hoverTransformRatioOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(hoverTransformRatioOffset == 0 ? WARN : DEBUG, "Hover Transform Active Offset: 0x%X", hoverTransformRatioOffset);
//addr = mem::FindPattern("\xF3\x0F\x11\xB3\x00\x00\x00\x00\x44\x88\x00\x00\x00\x00\x00\x48\x85\xC9",
// "xxxx????xx?????xxx");
hoverTransformRatioLerpOffset = addr == 0 ? 0 : *(int*)(addr + 4) + 0x28;
logger.Write(hoverTransformRatioLerpOffset == 0 ? WARN : DEBUG, "Hover Transform Ratio Offset: 0x%X", hoverTransformRatioLerpOffset);
addr = mem::FindPattern("\x48\x85\xC0\x74\x3C\x8B\x80\x00\x00\x00\x00\xC1\xE8\x0F", "xxxxxxx????xxx");
vehicleFlagsOffset = addr == 0 ? 0 : *(int*)(addr + 7);
logger.Write(vehicleFlagsOffset == 0 ? WARN : DEBUG, "Vehicle Flags Offset: 0x%X", vehicleFlagsOffset);
addr = mem::FindPattern("\x74\x26\x0F\x57\xC9", "xxxxx");
fuelLevelOffset = addr == 0 ? 0 : *(int*)(addr + 8);
logger.Write(fuelLevelOffset == 0 ? WARN : DEBUG, "Fuel Level Offset: 0x%X", fuelLevelOffset);
// 86C -> bulb
addr = mem::FindPattern("F6 87 ? ? ? ? 02 75 06 C6 45 80 01");
lightsBrokenOffset = addr == 0 ? 0 : *(int*)(addr + 2);;
logger.Write(lightsBrokenOffset == 0 ? WARN : DEBUG, "Lights Broken Offset: 0x%X", lightsBrokenOffset);
// 874 -> visibly
lightsBrokenVisuallyOffset = addr == 0 ? 0 : lightsBrokenOffset + 8;
logger.Write(lightsBrokenVisuallyOffset == 0 ? WARN : DEBUG, "Lights Visually Broken Offset: 0x%X", lightsBrokenVisuallyOffset);
addr = mem::FindPattern("\x48\x8D\x8F\x00\x00\x00\x00\x4C\x8B\xC3\xF3\x0F\x11\x7C\x24",
"xxx????xxxxxxxx");
nextGearOffset = addr == 0 ? 0 : *(int*)(addr + 3);
logger.Write(nextGearOffset == 0 ? WARN : DEBUG, "Next Gear Offset: 0x%X", nextGearOffset);
currentGearOffset = addr == 0 ? 0 : *(int*)(addr + 3) + 2;
logger.Write(currentGearOffset == 0 ? WARN : DEBUG, "Current Gear Offset: 0x%X", currentGearOffset);
topGearOffset = addr == 0 ? 0 : *(int*)(addr + 3) + 6;
logger.Write(topGearOffset == 0 ? WARN : DEBUG, "Top Gear Offset: 0x%X", topGearOffset);
gearRatiosOffset = addr == 0 ? 0 : *(int*)(addr + 3) + 8;
logger.Write(gearRatiosOffset == 0 ? WARN : DEBUG, "Gear Ratios Offset: 0x%X", gearRatiosOffset);
if (g_gameVersion >= G_VER_1_0_1604_0_STEAM) {
addr = mem::FindPattern("\xF3\x0F\x10\x8F\xA4\x08\x00\x00\xF3\x0F\x5E\xF0\x41\x0F\x2F\xCA", "xxxx????xxx?xxx?");
driveForceOffset = addr == 0 ? 0 : *(int*)(addr + 4);
}
else {
driveForceOffset = addr == 0 ? 0 : *(int*)(addr + 3) + 0x28;
}
logger.Write(driveForceOffset == 0 ? WARN : DEBUG, "Drive Force Offset: 0x%X", driveForceOffset);
initialDriveMaxFlatVelOffset = driveForceOffset == 0 ? 0 : driveForceOffset + 0x04;
logger.Write(initialDriveMaxFlatVelOffset == 0 ? WARN : DEBUG, "Initial Drive Max Flat Velocity Offset: 0x%X", initialDriveMaxFlatVelOffset);
driveMaxFlatVelOffset = driveForceOffset == 0 ? 0 : driveForceOffset + 0x08;
logger.Write(driveMaxFlatVelOffset == 0 ? WARN : DEBUG, "Drive Max Flat Velocity Offset: 0x%X", driveMaxFlatVelOffset);
addr = mem::FindPattern("\x76\x03\x0F\x28\xF0\xF3\x44\x0F\x10\x93",
"xxxxxxxxxx");
currentRPMOffset = addr == 0 ? 0 : *(int*)(addr + 10);
logger.Write(currentRPMOffset == 0 ? WARN : DEBUG, "RPM Offset: 0x%X", currentRPMOffset);
clutchOffset = addr == 0 ? 0 : *(int*)(addr + 10) + 0xC;
logger.Write(clutchOffset == 0 ? WARN : DEBUG, "Clutch Offset: 0x%X", clutchOffset);
throttleOffset = addr == 0 ? 0 : *(int*)(addr + 10) + 0x10;
logger.Write(throttleOffset == 0 ? WARN : DEBUG, "Throttle Offset: 0x%X", throttleOffset);
if (g_gameVersion >= G_VER_1_0_1604_0_STEAM) {
addr = mem::FindPattern("\xF3\x0F\x10\x9F\xD4\x08\x00\x00\x0F\x2F\xDF\x73\x0A", "xxxx????xxxxx");
}
else {
addr = mem::FindPattern("\xF3\x0F\x10\x8F\x68\x08\x00\x00\x88\x4D\x8C\x0F\x2F\xCF",
"xxxx????xxx???");
}
turboOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(turboOffset == 0 ? WARN : DEBUG, "Turbo Offset: 0x%X", turboOffset);
if (g_gameVersion >= G_VER_1_0_1604_0_STEAM) {
// TODO: pattern
arenaBoostOffset = turboOffset + 0x30;
}
else {
arenaBoostOffset = 0;
}
addr = mem::FindPattern("\x3C\x03\x0F\x85\x00\x00\x00\x00\x48\x8B\x41\x20\x48\x8B\x88",
"xxxx????xxxxxxx");
handlingOffset = addr == 0 ? 0 : *(int*)(addr + 0x16);
logger.Write(handlingOffset == 0 ? WARN : DEBUG, "Handling Offset: 0x%X", handlingOffset);
addr = mem::FindPattern("FD 02 DB 08 98 ? ? ? ? 48 8B 5C 24 30");
lightStatesOffset = addr == 0 ? 0 : *(int*)(addr - 4) - 1;
logger.Write(lightStatesOffset == 0 ? WARN : DEBUG, "Light States Offset: 0x%X", lightStatesOffset);
// Or "8A 96 ? ? ? ? 0F B6 C8 84 D2 41", +10 or something (+31 is the engine starting bit), (0x928 starting addr)
addr = mem::FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
steeringAngleInputOffset = addr == 0 ? 0 : *(int*)(addr + 6);
logger.Write(steeringAngleInputOffset == 0 ? WARN : DEBUG, "Steering Input Offset: 0x%X", steeringAngleInputOffset);
steeringAngleOffset = addr == 0 ? 0 : *(int*)(addr + 6) + 8;
logger.Write(steeringAngleOffset == 0 ? WARN : DEBUG, "Steering Angle Offset: 0x%X", steeringAngleOffset);
throttlePOffset = addr == 0 ? 0 : *(int*)(addr + 6) + 0x10;
logger.Write(throttlePOffset == 0 ? WARN : DEBUG, "ThrottleP Offset: 0x%X", throttlePOffset);
brakePOffset = addr == 0 ? 0 : *(int*)(addr + 6) + 0x14;
logger.Write(brakePOffset == 0 ? WARN : DEBUG, "BrakeP Offset: 0x%X", brakePOffset);
if (g_gameVersion >= G_VER_1_0_2060_0_STEAM) {
addr = mem::FindPattern("8A C2 24 01 C0 E0 04 08 81");
handbrakeOffset = addr == 0 ? 0 : *(int*)(addr + 19);
}
else {
addr = mem::FindPattern("\x44\x88\xA3\x00\x00\x00\x00\x45\x8A\xF4", "xxx????xxx");
handbrakeOffset = addr == 0 ? 0 : *(int*)(addr + 3);
}
logger.Write(handbrakeOffset == 0 ? WARN : DEBUG, "Handbrake Offset: 0x%X", handbrakeOffset);
addr = mem::FindPattern("\x0F\x29\x7C\x24\x30\x0F\x85\xE3\x00\x00\x00\xF3\x0F\x10\xB9\x68\x09\x00\x00",
"xx???xx????xxxx????");
dirtLevelOffset = addr == 0 ? 0 : *(int*)(addr + 0xF);
logger.Write(dirtLevelOffset == 0 ? WARN : DEBUG, "Dirt Level Offset: 0x%X", dirtLevelOffset);
addr = mem::FindPattern("\xF3\x0F\x11\x9B\xDC\x09\x00\x00\x0F\x84\xB1\x00\x00\x00",
"xxxx????xxx???");
engineTempOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(engineTempOffset == 0 ? WARN : DEBUG, "Engine Temperature Offset: 0x%X", engineTempOffset);
addr = mem::FindPattern("\xF3\x0F\x10\x8F\x10\x0A\x00\x00\xF3\x0F\x59\x05\x5E\x30\x8D\x00",
"xxxx????xxxx????");
dashSpeedOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(dashSpeedOffset == 0 ? WARN : DEBUG, "Dashboard Speed Offset: 0x%X", dashSpeedOffset);
addr = mem::FindPattern("\x8B\x83\x38\x0B\x00\x00\x83\xE8\x08\x83\xF8\x02", "xx????xx?xxx");
modelTypeOffset = addr == 0 ? 0 : *(int*)(addr + 2);
logger.Write(modelTypeOffset == 0 ? WARN : DEBUG, "Model Type Offset: 0x%X", modelTypeOffset);
addr = mem::FindPattern("\x3B\xB7\x48\x0B\x00\x00\x7D\x0D", "xx????xx");
wheelsPtrOffset = addr == 0 ? 0 : *(int*)(addr + 2) - 8;
logger.Write(wheelsPtrOffset == 0 ? WARN : DEBUG, "Wheels Pointer Offset: 0x%X", wheelsPtrOffset);
numWheelsOffset = addr == 0 ? 0 : *(int*)(addr + 2);
logger.Write(numWheelsOffset == 0 ? WARN : DEBUG, "Wheel Count Offset: 0x%X", numWheelsOffset);
addr = mem::FindPattern("F3 0F 59 BF ? ? ? ? 4D 85 E4 0F 8E ? ? ? ?");
gravityOffset = addr == 0 ? 0 : *(int*)(addr + 4);
logger.Write(gravityOffset == 0 ? WARN : DEBUG, "Gravity Offset: 0x%X", gravityOffset);
// Wheel stuff offset from here
addr = mem::FindPattern("\x0F\xBA\xAB\xEC\x01\x00\x00\x09\x0F\x2F\xB3\x40\x01\x00\x00\x48\x8B\x83\x20\x01\x00\x00",
"xx?????xxx???xxxx?????");
wheelSteerMultOffset = addr == 0 ? 0 : *(int*)(addr + 11);
logger.Write(wheelSteerMultOffset == 0 ? WARN : DEBUG, "Wheel Steering Multiplier Offset: 0x%X", wheelSteerMultOffset);
addr = mem::FindPattern("\x45\x0f\x57\xc9\xf3\x0f\x11\x83\x60\x01\x00\x00\xf3\x0f\x5c", "xxx?xxx???xxxxx");
wheelSuspensionCompressionOffset = addr == 0 ? 0 : *(int*)(addr + 8);
logger.Write(wheelSuspensionCompressionOffset == 0 ? WARN : DEBUG, "Wheel Suspension Compression Offset: 0x%X", wheelSuspensionCompressionOffset);
wheelAngularVelocityOffset = addr == 0 ? 0 : (*(int*)(addr + 8)) + 0xc;
logger.Write(wheelAngularVelocityOffset == 0 ? WARN : DEBUG, "Wheel Angular Velocity Offset: 0x%X", wheelAngularVelocityOffset);
// angular velocity offset + 0x08
wheelOverheatOffset = addr == 0 ? 0 : (*(int*)(addr + 8)) + 0xc + 0x08;
logger.Write(wheelOverheatOffset == 0 ? WARN : DEBUG, "Wheel Overheat Offset: 0x%X", wheelOverheatOffset);
// Material stuff only tested for b2245
addr = mem::FindPattern("89 8B ? ? 00 00 E8 ? ? ? ? 0F 57 ?");
wheelMatTyreGripOffset = addr == 0 ? 0 : (*(int*)(addr + 2));
logger.Write(wheelMatTyreGripOffset == 0 ? WARN : DEBUG, "Wheel Material TYRE_GRIP Offset: 0x%X", wheelMatTyreGripOffset);
wheelMatWetGripOffset = addr == 0 ? 0 : (*(int*)(addr + 2) + 4);
logger.Write(wheelMatWetGripOffset == 0 ? WARN : DEBUG, "Wheel Material WET_GRIP Offset: 0x%X", wheelMatWetGripOffset);
wheelMatTyreDragOffset = addr == 0 ? 0 : (*(int*)(addr + 2) + 8);
logger.Write(wheelMatTyreDragOffset == 0 ? WARN : DEBUG, "Wheel Material TYRE_DRAG Offset: 0x%X", wheelMatTyreDragOffset);
wheelMatTopSpeedMultOffset = addr == 0 ? 0 : (*(int*)(addr + 2) + 12);
logger.Write(wheelMatTopSpeedMultOffset == 0 ? WARN : DEBUG, "Wheel Material TOP_SPEED_MULT Offset: 0x%X", wheelMatTopSpeedMultOffset);
if (g_gameVersion >= G_VER_1_0_1737_0_STEAM) {
addr = mem::FindPattern("\x0F\x2F\x81\xBC\x01\x00\x00" "\x0F\x97\xC0" "\xEB\x00" "\xD1\x00", "xx???xx" "xxx" "x?" "x?");
}
else {
addr = mem::FindPattern("\x0F\x2F\x81\xBC\x01\x00\x00" "\x0F\x97\xC0\xEB\xDA", "xx???xx" "xxxxx");
}
wheelTractionVectorLengthOffset = addr == 0 ? 0 : (*(int*)(addr + 3)) - 0x14;
logger.Write(wheelTractionVectorLengthOffset == 0 ? WARN : DEBUG, "Wheel Traction Vector Length Offset: 0x%X", wheelTractionVectorLengthOffset);
wheelLoadOffset = addr == 0 ? 0 : *(int*)(addr + 3) - 0x10;
logger.Write(wheelLoadOffset == 0 ? WARN : DEBUG, "Wheel Load Offset: 0x%X", wheelLoadOffset);
wheelTractionVectorYOffset = addr == 0 ? 0 : (*(int*)(addr + 3)) - 0x0C;
logger.Write(wheelTractionVectorYOffset == 0 ? WARN : DEBUG, "Wheel Traction Vector Y Offset: 0x%X", wheelTractionVectorYOffset);
wheelTractionVectorXOffset = addr == 0 ? 0 : (*(int*)(addr + 3)) - 0x08;
logger.Write(wheelTractionVectorXOffset == 0 ? WARN : DEBUG, "Wheel Traction Vector X Offset: 0x%X", wheelTractionVectorXOffset);
wheelSteeringAngleOffset = addr == 0 ? 0 : *(int*)(addr + 3);
logger.Write(wheelSteeringAngleOffset == 0 ? WARN : DEBUG, "Wheel Steering Angle Offset: 0x%X", wheelSteeringAngleOffset);
wheelBrakeOffset = addr == 0 ? 0 : (*(int*)(addr + 3)) + 0x4;
logger.Write(wheelBrakeOffset == 0 ? WARN : DEBUG, "Wheel Brake Offset: 0x%X", wheelBrakeOffset);
wheelPowerOffset = addr == 0 ? 0 : (*(int*)(addr + 3)) + 0x8;
logger.Write(wheelPowerOffset == 0 ? WARN : DEBUG, "Wheel Power Offset: 0x%X", wheelPowerOffset);
addr = mem::FindPattern("\x75\x24\xF3\x0F\x10\x81\xE0\x01\x00\x00\xF3\x0F\x5C\xC1", "xxxxx???xxxx??");
wheelHealthOffset = addr == 0 ? 0 : *(int*)(addr + 6);
logger.Write(wheelHealthOffset == 0 ? WARN : DEBUG, "Wheel Health Offset: 0x%X", wheelHealthOffset);
// wheelHealthOffset + float = tyre health
addr = mem::FindPattern("\x75\x11\x48\x8b\x01\x8b\x88", "xxxxxxx");
wheelFlagsOffset = addr == 0 ? 0 : *(int*)(addr + 7);
logger.Write(wheelFlagsOffset == 0 ? WARN : DEBUG, "Wheel Flags Offset: 0x%X", wheelFlagsOffset);
addr = mem::FindPattern("88 8B ? ? 00 00 41 0F B6 47 51 66 89 83 ? ? 00 00");
wheelMatTypeOffset = addr == 0 ? 0 : (*(int*)(addr + 2));
logger.Write(wheelMatTypeOffset == 0 ? WARN : DEBUG, "Wheel Material Type Offset: 0x%X", wheelMatTypeOffset);
wheelDownforceOffset = addr == 0 ? 0 : *(int*)(addr + 2) + 0x16;
logger.Write(wheelDownforceOffset == 0 ? WARN : DEBUG, "Wheel Downforce Offset: 0x%X", wheelDownforceOffset);
}
BYTE *VehicleExtensions::GetAddress(Vehicle handle) {
return reinterpret_cast<BYTE *>(mem::GetAddressOfEntity(handle));
}
bool VehicleExtensions::GetRocketBoostActive(Vehicle handle) {
if (rocketBoostActiveOffset == 0) return false;
return *reinterpret_cast<bool *>(GetAddress(handle) + rocketBoostActiveOffset);
}
void VehicleExtensions::SetRocketBoostActive(Vehicle handle, bool val) {
if (rocketBoostActiveOffset == 0) return;
*reinterpret_cast<bool *>(GetAddress(handle) + rocketBoostActiveOffset) = val;
}
float VehicleExtensions::GetRocketBoostCharge(Vehicle handle) {
if (rocketBoostChargeOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + rocketBoostChargeOffset);
}
void VehicleExtensions::SetRocketBoostCharge(Vehicle handle, float value) {
if (rocketBoostChargeOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + rocketBoostChargeOffset) = value;
}
float VehicleExtensions::GetHoverTransformRatio(Vehicle handle) {
if (hoverTransformRatioOffset == 0) return false;
return *reinterpret_cast<float *>(GetAddress(handle) + hoverTransformRatioOffset);
}
void VehicleExtensions::SetHoverTransformRatio(Vehicle handle, float value) {
if (hoverTransformRatioOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + hoverTransformRatioOffset) = value;
}
float VehicleExtensions::GetHoverTransformRatioLerp(Vehicle handle) {
if (hoverTransformRatioLerpOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + hoverTransformRatioLerpOffset);
}
void VehicleExtensions::SetHoverTransformRatioLerp(Vehicle handle, float value) {
if (hoverTransformRatioLerpOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + hoverTransformRatioLerpOffset) = value;
}
float VehicleExtensions::GetFuelLevel(Vehicle handle) {
if (fuelLevelOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + fuelLevelOffset);
}
void VehicleExtensions::SetFuelLevel(Vehicle handle, float value) {
if (fuelLevelOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + fuelLevelOffset) = value;
}
uint32_t VehicleExtensions::GetLightsBroken(Vehicle handle) {
if (lightsBrokenOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<uint32_t*>(address + lightsBrokenOffset);
}
void VehicleExtensions::SetLightsBroken(Vehicle handle, uint32_t value) {
if (lightsBrokenOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<uint32_t*>(address + lightsBrokenOffset) = value;
}
uint32_t VehicleExtensions::GetLightsBrokenVisual(Vehicle handle) {
if (lightsBrokenVisuallyOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<uint32_t*>(address + lightsBrokenVisuallyOffset);
}
void VehicleExtensions::SetLightsBrokenVisual(Vehicle handle, uint32_t value) {
if (lightsBrokenVisuallyOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<uint32_t*>(address + lightsBrokenVisuallyOffset) = value;
}
uint16_t VehicleExtensions::GetGearNext(Vehicle handle) {
if (nextGearOffset == 0) return 0;
return *reinterpret_cast<const uint16_t *>(GetAddress(handle) + nextGearOffset);
}
void VehicleExtensions::SetGearNext(Vehicle handle, uint16_t value) {
if (nextGearOffset == 0) return;
*reinterpret_cast<uint16_t *>(GetAddress(handle) + nextGearOffset) = value;
}
uint16_t VehicleExtensions::GetGearCurr(Vehicle handle) {
if (currentGearOffset == 0) return 0;
return *reinterpret_cast<const uint16_t *>(GetAddress(handle) + currentGearOffset);
}
void VehicleExtensions::SetGearCurr(Vehicle handle, uint16_t value) {
if (currentGearOffset == 0) return;
*reinterpret_cast<uint16_t *>(GetAddress(handle) + currentGearOffset) = value;
}
uint8_t VehicleExtensions::GetTopGear(Vehicle handle) {
if (topGearOffset == 0) return 0;
return *reinterpret_cast<uint8_t *>(GetAddress(handle) + topGearOffset);
}
void VehicleExtensions::SetTopGear(Vehicle handle, uint8_t value) {
if (topGearOffset == 0) return;
*reinterpret_cast<uint8_t *>(GetAddress(handle) + topGearOffset) = value;
}
float* VehicleExtensions::GetGearRatioPtr(Vehicle handle, uint8_t gear) {
if (gearRatiosOffset == 0) return nullptr;
return reinterpret_cast<float*>(
GetAddress(handle) + gearRatiosOffset + gear * sizeof(float));
}
std::vector<float> VehicleExtensions::GetGearRatios(Vehicle handle) {
if (gearRatiosOffset == 0) return {};
auto address = GetAddress(handle);
std::vector<float> ratios(GetTopGear(handle) + 1);
for (int gear = 0; gear < GetTopGear(handle) + 1; ++gear) {
ratios[gear] = *reinterpret_cast<float *>(address + gearRatiosOffset + gear * sizeof(float));
}
return ratios;
}
void VehicleExtensions::SetGearRatios(Vehicle handle, const std::vector<float>& values) {
if (gearRatiosOffset == 0) return;
auto address = GetAddress(handle);
for (uint8_t gear = 0; gear < values.size(); ++gear) {
*reinterpret_cast<float *>(address + gearRatiosOffset + gear * sizeof(float)) = values[gear];
}
}
float VehicleExtensions::GetDriveForce(Vehicle handle) {
if (driveForceOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + driveForceOffset);
}
void VehicleExtensions::SetDriveForce(Vehicle handle, float value) {
if (driveForceOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + driveForceOffset) = value;
}
float VehicleExtensions::GetInitialDriveMaxFlatVel(Vehicle handle) {
if (initialDriveMaxFlatVelOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + initialDriveMaxFlatVelOffset);
}
void VehicleExtensions::SetInitialDriveMaxFlatVel(Vehicle handle, float value) {
if (initialDriveMaxFlatVelOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + initialDriveMaxFlatVelOffset) = value;
}
float VehicleExtensions::GetDriveMaxFlatVel(Vehicle handle) {
if (driveMaxFlatVelOffset == 0) return 0.0f;
return *reinterpret_cast<float *>(GetAddress(handle) + driveMaxFlatVelOffset);
}
void VehicleExtensions::SetDriveMaxFlatVel(Vehicle handle, float value) {
if (driveMaxFlatVelOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + driveMaxFlatVelOffset) = value;
}
float VehicleExtensions::GetCurrentRPM(Vehicle handle) {
if (currentRPMOffset == 0) return 0.0f;
return *reinterpret_cast<const float *>(GetAddress(handle) + currentRPMOffset);
}
void VehicleExtensions::SetCurrentRPM(Vehicle handle, float value) {
if (currentRPMOffset == 0) return;
*reinterpret_cast<float *>(GetAddress(handle) + currentRPMOffset) = value;
}
float VehicleExtensions::GetClutch(Vehicle handle) {
if (clutchOffset == 0) return 0.0f;
auto address = GetAddress(handle);
return address == nullptr ? 0 : *reinterpret_cast<const float *>(address + clutchOffset);
}
void VehicleExtensions::SetClutch(Vehicle handle, float value) {
if (clutchOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + clutchOffset) = value;
}
float VehicleExtensions::GetThrottle(Vehicle handle) {
if (throttleOffset == 0) return 0.0f;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + throttleOffset);
}
// Seems to just control the sound.
void VehicleExtensions::SetThrottle(Vehicle handle, float value) {
if (throttleOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + throttleOffset) = value;
}
float VehicleExtensions::GetTurbo(Vehicle handle) {
if (turboOffset == 0) return 0.0f;
auto address = GetAddress(handle);
return address == nullptr ? 0 : *reinterpret_cast<const float *>(address + turboOffset);
}
void VehicleExtensions::SetTurbo(Vehicle handle, float value) {
if (turboOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + turboOffset) = value;
}
float VehicleExtensions::GetArenaBoost(Vehicle handle) {
if (arenaBoostOffset == 0) return 0.0f;
auto address = GetAddress(handle);
return address == nullptr ? 0 : *reinterpret_cast<const float*>(address + arenaBoostOffset);
}
void VehicleExtensions::SetArenaBoost(Vehicle handle, float value) {
if (arenaBoostOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float*>(address + arenaBoostOffset) = value;
}
uint64_t VehicleExtensions::GetHandlingPtr(Vehicle handle) {
if (handlingOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<uint64_t*>(address + handlingOffset);
}
void VehicleExtensions::SetHandlingPtr(Vehicle handle, uint64_t value) {
if (handlingOffset == 0) return;
auto address = GetAddress(handle);
if (address == 0) return;
*reinterpret_cast<uint64_t*>(address + handlingOffset) = value;
}
uint32_t VehicleExtensions::GetLightStates(Vehicle handle) {
if (lightStatesOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<uint32_t*>(address + lightStatesOffset);
}
void VehicleExtensions::SetLightStates(Vehicle handle, uint32_t value) {
if (lightStatesOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<uint32_t*>(address + lightStatesOffset) = value;
}
bool VehicleExtensions::GetIndicatorHigh(Vehicle handle, int gameTime) {
if (indicatorTimingOffset == 0) return false;
auto address = GetAddress(handle);
auto a = *reinterpret_cast<uint32_t*>(address + indicatorTimingOffset);
a += (uint32_t)gameTime;
a = a >> 9;
a = a & 1;
return a == 1;
}
float VehicleExtensions::GetGravity(Vehicle handle) {
if (gravityOffset == 0) return 0.0f;
auto address = GetAddress(handle);
return *reinterpret_cast<float*>(address + gravityOffset);
}
void VehicleExtensions::SetGravity(Vehicle handle, float value) {
if (gravityOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float*>(address + gravityOffset) = value;
}
float VehicleExtensions::GetSteeringInputAngle(Vehicle handle) {
if (steeringAngleInputOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + steeringAngleInputOffset);
}
void VehicleExtensions::SetSteeringInputAngle(Vehicle handle, float value) {
if (steeringAngleInputOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + steeringAngleInputOffset) = value;
}
float VehicleExtensions::GetSteeringAngle(Vehicle handle) {
if (steeringAngleOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + steeringAngleOffset);
}
void VehicleExtensions::SetSteeringAngle(Vehicle handle, float value) {
if (steeringAngleOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + steeringAngleOffset) = value;
}
float VehicleExtensions::GetThrottleP(Vehicle handle) {
if (throttlePOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + throttlePOffset);
}
void VehicleExtensions::SetThrottleP(Vehicle handle, float value) {
if (throttlePOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + throttlePOffset) = value;
}
float VehicleExtensions::GetBrakeP(Vehicle handle) {
if (brakePOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + brakePOffset);
}
void VehicleExtensions::SetBrakeP(Vehicle handle, float value) {
if (brakePOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<float *>(address + brakePOffset) = value;
}
bool VehicleExtensions::GetHandbrake(Vehicle handle) {
if (handbrakeOffset == 0) return false;
auto address = GetAddress(handle);
return *reinterpret_cast<bool *>(address + handbrakeOffset);
}
void VehicleExtensions::SetHandbrake(Vehicle handle, bool value) {
if (handbrakeOffset == 0) return;
auto address = GetAddress(handle);
*reinterpret_cast<bool*>(address + handbrakeOffset) = value;
}
float VehicleExtensions::GetDirtLevel(Vehicle handle) {
if (dirtLevelOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + dirtLevelOffset);
}
float VehicleExtensions::GetEngineTemp(Vehicle handle) {
if (engineTempOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + engineTempOffset);
}
float VehicleExtensions::GetDashSpeed(Vehicle handle) {
if (dashSpeedOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<float *>(address + dashSpeedOffset);
}
int VehicleExtensions::GetModelType(Vehicle handle) {
if (modelTypeOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<int *>(address + modelTypeOffset);
}
uint64_t VehicleExtensions::GetWheelsPtr(Vehicle handle) {
if (wheelsPtrOffset == 0) return 0;
auto address = GetAddress(handle);
return *reinterpret_cast<uint64_t *>(address + wheelsPtrOffset);
}
uint8_t VehicleExtensions::GetNumWheels(Vehicle handle) {
if (numWheelsOffset == 0) return 0;
auto address = GetAddress(handle);
if (address == 0) return 0;
return *reinterpret_cast<int *>(address + numWheelsOffset);
}
float VehicleExtensions::GetDriveBiasFront(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0.0f;
return *reinterpret_cast<float *>(address + hOffsets.fDriveBiasFront);
}
float VehicleExtensions::GetDriveBiasRear(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0.0f;
return *reinterpret_cast<float *>(address + hOffsets.fDriveBiasRear);
}
float VehicleExtensions::GetPetrolTankVolume(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0.0f;
return *reinterpret_cast<float *>(address + hOffsets.fPetrolTankVolume);
}
float VehicleExtensions::GetOilVolume(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0.0f;
return *reinterpret_cast<float *>(address + hOffsets.fOilVolume);
}
float VehicleExtensions::GetMaxSteeringAngle(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0.0f;
return *reinterpret_cast<float*>(address + hOffsets.fSteeringLock);
}
Hash VehicleExtensions::GetAIHandling(Vehicle handle) {
auto address = GetHandlingPtr(handle);
if (address == 0) return 0;
auto offset = 0x13C;
if (offset == 0) return 0;
return *reinterpret_cast<Hash *>(address + offset);
}
std::vector<uint64_t> VehicleExtensions::GetWheelPtrs(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle); // pointer to wheel pointers
auto numWheels = GetNumWheels(handle);
std::vector<uint64_t> wheelPtrs(numWheels);
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
wheelPtrs[i] = wheelAddr;
}
return wheelPtrs;
}
float VehicleExtensions::GetVisualHeight(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto offset = g_gameVersion >= G_VER_1_0_944_2_STEAM ? 0x080 : 0;
if (offset == 0)
return 0.0f;
return *reinterpret_cast<float *>(wheelPtr + offset);
}
void VehicleExtensions::SetVisualHeight(Vehicle handle, float height) {
auto wheelPtr = GetWheelsPtr(handle);
auto offset = g_gameVersion >= G_VER_1_0_944_2_STEAM ? 0x07C : 0;
if (offset == 0)
return;
*reinterpret_cast<float *>(wheelPtr + offset) = height;
}
std::vector<float> VehicleExtensions::GetWheelHealths(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> healths(numWheels);
if (wheelHealthOffset == 0) return healths;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
healths[i] = *reinterpret_cast<float *>(wheelAddr + wheelHealthOffset);
}
return healths;
}
void VehicleExtensions::SetWheelsHealth(Vehicle handle, float health) {
if (wheelHealthOffset == 0) return;
auto wheelPtr = GetWheelsPtr(handle); // pointer to wheel pointers
auto numWheels = GetNumWheels(handle);
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
*reinterpret_cast<float *>(wheelAddr + wheelHealthOffset) = health;
}
}
float VehicleExtensions::GetSteeringMultiplier(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
if (numWheels > 1) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * 1);
return abs(*reinterpret_cast<float*>(wheelAddr + wheelSteerMultOffset));
}
return 1.0f;
}
void VehicleExtensions::SetSteeringMultiplier(Vehicle handle, float value) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
for (int i = 0; i<numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
float sign = Sign(*reinterpret_cast<float*>(wheelAddr + wheelSteerMultOffset));
*reinterpret_cast<float*>(wheelAddr + wheelSteerMultOffset) = value * sign;
}
}
std::vector<Vector3> VehicleExtensions::GetWheelOffsets(Vehicle handle) {
auto wheels = GetWheelPtrs(handle);
std::vector<Vector3> positions;
int offPosX = 0x20;
int offPosY = 0x24;
int offPosZ = 0x28;
positions.reserve(wheels.size());
for (auto wheelAddr : wheels) {
positions.emplace_back(Vector3 {
*reinterpret_cast<float *>(wheelAddr + offPosX), 0,
*reinterpret_cast<float *>(wheelAddr + offPosY), 0,
*reinterpret_cast<float *>(wheelAddr + offPosZ), 0,
});
}
return positions;
}
std::vector<Vector3> VehicleExtensions::GetWheelLastContactCoords(Vehicle handle) {
auto wheels = GetWheelPtrs(handle);
std::vector<Vector3> positions;
// 0x40: Last wheel contact coordinates
// 0x50: Last wheel contact coordinates but centered on the wheel width
// 0x60: Next probable wheel position? Seems to flutter around a lot, while
// position is entirely lost (0.0) when contact is lost. Wheels that
// steer emphasise this further, though acceleration/deceleration
// will also influence it.
int offPosX = 0x40;
int offPosY = 0x44;
int offPosZ = 0x48;
positions.reserve(wheels.size());
for (auto wheelAddr : wheels) {
positions.emplace_back(Vector3{
*reinterpret_cast<float *>(wheelAddr + offPosX), 0,
*reinterpret_cast<float *>(wheelAddr + offPosY), 0,
*reinterpret_cast<float *>(wheelAddr + offPosZ), 0,
});
}
return positions;
}
std::vector<float> VehicleExtensions::GetWheelCompressions(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> compressions(numWheels);
if (wheelSuspensionCompressionOffset == 0) return compressions;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
compressions[i] = *reinterpret_cast<float *>(wheelAddr + wheelSuspensionCompressionOffset);
}
return compressions;
}
std::vector<float> VehicleExtensions::GetWheelSteeringAngles(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> angles(numWheels);
if (wheelSteeringAngleOffset == 0) return angles;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
angles[i] = *reinterpret_cast<float *>(wheelAddr + wheelSteeringAngleOffset);
}
return angles;
}
std::vector<bool> VehicleExtensions::GetWheelsOnGround(Vehicle handle) {
auto compressions = GetWheelCompressions(handle);
std::vector<bool> onGround;
onGround.reserve(compressions.size());
for (auto comp : compressions) {
onGround.push_back(comp != 0.0f);
}
return onGround;
}
float VehicleExtensions::GetWheelLargestAngle(Vehicle handle) {
float largestAngle = 0.0f;
auto angles = GetWheelSteeringAngles(handle);
for (auto angle : angles) {
if (abs(angle) > abs(largestAngle)) {
largestAngle = angle;
}
}
return largestAngle;
}
float VehicleExtensions::GetWheelAverageAngle(Vehicle handle) {
auto angles = GetWheelSteeringAngles(handle);
float wheelsSteered = 0.0f;
float avgAngle = 0.0f;
for (int i = 0; i < GetNumWheels(handle); i++) {
if (i < 3 && angles[i] != 0.0f) {
wheelsSteered += 1.0f;
avgAngle += angles[i];
}
}
if (wheelsSteered > 0.5f && wheelsSteered < 2.5f) { // bikes, cars, quads
avgAngle /= wheelsSteered;
}
else {
avgAngle = GetSteeringAngle(handle) * GetSteeringMultiplier(handle); // tank, forklift
}
return avgAngle;
}
std::vector<WheelDimensions> VehicleExtensions::GetWheelDimensions(Vehicle handle) {
auto wheels = GetWheelPtrs(handle);
std::vector<WheelDimensions> dimensionsSet;
int offTyreRadius = 0x110;
int offRimRadius = 0x114;
int offTyreWidth = 0x118;
for (auto wheelAddr : wheels) {
if (!wheelAddr) continue;
WheelDimensions dimensions;
dimensions.TyreRadius = *reinterpret_cast<float *>(wheelAddr + offTyreRadius);
dimensions.RimRadius = *reinterpret_cast<float *>(wheelAddr + offRimRadius);
dimensions.TyreWidth = *reinterpret_cast<float *>(wheelAddr + offTyreWidth);
dimensionsSet.push_back(dimensions);
}
return dimensionsSet;
}
std::vector<float> VehicleExtensions::GetWheelRotationSpeeds(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> speeds(numWheels);
if (wheelAngularVelocityOffset == 0) return speeds;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
speeds[i] = -*reinterpret_cast<float *>(wheelAddr + wheelAngularVelocityOffset);
}
return speeds;
}
void VehicleExtensions::SetWheelRotationSpeed(Vehicle handle, uint8_t index, float value) {
if (index > GetNumWheels(handle)) return;
if (wheelAngularVelocityOffset == 0) return;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * index);
*reinterpret_cast<float*>(wheelAddr + wheelAngularVelocityOffset) = value;
}
std::vector<float> VehicleExtensions::GetTyreSpeeds(Vehicle handle) {
int numWheels = GetNumWheels(handle);
std::vector<float> rotationSpeed = GetWheelRotationSpeeds(handle);
std::vector<WheelDimensions> dimensionsSet = GetWheelDimensions(handle);
std::vector<float> wheelSpeeds(numWheels);
for (int i = 0; i < numWheels; i++) {
wheelSpeeds[i] = rotationSpeed[i] * dimensionsSet[i].TyreRadius;
}
return wheelSpeeds;
}
void VehicleExtensions::SetWheelTractionVectorLength(Vehicle handle, uint8_t index, float value) {
if (index > GetNumWheels(handle)) return;
if (wheelTractionVectorLengthOffset == 0) return;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * index);
*reinterpret_cast<float *>(wheelAddr + wheelTractionVectorLengthOffset) = value;
}
std::vector<float> VehicleExtensions::GetWheelTractionVectorLength(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelTractionVectorLengthOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
values[i] = (-*reinterpret_cast<float *>(wheelAddr + wheelTractionVectorLengthOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetWheelTractionVectorY(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelTractionVectorYOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (-*reinterpret_cast<float*>(wheelAddr + wheelTractionVectorYOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetWheelTractionVectorX(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelTractionVectorXOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (-*reinterpret_cast<float*>(wheelAddr + wheelTractionVectorXOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetTyreGrips(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelMatTyreGripOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (*reinterpret_cast<float*>(wheelAddr + wheelMatTyreGripOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetWetGrips(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelMatWetGripOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (*reinterpret_cast<float*>(wheelAddr + wheelMatWetGripOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetTyreDrags(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelMatTyreDragOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (*reinterpret_cast<float*>(wheelAddr + wheelMatTyreDragOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetTopSpeedMults(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelMatTopSpeedMultOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (*reinterpret_cast<float*>(wheelAddr + wheelMatTopSpeedMultOffset));
}
return values;
}
std::vector<uint16_t> VehicleExtensions::GetTireContactMaterial(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
std::vector<uint16_t> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelMatTypeOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = (*reinterpret_cast<uint16_t*>(wheelAddr + wheelMatTypeOffset));
}
return values;
}
std::vector<float> VehicleExtensions::GetWheelPower(Vehicle handle) {
auto numWheels = GetNumWheels(handle);
auto wheelPtr = GetWheelsPtr(handle);
std::vector<float> values(numWheels);
if (wheelPowerOffset == 0) return values;
for (auto i = 0; i < numWheels; ++i) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
values[i] = *reinterpret_cast<float *>(wheelAddr + wheelPowerOffset);
}
return values;
}
void VehicleExtensions::SetWheelPower(Vehicle handle, uint8_t index, float value) {
if (index > GetNumWheels(handle)) return;
if (wheelPowerOffset == 0) return;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * index);
*reinterpret_cast<float *>(wheelAddr + wheelPowerOffset) = value;
}
std::vector<float> VehicleExtensions::GetWheelBrakePressure(Vehicle handle) {
const auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelBrakeOffset == 0) return values;
for (auto i = 0; i < numWheels; ++i) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
values[i] = *reinterpret_cast<float *>(wheelAddr + wheelBrakeOffset);
}
return values;
}
void VehicleExtensions::SetWheelBrakePressure(Vehicle handle, uint8_t index, float value) {
if (index > GetNumWheels(handle)) return;
if (wheelBrakeOffset == 0) return;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * index);
*reinterpret_cast<float *>(wheelAddr + wheelBrakeOffset) = value;
}
bool VehicleExtensions::IsWheelPowered(Vehicle handle, uint8_t index) {
if (index > GetNumWheels(handle)) return false;
if (wheelFlagsOffset == 0) return false;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * index);
auto wheelFlags = *reinterpret_cast<uint32_t *>(wheelAddr + wheelFlagsOffset);
return wheelFlags & 0x10;
}
std::vector<uint16_t> VehicleExtensions::GetWheelFlags(Vehicle handle) {
const auto numWheels = GetNumWheels(handle);
std::vector<uint16_t> flags(numWheels);
auto wheelPtr = GetWheelsPtr(handle);
if (wheelFlagsOffset == 0) return flags;
for (auto i = 0; i < numWheels; ++i) {
auto wheelAddr = *reinterpret_cast<uint64_t *>(wheelPtr + 0x008 * i);
flags[i] = *reinterpret_cast<uint16_t *>(wheelAddr + wheelFlagsOffset);
}
return flags;
}
std::vector<float> VehicleExtensions::GetWheelLoads(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> values(numWheels);
if (wheelLoadOffset == 0) return values;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
values[i] = *reinterpret_cast<float*>(wheelAddr + 0x1BC);
}
return values;
}
std::vector<float> VehicleExtensions::GetWheelDownforces(Vehicle handle) {
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> dfs(numWheels);
if (wheelDownforceOffset == 0) return dfs;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
dfs[i] = *reinterpret_cast<float*>(wheelAddr + wheelDownforceOffset);
}
return dfs;
}
std::vector<float> VehicleExtensions::GetWheelOverheats(Vehicle handle)
{
auto wheelPtr = GetWheelsPtr(handle);
auto numWheels = GetNumWheels(handle);
std::vector<float> vals(numWheels);
if (wheelOverheatOffset == 0) return vals;
for (auto i = 0; i < numWheels; i++) {
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * i);
vals[i] = *reinterpret_cast<float*>(wheelAddr + wheelOverheatOffset);
}
return vals;
}
uint64_t VehicleExtensions::GetWheelHandlingPtr(Vehicle handle, uint8_t index) {
if (handlingOffset == 0) return 0;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * index);
return *reinterpret_cast<uint64_t*>(wheelAddr + 0x120);
}
void VehicleExtensions::SetWheelHandlingPtr(Vehicle handle, uint8_t index, uint64_t value) {
if (handlingOffset == 0) return;
auto address = GetAddress(handle);
if (address == 0) return;
auto wheelPtr = GetWheelsPtr(handle);
auto wheelAddr = *reinterpret_cast<uint64_t*>(wheelPtr + 0x008 * index);
*reinterpret_cast<uint64_t*>(wheelAddr + 0x120) = value;
}
std::vector<uint32_t> VehicleExtensions::GetVehicleFlags(Vehicle handle) {
auto address = GetAddress(handle);
if (!address)
return std::vector<uint32_t>();
std::vector<uint32_t> offs(6);
auto pCVehicleModelInfo = *(uint64_t*)(address + vehicleModelInfoOffset);
for (uint8_t i = 0; i < 6; i++) {
offs[i] = *(uint32_t*)(pCVehicleModelInfo + vehicleFlagsOffset + sizeof(uint32_t) * i);
}
return offs;
}
// These apply to b1103
// 0x7f8 to 0x814 are gear ratios!
// 0x7f8 - Reverse
// 0x7fc - 1
// 0x800 - 2
// 0x804 - 3
// 0x808 - 4
// 0x80c - 5
// 0x810 - 6
// 0x814 - 7
// 0x818: fDriveForce
// Affected by engine upgrade
//
// 0x81C: fInitialDriveMaxFlatVel (m/s)
// Affected by no tuning options
// Doesn't influence anything?
// 0x820: final drive speed
// divide this by gear ratio and there's the top speed for the gear
// b1180
// 0x838 - power? Drive Force?
// 0x9E4 - has spoiler? (2nd bit)
// Couldn't find anything torque-related
// wheel+0x1ec - power/brake flags? abs turned off for e-brake with [wheel+0x1ec] & 0xFFFF3FFF
// b2245
// Wheel
// 0x198 - TYRE_GRIP
// 0x19C - 1.0 - (WET_GRIP * Wetness)
// 0x1A0 - TYRE_DRAG
// 0x1A4 - TOP_SPEED_MULT
// 0x208 - Entity type? Bone?
// 0x20A - Material type (uint16_t)