Skip to content

Commit e71f482

Browse files
authored
Add server side weapon reloading (PR #3936, Fixes #1525)
1 parent 859b0da commit e71f482

19 files changed

+161
-95
lines changed

Client/mods/deathmatch/logic/CClientGame.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,7 @@ void CClientGame::UpdateMimics()
30853085
bool bSunbathing = m_pLocalPlayer->IsSunbathing();
30863086
bool bDoingDriveby = m_pLocalPlayer->IsDoingGangDriveby();
30873087
bool bStealthAiming = m_pLocalPlayer->IsStealthAiming();
3088+
bool reloadingWeapon = m_pLocalPlayer->IsReloadingWeapon();
30883089

30893090
// Is the current weapon goggles (44 or 45) or a camera (43), or a detonator (40), don't apply the fire key
30903091
if (weaponSlot == 11 || weaponSlot == 12 || ucWeaponType == 43)
@@ -3143,6 +3144,9 @@ void CClientGame::UpdateMimics()
31433144
pMimic->SetDoingGangDriveby(bDoingDriveby);
31443145
pMimic->SetStealthAiming(bStealthAiming);
31453146

3147+
if (reloadingWeapon)
3148+
pMimic->ReloadWeapon();
3149+
31463150
Controller.ShockButtonL = 0;
31473151

31483152
if (m_bMimicLag)

Client/mods/deathmatch/logic/CClientPed.cpp

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6008,51 +6008,42 @@ void CClientPed::SetSpeechEnabled(bool bEnabled)
60086008
m_bSpeechEnabled = bEnabled;
60096009
}
60106010

6011-
bool CClientPed::CanReloadWeapon()
6011+
bool CClientPed::CanReloadWeapon() noexcept
60126012
{
6013-
unsigned long ulNow = CClientTime::GetTime();
6014-
CControllerState Current;
6015-
GetControllerState(Current);
6016-
int iWeaponType = GetWeapon()->GetType();
6017-
// Hes not Aiming, ducked or if he is ducked he is not currently moving and he hasn't moved while crouching in the last 300ms (sometimes the crouching move
6018-
// anim runs over and kills the reload animation)
6019-
if (Current.RightShoulder1 == false && (!IsDucked() || (Current.LeftStickX == 0 && Current.LeftStickY == 0)) &&
6020-
ulNow - m_ulLastTimeMovedWhileCrouched > 300)
6021-
{
6022-
// Ignore certain weapons (anything without clip ammo)
6023-
if (iWeaponType >= WEAPONTYPE_PISTOL && iWeaponType <= WEAPONTYPE_TEC9 && iWeaponType != WEAPONTYPE_SHOTGUN)
6024-
{
6025-
return true;
6026-
}
6027-
}
6028-
return false;
6013+
const auto time = CClientTime::GetTime();
6014+
CControllerState state;
6015+
GetControllerState(state);
6016+
6017+
const auto weapon = GetWeapon()->GetType();
6018+
6019+
if (state.RightShoulder1 || (IsDucked() && (state.LeftStickX != 0 || state.LeftStickY != 0)) || time - m_ulLastTimeMovedWhileCrouched <= 300)
6020+
return false;
6021+
6022+
if (weapon < WEAPONTYPE_PISTOL || weapon > WEAPONTYPE_TEC9 || weapon == WEAPONTYPE_SHOTGUN)
6023+
return false;
6024+
6025+
return true;
60296026
}
60306027

6031-
bool CClientPed::ReloadWeapon()
6028+
bool CClientPed::ReloadWeapon() noexcept
60326029
{
6033-
if (m_pTaskManager)
6034-
{
6035-
CWeapon* pWeapon = GetWeapon();
6036-
CTask* pTask = m_pTaskManager->GetTaskSecondary(TASK_SECONDARY_ATTACK);
6030+
if (!m_pTaskManager)
6031+
return false;
60376032

6038-
// Check his control states for anything that can cancel the anim instantly and make sure he is not firing
6039-
if (CanReloadWeapon() && (!pTask || (pTask && pTask->GetTaskType() != TASK_SIMPLE_USE_GUN)))
6040-
{
6041-
// Play anim + reload
6042-
pWeapon->SetState(WEAPONSTATE_RELOADING);
6033+
auto* weapon = GetWeapon();
6034+
auto* task = m_pTaskManager->GetTaskSecondary(TASK_SECONDARY_ATTACK);
60436035

6044-
return true;
6045-
}
6046-
}
6047-
return false;
6036+
if (!CanReloadWeapon() || (task && task->GetTaskType() == TASK_SIMPLE_USE_GUN))
6037+
return false;
6038+
6039+
weapon->SetState(WEAPONSTATE_RELOADING);
6040+
return true;
60486041
}
60496042

