Skip to content

Commit

Permalink
Impossible to stop helicopter rotor if it has a driver (PR #3621, Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX authored Dec 30, 2024
1 parent 808ddf0 commit c7644f2
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 37 deletions.
65 changes: 31 additions & 34 deletions Client/game_sa/CHeliSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,37 @@
class CHeliSAInterface : public CAutomobileSAInterface
{
public:
std::uint8_t m_heliFlags;

std::uint8_t _pad1[3];
std::uint32_t m_leftRightSkid;
std::uint32_t m_steeringUpDown;
std::uint32_t m_steeringLeftRight;
std::uint32_t m_accelerationBreakStatus;
std::uint32_t field_99C;
std::uint32_t m_rotorZ;
std::uint32_t m_secondRotorZ;
std::uint32_t m_maxAltitude;
std::uint32_t field_9AC;
std::uint32_t m_minAltitude;
std::uint32_t field_9B4;
std::uint8_t field_9B8;
std::uint8_t m_numSwatOccupants;
std::uint8_t m_swatIDs[4];

std::uint8_t _pad2[2];
std::uint32_t field_9C0[4];
std::uint32_t field_9D0;

std::uint32_t m_particlesList;
std::uint8_t field_9D8[24];
std::uint32_t field_9F0;
CVector m_searchLightTarget;
std::uint32_t m_searchLightIntensity;
std::uint32_t field_A04;
std::uint32_t field_A08;
std::uint32_t m_gunflashFx;
std::uint8_t m_firingMultiplier;
std::uint8_t m_searchLightEnabled;
std::uint8_t _pad3[2];
std::uint32_t field_A14;
std::uint8_t m_nHeliFlags; // 0x988
std::uint8_t ___pad1[3]; // 0x989
float m_fLeftRightSkid; // 0x98C
float m_fSteeringUpDown; // 0x990
float m_fSteeringLeftRight; // 0x994
float m_fAccelerationBreakStatus; // 0x998
std::int32_t field_99C; // 0x99C
float m_fRotorZ; // 0x9A0
float m_fSecondRotorZ; // 0x9A4
float m_fMaxAltitude; // 0x9A8
std::int32_t field_9AC; // 0x9AC
float m_fMinAltitude; // 0x9B0
std::int32_t field_9B4; // 0x9B4
std::uint8_t field_9B8; // 0x9B8
std::uint8_t m_nNumSwatOccupants; // 0x9B9
std::uint8_t m_anSwatIDs[4]; // 0x9BA
std::uint8_t ___pad2[2]; // 0x9BE
std::uint32_t field_9C0[4]; // 0x9C0
std::int32_t field_9D0; // 0x9D0
FxSystem_c** m_pParticlesList; // 0x9D4
std::uint8_t field_9D8[24]; // 0x9D8
std::int32_t field_9F0; // 0x9F0
CVector m_vecSearchLightTarget; // 0x9F4
float m_fSearchLightIntensity; // 0xA00
std::int32_t field_A04; // 0xA04
std::int32_t field_A08; // 0xA08
FxSystem_c** m_ppGunflashFx; // 0xA0C
std::uint8_t m_nFiringMultiplier; // 0xA10
bool m_bSearchLightEnabled; // 0xA11
std::uint8_t ___pad3[2]; // 0xA12
std::int32_t field_A14; // 0xA14
};
static_assert(sizeof(CHeliSAInterface) == 0xA18, "Invalid size for CHeliSAInterface");

Expand Down
84 changes: 84 additions & 0 deletions Client/game_sa/CVehicleSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "CProjectileInfoSA.h"
#include "CTrainSA.h"
#include "CPlaneSA.h"
#include "CHeliSA.h"
#include "CVehicleSA.h"
#include "CBoatSA.h"
#include "CVisibilityPluginsSA.h"
Expand Down Expand Up @@ -52,6 +53,62 @@ void _declspec(naked) HOOK_Vehicle_PreRender(void)
}
}

static bool __fastcall CanProcessFlyingCarStuff(CAutomobileSAInterface* vehicleInterface)
{
SClientEntity<CVehicleSA>* vehicle = pGame->GetPools()->GetVehicle((DWORD*)vehicleInterface);
if (!vehicle || !vehicle->pEntity)
return true;

return vehicle->pEntity->GetVehicleRotorState();
}

static constexpr DWORD CONTINUE_CHeli_ProcessFlyingCarStuff = 0x6C4E82;
static constexpr DWORD RETURN_CHeli_ProcessFlyingCarStuff = 0x6C5404;
static void _declspec(naked) HOOK_CHeli_ProcessFlyingCarStuff()
{
_asm
{
mov esi, ecx
mov al, [esi+36h]

pushad
call CanProcessFlyingCarStuff
test al, al
jz skip

popad
jmp CONTINUE_CHeli_ProcessFlyingCarStuff

skip:
popad
jmp RETURN_CHeli_ProcessFlyingCarStuff
}
}

