bool CMapInfoPacket::Write ( NetBitStreamInterface& BitStream ) const { // Write the map weather BitStream.Write ( m_ucWeather ); BitStream.Write ( m_ucWeatherBlendingTo ); BitStream.Write ( m_ucBlendedWeatherHour ); BitStream.WriteBit ( m_bHasSkyGradient ); if ( m_bHasSkyGradient ) { BitStream.Write ( m_ucSkyGradientTR ); BitStream.Write ( m_ucSkyGradientTG ); BitStream.Write ( m_ucSkyGradientTB ); BitStream.Write ( m_ucSkyGradientBR ); BitStream.Write ( m_ucSkyGradientBG ); BitStream.Write ( m_ucSkyGradientBB ); } // Write the map hour BitStream.Write ( m_ucClockHour ); BitStream.Write ( m_ucClockMin ); BitStream.WriteCompressed ( m_ulMinuteDuration ); // Write the map flags SMapInfoFlagsSync flags; flags.data.bShowNametags = m_bShowNametags; flags.data.bShowRadar = m_bShowRadar; flags.data.bCloudsEnabled = m_bCloudsEnabled; BitStream.Write ( &flags ); // Write any other world conditions BitStream.Write ( m_fGravity ); if ( m_fGameSpeed == 1.0f ) BitStream.WriteBit ( true ); else { BitStream.WriteBit ( false ); BitStream.Write ( m_fGameSpeed ); } BitStream.Write ( m_fWaveHeight ); BitStream.Write ( m_fWaterLevel ); BitStream.WriteCompressed ( m_usFPSLimit ); // Write the garage states for ( unsigned char i = 0 ; i < MAX_GARAGES ; i++ ) { BitStream.WriteBit( static_cast < unsigned char > ( m_pbGarageStates[i] ) ); } // Write the fun bugs state SFunBugsStateSync funBugs; funBugs.data.bQuickReload = g_pGame->IsGlitchEnabled ( CGame::GLITCH_QUICKRELOAD ); funBugs.data.bFastFire = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTFIRE ); funBugs.data.bFastMove = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTMOVE ); BitStream.Write ( &funBugs ); return true; }
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; }
void CPositionRotationAnimation::ToBitStream( NetBitStreamInterface& a_rBitStream, bool a_bResumeMode ) const { a_rBitStream.WriteBit ( a_bResumeMode ); if ( a_bResumeMode ) { unsigned long ulNow = _GetTime (); unsigned long ulElaspedTime = ulNow - m_ulStartTime; unsigned long ulTimeLeft = 0; if ( m_ulEndTime > ulNow ) { ulTimeLeft = m_ulEndTime - ulNow; } a_rBitStream.WriteCompressed ( ulElaspedTime ); a_rBitStream.WriteCompressed ( ulTimeLeft ); } else { a_rBitStream.WriteCompressed ( m_ulDuration ); } SPositionSync positionSync; positionSync.data.vecPosition = m_SourceValue.m_vecPosition; a_rBitStream.Write ( &positionSync ); SRotationRadiansSync rotationSync ( true ); //RPC function used floats when join time packet didn't, let's go for float rotationSync.data.vecRotation = m_SourceValue.m_vecRotation; a_rBitStream.Write ( &rotationSync ); positionSync.data.vecPosition = m_TargetValue.m_vecPosition; a_rBitStream.Write ( &positionSync ); a_rBitStream.WriteBit ( m_bDeltaRotationMode ); if ( m_bDeltaRotationMode ) { rotationSync.data.vecRotation = m_DeltaValue.m_vecRotation; //We serialize DELTA } else { rotationSync.data.vecRotation = m_TargetValue.m_vecRotation; } a_rBitStream.Write ( &rotationSync ); ////We write the string directly to allow new types without changing netcode (since integer values of enum might change) a_rBitStream.WriteString ( CEasingCurve::GetStringFromEasingType( m_easingCurve.GetType() ) ); double fEasingPeriod, fEasingAmplitude, fEasingOvershoot; m_easingCurve.GetParams ( fEasingPeriod, fEasingAmplitude, fEasingOvershoot ); a_rBitStream.Write ( fEasingPeriod ); a_rBitStream.Write ( fEasingAmplitude ); a_rBitStream.Write ( fEasingOvershoot ); }
/////////////////////////////////////////////////////////////// // // CLatentSendQueue::SendCancelNotification // // Tell remote an in-progress transfer is cancelled // /////////////////////////////////////////////////////////////// void CLatentSendQueue::SendCancelNotification ( SSendItem& activeTx ) { assert ( activeTx.bSendStarted && !activeTx.bSendFinishing ); NetBitStreamInterface* pBitStream = DoAllocateNetBitStream ( m_RemoteId, m_usBitStreamVersion ); pBitStream->WriteBits ( &activeTx.uiId, 15 ); pBitStream->WriteBit ( 1 ); pBitStream->Write ( (uchar)FLAG_CANCEL ); DoSendPacket ( PACKET_ID_LATENT_TRANSFER, m_RemoteId, pBitStream, PACKET_PRIORITY_LOW, PACKET_RELIABILITY_RELIABLE_ORDERED, PACKET_ORDERING_DATA_TRANSFER ); DoDeallocateNetBitStream ( pBitStream ); }
bool CPickupHitConfirmPacket::Write ( NetBitStreamInterface& BitStream ) const { // unsigned short (2) - pickup id // bool - hide it? // Got a pickup to send? if ( m_pPickup ) { // Write the pickup id and visibily state BitStream.Write ( m_pPickup->GetID () ); // WRite the flags BitStream.WriteBit ( m_pPickup->IsVisible () ); BitStream.WriteBit ( m_bPlaySound ); return true; } return false; }
bool CPlayerJoinCompletePacket::Write ( NetBitStreamInterface& BitStream ) const { BitStream.Write ( m_PlayerID ); BitStream.Write ( m_ucNumberOfPlayers ); BitStream.Write ( m_RootElementID ); // Transmit server requirement for the client to check settings BitStream.Write ( m_iEnableClientChecks ); // Transmit whether or not the Voice is enabled BitStream.WriteBit ( m_bVoiceEnabled ); // Transmit the sample rate for voice SIntegerSync < unsigned char, 2 > sampleRate ( m_ucSampleRate ); BitStream.Write ( &sampleRate ); // Transmit the quality for voice SIntegerSync < unsigned char, 4 > voiceQuality ( m_ucQuality ); BitStream.Write ( &voiceQuality ); // Transmit the max bitrate for voice BitStream.WriteCompressed ( m_uiBitrate ); // Tellclient about maybe throttling back http client requests BitStream.Write ( m_iHTTPMaxConnectionsPerClient ); BitStream.Write ( static_cast < unsigned char > ( m_ucHTTPDownloadType ) ); switch ( m_ucHTTPDownloadType ) { case HTTP_DOWNLOAD_ENABLED_PORT: { BitStream.Write ( m_usHTTPDownloadPort ); } break; case HTTP_DOWNLOAD_ENABLED_URL: { // Internal http server port if ( BitStream.Version() >= 0x48 ) BitStream.Write( m_usHTTPDownloadPort ); // External http server URL BitStream.WriteString ( m_strHTTPDownloadURL ); } break; default: break; } return true; }
bool CExplosionSyncPacket::Write(NetBitStreamInterface& BitStream) const { // Write the source player and latency if any. Otherwize 0 if (m_pSourceElement) { BitStream.WriteBit(true); ElementID ID = m_pSourceElement->GetID(); BitStream.Write(ID); unsigned short usLatency = static_cast<CPlayer*>(m_pSourceElement)->GetPing(); BitStream.WriteCompressed(usLatency); } else { BitStream.WriteBit(false); } if (m_OriginID != INVALID_ELEMENT_ID) { BitStream.WriteBit(true); BitStream.Write(m_OriginID); } else BitStream.WriteBit(false); // Write position and type SPositionSync position(false); position.data.vecPosition = m_vecPosition; BitStream.Write(&position); SExplosionTypeSync explosionType; explosionType.data.uiType = m_ucType; BitStream.Write(&explosionType); return true; }
bool CVehicleTrailerPacket::Write ( NetBitStreamInterface& BitStream ) const { BitStream.Write ( m_Vehicle ); BitStream.Write ( m_AttachedVehicle ); BitStream.WriteBit ( m_bAttached ); if ( m_bAttached ) { SPositionSync position ( false ); position.data.vecPosition = m_vecPosition; BitStream.Write ( &position ); SRotationDegreesSync rotation ( false ); rotation.data.vecRotation = m_vecRotationDegrees; BitStream.Write ( &rotation ); SVelocitySync turn; turn.data.vecVelocity = m_vecTurnSpeed; BitStream.Write ( &turn ); } return true; }
bool CServerTextItemPacket::Write ( NetBitStreamInterface &BitStream ) const { BitStream.WriteCompressed ( m_ulUniqueId ); // Write the flag byte BitStream.WriteBit ( m_bDeletable ); // Not deleting this? if ( !m_bDeletable ) { BitStream.Write ( m_fX ); BitStream.Write ( m_fY ); BitStream.Write ( m_fScale ); BitStream.Write ( m_red ); BitStream.Write ( m_green ); BitStream.Write ( m_blue ); BitStream.Write ( m_alpha ); BitStream.Write ( m_ucFormat ); // Grab the text length size_t sizeText = strlen ( m_szText ); if ( sizeText > 1024 ) { sizeText = 1024; } // Write the text BitStream.WriteCompressed ( static_cast < unsigned short > ( sizeText ) ); if ( sizeText ) { BitStream.Write ( m_szText, sizeText ); } } return true; }
bool CLuaArgument::WriteToBitStream ( NetBitStreamInterface& bitStream, std::map < CLuaArguments*, unsigned long > * pKnownTables ) const { SLuaTypeSync type; switch ( GetType () ) { // Nil type case LUA_TNIL: { type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); break; } // Boolean type case LUA_TBOOLEAN: { type.data.ucType = LUA_TBOOLEAN; bitStream.Write ( &type ); // Write the boolean to it bitStream.WriteBit ( GetBoolean () ); break; } // Table argument case LUA_TTABLE: { if ( pKnownTables && pKnownTables->find ( m_pTableData ) != pKnownTables->end () ) { // Self-referencing table type.data.ucType = LUA_TTABLEREF; bitStream.Write ( &type ); bitStream.WriteCompressed ( pKnownTables->find ( m_pTableData )->second ); } else { type.data.ucType = LUA_TTABLE; bitStream.Write ( &type ); // Write the subtable to the bitstream m_pTableData->WriteToBitStream ( bitStream, pKnownTables ); } break; } // Number argument? case LUA_TNUMBER: { type.data.ucType = LUA_TNUMBER; bitStream.Write ( &type ); float fNumber = static_cast < float > ( GetNumber () ); long lNumber = static_cast < long > ( fNumber ); float fNumberInteger = static_cast < float > ( lNumber ); // Check if the number is an integer and can fit a long datatype if ( fabs ( fNumber ) > fabs ( fNumberInteger + 1 ) || fabs ( fNumber - fNumberInteger ) >= FLOAT_EPSILON ) { bitStream.WriteBit ( true ); bitStream.Write ( fNumber ); } else { bitStream.WriteBit ( false ); bitStream.WriteCompressed ( lNumber ); } break; } // String argument case LUA_TSTRING: { // Grab the string and its length. Is it short enough to be sendable? const char* szTemp = m_strString.c_str (); size_t sizeTemp = strlen ( szTemp ); unsigned short usLength = static_cast < unsigned short > ( sizeTemp ); if ( sizeTemp == usLength ) { // This is a string argument type.data.ucType = LUA_TSTRING; bitStream.Write ( &type ); // Write its length bitStream.WriteCompressed ( usLength ); // Write the content too if it's not empty if ( usLength > 0 ) { bitStream.Write ( const_cast < char* > ( szTemp ), usLength ); } } else { // Too long string LogUnableToPacketize ( "Couldn't packetize argument list. Invalid string specified, limit is 65535 characters." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } break; } // Element argument case LUA_TLIGHTUSERDATA: { // Grab the element from this userdata pointer. Valid and has a synced element ID? CElement* pElement = GetElement (); if ( pElement && pElement->GetID () != INVALID_ELEMENT_ID ) { // Write its ID type.data.ucType = LUA_TLIGHTUSERDATA; bitStream.Write ( &type ); bitStream.WriteCompressed ( static_cast < ElementID > ( pElement->GetID () ) ); } else { // Jax: this just spams the script debugger, it's not really neccesary // LogUnableToPacketize ( "Couldn't packetize argument list, invalid element specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } break; } // Unpacketizable type. default: { // Unpacketizable LogUnableToPacketize ( "Couldn't packetize argument list, unknown type specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } } // Success return true; }
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 CResourceStartPacket::Write(NetBitStreamInterface& BitStream) const { if (!m_strResourceName.empty()) { // Write the resource name unsigned char sizeResourceName = static_cast<unsigned char>(m_strResourceName.size()); BitStream.Write(sizeResourceName); if (sizeResourceName > 0) { BitStream.Write(m_strResourceName.c_str(), sizeResourceName); } // Write the resource id BitStream.Write(m_pResource->GetNetID()); // Write the resource element id BitStream.Write(m_pResource->GetResourceRootElement()->GetID()); // Write the resource dynamic element id BitStream.Write(m_pResource->GetDynamicElementRoot()->GetID()); // Count the amount of 'no client cache' scripts unsigned short usNoClientCacheScriptCount = 0; if (m_pResource->IsClientScriptsOn() == true) { list<CResourceFile*>::iterator iter = m_pResource->IterBegin(); for (; iter != m_pResource->IterEnd(); ++iter) { if ((*iter)->GetType() == CResourceScriptItem::RESOURCE_FILE_TYPE_CLIENT_SCRIPT && static_cast<CResourceClientScriptItem*>(*iter)->IsNoClientCache() == true) { ++usNoClientCacheScriptCount; } } } BitStream.Write(usNoClientCacheScriptCount); // Write the declared min client version for this resource if (BitStream.Version() >= 0x32) { BitStream.WriteString(m_pResource->GetMinServerReqFromMetaXml()); BitStream.WriteString(m_pResource->GetMinClientReqFromMetaXml()); } if (BitStream.Version() >= 0x45) { BitStream.WriteBit(m_pResource->IsOOPEnabledInMetaXml()); } if (BitStream.Version() >= 0x62) { BitStream.Write(m_pResource->GetDownloadPriorityGroup()); } // Send the resource files info list<CResourceFile*>::iterator iter = m_pResource->IterBegin(); for (; iter != m_pResource->IterEnd(); iter++) { if (((*iter)->GetType() == CResourceScriptItem::RESOURCE_FILE_TYPE_CLIENT_CONFIG && m_pResource->IsClientConfigsOn()) || ((*iter)->GetType() == CResourceScriptItem::RESOURCE_FILE_TYPE_CLIENT_SCRIPT && m_pResource->IsClientScriptsOn() && static_cast<CResourceClientScriptItem*>(*iter)->IsNoClientCache() == false) || ((*iter)->GetType() == CResourceScriptItem::RESOURCE_FILE_TYPE_CLIENT_FILE && m_pResource->IsClientFilesOn())) { // Write the Type of chunk to read (F - File, E - Exported Function) BitStream.Write(static_cast<unsigned char>('F')); // Write the map name const char* szFileName = (*iter)->GetWindowsName(); size_t sizeFileName = strlen(szFileName); // Make sure we don't have any backslashes in the name char* szCleanedFilename = new char[sizeFileName + 1]; strcpy(szCleanedFilename, szFileName); for (unsigned int i = 0; i < sizeFileName; i++) { if (szCleanedFilename[i] == '\\') szCleanedFilename[i] = '/'; } BitStream.Write(static_cast<unsigned char>(sizeFileName)); if (sizeFileName > 0) { BitStream.Write(szCleanedFilename, sizeFileName); } // ChrML: Don't forget this... delete[] szCleanedFilename; BitStream.Write(static_cast<unsigned char>((*iter)->GetType())); CChecksum checksum = (*iter)->GetLastChecksum(); BitStream.Write(checksum.ulCRC); BitStream.Write((const char*)checksum.md5.data, sizeof(checksum.md5.data)); BitStream.Write((*iter)->GetApproxSize()); if ((*iter)->GetType() == CResourceScriptItem::RESOURCE_FILE_TYPE_CLIENT_FILE) { CResourceClientFileItem* pRCFItem = reinterpret_cast<CResourceClientFileItem*>(*iter); // write bool whether to download or not BitStream.WriteBit(pRCFItem->IsAutoDownload()); } } } // Loop through the exported functions list<CExportedFunction>::iterator iterExportedFunction = m_pResource->IterBeginExportedFunctions(); for (; iterExportedFunction != m_pResource->IterEndExportedFunctions(); iterExportedFunction++) { // Check to see if the exported function is 'client' if (iterExportedFunction->GetType() == CExportedFunction::EXPORTED_FUNCTION_TYPE_CLIENT) { // Write the Type of chunk to read (F - File, E - Exported Function) BitStream.Write(static_cast<unsigned char>('E')); // Write the exported function std::string strFunctionName = iterExportedFunction->GetFunctionName(); size_t sizeFunctionName = strFunctionName.length(); BitStream.Write(static_cast<unsigned char>(sizeFunctionName)); if (sizeFunctionName > 0) { BitStream.Write(strFunctionName.c_str(), sizeFunctionName); } } } 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; }
// Can't use bitStream.Version() here as it is sometimes not set bool CLuaArgument::WriteToBitStream(NetBitStreamInterface& bitStream, CFastHashMap<CLuaArguments*, unsigned long>* pKnownTables) const { SLuaTypeSync type; switch (GetType()) { // Nil type case LUA_TNIL: { type.data.ucType = LUA_TNIL; bitStream.Write(&type); break; } // Boolean type case LUA_TBOOLEAN: { type.data.ucType = LUA_TBOOLEAN; bitStream.Write(&type); // Write the boolean to it bitStream.WriteBit(GetBoolean()); break; } // Table argument case LUA_TTABLE: { ulong* pThingy; if (pKnownTables && (pThingy = MapFind(*pKnownTables, m_pTableData))) { // Self-referencing table type.data.ucType = LUA_TTABLEREF; bitStream.Write(&type); bitStream.WriteCompressed(*pThingy); } else { type.data.ucType = LUA_TTABLE; bitStream.Write(&type); // Write the subtable to the bitstream m_pTableData->WriteToBitStream(bitStream, pKnownTables); } break; } // Number argument? case LUA_TNUMBER: { type.data.ucType = LUA_TNUMBER; bitStream.Write(&type); int iNumber; float fNumber; double dNumber; EDataType dataType = GetDataTypeToUse(GetNumber(), &iNumber, &fNumber, &dNumber); if (dataType == DATA_TYPE_INT) { bitStream.WriteBit(false); bitStream.WriteCompressed(iNumber); } else if (dataType == DATA_TYPE_FLOAT) { bitStream.WriteBit(true); bitStream.WriteBit(false); bitStream.Write(fNumber); } else { bitStream.WriteBit(true); bitStream.WriteBit(true); bitStream.Write(dNumber); } break; } // String argument case LUA_TSTRING: { // Grab the string and its length. Is it short enough to be sendable? const char* szTemp = m_strString.c_str(); size_t sizeTemp = m_strString.length(); unsigned short usLength = static_cast<unsigned short>(sizeTemp); if (sizeTemp == usLength) { // This is a string argument type.data.ucType = LUA_TSTRING; bitStream.Write(&type); // Write its length bitStream.WriteCompressed(usLength); // Write the content too if it's not empty if (usLength > 0) { bitStream.Write(szTemp, usLength); } } else { // This is a long string argument type.data.ucType = LUA_TSTRING_LONG; bitStream.Write(&type); // Write its length uint uiLength = sizeTemp; bitStream.WriteCompressed(uiLength); // Write the content too if it's not empty if (uiLength > 0) { bitStream.AlignWriteToByteBoundary(); bitStream.Write(szTemp, uiLength); } } break; } // Element argument case LUA_TLIGHTUSERDATA: case LUA_TUSERDATA: { // Grab the element from this userdata pointer. Valid and has a synced element ID? CElement* pElement = GetElement(); if (pElement && pElement->GetID() != INVALID_ELEMENT_ID) { // Write its ID type.data.ucType = LUA_TUSERDATA; bitStream.Write(&type); bitStream.Write(pElement->GetID()); } else { // Jax: this just spams the script debugger, it's not really neccesary // LogUnableToPacketize ( "Couldn't packetize argument list, invalid element specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write(&type); return false; } break; } // Unpacketizable type. default: { // Unpacketizable LogUnableToPacketize("Couldn't packetize argument list, unknown type specified."); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write(&type); return false; } } // Success return true; }
// // Should do the same this as what CKeysyncPacket::Write() does // bool CSimKeysyncPacket::Write ( NetBitStreamInterface& BitStream ) const { // Write the source player id BitStream.Write ( m_PlayerID ); // Write the keysync data WriteSmallKeysync ( m_sharedControllerState, BitStream ); // Write the rotations SKeysyncRotation rotation; rotation.data.fPlayerRotation = m_Cache.fPlayerRotation; rotation.data.fCameraRotation = m_Cache.fCameraRotation; BitStream.Write ( &rotation ); // Write the flags BitStream.Write ( &m_Cache.flags ); // If he's shooting or aiming if ( m_sharedControllerState.ButtonCircle || ( m_sharedControllerState.RightShoulder1 ) ) { // Write his current weapon slot unsigned int uiSlot = m_Cache.ucWeaponSlot; // check m_Cache.bWeaponCorrect ! SWeaponSlotSync slot; slot.data.uiSlot = uiSlot; BitStream.Write ( &slot ); if ( CWeaponNames::DoesSlotHaveAmmo ( uiSlot ) ) { // Write his ammo in clip SWeaponAmmoSync ammo ( m_ucPlayerGotWeaponType, false, true ); ammo.data.usAmmoInClip = m_Cache.usAmmoInClip; BitStream.Write ( &ammo ); // Write the weapon aim data SWeaponAimSync aim ( 0.0f ); aim.data.vecOrigin = m_Cache.vecSniperSource; aim.data.vecTarget = m_Cache.vecTargetting; aim.data.fArm = m_Cache.fAimDirection; BitStream.Write ( &aim ); // Write the driveby aim directoin BitStream.Write ( m_Cache.ucDriveByDirection ); } } // If he's in a vehicle, read out the small vehicle specific data if ( m_bPlayerHasOccupiedVehicle && m_Cache.flags.data.bSyncingVehicle ) { if ( CVehicleManager::HasTurret ( m_usVehicleGotModel ) ) BitStream.Write ( &m_Cache.turretSync ); if ( m_bVehicleHasHydraulics ) { BitStream.Write ( m_sharedControllerState.RightStickX ); BitStream.Write ( m_sharedControllerState.RightStickY ); } if ( m_bVehicleIsPlaneOrHeli ) { BitStream.WriteBit ( m_sharedControllerState.LeftShoulder2 != 0); BitStream.WriteBit ( m_sharedControllerState.RightShoulder2 != 0); } } return true; }
bool CPlayerListPacket::Write ( NetBitStreamInterface& BitStream ) const { // bool - show the "X has joined the game" messages? // [ following repeats <number of players joined> times ] // unsigned char (1) - assigned player id // unsigned char (1) - player nick length // unsigned char (X) - player nick (X = player nick length) // bool - is he dead? // bool - spawned? (following data only if this is TRUE) // unsigned char (1) - model id // unsigned char (1) - team id // bool - in a vehicle? // unsigned short (2) - vehicle id (if vehicle) // unsigned char (1) - vehicle seat (if vehicle) // CVector (12) - position (if player) // float (4) - rotation (if player) // bool - has a jetpack? // unsigned short (2) - dimension // Write the global flags BitStream.WriteBit ( m_bShowInChat ); CPlayer* pPlayer = NULL; // Put each player in our list into the packet list < CPlayer* > ::const_iterator iter = m_List.begin (); for ( ; iter != m_List.end (); ++iter ) { // Grab the real pointer pPlayer = *iter; // Write the player ID ElementID PlayerID = pPlayer->GetID (); BitStream.Write ( PlayerID ); // Time sync context BitStream.Write ( pPlayer->GetSyncTimeContext () ); // Write the nick length const char* szNickPointer = pPlayer->GetNick (); unsigned char ucNickLength = static_cast < unsigned char > ( strlen ( szNickPointer ) ); if ( ucNickLength < MIN_NICK_LENGTH || ucNickLength > MAX_NICK_LENGTH ) { BitStream.Write ( static_cast < unsigned char > ( 3 ) ); BitStream.Write ( "???", 3 ); } else { BitStream.Write ( ucNickLength ); BitStream.Write ( szNickPointer, ucNickLength ); } // Version info if ( BitStream.Version () >= 0x34 ) { BitStream.Write ( pPlayer->GetBitStreamVersion () ); SString strBuild = pPlayer->GetPlayerVersion ().SubStr ( 8 ); uint uiBuildNumber = atoi ( strBuild ); BitStream.Write ( uiBuildNumber ); } // Flags bool bInVehicle = ( pPlayer->GetOccupiedVehicle () != NULL ); BitStream.WriteBit ( pPlayer->IsDead () ); // Currently unused by the client BitStream.WriteBit ( true ); // (Was IsSpawned) Used by the client to determine if extra info was sent (in this packet) BitStream.WriteBit ( bInVehicle ); BitStream.WriteBit ( pPlayer->HasJetPack () ); BitStream.WriteBit ( pPlayer->IsNametagShowing () ); BitStream.WriteBit ( pPlayer->IsNametagColorOverridden () ); BitStream.WriteBit ( pPlayer->IsHeadless() ); BitStream.WriteBit ( pPlayer->IsFrozen() ); // Nametag stuff unsigned char ucNametagTextLength = 0; char* szNametagText = pPlayer->GetNametagText (); if ( szNametagText ) ucNametagTextLength = static_cast < unsigned char > ( strlen ( szNametagText ) ); BitStream.Write ( ucNametagTextLength ); if ( ucNametagTextLength > 0 ) BitStream.Write ( szNametagText, ucNametagTextLength ); // Write nametag color if it's overridden if ( pPlayer->IsNametagColorOverridden () ) { unsigned char ucR, ucG, ucB; pPlayer->GetNametagColor ( ucR, ucG, ucB ); BitStream.Write ( ucR ); BitStream.Write ( ucG ); BitStream.Write ( ucB ); } // Move anim if ( BitStream.Version() > 0x4B ) { uchar ucMoveAnim = pPlayer->GetMoveAnim(); BitStream.Write ( ucMoveAnim ); } // Always send extra info (Was: "Write spawn info if he's spawned") if ( true ) { // Player model ID BitStream.WriteCompressed ( pPlayer->GetModel () ); // Team id CTeam* pTeam = pPlayer->GetTeam (); if ( pTeam ) { BitStream.WriteBit ( true ); BitStream.Write ( pTeam->GetID () ); } else BitStream.WriteBit ( false ); if ( bInVehicle ) { // Grab the occupied vehicle CVehicle* pVehicle = pPlayer->GetOccupiedVehicle (); // Vehicle ID and seat BitStream.Write ( pVehicle->GetID () ); SOccupiedSeatSync seat; seat.data.ucSeat = pPlayer->GetOccupiedVehicleSeat (); BitStream.Write ( &seat ); } else { // Player position SPositionSync position ( false ); position.data.vecPosition = pPlayer->GetPosition (); BitStream.Write ( &position ); // Player rotation SPedRotationSync rotation; rotation.data.fRotation = pPlayer->GetRotation (); BitStream.Write ( &rotation ); } BitStream.WriteCompressed ( pPlayer->GetDimension () ); BitStream.Write ( pPlayer->GetFightingStyle () ); SEntityAlphaSync alpha; alpha.data.ucAlpha = pPlayer->GetAlpha (); BitStream.Write ( &alpha ); BitStream.Write ( pPlayer->GetInterior () ); // Write the weapons of the player weapon slots for ( unsigned int i = 0; i < 16; ++i ) { CWeapon* pWeapon = pPlayer->GetWeapon ( i ); if ( pWeapon && pWeapon->ucType != 0 ) { BitStream.WriteBit ( true ); SWeaponTypeSync weaponType; weaponType.data.ucWeaponType = pWeapon->ucType; BitStream.Write ( &weaponType ); } else BitStream.WriteBit ( false ); } } } return true; }
bool CMapInfoPacket::Write ( NetBitStreamInterface& BitStream ) const { // Write the map weather BitStream.Write ( m_ucWeather ); BitStream.Write ( m_ucWeatherBlendingTo ); BitStream.Write ( m_ucBlendedWeatherHour ); BitStream.WriteBit ( m_bHasSkyGradient ); if ( m_bHasSkyGradient ) { BitStream.Write ( m_ucSkyGradientTR ); BitStream.Write ( m_ucSkyGradientTG ); BitStream.Write ( m_ucSkyGradientTB ); BitStream.Write ( m_ucSkyGradientBR ); BitStream.Write ( m_ucSkyGradientBG ); BitStream.Write ( m_ucSkyGradientBB ); } // Write heat haze BitStream.WriteBit ( m_bHasHeatHaze ); if ( m_bHasHeatHaze ) { SHeatHazeSync heatHaze ( m_HeatHazeSettings ); BitStream.Write ( &heatHaze ); } // Write the map hour BitStream.Write ( m_ucClockHour ); BitStream.Write ( m_ucClockMin ); BitStream.WriteCompressed ( m_ulMinuteDuration ); // Write the map flags SMapInfoFlagsSync flags; flags.data.bShowNametags = m_bShowNametags; flags.data.bShowRadar = m_bShowRadar; flags.data.bCloudsEnabled = m_bCloudsEnabled; BitStream.Write ( &flags ); // Write any other world conditions BitStream.Write ( m_fGravity ); if ( m_fGameSpeed == 1.0f ) BitStream.WriteBit ( true ); else { BitStream.WriteBit ( false ); BitStream.Write ( m_fGameSpeed ); } BitStream.Write ( m_fWaveHeight ); // Write world water level BitStream.Write ( m_WorldWaterLevelInfo.fSeaLevel ); BitStream.WriteBit ( m_WorldWaterLevelInfo.bNonSeaLevelSet ); if ( m_WorldWaterLevelInfo.bNonSeaLevelSet ) BitStream.Write ( m_WorldWaterLevelInfo.fNonSeaLevel ); BitStream.WriteCompressed ( m_usFPSLimit ); // Write the garage states for ( unsigned char i = 0 ; i < MAX_GARAGES ; i++ ) { BitStream.WriteBit( static_cast < unsigned char > ( m_pbGarageStates[i] ) ); } // Write the fun bugs state SFunBugsStateSync funBugs; funBugs.data.bQuickReload = g_pGame->IsGlitchEnabled ( CGame::GLITCH_QUICKRELOAD ); funBugs.data.bFastFire = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTFIRE ); funBugs.data.bFastMove = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTMOVE ); funBugs.data.bCrouchBug = g_pGame->IsGlitchEnabled ( CGame::GLITCH_CROUCHBUG ); funBugs.data.bCloseRangeDamage = g_pGame->IsGlitchEnabled ( CGame::GLITCH_CLOSEDAMAGE ); BitStream.Write ( &funBugs ); BitStream.Write ( m_fJetpackMaxHeight ); BitStream.WriteBit ( m_bOverrideWaterColor ); if ( m_bOverrideWaterColor ) { BitStream.Write ( m_ucWaterRed ); BitStream.Write ( m_ucWaterGreen ); BitStream.Write ( m_ucWaterBlue ); BitStream.Write ( m_ucWaterAlpha ); } // Interior sounds BitStream.WriteBit ( m_bInteriorSoundsEnabled ); // Rain level BitStream.WriteBit ( m_bOverrideRainLevel ); if ( m_bOverrideRainLevel ) { BitStream.Write ( m_fRainLevel ); } // Sun size BitStream.WriteBit ( m_bOverrideSunSize ); if ( m_bOverrideSunSize ) { BitStream.Write ( m_fSunSize ); } // Sun color BitStream.WriteBit ( m_bOverrideSunColor ); if ( m_bOverrideSunColor ) { BitStream.Write ( m_ucSunCoreR ); BitStream.Write ( m_ucSunCoreG ); BitStream.Write ( m_ucSunCoreB ); BitStream.Write ( m_ucSunCoronaR ); BitStream.Write ( m_ucSunCoronaG ); BitStream.Write ( m_ucSunCoronaB ); } // Wind velocity BitStream.WriteBit ( m_bOverrideWindVelocity ); if ( m_bOverrideWindVelocity ) { BitStream.Write ( m_fWindVelX ); BitStream.Write ( m_fWindVelY ); BitStream.Write ( m_fWindVelZ ); } // Far clip distance BitStream.WriteBit ( m_bOverrideFarClipDistance ); if ( m_bOverrideFarClipDistance ) { BitStream.Write ( m_fFarClip ); } // Fog distance BitStream.WriteBit ( m_bOverrideFogDistance ); if ( m_bOverrideFogDistance ) { BitStream.Write ( m_fFogDistance ); } BitStream.Write ( m_fAircraftMaxHeight ); for (int i = WEAPONTYPE_PISTOL;i <= WEAPONTYPE_EXTINGUISHER;i++) { sWeaponPropertySync WeaponProperty; CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager ()->GetWeaponStats( (eWeaponType)i ); BitStream.WriteBit ( true ); WeaponProperty.data.weaponType = (int)pWeaponStat->GetWeaponType(); WeaponProperty.data.fAccuracy = pWeaponStat->GetAccuracy(); WeaponProperty.data.fMoveSpeed = pWeaponStat->GetMoveSpeed(); WeaponProperty.data.fTargetRange = pWeaponStat->GetTargetRange(); WeaponProperty.data.fWeaponRange = pWeaponStat->GetWeaponRange(); WeaponProperty.data.nAmmo = pWeaponStat->GetMaximumClipAmmo(); WeaponProperty.data.nDamage = pWeaponStat->GetDamagePerHit(); WeaponProperty.data.nFlags = pWeaponStat->GetFlags(); WeaponProperty.data.anim_loop_start = pWeaponStat->GetWeaponAnimLoopStart(); WeaponProperty.data.anim_loop_stop = pWeaponStat->GetWeaponAnimLoopStop(); WeaponProperty.data.anim_loop_bullet_fire = pWeaponStat->GetWeaponAnimLoopFireTime(); WeaponProperty.data.anim2_loop_start = pWeaponStat->GetWeaponAnim2LoopStart(); WeaponProperty.data.anim2_loop_stop = pWeaponStat->GetWeaponAnim2LoopStop(); WeaponProperty.data.anim2_loop_bullet_fire = pWeaponStat->GetWeaponAnim2LoopFireTime(); WeaponProperty.data.anim_breakout_time = pWeaponStat->GetWeaponAnimBreakoutTime(); BitStream.Write( &WeaponProperty ); } for (int i = WEAPONTYPE_PISTOL;i <= WEAPONTYPE_TEC9;i++) { sWeaponPropertySync WeaponProperty; BitStream.WriteBit ( true ); for (int j = 0; j <= 2;j++) { CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager ()->GetWeaponStats( (eWeaponType)i, (eWeaponSkill)j ); WeaponProperty.data.weaponType = (int)pWeaponStat->GetWeaponType(); WeaponProperty.data.fAccuracy = pWeaponStat->GetAccuracy(); WeaponProperty.data.fMoveSpeed = pWeaponStat->GetMoveSpeed(); WeaponProperty.data.fTargetRange = pWeaponStat->GetTargetRange(); WeaponProperty.data.fWeaponRange = pWeaponStat->GetWeaponRange(); WeaponProperty.data.nAmmo = pWeaponStat->GetMaximumClipAmmo(); WeaponProperty.data.nDamage = pWeaponStat->GetDamagePerHit(); WeaponProperty.data.nFlags = pWeaponStat->GetFlags(); WeaponProperty.data.anim_loop_start = pWeaponStat->GetWeaponAnimLoopStart(); WeaponProperty.data.anim_loop_stop = pWeaponStat->GetWeaponAnimLoopStop(); WeaponProperty.data.anim_loop_bullet_fire = pWeaponStat->GetWeaponAnimLoopFireTime(); WeaponProperty.data.anim2_loop_start = pWeaponStat->GetWeaponAnim2LoopStart(); WeaponProperty.data.anim2_loop_stop = pWeaponStat->GetWeaponAnim2LoopStop(); WeaponProperty.data.anim2_loop_bullet_fire = pWeaponStat->GetWeaponAnim2LoopFireTime(); WeaponProperty.data.anim_breakout_time = pWeaponStat->GetWeaponAnimBreakoutTime(); BitStream.Write( &WeaponProperty ); } } return true; }
/////////////////////////////////////////////////////////////// // // CLatentSendQueue::DoPulse // // Send next part of the active transfer // /////////////////////////////////////////////////////////////// void CLatentSendQueue::DoPulse ( int iTimeMsBetweenCalls ) { if ( m_TxQueue.empty () ) { m_iBytesOwing = 0; return; } // Check if previous tx has completed if ( m_TxQueue.front ().uiReadPosition == m_TxQueue.front ().bufferRef->GetSize () && m_TxQueue.front ().bSendFinishing ) { m_TxQueue.pop_front (); PostQueueRemove (); if ( m_TxQueue.empty () ) { m_iBytesOwing = 0; return; } } m_uiCurrentRate = Max < uint > ( MIN_SEND_RATE, m_uiCurrentRate ); // How many bytes to send this pulse int iBytesToSendThisPulse = iTimeMsBetweenCalls * m_uiCurrentRate / 1000; // Add bytes owing from last pulse iBytesToSendThisPulse += m_iBytesOwing; // Calc packet size depending on rate uint uiMaxPacketSize = Lerp ( MIN_PACKET_SIZE, UnlerpClamped ( MIN_PACKET_SIZE * 10, m_uiCurrentRate, MAX_PACKET_SIZE * 15 ), MAX_PACKET_SIZE ); // Calc how many packets to do this pulse uint uiNumPackets = iBytesToSendThisPulse / uiMaxPacketSize; // Update carry over m_iBytesOwing = iBytesToSendThisPulse % uiMaxPacketSize; // Process item at front of queue SSendItem& activeTx = m_TxQueue.front (); for ( uint i = 0 ; i < uiNumPackets && !activeTx.bSendFinishing ; i++ ) { // Send next part of data NetBitStreamInterface* pBitStream = DoAllocateNetBitStream ( m_RemoteId, m_usBitStreamVersion ); pBitStream->WriteBits ( &activeTx.uiId, 15 ); // Next bit indicates if it has a special flag if ( activeTx.uiReadPosition == 0 ) { // Head pBitStream->WriteBit ( 1 ); pBitStream->Write ( (uchar)FLAG_HEAD ); pBitStream->Write ( activeTx.usCategory ); pBitStream->Write ( activeTx.bufferRef->GetSize () ); pBitStream->Write ( activeTx.uiRate ); if ( pBitStream->Version () >= 0x31 ) pBitStream->Write ( activeTx.usResourceNetId ); activeTx.bSendStarted = true; } else if ( activeTx.bufferRef->GetSize () == activeTx.uiReadPosition ) { // Tail pBitStream->WriteBit ( 1 ); pBitStream->Write ( (uchar)FLAG_TAIL ); activeTx.bSendFinishing = true; } else { // Body pBitStream->WriteBit ( 0 ); } // Align to next boundary pBitStream->AlignWriteToByteBoundary (); uint uiMaxDataSize = Max < int > ( 10, uiMaxPacketSize - pBitStream->GetNumberOfBytesUsed () ); // Calc how much data to send uint uiDataOffset = activeTx.uiReadPosition; uint uiSizeToSend = Min ( uiMaxDataSize, activeTx.bufferRef->GetSize () - activeTx.uiReadPosition ); activeTx.uiReadPosition += uiSizeToSend; pBitStream->Write ( (ushort)uiSizeToSend ); pBitStream->Write ( activeTx.bufferRef->GetData () + uiDataOffset, uiSizeToSend ); // Send DoSendPacket ( PACKET_ID_LATENT_TRANSFER, m_RemoteId, pBitStream, PACKET_PRIORITY_LOW, PACKET_RELIABILITY_RELIABLE_ORDERED, PACKET_ORDERING_DATA_TRANSFER ); DoDeallocateNetBitStream ( pBitStream ); } }
bool CProjectileSyncPacket::Write ( NetBitStreamInterface& BitStream ) const { // Write the source player and latency if any. Otherwize 0 if ( m_pSourceElement ) { BitStream.WriteBit ( true ); BitStream.WriteCompressed ( m_pSourceElement->GetID () ); unsigned short usLatency = static_cast < CPlayer * > ( m_pSourceElement )->GetPing (); BitStream.WriteCompressed ( usLatency ); } else BitStream.WriteBit ( false ); if ( m_OriginID != INVALID_ELEMENT_ID ) { BitStream.WriteBit ( true ); BitStream.WriteCompressed ( m_OriginID ); } else BitStream.WriteBit ( false ); SPositionSync position ( false ); position.data.vecPosition = m_vecOrigin; BitStream.Write ( &position ); SWeaponTypeSync weaponType; weaponType.data.ucWeaponType = m_ucWeaponType; BitStream.Write ( &weaponType ); switch ( m_ucWeaponType ) { case 16: // WEAPONTYPE_GRENADE case 17: // WEAPONTYPE_TEARGAS case 18: // WEAPONTYPE_MOLOTOV case 39: // WEAPONTYPE_REMOTE_SATCHEL_CHARGE { SFloatSync < 7, 17 > projectileForce; projectileForce.data.fValue = m_fForce; BitStream.Write ( &projectileForce ); SVelocitySync velocity; velocity.data.vecVelocity = m_vecMoveSpeed; BitStream.Write ( &velocity ); break; } case 19: // WEAPONTYPE_ROCKET case 20: // WEAPONTYPE_ROCKET_HS { if ( m_TargetID != INVALID_ELEMENT_ID ) { BitStream.WriteBit ( true ); BitStream.WriteCompressed ( m_TargetID ); } else BitStream.WriteBit ( false ); SVelocitySync velocity; velocity.data.vecVelocity = m_vecMoveSpeed; BitStream.Write ( &velocity ); SRotationRadiansSync rotation ( true ); rotation.data.vecRotation = m_vecRotation; BitStream.Write ( &rotation ); break; } case 58: // WEAPONTYPE_FLARE break; } return true; }
bool CMapInfoPacket::Write ( NetBitStreamInterface& BitStream ) const { // Write the map weather BitStream.Write ( m_ucWeather ); BitStream.Write ( m_ucWeatherBlendingTo ); BitStream.Write ( m_ucBlendedWeatherHour ); BitStream.WriteBit ( m_bHasSkyGradient ); if ( m_bHasSkyGradient ) { BitStream.Write ( m_ucSkyGradientTR ); BitStream.Write ( m_ucSkyGradientTG ); BitStream.Write ( m_ucSkyGradientTB ); BitStream.Write ( m_ucSkyGradientBR ); BitStream.Write ( m_ucSkyGradientBG ); BitStream.Write ( m_ucSkyGradientBB ); } // Write heat haze BitStream.WriteBit ( m_bHasHeatHaze ); if ( m_bHasHeatHaze ) { SHeatHazeSync heatHaze ( m_HeatHazeSettings ); BitStream.Write ( &heatHaze ); } // Write the map hour BitStream.Write ( m_ucClockHour ); BitStream.Write ( m_ucClockMin ); BitStream.WriteCompressed ( m_ulMinuteDuration ); // Write the map flags SMapInfoFlagsSync flags; flags.data.bShowNametags = m_bShowNametags; flags.data.bShowRadar = m_bShowRadar; flags.data.bCloudsEnabled = m_bCloudsEnabled; BitStream.Write ( &flags ); // Write any other world conditions BitStream.Write ( m_fGravity ); if ( m_fGameSpeed == 1.0f ) BitStream.WriteBit ( true ); else { BitStream.WriteBit ( false ); BitStream.Write ( m_fGameSpeed ); } BitStream.Write ( m_fWaveHeight ); // Write world water level BitStream.Write ( m_WorldWaterLevelInfo.fSeaLevel ); BitStream.WriteBit ( m_WorldWaterLevelInfo.bNonSeaLevelSet ); if ( m_WorldWaterLevelInfo.bNonSeaLevelSet ) BitStream.Write ( m_WorldWaterLevelInfo.fNonSeaLevel ); BitStream.WriteCompressed ( m_usFPSLimit ); // Write the garage states for ( unsigned char i = 0 ; i < MAX_GARAGES ; i++ ) { const SGarageStates& garageStates = *m_pGarageStates; BitStream.WriteBit( garageStates[i] ); } // Write the fun bugs state SFunBugsStateSync funBugs; funBugs.data.bQuickReload = g_pGame->IsGlitchEnabled ( CGame::GLITCH_QUICKRELOAD ); funBugs.data.bFastFire = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTFIRE ); funBugs.data.bFastMove = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTMOVE ); funBugs.data.bCrouchBug = g_pGame->IsGlitchEnabled ( CGame::GLITCH_CROUCHBUG ); funBugs.data.bCloseRangeDamage = g_pGame->IsGlitchEnabled ( CGame::GLITCH_CLOSEDAMAGE ); funBugs.data2.bHitAnim = g_pGame->IsGlitchEnabled ( CGame::GLITCH_HITANIM ); funBugs.data3.bFastSprint = g_pGame->IsGlitchEnabled ( CGame::GLITCH_FASTSPRINT ); BitStream.Write ( &funBugs ); BitStream.Write ( m_fJetpackMaxHeight ); BitStream.WriteBit ( m_bOverrideWaterColor ); if ( m_bOverrideWaterColor ) { BitStream.Write ( m_ucWaterRed ); BitStream.Write ( m_ucWaterGreen ); BitStream.Write ( m_ucWaterBlue ); BitStream.Write ( m_ucWaterAlpha ); } // Interior sounds BitStream.WriteBit ( m_bInteriorSoundsEnabled ); // Rain level BitStream.WriteBit ( m_bOverrideRainLevel ); if ( m_bOverrideRainLevel ) { BitStream.Write ( m_fRainLevel ); } // Moon size if ( BitStream.Version () >= 0x40 ) { BitStream.WriteBit ( m_bOverrideMoonSize ); if ( m_bOverrideMoonSize ) { BitStream.Write ( m_iMoonSize ); } } // Sun size BitStream.WriteBit ( m_bOverrideSunSize ); if ( m_bOverrideSunSize ) { BitStream.Write ( m_fSunSize ); } // Sun color BitStream.WriteBit ( m_bOverrideSunColor ); if ( m_bOverrideSunColor ) { BitStream.Write ( m_ucSunCoreR ); BitStream.Write ( m_ucSunCoreG ); BitStream.Write ( m_ucSunCoreB ); BitStream.Write ( m_ucSunCoronaR ); BitStream.Write ( m_ucSunCoronaG ); BitStream.Write ( m_ucSunCoronaB ); } // Wind velocity BitStream.WriteBit ( m_bOverrideWindVelocity ); if ( m_bOverrideWindVelocity ) { BitStream.Write ( m_fWindVelX ); BitStream.Write ( m_fWindVelY ); BitStream.Write ( m_fWindVelZ ); } // Far clip distance BitStream.WriteBit ( m_bOverrideFarClipDistance ); if ( m_bOverrideFarClipDistance ) { BitStream.Write ( m_fFarClip ); } // Fog distance BitStream.WriteBit ( m_bOverrideFogDistance ); if ( m_bOverrideFogDistance ) { BitStream.Write ( m_fFogDistance ); } BitStream.Write ( m_fAircraftMaxHeight ); if ( BitStream.Version () >= 0x3E ) BitStream.Write ( m_fAircraftMaxVelocity ); if ( BitStream.Version () >= 0x30 ) { for (int i = WEAPONTYPE_BRASSKNUCKLE; i < WEAPONTYPE_PISTOL; i++) { bool bEnabled; bEnabled = g_pGame->GetJetpackWeaponEnabled ( (eWeaponType) i ); BitStream.WriteBit ( bEnabled ); } } for (int i = WEAPONTYPE_PISTOL;i <= WEAPONTYPE_EXTINGUISHER;i++) { sWeaponPropertySync WeaponProperty; CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager ()->GetWeaponStats( (eWeaponType)i ); BitStream.WriteBit ( true ); WeaponProperty.data.weaponType = (int)pWeaponStat->GetWeaponType(); WeaponProperty.data.fAccuracy = pWeaponStat->GetAccuracy(); WeaponProperty.data.fMoveSpeed = pWeaponStat->GetMoveSpeed(); WeaponProperty.data.fTargetRange = pWeaponStat->GetTargetRange(); WeaponProperty.data.fWeaponRange = pWeaponStat->GetWeaponRange(); WeaponProperty.data.nAmmo = pWeaponStat->GetMaximumClipAmmo(); WeaponProperty.data.nDamage = pWeaponStat->GetDamagePerHit(); WeaponProperty.data.nFlags = pWeaponStat->GetFlags(); WeaponProperty.data.anim_loop_start = pWeaponStat->GetWeaponAnimLoopStart(); WeaponProperty.data.anim_loop_stop = pWeaponStat->GetWeaponAnimLoopStop(); WeaponProperty.data.anim_loop_bullet_fire = pWeaponStat->GetWeaponAnimLoopFireTime(); WeaponProperty.data.anim2_loop_start = pWeaponStat->GetWeaponAnim2LoopStart(); WeaponProperty.data.anim2_loop_stop = pWeaponStat->GetWeaponAnim2LoopStop(); WeaponProperty.data.anim2_loop_bullet_fire = pWeaponStat->GetWeaponAnim2LoopFireTime(); WeaponProperty.data.anim_breakout_time = pWeaponStat->GetWeaponAnimBreakoutTime(); BitStream.Write( &WeaponProperty ); if ( BitStream.Version () >= 0x30 ) { BitStream.WriteBit ( g_pGame->GetJetpackWeaponEnabled ( (eWeaponType) i ) ); } } for (int i = WEAPONTYPE_PISTOL;i <= WEAPONTYPE_TEC9;i++) { sWeaponPropertySync WeaponProperty; BitStream.WriteBit ( true ); for (int j = 0; j <= 2;j++) { CWeaponStat* pWeaponStat = g_pGame->GetWeaponStatManager ()->GetWeaponStats( (eWeaponType)i, (eWeaponSkill)j ); WeaponProperty.data.weaponType = (int)pWeaponStat->GetWeaponType(); WeaponProperty.data.fAccuracy = pWeaponStat->GetAccuracy(); WeaponProperty.data.fMoveSpeed = pWeaponStat->GetMoveSpeed(); WeaponProperty.data.fTargetRange = pWeaponStat->GetTargetRange(); WeaponProperty.data.fWeaponRange = pWeaponStat->GetWeaponRange(); WeaponProperty.data.nAmmo = pWeaponStat->GetMaximumClipAmmo(); WeaponProperty.data.nDamage = pWeaponStat->GetDamagePerHit(); WeaponProperty.data.nFlags = pWeaponStat->GetFlags(); WeaponProperty.data.anim_loop_start = pWeaponStat->GetWeaponAnimLoopStart(); WeaponProperty.data.anim_loop_stop = pWeaponStat->GetWeaponAnimLoopStop(); WeaponProperty.data.anim_loop_bullet_fire = pWeaponStat->GetWeaponAnimLoopFireTime(); WeaponProperty.data.anim2_loop_start = pWeaponStat->GetWeaponAnim2LoopStart(); WeaponProperty.data.anim2_loop_stop = pWeaponStat->GetWeaponAnim2LoopStop(); WeaponProperty.data.anim2_loop_bullet_fire = pWeaponStat->GetWeaponAnim2LoopFireTime(); WeaponProperty.data.anim_breakout_time = pWeaponStat->GetWeaponAnimBreakoutTime(); BitStream.Write( &WeaponProperty ); } if ( BitStream.Version () >= 0x36 ) { BitStream.WriteBit ( g_pGame->GetJetpackWeaponEnabled ( (eWeaponType) i ) ); } } if ( BitStream.Version () >= 0x30 ) { for (int i = WEAPONTYPE_CAMERA; i <= WEAPONTYPE_PARACHUTE; i++) { bool bEnabled; bEnabled = g_pGame->GetJetpackWeaponEnabled ( (eWeaponType) i ); BitStream.WriteBit ( bEnabled ); } } multimap< unsigned short, CBuildingRemoval* >::const_iterator iter = g_pGame->GetBuildingRemovalManager ( )->IterBegin(); for (; iter != g_pGame->GetBuildingRemovalManager ( )->IterEnd();++iter) { CBuildingRemoval * pBuildingRemoval = (*iter).second; BitStream.WriteBit( true ); BitStream.Write( pBuildingRemoval->GetModel ( ) ); BitStream.Write( pBuildingRemoval->GetRadius ( ) ); BitStream.Write( pBuildingRemoval->GetPosition ( ).fX ); BitStream.Write( pBuildingRemoval->GetPosition ( ).fY ); BitStream.Write( pBuildingRemoval->GetPosition ( ).fZ ); if ( BitStream.Version() >= 0x039 ) { BitStream.Write ( pBuildingRemoval->GetInterior ( ) ); } } BitStream.WriteBit( false ); if ( BitStream.Version () >= 0x25 ) { bool bOcclusionsEnabled = g_pGame->GetOcclusionsEnabled (); BitStream.WriteBit( bOcclusionsEnabled ); } return true; }
bool CKeysyncPacket::Write ( NetBitStreamInterface& BitStream ) const { // Got a player to write? if ( m_pSourceElement ) { CPlayer * pSourcePlayer = static_cast < CPlayer * > ( m_pSourceElement ); CVehicle* pVehicle = pSourcePlayer->GetOccupiedVehicle (); // Write the source player id ElementID PlayerID = pSourcePlayer->GetID (); BitStream.WriteCompressed ( PlayerID ); // Write the keysync data const CControllerState& ControllerState = pSourcePlayer->GetPad ()->GetCurrentControllerState (); const CControllerState& LastControllerState = pSourcePlayer->GetPad ()->GetLastControllerState (); WriteSmallKeysync ( ControllerState, LastControllerState, BitStream ); // Flags SKeysyncFlags flags; flags.data.bIsDucked = ( pSourcePlayer->IsDucked () == true ); flags.data.bIsChoking = ( pSourcePlayer->IsChoking () == true ); flags.data.bAkimboTargetUp = ( pSourcePlayer->IsAkimboArmUp () == true ); flags.data.bSyncingVehicle = ( pVehicle != NULL && pSourcePlayer->GetOccupiedVehicleSeat () == 0 ); // Write the flags BitStream.Write ( &flags ); // If he's shooting if ( ControllerState.ButtonCircle ) { // Write his current weapon slot unsigned int uiSlot = pSourcePlayer->GetWeaponSlot (); SWeaponSlotSync slot; slot.data.uiSlot = uiSlot; BitStream.Write ( &slot ); if ( CWeaponNames::DoesSlotHaveAmmo ( uiSlot ) ) { // Write his ammo in clip SWeaponAmmoSync ammo ( pSourcePlayer->GetWeaponType (), false, true ); ammo.data.usAmmoInClip = pSourcePlayer->GetWeaponAmmoInClip (); BitStream.Write ( &ammo ); // Write the weapon aim data SWeaponAimSync aim ( 0.0f ); aim.data.vecOrigin = pSourcePlayer->GetSniperSourceVector (); pSourcePlayer->GetTargettingVector ( aim.data.vecTarget ); aim.data.fArm = pSourcePlayer->GetAimDirection (); BitStream.Write ( &aim ); // Write the driveby aim directoin BitStream.Write ( pSourcePlayer->GetDriveByDirection () ); } else { pSourcePlayer->SetWeaponAmmoInClip ( 1 ); pSourcePlayer->SetWeaponTotalAmmo ( 1 ); } } // If he's in a vehicle, read out the small vehicle specific data if ( flags.data.bSyncingVehicle ) { WriteVehicleSpecific ( pVehicle, BitStream ); if ( pVehicle->GetUpgrades ()->HasUpgrade ( 1087 ) ) // Hydraulics? { BitStream.Write ( ControllerState.RightStickX ); BitStream.Write ( ControllerState.RightStickY ); } if ( pVehicle->GetVehicleType () == VEHICLE_PLANE || pVehicle->GetVehicleType () == VEHICLE_HELI ) { BitStream.WriteBit ( ControllerState.LeftShoulder2 != 0); BitStream.WriteBit ( ControllerState.RightShoulder2 != 0); } } return true; } return false; }
bool CLuaArgument::WriteToBitStream ( NetBitStreamInterface& bitStream, CFastHashMap < CLuaArguments*, unsigned long > * pKnownTables ) const { SLuaTypeSync type; switch ( GetType () ) { // Nil type case LUA_TNIL: { type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); break; } // Boolean type case LUA_TBOOLEAN: { type.data.ucType = LUA_TBOOLEAN; bitStream.Write ( &type ); // Write the boolean to it bitStream.WriteBit ( GetBoolean () ); break; } // Table argument case LUA_TTABLE: { ulong* pTableId; if ( pKnownTables && ( pTableId = MapFind ( *pKnownTables, m_pTableData ) ) ) { // Self-referencing table type.data.ucType = LUA_TTABLEREF; bitStream.Write ( &type ); bitStream.WriteCompressed ( *pTableId ); } else { type.data.ucType = LUA_TTABLE; bitStream.Write ( &type ); // Write the subtable to the bitstream m_pTableData->WriteToBitStream ( bitStream, pKnownTables ); } break; } // Number argument? case LUA_TNUMBER: { type.data.ucType = LUA_TNUMBER; bitStream.Write ( &type ); if ( bitStream.Version() < 0x59 ) { // Old way int iNumber; if ( !ShouldUseInt( GetNumber(), &iNumber ) ) { bitStream.WriteBit ( true ); bitStream.Write ( static_cast < float > ( GetNumber() ) ); } else { bitStream.WriteBit ( false ); bitStream.WriteCompressed ( iNumber ); } } else { // New way - Maybe use double to better preserve > 32bit numbers int iNumber; float fNumber; double dNumber; EDataType dataType = GetDataTypeToUse( GetNumber(), &iNumber, &fNumber, &dNumber ); if ( dataType == DATA_TYPE_INT ) { bitStream.WriteBit ( false ); bitStream.WriteCompressed ( iNumber ); } else if ( dataType == DATA_TYPE_FLOAT ) { bitStream.WriteBit ( true ); bitStream.WriteBit ( false ); bitStream.Write ( fNumber ); } else { bitStream.WriteBit ( true ); bitStream.WriteBit ( true ); bitStream.Write ( dNumber ); } } break; } // String argument case LUA_TSTRING: { // Grab the string and its length. Is it short enough to be sendable? const char* szTemp = m_strString.c_str (); size_t sizeTemp = m_strString.length (); unsigned short usLength = static_cast < unsigned short > ( sizeTemp ); if ( sizeTemp == usLength ) { // This is a string argument type.data.ucType = LUA_TSTRING; bitStream.Write ( &type ); // Write its length bitStream.WriteCompressed ( usLength ); // Write the content too if it's not empty if ( usLength > 0 ) { bitStream.Write ( szTemp, usLength ); } } else { // This is a long string argument type.data.ucType = LUA_TSTRING_LONG; bitStream.Write ( &type ); // Write its length uint uiLength = sizeTemp; bitStream.WriteCompressed ( uiLength ); // Write the content too if it's not empty if ( uiLength > 0 ) { bitStream.AlignWriteToByteBoundary (); bitStream.Write ( szTemp, uiLength ); } } break; } // Element packet case LUA_TLIGHTUSERDATA: case LUA_TUSERDATA: { // Got a valid element to send? CClientEntity* pElement = GetElement (); if ( pElement ) { // Clientside element? if ( !pElement->IsLocalEntity () ) { type.data.ucType = LUA_TLIGHTUSERDATA; bitStream.Write ( &type ); bitStream.Write ( pElement->GetID () ); } else { // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } } else { // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } break; } // Unpacketizable type. default: { // Unpacketizable LogUnableToPacketize ( "Couldn't packetize argument list, unknown type specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } } // Success return true; }
bool CLuaArgument::WriteToBitStream ( NetBitStreamInterface& bitStream, CFastHashMap < CLuaArguments*, unsigned long > * pKnownTables ) const { SLuaTypeSync type; switch ( GetType () ) { // Nil type case LUA_TNIL: { type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); break; } // Boolean type case LUA_TBOOLEAN: { type.data.ucType = LUA_TBOOLEAN; bitStream.Write ( &type ); // Write the boolean to it bitStream.WriteBit ( GetBoolean () ); break; } // Table argument case LUA_TTABLE: { ulong* pThingy; if ( pKnownTables && ( pThingy = MapFind ( *pKnownTables, m_pTableData ) ) ) { // Self-referencing table type.data.ucType = LUA_TTABLEREF; bitStream.Write ( &type ); bitStream.WriteCompressed ( *pThingy ); } else { type.data.ucType = LUA_TTABLE; bitStream.Write ( &type ); // Write the subtable to the bitstream m_pTableData->WriteToBitStream ( bitStream, pKnownTables ); } break; } // Number argument? case LUA_TNUMBER: { type.data.ucType = LUA_TNUMBER; bitStream.Write ( &type ); float fNumber = static_cast < float > ( GetNumber () ); long lNumber = static_cast < long > ( fNumber ); float fNumberInteger = static_cast < float > ( lNumber ); // Check if the number is an integer and can fit a long datatype if ( fabs ( fNumber ) > fabs ( fNumberInteger + 1 ) || fabs ( fNumber - fNumberInteger ) >= FLOAT_EPSILON ) { bitStream.WriteBit ( true ); bitStream.Write ( fNumber ); } else { bitStream.WriteBit ( false ); bitStream.WriteCompressed ( lNumber ); } break; } // String argument case LUA_TSTRING: { // Grab the string and its length. Is it short enough to be sendable? const char* szTemp = m_strString.c_str (); size_t sizeTemp = m_strString.length (); unsigned short usLength = static_cast < unsigned short > ( sizeTemp ); if ( sizeTemp == usLength ) { // This is a string argument type.data.ucType = LUA_TSTRING; bitStream.Write ( &type ); // Write its length bitStream.WriteCompressed ( usLength ); // Write the content too if it's not empty if ( usLength > 0 ) { bitStream.Write ( szTemp, usLength ); } } else if ( sizeTemp > 65535 && bitStream.Version () >= 0x027 && g_pGame->CalculateMinClientRequirement () >= LONG_STRING_MIN_VERSION ) { // This is a long string argument type.data.ucType = LUA_TSTRING_LONG; bitStream.Write ( &type ); // Write its length uint uiLength = sizeTemp; bitStream.WriteCompressed ( uiLength ); // Write the content too if it's not empty if ( uiLength > 0 ) { bitStream.AlignWriteToByteBoundary (); bitStream.Write ( szTemp, uiLength ); } } else { // Too long string LogUnableToPacketize ( "Couldn't packetize argument list. Invalid string specified, limit is 65535 characters." " To use longer strings, set script <min_mta_version> to " LONG_STRING_MIN_VERSION " or higher." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } break; } // Element argument case LUA_TLIGHTUSERDATA: { // Grab the element from this userdata pointer. Valid and has a synced element ID? CElement* pElement = GetElement (); if ( pElement && pElement->GetID () != INVALID_ELEMENT_ID ) { // Write its ID type.data.ucType = LUA_TLIGHTUSERDATA; bitStream.Write ( &type ); bitStream.Write ( pElement->GetID () ); } else { // Jax: this just spams the script debugger, it's not really neccesary // LogUnableToPacketize ( "Couldn't packetize argument list, invalid element specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } break; } // Unpacketizable type. default: { // Unpacketizable LogUnableToPacketize ( "Couldn't packetize argument list, unknown type specified." ); // Write a nil though so other side won't get out of sync type.data.ucType = LUA_TNIL; bitStream.Write ( &type ); return false; } } // Success return true; }