6050-
bool CClientPed::IsReloadingWeapon()
6043+
bool CClientPed::IsReloadingWeapon() noexcept
60516044
{
6052-
if (CWeapon* weapon = GetWeapon(); weapon != nullptr)
6053-
return weapon->GetState() == WEAPONSTATE_RELOADING;
6054-
else
6055-
return false;
6045+
auto* weapon = GetWeapon();
6046+
return weapon && weapon->GetState() == WEAPONSTATE_RELOADING;
60566047
}
60576048

60586049
bool CClientPed::ShouldBeStealthAiming()

Client/mods/deathmatch/logic/CClientPed.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct SLastSyncedPedData
107107
float fRotation;
108108
bool bOnFire;
109109
bool bIsInWater;
110+
bool isReloadingWeapon;
110111
};
111112

112113
struct SRestoreWeaponItem
@@ -495,9 +496,9 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule
495496
bool GetBulletImpactData(CClientEntity** ppVictim = 0, CVector* pvecHitPosition = 0);
496497
void ClearBulletImpactData() { m_bBulletImpactData = false; }
497498

498-
bool CanReloadWeapon();
499-
bool ReloadWeapon();
500-
bool IsReloadingWeapon();
499+
bool CanReloadWeapon() noexcept;
500+
bool ReloadWeapon() noexcept;
501+
bool IsReloadingWeapon() noexcept;
501502

502503
bool ShouldBeStealthAiming();
503504
bool IsStealthAiming() { return m_bStealthAiming; }

Client/mods/deathmatch/logic/CNetAPI.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,9 @@ void CNetAPI::WritePlayerPuresync(CClientPlayer* pPlayerModel, NetBitStreamInter
11181118
flags.data.bSyncingVelocity = (!flags.data.bIsOnGround || (pPlayerModel->GetPlayerSyncCount() % 4) == 0);
11191119
flags.data.bStealthAiming = (pPlayerModel->IsStealthAiming() == true);
11201120

1121+
if (BitStream.Can(eBitStreamVersion::IsPedReloadingWeapon))
1122+
flags.data2.isReloadingWeapon = (pPlayerModel->IsReloadingWeapon() == true);
1123+
11211124
if (pPlayerWeapon->GetSlot() > 15)
11221125
flags.data.bHasAWeapon = false;
11231126

Client/mods/deathmatch/logic/CPedSync.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
307307
ucFlags |= 0x20;
308308
if (pPed->IsInWater() != pPed->m_LastSyncedData->bIsInWater)
309309
ucFlags |= 0x40;
310+
if (pPed->IsReloadingWeapon() != pPed->m_LastSyncedData->isReloadingWeapon && pBitStream->Can(eBitStreamVersion::IsPedReloadingWeapon))
311+
ucFlags |= 0x60;
310312
if (pPed->HasSyncedAnim() && (!pPed->IsRunningAnimation() || pPed->m_animationOverridedByClient))
311313
ucFlags |= 0x80;
312314

@@ -380,6 +382,7 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
380382
pBitStream->Write(pPed->GetHealth());
381383
pPed->m_LastSyncedData->fHealth = pPed->GetHealth();
382384
}
385+
383386
if (ucFlags & 0x10)
384387
{
385388
pBitStream->Write(pPed->GetArmor());
@@ -398,6 +401,14 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
398401
pPed->m_LastSyncedData->bIsInWater = pPed->IsInWater();
399402
}
400403

