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;
}