Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions code/components/extra-natives-five/src/VehicleExtraNatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ static hook::cdecl_stub<bool(void*, int)> getWheelBroken([]
return hook::get_call(hook::get_pattern("E8 ? ? ? ? 48 8B CD 41 88 84 1F"));
});

static hook::cdecl_stub<void(void*)> restoreVehicleWheelState([]
{
return hook::get_pattern("45 33 C0 B8 00 00 7A 44 89 81 E8 01 00 00");
});

static hook::cdecl_stub<void(void*, int)> reattachByBoneIndex([]
{
return hook::get_call(hook::get_pattern("0F BE 57 06 48 8B 8E C0 09 00 00 E8", 11));
});

static hook::cdecl_stub<void(void*, bool)> switchEngineOff([]
{
return hook::get_call(hook::get_pattern("E8 ? ? ? ? 48 8B 8B ? ? ? ? 0F 2F FE"));
Expand Down Expand Up @@ -327,6 +337,7 @@ static char* VehicleTopSpeedModifierPtr;
static int VehicleCheatPowerIncreaseOffset;

static int VehicleDamageStructOffset;
static int BrokenWheelsMaskOffset;

static bool* g_trainsForceDoorsOpen;
static int TrainDoorCountOffset;
Expand Down Expand Up @@ -806,6 +817,16 @@ static HookFunction initFunction([]()
VehicleDamageStructOffset = *(uint32_t*)(location - 11);
}

{
// read the broken-wheels bitmask offset from the IS_VEHICLE_WHEEL_BROKEN_OFF
// mov eax, [rcx+A98h] <-- bitmask offset we extract
// bt eax, edx
// setb al
// retn
auto fn = hook::get_pattern<char>("8B 81 ? ? 00 00 0F A3 D0 0F 92 C0 C3");
BrokenWheelsMaskOffset = *(int32_t*)(fn + 2);
}

{
VehiclePitchBiasOffset = *hook::get_pattern<uint32_t>("0F 2F F7 44 0F 28 C0 F3 44 0F 58 83", 12);
VehicleRollBiasOffset = VehiclePitchBiasOffset - 4;
Expand Down Expand Up @@ -2007,6 +2028,45 @@ static HookFunction initFunction([]()
}
});

fx::ScriptEngine::RegisterNativeHandler("RESTORE_VEHICLE_WHEEL", [](fx::ScriptContext& context)
{
if (fwEntity* vehicle = getAndCheckVehicle(context, "RESTORE_VEHICLE_WHEEL"))
{
auto wheelIndex = context.GetArgument<uint32_t>(1);
auto numWheels = readValue<unsigned char>(vehicle, NumWheelsOffset);

if (wheelIndex >= numWheels)
return;

if (!getWheelBroken(vehicle, wheelIndex))
return;


*reinterpret_cast<uint32_t*>((char*)vehicle + BrokenWheelsMaskOffset) &= ~(1u << wheelIndex);

auto wheelsAddress = readValue<uint64_t>(vehicle, WheelsPtrOffset);
auto wheelPtr = reinterpret_cast<void*>(*reinterpret_cast<uint64_t*>(wheelsAddress + 8 * wheelIndex));

if (!wheelPtr)
{
return;
}

restoreVehicleWheelState(wheelPtr);

// reattach only this wheel's fragment child not the whole vehicle (reattachVehicleFragments
// would restore hoods/doors/bumpers too) For deleteWheel=true the fragment was deleted
// so RestoreAbove recreates it from fragType data For deleteWheel=false it's a no-op
auto boneIndex = *reinterpret_cast<int8_t*>((char*)wheelPtr + 0x10C);
if (boneIndex >= 0)
{
auto fragInst = *reinterpret_cast<void**>((char*)vehicle + 0x9C0);
if (fragInst)
reattachByBoneIndex(fragInst, boneIndex);
}
}
});

fx::ScriptEngine::RegisterNativeHandler("SET_FUEL_CONSUMPTION_STATE", [](fx::ScriptContext& context)
{
g_isFuelConsumptionOn = context.GetArgument<bool>(0);
Expand Down
33 changes: 33 additions & 0 deletions ext/native-decls/RestoreVehicleWheel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
ns: CFX
apiset: client
game: gta5
---
## RESTORE_VEHICLE_WHEEL

```c
void RESTORE_VEHICLE_WHEEL(Vehicle vehicle, int wheelIndex);
```

Restores a previously broken-off vehicle wheel by index. Inverse of [BREAK_OFF_VEHICLE_WHEEL](#_0xA274CADB).

Clears the broken-off state, restores tyre and suspension health to full, and reattaches the detached wheel fragment back to the vehicle.

Please note that this is not synchronized across the network.

## Examples
```lua
local vehicle = GetVehiclePedIsIn(PlayerPedId())

if DoesEntityExist(vehicle) then
for i = 0, GetVehicleNumberOfWheels(vehicle) - 1 do
if IsVehicleWheelBrokenOff(vehicle, i) then
RestoreVehicleWheel(vehicle, i)
end
end
end
```

## Parameters
* **vehicle**: The vehicle handle.
* **wheelIndex**: The wheel index to restore.
Loading