Skip to content

Commit 8b3f344

Browse files
authored
Add new world special property (vehicle_engine_autostart) (#4238)
* Add new world special property (vehenginemanualmode) * Move SetVehicleEngineManualModeEnabled() to appropriate module * Restore original implementation of SetVehicleEngineManualModeEnabled() * Use direct memory check instead of new variable * Move Is/SetVehicleEngineManualModeEnabled back to MultiplayerSA * Rename property to vehicle_engine_autostart * Fix typo
1 parent 93963a9 commit 8b3f344

File tree

16 files changed

+129
-4
lines changed

16 files changed

+129
-4
lines changed

Client/game_sa/CVehicleSA.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
*****************************************************************************/
1111

1212
#include "StdInc.h"
13+
#include <core/CCoreInterface.h>
14+
#include <multiplayer/CMultiplayer.h>
1315
#include "CAutomobileSA.h"
1416
#include "CBikeSA.h"
1517
#include "CCameraSA.h"
@@ -28,7 +30,8 @@
2830
#include "gamesa_renderware.h"
2931
#include "CFireManagerSA.h"
3032

31-
extern CGameSA* pGame;
33+
extern CCoreInterface* g_pCore;
34+
extern CGameSA* pGame;
3235

3336
static BOOL m_bVehicleSunGlare = false;
3437
_declspec(naked) void DoVehicleSunGlare(void* this_)
@@ -54,13 +57,39 @@ void _declspec(naked) HOOK_Vehicle_PreRender(void)
5457
}
5558
}
5659

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

63-
return vehicle->pEntity->GetVehicleRotorState();
67+
if (vehicle->pEntity->GetVehicleRotorState())
68+
{
69+
if (g_pCore->GetMultiplayer()->IsVehicleEngineAutoStartEnabled()) // keep default behavior
70+
return true;
71+
72+
if (vehicle->pEntity->GetEntityStatus() != eEntityStatus::STATUS_PHYSICS && !vehicle->pEntity->IsBeingDriven())
73+
{
74+
vehicle->pEntity->SetEntityStatus(eEntityStatus::STATUS_PHYSICS); // this will make rotors spin without driver when engine is on
75+
return false;
76+
}
77+
if (!vehicle->pEntity->IsEngineOn())
78+
{
79+
// Smoothly change rotors speed to 0
80+
float speed = vehicle->pEntity->GetHeliRotorSpeed();
81+
if (speed > 0)
82+
vehicle->pEntity->SetHeliRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.00055f)); // 0x6C4EB7
83+
84+
speed = vehicle->pEntity->GetPlaneRotorSpeed();
85+
if (speed > 0)
86+
vehicle->pEntity->SetPlaneRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.003f)); // 0x6CC145
87+
88+
return false;
89+
}
90+
return true;
91+
}
92+
return false;
6493
}
6594

6695
static constexpr DWORD CONTINUE_CHeli_ProcessFlyingCarStuff = 0x6C4E82;

Client/mods/deathmatch/logic/CClientGame.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6057,6 +6057,9 @@ bool CClientGame::SetWorldSpecialProperty(const WorldSpecialProperty property, c
60576057
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
60586058
g_pGame->SetVehicleBurnExplosionsEnabled(enabled);
60596059
break;
6060+
case WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART:
6061+
SetVehicleEngineAutoStartEnabled(enabled);
6062+
break;
60606063
default:
60616064
return false;
60626065
}
@@ -6103,6 +6106,8 @@ bool CClientGame::IsWorldSpecialProperty(const WorldSpecialProperty property)
61036106
return m_pVehicleManager->IsSpawnFlyingComponentEnabled();
61046107
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
61056108
return g_pGame->IsVehicleBurnExplosionsEnabled();
6109+
case WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART:
6110+
return IsVehicleEngineAutoStartEnabled();
61066111
}
61076112