404+
if (ucFlags & 0x60 && pBitStream->Can(eBitStreamVersion::IsPedReloadingWeapon))
405+
{
406+
bool isReloadingWeapon = pPed->IsReloadingWeapon();
407+
408+
pBitStream->WriteBit(isReloadingWeapon);
409+
pPed->m_LastSyncedData->isReloadingWeapon = isReloadingWeapon;
410+
}
411+
401412
// The animation has been overwritten or interrupted by the client
402413
if (ucFlags & 0x80 && pBitStream->Can(eBitStreamVersion::AnimationsSync))
403414
{

Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void CLuaPedDefs::LoadFunctions()
114114
{"isPedChoking", IsPedChoking},
115115
{"isPedDucked", IsPedDucked},
116116
{"isPedDead", IsPedDead},
117-
{"isPedReloadingWeapon", IsPedReloadingWeapon},
117+
{"isPedReloadingWeapon", ArgumentParserWarn<false, IsPedReloadingWeapon>},
118118
{"killPedTask", ArgumentParser<killPedTask>},
119119
};
120120

@@ -1233,25 +1233,11 @@ int CLuaPedDefs::GivePedWeapon(lua_State* luaVM)
12331233
return 1;
12341234
}
12351235

1236-
int CLuaPedDefs::IsPedReloadingWeapon(lua_State* luaVM)
1236+
bool CLuaPedDefs::IsPedReloadingWeapon(CClientPed* const ped) noexcept
12371237
{
1238-
// Verify the argument
1239-
CClientPed* pPed = NULL;
1240-
CScriptArgReader argStream(luaVM);
1241-
argStream.ReadUserData(pPed);
1242-
1243-
if (!argStream.HasErrors())
1244-
{
1245-
lua_pushboolean(luaVM, pPed->IsReloadingWeapon());
1246-
return 1;
1247-
}
1248-
else
1249-
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
1250-
1251-
lua_pushboolean(luaVM, false);
1252-
return 1;
1238+
return ped->IsReloadingWeapon();
12531239
}
1254-
1240+
12551241
int CLuaPedDefs::GetPedClothes(lua_State* luaVM)
12561242
{
12571243
// Verify the argument

Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class CLuaPedDefs : public CLuaDefs
9393
static bool SetPedArmor(CClientPed* const ped, const float armor);
9494
LUA_DECLARE(SetPedWeaponSlot);
9595
LUA_DECLARE(GivePedWeapon);
96-
LUA_DECLARE(IsPedReloadingWeapon);
96+
static bool IsPedReloadingWeapon(CClientPed* const ped) noexcept;
9797
LUA_DECLARE(AddPedClothes);
9898
LUA_DECLARE(RemovePedClothes);
9999
LUA_DECLARE(SetPedControlState);

Server/mods/deathmatch/logic/CGame.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1610,6 +1610,8 @@ void CGame::AddBuiltInEvents()
16101610
m_Events.AddEvent("onPlayerTarget", "target", NULL, false);
16111611
m_Events.AddEvent("onPlayerWasted", "ammo, killer, weapon, bodypart, isStealth, animGroup, animID", nullptr, false);
16121612
m_Events.AddEvent("onPlayerWeaponSwitch", "previous, current", NULL, false);
1613+
m_Events.AddEvent("onPlayerWeaponFire", "weapon, endX, endY, endZ, hitElement, startX, startY, startZ", nullptr, false);
1614+
m_Events.AddEvent("onPlayerWeaponReload", "weapon, clip, ammo", nullptr, false);
16131615
m_Events.AddEvent("onPlayerMarkerHit", "marker, matchingDimension", NULL, false);
16141616
m_Events.AddEvent("onPlayerMarkerLeave", "marker, matchingDimension", NULL, false);
16151617
m_Events.AddEvent("onPlayerPickupHit", "pickup", NULL, false);
@@ -1644,6 +1646,7 @@ void CGame::AddBuiltInEvents()
16441646
m_Events.AddEvent("onPedVehicleExit", "vehicle, reason, jacker", NULL, false);
16451647
m_Events.AddEvent("onPedWasted", "ammo, killer, weapon, bodypart, isStealth, animGroup, animID", nullptr, false);
16461648
m_Events.AddEvent("onPedWeaponSwitch", "previous, current", NULL, false);
1649+
m_Events.AddEvent("onPedWeaponReload", "weapon, clip, ammo", nullptr, false);
16471650
m_Events.AddEvent("onPedDamage", "loss", NULL, false);
16481651

16491652
// Element events
@@ -1699,7 +1702,6 @@ void CGame::AddBuiltInEvents()
16991702

17001703
// Weapon events
17011704
m_Events.AddEvent("onWeaponFire", "", NULL, false);
1702-
m_Events.AddEvent("onPlayerWeaponFire", "weapon, endX, endY, endZ, hitElement, startX, startY, startZ", NULL, false);
17031705
}
17041706

