Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #552 Impossible to stop helicopter rotor if it has a driver #3621

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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 @@ -484,6 +541,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)
FileEX marked this conversation as resolved.
Show resolved Hide resolved
{
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 @@ -1838,6 +1918,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 @@ -1576,6 +1576,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 @@ -92,6 +92,7 @@ void CLuaVehicleDefs::LoadFunctions()
{"getVehicleModelWheelSize", ArgumentParser<GetVehicleModelWheelSize>},
{"getVehicleWheelFrictionState", ArgumentParser<GetVehicleWheelFrictionState>},
{"getVehicleEntryPoints", ArgumentParser<GetVehicleEntryPoints>},
{"getVehicleRotorState", ArgumentParser<GetVehicleRotorState>},

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

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

lua_classfunction(luaVM, "setComponentVisible", "setVehicleComponentVisible");
lua_classfunction(luaVM, "setSirensOn", "setVehicleSirensOn");
Expand Down Expand Up @@ -292,6 +295,7 @@ void CLuaVehicleDefs::AddClass(lua_State* luaVM)
lua_classfunction(luaVM, "setVariant", "setVehicleVariant");
lua_classfunction(luaVM, "setWheelScale", "setVehicleWheelScale");
lua_classfunction(luaVM, "setModelWheelSize", "setVehicleModelWheelSize");
lua_classfunction(luaVM, "setRotorState", "setVehicleRotorState");

lua_classfunction(luaVM, "resetComponentPosition", "resetVehicleComponentPosition");
lua_classfunction(luaVM, "resetComponentRotation", "resetVehicleComponentRotation");
Expand Down Expand Up @@ -350,6 +354,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 @@ -4340,3 +4345,17 @@ bool CLuaVehicleDefs::SpawnVehicleFlyingComponent(CClientVehicle* const vehicle,

return vehicle->SpawnFlyingComponent(partNodeIndex, collisionType, removalTime.value_or(-1));
}

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;

// Components
LUA_DECLARE(SetVehicleComponentPosition);
LUA_DECLARE_OOP(GetVehicleComponentPosition);
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
Loading