Skip to content
Open
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
102 changes: 52 additions & 50 deletions Client/mods/deathmatch/logic/CNetAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ bool CNetAPI::ProcessPacket(unsigned char bytePacketID, NetBitStreamInterface& B
if (!BitStream.Read(id))
return true;

auto* player = m_pPlayerManager->Get(id);
CClientPlayer* player = m_pPlayerManager->Get(id);
if (!player)
return true;

Expand Down Expand Up @@ -2236,48 +2236,37 @@ void CNetAPI::ReadBulletsync(CClientPlayer* player, NetBitStreamInterface& strea
if (!stream.Read(weapon) || !CClientWeaponManager::HasWeaponBulletSync(weapon))
return;

const auto type = static_cast<eWeaponType>(weapon);
auto type = static_cast<eWeaponType>(weapon);

SPositionSync startPosition;
SPositionSync endPosition;
if (!stream.Read(&startPosition) || !stream.Read(&endPosition))
return;

CVector start;
CVector end;
if (!stream.Read(reinterpret_cast<char*>(&start), sizeof(CVector)) || !stream.Read(reinterpret_cast<char*>(&end), sizeof(CVector)) || !start.IsValid() ||
!end.IsValid())
if (!startPosition.data.vecPosition.IsValid() || !endPosition.data.vecPosition.IsValid())
return;

std::uint8_t order = 0;
if (!stream.Read(order))
// Huge coordinates can crash other players
if (!startPosition.data.vecPosition.IsInWorldBounds(true) || !endPosition.data.vecPosition.IsInWorldBounds(true))
return;

float damage = 0.0f;
// 200 is MAX weapon damage
SFloatAsBitsSync<8> damage(0, 200.0f, true, false);
damage.data.fValue = 0.0f;

std::uint8_t zone = 0;
CClientPlayer* damaged = nullptr;

if (stream.ReadBit())
{
ElementID id = INVALID_ELEMENT_ID;
if (!stream.Read(damage) || !stream.Read(zone) || !stream.Read(id))
if (!stream.Read(&damage) || !stream.Read(zone) || !stream.Read(id))
return;

damaged = DynamicCast<CClientPlayer>(CElementIDs::GetElement(id));
}

bool duplicate = false;

if (start == player->m_vecPrevBulletSyncStart && end == player->m_vecPrevBulletSyncEnd)
duplicate = true;

player->m_vecPrevBulletSyncStart = start;
player->m_vecPrevBulletSyncEnd = end;

if (static_cast<char>(order - player->m_ucPrevBulletSyncOrderCounter) > 0)
duplicate = false;

player->m_ucPrevBulletSyncOrderCounter = order;

if (duplicate)
return;

player->DischargeWeapon(type, start, end, damage, zone, damaged);
player->DischargeWeapon(type, startPosition.data.vecPosition, endPosition.data.vecPosition, damage.data.fValue, zone, damaged);
}

void CNetAPI::ReadWeaponBulletsync(CClientPlayer* player, NetBitStreamInterface& stream)
Expand All @@ -2290,39 +2279,47 @@ void CNetAPI::ReadWeaponBulletsync(CClientPlayer* player, NetBitStreamInterface&
if (!weapon || !CClientWeaponManager::HasWeaponBulletSync(weapon->GetWeaponType()))
return;

CVector start;
CVector end;
if (!stream.Read(reinterpret_cast<char*>(&start), sizeof(CVector)) || !stream.Read(reinterpret_cast<char*>(&end), sizeof(CVector)) || !start.IsValid() ||
!end.IsValid())
SPositionSync startPosition;
SPositionSync endPosition;
if (!stream.Read(&startPosition) || !stream.Read(&endPosition))
return;

uint8_t order = 0;
if (!stream.Read(order))
if (!startPosition.data.vecPosition.IsValid() || !endPosition.data.vecPosition.IsValid())
return;

weapon->FireInstantHit(start, end, false, true);
// Huge coordinates can crash other players
if (!startPosition.data.vecPosition.IsInWorldBounds(true) || !endPosition.data.vecPosition.IsInWorldBounds(true))
return;

weapon->FireInstantHit(startPosition.data.vecPosition, endPosition.data.vecPosition, false, true);
}

void CNetAPI::SendBulletSyncFire(eWeaponType weapon, const CVector& start, const CVector& end, float damage, std::uint8_t zone, CClientPlayer* damaged)
{
auto* stream = g_pNet->AllocateNetBitStream();
NetBitStreamInterface* stream = g_pNet->AllocateNetBitStream();
SPositionSync startPosition;
startPosition.data.vecPosition = start;

SPositionSync endPosition;
endPosition.data.vecPosition = end;

stream->Write(static_cast<char>(weapon));
stream->Write(reinterpret_cast<const char*>(&start), sizeof(CVector));
stream->Write(reinterpret_cast<const char*>(&end), sizeof(CVector));
stream->Write(m_ucBulletSyncOrderCounter++);
stream->Write(static_cast<std::uint8_t>(weapon));

if (damage > 0.0f && damaged)
stream->Write(&startPosition);
stream->Write(&endPosition);

bool hasDamaged = damaged && damage > 0.0f;
stream->WriteBit(hasDamaged);

if (hasDamaged)
{
stream->WriteBit(true);
stream->Write(damage);
SFloatAsBitsSync<8> damageF(0, 200.0f, false);
damageF.data.fValue = damage;

stream->Write(&damageF);
stream->Write(zone);
stream->Write(damaged->GetID());
}
else
{
stream->WriteBit(false);
}

g_pNet->SendPacket(PACKET_ID_PLAYER_BULLETSYNC, stream, PACKET_PRIORITY_MEDIUM, PACKET_RELIABILITY_RELIABLE);
g_pNet->DeallocateNetBitStream(stream);
Expand All @@ -2333,12 +2330,17 @@ void CNetAPI::SendBulletSyncCustomWeaponFire(CClientWeapon* weapon, const CVecto
if (weapon->IsLocalEntity())
return;

auto* stream = g_pNet->AllocateNetBitStream();
NetBitStreamInterface* stream = g_pNet->AllocateNetBitStream();

SPositionSync startPosition;
startPosition.data.vecPosition = start;

SPositionSync endPosition;
endPosition.data.vecPosition = end;

stream->Write(weapon->GetID());
stream->Write(reinterpret_cast<const char*>(&start), sizeof(CVector));
stream->Write(reinterpret_cast<const char*>(&end), sizeof(CVector));
stream->Write(m_ucCustomWeaponBulletSyncOrderCounter++);
stream->Write(&startPosition);
stream->Write(&endPosition);

g_pNet->SendPacket(PACKET_ID_WEAPON_BULLETSYNC, stream, PACKET_PRIORITY_MEDIUM, PACKET_RELIABILITY_RELIABLE);
g_pNet->DeallocateNetBitStream(stream);
Expand Down
2 changes: 0 additions & 2 deletions Client/mods/deathmatch/logic/CNetAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,4 @@ class CNetAPI
CControllerState m_LastSentControllerState;
float m_fLastSentCameraRotation;
float m_fLastSentAimY;
uchar m_ucBulletSyncOrderCounter;
uchar m_ucCustomWeaponBulletSyncOrderCounter;
};
26 changes: 13 additions & 13 deletions Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2527,10 +2527,11 @@ void CGame::Packet_Keysync(CKeysyncPacket& Packet)

void CGame::Packet_Bulletsync(CBulletsyncPacket& packet)
{
auto* player = packet.GetSourcePlayer();
CPlayer* player = packet.GetSourcePlayer();
if (!player || !player->IsJoined())
return;

// Early return when the player attempts to fire a weapon they do not have
const auto type = static_cast<std::uint8_t>(packet.m_weapon);
if (!player->HasWeaponType(type))
return;
Expand All @@ -2546,48 +2547,47 @@ void CGame::Packet_Bulletsync(CBulletsyncPacket& packet)
const auto level = player->GetPlayerStat(stat);
auto* stats = g_pGame->GetWeaponStatManager()->GetWeaponStatsFromSkillLevel(packet.m_weapon, level);

const float distanceSq = (packet.m_start - packet.m_end).LengthSquared();
const float distanceSq = (packet.m_start.data.vecPosition - packet.m_end.data.vecPosition).LengthSquared();
const float range = stats->GetWeaponRange();
const float rangeSq = range * range;

const float maxRangeSq = rangeSq * 1.1f; // 10% tolerance for floating point
if (distanceSq > maxRangeSq)
return;

RelayNearbyPacket(packet);

CLuaArguments args;
args.PushNumber(packet.m_weapon);
args.PushNumber(packet.m_end.fX);
args.PushNumber(packet.m_end.fY);
args.PushNumber(packet.m_end.fZ);
args.PushNumber(packet.m_end.data.vecPosition.fX);
args.PushNumber(packet.m_end.data.vecPosition.fY);
args.PushNumber(packet.m_end.data.vecPosition.fZ);

if (packet.m_damaged == INVALID_ELEMENT_ID)
args.PushNil();
else
args.PushElement(CElementIDs::GetElement(packet.m_damaged));

args.PushNumber(packet.m_start.fX);
args.PushNumber(packet.m_start.fY);
args.PushNumber(packet.m_start.fZ);
args.PushNumber(packet.m_start.data.vecPosition.fX);
args.PushNumber(packet.m_start.data.vecPosition.fY);
args.PushNumber(packet.m_start.data.vecPosition.fZ);

player->CallEvent("onPlayerWeaponFire", args);
}

void CGame::Packet_WeaponBulletsync(CCustomWeaponBulletSyncPacket& packet)
{
auto* player = packet.GetSourcePlayer();
CPlayer* player = packet.GetSourcePlayer();
if (!player || !player->IsJoined())
return;

if (player != packet.GetWeaponOwner())
return;

auto* weapon = packet.GetWeapon();
CCustomWeapon* weapon = packet.GetWeapon();
if (weapon->GetAmmo() <= 0)
return;

if (weapon->GetClipAmmo() <= 0)
return;

CLuaArguments args;
args.PushElement(player);

Expand Down
2 changes: 1 addition & 1 deletion Server/mods/deathmatch/logic/CWeaponStatManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@ float CWeaponStatManager::GetWeaponRangeFromSkillLevel(eWeaponType eWeapon, floa
return fWeaponRange;
}

bool CWeaponStatManager::HasWeaponBulletSync(uint32_t weaponID) noexcept
bool CWeaponStatManager::HasWeaponBulletSync(std::uint8_t weaponID) noexcept
{
return weaponID >= 22 && weaponID <= 34;
}
2 changes: 1 addition & 1 deletion Server/mods/deathmatch/logic/CWeaponStatManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class CWeaponStatManager

// Static Methods
static eStats GetSkillStatIndex(eWeaponType weapon);
static bool HasWeaponBulletSync(uint32_t weaponID) noexcept;
static bool HasWeaponBulletSync(std::uint8_t weaponID) noexcept;

private:
std::list<CWeaponStat*> m_OriginalWeaponData;
Expand Down
50 changes: 31 additions & 19 deletions Server/mods/deathmatch/logic/net/CSimBulletsyncPacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,49 @@

#include "StdInc.h"
#include "SimHeaders.h"
#include "CPickupManager.h"
#include "CWeaponStatManager.h"
#include <packets/CBulletsyncPacket.h>

CSimBulletsyncPacket::CSimBulletsyncPacket(ElementID id) : m_id(id)
{
m_cache.damage.data.fValue = 0.0f;
}

bool CSimBulletsyncPacket::Read(NetBitStreamInterface& stream)
{
char type = 0;
if (!stream.Read(type) || !CWeaponStatManager::HasWeaponBulletSync(type))
std::uint8_t weaponType = 0;
if (!stream.Read(weaponType) || !CWeaponStatManager::HasWeaponBulletSync(weaponType))
return false;

m_cache.weapon = static_cast<eWeaponType>(type);
m_cache.weapon = static_cast<eWeaponType>(weaponType);

if (!stream.Read(reinterpret_cast<char*>(&m_cache.start), sizeof(CVector)) || !stream.Read(reinterpret_cast<char*>(&m_cache.end), sizeof(CVector)))
if (!stream.Read(&m_cache.start) || !stream.Read(&m_cache.end))
return false;

if (!m_cache.start.IsValid() || !m_cache.end.IsValid())
if (!m_cache.start.data.vecPosition.IsValid() || !m_cache.end.data.vecPosition.IsValid())
return false;

if (!stream.Read(m_cache.order))
// Huge coordinates can crash other players
if (!m_cache.start.data.vecPosition.IsInWorldBounds(true) || !m_cache.end.data.vecPosition.IsInWorldBounds(true))
return false;

if (!CBulletsyncPacket::ValidateTrajectory(m_cache.start.data.vecPosition, m_cache.end.data.vecPosition))
return false;

if (stream.ReadBit())
{
stream.Read(m_cache.damage);
stream.Read(&m_cache.damage);

if (!std::isfinite(m_cache.damage.data.fValue))
return false;

if (m_cache.damage.data.fValue < 0.0f || m_cache.damage.data.fValue > CBulletsyncPacket::MAX_DAMAGE)
return false;

stream.Read(m_cache.zone);
if (m_cache.zone > CBulletsyncPacket::MAX_BODY_ZONE)
return false;

stream.Read(m_cache.damaged);
}

Expand All @@ -46,22 +61,19 @@ bool CSimBulletsyncPacket::Read(NetBitStreamInterface& stream)
bool CSimBulletsyncPacket::Write(NetBitStreamInterface& stream) const
{
stream.Write(m_id);
stream.Write(static_cast<char>(m_cache.weapon));
stream.Write(reinterpret_cast<const char*>(&m_cache.start), sizeof(CVector));
stream.Write(reinterpret_cast<const char*>(&m_cache.end), sizeof(CVector));
stream.Write(m_cache.order);
stream.Write(static_cast<std::uint8_t>(m_cache.weapon));
stream.Write(&m_cache.start);
stream.Write(&m_cache.end);

bool hasDamaged = m_cache.damage.data.fValue > 0.0f && m_cache.damaged != INVALID_ELEMENT_ID;

if (m_cache.damage > 0 && m_cache.damaged != INVALID_ELEMENT_ID)
stream.WriteBit(hasDamaged);
if (hasDamaged)
{
stream.WriteBit(true);
stream.Write(m_cache.damage);
stream.Write(&m_cache.damage);
stream.Write(m_cache.zone);
stream.Write(m_cache.damaged);
}
else
{
stream.WriteBit(false);
}

return true;
}
13 changes: 6 additions & 7 deletions Server/mods/deathmatch/logic/net/CSimBulletsyncPacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ class CSimBulletsyncPacket : public CSimPacket

struct
{
eWeaponType weapon = eWeaponType::WEAPONTYPE_UNARMED;
CVector start{};
CVector end{};
std::uint8_t order{};
float damage{};
uchar zone{};
ElementID damaged = INVALID_ELEMENT_ID;
eWeaponType weapon = eWeaponType::WEAPONTYPE_UNARMED;
SPositionSync start{};
SPositionSync end{};
SFloatAsBitsSync<8> damage{0.0f, 200.0f, true, false};
std::uint8_t zone{};
ElementID damaged = INVALID_ELEMENT_ID;
} m_cache;
};
Loading
Loading