void CElementRPCs::SetElementCollisionsEnabled ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { bool bEnable; if ( bitStream.ReadBit ( bEnable ) ) { switch ( pSource->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed * > ( pSource ); pPed->SetUsesCollision ( bEnable ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle * > ( pSource ); pVehicle->SetCollisionEnabled ( bEnable ); break; } case CCLIENTOBJECT: { CClientObject* pObject = static_cast < CClientObject * > ( pSource ); pObject->SetCollisionEnabled ( bEnable ); break; } } } }
void CElementRPCs::SetElementAlpha ( NetBitStreamInterface& bitStream ) { ElementID ID; unsigned char ucAlpha; if ( bitStream.Read ( ID ) && bitStream.Read ( ucAlpha ) ) { CClientEntity* pEntity = CElementIDs::GetElement ( ID ); if ( pEntity ) { switch ( pEntity->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed* > ( pEntity ); pPed->SetAlpha ( ucAlpha ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle* > ( pEntity ); pVehicle->SetAlpha ( ucAlpha ); break; } case CCLIENTOBJECT: { CClientObject * pObject = static_cast < CClientObject* > ( pEntity ); pObject->SetAlpha ( ucAlpha ); break; } default: break; } } } }
void CElementRPCs::SetElementFrozen ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { bool bFrozen; if ( bitStream.ReadBit ( bFrozen ) ) { switch ( pSource->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed * > ( pSource ); pPed->SetFrozen ( bFrozen ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle * > ( pSource ); pVehicle->SetFrozen ( bFrozen ); break; } case CCLIENTOBJECT: { CClientObject* pObject = static_cast < CClientObject * > ( pSource ); pObject->SetStatic ( bFrozen ); break; } } } }
void CElementRPCs::SetElementAlpha ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { unsigned char ucAlpha; if ( bitStream.Read ( ucAlpha ) ) { switch ( pSource->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed* > ( pSource ); pPed->SetAlpha ( ucAlpha ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle* > ( pSource ); pVehicle->SetAlpha ( ucAlpha ); break; } case CCLIENTOBJECT: case CCLIENTWEAPON: { CClientObject * pObject = static_cast < CClientObject* > ( pSource ); pObject->SetAlpha ( ucAlpha ); break; } default: break; } } }
void CClientObjectManager::DoPulse ( void ) { UpdateLimitInfo (); // Loop through all our streamed-in objects for ( uint i = 0 ; i < m_StreamedIn.size () ; i++ ) { CClientObject* pObject = m_StreamedIn[i]; // We should have a game-object here assert ( pObject->GetGameObject () ); pObject->StreamedInPulse (); } }
void CElementRPCs::SetElementVelocity ( NetBitStreamInterface& bitStream ) { // Read out the entity id and the speed ElementID ID; CVector vecVelocity; if ( bitStream.Read ( ID ) && bitStream.Read ( vecVelocity.fX ) && bitStream.Read ( vecVelocity.fY ) && bitStream.Read ( vecVelocity.fZ ) ) { // Grab the entity CClientEntity* pEntity = CElementIDs::GetElement ( ID ); if ( pEntity ) { switch ( pEntity->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed* > ( pEntity ); pPed->SetMoveSpeed ( vecVelocity ); pPed->ResetInterpolation (); // If local player, reset return position (so we can't warp back if connection fails) if ( pPed->IsLocalPlayer () ) { m_pClientGame->GetNetAPI ()->ResetReturnPosition (); } break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle* > ( pEntity ); pVehicle->SetMoveSpeed ( vecVelocity ); break; } case CCLIENTOBJECT: { CClientObject * pObject = static_cast < CClientObject * > ( pEntity ); pObject->SetMoveSpeed ( vecVelocity ); break; } } } } }
void CClientObjectManager::DoPulse ( void ) { UpdateLimitInfo (); CClientObject * pObject = NULL; // Loop through all our streamed-in objects vector < CClientObject * > ::iterator iter = m_StreamedIn.begin (); for ( ; iter != m_StreamedIn.end () ; ++iter ) { pObject = *iter; // We should have a game-object here assert ( pObject->GetGameObject () ); pObject->StreamedInPulse (); } }
void CClientObjectManager::RestreamObjects ( unsigned short usModel ) { for ( uint i = 0 ; i < m_Objects.size() ; i++ ) { CClientObject* pObject = m_Objects[i]; // Streamed in and same model ID? if ( pObject->IsStreamedIn () && pObject->GetModel () == usModel ) { // Stream it out for a while until streamed decides to stream it // back in eventually pObject->StreamOutForABit (); } } }
void CObjectRespawner::DoRespawnAll() { for (uint i = 0; i < m_List.size(); i++) { CClientObject* pObject = m_List[i]; // Only recreate if we're still valid and streamed in if (pObject && !pObject->IsBeingDeleted() && pObject->IsStreamedIn()) { pObject->ReCreate(); pObject->SetBeingRespawned(false); } } m_List.clear(); }
void CElementRPCs::SetLowLodElement ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { ElementID LowLodObjectID; if ( bitStream.Read ( LowLodObjectID ) ) { switch ( pSource->GetType () ) { case CCLIENTOBJECT: { CClientObject* pLowLodObject = DynamicCast < CClientObject > ( CElementIDs::GetElement ( LowLodObjectID ) ); CClientObject* pObject = static_cast < CClientObject * > ( pSource ); pObject->SetLowLodObject ( pLowLodObject ); break; } } } }
void CClientObjectManager::RestreamObjects ( unsigned short usModel ) { // Store the affected vehicles CClientObject* pObject; std::list < CClientObject* > ::const_iterator iter = IterBegin (); for ( ; iter != IterEnd (); iter++ ) { pObject = *iter; // Streamed in and same vehicle ID? if ( pObject->IsStreamedIn () && pObject->GetModel () == usModel ) { // Stream it out for a while until streamed decides to stream it // back in eventually pObject->StreamOutForABit (); } } }
bool CClientObjectManager::ObjectsAroundPointLoaded ( const CVector& vecPosition, float fRadius, unsigned short usDimension, SString* pstrStatus ) { // Get list of objects that may be intersecting the sphere CClientEntityResult result; GetClientSpatialDatabase()->SphereQuery ( result, CSphere ( vecPosition, fRadius ) ); bool bResult = true; // Extract relevant types for ( CClientEntityResult::const_iterator it = result.begin () ; it != result.end (); ++it ) { CClientEntity* pEntity = *it; if ( pEntity->GetType () == CCLIENTOBJECT ) { CClientObject* pObject = static_cast < CClientObject* > ( pEntity ); if ( !pObject->GetGameObject () || !pObject->GetModelInfo ()->IsLoaded () || !pObject->IsStreamedIn () ) { if ( pObject->GetDimension () == usDimension ) { // Final distance check float fDistSquared = pObject->GetDistanceToBoundingBoxSquared ( vecPosition ); if ( fDistSquared < fRadius * fRadius ) bResult = false; if ( pstrStatus ) { // Debugging information *pstrStatus += SString ( "ID:%05d Dist:%4.1f GetGameObject:%d IsLoaded:%d IsStreamedIn:%d\n" ,pObject->GetModel () ,sqrtf ( fDistSquared ) ,pObject->GetGameObject () ? 1 : 0 ,pObject->GetModelInfo ()->IsLoaded () ? 1 : 0 ,pObject->IsStreamedIn () ? 1 : 0 ); } else if ( !bResult ) break; } } } } return bResult; }
void CElementRPCs::SetElementHealth ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { float fHealth; unsigned char ucTimeContext; if ( bitStream.Read ( fHealth ) && bitStream.Read ( ucTimeContext ) ) { pSource->SetSyncTimeContext ( ucTimeContext ); switch ( pSource->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed * > ( pSource ); if ( pPed->IsHealthLocked() ) pPed->LockHealth ( fHealth ); else pPed->SetHealth ( fHealth ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle * > ( pSource ); pVehicle->SetHealth ( fHealth ); break; } case CCLIENTOBJECT: case CCLIENTWEAPON: { CClientObject* pObject = static_cast < CClientObject * > ( pSource ); pObject->SetHealth ( fHealth ); break; } } } }
void CElementRPCs::SetElementModel ( CClientEntity* pSource, NetBitStreamInterface& bitStream ) { unsigned short usModel; if ( bitStream.Read ( usModel ) ) { switch ( pSource->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed * > ( pSource ); pPed->SetModel ( usModel ); break; } case CCLIENTVEHICLE: { uchar ucVariant = 255, ucVariant2 = 255; if ( bitStream.GetNumberOfUnreadBits () >= sizeof ( ucVariant ) + sizeof ( ucVariant2 ) ) { bitStream.Read ( ucVariant ); bitStream.Read ( ucVariant2 ); } CClientVehicle* pVehicle = static_cast < CClientVehicle * > ( pSource ); pVehicle->SetModelBlocking ( usModel, ucVariant, ucVariant2 ); break; } case CCLIENTOBJECT: case CCLIENTWEAPON: { CClientObject* pObject = static_cast < CClientObject * > ( pSource ); pObject->SetModel ( usModel ); break; } } } }
void CElementRPCs::SetElementModel ( NetBitStreamInterface& bitStream ) { ElementID ID; unsigned short usModel; if ( bitStream.Read ( ID ) && bitStream.Read ( usModel ) ) { CClientEntity * pEntity = CElementIDs::GetElement ( ID ); if ( pEntity ) { switch ( pEntity->GetType () ) { case CCLIENTPED: case CCLIENTPLAYER: { CClientPed* pPed = static_cast < CClientPed * > ( pEntity ); pPed->SetModel ( usModel ); break; } case CCLIENTVEHICLE: { CClientVehicle* pVehicle = static_cast < CClientVehicle * > ( pEntity ); pVehicle->SetModelBlocking ( usModel ); break; } case CCLIENTOBJECT: { CClientObject* pObject = static_cast < CClientObject * > ( pEntity ); pObject->SetModel ( usModel ); break; } } } } }
void CClientStreamer::Restream ( bool bMovedFar ) { // Limit distance stream in/out rate // Vehicles might have to ignore this to reduce blocking loads elsewhere. int iMaxOut = 6; int iMaxIn = 6; if ( bMovedFar ) { iMaxOut = 1000; iMaxIn = 1000; } // Do we have any elements waiting to be streamed out? while ( !m_ToStreamOut.empty () ) { CClientStreamElement* pElement = m_ToStreamOut.front (); // Make sure we have no stream-references if ( pElement->GetTotalStreamReferences () == 0 ) { // Stream out 1 of them per frame pElement->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pElement ); if ( iMaxOut <= 0 ) break; } static std::vector < CClientStreamElement* > ClosestStreamedOutList; static std::vector < CClientStreamElement* > FurthestStreamedInList; ClosestStreamedOutList.clear(); FurthestStreamedInList.clear(); bool bReachedLimit = ReachedLimit (); // Loop through our active elements list (they should be ordered closest to furthest) list < CClientStreamElement* > ::iterator iter = m_ActiveElements.begin (); for ( ; iter != m_ActiveElements.end (); iter++ ) { CClientStreamElement* pElement = *iter; float fElementDistanceExp = pElement->GetExpDistance (); // Is this element streamed in? if ( pElement->IsStreamedIn () ) { if ( IS_VEHICLE ( pElement ) ) { CClientVehicle* pVehicle = DynamicCast < CClientVehicle > ( pElement ); if ( pVehicle ) { if ( pVehicle->GetOccupant ( ) && IS_PLAYER ( pVehicle->GetOccupant ( ) ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pVehicle->GetOccupant ( ) ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he shouldn't be streamed in m_ToStreamOut.push_back ( pElement ); } } // Is this a trailer? if ( pVehicle->GetTowedByVehicle ( ) != NULL ) { // Don't stream it out (this is handled by the towing vehicle) continue; } } } if ( IS_PLAYER ( pElement ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pElement ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't/shouldn't be streamed in m_ToStreamOut.push_back ( pElement ); } } // Too far away? Use the threshold so we won't flicker load it if it's on the border moving. if ( fElementDistanceExp > m_fMaxDistanceThreshold ) { // Unstream it now? if ( iMaxOut > 0 ) { // Make sure we have no stream-references if ( pElement->GetTotalStreamReferences () == 0 ) { // Stream out now pElement->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pElement ); } else { // or later m_ToStreamOut.push_back ( pElement ); } } else { FurthestStreamedInList.push_back( pElement ); } } else { // Same dimension as us? if ( pElement->GetDimension () == m_usDimension ) { // Too far away? Stop here. if ( fElementDistanceExp > m_fMaxDistanceExp ) continue; if ( IS_VEHICLE ( pElement ) ) { CClientVehicle* pVehicle = DynamicCast < CClientVehicle > ( pElement ); if ( pVehicle && pVehicle->GetOccupant ( ) && IS_PLAYER ( pVehicle->GetOccupant ( ) )) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pVehicle->GetOccupant ( ) ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't streaming in soon. continue; } } if ( pVehicle && pVehicle->GetTowedByVehicle ( ) ) { // Streaming in of towed vehicles is done in CClientVehicle::StreamIn by the towing vehicle continue; } } if ( IS_PLAYER ( pElement ) ) { CClientPlayer* pPlayer = DynamicCast < CClientPlayer > ( pElement ); if ( pPlayer->GetLastPuresyncType ( ) == PURESYNC_TYPE_LIGHTSYNC ) { // if the last packet was ls he isn't streaming in soon. continue; } } // If attached and attached-to is streamed out, don't consider for streaming in CClientStreamElement* pAttachedTo = DynamicCast< CClientStreamElement >( pElement->GetAttachedTo() ); if ( pAttachedTo && !pAttachedTo->IsStreamedIn() ) { // ...unless attached to low LOD version CClientObject* pAttachedToObject = DynamicCast < CClientObject > ( pAttachedTo ); CClientObject* pObject = DynamicCast < CClientObject > ( pElement ); if ( !pObject || !pAttachedToObject || pObject->IsLowLod () == pAttachedToObject->IsLowLod () ) continue; } // Not room to stream in more elements? if ( bReachedLimit ) { // Add to the list that might be streamed in during the final phase if ( (int)ClosestStreamedOutList.size() < iMaxIn ) // (only add if there is a chance it will be used) ClosestStreamedOutList.push_back( pElement ); } else { // Stream in the new element. Don't do it instantly unless moved from far away. pElement->InternalStreamIn ( bMovedFar ); bReachedLimit = ReachedLimit (); if ( !bReachedLimit ) { iMaxIn--; if ( iMaxIn <= 0 ) break; } } } } } // Complex code of doom: // ClosestStreamedOutList is {nearest to furthest} list of streamed out elements within streaming distance // FurthestStreamedInList is {nearest to furthest} list of streamed in elements if ( bReachedLimit ) { // Check 'furthest streamed in' against 'closest streamed out' to see if the state can be swapped int iFurthestStreamedInIndex = FurthestStreamedInList.size() - 1; uint uiClosestStreamedOutIndex = 0; for( uint i = 0 ; i < 10 ; i++ ) { // Check limits for this frame if ( iMaxIn <= 0 || iMaxOut <= 0 ) break; // Check indicies are valid if ( iFurthestStreamedInIndex < 0 ) break; if ( uiClosestStreamedOutIndex >= ClosestStreamedOutList.size() ) break; // See if ClosestStreamedOut is nearer than FurthestStreamedIn CClientStreamElement* pFurthestStreamedIn = FurthestStreamedInList[ iFurthestStreamedInIndex ]; CClientStreamElement* pClosestStreamedOut = ClosestStreamedOutList[ uiClosestStreamedOutIndex ]; if ( pClosestStreamedOut->GetExpDistance () >= pFurthestStreamedIn->GetExpDistance () ) break; // Stream out FurthestStreamedIn candidate if possible if ( pFurthestStreamedIn->GetTotalStreamReferences () == 0 ) { // Stream out now pFurthestStreamedIn->InternalStreamOut (); iMaxOut--; } m_ToStreamOut.remove ( pFurthestStreamedIn ); iFurthestStreamedInIndex--; // Always advance to the next candidate // Stream in ClosestStreamedOut candidate if possible if ( !ReachedLimit () ) { // Stream in the new element. No need to do it instantly unless moved from far away. pClosestStreamedOut->InternalStreamIn ( bMovedFar ); iMaxIn--; uiClosestStreamedOutIndex++; } } } }