61086113
return false;
@@ -6138,6 +6143,20 @@ bool CClientGame::IsWeaponRenderEnabled() const
61386143
return g_pGame->IsWeaponRenderEnabled();
61396144
}
61406145

6146+
void CClientGame::SetVehicleEngineAutoStartEnabled(bool enabled)
6147+
{
6148+
if (enabled == g_pMultiplayer->IsVehicleEngineAutoStartEnabled())
6149+
return;
6150+
6151+
g_pMultiplayer->SetVehicleEngineAutoStartEnabled(enabled);
6152+
m_pVehicleManager->ResetNotControlledRotors(enabled);
6153+
}
6154+
6155+
bool CClientGame::IsVehicleEngineAutoStartEnabled() const
6156+
{
6157+
return g_pMultiplayer->IsVehicleEngineAutoStartEnabled();
6158+
}
6159+
61416160
#pragma code_seg(".text")
61426161
bool CClientGame::VerifySADataFiles(int iEnableClientChecks)
61436162
{
@@ -6823,6 +6842,7 @@ void CClientGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo
68236842
g_pGame->SetIgnoreFireStateEnabled(false);
68246843
m_pVehicleManager->SetSpawnFlyingComponentEnabled(true);
68256844
g_pGame->SetVehicleBurnExplosionsEnabled(true);
6845+
SetVehicleEngineAutoStartEnabled(true);
68266846
}
68276847

68286848
// Reset all setWorldProperty to default

Client/mods/deathmatch/logic/CClientGame.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,9 @@ class CClientGame
426426
void SetWeaponRenderEnabled(bool enabled);
427427
bool IsWeaponRenderEnabled() const;
428428

429+
void SetVehicleEngineAutoStartEnabled(bool enabled);
430+
bool IsVehicleEngineAutoStartEnabled() const;
431+
429432
void ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo);
430433

431434
CTransferBox* GetTransferBox() { return m_pTransferBox; };

Client/mods/deathmatch/logic/CClientVehicleManager.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,3 +791,20 @@ void CClientVehicleManager::RestreamVehicleUpgrades(unsigned short usModel)
791791
pVehicle->GetUpgrades()->RestreamVehicleUpgrades(usModel);
792792
}
793793
}
794+
795+
void CClientVehicleManager::ResetNotControlledRotors(bool engineAutoStart)
796+
{
797+
// Reset rotors to original or custom state for loaded vehicles without controller
798+
// Custom state allows rotors to spin without driver inside (if engine is on)
799+
eEntityStatus status = engineAutoStart ? eEntityStatus::STATUS_ABANDONED : eEntityStatus::STATUS_PHYSICS;
800+
for (auto& pVehicle : m_List)
801+
{
802+
if (pVehicle->GetGameEntity() && pVehicle->GetVehicleRotorState() && !pVehicle->IsDriven())
803+
{
804+
float speed = (!engineAutoStart && pVehicle->IsEngineOn()) ? 0.001f : 0.0f;
805+
pVehicle->GetGameEntity()->SetEntityStatus(status);
806+
pVehicle->SetHeliRotorSpeed(speed);
807+
pVehicle->SetPlaneRotorSpeed(speed);
808+
}
809+
}
810+
}

Client/mods/deathmatch/logic/CClientVehicleManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class CClientVehicleManager
7373
bool IsSpawnFlyingComponentEnabled() const noexcept { return m_spawnFlyingComponentsDuringRecreate; }
7474
void SetSpawnFlyingComponentEnabled(bool isEnabled) noexcept { m_spawnFlyingComponentsDuringRecreate = isEnabled; }
7575

76+
void ResetNotControlledRotors(bool engineAutoStart);
77+
7678
protected:
7779
CClientManager* m_pManager;
7880
bool m_bCanRemoveFromList;