static constexpr DWORD CONTINUE_CPlane_ProcessFlyingCarStuff = 0x6CB7D7;
static constexpr DWORD RETURN_CPlane_ProcessFlyingCarStuff = 0x6CC482;
static void _declspec(naked) HOOK_CPlane_ProcessFlyingCarStuff()
{
_asm
{
push esi
mov esi, ecx
fnstsw ax

pushad
call CanProcessFlyingCarStuff
test al, al
jz skip

popad
jmp CONTINUE_CPlane_ProcessFlyingCarStuff

skip:
popad
jmp RETURN_CPlane_ProcessFlyingCarStuff
}
}

namespace
{
bool ClumpDumpCB(RpAtomic* pAtomic, void* data)
Expand Down Expand Up @@ -491,6 +548,29 @@ void CVehicleSA::SetTrainSpeed(float fSpeed)
pInterface->m_fTrainSpeed = fSpeed;
}

float CVehicleSA::GetHeliRotorSpeed() const
{
return static_cast<CHeliSAInterface*>(m_pInterface)->m_wheelSpeed[1];
}

void CVehicleSA::SetHeliRotorSpeed(float speed)
{
static_cast<CHeliSAInterface*>(GetInterface())->m_wheelSpeed[1] = speed;
}

void CVehicleSA::SetVehicleRotorState(bool state, bool stopRotor, bool isHeli) noexcept
{
m_rotorState = state;

if (state || !stopRotor)
return;

if (isHeli)
SetHeliRotorSpeed(0.0f);
else
SetPlaneRotorSpeed(0.0f);
}

void CVehicleSA::SetPlaneRotorSpeed(float fSpeed)
{
auto pInterface = static_cast<CPlaneSAInterface*>(GetInterface());
Expand Down Expand Up @@ -1849,6 +1929,10 @@ void CVehicleSA::StaticSetHooks()
{
// Setup vehicle sun glare hook
HookInstall(FUNC_CAutomobile_OnVehiclePreRender, (DWORD)HOOK_Vehicle_PreRender, 5);

// Setup hooks to handle setVehicleRotorState function
HookInstall(FUNC_CHeli_ProcessFlyingCarStuff, (DWORD)HOOK_CHeli_ProcessFlyingCarStuff, 5);
HookInstall(FUNC_CPlane_ProcessFlyingCarStuff, (DWORD)HOOK_CPlane_ProcessFlyingCarStuff, 5);
}

void CVehicleSA::SetVehiclesSunGlareEnabled(bool bEnabled)
Expand Down
10 changes: 8 additions & 2 deletions Client/game_sa/CVehicleSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ struct RwTexture;
#define FUNC_CAutomobile_OnVehiclePreRender 0x6ABCFD
#define FUNC_CVehicle_DoSunGlare 0x6DD6F0

#define FUNC_CHeli_ProcessFlyingCarStuff 0x6C4E7D
#define FUNC_CPlane_ProcessFlyingCarStuff 0x6CB7D2

// CClumpModelInfo::GetFrameFromName
#define FUNC_CClumpModelInfo_GetFrameFromName 0x4C5400

Expand Down Expand Up @@ -422,6 +425,7 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
unsigned char m_ucVariant2;
unsigned char m_ucVariantCount{0};
bool m_doorsUndamageable{false};
bool m_rotorState{true};

std::array<CVector, VEHICLE_DUMMY_COUNT> m_dummyPositions;

Expand Down Expand Up @@ -552,7 +556,8 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
bool GetTakeLessDamage() { return GetVehicleInterface()->m_nVehicleFlags.bTakeLessDamage; };
bool GetTyresDontBurst() { return GetVehicleInterface()->m_nVehicleFlags.bTyresDontBurst; };
unsigned short GetAdjustablePropertyValue() { return *reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned long>(m_pInterface) + 2156); };
float GetHeliRotorSpeed() { return *reinterpret_cast<float*>(reinterpret_cast<unsigned int>(m_pInterface) + 2124); };
float GetHeliRotorSpeed() const;
bool GetVehicleRotorState() const noexcept override { return m_rotorState; }
float GetPlaneRotorSpeed();

