Skip to content

Add new world special property (vehicle_engine_autostart) #4238

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

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 14 additions & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,20 @@ void CGameSA::SetVehicleBurnExplosionsEnabled(bool isEnabled)
m_isVehicleBurnExplosionsEnabled = isEnabled;
}

void CGameSA::SetVehicleEngineManualModeEnabled(bool isEnabled)
{
if (isEnabled)
{
MemSet((void*)0x64BC03, 0x90, 5); // prevent vehicle engine from turning on (driver enter)
MemCpy((void*)0x6C4EA9, "\xE9\x15\x03\x00", 4); // prevent aircraft engine from turning off (driver exit)
}
else
{
MemCpy((void*)0x64BC03, "\x75\x05\x80\xC9\x10", 5);
MemCpy((void*)0x6C4EA9, "\x8A\x86\x28\x04", 4);
}
}

bool CGameSA::PerformChecks()
{
std::map<std::string, SCheatSA*>::iterator it;
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ class CGameSA : public CGame
bool IsVehicleBurnExplosionsEnabled() const noexcept override { return m_isVehicleBurnExplosionsEnabled; }
void SetVehicleBurnExplosionsEnabled(bool isEnabled) override;

void SetVehicleEngineManualModeEnabled(bool isEnabled) override;

unsigned long GetMinuteDuration();
void SetMinuteDuration(unsigned long ulTime);

Expand Down
28 changes: 27 additions & 1 deletion Client/game_sa/CVehicleSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,39 @@ void _declspec(naked) HOOK_Vehicle_PreRender(void)
}
}

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

return vehicle->pEntity->GetVehicleRotorState();
if (vehicle->pEntity->GetVehicleRotorState())
{
if (*(unsigned char*)0x64BC03 == 0x75) // keep default behavior
return true;

if (vehicle->pEntity->GetEntityStatus() != eEntityStatus::STATUS_PHYSICS && !vehicle->pEntity->IsBeingDriven())
{
vehicle->pEntity->SetEntityStatus(eEntityStatus::STATUS_PHYSICS); // this will make rotors spin without driver when engine is on
return false;
}
if (!vehicle->pEntity->IsEngineOn())
{
// Smoothly change rotors speed to 0
float speed = vehicle->pEntity->GetHeliRotorSpeed();
if (speed > 0)
vehicle->pEntity->SetHeliRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.00055f)); // 0x6C4EB7

speed = vehicle->pEntity->GetPlaneRotorSpeed();
if (speed > 0)
vehicle->pEntity->SetPlaneRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.003f)); // 0x6CC145

return false;
}
return true;
}
return false;
}

static constexpr DWORD CONTINUE_CHeli_ProcessFlyingCarStuff = 0x6C4E82;
Expand Down
17 changes: 17 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6057,6 +6057,9 @@ bool CClientGame::SetWorldSpecialProperty(const WorldSpecialProperty property, c
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
g_pGame->SetVehicleBurnExplosionsEnabled(enabled);
break;
case WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE:
SetVehicleEngineManualModeEnabled(enabled);
break;
default:
return false;
}
Expand Down Expand Up @@ -6103,6 +6106,8 @@ bool CClientGame::IsWorldSpecialProperty(const WorldSpecialProperty property)
return m_pVehicleManager->IsSpawnFlyingComponentEnabled();
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
return g_pGame->IsVehicleBurnExplosionsEnabled();
case WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE:
return IsVehicleEngineManualModeEnabled();
}

return false;
Expand Down Expand Up @@ -6138,6 +6143,17 @@ bool CClientGame::IsWeaponRenderEnabled() const
return g_pGame->IsWeaponRenderEnabled();
}

void CClientGame::SetVehicleEngineManualModeEnabled(bool isEnabled)
{
if (isEnabled == m_isVehEngineManualModeEnabled)
return;

g_pGame->SetVehicleEngineManualModeEnabled(isEnabled);
m_pVehicleManager->ResetNotControlledRotors(isEnabled);

m_isVehEngineManualModeEnabled = isEnabled;
}

