Skip to content

Server side weapon reloading #3936

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 7 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3085,6 +3085,7 @@ void CClientGame::UpdateMimics()
bool bSunbathing = m_pLocalPlayer->IsSunbathing();
bool bDoingDriveby = m_pLocalPlayer->IsDoingGangDriveby();
bool bStealthAiming = m_pLocalPlayer->IsStealthAiming();
bool reloadingWeapon = m_pLocalPlayer->IsReloadingWeapon();

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

if (reloadingWeapon)
pMimic->ReloadWeapon();

Controller.ShockButtonL = 0;

if (m_bMimicLag)
Expand Down
63 changes: 27 additions & 36 deletions Client/mods/deathmatch/logic/CClientPed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6008,51 +6008,42 @@ void CClientPed::SetSpeechEnabled(bool bEnabled)
m_bSpeechEnabled = bEnabled;
}

bool CClientPed::CanReloadWeapon()
bool CClientPed::CanReloadWeapon() noexcept
{
unsigned long ulNow = CClientTime::GetTime();
CControllerState Current;
GetControllerState(Current);
int iWeaponType = GetWeapon()->GetType();
// 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
// anim runs over and kills the reload animation)
if (Current.RightShoulder1 == false && (!IsDucked() || (Current.LeftStickX == 0 && Current.LeftStickY == 0)) &&
ulNow - m_ulLastTimeMovedWhileCrouched > 300)
{
// Ignore certain weapons (anything without clip ammo)
if (iWeaponType >= WEAPONTYPE_PISTOL && iWeaponType <= WEAPONTYPE_TEC9 && iWeaponType != WEAPONTYPE_SHOTGUN)
{
return true;
}
}
return false;
const auto time = CClientTime::GetTime();
CControllerState state;
GetControllerState(state);

const auto weapon = GetWeapon()->GetType();

if (state.RightShoulder1 || (IsDucked() && (state.LeftStickX != 0 || state.LeftStickY != 0)) || time - m_ulLastTimeMovedWhileCrouched <= 300)
return false;

if (weapon < WEAPONTYPE_PISTOL || weapon > WEAPONTYPE_TEC9 || weapon == WEAPONTYPE_SHOTGUN)
return false;

return true;
}

bool CClientPed::ReloadWeapon()
bool CClientPed::ReloadWeapon() noexcept
{
if (m_pTaskManager)
{
CWeapon* pWeapon = GetWeapon();
CTask* pTask = m_pTaskManager->GetTaskSecondary(TASK_SECONDARY_ATTACK);
if (!m_pTaskManager)
return false;

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

return true;
}
}
return false;
if (!CanReloadWeapon() || (task && task->GetTaskType() == TASK_SIMPLE_USE_GUN))
return false;

weapon->SetState(WEAPONSTATE_RELOADING);
return true;
}

bool CClientPed::IsReloadingWeapon()
bool CClientPed::IsReloadingWeapon() noexcept
{
if (CWeapon* weapon = GetWeapon(); weapon != nullptr)
return weapon->GetState() == WEAPONSTATE_RELOADING;
else
return false;
auto* weapon = GetWeapon();
return weapon && weapon->GetState() == WEAPONSTATE_RELOADING;
}

bool CClientPed::ShouldBeStealthAiming()
Expand Down
7 changes: 4 additions & 3 deletions Client/mods/deathmatch/logic/CClientPed.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ struct SLastSyncedPedData
float fRotation;
bool bOnFire;
bool bIsInWater;
bool isReloadingWeapon;
};

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

bool CanReloadWeapon();
bool ReloadWeapon();
bool IsReloadingWeapon();
bool CanReloadWeapon() noexcept;
bool ReloadWeapon() noexcept;
bool IsReloadingWeapon() noexcept;

