bool CLightsyncPacket::Write(NetBitStreamInterface& BitStream) const { bool bSyncPosition; if (Count() == 0) return false; for (std::vector<CPlayer*>::const_iterator iter = m_players.begin(); iter != m_players.end(); ++iter) { CPlayer* pPlayer = *iter; CPlayer::SLightweightSyncData& data = pPlayer->GetLightweightSyncData(); CVehicle* pVehicle = pPlayer->GetOccupiedVehicle(); // Find the difference between now and the time the position last changed for the player long long llTicksDifference = GetTickCount64_() - pPlayer->GetPositionLastChanged(); // Right we need to sync the position if there is no vehicle or he's in a vehicle and the difference between setPosition is less than or equal to the // slow sync rate i.e. make sure his position has been updated more than 0.001f in the last 1500ms plus a small margin for error (probably not needed). // This will ensure we only send positions when the position has changed. bSyncPosition = (!pVehicle || pPlayer->GetOccupiedVehicleSeat() == 0) && llTicksDifference <= g_TickRateSettings.iLightSync + 100; BitStream.Write(pPlayer->GetID()); BitStream.Write((unsigned char)pPlayer->GetSyncTimeContext()); unsigned short usLatency = pPlayer->GetPing(); BitStream.WriteCompressed(usLatency); BitStream.WriteBit(data.health.bSync); if (data.health.bSync) { SPlayerHealthSync health; health.data.fValue = pPlayer->GetHealth(); BitStream.Write(&health); SPlayerArmorSync armor; armor.data.fValue = pPlayer->GetArmor(); BitStream.Write(&armor); } BitStream.WriteBit(bSyncPosition); if (bSyncPosition) { SLowPrecisionPositionSync pos; pos.data.vecPosition = pPlayer->GetPosition(); BitStream.Write(&pos); bool bSyncVehicleHealth = data.vehicleHealth.bSync && pVehicle; BitStream.WriteBit(bSyncVehicleHealth); if (bSyncVehicleHealth) { SLowPrecisionVehicleHealthSync health; health.data.fValue = pVehicle->GetHealth(); BitStream.Write(&health); } } } return true; }
// getVehicleHealth(vehicleid) int CVehicleModuleNatives::GetHealth(EntityId vehicleid) { if(g_pVehicleManager->DoesExist(vehicleid)) { CVehicle * pVehicle = g_pVehicleManager->GetAt(vehicleid); if(pVehicle) { return pVehicle->GetHealth(); } } return -1; }
void CLocalPlayer::SendInCarFullSyncData() { if(m_pPlayerPed) { RakNet::BitStream bsVehicleSync; VEHICLE_SYNC_DATA vehicleSyncData; MATRIX4X4 matVehicle; CVehicleManager * pVehicleManager = pNetowkManager->GetVehicleManager(); CVehicle * pGameVehicle = NULL; // write packet id bsVehicleSync.Write((MessageID)ID_VEHICLE_SYNC); vehicleSyncData.vehicleID = pVehicleManager->FindIDFromGtaPtr(m_pPlayerPed->GetGtaVehicle()); // make sure we have a valid vehicle if(vehicleSyncData.vehicleID == INVALID_ENTITY_ID) { return; } // get the player keys vehicleSyncData.wKeys = m_pPlayerPed->GetKeys(); // get the vehicle pointer pGameVehicle = pVehicleManager->GetAt(vehicleSyncData.vehicleID); // make sure the vehicle pointer is valid if(!pGameVehicle) { return; } // get the vehicle matrix pGameVehicle->GetMatrix(&matVehicle); // copy the roll and direction vectors memcpy(&vehicleSyncData.vecRoll, &matVehicle.vLookRight, sizeof(Vector3)); memcpy(&vehicleSyncData.vecDirection, &matVehicle.vLookUp, sizeof(Vector3)); // pack the roll and direction vectors //CompressVector1(&matVehicle.vLookRight, &vehicleSyncData.cvecRoll); //CompressVector1(&matVehicle.vLookUp, &vehicleSyncData.cvecDirection); // copy the vehicle position memcpy(&vehicleSyncData.vecPos, &matVehicle.vPos, sizeof(Vector3)); // get the vehicle move speed pGameVehicle->GetMoveSpeed(&vehicleSyncData.vecMoveSpeed); // get the vehicle turn speed pGameVehicle->GetTurnSpeed(&vehicleSyncData.vecTurnSpeed); // pack the vehicle health vehicleSyncData.byteVehicleHealth = PACK_VEHICLE_HEALTH(pGameVehicle->GetHealth()); // get the player health (casted to a byte to save space) vehicleSyncData.bytePlayerHealth = (BYTE)m_pPlayerPed->GetHealth(); // get the player armour (casted to a byte to save space) vehicleSyncData.bytePlayerArmour = (BYTE)m_pPlayerPed->GetArmour(); // write vehicle sync struct to bit stream bsVehicleSync.Write((char *)&vehicleSyncData, sizeof(VEHICLE_SYNC_DATA)); // send sync data pNetowkManager->GetRakPeer()->Send(&bsVehicleSync,HIGH_PRIORITY,UNRELIABLE_SEQUENCED,0,UNASSIGNED_SYSTEM_ADDRESS,TRUE); } }
void CLightsyncManager::DoPulse () { // The point of this method is to get all players that should receive right now the lightweight // sync from all the other players. To make this efficient, we are using a queue in what the // players at the front have are more inminent to receive this sync. As all players have the same // far sync rate, just taking the players from the front, processing them and pushing them to the // back will keep the order of priority to be processed. // // We also want to perform delta sync on stuff like the health, but it would require to know the last // value synced from every player to every player, because we are getting players from the front and // sending them all the other players data. This would be crazily inefficient and would require a lot // of mainteinance, so we will leave special entries in the queue to mark in what moment a player // health changed. This way, we will force the health sync for that player until the queue cycle // reaches that special entry again. As there might be multiple changes in a complete queue cycle, we // are also storing the delta context in what it happened, so we only consider the health unchanged // when we find the marker with the same context value. if ( g_pBandwidthSettings->bLightSyncEnabled == false ) return; // For counting stats long iPacketsSent = 0; long iBitsSent = 0; // For limiting light sync processing long iLimitCounter = Max < uint > ( 10, g_pGame->GetPlayerManager ()->Count () / 25 ); int iLightsyncRate = g_TickRateSettings.iLightSync; long long llTickCountNow = GetTickCount64_ (); while ( m_Queue.size() > 0 && m_Queue.front().ullTime + iLightsyncRate <= llTickCountNow && iLimitCounter > 0 ) { SEntry entry = m_Queue.front (); m_Queue.pop_front (); CPlayer* pPlayer = entry.pPlayer; CPlayer::SLightweightSyncData& data = pPlayer->GetLightweightSyncData (); switch ( entry.eType ) { case SYNC_PLAYER: { CLightsyncPacket packet; // Use this players far list const SViewerMapType& farList = pPlayer->GetFarPlayerList (); // For each far player for ( SViewerMapType ::const_iterator it = farList.begin (); it != farList.end (); ++it ) { CPlayer* pCurrent = it->first; dassert ( pPlayer != pCurrent ); // Only send if he isn't network troubled. if ( pCurrent->UhOhNetworkTrouble ( ) == false ) { CPlayer::SLightweightSyncData& currentData = pCurrent->GetLightweightSyncData (); packet.AddPlayer ( pCurrent ); // Calculate the delta sync if ( fabs(currentData.health.fLastHealth - pCurrent->GetHealth()) > LIGHTSYNC_HEALTH_THRESHOLD || fabs(currentData.health.fLastArmor - pCurrent->GetArmor()) > LIGHTSYNC_HEALTH_THRESHOLD ) { currentData.health.fLastHealth = pCurrent->GetHealth (); currentData.health.fLastArmor = pCurrent->GetArmor (); currentData.health.bSync = true; currentData.health.uiContext++; // Generate the health marker SEntry marker; marker.ullTime = 0; marker.pPlayer = pCurrent; marker.eType = DELTA_MARKER_HEALTH; marker.uiContext = currentData.health.uiContext; m_Queue.push_back ( marker ); } CVehicle* pVehicle = pCurrent->GetOccupiedVehicle (); if ( pVehicle && pCurrent->GetOccupiedVehicleSeat() == 0 ) { if ( currentData.vehicleHealth.lastVehicle != pVehicle || fabs(currentData.vehicleHealth.fLastHealth - pVehicle->GetHealth ()) > LIGHTSYNC_VEHICLE_HEALTH_THRESHOLD ) { currentData.vehicleHealth.fLastHealth = pVehicle->GetHealth (); currentData.vehicleHealth.lastVehicle = pVehicle; currentData.vehicleHealth.bSync = true; currentData.vehicleHealth.uiContext++; // Generate the vehicle health marker SEntry marker; marker.ullTime = 0; marker.pPlayer = pCurrent; marker.eType = DELTA_MARKER_VEHICLE_HEALTH; marker.uiContext = currentData.vehicleHealth.uiContext; m_Queue.push_back ( marker ); } } if ( packet.Count () == LIGHTSYNC_MAX_PLAYERS ) { iBitsSent += pPlayer->Send ( packet ); iPacketsSent++; packet.Reset (); } } } if ( packet.Count () > 0 ) { iBitsSent += pPlayer->Send ( packet ); iPacketsSent++; } RegisterPlayer ( pPlayer ); iLimitCounter--; break; } case DELTA_MARKER_HEALTH: { if ( data.health.uiContext == entry.uiContext ) data.health.bSync = false; break; } case DELTA_MARKER_VEHICLE_HEALTH: { if ( data.vehicleHealth.uiContext == entry.uiContext ) data.vehicleHealth.bSync = false; break; } } } // Update stats g_pStats->lightsync.llLightSyncPacketsSent += iPacketsSent; g_pStats->lightsync.llLightSyncBytesSent += iBitsSent / 8; // Subtract lightsync usage from skipped accumulators g_pStats->lightsync.llSyncPacketsSkipped -= iPacketsSent; g_pStats->lightsync.llSyncBytesSkipped -= iBitsSent / 8; }
bool CVehiclePuresyncPacket::Write ( NetBitStreamInterface& BitStream ) const { // Got a player to send? if ( m_pSourceElement ) { CPlayer * pSourcePlayer = static_cast < CPlayer * > ( m_pSourceElement ); // Player is in a vehicle and is the driver? CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle (); if ( pVehicle ) { // Player ID ElementID PlayerID = pSourcePlayer->GetID (); BitStream.Write ( PlayerID ); // 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 the keysync data CControllerState ControllerState = pSourcePlayer->GetPad ()->GetCurrentControllerState (); WriteFullKeysync ( ControllerState, BitStream ); // 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 ); // 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 ); // Turn speed vector SVelocitySync turnSpeed; turnSpeed.data.vecVelocity = pVehicle->GetTurnSpeed (); BitStream.Write ( &turnSpeed ); // Health SVehicleHealthSync health; health.data.fValue = pVehicle->GetHealth (); BitStream.Write ( &health ); } // 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, false, true ); ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip (); 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 ); } // 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; } } return false; }
bool CVehiclePuresyncPacket::Read ( NetBitStreamInterface& BitStream ) { // Got a player to read? if ( m_pSourceElement ) { CPlayer * pSourcePlayer = static_cast < CPlayer * > ( m_pSourceElement ); // 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; // Only read this packet if it matches the current time context that // player is in. if ( !pSourcePlayer->CanUpdateSync ( ucTimeContext ) ) { return false; } // Read out the keysync data CControllerState ControllerState; if ( !ReadFullKeysync ( ControllerState, BitStream ) ) return false; // 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 unsigned char ucSeat; if ( !BitStream.Read ( ucSeat ) ) return false; if ( 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; // Set it pVehicle->SetPosition ( position.data.vecPosition ); pVehicle->SetRotationDegrees ( rotation.data.vecRotation ); // Move speed vector SVelocitySync velocity; if ( !BitStream.Read ( &velocity ) ) return false; pVehicle->SetVelocity ( velocity.data.vecVelocity ); pSourcePlayer->SetVelocity ( velocity.data.vecVelocity ); // Turn speed vector SVelocitySync turnSpeed; if ( !BitStream.Read ( &turnSpeed ) ) return false; pVehicle->SetTurnSpeed ( turnSpeed.data.vecVelocity ); // Health SVehicleHealthSync health; if ( !BitStream.Read ( &health ) ) return false; float fPreviousHealth = pVehicle->GetHealth (); float fHealth = health.data.fValue; // 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 ); // Trailer chain CVehicle* pTowedByVehicle = pVehicle; CVehicle* pTrailer = NULL; ElementID TrailerID; bool bHasTrailer; if ( !BitStream.ReadBit ( bHasTrailer ) ) return false; while ( bHasTrailer ) { BitStream.ReadCompressed ( TrailerID ); CElement* pElement = CElementIDs::GetElement ( TrailerID ); if ( pElement ) pTrailer = static_cast < CVehicle* > ( pElement ); // 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 ( 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 AttachPacket ( pTowedByVehicle, pCurrentTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // 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 AttachPacket ( pCurrentVehicle, pTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // 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 = 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 ); // Tell everyone else to detach them CVehicleTrailerPacket AttachPacket ( pTowedByVehicle, pCurrentTrailer, false ); g_pGame->GetPlayerManager ()->BroadcastOnlyJoined ( AttachPacket ); // Execute the detach trailer script function CLuaArguments Arguments; Arguments.PushElement ( pTowedByVehicle ); pCurrentTrailer->CallEvent ( "onTrailerDetach", Arguments ); } } // Player health SPlayerHealthSync health; if ( !BitStream.Read ( &health ) ) return false; float fHealth = health.data.fValue; float fOldHealth = pSourcePlayer->GetHealth (); float fHealthLoss = fOldHealth - fHealth; // Less than last packet's frame? if ( fHealth < fOldHealth && fHealthLoss > 0 ) { // Call the onPlayerDamage event CLuaArguments Arguments; Arguments.PushNil (); Arguments.PushNumber ( false ); Arguments.PushNumber ( false ); Arguments.PushNumber ( fHealthLoss ); pSourcePlayer->CallEvent ( "onPlayerDamage", Arguments ); } pSourcePlayer->SetHealth ( fHealth ); // Armor SPlayerArmorSync armor; if ( !BitStream.Read ( &armor ) ) return false; float fArmor = armor.data.fValue; float fOldArmor = pSourcePlayer->GetArmor (); float fArmorLoss = fOldArmor - fArmor; // Less than last packet's frame? if ( fArmor < fOldArmor && fArmorLoss > 0 ) { // Call the onPlayerDamage event CLuaArguments Arguments; Arguments.PushNil (); Arguments.PushNumber ( false ); Arguments.PushNumber ( false ); Arguments.PushNumber ( fArmorLoss ); pSourcePlayer->CallEvent ( "onPlayerDamage", Arguments ); } pSourcePlayer->SetArmor ( fArmor ); // Flags SVehiclePuresyncFlags flags; if ( !BitStream.Read ( &flags ) ) return false; 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 ) ) { // Read the ammo states SWeaponAmmoSync ammo ( pSourcePlayer->GetWeaponType (), false, true ); if ( !BitStream.Read ( &ammo ) ) return false; pSourcePlayer->SetWeaponAmmoInClip ( ammo.data.usAmmoInClip ); // Read aim data SWeaponAimSync aim ( pSourcePlayer->GetWeaponRange (), 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 ); // Vehicle specific data if he's the driver if ( uiSeat == 0 ) { ReadVehicleSpecific ( pVehicle, BitStream ); // 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 ); // Success return true; } } return false; }
bool CEntityAddPacket::Write ( NetBitStreamInterface& BitStream ) const { SPositionSync position ( false ); // Check that we have any entities if ( m_Entities.size () > 0 ) { // Write the number of entities unsigned int NumElements = m_Entities.size (); BitStream.WriteCompressed ( NumElements ); // For each entity ... CVector vecTemp; vector < CElement* > ::const_iterator iter = m_Entities.begin (); for ( ; iter != m_Entities.end (); iter++ ) { // Entity id CElement* pElement = *iter; BitStream.Write ( pElement->GetID () ); // Entity type id unsigned char ucEntityTypeID = static_cast < unsigned char > ( pElement->GetType () ); BitStream.Write ( ucEntityTypeID ); // Entity parent CElement* pParent = pElement->GetParentEntity (); ElementID ParentID = INVALID_ELEMENT_ID; if ( pParent ) ParentID = pParent->GetID (); BitStream.Write ( ParentID ); // Entity interior BitStream.Write ( pElement->GetInterior () ); // Entity dimension BitStream.WriteCompressed ( pElement->GetDimension () ); // Entity attached to CElement* pElementAttachedTo = pElement->GetAttachedToElement (); if ( pElementAttachedTo ) { BitStream.WriteBit ( true ); BitStream.Write ( pElementAttachedTo->GetID () ); // Attached position and rotation SPositionSync attachedPosition ( false ); SRotationDegreesSync attachedRotation ( false ); pElement->GetAttachedOffsets ( attachedPosition.data.vecPosition, attachedRotation.data.vecRotation ); BitStream.Write ( &attachedPosition ); BitStream.Write ( &attachedRotation ); } else BitStream.WriteBit ( false ); // Entity collisions enabled bool bCollisionsEnabled = true; switch ( pElement->GetType() ) { case CElement::VEHICLE: { CVehicle* pVehicle = static_cast < CVehicle* > ( pElement ); bCollisionsEnabled = pVehicle->GetCollisionEnabled ( ); break; } case CElement::OBJECT: { CObject* pObject = static_cast < CObject* > ( pElement ); bCollisionsEnabled = pObject->GetCollisionEnabled ( ); break; } case CElement::PED: case CElement::PLAYER: { CPed* pPed = static_cast < CPed* > ( pElement ); bCollisionsEnabled = pPed->GetCollisionEnabled ( ); break; } } BitStream.WriteBit ( bCollisionsEnabled ); // Write custom data CCustomData* pCustomData = pElement->GetCustomDataPointer (); assert ( pCustomData ); BitStream.WriteCompressed ( pCustomData->CountOnlySynchronized () ); map < string, SCustomData > :: const_iterator iter = pCustomData->IterBegin (); for ( ; iter != pCustomData->IterEnd (); iter++ ) { const char* szName = iter->first.c_str (); const CLuaArgument* pArgument = &iter->second.Variable; bool bSynchronized = iter->second.bSynchronized; if ( bSynchronized ) { unsigned char ucNameLength = static_cast < unsigned char > ( strlen ( szName ) ); BitStream.Write ( ucNameLength ); BitStream.Write ( szName, ucNameLength ); pArgument->WriteToBitStream ( BitStream ); } } // Grab its name char szEmpty [1]; szEmpty [0] = 0; const char* szName = pElement->GetName ().c_str (); if ( !szName ) szName = szEmpty; // Write the name. It can be empty. unsigned short usNameLength = static_cast < unsigned short > ( strlen ( szName ) ); BitStream.WriteCompressed ( usNameLength ); if ( usNameLength > 0 ) { BitStream.Write ( const_cast < char * > ( szName ), usNameLength ); } // Write the sync time context BitStream.Write ( pElement->GetSyncTimeContext () ); // Write the rest depending on the type switch ( ucEntityTypeID ) { case CElement::OBJECT: { CObject* pObject = static_cast < CObject* > ( pElement ); // Position position.data.vecPosition = pObject->GetPosition (); BitStream.Write ( &position ); // Rotation SRotationRadiansSync rotationRadians ( false ); pObject->GetRotation ( rotationRadians.data.vecRotation ); BitStream.Write ( &rotationRadians ); // Object id BitStream.WriteCompressed ( pObject->GetModel () ); // Alpha SEntityAlphaSync alpha; alpha.data.ucAlpha = pObject->GetAlpha (); BitStream.Write ( &alpha ); // Double sided bool bIsDoubleSided = pObject->IsDoubleSided (); BitStream.WriteBit ( bIsDoubleSided ); // Moving const CPositionRotationAnimation* pMoveAnimation = pObject->GetMoveAnimation (); if ( pMoveAnimation ) { BitStream.WriteBit ( true ); pMoveAnimation->ToBitStream ( BitStream, true ); } else { BitStream.WriteBit ( false ); } // Scale float fScale = pObject->GetScale (); BitStream.Write ( fScale ); // Static bool bStatic = pObject->IsStatic (); BitStream.WriteBit ( bStatic ); // Health SObjectHealthSync health; health.data.fValue = pObject->GetHealth (); BitStream.Write ( &health ); break; } case CElement::PICKUP: { CPickup* pPickup = static_cast < CPickup* > ( pElement ); // Position position.data.vecPosition = pPickup->GetPosition (); BitStream.Write ( &position ); // Grab the model and write it unsigned short usModel = pPickup->GetModel (); BitStream.WriteCompressed ( usModel ); // Write if it's visible bool bVisible = pPickup->IsVisible (); BitStream.WriteBit ( bVisible ); // Write the type SPickupTypeSync pickupType; pickupType.data.ucType = pPickup->GetPickupType (); BitStream.Write ( &pickupType ); switch ( pPickup->GetPickupType () ) { case CPickup::ARMOR: { SPlayerArmorSync armor; armor.data.fValue = pPickup->GetAmount (); BitStream.Write ( &armor ); break; } case CPickup::HEALTH: { SPlayerHealthSync health; health.data.fValue = pPickup->GetAmount (); BitStream.Write ( &health ); break; } case CPickup::WEAPON: { SWeaponTypeSync weaponType; weaponType.data.ucWeaponType = pPickup->GetWeaponType (); BitStream.Write ( &weaponType ); SWeaponAmmoSync ammo ( weaponType.data.ucWeaponType, true, false ); ammo.data.usTotalAmmo = pPickup->GetAmmo (); BitStream.Write ( &ammo ); break; } default: break; } break; } case CElement::VEHICLE: { CVehicle* pVehicle = static_cast < CVehicle* > ( pElement ); // Write the vehicle position and rotation position.data.vecPosition = pVehicle->GetPosition (); SRotationDegreesSync rotationDegrees ( false ); pVehicle->GetRotationDegrees ( rotationDegrees.data.vecRotation ); // Write it BitStream.Write ( &position ); BitStream.Write ( &rotationDegrees ); // Vehicle id as a char // I'm assuming the "-400" is for adjustment so that all car values can // fit into a char? Why doesn't someone document this? // // --slush BitStream.Write ( static_cast < unsigned char > ( pVehicle->GetModel () - 400 ) ); // Health SVehicleHealthSync health; health.data.fValue = pVehicle->GetHealth (); BitStream.Write ( &health ); // Color CVehicleColor& vehColor = pVehicle->GetColor (); uchar ucNumColors = vehColor.GetNumColorsUsed () - 1; BitStream.WriteBits ( &ucNumColors, 2 ); for ( uint i = 0 ; i <= ucNumColors ; i++ ) { SColor RGBColor = vehColor.GetRGBColor ( i ); BitStream.Write ( RGBColor.R ); BitStream.Write ( RGBColor.G ); BitStream.Write ( RGBColor.B ); } // Paintjob SPaintjobSync paintjob; paintjob.data.ucPaintjob = pVehicle->GetPaintjob (); BitStream.Write ( &paintjob ); // Write the damage model SVehicleDamageSync damage ( true, true, true, true, false ); memcpy ( damage.data.ucDoorStates, pVehicle->m_ucDoorStates, MAX_DOORS ); memcpy ( damage.data.ucWheelStates, pVehicle->m_ucWheelStates, MAX_WHEELS ); memcpy ( damage.data.ucPanelStates, pVehicle->m_ucPanelStates, MAX_PANELS ); memcpy ( damage.data.ucLightStates, pVehicle->m_ucLightStates, MAX_LIGHTS ); BitStream.Write ( &damage ); // If the vehicle has a turret, send its position too unsigned short usModel = pVehicle->GetModel (); if ( CVehicleManager::HasTurret ( usModel ) ) { SVehicleTurretSync specific; specific.data.fTurretX = pVehicle->GetTurretPositionX (); specific.data.fTurretY = pVehicle->GetTurretPositionY (); BitStream.Write ( &specific ); } // If the vehicle has an adjustable property send its value if ( CVehicleManager::HasAdjustableProperty ( usModel ) ) { BitStream.WriteCompressed ( pVehicle->GetAdjustableProperty () ); } // If the vehicle has doors, sync their open angle ratios. if ( CVehicleManager::HasDoors ( usModel ) ) { SDoorOpenRatioSync door; for ( unsigned char i = 0; i < 6; ++i ) { door.data.fRatio = pVehicle->GetDoorOpenRatio ( i ); BitStream.Write ( &door ); } } // Write all the upgrades CVehicleUpgrades* pUpgrades = pVehicle->GetUpgrades (); unsigned char ucNumUpgrades = pUpgrades->Count (); unsigned short* usSlotStates = pUpgrades->GetSlotStates (); BitStream.Write ( ucNumUpgrades ); if ( ucNumUpgrades > 0 ) { unsigned char ucSlot = 0; for ( ; ucSlot < VEHICLE_UPGRADE_SLOTS ; ucSlot++ ) { unsigned short usUpgrade = usSlotStates [ ucSlot ]; /* * This is another retarded modification in an attempt to save * a byte. We're apparently subtracting 1000 so we can store the * information in a single byte instead of two. This only gives us * a maximum of 256 vehicle slots. * * --slush * -- ChrML: Ehm, GTA only has 17 upgrade slots... This is a valid optimization. */ if ( usUpgrade ) BitStream.Write ( static_cast < unsigned char > ( usSlotStates [ ucSlot ] - 1000 ) ); } } // Get the vehicle's reg plate as 8 bytes of chars with the not used bytes // nulled. const char* cszRegPlate = pVehicle->GetRegPlate (); BitStream.Write ( cszRegPlate, 8 ); // Light override SOverrideLightsSync overrideLights; overrideLights.data.ucOverride = pVehicle->GetOverrideLights (); BitStream.Write ( &overrideLights ); // Grab various vehicle flags BitStream.WriteBit ( pVehicle->IsLandingGearDown () ); BitStream.WriteBit ( pVehicle->IsSirenActive () ); BitStream.WriteBit ( pVehicle->IsFuelTankExplodable () ); BitStream.WriteBit ( pVehicle->IsEngineOn () ); BitStream.WriteBit ( pVehicle->IsLocked () ); BitStream.WriteBit ( pVehicle->AreDoorsUndamageable () ); BitStream.WriteBit ( pVehicle->IsDamageProof () ); BitStream.WriteBit ( pVehicle->IsFrozen () ); BitStream.WriteBit ( pVehicle->IsDerailed () ); BitStream.WriteBit ( pVehicle->IsDerailable () ); BitStream.WriteBit ( pVehicle->GetTrainDirection () ); BitStream.WriteBit ( pVehicle->IsTaxiLightOn () ); // Write alpha SEntityAlphaSync alpha; alpha.data.ucAlpha = pVehicle->GetAlpha (); BitStream.Write ( &alpha ); // Write headlight color SColor color = pVehicle->GetHeadLightColor (); if ( color.R != 255 || color.G != 255 || color.B != 255 ) { BitStream.WriteBit ( true ); BitStream.Write ( color.R ); BitStream.Write ( color.G ); BitStream.Write ( color.B ); } else BitStream.WriteBit ( false ); // Write handling if ( g_pGame->GetHandlingManager()->HasModelHandlingChanged ( static_cast < eVehicleTypes > ( pVehicle->GetModel() ) ) || pVehicle->HasHandlingChanged() ) { BitStream.WriteBit ( true ); SVehicleHandlingSync handling; CHandlingEntry* pEntry = pVehicle->GetHandlingData (); handling.data.fMass = pEntry->GetMass (); handling.data.fTurnMass = pEntry->GetTurnMass (); handling.data.fDragCoeff = pEntry->GetDragCoeff (); handling.data.vecCenterOfMass = pEntry->GetCenterOfMass (); handling.data.ucPercentSubmerged = pEntry->GetPercentSubmerged (); handling.data.fTractionMultiplier = pEntry->GetTractionMultiplier (); handling.data.ucDriveType = pEntry->GetCarDriveType (); handling.data.ucEngineType = pEntry->GetCarEngineType (); handling.data.ucNumberOfGears = pEntry->GetNumberOfGears (); handling.data.fEngineAcceleration = pEntry->GetEngineAcceleration (); handling.data.fEngineInertia = pEntry->GetEngineInertia (); handling.data.fMaxVelocity = pEntry->GetMaxVelocity (); handling.data.fBrakeDeceleration = pEntry->GetBrakeDeceleration (); handling.data.fBrakeBias = pEntry->GetBrakeBias (); handling.data.bABS = pEntry->GetABS (); handling.data.fSteeringLock = pEntry->GetSteeringLock (); handling.data.fTractionLoss = pEntry->GetTractionLoss (); handling.data.fTractionBias = pEntry->GetTractionBias (); handling.data.fSuspensionForceLevel = pEntry->GetSuspensionForceLevel (); handling.data.fSuspensionDamping = pEntry->GetSuspensionDamping (); handling.data.fSuspensionHighSpdDamping = pEntry->GetSuspensionHighSpeedDamping (); handling.data.fSuspensionUpperLimit = pEntry->GetSuspensionUpperLimit (); handling.data.fSuspensionLowerLimit = pEntry->GetSuspensionLowerLimit (); handling.data.fSuspensionFrontRearBias = pEntry->GetSuspensionFrontRearBias (); handling.data.fSuspensionAntiDiveMultiplier = pEntry->GetSuspensionAntiDiveMultiplier (); handling.data.fCollisionDamageMultiplier = pEntry->GetCollisionDamageMultiplier (); handling.data.uiModelFlags = pEntry->GetModelFlags (); handling.data.uiHandlingFlags = pEntry->GetHandlingFlags (); handling.data.fSeatOffsetDistance = pEntry->GetSeatOffsetDistance (); //handling.data.uiMonetary = pEntry->GetMonetary (); //handling.data.ucHeadLight = pEntry->GetHeadLight (); //handling.data.ucTailLight = pEntry->GetTailLight (); handling.data.ucAnimGroup = pEntry->GetAnimGroup (); BitStream.Write ( &handling ); } else BitStream.WriteBit ( false ); break; } case CElement::MARKER: { CMarker* pMarker = static_cast < CMarker* > ( pElement ); // Position position.data.vecPosition = pMarker->GetPosition (); BitStream.Write ( &position ); // Type SMarkerTypeSync markerType; markerType.data.ucType = pMarker->GetMarkerType (); BitStream.Write ( &markerType ); // Size float fSize = pMarker->GetSize (); BitStream.Write ( fSize ); // Colour SColorSync color; color = pMarker->GetColor (); BitStream.Write ( &color ); // Write the target position vector eventually if ( markerType.data.ucType == CMarker::TYPE_CHECKPOINT || markerType.data.ucType == CMarker::TYPE_RING ) { if ( pMarker->HasTarget () ) { BitStream.WriteBit ( true ); position.data.vecPosition = pMarker->GetTarget (); BitStream.Write ( &position ); } else BitStream.WriteBit ( false ); } break; } case CElement::BLIP: { CBlip* pBlip = static_cast < CBlip* > ( pElement ); // Grab the blip position position.data.vecPosition = pBlip->GetPosition (); BitStream.Write ( &position ); // Write the ordering id BitStream.WriteCompressed ( pBlip->m_sOrdering ); // Write the visible distance SIntegerSync < unsigned short, 14 > visibleDistance ( pBlip->m_usVisibleDistance ); BitStream.Write ( &visibleDistance ); // Write the icon SIntegerSync < unsigned char, 6 > icon ( pBlip->m_ucIcon ); BitStream.Write ( &icon ); if ( pBlip->m_ucIcon == 0 ) { // Write the size SIntegerSync < unsigned char, 5 > size ( pBlip->m_ucSize ); BitStream.Write ( &size ); // Write the color SColorSync color; color = pBlip->GetColor (); BitStream.Write ( &color ); } break; } case CElement::RADAR_AREA: { CRadarArea* pArea = static_cast < CRadarArea* > ( pElement ); // Write the position SPosition2DSync position2D ( false ); position2D.data.vecPosition = pArea->GetPosition (); BitStream.Write ( &position2D ); // Write the size SPosition2DSync size2D ( false ); size2D.data.vecPosition = pArea->GetSize (); BitStream.Write ( &size2D ); // And the color SColor color = pArea->GetColor (); BitStream.Write ( color.R ); BitStream.Write ( color.G ); BitStream.Write ( color.B ); BitStream.Write ( color.A ); // Write whether it is flashing bool bIsFlashing = pArea->IsFlashing (); BitStream.WriteBit ( bIsFlashing ); break; } case CElement::WORLD_MESH: { /* CWorldMesh* pMesh = static_cast < CWorldMesh* > ( pElement ); // Write the name char* szName = pMesh->GetName (); unsigned short usNameLength = static_cast < unsigned short > ( strlen ( szName ) ); BitStream.Write ( usNameLength ); BitStream.Write ( szName, static_cast < int > ( usNameLength ) ); // Write the position and rotation CVector vecTemp = pMesh->GetPosition (); BitStream.Write ( vecTemp.fX ); BitStream.Write ( vecTemp.fY ); BitStream.Write ( vecTemp.fZ ); vecTemp = pMesh->GetRotation (); BitStream.Write ( vecTemp.fX ); BitStream.Write ( vecTemp.fY ); BitStream.Write ( vecTemp.fZ ); */ break; } case CElement::TEAM: { CTeam* pTeam = static_cast < CTeam* > ( pElement ); // Write the name char* szTeamName = pTeam->GetTeamName (); unsigned short usNameLength = static_cast < unsigned short > ( strlen ( szTeamName ) ); unsigned char ucRed, ucGreen, ucBlue; pTeam->GetColor ( ucRed, ucGreen, ucBlue ); bool bFriendlyFire = pTeam->GetFriendlyFire (); BitStream.WriteCompressed ( usNameLength ); BitStream.Write ( szTeamName, usNameLength ); BitStream.Write ( ucRed ); BitStream.Write ( ucGreen ); BitStream.Write ( ucBlue ); BitStream.WriteBit ( bFriendlyFire ); break; } case CElement::PED: { CPed* pPed = static_cast < CPed* > ( pElement ); // position position.data.vecPosition = pPed->GetPosition (); BitStream.Write ( &position ); // model unsigned short usModel = pPed->GetModel (); BitStream.WriteCompressed ( usModel ); // rotation SPedRotationSync pedRotation; pedRotation.data.fRotation = pPed->GetRotation (); BitStream.Write ( &pedRotation ); // health SPlayerHealthSync health; health.data.fValue = pPed->GetHealth (); BitStream.Write ( &health ); // Armor SPlayerArmorSync armor; armor.data.fValue = pPed->GetArmor (); BitStream.Write ( &armor ); // vehicle CVehicle * pVehicle = pPed->GetOccupiedVehicle (); if ( pVehicle ) { BitStream.WriteBit ( true ); BitStream.Write ( pVehicle->GetID () ); SOccupiedSeatSync seat; seat.data.ucSeat = pPed->GetOccupiedVehicleSeat (); BitStream.Write ( &seat ); } else BitStream.WriteBit ( false ); // flags BitStream.WriteBit ( pPed->HasJetPack () ); BitStream.WriteBit ( pPed->IsSyncable () ); BitStream.WriteBit ( pPed->IsHeadless () ); BitStream.WriteBit ( pPed->IsFrozen () ); // alpha SEntityAlphaSync alpha; alpha.data.ucAlpha = pPed->GetAlpha (); BitStream.Write ( &alpha ); // clothes unsigned char ucNumClothes = 0; CPlayerClothes* pClothes = pPed->GetClothes ( ); for ( unsigned char ucType = 0 ; ucType < PLAYER_CLOTHING_SLOTS ; ucType++ ) { SPlayerClothing* pClothing = pClothes->GetClothing ( ucType ); if ( pClothing ) { ucNumClothes++; } } BitStream.Write ( ucNumClothes ); for ( unsigned char ucType = 0 ; ucType < PLAYER_CLOTHING_SLOTS ; ucType++ ) { SPlayerClothing* pClothing = pClothes->GetClothing ( ucType ); if ( pClothing ) { unsigned char ucTextureLength = strlen ( pClothing->szTexture ); unsigned char ucModelLength = strlen ( pClothing->szModel ); BitStream.Write ( ucTextureLength ); BitStream.Write ( pClothing->szTexture, ucTextureLength ); BitStream.Write ( ucModelLength ); BitStream.Write ( pClothing->szModel, ucModelLength ); BitStream.Write ( ucType ); } } break; } case CElement::DUMMY: { CDummy* pDummy = static_cast < CDummy* > ( pElement ); // Type Name const char* szTypeName = pDummy->GetTypeName ().c_str (); unsigned short usTypeNameLength = static_cast < unsigned short > ( strlen ( szTypeName ) ); BitStream.WriteCompressed ( usTypeNameLength ); BitStream.Write ( const_cast < char* > ( szTypeName ), usTypeNameLength ); // Position position.data.vecPosition = pDummy->GetPosition(); if ( position.data.vecPosition != CVector ( 0.0f, 0.0f, 0.0f ) ) { BitStream.WriteBit ( true ); BitStream.Write ( &position ); } else BitStream.WriteBit ( false ); break; } case CElement::PLAYER: { break; } case CElement::SCRIPTFILE: { // No extra data break; } case CElement::COLSHAPE: { CColShape* pColShape = static_cast < CColShape* > ( pElement ); if ( !pColShape->GetParentEntity () ) { // Jax: i'm pretty sure this is f*****g up our packet somehow.. // all valid col-shapes should have a parent! assert ( false ); } // Type SColshapeTypeSync colType; colType.data.ucType = static_cast < unsigned char > ( pColShape->GetShapeType () ); BitStream.Write ( &colType ); // Position position.data.vecPosition = pColShape->GetPosition (); BitStream.Write ( &position ); // Enabled BitStream.WriteBit ( pColShape->IsEnabled () ); // Auto Call Event BitStream.WriteBit ( pColShape->GetAutoCallEvent () ); switch ( pColShape->GetShapeType () ) { case COLSHAPE_CIRCLE: { BitStream.Write ( static_cast < CColCircle* > ( pColShape )->GetRadius () ); break; } case COLSHAPE_CUBOID: { SPositionSync size ( false ); size.data.vecPosition = static_cast < CColCuboid* > ( pColShape )->GetSize (); BitStream.Write ( &size ); break; } case COLSHAPE_SPHERE: { BitStream.Write ( static_cast < CColSphere* > ( pColShape )->GetRadius () ); break; } case COLSHAPE_RECTANGLE: { SPosition2DSync size ( false ); size.data.vecPosition = static_cast < CColRectangle* > ( pColShape )->GetSize (); BitStream.Write ( &size ); break; } case COLSHAPE_TUBE: { BitStream.Write ( static_cast < CColTube* > ( pColShape )->GetRadius () ); BitStream.Write ( static_cast < CColTube* > ( pColShape )->GetHeight () ); break; } case COLSHAPE_POLYGON: { CColPolygon* pPolygon = static_cast < CColPolygon* > ( pColShape ); BitStream.WriteCompressed ( pPolygon->CountPoints() ); std::vector < CVector2D > ::const_iterator iter = pPolygon->IterBegin(); for ( ; iter != pPolygon->IterEnd () ; iter++ ) { SPosition2DSync vertex ( false ); vertex.data.vecPosition = *iter; BitStream.Write ( &vertex ); } break; } default: break; } break; } case CElement::WATER: { CWater* pWater = static_cast < CWater* > ( pElement ); unsigned char ucNumVertices = (unsigned char)pWater->GetNumVertices (); BitStream.Write ( ucNumVertices ); CVector vecVertex; for ( int i = 0; i < ucNumVertices; i++ ) { pWater->GetVertex ( i, vecVertex ); BitStream.Write ( (short)vecVertex.fX ); BitStream.Write ( (short)vecVertex.fY ); BitStream.Write ( vecVertex.fZ ); } break; } default: { assert ( 0 ); CLogger::LogPrintf ( "not sending this element - id: %i\n", pElement->GetType () ); } } } // Success return true; } return false; }
void CVehiclePool::Process() { BYTE x=0; CVehicle *pVehicle; DWORD dwThisTime = GetTickCount(); while(x != MAX_VEHICLES) { if(GetSlotState(x) == TRUE) { // It's inuse. pVehicle = m_pVehicles[x]; if(m_bIsActive[x]) { if(pVehicle->GetHealth() == 0.0f) { // It's dead SetForRespawn(x); } else if(pVehicle->HasExceededWorldBoundries( pNetGame->m_WorldBounds[0],pNetGame->m_WorldBounds[1], pNetGame->m_WorldBounds[2],pNetGame->m_WorldBounds[3])) { if(pVehicle->IsOkToRespawn()) { SetForRespawn(x); } } else if(pVehicle->GetVehicleSubtype() != VEHICLE_SUBTYPE_BOAT && pVehicle->GetVehicleSubtype() != VEHICLE_SUBTYPE_PLANE && pVehicle->HasSunk()) // Not boat and has sunk. { SetForRespawn(x); } else { if(pVehicle->IsDriverLocalPlayer()) { pVehicle->SetInvulnerable(FALSE); } else { pVehicle->SetInvulnerable(TRUE); } // Lock vehicles beyond given radius. if(pVehicle->GetDistanceFromLocalPlayerPed() > 300.0f) { pVehicle->SetLockedState(1); } else { pVehicle->SetLockedState(0); } if(pVehicle->GetVehicleSubtype() == VEHICLE_SUBTYPE_BIKE) { pVehicle->VerifyControlState(); } // code to respawn vehicle after it has been idle for 4 minutes pVehicle->UpdateLastDrivenTime(); if(pVehicle->m_bHasBeenDriven) { if((dwThisTime - pVehicle->m_dwTimeSinceLastDriven) > 250000) { SetForRespawn(x); } } } } else // !m_bIsActive { if(m_iRespawnDelay[x] != 0) { m_iRespawnDelay[x]--; } else { if(pVehicle->IsOkToRespawn()) { Spawn(x,m_SpawnInfo[x].byteVehicleType,&m_SpawnInfo[x].vecPos, m_SpawnInfo[x].fRotation,m_SpawnInfo[x].iColor1,m_SpawnInfo[x].iColor2); } } } } x++; } }
void CVehiclePool::Process() { // Process all vehicles in the vehicle pool. CVehicle *pVehicle; DWORD dwThisTime = GetTickCount(); CPlayerPool* pPlayerPool = pNetGame->GetPlayerPool(); CLocalPlayer* pLocalPlayer = pPlayerPool->GetLocalPlayer(); int iLocalPlayersInRange = 0; if (pLocalPlayer) iLocalPlayersInRange = pLocalPlayer->DetermineNumberOfPlayersInLocalRange(); ProcessWaitingList(); for(VEHICLEID x = 0; x != MAX_VEHICLES; x++) { if(GetSlotState(x) == TRUE) { // It's in use. pVehicle = m_pVehicles[x]; if(m_bIsActive[x]) { if(pVehicle->IsDriverLocalPlayer()) { pVehicle->SetInvulnerable(FALSE); } else { pVehicle->SetInvulnerable(TRUE); } if (pVehicle->GetHealth() == 0.0f) // || pVehicle->IsWrecked()) // It's dead { if (pLocalPlayer->m_LastVehicle == x) // Notify server of death { NotifyVehicleDeath(x); } continue; } if( pVehicle->GetVehicleSubtype() != VEHICLE_SUBTYPE_BOAT && pVehicle->HasSunk() ) // Not boat and has sunk. { if (pLocalPlayer->m_LastVehicle == x) { NotifyVehicleDeath(x); } continue; } // Active and in world. pLocalPlayer->ProcessUndrivenSync(x, pVehicle, iLocalPlayersInRange); // sync unoccupied vehicle if needed /* This has an impact on undriven passenger sync. check for driver instead // Kye: This the source of the audio bug? if(!pVehicle->IsOccupied()) { pVehicle->SetEngineState(FALSE); } else { pVehicle->SetEngineState(TRUE); }*/ // Update the actual ingame pointer if it's not the same as the one we have listed. if(pVehicle->m_pVehicle != m_pGTAVehicles[x]) { m_pGTAVehicles[x] = pVehicle->m_pVehicle; } pVehicle->ProcessMarkers(); } } } }