unsigned long GetExplodeTime() { return *reinterpret_cast<unsigned long*>(reinterpret_cast<unsigned int>(m_pInterface) + 1240); };
Expand All @@ -578,7 +583,8 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
{
*reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned int>(m_pInterface) + 2156) = usAdjustableProperty;
};
void SetHeliRotorSpeed(float fSpeed) { *reinterpret_cast<float*>(reinterpret_cast<unsigned int>(m_pInterface) + 2124) = fSpeed; };
void SetHeliRotorSpeed(float speed);
void SetVehicleRotorState(bool state, bool stopRotor, bool isHeli) noexcept override;
void SetPlaneRotorSpeed(float fSpeed);
bool SetVehicleWheelRotation(float fWheelRot1, float fWheelRot2, float fWheelRot3, float fWheelRot4) noexcept;
void SetExplodeTime(unsigned long ulTime) { *reinterpret_cast<unsigned long*>(reinterpret_cast<unsigned int>(m_pInterface) + 1240) = ulTime; };
Expand Down
13 changes: 13 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,19 @@ void CClientVehicle::SetHeliRotorSpeed(float fSpeed)
m_fHeliRotorSpeed = fSpeed;
}

bool CClientVehicle::GetVehicleRotorState() const noexcept
{
return m_pVehicle && (m_eVehicleType == CLIENTVEHICLE_HELI || m_eVehicleType == CLIENTVEHICLE_PLANE) ? m_pVehicle->GetVehicleRotorState() : m_rotorState;
}

void CClientVehicle::SetVehicleRotorState(bool state, bool stopRotor) noexcept
{
if (m_pVehicle && (m_eVehicleType == CLIENTVEHICLE_HELI || m_eVehicleType == CLIENTVEHICLE_PLANE))
m_pVehicle->SetVehicleRotorState(state, stopRotor, GetVehicleType() == CLIENTVEHICLE_HELI);

m_rotorState = state;
}

void CClientVehicle::SetPlaneRotorSpeed(float fSpeed)
{
if (m_pVehicle && m_eVehicleType == CLIENTVEHICLE_PLANE)
Expand Down
3 changes: 3 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,12 @@ class CClientVehicle : public CClientStreamElement
// TODO: Make the class remember on virtualization
float GetHeliRotorSpeed();
float GetPlaneRotorSpeed();
bool GetVehicleRotorState() const noexcept;

bool GetRotorSpeed(float&);
bool SetRotorSpeed(float);
bool SetWheelsRotation(float fRot1, float fRot2, float fRot3, float fRot4) noexcept;
void SetVehicleRotorState(bool state, bool stopRotor) noexcept;
void SetHeliRotorSpeed(float fSpeed);
void SetPlaneRotorSpeed(float fSpeed);
bool IsHeliSearchLightVisible();
Expand Down Expand Up @@ -673,6 +675,7 @@ class CClientVehicle : public CClientStreamElement
uchar m_ucTrackID;
bool m_bJustStreamedIn;
bool m_bWheelScaleChanged;
bool m_rotorState{true};

// Time dependent error compensation interpolation
struct
Expand Down
19 changes: 19 additions & 0 deletions Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void CLuaVehicleDefs::LoadFunctions()
{"getVehicleWheelFrictionState", ArgumentParser<GetVehicleWheelFrictionState>},
{"getVehicleEntryPoints", ArgumentParser<GetVehicleEntryPoints>},
{"isVehicleSmokeTrailEnabled", ArgumentParser<IsSmokeTrailEnabled>},
{"getVehicleRotorState", ArgumentParser<GetVehicleRotorState>},

// Vehicle set funcs
{"createVehicle", CreateVehicle},
Expand Down Expand Up @@ -161,6 +162,7 @@ void CLuaVehicleDefs::LoadFunctions()
{"setVehicleModelWheelSize", ArgumentParser<SetVehicleModelWheelSize>},
{"spawnVehicleFlyingComponent", ArgumentParser<SpawnVehicleFlyingComponent>},
{"setVehicleSmokeTrailEnabled", ArgumentParser<SetSmokeTrailEnabled>},
{"setVehicleRotorState", ArgumentParser<SetVehicleRotorState>},
};

// Add functions
Expand Down Expand Up @@ -250,6 +252,7 @@ void CLuaVehicleDefs::AddClass(lua_State* luaVM)
lua_classfunction(luaVM, "getWheelFrictionState", "getVehicleWheelFrictionState");
lua_classfunction(luaVM, "getEntryPoints", ArgumentParser<OOP_GetVehicleEntryPoints>);
lua_classfunction(luaVM, "isSmokeTrailEnabled", "isVehicleSmokeTrailEnabled");
lua_classfunction(luaVM, "getRotorState", "getVehicleRotorState");