#pragma code_seg(".text")
bool CClientGame::VerifySADataFiles(int iEnableClientChecks)
{
Expand Down Expand Up @@ -6823,6 +6839,7 @@ void CClientGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo
g_pGame->SetIgnoreFireStateEnabled(false);
m_pVehicleManager->SetSpawnFlyingComponentEnabled(true);
g_pGame->SetVehicleBurnExplosionsEnabled(true);
SetVehicleEngineManualModeEnabled(false);
}

// Reset all setWorldProperty to default
Expand Down
5 changes: 5 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ class CClientGame
void SetWeaponRenderEnabled(bool enabled);
bool IsWeaponRenderEnabled() const;

bool IsVehicleEngineManualModeEnabled() const noexcept { return m_isVehEngineManualModeEnabled; }
void SetVehicleEngineManualModeEnabled(bool isEnabled);

void ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo);

CTransferBox* GetTransferBox() { return m_pTransferBox; };
Expand Down Expand Up @@ -784,6 +787,8 @@ class CClientGame
// Birds Enabled
bool m_bBirdsEnabled;

bool m_isVehEngineManualModeEnabled{false};

unsigned long m_ulMinuteDuration;

CClientGUIElement* m_pClickedGUIElement;
Expand Down
17 changes: 17 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,3 +791,20 @@ void CClientVehicleManager::RestreamVehicleUpgrades(unsigned short usModel)
pVehicle->GetUpgrades()->RestreamVehicleUpgrades(usModel);
}
}

void CClientVehicleManager::ResetNotControlledRotors(bool isManualMode)
{
// Reset rotors to custom or original state for loaded vehicles without controller
// Custom state allows rotors to spin without driver inside (if engine is on)
eEntityStatus status = isManualMode ? eEntityStatus::STATUS_PHYSICS : eEntityStatus::STATUS_ABANDONED;
for (auto& pVehicle : m_List)
{
if (pVehicle->GetGameEntity() && pVehicle->GetVehicleRotorState() && !pVehicle->IsDriven())
{
float speed = (isManualMode && pVehicle->IsEngineOn()) ? 0.001f : 0.0f;
pVehicle->GetGameEntity()->SetEntityStatus(status);
pVehicle->SetHeliRotorSpeed(speed);
pVehicle->SetPlaneRotorSpeed(speed);
}
}
}
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class CClientVehicleManager
bool IsSpawnFlyingComponentEnabled() const noexcept { return m_spawnFlyingComponentsDuringRecreate; }
void SetSpawnFlyingComponentEnabled(bool isEnabled) noexcept { m_spawnFlyingComponentsDuringRecreate = isEnabled; }

void ResetNotControlledRotors(bool isManualMode);

protected:
CClientManager* m_pManager;
bool m_bCanRemoveFromList;
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CPacketHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2402,6 +2402,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream)
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::IGNOREFIRESTATE, wsProps.data6.ignoreFireState);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::FLYINGCOMPONENTS, wsProps.data7.flyingcomponents);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, wsProps.data8.vehicleburnexplosions);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, wsProps.data9.vehEngineManualMode);

float fJetpackMaxHeight = 100;
if (!bitStream.Read(fJetpackMaxHeight))
Expand Down
2 changes: 2 additions & 0 deletions Client/sdk/game/CGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ class __declspec(novtable) CGame
virtual bool IsVehicleBurnExplosionsEnabled() const noexcept = 0;
virtual void SetVehicleBurnExplosionsEnabled(bool isEnabled) = 0;

virtual void SetVehicleEngineManualModeEnabled(bool isEnabled) = 0;

virtual CWeapon* CreateWeapon() = 0;
virtual CWeaponStat* CreateWeaponStat(eWeaponType weaponType, eWeaponSkill weaponSkill) = 0;

Expand Down
5 changes: 4 additions & 1 deletion Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti
m_WorldSpecialProps[WorldSpecialProperty::IGNOREFIRESTATE] = false;
m_WorldSpecialProps[WorldSpecialProperty::FLYINGCOMPONENTS] = true;
m_WorldSpecialProps[WorldSpecialProperty::VEHICLEBURNEXPLOSIONS] = true;
m_WorldSpecialProps[WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE] = false;

m_JetpackWeapons[WEAPONTYPE_MICRO_UZI] = true;
m_JetpackWeapons[WEAPONTYPE_TEC9] = true;
Expand Down Expand Up @@ -3405,7 +3406,8 @@ void CGame::Packet_Vehicle_InOut(CVehicleInOutPacket& Packet)
pPed->SetVehicleAction(CPed::VEHICLEACTION_NONE);

