Exemple #1
0
// 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;
}
///////////////////////////////////////////////////////////////
//
// 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 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;
}