lua_classfunction(luaVM, "setComponentVisible", "setVehicleComponentVisible");
lua_classfunction(luaVM, "setSirensOn", "setVehicleSirensOn");
Expand Down Expand Up @@ -299,6 +302,7 @@ void CLuaVehicleDefs::AddClass(lua_State* luaVM)
lua_classfunction(luaVM, "setWheelScale", "setVehicleWheelScale");
lua_classfunction(luaVM, "setModelWheelSize", "setVehicleModelWheelSize");
lua_classfunction(luaVM, "setSmokeTrailEnabled", "setVehicleSmokeTrailEnabled");
lua_classfunction(luaVM, "setRotorState", "setVehicleRotorState");

lua_classfunction(luaVM, "resetComponentPosition", "resetVehicleComponentPosition");
lua_classfunction(luaVM, "resetComponentRotation", "resetVehicleComponentRotation");
Expand Down Expand Up @@ -357,6 +361,7 @@ void CLuaVehicleDefs::AddClass(lua_State* luaVM)
lua_classvariable(luaVM, "gravity", SetVehicleGravity, OOP_GetVehicleGravity);
lua_classvariable(luaVM, "turnVelocity", SetVehicleTurnVelocity, OOP_GetVehicleTurnVelocity);
lua_classvariable(luaVM, "wheelScale", "setVehicleWheelScale", "getVehicleWheelScale");
lua_classvariable(luaVM, "rotorState", "setVehicleRotorState", "getVehicleRotorState");

lua_registerclass(luaVM, "Vehicle", "Element");
}
Expand Down Expand Up @@ -4398,3 +4403,17 @@ bool CLuaVehicleDefs::IsSmokeTrailEnabled(CClientVehicle* vehicle) noexcept
{
return vehicle->IsSmokeTrailEnabled();
}

bool CLuaVehicleDefs::SetVehicleRotorState(CClientVehicle* vehicle, bool state, std::optional<bool> stopRotor) noexcept
{
if (vehicle->GetVehicleType() != eClientVehicleType::CLIENTVEHICLE_HELI && vehicle->GetVehicleType() != eClientVehicleType::CLIENTVEHICLE_PLANE)
return false;

vehicle->SetVehicleRotorState(state, stopRotor.value_or(true));
return true;
}

bool CLuaVehicleDefs::GetVehicleRotorState(CClientVehicle* vehicle) noexcept
{
return vehicle->GetVehicleRotorState();
}
3 changes: 3 additions & 0 deletions Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ class CLuaVehicleDefs : public CLuaDefs
static bool SetVehicleModelWheelSize(const unsigned short usModel, const eResizableVehicleWheelGroup eWheelGroup, const float fWheelSize);
static int GetVehicleWheelFrictionState(CClientVehicle* pVehicle, unsigned char wheel);

static bool SetVehicleRotorState(CClientVehicle* const vehicle, bool state, std::optional<bool> stopRotor) noexcept;
static bool GetVehicleRotorState(CClientVehicle* const vehicle) noexcept;

static bool AddVehicleSirens(CClientVehicle* vehicle, std::uint8_t sirenType, std::uint8_t sirenCount, std::optional<bool> enable360, std::optional<bool> enableLOSCheck, std::optional<bool> enableRandomiser, std::optional<bool> enableSilent) noexcept;
static bool RemoveVehicleSirens(CClientVehicle* vehicle) noexcept;

Expand Down
4 changes: 3 additions & 1 deletion Client/sdk/game/CVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ class CVehicle : public virtual CPhysical
virtual bool GetTakeLessDamage() = 0;
virtual bool GetTyresDontBurst() = 0;
virtual unsigned short GetAdjustablePropertyValue() = 0;
virtual float GetHeliRotorSpeed() = 0;
virtual float GetHeliRotorSpeed() const = 0;
virtual bool GetVehicleRotorState() const noexcept = 0;
virtual float GetPlaneRotorSpeed() = 0;
virtual unsigned long GetExplodeTime() = 0;

Expand All @@ -220,6 +221,7 @@ class CVehicle : public virtual CPhysical
virtual void SetTyresDontBurst(bool bTyresDontBurst) = 0;
virtual void SetAdjustablePropertyValue(unsigned short usAdjustableProperty) = 0;
virtual void SetHeliRotorSpeed(float fSpeed) = 0;
virtual void SetVehicleRotorState(bool state, bool stopRotor, bool isHeli) noexcept = 0;
virtual void SetPlaneRotorSpeed(float fSpeed) = 0;
virtual bool SetVehicleWheelRotation(float fRot1, float fRot2, float fRot3, float fRot4) noexcept = 0;
virtual void SetTaxiLightOn(bool bLightState) = 0;
Expand Down

0 comments on commit c7644f2

Please sign in to comment.