// Update our engine State
pVehicle->SetEngineOn(true);
if (!g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE))
pVehicle->SetEngineOn(true);

// Tell everyone he's in (they should warp him in)
CVehicleInOutPacket Reply(PedID, VehicleID, ucOccupiedSeat, VEHICLE_NOTIFY_IN_RETURN);
Expand Down Expand Up @@ -4524,6 +4526,7 @@ void CGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo)
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE, false);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS, true);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, true);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, false);
}

// Reset all weather stuff like heat haze, wind velocity etc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4262,7 +4262,7 @@ bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehic
pPed->SetVehicleAction(CPed::VEHICLEACTION_NONE);

// If he's the driver, switch on the engine
if (uiSeat == 0)
if (uiSeat == 0 && !g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE))
pVehicle->SetEngineOn(true);

// Tell all the players
Expand Down
1 change: 1 addition & 0 deletions Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const
wsProps.data6.ignoreFireState = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE);
wsProps.data7.flyingcomponents = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS);
wsProps.data8.vehicleburnexplosions = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS);
wsProps.data9.vehEngineManualMode = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE);
BitStream.Write(&wsProps);
}

Expand Down
1 change: 1 addition & 0 deletions Shared/mods/deathmatch/logic/Enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ ADD_ENUM(WorldSpecialProperty::TUNNELWEATHERBLEND, "tunnelweatherblend")
ADD_ENUM(WorldSpecialProperty::IGNOREFIRESTATE, "ignorefirestate")
ADD_ENUM(WorldSpecialProperty::FLYINGCOMPONENTS, "flyingcomponents")
ADD_ENUM(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, "vehicleburnexplosions")
ADD_ENUM(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, "vehenginemanualmode")
IMPLEMENT_ENUM_CLASS_END("world-special-property")

IMPLEMENT_ENUM_BEGIN(ePacketID)
Expand Down
1 change: 1 addition & 0 deletions Shared/mods/deathmatch/logic/Enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum class WorldSpecialProperty
IGNOREFIRESTATE,
FLYINGCOMPONENTS,
VEHICLEBURNEXPLOSIONS,
VEHICLE_ENGINE_MANUAL_MODE,
};
DECLARE_ENUM_CLASS(WorldSpecialProperty);

Expand Down
18 changes: 18 additions & 0 deletions Shared/sdk/net/SyncStructures.h
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,10 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
{
BITCOUNT8 = 1
};
enum
{
BITCOUNT9 = 1
};

bool Read(NetBitStreamInterface& bitStream)
{
Expand Down Expand Up @@ -2121,6 +2125,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data8), BITCOUNT8);
else
data8.vehicleburnexplosions = true;

if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineManualMode))
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data9), BITCOUNT9);
else
data9.vehEngineManualMode = false;

//// Example for adding item:
// if (bitStream.Can(eBitStreamVersion::YourProperty))
Expand Down Expand Up @@ -2154,6 +2163,9 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleBurnExplosions))
bitStream.WriteBits(reinterpret_cast<const char*>(&data8), BITCOUNT8);

if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineManualMode))
bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);

//// Example for adding item:
// if (bitStream.Can(eBitStreamVersion::YourProperty))
// bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);
Expand Down Expand Up @@ -2210,6 +2222,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
{
bool vehicleburnexplosions : 1;
} data8;

struct
{
bool vehEngineManualMode : 1;
} data9;

SWorldSpecialPropertiesStateSync()
{
Expand All @@ -2233,6 +2250,7 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
data6.ignoreFireState = false;
data7.flyingcomponents = true;
data8.vehicleburnexplosions = true;
data9.vehEngineManualMode = false;
}
};

Expand Down
4 changes: 4 additions & 0 deletions Shared/sdk/net/bitstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,10 @@ enum class eBitStreamVersion : unsigned short
// 2025-05-26
ServersideBuildingElement,

// Add "vehenginemanualmode" to setWorldSpecialPropertyEnabled
// 2025-05-29
WorldSpecialProperty_VehicleEngineManualMode,

// This allows us to automatically increment the BitStreamVersion when things are added to this enum.
// Make sure you only add things above this comment.
Next,
Expand Down
Loading