bool ShouldBeStealthAiming();
bool IsStealthAiming() { return m_bStealthAiming; }
Expand Down
3 changes: 3 additions & 0 deletions Client/mods/deathmatch/logic/CNetAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,9 @@ void CNetAPI::WritePlayerPuresync(CClientPlayer* pPlayerModel, NetBitStreamInter
flags.data.bSyncingVelocity = (!flags.data.bIsOnGround || (pPlayerModel->GetPlayerSyncCount() % 4) == 0);
flags.data.bStealthAiming = (pPlayerModel->IsStealthAiming() == true);

if (BitStream.Can(eBitStreamVersion::IsPedReloadingWeapon))
flags.data2.isReloadingWeapon = (pPlayerModel->IsReloadingWeapon() == true);

if (pPlayerWeapon->GetSlot() > 15)
flags.data.bHasAWeapon = false;

Expand Down
11 changes: 11 additions & 0 deletions Client/mods/deathmatch/logic/CPedSync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
ucFlags |= 0x20;
if (pPed->IsInWater() != pPed->m_LastSyncedData->bIsInWater)
ucFlags |= 0x40;
if (pPed->IsReloadingWeapon() != pPed->m_LastSyncedData->isReloadingWeapon && pBitStream->Can(eBitStreamVersion::IsPedReloadingWeapon))
ucFlags |= 0x60;
if (pPed->HasSyncedAnim() && (!pPed->IsRunningAnimation() || pPed->m_animationOverridedByClient))
ucFlags |= 0x80;

Expand Down Expand Up @@ -380,6 +382,7 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
pBitStream->Write(pPed->GetHealth());
pPed->m_LastSyncedData->fHealth = pPed->GetHealth();
}

if (ucFlags & 0x10)
{
pBitStream->Write(pPed->GetArmor());
Expand All @@ -398,6 +401,14 @@ void CPedSync::WritePedInformation(NetBitStreamInterface* pBitStream, CClientPed
pPed->m_LastSyncedData->bIsInWater = pPed->IsInWater();
}

if (ucFlags & 0x60 && pBitStream->Can(eBitStreamVersion::IsPedReloadingWeapon))
{
bool isReloadingWeapon = pPed->IsReloadingWeapon();

pBitStream->WriteBit(isReloadingWeapon);
pPed->m_LastSyncedData->isReloadingWeapon = isReloadingWeapon;
}

// The animation has been overwritten or interrupted by the client
if (ucFlags & 0x80 && pBitStream->Can(eBitStreamVersion::AnimationsSync))
{
Expand Down
22 changes: 4 additions & 18 deletions Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void CLuaPedDefs::LoadFunctions()
{"isPedChoking", IsPedChoking},
{"isPedDucked", IsPedDucked},
{"isPedDead", IsPedDead},
{"isPedReloadingWeapon", IsPedReloadingWeapon},
{"isPedReloadingWeapon", ArgumentParserWarn<false, IsPedReloadingWeapon>},
{"killPedTask", ArgumentParser<killPedTask>},
};

Expand Down Expand Up @@ -1233,25 +1233,11 @@ int CLuaPedDefs::GivePedWeapon(lua_State* luaVM)
return 1;
}

int CLuaPedDefs::IsPedReloadingWeapon(lua_State* luaVM)
bool CLuaPedDefs::IsPedReloadingWeapon(CClientPed* const ped) noexcept
{
// Verify the argument
CClientPed* pPed = NULL;
CScriptArgReader argStream(luaVM);
argStream.ReadUserData(pPed);

if (!argStream.HasErrors())
{
lua_pushboolean(luaVM, pPed->IsReloadingWeapon());
return 1;
}
else
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());

lua_pushboolean(luaVM, false);
return 1;
return ped->IsReloadingWeapon();
}

