From 7904449cf70a48e47640f6deebd0a702c474721f Mon Sep 17 00:00:00 2001 From: Tracer <43095317+TracerDS@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:08:36 +0200 Subject: [PATCH 1/3] Add `isVehicleNitroActivated` to serverside --- Client/mods/deathmatch/logic/CNetAPI.cpp | 11 + Server/mods/deathmatch/logic/CVehicle.h | 8 + .../logic/luadefs/CLuaVehicleDefs.cpp | 24 +- .../logic/luadefs/CLuaVehicleDefs.h | 4 + .../logic/net/CSimVehiclePuresyncPacket.cpp | 620 ++++----- .../logic/net/CSimVehiclePuresyncPacket.h | 1 + .../logic/packets/CVehiclePuresyncPacket.cpp | 1116 +++++++++-------- Shared/sdk/net/bitstream.h | 4 + 8 files changed, 926 insertions(+), 862 deletions(-) diff --git a/Client/mods/deathmatch/logic/CNetAPI.cpp b/Client/mods/deathmatch/logic/CNetAPI.cpp index a6238512c7..82b636e963 100644 --- a/Client/mods/deathmatch/logic/CNetAPI.cpp +++ b/Client/mods/deathmatch/logic/CNetAPI.cpp @@ -1548,6 +1548,15 @@ void CNetAPI::ReadVehiclePuresync(CClientPlayer* pPlayer, CClientVehicle* pVehic pPlayer->SetLastPuresyncTime(CClientTime::GetTime()); pPlayer->IncrementVehicleSync(); pPlayer->SetLastPuresyncType(PURESYNC_TYPE_PURESYNC); + + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + float vehicleNitro; + if (!BitStream.Read(vehicleNitro)) + return; + + pVehicle->SetNitroLevel(vehicleNitro); + } } void CNetAPI::WriteVehiclePuresync(CClientPed* pPlayerModel, CClientVehicle* pVehicle, NetBitStreamInterface& BitStream) @@ -1768,6 +1777,8 @@ void CNetAPI::WriteVehiclePuresync(CClientPed* pPlayerModel, CClientVehicle* pVe // Write the sent position to the interpolator AddInterpolation(vecPosition); + + BitStream.Write(static_cast(pVehicle->GetNitroLevel())); } bool CNetAPI::ReadSmallKeysync(CControllerState& ControllerState, NetBitStreamInterface& BitStream) diff --git a/Server/mods/deathmatch/logic/CVehicle.h b/Server/mods/deathmatch/logic/CVehicle.h index 10de01e625..680817f732 100644 --- a/Server/mods/deathmatch/logic/CVehicle.h +++ b/Server/mods/deathmatch/logic/CVehicle.h @@ -280,6 +280,12 @@ class CVehicle final : public CElement CPed* GetJackingPed() { return m_pJackingPed; } void SetJackingPed(CPed* pPed); + float GetNitroLevel() const noexcept { return m_nitroLevel; } + void SetNitroLevel(float level) noexcept { m_nitroLevel = level; } + + bool IsNitroActivated() const noexcept { return m_nitroLevel > 0; } + void SetNitroActivated(bool activated) noexcept { m_nitroLevel = activated ? 1 : 0; } + bool IsInWater() { return m_bInWater; } void SetInWater(bool bInWater) { m_bInWater = bInWater; } @@ -453,6 +459,8 @@ class CVehicle final : public CElement bool m_bNeedsDimensionResync; ushort m_usLastUnoccupiedSyncDimension; + float m_nitroLevel; + public: // 'Safe' variables (that have no need for accessors) bool m_bDamageProof; uint m_uiDamageInfoSendPhase; diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp index 294ea7310c..61aa9c6032 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp @@ -39,7 +39,6 @@ void CLuaVehicleDefs::LoadFunctions() {"getVehicleTurnVelocity", GetVehicleTurnVelocity}, {"getVehicleTurretPosition", GetVehicleTurretPosition}, {"getVehicleMaxPassengers", GetVehicleMaxPassengers}, - {"isVehicleLocked", IsVehicleLocked}, {"getVehiclesOfType", GetVehiclesOfType}, {"getVehicleUpgradeOnSlot", GetVehicleUpgradeOnSlot}, {"getVehicleUpgrades", GetVehicleUpgrades}, @@ -54,15 +53,17 @@ void CLuaVehicleDefs::LoadFunctions() {"getVehicleTowingVehicle", GetVehicleTowingVehicle}, {"getVehiclePaintjob", GetVehiclePaintjob}, {"getVehiclePlateText", GetVehiclePlateText}, + {"getVehicleEngineState", GetVehicleEngineState}, + {"getTrainDirection", GetTrainDirection}, + {"getTrainSpeed", GetTrainSpeed}, + {"isVehicleNitroActivated", ArgumentParser}, + {"isVehicleLocked", IsVehicleLocked}, {"isVehicleDamageProof", IsVehicleDamageProof}, {"isVehicleFuelTankExplodable", IsVehicleFuelTankExplodable}, {"isVehicleFrozen", IsVehicleFrozen}, {"isVehicleOnGround", IsVehicleOnGround}, - {"getVehicleEngineState", GetVehicleEngineState}, {"isTrainDerailed", IsTrainDerailed}, {"isTrainDerailable", IsTrainDerailable}, - {"getTrainDirection", GetTrainDirection}, - {"getTrainSpeed", GetTrainSpeed}, //{"getTrainTrack", ArgumentParser}, {"getTrainPosition", GetTrainPosition}, {"isVehicleBlown", ArgumentParserWarn}, @@ -349,6 +350,21 @@ int CLuaVehicleDefs::CreateVehicle(lua_State* luaVM) return 1; } +bool CLuaVehicleDefs::IsVehicleNitroActivated(CVehicle* vehicle) noexcept +{ + return vehicle->IsNitroActivated(); +} + +float CLuaVehicleDefs::GetVehicleNitroLevel(CVehicle* vehicle) noexcept +{ + return vehicle->GetNitroLevel(); +} + +void CLuaVehicleDefs::SetVehicleNitroLevel(CVehicle* vehicle, std::int8_t level) noexcept +{ + vehicle->SetNitroLevel(level); +} + int CLuaVehicleDefs::GetVehicleType(lua_State* luaVM) { unsigned long ulModel; diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.h b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.h index 3200e2ada3..9e8ef06b03 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.h +++ b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.h @@ -68,6 +68,10 @@ class CLuaVehicleDefs : public CLuaDefs LUA_DECLARE(GetVehicleHeadLightColor); LUA_DECLARE(GetVehicleDoorOpenRatio); + static bool IsVehicleNitroActivated(CVehicle* vehicle) noexcept; + static float GetVehicleNitroLevel(CVehicle* vehicle) noexcept; + static void SetVehicleNitroLevel(CVehicle* vehicle, std::int8_t level) noexcept; + // Vehicle set functions LUA_DECLARE(FixVehicle); LUA_DECLARE(SetVehicleRotation); diff --git a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp index a89d2d3c3c..173f554880 100644 --- a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp +++ b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp @@ -35,227 +35,234 @@ CSimVehiclePuresyncPacket::CSimVehiclePuresyncPacket(ElementID PlayerID, ushort bool CSimVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) { // Player is in a vehicle? - if (m_bPlayerHasOccupiedVehicle) + if (!m_bPlayerHasOccupiedVehicle) + return false; + + // Read out the time context + if (!BitStream.Read(m_Cache.ucTimeContext)) + return false; + + // If incoming time context is zero, use the one here + if (m_Cache.ucTimeContext == 0) + m_Cache.ucTimeContext = m_ucPlayerSyncTimeContext; + + // Only read this packet if it matches the current time context that + // player is in. + if (!CanUpdateSync(m_Cache.ucTimeContext)) + return false; + + // Read out the keysync data + if (!ReadFullKeysync(m_sharedControllerState, BitStream)) + return false; + + // Read out the remote model + if (BitStream.Version() >= 0x05F) + BitStream.Read(m_Cache.iModelID); + else + m_Cache.iModelID = m_usVehicleGotModel; + + // Read out its position + SPositionSync position(false); + if (!BitStream.Read(&position)) + return false; + m_Cache.PlrPosition = position.data.vecPosition; + + if (CVehicleManager::GetVehicleType(m_Cache.iModelID) == VEHICLE_TRAIN) { - // Read out the time context - if (!BitStream.Read(m_Cache.ucTimeContext)) + // Train specific data + float fRailPosition = 0.0f; + uchar ucRailTrack = 0; + bool bRailDirection = false; + float fRailSpeed = 0.0f; + if (!BitStream.Read(fRailPosition) || !BitStream.ReadBit(bRailDirection) || !BitStream.Read(ucRailTrack) || !BitStream.Read(fRailSpeed)) + { return false; + } + m_Cache.fRailPosition = fRailPosition; + m_Cache.bRailDirection = bRailDirection; + m_Cache.ucRailTrack = ucRailTrack; + m_Cache.fRailSpeed = fRailSpeed; + } - // If incoming time context is zero, use the one here - if (m_Cache.ucTimeContext == 0) - m_Cache.ucTimeContext = m_ucPlayerSyncTimeContext; + // Read the camera orientation + ReadCameraOrientation(position.data.vecPosition, BitStream, m_Cache.vecCamPosition, m_Cache.vecCamFwd); - // Only read this packet if it matches the current time context that - // player is in. - if (!CanUpdateSync(m_Cache.ucTimeContext)) - return false; + // Jax: don't allow any outdated packets through + SOccupiedSeatSync seat; + if (!BitStream.Read(&seat)) + return false; + if (seat.data.ucSeat != m_ucPlayerGotOccupiedVehicleSeat) + { + // Mis-matching seats can happen when we warp into a different one, + // which will screw up the whole packet + return false; + } - // Read out the keysync data - if (!ReadFullKeysync(m_sharedControllerState, BitStream)) + // Read out the vehicle matrix only if he's the driver + const unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; + if (uiSeat == 0) + { + // Read out the vehicle rotation in degrees + SRotationDegreesSync rotation; + if (!BitStream.Read(&rotation)) return false; - // Read out the remote model - if (BitStream.Version() >= 0x05F) - BitStream.Read(m_Cache.iModelID); - else - m_Cache.iModelID = m_usVehicleGotModel; + // Set it + m_Cache.VehPosition = position.data.vecPosition; + m_Cache.VehRotationDeg = rotation.data.vecRotation; - // Read out its position - SPositionSync position(false); - if (!BitStream.Read(&position)) + // Move speed vector + SVelocitySync velocity; + if (!BitStream.Read(&velocity)) return false; - m_Cache.PlrPosition = position.data.vecPosition; - if (CVehicleManager::GetVehicleType(m_Cache.iModelID) == VEHICLE_TRAIN) - { - // Train specific data - float fRailPosition = 0.0f; - uchar ucRailTrack = 0; - bool bRailDirection = false; - float fRailSpeed = 0.0f; - if (!BitStream.Read(fRailPosition) || !BitStream.ReadBit(bRailDirection) || !BitStream.Read(ucRailTrack) || !BitStream.Read(fRailSpeed)) - { - return false; - } - m_Cache.fRailPosition = fRailPosition; - m_Cache.bRailDirection = bRailDirection; - m_Cache.ucRailTrack = ucRailTrack; - m_Cache.fRailSpeed = fRailSpeed; - } + m_Cache.BothVelocity = velocity.data.vecVelocity; - // Read the camera orientation - ReadCameraOrientation(position.data.vecPosition, BitStream, m_Cache.vecCamPosition, m_Cache.vecCamFwd); - - // Jax: don't allow any outdated packets through - SOccupiedSeatSync seat; - if (!BitStream.Read(&seat)) - return false; - if (seat.data.ucSeat != m_ucPlayerGotOccupiedVehicleSeat) - { - // Mis-matching seats can happen when we warp into a different one, - // which will screw up the whole packet + // Turn speed vector + SVelocitySync turnSpeed; + if (!BitStream.Read(&turnSpeed)) return false; - } - - // Read out the vehicle matrix only if he's the driver - const unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; - if (uiSeat == 0) - { - // Read out the vehicle rotation in degrees - SRotationDegreesSync rotation; - if (!BitStream.Read(&rotation)) - return false; - - // Set it - m_Cache.VehPosition = position.data.vecPosition; - m_Cache.VehRotationDeg = rotation.data.vecRotation; - // Move speed vector - SVelocitySync velocity; - if (!BitStream.Read(&velocity)) - return false; + m_Cache.VehTurnSpeed = turnSpeed.data.vecVelocity; - m_Cache.BothVelocity = velocity.data.vecVelocity; + // Health + SVehicleHealthSync health; + if (!BitStream.Read(&health)) + return false; + m_Cache.fVehHealth = health.data.fValue; - // Turn speed vector - SVelocitySync turnSpeed; - if (!BitStream.Read(&turnSpeed)) - return false; + // Trailer chain + bool bHasTrailer; + if (!BitStream.ReadBit(bHasTrailer)) + return false; - m_Cache.VehTurnSpeed = turnSpeed.data.vecVelocity; + while (bHasTrailer) + { + STrailerInfo info; + BitStream.Read(info.m_TrailerID); - // Health - SVehicleHealthSync health; - if (!BitStream.Read(&health)) + // Read out the trailer position and rotation + SPositionSync trailerPosition(false); + if (!BitStream.Read(&trailerPosition)) return false; - m_Cache.fVehHealth = health.data.fValue; - // Trailer chain - bool bHasTrailer; - if (!BitStream.ReadBit(bHasTrailer)) + SRotationDegreesSync trailerRotation; + if (!BitStream.Read(&trailerRotation)) return false; - while (bHasTrailer) + // If we found the trailer + if (true) { - STrailerInfo info; - BitStream.Read(info.m_TrailerID); - - // Read out the trailer position and rotation - SPositionSync trailerPosition(false); - if (!BitStream.Read(&trailerPosition)) - return false; + // Set its position and rotation + info.m_TrailerPosition = trailerPosition.data.vecPosition; + info.m_TrailerRotationDeg = trailerRotation.data.vecRotation; - SRotationDegreesSync trailerRotation; - if (!BitStream.Read(&trailerRotation)) - return false; - - // If we found the trailer - if (true) - { - // Set its position and rotation - info.m_TrailerPosition = trailerPosition.data.vecPosition; - info.m_TrailerRotationDeg = trailerRotation.data.vecRotation; - - m_Cache.TrailerList.push_back(info); - } - else - break; - - if (BitStream.ReadBit(bHasTrailer) == false) - return false; + m_Cache.TrailerList.push_back(info); } + else + break; + + if (BitStream.ReadBit(bHasTrailer) == false) + return false; } + } - // Read Damage info, but do not store, as we do not relay this info - if (BitStream.Version() >= 0x047) + // Read Damage info, but do not store, as we do not relay this info + if (BitStream.Version() >= 0x047) + { + if (BitStream.ReadBit() == true) { - if (BitStream.ReadBit() == true) - { - ElementID DamagerID; - if (!BitStream.Read(DamagerID)) - return false; + ElementID DamagerID; + if (!BitStream.Read(DamagerID)) + return false; - SWeaponTypeSync weaponType; - if (!BitStream.Read(&weaponType)) - return false; + SWeaponTypeSync weaponType; + if (!BitStream.Read(&weaponType)) + return false; - SBodypartSync bodyPart; - if (!BitStream.Read(&bodyPart)) - return false; - } + SBodypartSync bodyPart; + if (!BitStream.Read(&bodyPart)) + return false; } + } - // Player health - SPlayerHealthSync health; - if (!BitStream.Read(&health)) - return false; - m_Cache.fPlrHealth = health.data.fValue; + // Player health + SPlayerHealthSync health; + if (!BitStream.Read(&health)) + return false; + m_Cache.fPlrHealth = health.data.fValue; - // Armor - SPlayerArmorSync armor; - if (!BitStream.Read(&armor)) - return false; - m_Cache.fArmor = armor.data.fValue; + // Armor + SPlayerArmorSync armor; + if (!BitStream.Read(&armor)) + return false; + m_Cache.fArmor = armor.data.fValue; - // Flags - if (!BitStream.Read(&m_Cache.flags)) + // Flags + if (!BitStream.Read(&m_Cache.flags)) + return false; + + // Weapon sync + if (m_Cache.flags.data.bHasAWeapon) + { + SWeaponSlotSync slot; + if (!BitStream.Read(&slot)) return false; - // Weapon sync - if (m_Cache.flags.data.bHasAWeapon) + m_Cache.ucWeaponSlot = slot.data.uiSlot; + + if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) { - SWeaponSlotSync slot; - if (!BitStream.Read(&slot)) + // Read the ammo states + SWeaponAmmoSync ammo(m_ucPlayerGotWeaponType, BitStream.Version() >= 0x44, true); + if (!BitStream.Read(&ammo)) return false; + m_Cache.usAmmoInClip = ammo.data.usAmmoInClip; + m_Cache.usTotalAmmo = ammo.data.usTotalAmmo; - m_Cache.ucWeaponSlot = slot.data.uiSlot; + // Read aim data + SWeaponAimSync aim(m_fPlayerGotWeaponRange, true); + if (!BitStream.Read(&aim)) + return false; + m_Cache.fAimDirection = aim.data.fArm; + m_Cache.vecSniperSource = aim.data.vecOrigin; + m_Cache.vecTargetting = aim.data.vecTarget; - if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - // Read the ammo states - SWeaponAmmoSync ammo(m_ucPlayerGotWeaponType, BitStream.Version() >= 0x44, true); - if (!BitStream.Read(&ammo)) - return false; - m_Cache.usAmmoInClip = ammo.data.usAmmoInClip; - m_Cache.usTotalAmmo = ammo.data.usTotalAmmo; - - // Read aim data - SWeaponAimSync aim(m_fPlayerGotWeaponRange, true); - if (!BitStream.Read(&aim)) - return false; - m_Cache.fAimDirection = aim.data.fArm; - m_Cache.vecSniperSource = aim.data.vecOrigin; - m_Cache.vecTargetting = aim.data.vecTarget; - - // Read the driveby direction - SDrivebyDirectionSync driveby; - if (!BitStream.Read(&driveby)) - return false; - m_Cache.ucDriveByDirection = driveby.data.ucDirection; - } + // Read the driveby direction + SDrivebyDirectionSync driveby; + if (!BitStream.Read(&driveby)) + return false; + m_Cache.ucDriveByDirection = driveby.data.ucDirection; } - else - m_Cache.ucWeaponSlot = 0; + } + else + m_Cache.ucWeaponSlot = 0; - // Vehicle specific data if he's the driver - if (uiSeat == 0) - { - ReadVehicleSpecific(BitStream); - } + // Vehicle specific data if he's the driver + if (uiSeat == 0) + { + ReadVehicleSpecific(BitStream); + } - // Read the vehicle_look_left and vehicle_look_right control states - // if it's an aircraft. - if (m_Cache.flags.data.bIsAircraft) - { - m_sharedControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; - m_sharedControllerState.RightShoulder2 = BitStream.ReadBit() * 255; - } + // Read the vehicle_look_left and vehicle_look_right control states + // if it's an aircraft. + if (m_Cache.flags.data.bIsAircraft) + { + m_sharedControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; + m_sharedControllerState.RightShoulder2 = BitStream.ReadBit() * 255; + } + + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + float vehicleNitro; + if (!BitStream.Read(vehicleNitro)) + return false; - // Success - return true; + m_Cache.VehNitroLevel = vehicleNitro; } - return false; + // Success + return true; } // @@ -264,165 +271,168 @@ bool CSimVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) bool CSimVehiclePuresyncPacket::Write(NetBitStreamInterface& BitStream) const { // Player is in a vehicle and is the driver? - if (m_bPlayerHasOccupiedVehicle) - { - // Player ID - BitStream.Write(m_PlayerID); + if (!m_bPlayerHasOccupiedVehicle) + return false; - // Write the time context of that player - BitStream.Write(m_Cache.ucTimeContext); + // Player ID + BitStream.Write(m_PlayerID); - // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent - BitStream.WriteCompressed(m_usPlayerLatency); + // Write the time context of that player + BitStream.Write(m_Cache.ucTimeContext); - // Write the keysync data - WriteFullKeysync(m_sharedControllerState, BitStream); + // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent + BitStream.WriteCompressed(m_usPlayerLatency); - // Write the serverside model (#8800) - if (BitStream.Version() >= 0x05F) - BitStream.Write(m_Cache.iModelID); + // Write the keysync data + WriteFullKeysync(m_sharedControllerState, BitStream); - // Write the vehicle matrix only if he's the driver - CVector vecTemp; - unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; - if (uiSeat == 0) - { - // Vehicle position - SPositionSync position(false); - position.data.vecPosition = m_Cache.VehPosition; - BitStream.Write(&position); + // Write the serverside model (#8800) + if (BitStream.Version() >= 0x05F) + BitStream.Write(m_Cache.iModelID); - if (m_usVehicleGotModel == 449 || m_usVehicleGotModel == 537 || m_usVehicleGotModel == 538 || m_usVehicleGotModel == 570 || - m_usVehicleGotModel == 569 || m_usVehicleGotModel == 590) - { - BitStream.Write(m_Cache.fRailPosition); - BitStream.WriteBit(m_Cache.bRailDirection); - BitStream.Write(m_Cache.ucRailTrack); - BitStream.Write(m_Cache.fRailSpeed); - } + // Write the vehicle matrix only if he's the driver + CVector vecTemp; + unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; + if (uiSeat == 0) + { + // Vehicle position + SPositionSync position(false); + position.data.vecPosition = m_Cache.VehPosition; + BitStream.Write(&position); - // Vehicle rotation - SRotationDegreesSync rotation; - rotation.data.vecRotation = m_Cache.VehRotationDeg; - BitStream.Write(&rotation); + if (m_usVehicleGotModel == 449 || m_usVehicleGotModel == 537 || m_usVehicleGotModel == 538 || m_usVehicleGotModel == 570 || + m_usVehicleGotModel == 569 || m_usVehicleGotModel == 590) + { + BitStream.Write(m_Cache.fRailPosition); + BitStream.WriteBit(m_Cache.bRailDirection); + BitStream.Write(m_Cache.ucRailTrack); + BitStream.Write(m_Cache.fRailSpeed); + } - // Move speed vector - SVelocitySync velocity; - velocity.data.vecVelocity = m_Cache.BothVelocity; - BitStream.Write(&velocity); + // Vehicle rotation + SRotationDegreesSync rotation; + rotation.data.vecRotation = m_Cache.VehRotationDeg; + BitStream.Write(&rotation); - // Turn speed vector - SVelocitySync turnSpeed; - turnSpeed.data.vecVelocity = m_Cache.VehTurnSpeed; - BitStream.Write(&turnSpeed); + // Move speed vector + SVelocitySync velocity; + velocity.data.vecVelocity = m_Cache.BothVelocity; + BitStream.Write(&velocity); - // Health - SVehicleHealthSync health; - health.data.fValue = m_Cache.fVehHealth; - BitStream.Write(&health); + // Turn speed vector + SVelocitySync turnSpeed; + turnSpeed.data.vecVelocity = m_Cache.VehTurnSpeed; + BitStream.Write(&turnSpeed); - // Write trailer chain - if (BitStream.Version() >= 0x42) - { - for (std::vector::const_iterator it = m_Cache.TrailerList.begin(); it != m_Cache.TrailerList.end(); ++it) - { - BitStream.WriteBit(true); + // Health + SVehicleHealthSync health; + health.data.fValue = m_Cache.fVehHealth; + BitStream.Write(&health); - BitStream.Write(it->m_TrailerID); + // Write trailer chain + if (BitStream.Version() >= 0x42) + { + for (std::vector::const_iterator it = m_Cache.TrailerList.begin(); it != m_Cache.TrailerList.end(); ++it) + { + BitStream.WriteBit(true); - SPositionSync trailerPosition(false); - trailerPosition.data.vecPosition = it->m_TrailerPosition; - BitStream.Write(&trailerPosition); + BitStream.Write(it->m_TrailerID); - SRotationDegreesSync trailerRotation; - trailerRotation.data.vecRotation = it->m_TrailerRotationDeg; - BitStream.Write(&trailerRotation); - } + SPositionSync trailerPosition(false); + trailerPosition.data.vecPosition = it->m_TrailerPosition; + BitStream.Write(&trailerPosition); - BitStream.WriteBit(false); + SRotationDegreesSync trailerRotation; + trailerRotation.data.vecRotation = it->m_TrailerRotationDeg; + BitStream.Write(&trailerRotation); } - } - // Player health and armor - SPlayerHealthSync health; - health.data.fValue = m_Cache.fPlrHealth; - BitStream.Write(&health); + BitStream.WriteBit(false); + } + } - SPlayerArmorSync armor; - armor.data.fValue = m_Cache.fArmor; - BitStream.Write(&armor); + // Player health and armor + SPlayerHealthSync health; + health.data.fValue = m_Cache.fPlrHealth; + BitStream.Write(&health); - // Weapon - unsigned char ucWeaponType = m_ucPlayerGotWeaponType; + SPlayerArmorSync armor; + armor.data.fValue = m_Cache.fArmor; + BitStream.Write(&armor); - BitStream.Write(&m_Cache.flags); + // Weapon + unsigned char ucWeaponType = m_ucPlayerGotWeaponType; - // Write the weapon stuff - if (m_Cache.flags.data.bHasAWeapon) - { - // Write the weapon slot - SWeaponSlotSync slot; - slot.data.uiSlot = m_Cache.ucWeaponSlot; - BitStream.Write(&slot); + BitStream.Write(&m_Cache.flags); - if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - // Write the ammo states - SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); - ammo.data.usAmmoInClip = m_Cache.usAmmoInClip; - ammo.data.usTotalAmmo = m_Cache.usTotalAmmo; - BitStream.Write(&ammo); - - // Sync aim data - SWeaponAimSync aim(0.0f, true); - aim.data.vecOrigin = m_Cache.vecSniperSource; - aim.data.vecTarget = m_Cache.vecTargetting; - aim.data.fArm = m_Cache.fAimDirection; - BitStream.Write(&aim); - - // Sync driveby direction - SDrivebyDirectionSync driveby; - driveby.data.ucDirection = m_Cache.ucDriveByDirection; - BitStream.Write(&driveby); - } - } + // Write the weapon stuff + if (m_Cache.flags.data.bHasAWeapon) + { + // Write the weapon slot + SWeaponSlotSync slot; + slot.data.uiSlot = m_Cache.ucWeaponSlot; + BitStream.Write(&slot); - // Vehicle specific data only if he's the driver - if (uiSeat == 0) + if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) { - WriteVehicleSpecific(BitStream); + // Write the ammo states + SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); + ammo.data.usAmmoInClip = m_Cache.usAmmoInClip; + ammo.data.usTotalAmmo = m_Cache.usTotalAmmo; + BitStream.Write(&ammo); + + // Sync aim data + SWeaponAimSync aim(0.0f, true); + aim.data.vecOrigin = m_Cache.vecSniperSource; + aim.data.vecTarget = m_Cache.vecTargetting; + aim.data.fArm = m_Cache.fAimDirection; + BitStream.Write(&aim); + + // Sync driveby direction + SDrivebyDirectionSync driveby; + driveby.data.ucDirection = m_Cache.ucDriveByDirection; + BitStream.Write(&driveby); } + } - // Write vehicle_look_left and vehicle_look_right control states when - // it's an aircraft. - if (m_Cache.flags.data.bIsAircraft) - { - BitStream.WriteBit(m_sharedControllerState.LeftShoulder2 != 0); - BitStream.WriteBit(m_sharedControllerState.RightShoulder2 != 0); - } + // Vehicle specific data only if he's the driver + if (uiSeat == 0) + { + WriteVehicleSpecific(BitStream); + } - // Write parts state - if (BitStream.Version() >= 0x5D) - { - SVehicleDamageSyncMethodeB damage; - // Check where we are in the cycle - uint uiPhase = (m_uiDamageInfoSendPhase & 3); - damage.data.bSyncDoors = (uiPhase == 0); - damage.data.bSyncWheels = (uiPhase == 1); - damage.data.bSyncPanels = (uiPhase == 2); - damage.data.bSyncLights = (uiPhase == 3); - damage.data.doors.data.ucStates = m_DamageInfo.m_ucDoorStates; - damage.data.wheels.data.ucStates = m_DamageInfo.m_ucWheelStates; - damage.data.panels.data.ucStates = m_DamageInfo.m_ucPanelStates; - damage.data.lights.data.ucStates = m_DamageInfo.m_ucLightStates; - BitStream.Write(&damage); - } + // Write vehicle_look_left and vehicle_look_right control states when + // it's an aircraft. + if (m_Cache.flags.data.bIsAircraft) + { + BitStream.WriteBit(m_sharedControllerState.LeftShoulder2 != 0); + BitStream.WriteBit(m_sharedControllerState.RightShoulder2 != 0); + } + + // Write parts state + if (BitStream.Version() >= 0x5D) + { + SVehicleDamageSyncMethodeB damage; + // Check where we are in the cycle + uint uiPhase = (m_uiDamageInfoSendPhase & 3); + damage.data.bSyncDoors = (uiPhase == 0); + damage.data.bSyncWheels = (uiPhase == 1); + damage.data.bSyncPanels = (uiPhase == 2); + damage.data.bSyncLights = (uiPhase == 3); + damage.data.doors.data.ucStates = m_DamageInfo.m_ucDoorStates; + damage.data.wheels.data.ucStates = m_DamageInfo.m_ucWheelStates; + damage.data.panels.data.ucStates = m_DamageInfo.m_ucPanelStates; + damage.data.lights.data.ucStates = m_DamageInfo.m_ucLightStates; + BitStream.Write(&damage); + } - // Success - return true; + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + BitStream.Write(m_Cache.VehNitroLevel); } - return false; + // Success + return true; } void CSimVehiclePuresyncPacket::ReadVehicleSpecific(NetBitStreamInterface& BitStream) diff --git a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.h b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.h index ead28e54b7..5536ad9872 100644 --- a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.h +++ b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.h @@ -73,6 +73,7 @@ class CSimVehiclePuresyncPacket : public CSimPacket CVector VehRotationDeg; CVector BothVelocity; CVector VehTurnSpeed; + float VehNitroLevel; float fVehHealth; diff --git a/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp b/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp index 67bc9574be..63bf627c43 100644 --- a/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp @@ -32,431 +32,438 @@ CVehiclePuresyncPacket::CVehiclePuresyncPacket(CPlayer* pPlayer) bool CVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) { // Got a player to read? - if (m_pSourceElement) - { - CPlayer* pSourcePlayer = static_cast(m_pSourceElement); + if (!m_pSourceElement) + return false; - // Player is in a vehicle? - CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); - if (pVehicle) - { - // Read out the time context - unsigned char ucTimeContext = 0; - if (!BitStream.Read(ucTimeContext)) - return false; + CPlayer* pSourcePlayer = static_cast(m_pSourceElement); - // Only read this packet if it matches the current time context that - // player is in. - if (!pSourcePlayer->CanUpdateSync(ucTimeContext)) - { - return false; - } + // Player is in a vehicle? + CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); + if (pVehicle) + return false; - // Read out the keysync data - CControllerState ControllerState; - if (!ReadFullKeysync(ControllerState, BitStream)) - return false; + // Read out the time context + unsigned char ucTimeContext = 0; + if (!BitStream.Read(ucTimeContext)) + return false; - // Read out the remote model - int iModelID = pVehicle->GetModel(); - int iRemoteModelID = iModelID; + // Only read this packet if it matches the current time context that + // player is in. + if (!pSourcePlayer->CanUpdateSync(ucTimeContext)) + { + return false; + } - if (BitStream.Version() >= 0x05F) - BitStream.Read(iRemoteModelID); + // Read out the keysync data + CControllerState ControllerState; + if (!ReadFullKeysync(ControllerState, BitStream)) + return false; - eVehicleType vehicleType = pVehicle->GetVehicleType(); - eVehicleType remoteVehicleType = CVehicleManager::GetVehicleType(iRemoteModelID); + // Read out the remote model + int iModelID = pVehicle->GetModel(); + int iRemoteModelID = iModelID; - // Read out its position - SPositionSync position(false); - if (!BitStream.Read(&position)) - return false; - pSourcePlayer->SetPosition(position.data.vecPosition); + if (BitStream.Version() >= 0x05F) + BitStream.Read(iRemoteModelID); - // If the remote vehicle is a train, we want to read special train-specific data - if (remoteVehicleType == VEHICLE_TRAIN) - { - float fPosition; - bool bDirection; - CTrainTrack* pTrainTrack; - float fSpeed; + eVehicleType vehicleType = pVehicle->GetVehicleType(); + eVehicleType remoteVehicleType = CVehicleManager::GetVehicleType(iRemoteModelID); - BitStream.Read(fPosition); - BitStream.ReadBit(bDirection); - BitStream.Read(fSpeed); + // Read out its position + SPositionSync position(false); + if (!BitStream.Read(&position)) + return false; + pSourcePlayer->SetPosition(position.data.vecPosition); - // TODO(qaisjp, feature/custom-train-tracks): this needs to be changed to an ElementID when the time is right (in a backwards compatible manner) - // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important - uchar trackIndex; - BitStream.Read(trackIndex); - pTrainTrack = g_pGame->GetTrainTrackManager()->GetTrainTrackByIndex(trackIndex); + // If the remote vehicle is a train, we want to read special train-specific data + if (remoteVehicleType == VEHICLE_TRAIN) + { + float fPosition; + bool bDirection; + CTrainTrack* pTrainTrack; + float fSpeed; + + BitStream.Read(fPosition); + BitStream.ReadBit(bDirection); + BitStream.Read(fSpeed); + + // TODO(qaisjp, feature/custom-train-tracks): this needs to be changed to an ElementID when the time is right (in a backwards compatible manner) + // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important + uchar trackIndex; + BitStream.Read(trackIndex); + pTrainTrack = g_pGame->GetTrainTrackManager()->GetTrainTrackByIndex(trackIndex); + + // But we should only actually apply that train-specific data if that vehicle is train on our side + if (vehicleType == VEHICLE_TRAIN) + { + pVehicle->SetTrainPosition(fPosition); + pVehicle->SetTrainDirection(bDirection); + pVehicle->SetTrainTrack(pTrainTrack); + pVehicle->SetTrainSpeed(fSpeed); + } + } - // But we should only actually apply that train-specific data if that vehicle is train on our side - if (vehicleType == VEHICLE_TRAIN) - { - pVehicle->SetTrainPosition(fPosition); - pVehicle->SetTrainDirection(bDirection); - pVehicle->SetTrainTrack(pTrainTrack); - pVehicle->SetTrainSpeed(fSpeed); - } - } + // Read the camera orientation + CVector vecCamPosition, vecCamFwd; + ReadCameraOrientation(position.data.vecPosition, BitStream, vecCamPosition, vecCamFwd); + pSourcePlayer->SetCameraOrientation(vecCamPosition, vecCamFwd); - // Read the camera orientation - CVector vecCamPosition, vecCamFwd; - ReadCameraOrientation(position.data.vecPosition, BitStream, vecCamPosition, vecCamFwd); - pSourcePlayer->SetCameraOrientation(vecCamPosition, vecCamFwd); + // Jax: don't allow any outdated packets through + SOccupiedSeatSync seat; + if (!BitStream.Read(&seat)) + return false; + if (seat.data.ucSeat != pSourcePlayer->GetOccupiedVehicleSeat()) + { + // Mis-matching seats can happen when we warp into a different one, + // which will screw up the whole packet + return false; + } - // Jax: don't allow any outdated packets through - SOccupiedSeatSync seat; - if (!BitStream.Read(&seat)) - return false; - if (seat.data.ucSeat != pSourcePlayer->GetOccupiedVehicleSeat()) - { - // Mis-matching seats can happen when we warp into a different one, - // which will screw up the whole packet - return false; - } + // Read out the vehicle matrix only if he's the driver + unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); + if (uiSeat == 0) + { + // Read out the vehicle rotation in degrees + SRotationDegreesSync rotation; + if (!BitStream.Read(&rotation)) + return false; - // Read out the vehicle matrix only if he's the driver - unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); - if (uiSeat == 0) - { - // Read out the vehicle rotation in degrees - SRotationDegreesSync rotation; - if (!BitStream.Read(&rotation)) - return false; + // Set it + pVehicle->SetPosition(position.data.vecPosition); + pVehicle->SetRotationDegrees(rotation.data.vecRotation); - // Set it - pVehicle->SetPosition(position.data.vecPosition); - pVehicle->SetRotationDegrees(rotation.data.vecRotation); + // Move speed vector + SVelocitySync velocity; + if (!BitStream.Read(&velocity)) + return false; - // Move speed vector - SVelocitySync velocity; - if (!BitStream.Read(&velocity)) - return false; + pVehicle->SetVelocity(velocity.data.vecVelocity); + pSourcePlayer->SetVelocity(velocity.data.vecVelocity); - pVehicle->SetVelocity(velocity.data.vecVelocity); - pSourcePlayer->SetVelocity(velocity.data.vecVelocity); + // Turn speed vector + SVelocitySync turnSpeed; + if (!BitStream.Read(&turnSpeed)) + return false; - // Turn speed vector - SVelocitySync turnSpeed; - if (!BitStream.Read(&turnSpeed)) - return false; + pVehicle->SetTurnSpeed(turnSpeed.data.vecVelocity); - pVehicle->SetTurnSpeed(turnSpeed.data.vecVelocity); + // Health + SVehicleHealthSync health; + if (!BitStream.Read(&health)) + return false; - // Health - SVehicleHealthSync health; - if (!BitStream.Read(&health)) - return false; + float fPreviousHealth = pVehicle->GetLastSyncedHealth(); + float fHealth = health.data.fValue; - float fPreviousHealth = pVehicle->GetLastSyncedHealth(); - float fHealth = health.data.fValue; + // Less than last time? + if (fHealth < fPreviousHealth) + { + // Grab the delta health + float fDeltaHealth = fPreviousHealth - fHealth; - // Less than last time? - if (fHealth < fPreviousHealth) - { - // Grab the delta health - float fDeltaHealth = fPreviousHealth - fHealth; + if (fDeltaHealth > 0.0f) + { + // Call the onVehicleDamage event + CLuaArguments Arguments; + Arguments.PushNumber(fDeltaHealth); + pVehicle->CallEvent("onVehicleDamage", Arguments); + } + } + pVehicle->SetHealth(fHealth); + // Stops sync + fixVehicle/setElementHealth conflicts triggering onVehicleDamage by having a separate stored float keeping track of ONLY what + // comes in via sync + // - Caz + pVehicle->SetLastSyncedHealth(fHealth); + + // Trailer chain + CVehicle* pTowedByVehicle = pVehicle; + ElementID TrailerID; + bool bHasTrailer; + if (!BitStream.ReadBit(bHasTrailer)) + return false; + + while (bHasTrailer) + { + BitStream.Read(TrailerID); + CVehicle* pTrailer = GetElementFromId(TrailerID); - if (fDeltaHealth > 0.0f) - { - // Call the onVehicleDamage event - CLuaArguments Arguments; - Arguments.PushNumber(fDeltaHealth); - pVehicle->CallEvent("onVehicleDamage", Arguments); - } - } - pVehicle->SetHealth(fHealth); - // Stops sync + fixVehicle/setElementHealth conflicts triggering onVehicleDamage by having a separate stored float keeping track of ONLY what - // comes in via sync - // - Caz - pVehicle->SetLastSyncedHealth(fHealth); - - // Trailer chain - CVehicle* pTowedByVehicle = pVehicle; - ElementID TrailerID; - bool bHasTrailer; - if (!BitStream.ReadBit(bHasTrailer)) - return false; - - while (bHasTrailer) - { - BitStream.Read(TrailerID); - CVehicle* pTrailer = GetElementFromId(TrailerID); + // Read out the trailer position and rotation + SPositionSync trailerPosition(false); + if (!BitStream.Read(&trailerPosition)) + return false; - // Read out the trailer position and rotation - SPositionSync trailerPosition(false); - if (!BitStream.Read(&trailerPosition)) - return false; + SRotationDegreesSync trailerRotation; + if (!BitStream.Read(&trailerRotation)) + return false; - SRotationDegreesSync trailerRotation; - if (!BitStream.Read(&trailerRotation)) - return false; + // If we found the trailer + if (pTrailer) + { + // Set its position and rotation + pTrailer->SetPosition(trailerPosition.data.vecPosition); + pTrailer->SetRotationDegrees(trailerRotation.data.vecRotation); - // If we found the trailer - if (pTrailer) + // Is this a new trailer, attached? + CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); + if (pCurrentTrailer != pTrailer) + { + // If theres a trailer already attached + if (pCurrentTrailer) { - // Set its position and rotation - pTrailer->SetPosition(trailerPosition.data.vecPosition); - pTrailer->SetRotationDegrees(trailerRotation.data.vecRotation); - - // Is this a new trailer, attached? - CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); - if (pCurrentTrailer != pTrailer) - { - // If theres a trailer already attached - if (pCurrentTrailer) - { - pTowedByVehicle->SetTowedVehicle(NULL); - pCurrentTrailer->SetTowedByVehicle(NULL); - - // Tell everyone to detach them - CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); - - // Execute the attach trailer script function - CLuaArguments Arguments; - Arguments.PushElement(pTowedByVehicle); - pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); - } - - // If something else is towing this trailer - CVehicle* pCurrentVehicle = pTrailer->GetTowedByVehicle(); - if (pCurrentVehicle) - { - pCurrentVehicle->SetTowedVehicle(NULL); - pTrailer->SetTowedByVehicle(NULL); - - // Tell everyone to detach them - CVehicleTrailerPacket DetachPacket(pCurrentVehicle, pTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); - - // Execute the attach trailer script function - CLuaArguments Arguments; - Arguments.PushElement(pCurrentVehicle); - pTrailer->CallEvent("onTrailerDetach", Arguments); - } - - pTowedByVehicle->SetTowedVehicle(pTrailer); - pTrailer->SetTowedByVehicle(pTowedByVehicle); - - // Execute the attach trailer script function - CLuaArguments Arguments; - Arguments.PushElement(pTowedByVehicle); - bool bContinue = pTrailer->CallEvent("onTrailerAttach", Arguments); - - // Attach or detach trailers depending on the event outcome - CVehicleTrailerPacket TrailerPacket(pTowedByVehicle, pTrailer, bContinue); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(TrailerPacket); - } + pTowedByVehicle->SetTowedVehicle(NULL); + pCurrentTrailer->SetTowedByVehicle(NULL); + + // Tell everyone to detach them + CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + + // Execute the attach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pTowedByVehicle); + pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); } - else - break; - pTowedByVehicle = pTrailer; + // If something else is towing this trailer + CVehicle* pCurrentVehicle = pTrailer->GetTowedByVehicle(); + if (pCurrentVehicle) + { + pCurrentVehicle->SetTowedVehicle(NULL); + pTrailer->SetTowedByVehicle(NULL); - if (BitStream.ReadBit(bHasTrailer) == false) - return false; - } + // Tell everyone to detach them + CVehicleTrailerPacket DetachPacket(pCurrentVehicle, pTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); - // If there was a trailer before - CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); - if (pCurrentTrailer) - { - pTowedByVehicle->SetTowedVehicle(NULL); - pCurrentTrailer->SetTowedByVehicle(NULL); + // Execute the attach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pCurrentVehicle); + pTrailer->CallEvent("onTrailerDetach", Arguments); + } - // Tell everyone else to detach them - CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + pTowedByVehicle->SetTowedVehicle(pTrailer); + pTrailer->SetTowedByVehicle(pTowedByVehicle); - // Execute the detach trailer script function + // Execute the attach trailer script function CLuaArguments Arguments; Arguments.PushElement(pTowedByVehicle); - pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); + bool bContinue = pTrailer->CallEvent("onTrailerAttach", Arguments); + + // Attach or detach trailers depending on the event outcome + CVehicleTrailerPacket TrailerPacket(pTowedByVehicle, pTrailer, bContinue); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(TrailerPacket); } } + else + break; - // Update Damage info - if (BitStream.Version() >= 0x047) - { - if (BitStream.ReadBit() == true) - { - ElementID DamagerID; - if (!BitStream.Read(DamagerID)) - return false; - - SWeaponTypeSync weaponType; - if (!BitStream.Read(&weaponType)) - return false; + pTowedByVehicle = pTrailer; - SBodypartSync bodyPart; - if (!BitStream.Read(&bodyPart)) - return false; + if (BitStream.ReadBit(bHasTrailer) == false) + return false; + } - pSourcePlayer->SetDamageInfo(DamagerID, weaponType.data.ucWeaponType, bodyPart.data.uiBodypart); - } - } + // If there was a trailer before + CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); + if (pCurrentTrailer) + { + pTowedByVehicle->SetTowedVehicle(NULL); + pCurrentTrailer->SetTowedByVehicle(NULL); - // Player health - SPlayerHealthSync health; - if (!BitStream.Read(&health)) - return false; - float fHealth = health.data.fValue; + // Tell everyone else to detach them + CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); - float fOldHealth = pSourcePlayer->GetHealth(); - float fHealthLoss = fOldHealth - fHealth; + // Execute the detach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pTowedByVehicle); + pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); + } + } - // Less than last packet's frame? - if (fHealth < fOldHealth && fHealthLoss > 0) - { - if (BitStream.Version() <= 0x046) - { - // Call the onPlayerDamage event - CLuaArguments Arguments; - Arguments.PushNil(); - Arguments.PushNumber(false); - Arguments.PushNumber(false); - Arguments.PushNumber(fHealthLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - else - { - // Call the onPlayerDamage event - CLuaArguments Arguments; + // Update Damage info + if (BitStream.Version() >= 0x047) + { + if (BitStream.ReadBit() == true) + { + ElementID DamagerID; + if (!BitStream.Read(DamagerID)) + return false; - CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); - if (pDamageSource) - Arguments.PushElement(pDamageSource); - else - Arguments.PushNil(); - Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); - Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); - Arguments.PushNumber(fHealthLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - } - pSourcePlayer->SetHealth(fHealth); + SWeaponTypeSync weaponType; + if (!BitStream.Read(&weaponType)) + return false; - // Armor - SPlayerArmorSync armor; - if (!BitStream.Read(&armor)) + SBodypartSync bodyPart; + if (!BitStream.Read(&bodyPart)) return false; - float fArmor = armor.data.fValue; - float fOldArmor = pSourcePlayer->GetArmor(); - float fArmorLoss = fOldArmor - fArmor; + pSourcePlayer->SetDamageInfo(DamagerID, weaponType.data.ucWeaponType, bodyPart.data.uiBodypart); + } + } - // Less than last packet's frame? - if (fArmor < fOldArmor && fArmorLoss > 0) - { - if (BitStream.Version() <= 0x046) - { - // Call the onPlayerDamage event - CLuaArguments Arguments; - Arguments.PushNil(); - Arguments.PushNumber(false); - Arguments.PushNumber(false); - Arguments.PushNumber(fArmorLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - else - { - // Call the onPlayerDamage event - CLuaArguments Arguments; + // Player health + SPlayerHealthSync health; + if (!BitStream.Read(&health)) + return false; + float fHealth = health.data.fValue; - CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); - if (pDamageSource) - Arguments.PushElement(pDamageSource); - else - Arguments.PushNil(); - Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); - Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); - Arguments.PushNumber(fArmorLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - } - pSourcePlayer->SetArmor(fArmor); + float fOldHealth = pSourcePlayer->GetHealth(); + float fHealthLoss = fOldHealth - fHealth; - // Flags - SVehiclePuresyncFlags flags; - if (!BitStream.Read(&flags)) - return false; + // Less than last packet's frame? + if (fHealth < fOldHealth && fHealthLoss > 0) + { + if (BitStream.Version() <= 0x046) + { + // Call the onPlayerDamage event + CLuaArguments Arguments; + Arguments.PushNil(); + Arguments.PushNumber(false); + Arguments.PushNumber(false); + Arguments.PushNumber(fHealthLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + else + { + // Call the onPlayerDamage event + CLuaArguments Arguments; - pSourcePlayer->SetWearingGoggles(flags.data.bIsWearingGoggles); - pSourcePlayer->SetDoingGangDriveby(flags.data.bIsDoingGangDriveby); + CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); + if (pDamageSource) + Arguments.PushElement(pDamageSource); + else + Arguments.PushNil(); + Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); + Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); + Arguments.PushNumber(fHealthLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + } + pSourcePlayer->SetHealth(fHealth); - // Weapon sync - if (flags.data.bHasAWeapon) - { - SWeaponSlotSync slot; - if (!BitStream.Read(&slot)) - return false; + // Armor + SPlayerArmorSync armor; + if (!BitStream.Read(&armor)) + return false; + float fArmor = armor.data.fValue; - pSourcePlayer->SetWeaponSlot(slot.data.uiSlot); + float fOldArmor = pSourcePlayer->GetArmor(); + float fArmorLoss = fOldArmor - fArmor; - if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - float fWeaponRange = pSourcePlayer->GetWeaponRangeFromSlot(slot.data.uiSlot); - - // Read the ammo states - SWeaponAmmoSync ammo(pSourcePlayer->GetWeaponType(), BitStream.Version() >= 0x44, true); - if (!BitStream.Read(&ammo)) - return false; - pSourcePlayer->SetWeaponAmmoInClip(ammo.data.usAmmoInClip); - if (BitStream.Version() >= 0x44) - pSourcePlayer->SetWeaponTotalAmmo(ammo.data.usTotalAmmo); - - // Read aim data - SWeaponAimSync aim(fWeaponRange, true); - if (!BitStream.Read(&aim)) - return false; - pSourcePlayer->SetAimDirection(aim.data.fArm); - pSourcePlayer->SetSniperSourceVector(aim.data.vecOrigin); - pSourcePlayer->SetTargettingVector(aim.data.vecTarget); - - // Read the driveby direction - SDrivebyDirectionSync driveby; - if (!BitStream.Read(&driveby)) - return false; - pSourcePlayer->SetDriveByDirection(driveby.data.ucDirection); - } - } + // Less than last packet's frame? + if (fArmor < fOldArmor && fArmorLoss > 0) + { + if (BitStream.Version() <= 0x046) + { + // Call the onPlayerDamage event + CLuaArguments Arguments; + Arguments.PushNil(); + Arguments.PushNumber(false); + Arguments.PushNumber(false); + Arguments.PushNumber(fArmorLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + else + { + // Call the onPlayerDamage event + CLuaArguments Arguments; + + CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); + if (pDamageSource) + Arguments.PushElement(pDamageSource); else - pSourcePlayer->SetWeaponSlot(0); + Arguments.PushNil(); + Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); + Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); + Arguments.PushNumber(fArmorLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + } + pSourcePlayer->SetArmor(fArmor); - // Vehicle specific data if he's the driver - if (uiSeat == 0) - { - ReadVehicleSpecific(pVehicle, BitStream, iRemoteModelID); - - // Set vehicle specific stuff if he's the driver - pVehicle->SetSirenActive(flags.data.bIsSirenOrAlarmActive); - pVehicle->SetSmokeTrailEnabled(flags.data.bIsSmokeTrailEnabled); - pVehicle->SetLandingGearDown(flags.data.bIsLandingGearDown); - pVehicle->SetOnGround(flags.data.bIsOnGround); - pVehicle->SetInWater(flags.data.bIsInWater); - pVehicle->SetDerailed(flags.data.bIsDerailed); - pVehicle->SetHeliSearchLightVisible(flags.data.bIsHeliSearchLightVisible); - } + // Flags + SVehiclePuresyncFlags flags; + if (!BitStream.Read(&flags)) + return false; - // Read the vehicle_look_left and vehicle_look_right control states - // if it's an aircraft. - if (flags.data.bIsAircraft) - { - ControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; - ControllerState.RightShoulder2 = BitStream.ReadBit() * 255; - } + pSourcePlayer->SetWearingGoggles(flags.data.bIsWearingGoggles); + pSourcePlayer->SetDoingGangDriveby(flags.data.bIsDoingGangDriveby); + + // Weapon sync + if (flags.data.bHasAWeapon) + { + SWeaponSlotSync slot; + if (!BitStream.Read(&slot)) + return false; + + pSourcePlayer->SetWeaponSlot(slot.data.uiSlot); + + if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + float fWeaponRange = pSourcePlayer->GetWeaponRangeFromSlot(slot.data.uiSlot); - pSourcePlayer->GetPad()->NewControllerState(ControllerState); + // Read the ammo states + SWeaponAmmoSync ammo(pSourcePlayer->GetWeaponType(), BitStream.Version() >= 0x44, true); + if (!BitStream.Read(&ammo)) + return false; + pSourcePlayer->SetWeaponAmmoInClip(ammo.data.usAmmoInClip); + if (BitStream.Version() >= 0x44) + pSourcePlayer->SetWeaponTotalAmmo(ammo.data.usTotalAmmo); + + // Read aim data + SWeaponAimSync aim(fWeaponRange, true); + if (!BitStream.Read(&aim)) + return false; + pSourcePlayer->SetAimDirection(aim.data.fArm); + pSourcePlayer->SetSniperSourceVector(aim.data.vecOrigin); + pSourcePlayer->SetTargettingVector(aim.data.vecTarget); - // Success - return true; + // Read the driveby direction + SDrivebyDirectionSync driveby; + if (!BitStream.Read(&driveby)) + return false; + pSourcePlayer->SetDriveByDirection(driveby.data.ucDirection); } } + else + pSourcePlayer->SetWeaponSlot(0); + + // Vehicle specific data if he's the driver + if (uiSeat == 0) + { + ReadVehicleSpecific(pVehicle, BitStream, iRemoteModelID); + + // Set vehicle specific stuff if he's the driver + pVehicle->SetSirenActive(flags.data.bIsSirenOrAlarmActive); + pVehicle->SetSmokeTrailEnabled(flags.data.bIsSmokeTrailEnabled); + pVehicle->SetLandingGearDown(flags.data.bIsLandingGearDown); + pVehicle->SetOnGround(flags.data.bIsOnGround); + pVehicle->SetInWater(flags.data.bIsInWater); + pVehicle->SetDerailed(flags.data.bIsDerailed); + pVehicle->SetHeliSearchLightVisible(flags.data.bIsHeliSearchLightVisible); + } + + // Read the vehicle_look_left and vehicle_look_right control states + // if it's an aircraft. + if (flags.data.bIsAircraft) + { + ControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; + ControllerState.RightShoulder2 = BitStream.ReadBit() * 255; + } + + pSourcePlayer->GetPad()->NewControllerState(ControllerState); - return false; + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + float vehicleNitro; + if (!BitStream.Read(vehicleNitro)) + return false; + + pVehicle->SetNitroLevel(vehicleNitro); + } + + // Success + return true; } // @@ -465,223 +472,226 @@ bool CVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) bool CVehiclePuresyncPacket::Write(NetBitStreamInterface& BitStream) const { // Got a player to send? - if (m_pSourceElement) - { - CPlayer* pSourcePlayer = static_cast(m_pSourceElement); + if (!m_pSourceElement) + return false; - // Player is in a vehicle and is the driver? - CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); - if (pVehicle) - { - // Player ID - ElementID PlayerID = pSourcePlayer->GetID(); - BitStream.Write(PlayerID); + CPlayer* pSourcePlayer = static_cast(m_pSourceElement); - // Write the time context of that player - BitStream.Write(pSourcePlayer->GetSyncTimeContext()); + // Player is in a vehicle and is the driver? + CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); + if (!pVehicle) + return false; - // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent - unsigned short usLatency = pSourcePlayer->GetPing(); - BitStream.WriteCompressed(usLatency); + // Player ID + ElementID PlayerID = pSourcePlayer->GetID(); + BitStream.Write(PlayerID); - // Write the keysync data - const CControllerState& ControllerState = pSourcePlayer->GetPad()->GetCurrentControllerState(); - WriteFullKeysync(ControllerState, BitStream); + // Write the time context of that player + BitStream.Write(pSourcePlayer->GetSyncTimeContext()); - // Write the serverside model (#8800) - if (BitStream.Version() >= 0x05F) - BitStream.Write((int)pVehicle->GetModel()); + // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent + unsigned short usLatency = pSourcePlayer->GetPing(); + BitStream.WriteCompressed(usLatency); - // Write the vehicle matrix only if he's the driver - CVector vecTemp; - unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); - if (uiSeat == 0) - { - // Vehicle position - SPositionSync position(false); - position.data.vecPosition = pVehicle->GetPosition(); - BitStream.Write(&position); + // Write the keysync data + const CControllerState& ControllerState = pSourcePlayer->GetPad()->GetCurrentControllerState(); + WriteFullKeysync(ControllerState, BitStream); - // If the remote vehicle is a train, we want to read special train-specific data - if (pVehicle->GetVehicleType() == VEHICLE_TRAIN) - { - // Train specific data - float fPosition = pVehicle->GetTrainPosition(); - bool bDirection = pVehicle->GetTrainDirection(); - float fSpeed = pVehicle->GetTrainSpeed(); - - BitStream.Write(fPosition); - BitStream.WriteBit(bDirection); - BitStream.Write(fSpeed); - - // Push the train track information - const auto trainTrack = pVehicle->GetTrainTrack(); - if (!trainTrack || pVehicle->IsDerailed()) - { - // NOTE(qaisjp, feature/custom-train-tracks): when can a train both be on a track AND derailed? - // I suppose it's possible for some weirdness here. We should make sure that whenever we set the train track, - // we set that the train is NOT derailed; and that whenever we derail the track, we set the train track to nil. - // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important - BitStream.Write((uchar)0); - } - else if (trainTrack && trainTrack->IsDefault()) - { - BitStream.Write(trainTrack->GetDefaultTrackId()); - } - else - { - // TODO(qaisjp, feature/custom-train-tracks): implement behaviour for non-default tracks - assert(0 && "It is impossible for custom train tracks to exist right now, so this should never be reached."); - } - } + // Write the serverside model (#8800) + if (BitStream.Version() >= 0x05F) + BitStream.Write((int)pVehicle->GetModel()); - // Vehicle rotation - SRotationDegreesSync rotation; - pVehicle->GetRotationDegrees(rotation.data.vecRotation); - BitStream.Write(&rotation); + // Write the vehicle matrix only if he's the driver + CVector vecTemp; + unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); + if (uiSeat == 0) + { + // Vehicle position + SPositionSync position(false); + position.data.vecPosition = pVehicle->GetPosition(); + BitStream.Write(&position); - // Move speed vector - SVelocitySync velocity; - velocity.data.vecVelocity = pVehicle->GetVelocity(); - BitStream.Write(&velocity); + // If the remote vehicle is a train, we want to read special train-specific data + if (pVehicle->GetVehicleType() == VEHICLE_TRAIN) + { + // Train specific data + float fPosition = pVehicle->GetTrainPosition(); + bool bDirection = pVehicle->GetTrainDirection(); + float fSpeed = pVehicle->GetTrainSpeed(); + + BitStream.Write(fPosition); + BitStream.WriteBit(bDirection); + BitStream.Write(fSpeed); + + // Push the train track information + const auto trainTrack = pVehicle->GetTrainTrack(); + if (!trainTrack || pVehicle->IsDerailed()) + { + // NOTE(qaisjp, feature/custom-train-tracks): when can a train both be on a track AND derailed? + // I suppose it's possible for some weirdness here. We should make sure that whenever we set the train track, + // we set that the train is NOT derailed; and that whenever we derail the track, we set the train track to nil. + // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important + BitStream.Write((uchar)0); + } + else if (trainTrack && trainTrack->IsDefault()) + { + BitStream.Write(trainTrack->GetDefaultTrackId()); + } + else + { + // TODO(qaisjp, feature/custom-train-tracks): implement behaviour for non-default tracks + assert(0 && "It is impossible for custom train tracks to exist right now, so this should never be reached."); + } + } - // Turn speed vector - SVelocitySync turnSpeed; - turnSpeed.data.vecVelocity = pVehicle->GetTurnSpeed(); - BitStream.Write(&turnSpeed); + // Vehicle rotation + SRotationDegreesSync rotation; + pVehicle->GetRotationDegrees(rotation.data.vecRotation); + BitStream.Write(&rotation); - // Health - SVehicleHealthSync health; - health.data.fValue = pVehicle->GetHealth(); - BitStream.Write(&health); + // Move speed vector + SVelocitySync velocity; + velocity.data.vecVelocity = pVehicle->GetVelocity(); + BitStream.Write(&velocity); - // Write the trailer chain - if (BitStream.Version() >= 0x42) - { - CVehicle* pTrailer = pVehicle->GetTowedVehicle(); - while (pTrailer) - { - BitStream.WriteBit(true); - BitStream.Write(pTrailer->GetID()); + // Turn speed vector + SVelocitySync turnSpeed; + turnSpeed.data.vecVelocity = pVehicle->GetTurnSpeed(); + BitStream.Write(&turnSpeed); - // Write the position and rotation - CVector vecTrailerPosition, vecTrailerRotationDegrees; + // Health + SVehicleHealthSync health; + health.data.fValue = pVehicle->GetHealth(); + BitStream.Write(&health); - // Write the matrix - vecTrailerPosition = pTrailer->GetPosition(); - pTrailer->GetRotationDegrees(vecTrailerRotationDegrees); + // Write the trailer chain + if (BitStream.Version() >= 0x42) + { + CVehicle* pTrailer = pVehicle->GetTowedVehicle(); + while (pTrailer) + { + BitStream.WriteBit(true); + BitStream.Write(pTrailer->GetID()); - SPositionSync trailerPosition(false); - trailerPosition.data.vecPosition = vecTrailerPosition; - BitStream.Write(&trailerPosition); + // Write the position and rotation + CVector vecTrailerPosition, vecTrailerRotationDegrees; - SRotationDegreesSync trailerRotation; - trailerRotation.data.vecRotation = vecTrailerRotationDegrees; - BitStream.Write(&trailerRotation); + // Write the matrix + vecTrailerPosition = pTrailer->GetPosition(); + pTrailer->GetRotationDegrees(vecTrailerRotationDegrees); - // Get the next towed vehicle - pTrailer = pTrailer->GetTowedVehicle(); - } + SPositionSync trailerPosition(false); + trailerPosition.data.vecPosition = vecTrailerPosition; + BitStream.Write(&trailerPosition); - // End of our trailer chain - BitStream.WriteBit(false); - } + SRotationDegreesSync trailerRotation; + trailerRotation.data.vecRotation = vecTrailerRotationDegrees; + BitStream.Write(&trailerRotation); + + // Get the next towed vehicle + pTrailer = pTrailer->GetTowedVehicle(); } - // Player health and armor - SPlayerHealthSync health; - health.data.fValue = pSourcePlayer->GetHealth(); - BitStream.Write(&health); - - SPlayerArmorSync armor; - armor.data.fValue = pSourcePlayer->GetArmor(); - BitStream.Write(&armor); - - // Weapon - unsigned char ucWeaponType = pSourcePlayer->GetWeaponType(); - - // Flags - SVehiclePuresyncFlags flags; - flags.data.bIsWearingGoggles = pSourcePlayer->IsWearingGoggles(); - flags.data.bIsDoingGangDriveby = pSourcePlayer->IsDoingGangDriveby(); - flags.data.bIsSirenOrAlarmActive = pVehicle->IsSirenActive(); - flags.data.bIsSmokeTrailEnabled = pVehicle->IsSmokeTrailEnabled(); - flags.data.bIsLandingGearDown = pVehicle->IsLandingGearDown(); - flags.data.bIsOnGround = pVehicle->IsOnGround(); - flags.data.bIsInWater = pVehicle->IsInWater(); - flags.data.bIsDerailed = pVehicle->IsDerailed(); - flags.data.bIsAircraft = (pVehicle->GetVehicleType() == VEHICLE_PLANE || pVehicle->GetVehicleType() == VEHICLE_HELI); - flags.data.bHasAWeapon = (ucWeaponType != 0); - flags.data.bIsHeliSearchLightVisible = pVehicle->IsHeliSearchLightVisible(); - BitStream.Write(&flags); - - // Write the weapon stuff - if (flags.data.bHasAWeapon) - { - // Write the weapon slot - SWeaponSlotSync slot; - slot.data.uiSlot = pSourcePlayer->GetWeaponSlot(); - BitStream.Write(&slot); + // End of our trailer chain + BitStream.WriteBit(false); + } + } - if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - // Write the ammo states - SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); - ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip(); - ammo.data.usTotalAmmo = pSourcePlayer->GetWeaponTotalAmmo(); - BitStream.Write(&ammo); - - // Sync aim data - SWeaponAimSync aim(0.0f, true); - aim.data.vecOrigin = pSourcePlayer->GetSniperSourceVector(); - pSourcePlayer->GetTargettingVector(aim.data.vecTarget); - aim.data.fArm = pSourcePlayer->GetAimDirection(); - BitStream.Write(&aim); - - // Sync driveby direction - SDrivebyDirectionSync driveby; - driveby.data.ucDirection = pSourcePlayer->GetDriveByDirection(); - BitStream.Write(&driveby); - } - } + // Player health and armor + SPlayerHealthSync health; + health.data.fValue = pSourcePlayer->GetHealth(); + BitStream.Write(&health); + + SPlayerArmorSync armor; + armor.data.fValue = pSourcePlayer->GetArmor(); + BitStream.Write(&armor); + + // Weapon + unsigned char ucWeaponType = pSourcePlayer->GetWeaponType(); + + // Flags + SVehiclePuresyncFlags flags; + flags.data.bIsWearingGoggles = pSourcePlayer->IsWearingGoggles(); + flags.data.bIsDoingGangDriveby = pSourcePlayer->IsDoingGangDriveby(); + flags.data.bIsSirenOrAlarmActive = pVehicle->IsSirenActive(); + flags.data.bIsSmokeTrailEnabled = pVehicle->IsSmokeTrailEnabled(); + flags.data.bIsLandingGearDown = pVehicle->IsLandingGearDown(); + flags.data.bIsOnGround = pVehicle->IsOnGround(); + flags.data.bIsInWater = pVehicle->IsInWater(); + flags.data.bIsDerailed = pVehicle->IsDerailed(); + flags.data.bIsAircraft = (pVehicle->GetVehicleType() == VEHICLE_PLANE || pVehicle->GetVehicleType() == VEHICLE_HELI); + flags.data.bHasAWeapon = (ucWeaponType != 0); + flags.data.bIsHeliSearchLightVisible = pVehicle->IsHeliSearchLightVisible(); + BitStream.Write(&flags); + + // Write the weapon stuff + if (flags.data.bHasAWeapon) + { + // Write the weapon slot + SWeaponSlotSync slot; + slot.data.uiSlot = pSourcePlayer->GetWeaponSlot(); + BitStream.Write(&slot); - // Vehicle specific data only if he's the driver - if (uiSeat == 0) - { - WriteVehicleSpecific(pVehicle, BitStream); - } + if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + // Write the ammo states + SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); + ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip(); + ammo.data.usTotalAmmo = pSourcePlayer->GetWeaponTotalAmmo(); + BitStream.Write(&ammo); + + // Sync aim data + SWeaponAimSync aim(0.0f, true); + aim.data.vecOrigin = pSourcePlayer->GetSniperSourceVector(); + pSourcePlayer->GetTargettingVector(aim.data.vecTarget); + aim.data.fArm = pSourcePlayer->GetAimDirection(); + BitStream.Write(&aim); + + // Sync driveby direction + SDrivebyDirectionSync driveby; + driveby.data.ucDirection = pSourcePlayer->GetDriveByDirection(); + BitStream.Write(&driveby); + } + } - // Write vehicle_look_left and vehicle_look_right control states when - // it's an aircraft. - if (flags.data.bIsAircraft) - { - BitStream.WriteBit(ControllerState.LeftShoulder2 != 0); - BitStream.WriteBit(ControllerState.RightShoulder2 != 0); - } + // Vehicle specific data only if he's the driver + if (uiSeat == 0) + { + WriteVehicleSpecific(pVehicle, BitStream); + } - // Write parts state - if (BitStream.Version() >= 0x5D) - { - SVehicleDamageSyncMethodeB damage; - // Check where we are in the cycle - uchar ucMode = (pVehicle->m_uiDamageInfoSendPhase & 3); - damage.data.bSyncDoors = (ucMode == 0); - damage.data.bSyncWheels = (ucMode == 1); - damage.data.bSyncPanels = (ucMode == 2); - damage.data.bSyncLights = (ucMode == 3); - damage.data.doors.data.ucStates = pVehicle->m_ucDoorStates; - damage.data.wheels.data.ucStates = pVehicle->m_ucWheelStates; - damage.data.panels.data.ucStates = pVehicle->m_ucPanelStates; - damage.data.lights.data.ucStates = pVehicle->m_ucLightStates; - BitStream.Write(&damage); - } + // Write vehicle_look_left and vehicle_look_right control states when + // it's an aircraft. + if (flags.data.bIsAircraft) + { + BitStream.WriteBit(ControllerState.LeftShoulder2 != 0); + BitStream.WriteBit(ControllerState.RightShoulder2 != 0); + } - // Success - return true; - } + // Write parts state + if (BitStream.Version() >= 0x5D) + { + SVehicleDamageSyncMethodeB damage; + // Check where we are in the cycle + uchar ucMode = (pVehicle->m_uiDamageInfoSendPhase & 3); + damage.data.bSyncDoors = (ucMode == 0); + damage.data.bSyncWheels = (ucMode == 1); + damage.data.bSyncPanels = (ucMode == 2); + damage.data.bSyncLights = (ucMode == 3); + damage.data.doors.data.ucStates = pVehicle->m_ucDoorStates; + damage.data.wheels.data.ucStates = pVehicle->m_ucWheelStates; + damage.data.panels.data.ucStates = pVehicle->m_ucPanelStates; + damage.data.lights.data.ucStates = pVehicle->m_ucLightStates; + BitStream.Write(&damage); + } + + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + BitStream.Write(pVehicle->GetNitroLevel()); } - return false; + // Success + return true; } void CVehiclePuresyncPacket::ReadVehicleSpecific(CVehicle* pVehicle, NetBitStreamInterface& BitStream, int iRemoteModel) diff --git a/Shared/sdk/net/bitstream.h b/Shared/sdk/net/bitstream.h index c29f739ff1..768db59ed1 100644 --- a/Shared/sdk/net/bitstream.h +++ b/Shared/sdk/net/bitstream.h @@ -572,6 +572,10 @@ enum class eBitStreamVersion : unsigned short // 2024-09-04 RespawnObject_Serverside, + // Add "isVehicleNitroActivated" to serverside + // 2024-09-18 + IsVehicleNitroActivated_Serverside, + // 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, From d5e6247cb6ac2d12cee9ba0d94159adbf2ed3e01 Mon Sep 17 00:00:00 2001 From: Tracer <43095317+TracerDS@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:29:18 +0200 Subject: [PATCH 2/3] Removed refactoring changes --- .../logic/luadefs/CLuaVehicleDefs.cpp | 24 +- .../logic/net/CSimVehiclePuresyncPacket.cpp | 631 ++++----- .../logic/packets/CVehiclePuresyncPacket.cpp | 1124 +++++++++-------- 3 files changed, 886 insertions(+), 893 deletions(-) diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp index 61aa9c6032..294ea7310c 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp @@ -39,6 +39,7 @@ void CLuaVehicleDefs::LoadFunctions() {"getVehicleTurnVelocity", GetVehicleTurnVelocity}, {"getVehicleTurretPosition", GetVehicleTurretPosition}, {"getVehicleMaxPassengers", GetVehicleMaxPassengers}, + {"isVehicleLocked", IsVehicleLocked}, {"getVehiclesOfType", GetVehiclesOfType}, {"getVehicleUpgradeOnSlot", GetVehicleUpgradeOnSlot}, {"getVehicleUpgrades", GetVehicleUpgrades}, @@ -53,17 +54,15 @@ void CLuaVehicleDefs::LoadFunctions() {"getVehicleTowingVehicle", GetVehicleTowingVehicle}, {"getVehiclePaintjob", GetVehiclePaintjob}, {"getVehiclePlateText", GetVehiclePlateText}, - {"getVehicleEngineState", GetVehicleEngineState}, - {"getTrainDirection", GetTrainDirection}, - {"getTrainSpeed", GetTrainSpeed}, - {"isVehicleNitroActivated", ArgumentParser}, - {"isVehicleLocked", IsVehicleLocked}, {"isVehicleDamageProof", IsVehicleDamageProof}, {"isVehicleFuelTankExplodable", IsVehicleFuelTankExplodable}, {"isVehicleFrozen", IsVehicleFrozen}, {"isVehicleOnGround", IsVehicleOnGround}, + {"getVehicleEngineState", GetVehicleEngineState}, {"isTrainDerailed", IsTrainDerailed}, {"isTrainDerailable", IsTrainDerailable}, + {"getTrainDirection", GetTrainDirection}, + {"getTrainSpeed", GetTrainSpeed}, //{"getTrainTrack", ArgumentParser}, {"getTrainPosition", GetTrainPosition}, {"isVehicleBlown", ArgumentParserWarn}, @@ -350,21 +349,6 @@ int CLuaVehicleDefs::CreateVehicle(lua_State* luaVM) return 1; } -bool CLuaVehicleDefs::IsVehicleNitroActivated(CVehicle* vehicle) noexcept -{ - return vehicle->IsNitroActivated(); -} - -float CLuaVehicleDefs::GetVehicleNitroLevel(CVehicle* vehicle) noexcept -{ - return vehicle->GetNitroLevel(); -} - -void CLuaVehicleDefs::SetVehicleNitroLevel(CVehicle* vehicle, std::int8_t level) noexcept -{ - vehicle->SetNitroLevel(level); -} - int CLuaVehicleDefs::GetVehicleType(lua_State* luaVM) { unsigned long ulModel; diff --git a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp index 173f554880..68d79121ce 100644 --- a/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp +++ b/Server/mods/deathmatch/logic/net/CSimVehiclePuresyncPacket.cpp @@ -35,234 +35,237 @@ CSimVehiclePuresyncPacket::CSimVehiclePuresyncPacket(ElementID PlayerID, ushort bool CSimVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) { // Player is in a vehicle? - if (!m_bPlayerHasOccupiedVehicle) - return false; - - // Read out the time context - if (!BitStream.Read(m_Cache.ucTimeContext)) - return false; - - // If incoming time context is zero, use the one here - if (m_Cache.ucTimeContext == 0) - m_Cache.ucTimeContext = m_ucPlayerSyncTimeContext; - - // Only read this packet if it matches the current time context that - // player is in. - if (!CanUpdateSync(m_Cache.ucTimeContext)) - return false; - - // Read out the keysync data - if (!ReadFullKeysync(m_sharedControllerState, BitStream)) - return false; - - // Read out the remote model - if (BitStream.Version() >= 0x05F) - BitStream.Read(m_Cache.iModelID); - else - m_Cache.iModelID = m_usVehicleGotModel; - - // Read out its position - SPositionSync position(false); - if (!BitStream.Read(&position)) - return false; - m_Cache.PlrPosition = position.data.vecPosition; - - if (CVehicleManager::GetVehicleType(m_Cache.iModelID) == VEHICLE_TRAIN) + if (m_bPlayerHasOccupiedVehicle) { - // Train specific data - float fRailPosition = 0.0f; - uchar ucRailTrack = 0; - bool bRailDirection = false; - float fRailSpeed = 0.0f; - if (!BitStream.Read(fRailPosition) || !BitStream.ReadBit(bRailDirection) || !BitStream.Read(ucRailTrack) || !BitStream.Read(fRailSpeed)) - { + // Read out the time context + if (!BitStream.Read(m_Cache.ucTimeContext)) return false; - } - m_Cache.fRailPosition = fRailPosition; - m_Cache.bRailDirection = bRailDirection; - m_Cache.ucRailTrack = ucRailTrack; - m_Cache.fRailSpeed = fRailSpeed; - } - // Read the camera orientation - ReadCameraOrientation(position.data.vecPosition, BitStream, m_Cache.vecCamPosition, m_Cache.vecCamFwd); + // If incoming time context is zero, use the one here + if (m_Cache.ucTimeContext == 0) + m_Cache.ucTimeContext = m_ucPlayerSyncTimeContext; - // Jax: don't allow any outdated packets through - SOccupiedSeatSync seat; - if (!BitStream.Read(&seat)) - return false; - if (seat.data.ucSeat != m_ucPlayerGotOccupiedVehicleSeat) - { - // Mis-matching seats can happen when we warp into a different one, - // which will screw up the whole packet - return false; - } - - // Read out the vehicle matrix only if he's the driver - const unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; - if (uiSeat == 0) - { - // Read out the vehicle rotation in degrees - SRotationDegreesSync rotation; - if (!BitStream.Read(&rotation)) + // Only read this packet if it matches the current time context that + // player is in. + if (!CanUpdateSync(m_Cache.ucTimeContext)) return false; - // Set it - m_Cache.VehPosition = position.data.vecPosition; - m_Cache.VehRotationDeg = rotation.data.vecRotation; - - // Move speed vector - SVelocitySync velocity; - if (!BitStream.Read(&velocity)) + // Read out the keysync data + if (!ReadFullKeysync(m_sharedControllerState, BitStream)) return false; - m_Cache.BothVelocity = velocity.data.vecVelocity; + // Read out the remote model + if (BitStream.Version() >= 0x05F) + BitStream.Read(m_Cache.iModelID); + else + m_Cache.iModelID = m_usVehicleGotModel; - // Turn speed vector - SVelocitySync turnSpeed; - if (!BitStream.Read(&turnSpeed)) + // Read out its position + SPositionSync position(false); + if (!BitStream.Read(&position)) return false; + m_Cache.PlrPosition = position.data.vecPosition; + + if (CVehicleManager::GetVehicleType(m_Cache.iModelID) == VEHICLE_TRAIN) + { + // Train specific data + float fRailPosition = 0.0f; + uchar ucRailTrack = 0; + bool bRailDirection = false; + float fRailSpeed = 0.0f; + if (!BitStream.Read(fRailPosition) || !BitStream.ReadBit(bRailDirection) || !BitStream.Read(ucRailTrack) || !BitStream.Read(fRailSpeed)) + { + return false; + } + m_Cache.fRailPosition = fRailPosition; + m_Cache.bRailDirection = bRailDirection; + m_Cache.ucRailTrack = ucRailTrack; + m_Cache.fRailSpeed = fRailSpeed; + } - m_Cache.VehTurnSpeed = turnSpeed.data.vecVelocity; + // Read the camera orientation + ReadCameraOrientation(position.data.vecPosition, BitStream, m_Cache.vecCamPosition, m_Cache.vecCamFwd); - // Health - SVehicleHealthSync health; - if (!BitStream.Read(&health)) + // Jax: don't allow any outdated packets through + SOccupiedSeatSync seat; + if (!BitStream.Read(&seat)) return false; - m_Cache.fVehHealth = health.data.fValue; - - // Trailer chain - bool bHasTrailer; - if (!BitStream.ReadBit(bHasTrailer)) + if (seat.data.ucSeat != m_ucPlayerGotOccupiedVehicleSeat) + { + // Mis-matching seats can happen when we warp into a different one, + // which will screw up the whole packet return false; + } - while (bHasTrailer) + // Read out the vehicle matrix only if he's the driver + const unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; + if (uiSeat == 0) { - STrailerInfo info; - BitStream.Read(info.m_TrailerID); - - // Read out the trailer position and rotation - SPositionSync trailerPosition(false); - if (!BitStream.Read(&trailerPosition)) + // Read out the vehicle rotation in degrees + SRotationDegreesSync rotation; + if (!BitStream.Read(&rotation)) return false; - SRotationDegreesSync trailerRotation; - if (!BitStream.Read(&trailerRotation)) - return false; + // Set it + m_Cache.VehPosition = position.data.vecPosition; + m_Cache.VehRotationDeg = rotation.data.vecRotation; - // If we found the trailer - if (true) - { - // Set its position and rotation - info.m_TrailerPosition = trailerPosition.data.vecPosition; - info.m_TrailerRotationDeg = trailerRotation.data.vecRotation; + // Move speed vector + SVelocitySync velocity; + if (!BitStream.Read(&velocity)) + return false; - m_Cache.TrailerList.push_back(info); - } - else - break; + m_Cache.BothVelocity = velocity.data.vecVelocity; - if (BitStream.ReadBit(bHasTrailer) == false) + // Turn speed vector + SVelocitySync turnSpeed; + if (!BitStream.Read(&turnSpeed)) return false; - } - } - // Read Damage info, but do not store, as we do not relay this info - if (BitStream.Version() >= 0x047) - { - if (BitStream.ReadBit() == true) - { - ElementID DamagerID; - if (!BitStream.Read(DamagerID)) - return false; + m_Cache.VehTurnSpeed = turnSpeed.data.vecVelocity; - SWeaponTypeSync weaponType; - if (!BitStream.Read(&weaponType)) + // Health + SVehicleHealthSync health; + if (!BitStream.Read(&health)) return false; + m_Cache.fVehHealth = health.data.fValue; - SBodypartSync bodyPart; - if (!BitStream.Read(&bodyPart)) + // Trailer chain + bool bHasTrailer; + if (!BitStream.ReadBit(bHasTrailer)) return false; + + while (bHasTrailer) + { + STrailerInfo info; + BitStream.Read(info.m_TrailerID); + + // Read out the trailer position and rotation + SPositionSync trailerPosition(false); + if (!BitStream.Read(&trailerPosition)) + return false; + + SRotationDegreesSync trailerRotation; + if (!BitStream.Read(&trailerRotation)) + return false; + + // If we found the trailer + if (true) + { + // Set its position and rotation + info.m_TrailerPosition = trailerPosition.data.vecPosition; + info.m_TrailerRotationDeg = trailerRotation.data.vecRotation; + + m_Cache.TrailerList.push_back(info); + } + else + break; + + if (BitStream.ReadBit(bHasTrailer) == false) + return false; + } } - } - // Player health - SPlayerHealthSync health; - if (!BitStream.Read(&health)) - return false; - m_Cache.fPlrHealth = health.data.fValue; + // Read Damage info, but do not store, as we do not relay this info + if (BitStream.Version() >= 0x047) + { + if (BitStream.ReadBit() == true) + { + ElementID DamagerID; + if (!BitStream.Read(DamagerID)) + return false; - // Armor - SPlayerArmorSync armor; - if (!BitStream.Read(&armor)) - return false; - m_Cache.fArmor = armor.data.fValue; + SWeaponTypeSync weaponType; + if (!BitStream.Read(&weaponType)) + return false; - // Flags - if (!BitStream.Read(&m_Cache.flags)) - return false; + SBodypartSync bodyPart; + if (!BitStream.Read(&bodyPart)) + return false; + } + } - // Weapon sync - if (m_Cache.flags.data.bHasAWeapon) - { - SWeaponSlotSync slot; - if (!BitStream.Read(&slot)) + // Player health + SPlayerHealthSync health; + if (!BitStream.Read(&health)) + return false; + m_Cache.fPlrHealth = health.data.fValue; + + // Armor + SPlayerArmorSync armor; + if (!BitStream.Read(&armor)) return false; + m_Cache.fArmor = armor.data.fValue; - m_Cache.ucWeaponSlot = slot.data.uiSlot; + // Flags + if (!BitStream.Read(&m_Cache.flags)) + return false; - if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + // Weapon sync + if (m_Cache.flags.data.bHasAWeapon) { - // Read the ammo states - SWeaponAmmoSync ammo(m_ucPlayerGotWeaponType, BitStream.Version() >= 0x44, true); - if (!BitStream.Read(&ammo)) + SWeaponSlotSync slot; + if (!BitStream.Read(&slot)) return false; - m_Cache.usAmmoInClip = ammo.data.usAmmoInClip; - m_Cache.usTotalAmmo = ammo.data.usTotalAmmo; - // Read aim data - SWeaponAimSync aim(m_fPlayerGotWeaponRange, true); - if (!BitStream.Read(&aim)) - return false; - m_Cache.fAimDirection = aim.data.fArm; - m_Cache.vecSniperSource = aim.data.vecOrigin; - m_Cache.vecTargetting = aim.data.vecTarget; + m_Cache.ucWeaponSlot = slot.data.uiSlot; - // Read the driveby direction - SDrivebyDirectionSync driveby; - if (!BitStream.Read(&driveby)) - return false; - m_Cache.ucDriveByDirection = driveby.data.ucDirection; + if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + // Read the ammo states + SWeaponAmmoSync ammo(m_ucPlayerGotWeaponType, BitStream.Version() >= 0x44, true); + if (!BitStream.Read(&ammo)) + return false; + m_Cache.usAmmoInClip = ammo.data.usAmmoInClip; + m_Cache.usTotalAmmo = ammo.data.usTotalAmmo; + + // Read aim data + SWeaponAimSync aim(m_fPlayerGotWeaponRange, true); + if (!BitStream.Read(&aim)) + return false; + m_Cache.fAimDirection = aim.data.fArm; + m_Cache.vecSniperSource = aim.data.vecOrigin; + m_Cache.vecTargetting = aim.data.vecTarget; + + // Read the driveby direction + SDrivebyDirectionSync driveby; + if (!BitStream.Read(&driveby)) + return false; + m_Cache.ucDriveByDirection = driveby.data.ucDirection; + } } - } - else - m_Cache.ucWeaponSlot = 0; + else + m_Cache.ucWeaponSlot = 0; - // Vehicle specific data if he's the driver - if (uiSeat == 0) - { - ReadVehicleSpecific(BitStream); - } + // Vehicle specific data if he's the driver + if (uiSeat == 0) + { + ReadVehicleSpecific(BitStream); + } - // Read the vehicle_look_left and vehicle_look_right control states - // if it's an aircraft. - if (m_Cache.flags.data.bIsAircraft) - { - m_sharedControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; - m_sharedControllerState.RightShoulder2 = BitStream.ReadBit() * 255; - } + // Read the vehicle_look_left and vehicle_look_right control states + // if it's an aircraft. + if (m_Cache.flags.data.bIsAircraft) + { + m_sharedControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; + m_sharedControllerState.RightShoulder2 = BitStream.ReadBit() * 255; + } - if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) - { - float vehicleNitro; - if (!BitStream.Read(vehicleNitro)) - return false; - m_Cache.VehNitroLevel = vehicleNitro; + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + float vehicleNitro; + if (!BitStream.Read(vehicleNitro)) + return false; + + m_Cache.VehNitroLevel = vehicleNitro; + } + + // Success + return true; } - // Success - return true; + return false; } // @@ -271,168 +274,170 @@ bool CSimVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) bool CSimVehiclePuresyncPacket::Write(NetBitStreamInterface& BitStream) const { // Player is in a vehicle and is the driver? - if (!m_bPlayerHasOccupiedVehicle) - return false; - - // Player ID - BitStream.Write(m_PlayerID); + if (m_bPlayerHasOccupiedVehicle) + { + // Player ID + BitStream.Write(m_PlayerID); - // Write the time context of that player - BitStream.Write(m_Cache.ucTimeContext); + // Write the time context of that player + BitStream.Write(m_Cache.ucTimeContext); - // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent - BitStream.WriteCompressed(m_usPlayerLatency); + // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent + BitStream.WriteCompressed(m_usPlayerLatency); - // Write the keysync data - WriteFullKeysync(m_sharedControllerState, BitStream); + // Write the keysync data + WriteFullKeysync(m_sharedControllerState, BitStream); - // Write the serverside model (#8800) - if (BitStream.Version() >= 0x05F) - BitStream.Write(m_Cache.iModelID); + // Write the serverside model (#8800) + if (BitStream.Version() >= 0x05F) + BitStream.Write(m_Cache.iModelID); - // Write the vehicle matrix only if he's the driver - CVector vecTemp; - unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; - if (uiSeat == 0) - { - // Vehicle position - SPositionSync position(false); - position.data.vecPosition = m_Cache.VehPosition; - BitStream.Write(&position); - - if (m_usVehicleGotModel == 449 || m_usVehicleGotModel == 537 || m_usVehicleGotModel == 538 || m_usVehicleGotModel == 570 || - m_usVehicleGotModel == 569 || m_usVehicleGotModel == 590) + // Write the vehicle matrix only if he's the driver + CVector vecTemp; + unsigned int uiSeat = m_ucPlayerGotOccupiedVehicleSeat; + if (uiSeat == 0) { - BitStream.Write(m_Cache.fRailPosition); - BitStream.WriteBit(m_Cache.bRailDirection); - BitStream.Write(m_Cache.ucRailTrack); - BitStream.Write(m_Cache.fRailSpeed); - } + // Vehicle position + SPositionSync position(false); + position.data.vecPosition = m_Cache.VehPosition; + BitStream.Write(&position); - // Vehicle rotation - SRotationDegreesSync rotation; - rotation.data.vecRotation = m_Cache.VehRotationDeg; - BitStream.Write(&rotation); + if (m_usVehicleGotModel == 449 || m_usVehicleGotModel == 537 || m_usVehicleGotModel == 538 || m_usVehicleGotModel == 570 || + m_usVehicleGotModel == 569 || m_usVehicleGotModel == 590) + { + BitStream.Write(m_Cache.fRailPosition); + BitStream.WriteBit(m_Cache.bRailDirection); + BitStream.Write(m_Cache.ucRailTrack); + BitStream.Write(m_Cache.fRailSpeed); + } - // Move speed vector - SVelocitySync velocity; - velocity.data.vecVelocity = m_Cache.BothVelocity; - BitStream.Write(&velocity); + // Vehicle rotation + SRotationDegreesSync rotation; + rotation.data.vecRotation = m_Cache.VehRotationDeg; + BitStream.Write(&rotation); - // Turn speed vector - SVelocitySync turnSpeed; - turnSpeed.data.vecVelocity = m_Cache.VehTurnSpeed; - BitStream.Write(&turnSpeed); + // Move speed vector + SVelocitySync velocity; + velocity.data.vecVelocity = m_Cache.BothVelocity; + BitStream.Write(&velocity); - // Health - SVehicleHealthSync health; - health.data.fValue = m_Cache.fVehHealth; - BitStream.Write(&health); + // Turn speed vector + SVelocitySync turnSpeed; + turnSpeed.data.vecVelocity = m_Cache.VehTurnSpeed; + BitStream.Write(&turnSpeed); - // Write trailer chain - if (BitStream.Version() >= 0x42) - { - for (std::vector::const_iterator it = m_Cache.TrailerList.begin(); it != m_Cache.TrailerList.end(); ++it) + // Health + SVehicleHealthSync health; + health.data.fValue = m_Cache.fVehHealth; + BitStream.Write(&health); + + // Write trailer chain + if (BitStream.Version() >= 0x42) { - BitStream.WriteBit(true); + for (std::vector::const_iterator it = m_Cache.TrailerList.begin(); it != m_Cache.TrailerList.end(); ++it) + { + BitStream.WriteBit(true); - BitStream.Write(it->m_TrailerID); + BitStream.Write(it->m_TrailerID); - SPositionSync trailerPosition(false); - trailerPosition.data.vecPosition = it->m_TrailerPosition; - BitStream.Write(&trailerPosition); + SPositionSync trailerPosition(false); + trailerPosition.data.vecPosition = it->m_TrailerPosition; + BitStream.Write(&trailerPosition); - SRotationDegreesSync trailerRotation; - trailerRotation.data.vecRotation = it->m_TrailerRotationDeg; - BitStream.Write(&trailerRotation); - } + SRotationDegreesSync trailerRotation; + trailerRotation.data.vecRotation = it->m_TrailerRotationDeg; + BitStream.Write(&trailerRotation); + } - BitStream.WriteBit(false); + BitStream.WriteBit(false); + } } - } - // Player health and armor - SPlayerHealthSync health; - health.data.fValue = m_Cache.fPlrHealth; - BitStream.Write(&health); + // Player health and armor + SPlayerHealthSync health; + health.data.fValue = m_Cache.fPlrHealth; + BitStream.Write(&health); - SPlayerArmorSync armor; - armor.data.fValue = m_Cache.fArmor; - BitStream.Write(&armor); + SPlayerArmorSync armor; + armor.data.fValue = m_Cache.fArmor; + BitStream.Write(&armor); - // Weapon - unsigned char ucWeaponType = m_ucPlayerGotWeaponType; + // Weapon + unsigned char ucWeaponType = m_ucPlayerGotWeaponType; - BitStream.Write(&m_Cache.flags); + BitStream.Write(&m_Cache.flags); - // Write the weapon stuff - if (m_Cache.flags.data.bHasAWeapon) - { - // Write the weapon slot - SWeaponSlotSync slot; - slot.data.uiSlot = m_Cache.ucWeaponSlot; - BitStream.Write(&slot); + // Write the weapon stuff + if (m_Cache.flags.data.bHasAWeapon) + { + // Write the weapon slot + SWeaponSlotSync slot; + slot.data.uiSlot = m_Cache.ucWeaponSlot; + BitStream.Write(&slot); - if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + if (m_Cache.flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + // Write the ammo states + SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); + ammo.data.usAmmoInClip = m_Cache.usAmmoInClip; + ammo.data.usTotalAmmo = m_Cache.usTotalAmmo; + BitStream.Write(&ammo); + + // Sync aim data + SWeaponAimSync aim(0.0f, true); + aim.data.vecOrigin = m_Cache.vecSniperSource; + aim.data.vecTarget = m_Cache.vecTargetting; + aim.data.fArm = m_Cache.fAimDirection; + BitStream.Write(&aim); + + // Sync driveby direction + SDrivebyDirectionSync driveby; + driveby.data.ucDirection = m_Cache.ucDriveByDirection; + BitStream.Write(&driveby); + } + } + + // Vehicle specific data only if he's the driver + if (uiSeat == 0) { - // Write the ammo states - SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); - ammo.data.usAmmoInClip = m_Cache.usAmmoInClip; - ammo.data.usTotalAmmo = m_Cache.usTotalAmmo; - BitStream.Write(&ammo); - - // Sync aim data - SWeaponAimSync aim(0.0f, true); - aim.data.vecOrigin = m_Cache.vecSniperSource; - aim.data.vecTarget = m_Cache.vecTargetting; - aim.data.fArm = m_Cache.fAimDirection; - BitStream.Write(&aim); - - // Sync driveby direction - SDrivebyDirectionSync driveby; - driveby.data.ucDirection = m_Cache.ucDriveByDirection; - BitStream.Write(&driveby); + WriteVehicleSpecific(BitStream); } - } - // Vehicle specific data only if he's the driver - if (uiSeat == 0) - { - WriteVehicleSpecific(BitStream); - } + // Write vehicle_look_left and vehicle_look_right control states when + // it's an aircraft. + if (m_Cache.flags.data.bIsAircraft) + { + BitStream.WriteBit(m_sharedControllerState.LeftShoulder2 != 0); + BitStream.WriteBit(m_sharedControllerState.RightShoulder2 != 0); + } - // Write vehicle_look_left and vehicle_look_right control states when - // it's an aircraft. - if (m_Cache.flags.data.bIsAircraft) - { - BitStream.WriteBit(m_sharedControllerState.LeftShoulder2 != 0); - BitStream.WriteBit(m_sharedControllerState.RightShoulder2 != 0); - } + // Write parts state + if (BitStream.Version() >= 0x5D) + { + SVehicleDamageSyncMethodeB damage; + // Check where we are in the cycle + uint uiPhase = (m_uiDamageInfoSendPhase & 3); + damage.data.bSyncDoors = (uiPhase == 0); + damage.data.bSyncWheels = (uiPhase == 1); + damage.data.bSyncPanels = (uiPhase == 2); + damage.data.bSyncLights = (uiPhase == 3); + damage.data.doors.data.ucStates = m_DamageInfo.m_ucDoorStates; + damage.data.wheels.data.ucStates = m_DamageInfo.m_ucWheelStates; + damage.data.panels.data.ucStates = m_DamageInfo.m_ucPanelStates; + damage.data.lights.data.ucStates = m_DamageInfo.m_ucLightStates; + BitStream.Write(&damage); + } - // Write parts state - if (BitStream.Version() >= 0x5D) - { - SVehicleDamageSyncMethodeB damage; - // Check where we are in the cycle - uint uiPhase = (m_uiDamageInfoSendPhase & 3); - damage.data.bSyncDoors = (uiPhase == 0); - damage.data.bSyncWheels = (uiPhase == 1); - damage.data.bSyncPanels = (uiPhase == 2); - damage.data.bSyncLights = (uiPhase == 3); - damage.data.doors.data.ucStates = m_DamageInfo.m_ucDoorStates; - damage.data.wheels.data.ucStates = m_DamageInfo.m_ucWheelStates; - damage.data.panels.data.ucStates = m_DamageInfo.m_ucPanelStates; - damage.data.lights.data.ucStates = m_DamageInfo.m_ucLightStates; - BitStream.Write(&damage); - } + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + BitStream.Write(m_Cache.VehNitroLevel); + } - if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) - { - BitStream.Write(m_Cache.VehNitroLevel); + // Success + return true; } - // Success - return true; + return false; } void CSimVehiclePuresyncPacket::ReadVehicleSpecific(NetBitStreamInterface& BitStream) diff --git a/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp b/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp index 63bf627c43..9dda43c4c1 100644 --- a/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CVehiclePuresyncPacket.cpp @@ -32,438 +32,440 @@ CVehiclePuresyncPacket::CVehiclePuresyncPacket(CPlayer* pPlayer) bool CVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) { // Got a player to read? - if (!m_pSourceElement) - return false; - - CPlayer* pSourcePlayer = static_cast(m_pSourceElement); - - // Player is in a vehicle? - CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); - if (pVehicle) - return false; - - // Read out the time context - unsigned char ucTimeContext = 0; - if (!BitStream.Read(ucTimeContext)) - return false; - - // Only read this packet if it matches the current time context that - // player is in. - if (!pSourcePlayer->CanUpdateSync(ucTimeContext)) + if (m_pSourceElement) { - return false; - } + CPlayer* pSourcePlayer = static_cast(m_pSourceElement); - // Read out the keysync data - CControllerState ControllerState; - if (!ReadFullKeysync(ControllerState, BitStream)) - return false; + // Player is in a vehicle? + CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); + if (pVehicle) + { + // Read out the time context + unsigned char ucTimeContext = 0; + if (!BitStream.Read(ucTimeContext)) + return false; - // Read out the remote model - int iModelID = pVehicle->GetModel(); - int iRemoteModelID = iModelID; + // Only read this packet if it matches the current time context that + // player is in. + if (!pSourcePlayer->CanUpdateSync(ucTimeContext)) + { + return false; + } - if (BitStream.Version() >= 0x05F) - BitStream.Read(iRemoteModelID); + // Read out the keysync data + CControllerState ControllerState; + if (!ReadFullKeysync(ControllerState, BitStream)) + return false; - eVehicleType vehicleType = pVehicle->GetVehicleType(); - eVehicleType remoteVehicleType = CVehicleManager::GetVehicleType(iRemoteModelID); + // Read out the remote model + int iModelID = pVehicle->GetModel(); + int iRemoteModelID = iModelID; - // Read out its position - SPositionSync position(false); - if (!BitStream.Read(&position)) - return false; - pSourcePlayer->SetPosition(position.data.vecPosition); + if (BitStream.Version() >= 0x05F) + BitStream.Read(iRemoteModelID); - // If the remote vehicle is a train, we want to read special train-specific data - if (remoteVehicleType == VEHICLE_TRAIN) - { - float fPosition; - bool bDirection; - CTrainTrack* pTrainTrack; - float fSpeed; - - BitStream.Read(fPosition); - BitStream.ReadBit(bDirection); - BitStream.Read(fSpeed); - - // TODO(qaisjp, feature/custom-train-tracks): this needs to be changed to an ElementID when the time is right (in a backwards compatible manner) - // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important - uchar trackIndex; - BitStream.Read(trackIndex); - pTrainTrack = g_pGame->GetTrainTrackManager()->GetTrainTrackByIndex(trackIndex); - - // But we should only actually apply that train-specific data if that vehicle is train on our side - if (vehicleType == VEHICLE_TRAIN) - { - pVehicle->SetTrainPosition(fPosition); - pVehicle->SetTrainDirection(bDirection); - pVehicle->SetTrainTrack(pTrainTrack); - pVehicle->SetTrainSpeed(fSpeed); - } - } + eVehicleType vehicleType = pVehicle->GetVehicleType(); + eVehicleType remoteVehicleType = CVehicleManager::GetVehicleType(iRemoteModelID); - // Read the camera orientation - CVector vecCamPosition, vecCamFwd; - ReadCameraOrientation(position.data.vecPosition, BitStream, vecCamPosition, vecCamFwd); - pSourcePlayer->SetCameraOrientation(vecCamPosition, vecCamFwd); + // Read out its position + SPositionSync position(false); + if (!BitStream.Read(&position)) + return false; + pSourcePlayer->SetPosition(position.data.vecPosition); - // Jax: don't allow any outdated packets through - SOccupiedSeatSync seat; - if (!BitStream.Read(&seat)) - return false; - if (seat.data.ucSeat != pSourcePlayer->GetOccupiedVehicleSeat()) - { - // Mis-matching seats can happen when we warp into a different one, - // which will screw up the whole packet - return false; - } + // If the remote vehicle is a train, we want to read special train-specific data + if (remoteVehicleType == VEHICLE_TRAIN) + { + float fPosition; + bool bDirection; + CTrainTrack* pTrainTrack; + float fSpeed; - // Read out the vehicle matrix only if he's the driver - unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); - if (uiSeat == 0) - { - // Read out the vehicle rotation in degrees - SRotationDegreesSync rotation; - if (!BitStream.Read(&rotation)) - return false; + BitStream.Read(fPosition); + BitStream.ReadBit(bDirection); + BitStream.Read(fSpeed); - // Set it - pVehicle->SetPosition(position.data.vecPosition); - pVehicle->SetRotationDegrees(rotation.data.vecRotation); + // TODO(qaisjp, feature/custom-train-tracks): this needs to be changed to an ElementID when the time is right (in a backwards compatible manner) + // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important + uchar trackIndex; + BitStream.Read(trackIndex); + pTrainTrack = g_pGame->GetTrainTrackManager()->GetTrainTrackByIndex(trackIndex); - // Move speed vector - SVelocitySync velocity; - if (!BitStream.Read(&velocity)) - return false; + // But we should only actually apply that train-specific data if that vehicle is train on our side + if (vehicleType == VEHICLE_TRAIN) + { + pVehicle->SetTrainPosition(fPosition); + pVehicle->SetTrainDirection(bDirection); + pVehicle->SetTrainTrack(pTrainTrack); + pVehicle->SetTrainSpeed(fSpeed); + } + } - pVehicle->SetVelocity(velocity.data.vecVelocity); - pSourcePlayer->SetVelocity(velocity.data.vecVelocity); + // Read the camera orientation + CVector vecCamPosition, vecCamFwd; + ReadCameraOrientation(position.data.vecPosition, BitStream, vecCamPosition, vecCamFwd); + pSourcePlayer->SetCameraOrientation(vecCamPosition, vecCamFwd); - // Turn speed vector - SVelocitySync turnSpeed; - if (!BitStream.Read(&turnSpeed)) - return false; + // Jax: don't allow any outdated packets through + SOccupiedSeatSync seat; + if (!BitStream.Read(&seat)) + return false; + if (seat.data.ucSeat != pSourcePlayer->GetOccupiedVehicleSeat()) + { + // Mis-matching seats can happen when we warp into a different one, + // which will screw up the whole packet + return false; + } - pVehicle->SetTurnSpeed(turnSpeed.data.vecVelocity); + // Read out the vehicle matrix only if he's the driver + unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); + if (uiSeat == 0) + { + // Read out the vehicle rotation in degrees + SRotationDegreesSync rotation; + if (!BitStream.Read(&rotation)) + return false; - // Health - SVehicleHealthSync health; - if (!BitStream.Read(&health)) - return false; + // Set it + pVehicle->SetPosition(position.data.vecPosition); + pVehicle->SetRotationDegrees(rotation.data.vecRotation); - float fPreviousHealth = pVehicle->GetLastSyncedHealth(); - float fHealth = health.data.fValue; + // Move speed vector + SVelocitySync velocity; + if (!BitStream.Read(&velocity)) + return false; - // Less than last time? - if (fHealth < fPreviousHealth) - { - // Grab the delta health - float fDeltaHealth = fPreviousHealth - fHealth; + pVehicle->SetVelocity(velocity.data.vecVelocity); + pSourcePlayer->SetVelocity(velocity.data.vecVelocity); - if (fDeltaHealth > 0.0f) - { - // Call the onVehicleDamage event - CLuaArguments Arguments; - Arguments.PushNumber(fDeltaHealth); - pVehicle->CallEvent("onVehicleDamage", Arguments); - } - } - pVehicle->SetHealth(fHealth); - // Stops sync + fixVehicle/setElementHealth conflicts triggering onVehicleDamage by having a separate stored float keeping track of ONLY what - // comes in via sync - // - Caz - pVehicle->SetLastSyncedHealth(fHealth); - - // Trailer chain - CVehicle* pTowedByVehicle = pVehicle; - ElementID TrailerID; - bool bHasTrailer; - if (!BitStream.ReadBit(bHasTrailer)) - return false; - - while (bHasTrailer) - { - BitStream.Read(TrailerID); - CVehicle* pTrailer = GetElementFromId(TrailerID); + // Turn speed vector + SVelocitySync turnSpeed; + if (!BitStream.Read(&turnSpeed)) + return false; - // Read out the trailer position and rotation - SPositionSync trailerPosition(false); - if (!BitStream.Read(&trailerPosition)) - return false; + pVehicle->SetTurnSpeed(turnSpeed.data.vecVelocity); - SRotationDegreesSync trailerRotation; - if (!BitStream.Read(&trailerRotation)) - return false; + // Health + SVehicleHealthSync health; + if (!BitStream.Read(&health)) + return false; - // If we found the trailer - if (pTrailer) - { - // Set its position and rotation - pTrailer->SetPosition(trailerPosition.data.vecPosition); - pTrailer->SetRotationDegrees(trailerRotation.data.vecRotation); + float fPreviousHealth = pVehicle->GetLastSyncedHealth(); + float fHealth = health.data.fValue; - // Is this a new trailer, attached? - CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); - if (pCurrentTrailer != pTrailer) + // Less than last time? + if (fHealth < fPreviousHealth) { - // If theres a trailer already attached - if (pCurrentTrailer) - { - pTowedByVehicle->SetTowedVehicle(NULL); - pCurrentTrailer->SetTowedByVehicle(NULL); + // Grab the delta health + float fDeltaHealth = fPreviousHealth - fHealth; - // Tell everyone to detach them - CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); - - // Execute the attach trailer script function + if (fDeltaHealth > 0.0f) + { + // Call the onVehicleDamage event CLuaArguments Arguments; - Arguments.PushElement(pTowedByVehicle); - pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); + Arguments.PushNumber(fDeltaHealth); + pVehicle->CallEvent("onVehicleDamage", Arguments); } + } + pVehicle->SetHealth(fHealth); + // Stops sync + fixVehicle/setElementHealth conflicts triggering onVehicleDamage by having a separate stored float keeping track of ONLY what + // comes in via sync + // - Caz + pVehicle->SetLastSyncedHealth(fHealth); + + // Trailer chain + CVehicle* pTowedByVehicle = pVehicle; + ElementID TrailerID; + bool bHasTrailer; + if (!BitStream.ReadBit(bHasTrailer)) + return false; + + while (bHasTrailer) + { + BitStream.Read(TrailerID); + CVehicle* pTrailer = GetElementFromId(TrailerID); - // If something else is towing this trailer - CVehicle* pCurrentVehicle = pTrailer->GetTowedByVehicle(); - if (pCurrentVehicle) - { - pCurrentVehicle->SetTowedVehicle(NULL); - pTrailer->SetTowedByVehicle(NULL); + // Read out the trailer position and rotation + SPositionSync trailerPosition(false); + if (!BitStream.Read(&trailerPosition)) + return false; - // Tell everyone to detach them - CVehicleTrailerPacket DetachPacket(pCurrentVehicle, pTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + SRotationDegreesSync trailerRotation; + if (!BitStream.Read(&trailerRotation)) + return false; - // Execute the attach trailer script function - CLuaArguments Arguments; - Arguments.PushElement(pCurrentVehicle); - pTrailer->CallEvent("onTrailerDetach", Arguments); + // If we found the trailer + if (pTrailer) + { + // Set its position and rotation + pTrailer->SetPosition(trailerPosition.data.vecPosition); + pTrailer->SetRotationDegrees(trailerRotation.data.vecRotation); + + // Is this a new trailer, attached? + CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); + if (pCurrentTrailer != pTrailer) + { + // If theres a trailer already attached + if (pCurrentTrailer) + { + pTowedByVehicle->SetTowedVehicle(NULL); + pCurrentTrailer->SetTowedByVehicle(NULL); + + // Tell everyone to detach them + CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + + // Execute the attach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pTowedByVehicle); + pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); + } + + // If something else is towing this trailer + CVehicle* pCurrentVehicle = pTrailer->GetTowedByVehicle(); + if (pCurrentVehicle) + { + pCurrentVehicle->SetTowedVehicle(NULL); + pTrailer->SetTowedByVehicle(NULL); + + // Tell everyone to detach them + CVehicleTrailerPacket DetachPacket(pCurrentVehicle, pTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + + // Execute the attach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pCurrentVehicle); + pTrailer->CallEvent("onTrailerDetach", Arguments); + } + + pTowedByVehicle->SetTowedVehicle(pTrailer); + pTrailer->SetTowedByVehicle(pTowedByVehicle); + + // Execute the attach trailer script function + CLuaArguments Arguments; + Arguments.PushElement(pTowedByVehicle); + bool bContinue = pTrailer->CallEvent("onTrailerAttach", Arguments); + + // Attach or detach trailers depending on the event outcome + CVehicleTrailerPacket TrailerPacket(pTowedByVehicle, pTrailer, bContinue); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(TrailerPacket); + } } + else + break; - pTowedByVehicle->SetTowedVehicle(pTrailer); - pTrailer->SetTowedByVehicle(pTowedByVehicle); + pTowedByVehicle = pTrailer; - // Execute the attach trailer script function + if (BitStream.ReadBit(bHasTrailer) == false) + return false; + } + + // If there was a trailer before + CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); + if (pCurrentTrailer) + { + pTowedByVehicle->SetTowedVehicle(NULL); + pCurrentTrailer->SetTowedByVehicle(NULL); + + // Tell everyone else to detach them + CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); + g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + + // Execute the detach trailer script function CLuaArguments Arguments; Arguments.PushElement(pTowedByVehicle); - bool bContinue = pTrailer->CallEvent("onTrailerAttach", Arguments); - - // Attach or detach trailers depending on the event outcome - CVehicleTrailerPacket TrailerPacket(pTowedByVehicle, pTrailer, bContinue); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(TrailerPacket); + pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); } } - else - break; - - pTowedByVehicle = pTrailer; - - if (BitStream.ReadBit(bHasTrailer) == false) - return false; - } - // If there was a trailer before - CVehicle* pCurrentTrailer = pTowedByVehicle->GetTowedVehicle(); - if (pCurrentTrailer) - { - pTowedByVehicle->SetTowedVehicle(NULL); - pCurrentTrailer->SetTowedByVehicle(NULL); + // Update Damage info + if (BitStream.Version() >= 0x047) + { + if (BitStream.ReadBit() == true) + { + ElementID DamagerID; + if (!BitStream.Read(DamagerID)) + return false; - // Tell everyone else to detach them - CVehicleTrailerPacket DetachPacket(pTowedByVehicle, pCurrentTrailer, false); - g_pGame->GetPlayerManager()->BroadcastOnlyJoined(DetachPacket); + SWeaponTypeSync weaponType; + if (!BitStream.Read(&weaponType)) + return false; - // Execute the detach trailer script function - CLuaArguments Arguments; - Arguments.PushElement(pTowedByVehicle); - pCurrentTrailer->CallEvent("onTrailerDetach", Arguments); - } - } + SBodypartSync bodyPart; + if (!BitStream.Read(&bodyPart)) + return false; - // Update Damage info - if (BitStream.Version() >= 0x047) - { - if (BitStream.ReadBit() == true) - { - ElementID DamagerID; - if (!BitStream.Read(DamagerID)) - return false; + pSourcePlayer->SetDamageInfo(DamagerID, weaponType.data.ucWeaponType, bodyPart.data.uiBodypart); + } + } - SWeaponTypeSync weaponType; - if (!BitStream.Read(&weaponType)) + // Player health + SPlayerHealthSync health; + if (!BitStream.Read(&health)) return false; + float fHealth = health.data.fValue; - SBodypartSync bodyPart; - if (!BitStream.Read(&bodyPart)) - return false; + float fOldHealth = pSourcePlayer->GetHealth(); + float fHealthLoss = fOldHealth - fHealth; - pSourcePlayer->SetDamageInfo(DamagerID, weaponType.data.ucWeaponType, bodyPart.data.uiBodypart); - } - } + // Less than last packet's frame? + if (fHealth < fOldHealth && fHealthLoss > 0) + { + if (BitStream.Version() <= 0x046) + { + // Call the onPlayerDamage event + CLuaArguments Arguments; + Arguments.PushNil(); + Arguments.PushNumber(false); + Arguments.PushNumber(false); + Arguments.PushNumber(fHealthLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + else + { + // Call the onPlayerDamage event + CLuaArguments Arguments; - // Player health - SPlayerHealthSync health; - if (!BitStream.Read(&health)) - return false; - float fHealth = health.data.fValue; + CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); + if (pDamageSource) + Arguments.PushElement(pDamageSource); + else + Arguments.PushNil(); + Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); + Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); + Arguments.PushNumber(fHealthLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + } + pSourcePlayer->SetHealth(fHealth); - float fOldHealth = pSourcePlayer->GetHealth(); - float fHealthLoss = fOldHealth - fHealth; + // Armor + SPlayerArmorSync armor; + if (!BitStream.Read(&armor)) + return false; + float fArmor = armor.data.fValue; - // Less than last packet's frame? - if (fHealth < fOldHealth && fHealthLoss > 0) - { - if (BitStream.Version() <= 0x046) - { - // Call the onPlayerDamage event - CLuaArguments Arguments; - Arguments.PushNil(); - Arguments.PushNumber(false); - Arguments.PushNumber(false); - Arguments.PushNumber(fHealthLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - else - { - // Call the onPlayerDamage event - CLuaArguments Arguments; + float fOldArmor = pSourcePlayer->GetArmor(); + float fArmorLoss = fOldArmor - fArmor; - CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); - if (pDamageSource) - Arguments.PushElement(pDamageSource); - else - Arguments.PushNil(); - Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); - Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); - Arguments.PushNumber(fHealthLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - } - pSourcePlayer->SetHealth(fHealth); + // Less than last packet's frame? + if (fArmor < fOldArmor && fArmorLoss > 0) + { + if (BitStream.Version() <= 0x046) + { + // Call the onPlayerDamage event + CLuaArguments Arguments; + Arguments.PushNil(); + Arguments.PushNumber(false); + Arguments.PushNumber(false); + Arguments.PushNumber(fArmorLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + else + { + // Call the onPlayerDamage event + CLuaArguments Arguments; - // Armor - SPlayerArmorSync armor; - if (!BitStream.Read(&armor)) - return false; - float fArmor = armor.data.fValue; + CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); + if (pDamageSource) + Arguments.PushElement(pDamageSource); + else + Arguments.PushNil(); + Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); + Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); + Arguments.PushNumber(fArmorLoss); + pSourcePlayer->CallEvent("onPlayerDamage", Arguments); + } + } + pSourcePlayer->SetArmor(fArmor); - float fOldArmor = pSourcePlayer->GetArmor(); - float fArmorLoss = fOldArmor - fArmor; + // Flags + SVehiclePuresyncFlags flags; + if (!BitStream.Read(&flags)) + return false; - // Less than last packet's frame? - if (fArmor < fOldArmor && fArmorLoss > 0) - { - if (BitStream.Version() <= 0x046) - { - // Call the onPlayerDamage event - CLuaArguments Arguments; - Arguments.PushNil(); - Arguments.PushNumber(false); - Arguments.PushNumber(false); - Arguments.PushNumber(fArmorLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - else - { - // Call the onPlayerDamage event - CLuaArguments Arguments; + pSourcePlayer->SetWearingGoggles(flags.data.bIsWearingGoggles); + pSourcePlayer->SetDoingGangDriveby(flags.data.bIsDoingGangDriveby); - CElement* pDamageSource = CElementIDs::GetElement(pSourcePlayer->GetPlayerAttacker()); - if (pDamageSource) - Arguments.PushElement(pDamageSource); - else - Arguments.PushNil(); - Arguments.PushNumber(pSourcePlayer->GetAttackWeapon()); - Arguments.PushNumber(pSourcePlayer->GetAttackBodyPart()); - Arguments.PushNumber(fArmorLoss); - pSourcePlayer->CallEvent("onPlayerDamage", Arguments); - } - } - pSourcePlayer->SetArmor(fArmor); + // Weapon sync + if (flags.data.bHasAWeapon) + { + SWeaponSlotSync slot; + if (!BitStream.Read(&slot)) + return false; - // Flags - SVehiclePuresyncFlags flags; - if (!BitStream.Read(&flags)) - return false; + pSourcePlayer->SetWeaponSlot(slot.data.uiSlot); - pSourcePlayer->SetWearingGoggles(flags.data.bIsWearingGoggles); - pSourcePlayer->SetDoingGangDriveby(flags.data.bIsDoingGangDriveby); + if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + float fWeaponRange = pSourcePlayer->GetWeaponRangeFromSlot(slot.data.uiSlot); + + // Read the ammo states + SWeaponAmmoSync ammo(pSourcePlayer->GetWeaponType(), BitStream.Version() >= 0x44, true); + if (!BitStream.Read(&ammo)) + return false; + pSourcePlayer->SetWeaponAmmoInClip(ammo.data.usAmmoInClip); + if (BitStream.Version() >= 0x44) + pSourcePlayer->SetWeaponTotalAmmo(ammo.data.usTotalAmmo); + + // Read aim data + SWeaponAimSync aim(fWeaponRange, true); + if (!BitStream.Read(&aim)) + return false; + pSourcePlayer->SetAimDirection(aim.data.fArm); + pSourcePlayer->SetSniperSourceVector(aim.data.vecOrigin); + pSourcePlayer->SetTargettingVector(aim.data.vecTarget); + + // Read the driveby direction + SDrivebyDirectionSync driveby; + if (!BitStream.Read(&driveby)) + return false; + pSourcePlayer->SetDriveByDirection(driveby.data.ucDirection); + } + } + else + pSourcePlayer->SetWeaponSlot(0); - // Weapon sync - if (flags.data.bHasAWeapon) - { - SWeaponSlotSync slot; - if (!BitStream.Read(&slot)) - return false; + // Vehicle specific data if he's the driver + if (uiSeat == 0) + { + ReadVehicleSpecific(pVehicle, BitStream, iRemoteModelID); + + // Set vehicle specific stuff if he's the driver + pVehicle->SetSirenActive(flags.data.bIsSirenOrAlarmActive); + pVehicle->SetSmokeTrailEnabled(flags.data.bIsSmokeTrailEnabled); + pVehicle->SetLandingGearDown(flags.data.bIsLandingGearDown); + pVehicle->SetOnGround(flags.data.bIsOnGround); + pVehicle->SetInWater(flags.data.bIsInWater); + pVehicle->SetDerailed(flags.data.bIsDerailed); + pVehicle->SetHeliSearchLightVisible(flags.data.bIsHeliSearchLightVisible); + } - pSourcePlayer->SetWeaponSlot(slot.data.uiSlot); + // Read the vehicle_look_left and vehicle_look_right control states + // if it's an aircraft. + if (flags.data.bIsAircraft) + { + ControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; + ControllerState.RightShoulder2 = BitStream.ReadBit() * 255; + } - if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - float fWeaponRange = pSourcePlayer->GetWeaponRangeFromSlot(slot.data.uiSlot); + pSourcePlayer->GetPad()->NewControllerState(ControllerState); - // Read the ammo states - SWeaponAmmoSync ammo(pSourcePlayer->GetWeaponType(), BitStream.Version() >= 0x44, true); - if (!BitStream.Read(&ammo)) - return false; - pSourcePlayer->SetWeaponAmmoInClip(ammo.data.usAmmoInClip); - if (BitStream.Version() >= 0x44) - pSourcePlayer->SetWeaponTotalAmmo(ammo.data.usTotalAmmo); + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + float vehicleNitro; + if (!BitStream.Read(vehicleNitro)) + return false; - // Read aim data - SWeaponAimSync aim(fWeaponRange, true); - if (!BitStream.Read(&aim)) - return false; - pSourcePlayer->SetAimDirection(aim.data.fArm); - pSourcePlayer->SetSniperSourceVector(aim.data.vecOrigin); - pSourcePlayer->SetTargettingVector(aim.data.vecTarget); + pVehicle->SetNitroLevel(vehicleNitro); + } - // Read the driveby direction - SDrivebyDirectionSync driveby; - if (!BitStream.Read(&driveby)) - return false; - pSourcePlayer->SetDriveByDirection(driveby.data.ucDirection); + // Success + return true; } } - else - pSourcePlayer->SetWeaponSlot(0); - - // Vehicle specific data if he's the driver - if (uiSeat == 0) - { - ReadVehicleSpecific(pVehicle, BitStream, iRemoteModelID); - - // Set vehicle specific stuff if he's the driver - pVehicle->SetSirenActive(flags.data.bIsSirenOrAlarmActive); - pVehicle->SetSmokeTrailEnabled(flags.data.bIsSmokeTrailEnabled); - pVehicle->SetLandingGearDown(flags.data.bIsLandingGearDown); - pVehicle->SetOnGround(flags.data.bIsOnGround); - pVehicle->SetInWater(flags.data.bIsInWater); - pVehicle->SetDerailed(flags.data.bIsDerailed); - pVehicle->SetHeliSearchLightVisible(flags.data.bIsHeliSearchLightVisible); - } - - // Read the vehicle_look_left and vehicle_look_right control states - // if it's an aircraft. - if (flags.data.bIsAircraft) - { - ControllerState.LeftShoulder2 = BitStream.ReadBit() * 255; - ControllerState.RightShoulder2 = BitStream.ReadBit() * 255; - } - - pSourcePlayer->GetPad()->NewControllerState(ControllerState); - - if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) - { - float vehicleNitro; - if (!BitStream.Read(vehicleNitro)) - return false; - pVehicle->SetNitroLevel(vehicleNitro); - } - - // Success - return true; + return false; } // @@ -472,226 +474,228 @@ bool CVehiclePuresyncPacket::Read(NetBitStreamInterface& BitStream) bool CVehiclePuresyncPacket::Write(NetBitStreamInterface& BitStream) const { // Got a player to send? - if (!m_pSourceElement) - return false; - - CPlayer* pSourcePlayer = static_cast(m_pSourceElement); + if (m_pSourceElement) + { + CPlayer* pSourcePlayer = static_cast(m_pSourceElement); - // Player is in a vehicle and is the driver? - CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); - if (!pVehicle) - return false; + // Player is in a vehicle and is the driver? + CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle(); + if (pVehicle) + { + // Player ID + ElementID PlayerID = pSourcePlayer->GetID(); + BitStream.Write(PlayerID); - // Player ID - ElementID PlayerID = pSourcePlayer->GetID(); - BitStream.Write(PlayerID); + // Write the time context of that player + BitStream.Write(pSourcePlayer->GetSyncTimeContext()); - // Write the time context of that player - BitStream.Write(pSourcePlayer->GetSyncTimeContext()); + // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent + unsigned short usLatency = pSourcePlayer->GetPing(); + BitStream.WriteCompressed(usLatency); - // Write his ping divided with 2 plus a small number so the client can find out when this packet was sent - unsigned short usLatency = pSourcePlayer->GetPing(); - BitStream.WriteCompressed(usLatency); + // Write the keysync data + const CControllerState& ControllerState = pSourcePlayer->GetPad()->GetCurrentControllerState(); + WriteFullKeysync(ControllerState, BitStream); - // Write the keysync data - const CControllerState& ControllerState = pSourcePlayer->GetPad()->GetCurrentControllerState(); - WriteFullKeysync(ControllerState, BitStream); + // Write the serverside model (#8800) + if (BitStream.Version() >= 0x05F) + BitStream.Write((int)pVehicle->GetModel()); - // Write the serverside model (#8800) - if (BitStream.Version() >= 0x05F) - BitStream.Write((int)pVehicle->GetModel()); + // Write the vehicle matrix only if he's the driver + CVector vecTemp; + unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); + if (uiSeat == 0) + { + // Vehicle position + SPositionSync position(false); + position.data.vecPosition = pVehicle->GetPosition(); + BitStream.Write(&position); - // Write the vehicle matrix only if he's the driver - CVector vecTemp; - unsigned int uiSeat = pSourcePlayer->GetOccupiedVehicleSeat(); - if (uiSeat == 0) - { - // Vehicle position - SPositionSync position(false); - position.data.vecPosition = pVehicle->GetPosition(); - BitStream.Write(&position); + // If the remote vehicle is a train, we want to read special train-specific data + if (pVehicle->GetVehicleType() == VEHICLE_TRAIN) + { + // Train specific data + float fPosition = pVehicle->GetTrainPosition(); + bool bDirection = pVehicle->GetTrainDirection(); + float fSpeed = pVehicle->GetTrainSpeed(); + + BitStream.Write(fPosition); + BitStream.WriteBit(bDirection); + BitStream.Write(fSpeed); + + // Push the train track information + const auto trainTrack = pVehicle->GetTrainTrack(); + if (!trainTrack || pVehicle->IsDerailed()) + { + // NOTE(qaisjp, feature/custom-train-tracks): when can a train both be on a track AND derailed? + // I suppose it's possible for some weirdness here. We should make sure that whenever we set the train track, + // we set that the train is NOT derailed; and that whenever we derail the track, we set the train track to nil. + // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important + BitStream.Write((uchar)0); + } + else if (trainTrack && trainTrack->IsDefault()) + { + BitStream.Write(trainTrack->GetDefaultTrackId()); + } + else + { + // TODO(qaisjp, feature/custom-train-tracks): implement behaviour for non-default tracks + assert(0 && "It is impossible for custom train tracks to exist right now, so this should never be reached."); + } + } - // If the remote vehicle is a train, we want to read special train-specific data - if (pVehicle->GetVehicleType() == VEHICLE_TRAIN) - { - // Train specific data - float fPosition = pVehicle->GetTrainPosition(); - bool bDirection = pVehicle->GetTrainDirection(); - float fSpeed = pVehicle->GetTrainSpeed(); - - BitStream.Write(fPosition); - BitStream.WriteBit(bDirection); - BitStream.Write(fSpeed); - - // Push the train track information - const auto trainTrack = pVehicle->GetTrainTrack(); - if (!trainTrack || pVehicle->IsDerailed()) - { - // NOTE(qaisjp, feature/custom-train-tracks): when can a train both be on a track AND derailed? - // I suppose it's possible for some weirdness here. We should make sure that whenever we set the train track, - // we set that the train is NOT derailed; and that whenever we derail the track, we set the train track to nil. - // Note: here we use a uchar, in the CTT branch this is a uint. Just don't forget that, it might be important - BitStream.Write((uchar)0); - } - else if (trainTrack && trainTrack->IsDefault()) - { - BitStream.Write(trainTrack->GetDefaultTrackId()); - } - else - { - // TODO(qaisjp, feature/custom-train-tracks): implement behaviour for non-default tracks - assert(0 && "It is impossible for custom train tracks to exist right now, so this should never be reached."); - } - } + // Vehicle rotation + SRotationDegreesSync rotation; + pVehicle->GetRotationDegrees(rotation.data.vecRotation); + BitStream.Write(&rotation); - // Vehicle rotation - SRotationDegreesSync rotation; - pVehicle->GetRotationDegrees(rotation.data.vecRotation); - BitStream.Write(&rotation); + // Move speed vector + SVelocitySync velocity; + velocity.data.vecVelocity = pVehicle->GetVelocity(); + BitStream.Write(&velocity); - // Move speed vector - SVelocitySync velocity; - velocity.data.vecVelocity = pVehicle->GetVelocity(); - BitStream.Write(&velocity); + // Turn speed vector + SVelocitySync turnSpeed; + turnSpeed.data.vecVelocity = pVehicle->GetTurnSpeed(); + BitStream.Write(&turnSpeed); - // Turn speed vector - SVelocitySync turnSpeed; - turnSpeed.data.vecVelocity = pVehicle->GetTurnSpeed(); - BitStream.Write(&turnSpeed); + // Health + SVehicleHealthSync health; + health.data.fValue = pVehicle->GetHealth(); + BitStream.Write(&health); - // Health - SVehicleHealthSync health; - health.data.fValue = pVehicle->GetHealth(); - BitStream.Write(&health); + // Write the trailer chain + if (BitStream.Version() >= 0x42) + { + CVehicle* pTrailer = pVehicle->GetTowedVehicle(); + while (pTrailer) + { + BitStream.WriteBit(true); + BitStream.Write(pTrailer->GetID()); - // Write the trailer chain - if (BitStream.Version() >= 0x42) - { - CVehicle* pTrailer = pVehicle->GetTowedVehicle(); - while (pTrailer) - { - BitStream.WriteBit(true); - BitStream.Write(pTrailer->GetID()); + // Write the position and rotation + CVector vecTrailerPosition, vecTrailerRotationDegrees; - // Write the position and rotation - CVector vecTrailerPosition, vecTrailerRotationDegrees; + // Write the matrix + vecTrailerPosition = pTrailer->GetPosition(); + pTrailer->GetRotationDegrees(vecTrailerRotationDegrees); - // Write the matrix - vecTrailerPosition = pTrailer->GetPosition(); - pTrailer->GetRotationDegrees(vecTrailerRotationDegrees); + SPositionSync trailerPosition(false); + trailerPosition.data.vecPosition = vecTrailerPosition; + BitStream.Write(&trailerPosition); - SPositionSync trailerPosition(false); - trailerPosition.data.vecPosition = vecTrailerPosition; - BitStream.Write(&trailerPosition); + SRotationDegreesSync trailerRotation; + trailerRotation.data.vecRotation = vecTrailerRotationDegrees; + BitStream.Write(&trailerRotation); - SRotationDegreesSync trailerRotation; - trailerRotation.data.vecRotation = vecTrailerRotationDegrees; - BitStream.Write(&trailerRotation); + // Get the next towed vehicle + pTrailer = pTrailer->GetTowedVehicle(); + } - // Get the next towed vehicle - pTrailer = pTrailer->GetTowedVehicle(); + // End of our trailer chain + BitStream.WriteBit(false); + } } - // End of our trailer chain - BitStream.WriteBit(false); - } - } + // Player health and armor + SPlayerHealthSync health; + health.data.fValue = pSourcePlayer->GetHealth(); + BitStream.Write(&health); + + SPlayerArmorSync armor; + armor.data.fValue = pSourcePlayer->GetArmor(); + BitStream.Write(&armor); + + // Weapon + unsigned char ucWeaponType = pSourcePlayer->GetWeaponType(); + + // Flags + SVehiclePuresyncFlags flags; + flags.data.bIsWearingGoggles = pSourcePlayer->IsWearingGoggles(); + flags.data.bIsDoingGangDriveby = pSourcePlayer->IsDoingGangDriveby(); + flags.data.bIsSirenOrAlarmActive = pVehicle->IsSirenActive(); + flags.data.bIsSmokeTrailEnabled = pVehicle->IsSmokeTrailEnabled(); + flags.data.bIsLandingGearDown = pVehicle->IsLandingGearDown(); + flags.data.bIsOnGround = pVehicle->IsOnGround(); + flags.data.bIsInWater = pVehicle->IsInWater(); + flags.data.bIsDerailed = pVehicle->IsDerailed(); + flags.data.bIsAircraft = (pVehicle->GetVehicleType() == VEHICLE_PLANE || pVehicle->GetVehicleType() == VEHICLE_HELI); + flags.data.bHasAWeapon = (ucWeaponType != 0); + flags.data.bIsHeliSearchLightVisible = pVehicle->IsHeliSearchLightVisible(); + BitStream.Write(&flags); + + // Write the weapon stuff + if (flags.data.bHasAWeapon) + { + // Write the weapon slot + SWeaponSlotSync slot; + slot.data.uiSlot = pSourcePlayer->GetWeaponSlot(); + BitStream.Write(&slot); - // Player health and armor - SPlayerHealthSync health; - health.data.fValue = pSourcePlayer->GetHealth(); - BitStream.Write(&health); - - SPlayerArmorSync armor; - armor.data.fValue = pSourcePlayer->GetArmor(); - BitStream.Write(&armor); - - // Weapon - unsigned char ucWeaponType = pSourcePlayer->GetWeaponType(); - - // Flags - SVehiclePuresyncFlags flags; - flags.data.bIsWearingGoggles = pSourcePlayer->IsWearingGoggles(); - flags.data.bIsDoingGangDriveby = pSourcePlayer->IsDoingGangDriveby(); - flags.data.bIsSirenOrAlarmActive = pVehicle->IsSirenActive(); - flags.data.bIsSmokeTrailEnabled = pVehicle->IsSmokeTrailEnabled(); - flags.data.bIsLandingGearDown = pVehicle->IsLandingGearDown(); - flags.data.bIsOnGround = pVehicle->IsOnGround(); - flags.data.bIsInWater = pVehicle->IsInWater(); - flags.data.bIsDerailed = pVehicle->IsDerailed(); - flags.data.bIsAircraft = (pVehicle->GetVehicleType() == VEHICLE_PLANE || pVehicle->GetVehicleType() == VEHICLE_HELI); - flags.data.bHasAWeapon = (ucWeaponType != 0); - flags.data.bIsHeliSearchLightVisible = pVehicle->IsHeliSearchLightVisible(); - BitStream.Write(&flags); - - // Write the weapon stuff - if (flags.data.bHasAWeapon) - { - // Write the weapon slot - SWeaponSlotSync slot; - slot.data.uiSlot = pSourcePlayer->GetWeaponSlot(); - BitStream.Write(&slot); + if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) + { + // Write the ammo states + SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); + ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip(); + ammo.data.usTotalAmmo = pSourcePlayer->GetWeaponTotalAmmo(); + BitStream.Write(&ammo); + + // Sync aim data + SWeaponAimSync aim(0.0f, true); + aim.data.vecOrigin = pSourcePlayer->GetSniperSourceVector(); + pSourcePlayer->GetTargettingVector(aim.data.vecTarget); + aim.data.fArm = pSourcePlayer->GetAimDirection(); + BitStream.Write(&aim); + + // Sync driveby direction + SDrivebyDirectionSync driveby; + driveby.data.ucDirection = pSourcePlayer->GetDriveByDirection(); + BitStream.Write(&driveby); + } + } - if (flags.data.bIsDoingGangDriveby && CWeaponNames::DoesSlotHaveAmmo(slot.data.uiSlot)) - { - // Write the ammo states - SWeaponAmmoSync ammo(ucWeaponType, BitStream.Version() >= 0x44, true); - ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip(); - ammo.data.usTotalAmmo = pSourcePlayer->GetWeaponTotalAmmo(); - BitStream.Write(&ammo); - - // Sync aim data - SWeaponAimSync aim(0.0f, true); - aim.data.vecOrigin = pSourcePlayer->GetSniperSourceVector(); - pSourcePlayer->GetTargettingVector(aim.data.vecTarget); - aim.data.fArm = pSourcePlayer->GetAimDirection(); - BitStream.Write(&aim); - - // Sync driveby direction - SDrivebyDirectionSync driveby; - driveby.data.ucDirection = pSourcePlayer->GetDriveByDirection(); - BitStream.Write(&driveby); - } - } + // Vehicle specific data only if he's the driver + if (uiSeat == 0) + { + WriteVehicleSpecific(pVehicle, BitStream); + } - // Vehicle specific data only if he's the driver - if (uiSeat == 0) - { - WriteVehicleSpecific(pVehicle, BitStream); - } + // Write vehicle_look_left and vehicle_look_right control states when + // it's an aircraft. + if (flags.data.bIsAircraft) + { + BitStream.WriteBit(ControllerState.LeftShoulder2 != 0); + BitStream.WriteBit(ControllerState.RightShoulder2 != 0); + } - // Write vehicle_look_left and vehicle_look_right control states when - // it's an aircraft. - if (flags.data.bIsAircraft) - { - BitStream.WriteBit(ControllerState.LeftShoulder2 != 0); - BitStream.WriteBit(ControllerState.RightShoulder2 != 0); - } + // Write parts state + if (BitStream.Version() >= 0x5D) + { + SVehicleDamageSyncMethodeB damage; + // Check where we are in the cycle + uchar ucMode = (pVehicle->m_uiDamageInfoSendPhase & 3); + damage.data.bSyncDoors = (ucMode == 0); + damage.data.bSyncWheels = (ucMode == 1); + damage.data.bSyncPanels = (ucMode == 2); + damage.data.bSyncLights = (ucMode == 3); + damage.data.doors.data.ucStates = pVehicle->m_ucDoorStates; + damage.data.wheels.data.ucStates = pVehicle->m_ucWheelStates; + damage.data.panels.data.ucStates = pVehicle->m_ucPanelStates; + damage.data.lights.data.ucStates = pVehicle->m_ucLightStates; + BitStream.Write(&damage); + } - // Write parts state - if (BitStream.Version() >= 0x5D) - { - SVehicleDamageSyncMethodeB damage; - // Check where we are in the cycle - uchar ucMode = (pVehicle->m_uiDamageInfoSendPhase & 3); - damage.data.bSyncDoors = (ucMode == 0); - damage.data.bSyncWheels = (ucMode == 1); - damage.data.bSyncPanels = (ucMode == 2); - damage.data.bSyncLights = (ucMode == 3); - damage.data.doors.data.ucStates = pVehicle->m_ucDoorStates; - damage.data.wheels.data.ucStates = pVehicle->m_ucWheelStates; - damage.data.panels.data.ucStates = pVehicle->m_ucPanelStates; - damage.data.lights.data.ucStates = pVehicle->m_ucLightStates; - BitStream.Write(&damage); - } + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + { + BitStream.Write(pVehicle->GetNitroLevel()); + } - if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) - { - BitStream.Write(pVehicle->GetNitroLevel()); + // Success + return true; + } } - // Success - return true; + return false; } void CVehiclePuresyncPacket::ReadVehicleSpecific(CVehicle* pVehicle, NetBitStreamInterface& BitStream, int iRemoteModel) From 6d4c779f7ffca02fc5fa0da5c8cd9b9ad4aabf1c Mon Sep 17 00:00:00 2001 From: Tracer <43095317+TracerDS@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:30:39 +0200 Subject: [PATCH 3/3] Added bitstream check --- Client/mods/deathmatch/logic/CNetAPI.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CNetAPI.cpp b/Client/mods/deathmatch/logic/CNetAPI.cpp index 82b636e963..1ce46c1267 100644 --- a/Client/mods/deathmatch/logic/CNetAPI.cpp +++ b/Client/mods/deathmatch/logic/CNetAPI.cpp @@ -1778,7 +1778,8 @@ void CNetAPI::WriteVehiclePuresync(CClientPed* pPlayerModel, CClientVehicle* pVe // Write the sent position to the interpolator AddInterpolation(vecPosition); - BitStream.Write(static_cast(pVehicle->GetNitroLevel())); + if (BitStream.Can(eBitStreamVersion::IsVehicleNitroActivated_Serverside)) + BitStream.Write(static_cast(pVehicle->GetNitroLevel())); } bool CNetAPI::ReadSmallKeysync(CControllerState& ControllerState, NetBitStreamInterface& BitStream)