17051707
void CGame::ProcessTrafficLights(long long llCurrentTime)

Server/mods/deathmatch/logic/CPed.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ class CPed : public CElement
286286
bool IsStealthAiming() { return m_bStealthAiming; }
287287
void SetStealthAiming(bool bAiming) { m_bStealthAiming = bAiming; }
288288

289+
bool IsReloadingWeapon() const noexcept { return m_reloadingWeapon; }
290+
void SetReloadingWeapon(bool state) noexcept { m_reloadingWeapon = state; }
291+
289292
bool GetCollisionEnabled() { return m_bCollisionsEnabled; }
290293
void SetCollisionEnabled(bool bCollisionEnabled) { m_bCollisionsEnabled = bCollisionEnabled; }
291294

@@ -340,6 +343,7 @@ class CPed : public CElement
340343
bool m_bHeadless;
341344
bool m_bFrozen;
342345
bool m_bStealthAiming;
346+
bool m_reloadingWeapon{};
343347
CVehicle* m_pJackingVehicle;
344348
SPlayerAnimData m_animData{};
345349

Server/mods/deathmatch/logic/CPedSync.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ void CPedSync::Packet_PedSync(CPedSyncPacket& Packet)
283283
if (Data.ucFlags & 0x40)
284284
pPed->SetInWater(Data.bIsInWater);
285285

286+
if (Data.ucFlags & 0x60)
287+
{
288+
pPed->SetReloadingWeapon(Data.isReloadingWeapon);
289+
}
290+
286291
if (Data.ucFlags & 0x80)
287292
pPed->SetAnimationData({});
288293

Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4508,19 +4508,41 @@ bool CStaticFunctionDefinitions::SetPedFrozen(CElement* pElement, bool bIsFrozen
45084508
}
45094509
return false;
45104510
}
4511-
bool CStaticFunctionDefinitions::reloadPedWeapon(CElement* pElement)
4512-
{
4511+
4512+
bool CStaticFunctionDefinitions::ReloadPedWeapon(CElement* pElement) noexcept {
45134513
assert(pElement);
4514-
RUN_CHILDREN(reloadPedWeapon(*iter))
4514+
RUN_CHILDREN(ReloadPedWeapon(*iter))
45154515

4516-
if (IS_PED(pElement))
4517-
{
4518-
CPed* pPed = static_cast<CPed*>(pElement);
4519-
CBitStream BitStream;
4520-
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, RELOAD_PED_WEAPON, *BitStream.pBitStream));
4521-
return true;
4522-
}
4523-
return false;
4516+
if (!IS_PED(pElement))
4517+
return false;
4518+
4519+
CPed* ped = static_cast<CPed*>(pElement);
4520+
4521+
bool result;
4522+
CLuaArguments arguments;
4523+
4524+
std::uint8_t weapon = ped->GetWeaponType();
4525+
std::uint16_t clip = ped->GetWeaponAmmoInClip();
4526+
std::uint16_t ammo = ped->GetWeaponTotalAmmo();
4527+
4528+
arguments.PushNumber(weapon);
4529+
arguments.PushNumber(clip);
4530+
arguments.PushNumber(ammo);
4531+
4532+
if (IS_PLAYER(pElement))
4533+
result = ped->CallEvent("onPlayerWeaponReload", arguments);
4534+
else
4535+
result = ped->CallEvent("onPedWeaponReload", arguments);
4536+
4537+
if (!result)
4538+
return false;
4539+
4540+
CBitStream stream;
4541+
4542+
ped->SetReloadingWeapon(true);
4543+
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(ped, RELOAD_PED_WEAPON, *stream.pBitStream));
4544+
4545+
return true;
45244546
}
45254547

45264548
bool CStaticFunctionDefinitions::GetCameraMatrix(CPlayer* pPlayer, CVector& vecPosition, CVector& vecLookAt, float& fRoll, float& fFOV)

Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class CStaticFunctionDefinitions
218218
static bool SetPedOnFire(CElement* pElement, bool bIsOnFire);
219219
static bool SetPedHeadless(CElement* pElement, bool bIsHeadless);
220220
static bool SetPedFrozen(CElement* pElement, bool bIsFrozen);
221-
static bool reloadPedWeapon(CElement* pElement);
221+
static bool ReloadPedWeapon(CElement* pElement) noexcept;
222222
static bool SetWeaponProperty(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, float fData);
223223
static bool SetWeaponProperty(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, int sData);
224224
static bool SetWeaponPropertyFlag(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, bool bEnable);