int CLuaPedDefs::GetPedClothes(lua_State* luaVM)
{
// Verify the argument
Expand Down
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/luadefs/CLuaPedDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class CLuaPedDefs : public CLuaDefs
static bool SetPedArmor(CClientPed* const ped, const float armor);
LUA_DECLARE(SetPedWeaponSlot);
LUA_DECLARE(GivePedWeapon);
LUA_DECLARE(IsPedReloadingWeapon);
static bool IsPedReloadingWeapon(CClientPed* const ped) noexcept;
LUA_DECLARE(AddPedClothes);
LUA_DECLARE(RemovePedClothes);
LUA_DECLARE(SetPedControlState);
Expand Down
4 changes: 3 additions & 1 deletion Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,8 @@ void CGame::AddBuiltInEvents()
m_Events.AddEvent("onPlayerTarget", "target", NULL, false);
m_Events.AddEvent("onPlayerWasted", "ammo, killer, weapon, bodypart, isStealth, animGroup, animID", nullptr, false);
m_Events.AddEvent("onPlayerWeaponSwitch", "previous, current", NULL, false);
m_Events.AddEvent("onPlayerWeaponFire", "weapon, endX, endY, endZ, hitElement, startX, startY, startZ", nullptr, false);
m_Events.AddEvent("onPlayerWeaponReload", "weapon, clip, ammo", nullptr, false);
m_Events.AddEvent("onPlayerMarkerHit", "marker, matchingDimension", NULL, false);
m_Events.AddEvent("onPlayerMarkerLeave", "marker, matchingDimension", NULL, false);
m_Events.AddEvent("onPlayerPickupHit", "pickup", NULL, false);
Expand Down Expand Up @@ -1644,6 +1646,7 @@ void CGame::AddBuiltInEvents()
m_Events.AddEvent("onPedVehicleExit", "vehicle, reason, jacker", NULL, false);
m_Events.AddEvent("onPedWasted", "ammo, killer, weapon, bodypart, isStealth, animGroup, animID", nullptr, false);
m_Events.AddEvent("onPedWeaponSwitch", "previous, current", NULL, false);
m_Events.AddEvent("onPedWeaponReload", "weapon, clip, ammo", nullptr, false);
m_Events.AddEvent("onPedDamage", "loss", NULL, false);

// Element events
Expand Down Expand Up @@ -1699,7 +1702,6 @@ void CGame::AddBuiltInEvents()

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

void CGame::ProcessTrafficLights(long long llCurrentTime)
Expand Down
4 changes: 4 additions & 0 deletions Server/mods/deathmatch/logic/CPed.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ class CPed : public CElement
bool IsStealthAiming() { return m_bStealthAiming; }
void SetStealthAiming(bool bAiming) { m_bStealthAiming = bAiming; }

bool IsReloadingWeapon() const noexcept { return m_reloadingWeapon; }
void SetReloadingWeapon(bool state) noexcept { m_reloadingWeapon = state; }

bool GetCollisionEnabled() { return m_bCollisionsEnabled; }
void SetCollisionEnabled(bool bCollisionEnabled) { m_bCollisionsEnabled = bCollisionEnabled; }

Expand Down Expand Up @@ -340,6 +343,7 @@ class CPed : public CElement
bool m_bHeadless;
bool m_bFrozen;
bool m_bStealthAiming;
bool m_reloadingWeapon{};
CVehicle* m_pJackingVehicle;
SPlayerAnimData m_animData{};

Expand Down
5 changes: 5 additions & 0 deletions Server/mods/deathmatch/logic/CPedSync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ void CPedSync::Packet_PedSync(CPedSyncPacket& Packet)
if (Data.ucFlags & 0x40)
pPed->SetInWater(Data.bIsInWater);

if (Data.ucFlags & 0x60)
{
pPed->SetReloadingWeapon(Data.isReloadingWeapon);
}

if (Data.ucFlags & 0x80)
pPed->SetAnimationData({});

Expand Down
44 changes: 33 additions & 11 deletions Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4508,19 +4508,41 @@ bool CStaticFunctionDefinitions::SetPedFrozen(CElement* pElement, bool bIsFrozen
}
return false;
}
bool CStaticFunctionDefinitions::reloadPedWeapon(CElement* pElement)
{

bool CStaticFunctionDefinitions::ReloadPedWeapon(CElement* pElement) noexcept {
assert(pElement);
RUN_CHILDREN(reloadPedWeapon(*iter))
RUN_CHILDREN(ReloadPedWeapon(*iter))

if (IS_PED(pElement))
{
CPed* pPed = static_cast<CPed*>(pElement);
CBitStream BitStream;
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, RELOAD_PED_WEAPON, *BitStream.pBitStream));
return true;
}
return false;
if (!IS_PED(pElement))
return false;