Client/mods/deathmatch/logic/CPacketHandler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream)
24022402
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::IGNOREFIRESTATE, wsProps.data6.ignoreFireState);
24032403
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::FLYINGCOMPONENTS, wsProps.data7.flyingcomponents);
24042404
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, wsProps.data8.vehicleburnexplosions);
2405+
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, wsProps.data9.vehicleEngineAutoStart);
24052406

24062407
float fJetpackMaxHeight = 100;
24072408
if (!bitStream.Read(fJetpackMaxHeight))

Client/multiplayer_sa/CMultiplayerSA.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6634,6 +6634,25 @@ void CMultiplayerSA::SetAutomaticVehicleStartupOnPedEnter(bool bSet)
66346634
MemSet((char*)0x64BC0D, 0x90, 6);
66356635
}
66366636

6637+
bool CMultiplayerSA::IsVehicleEngineAutoStartEnabled() const noexcept
6638+
{
6639+
return *(unsigned char*)0x64BC03 == 0x75;
6640+
}
6641+
6642+
void CMultiplayerSA::SetVehicleEngineAutoStartEnabled(bool enabled)
6643+
{
6644+
if (enabled)
6645+
{
6646+
MemCpy((void*)0x64BC03, "\x75\x05\x80\xC9\x10", 5);
6647+
MemCpy((void*)0x6C4EA9, "\x8A\x86\x28\x04", 4);
6648+
}
6649+
else
6650+
{
6651+
MemSet((void*)0x64BC03, 0x90, 5); // prevent vehicle engine from turning on (driver enter)
6652+
MemCpy((void*)0x6C4EA9, "\xE9\x15\x03\x00", 4); // prevent aircraft engine from turning off (driver exit)
6653+
}
6654+
}
6655+
66376656
// Storage
66386657
CVehicleSAInterface* pHeliKiller = NULL;
66396658
CEntitySAInterface* pHitByHeli = NULL;

Client/multiplayer_sa/CMultiplayerSA.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ class CMultiplayerSA : public CMultiplayer
333333

334334
void SetAutomaticVehicleStartupOnPedEnter(bool bSet);
335335

336+
bool IsVehicleEngineAutoStartEnabled() const noexcept override;
337+
void SetVehicleEngineAutoStartEnabled(bool enabled) override;
338+
336339
void SetPedTargetingMarkerEnabled(bool bEnable);
337340
bool IsPedTargetingMarkerEnabled();
338341
bool IsConnected();

Client/sdk/multiplayer/CMultiplayer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ class CMultiplayer
444444

445445
virtual void SetAutomaticVehicleStartupOnPedEnter(bool bSet) = 0;
446446

447+
virtual bool IsVehicleEngineAutoStartEnabled() const noexcept = 0;
448+
virtual void SetVehicleEngineAutoStartEnabled(bool enabled) = 0;
449+
447450
virtual void SetPedTargetingMarkerEnabled(bool bEnabled) = 0;
448451
virtual bool IsPedTargetingMarkerEnabled() = 0;
449452

Server/mods/deathmatch/logic/CGame.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti
263263
m_WorldSpecialProps[WorldSpecialProperty::IGNOREFIRESTATE] = false;
264264
m_WorldSpecialProps[WorldSpecialProperty::FLYINGCOMPONENTS] = true;
265265
m_WorldSpecialProps[WorldSpecialProperty::VEHICLEBURNEXPLOSIONS] = true;
266+
m_WorldSpecialProps[WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART] = true;
266267

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

34073408
// Update our engine State
3408-
pVehicle->SetEngineOn(true);
3409+
if (g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART))
3410+
pVehicle->SetEngineOn(true);
34093411

34103412
// Tell everyone he's in (they should warp him in)
34113413
CVehicleInOutPacket Reply(PedID, VehicleID, ucOccupiedSeat, VEHICLE_NOTIFY_IN_RETURN);
@@ -4524,6 +4526,7 @@ void CGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo)
45244526
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE, false);
45254527
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS, true);
45264528
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, true);
4529+
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, true);
45274530
}
45284531