Server/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void CLuaPedDefs::LoadFunctions()
4848
{"getPedOccupiedVehicle", GetPedOccupiedVehicle},
4949
{"getPedOccupiedVehicleSeat", GetPedOccupiedVehicleSeat},
5050
{"isPedInVehicle", IsPedInVehicle},
51+
{"isPedReloadingWeapon", ArgumentParser<IsPedReloadingWeapon>},
5152

5253
// Ped set functions
5354
{"setPedArmor", SetPedArmor},
@@ -71,7 +72,7 @@ void CLuaPedDefs::LoadFunctions()
7172
{"setPedOnFire", SetPedOnFire},
7273
{"setPedHeadless", SetPedHeadless},
7374
{"setPedFrozen", SetPedFrozen},
74-
{"reloadPedWeapon", reloadPedWeapon},
75+
{"reloadPedWeapon", ArgumentParserWarn<false, ReloadPedWeapon>},
7576

7677
// Weapon give/take functions
7778
{"giveWeapon", GiveWeapon},
@@ -118,6 +119,7 @@ void CLuaPedDefs::AddClass(lua_State* luaVM)
118119
lua_classfunction(luaVM, "isFrozen", "isPedFrozen");
119120
lua_classfunction(luaVM, "isHeadless", "isPedHeadless");
120121
lua_classfunction(luaVM, "isWearingJetpack", "isPedWearingJetpack"); // introduced in 1.5.5-9.13846
122+
lua_classfunction(luaVM, "isReloadingWeapon", "isPedReloadingWeapon");
121123

122124
lua_classfunction(luaVM, "getArmor", "getPedArmor");
123125
lua_classfunction(luaVM, "getFightingStyle", "getPedFightingStyle");
@@ -169,6 +171,7 @@ void CLuaPedDefs::AddClass(lua_State* luaVM)
169171
lua_classvariable(luaVM, "vehicle", "warpPedIntoVehicle", "getPedOccupiedVehicle", OOP_WarpPedIntoVehicle, GetPedOccupiedVehicle);
170172
lua_classvariable(luaVM, "walkingStyle", "setPedWalkingStyle", "getPedWalkingStyle");
171173
lua_classvariable(luaVM, "jetpack", "setPedWearingJetpack", "isPedWearingJetpack"); // introduced in 1.5.5-9.13846
174+
lua_classvariable(luaVM, "reloadingWeapon", nullptr, "isPedReloadingWeapon");
172175

173176
// TODO(qaisjp): setting this to any value will kill the ped. add OOP_KillPed that only allows `true`.
174177
lua_classvariable(luaVM, "dead", "killPed", "isPedDead");
@@ -289,28 +292,15 @@ int CLuaPedDefs::GetPedWeaponSlot(lua_State* luaVM)
289292
return 1;
290293
}
291294

292-
int CLuaPedDefs::reloadPedWeapon(lua_State* luaVM)
295+
bool CLuaPedDefs::ReloadPedWeapon(lua_State* vm, CPed* const ped) noexcept
293296
{
294-
CElement* pPed;
295-
296-
CScriptArgReader argStream(luaVM);
297-
argStream.ReadUserData(pPed);
298-
299-
if (!argStream.HasErrors())
300-
{
301-
LogWarningIfPlayerHasNotJoinedYet(luaVM, pPed);
302-
303-
if (CStaticFunctionDefinitions::reloadPedWeapon(pPed))
304-
{
305-
lua_pushboolean(luaVM, true);
306-
return 1;
307-
}
308-
}
309-
else
310-
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
297+
LogWarningIfPlayerHasNotJoinedYet(vm, ped);
298+
return CStaticFunctionDefinitions::ReloadPedWeapon(ped);
299+
}
311300

312-
lua_pushboolean(luaVM, false);
313-
return 1;
301+
bool CLuaPedDefs::IsPedReloadingWeapon(CPed* const ped) noexcept
302+
{
303+
return ped->IsReloadingWeapon();
314304
}
315305

316306
int CLuaPedDefs::IsPedDoingGangDriveby(lua_State* luaVM)

0 commit comments

Comments
 (0)