CPed* ped = static_cast<CPed*>(pElement);

bool result;
CLuaArguments arguments;

std::uint8_t weapon = ped->GetWeaponType();
std::uint16_t clip = ped->GetWeaponAmmoInClip();
std::uint16_t ammo = ped->GetWeaponTotalAmmo();

arguments.PushNumber(weapon);
arguments.PushNumber(clip);
arguments.PushNumber(ammo);

if (IS_PLAYER(pElement))
result = ped->CallEvent("onPlayerWeaponReload", arguments);
else
result = ped->CallEvent("onPedWeaponReload", arguments);

if (!result)
return false;

CBitStream stream;

ped->SetReloadingWeapon(true);
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(ped, RELOAD_PED_WEAPON, *stream.pBitStream));

return true;
}

bool CStaticFunctionDefinitions::GetCameraMatrix(CPlayer* pPlayer, CVector& vecPosition, CVector& vecLookAt, float& fRoll, float& fFOV)
Expand Down
2 changes: 1 addition & 1 deletion Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class CStaticFunctionDefinitions
static bool SetPedOnFire(CElement* pElement, bool bIsOnFire);
static bool SetPedHeadless(CElement* pElement, bool bIsHeadless);
static bool SetPedFrozen(CElement* pElement, bool bIsFrozen);
static bool reloadPedWeapon(CElement* pElement);
static bool ReloadPedWeapon(CElement* pElement) noexcept;
static bool SetWeaponProperty(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, float fData);
static bool SetWeaponProperty(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, int sData);
static bool SetWeaponPropertyFlag(eWeaponProperty eProperty, eWeaponType eWeapon, eWeaponSkill eSkillLevel, bool bEnable);
Expand Down
32 changes: 11 additions & 21 deletions Server/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void CLuaPedDefs::LoadFunctions()
{"getPedOccupiedVehicle", GetPedOccupiedVehicle},
{"getPedOccupiedVehicleSeat", GetPedOccupiedVehicleSeat},
{"isPedInVehicle", IsPedInVehicle},
{"isPedReloadingWeapon", ArgumentParser<IsPedReloadingWeapon>},

// Ped set functions
{"setPedArmor", SetPedArmor},
Expand All @@ -71,7 +72,7 @@ void CLuaPedDefs::LoadFunctions()
{"setPedOnFire", SetPedOnFire},
{"setPedHeadless", SetPedHeadless},
{"setPedFrozen", SetPedFrozen},
{"reloadPedWeapon", reloadPedWeapon},
{"reloadPedWeapon", ArgumentParserWarn<false, ReloadPedWeapon>},

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

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

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

int CLuaPedDefs::reloadPedWeapon(lua_State* luaVM)
bool CLuaPedDefs::ReloadPedWeapon(lua_State* vm, CPed* const ped) noexcept
{
CElement* pPed;

CScriptArgReader argStream(luaVM);
argStream.ReadUserData(pPed);

if (!argStream.HasErrors())
{
LogWarningIfPlayerHasNotJoinedYet(luaVM, pPed);

if (CStaticFunctionDefinitions::reloadPedWeapon(pPed))
{
lua_pushboolean(luaVM, true);
return 1;
}
}
else
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
LogWarningIfPlayerHasNotJoinedYet(vm, ped);
return CStaticFunctionDefinitions::ReloadPedWeapon(ped);
}

lua_pushboolean(luaVM, false);
return 1;
bool CLuaPedDefs::IsPedReloadingWeapon(CPed* const ped) noexcept
{
return ped->IsReloadingWeapon();
}

int CLuaPedDefs::IsPedDoingGangDriveby(lua_State* luaVM)
Expand Down
Loading
Loading