45294532
// Reset all weather stuff like heat haze, wind velocity etc

Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4262,7 +4262,7 @@ bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehic
42624262
pPed->SetVehicleAction(CPed::VEHICLEACTION_NONE);
42634263

42644264
// If he's the driver, switch on the engine
4265-
if (uiSeat == 0)
4265+
if (uiSeat == 0 && g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART))
42664266
pVehicle->SetEngineOn(true);
42674267

42684268
// Tell all the players

Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const
195195
wsProps.data6.ignoreFireState = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE);
196196
wsProps.data7.flyingcomponents = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS);
197197
wsProps.data8.vehicleburnexplosions = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS);
198+
wsProps.data9.vehicleEngineAutoStart = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART);
198199
BitStream.Write(&wsProps);
199200
}
200201

Shared/mods/deathmatch/logic/Enums.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ ADD_ENUM(WorldSpecialProperty::TUNNELWEATHERBLEND, "tunnelweatherblend")
119119
ADD_ENUM(WorldSpecialProperty::IGNOREFIRESTATE, "ignorefirestate")
120120
ADD_ENUM(WorldSpecialProperty::FLYINGCOMPONENTS, "flyingcomponents")
121121
ADD_ENUM(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, "vehicleburnexplosions")
122+
ADD_ENUM(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART, "vehicle_engine_autostart")
122123
IMPLEMENT_ENUM_CLASS_END("world-special-property")
123124

124125
IMPLEMENT_ENUM_BEGIN(ePacketID)

Shared/mods/deathmatch/logic/Enums.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ enum class WorldSpecialProperty
9696
IGNOREFIRESTATE,
9797
FLYINGCOMPONENTS,
9898
VEHICLEBURNEXPLOSIONS,
99+
VEHICLE_ENGINE_AUTOSTART,
99100
};
100101
DECLARE_ENUM_CLASS(WorldSpecialProperty);
101102

Shared/sdk/net/SyncStructures.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,10 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
20832083
{
20842084
BITCOUNT8 = 1
20852085
};
2086+
enum
2087+
{
2088+
BITCOUNT9 = 1
2089+
};
20862090

20872091
bool Read(NetBitStreamInterface& bitStream)
20882092
{
@@ -2121,6 +2125,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
21212125
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data8), BITCOUNT8);
21222126
else
21232127
data8.vehicleburnexplosions = true;
2128+
2129+
if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineAutoStart))
2130+
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data9), BITCOUNT9);
2131+
else
2132+
data9.vehicleEngineAutoStart = true;
21242133

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

2166+
if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineAutoStart))
2167+
bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);
2168+
21572169
//// Example for adding item:
21582170
// if (bitStream.Can(eBitStreamVersion::YourProperty))
21592171
// bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);
@@ -2210,6 +2222,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
22102222
{
22112223
bool vehicleburnexplosions : 1;
22122224
} data8;
2225+
2226+
struct
2227+
{
2228+
bool vehicleEngineAutoStart : 1;
2229+
} data9;
22132230

22142231
SWorldSpecialPropertiesStateSync()
22152232
{
@@ -2233,6 +2250,7 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
22332250
data6.ignoreFireState = false;
22342251
data7.flyingcomponents = true;
22352252
data8.vehicleburnexplosions = true;
2253+
data9.vehicleEngineAutoStart = true;
22362254
}
22372255
};
22382256

Shared/sdk/net/bitstream.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,10 @@ enum class eBitStreamVersion : unsigned short
620620
// 2025-05-26
621621
ServersideBuildingElement,
622622

623+
// Add "vehenginemanualmode" to setWorldSpecialPropertyEnabled
624+
// 2025-06-02
625+
WorldSpecialProperty_VehicleEngineAutoStart,
626+
623627
// This allows us to automatically increment the BitStreamVersion when things are added to this enum.
624628
// Make sure you only add things above this comment.
625629
Next,

0 commit comments

Comments
 (0)