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 bitStream.Write ( (unsigned char) LUA_TNIL ); return false; } break; } // Element packet case LUA_TLIGHTUSERDATA: { // 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.WriteCompressed ( static_cast < ElementID > ( 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 CClientExplosionManager::Hook_ExplosionCreation ( CEntity* pGameExplodingEntity, CEntity* pGameCreator, const CVector& vecPosition, eExplosionType explosionType ) { CClientPlayer * pLocalPlayer = m_pManager->GetPlayerManager ()->GetLocalPlayer (); // Grab the entity responsible CClientEntity * pResponsible = NULL; CEntity* pResponsibleGameEntity = ( pGameExplodingEntity ) ? pGameExplodingEntity : pGameCreator; if ( pResponsibleGameEntity ) pResponsible = m_pManager->FindEntity ( pResponsibleGameEntity, false ); unsigned short usModel; if ( pResponsible && ( pResponsible->IsLocalEntity () || ( CStaticFunctionDefinitions::GetElementModel ( *pResponsible, usModel ) && CClientObjectManager::IsBreakableModel ( usModel ) ) ) ) return true; // Handle this explosion client side only if entity is local or breakable (i.e. barrel) eWeaponType explosionWeaponType; switch ( explosionType ) { case EXP_TYPE_GRENADE: { // Grenade type explosions from vehicles should only be freefall bombs // TODO: need a way to check if its a freefall bomb if creator is a ped if ( pGameCreator && pGameCreator->GetEntityType () == ENTITY_TYPE_VEHICLE ) explosionWeaponType = WEAPONTYPE_FREEFALL_BOMB; else explosionWeaponType = WEAPONTYPE_GRENADE; break; } case EXP_TYPE_MOLOTOV: explosionWeaponType = WEAPONTYPE_MOLOTOV; break; case EXP_TYPE_ROCKET: case EXP_TYPE_ROCKET_WEAK: explosionWeaponType = WEAPONTYPE_ROCKET; break; case EXP_TYPE_TANK_GRENADE: explosionWeaponType = WEAPONTYPE_TANK_GRENADE; break; default: explosionWeaponType = WEAPONTYPE_EXPLOSION; break; } // Got a responsible entity? if ( pResponsible ) { // Is the local player responsible for this? bool bLocal = ( ( pResponsible == pLocalPlayer ) || ( pResponsible == pLocalPlayer->GetOccupiedVehicle () ) || ( g_pClientGame->GetUnoccupiedVehicleSync ()->Exists ( static_cast < CDeathmatchVehicle * > ( pResponsible ) ) ) ); if ( bLocal ) { CClientEntity * pOriginSource = NULL; // Is this an exploding vehicle? if ( pGameExplodingEntity && pGameExplodingEntity->GetEntityType () == ENTITY_TYPE_VEHICLE ) { // Set our origin-source to the vehicle pOriginSource = m_pManager->FindEntity ( pGameExplodingEntity, false ); } // If theres other players, sync it relative to the closest (lag compensation) else if ( m_pManager->GetPlayerManager ()->Count () > 1 ) { switch ( explosionWeaponType ) { case WEAPONTYPE_ROCKET: case WEAPONTYPE_ROCKET_HS: { CClientPlayer * pPlayer = g_pClientGame->GetClosestRemotePlayer ( vecPosition, 200.0f ); if ( pPlayer ) { pOriginSource = pPlayer; } break; } } } // Request a new explosion g_pClientGame->SendExplosionSync ( vecPosition, explosionType, pOriginSource ); } } // All explosions are handled server side 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; }