mxoemu/Reality/Source/GameClient.cpp

685 lines
19 KiB
C++
Raw Normal View History

2009-08-11 12:17:38 +00:00
// *************************************************************************************************
// --------------------------------------
// Copyright (C) 2006-2010 Rajko Stojadinovic
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// *************************************************************************************************
#include "Common.h"
#include "GameClient.h"
#include "Timer.h"
#include "Util.h"
#include "MersenneTwister.h"
2009-08-12 19:55:32 +00:00
#include "SequencedPacket.h"
2009-08-17 23:43:22 +00:00
#include "RsiData.h"
#include "MarginSocket.h"
#include "MarginServer.h"
#include "Database/Database.h"
#include "Log.h"
2010-02-13 14:32:04 +00:00
#include "GameServer.h"
#include "GameSocket.h"
#include "EncryptedPacket.h"
2009-08-17 23:43:22 +00:00
#pragma pack(1)
2009-08-11 12:17:38 +00:00
GameClient::GameClient(shared_ptr<SocketAddress> address, GameSocket *sock)
2009-08-11 12:17:38 +00:00
{
2010-02-13 14:32:04 +00:00
m_sock = sock;
m_address = address;
m_serverSequence = 0;
m_serverCommandsSent = 0;
m_clientCommandsReceived = 0;
m_numPackets = 0;
m_clientPSS = 0;
m_lastClientSequence = 0;
m_validClient = true;
m_worldLoaded = false;
m_characterSpawned = false;
m_encryptionInitialized = false;
m_lastSimTimeMS = 0;
m_lastOrderedFlush = 0;
m_playerGoId=0;
2009-08-11 12:17:38 +00:00
}
GameClient::~GameClient()
{
2010-02-13 14:32:04 +00:00
if (m_playerGoId != 0)
{
2010-02-13 14:32:04 +00:00
sObjMgr.deallocatePlayer(m_playerGoId);
}
2010-02-13 14:32:04 +00:00
sObjMgr.clientSigningOff(this);
MarginSocket *marginConn = sMargin.GetSocketByCharacterUID(m_characterUID);
if (marginConn != NULL)
{
2010-02-13 14:32:04 +00:00
marginConn->ForceDisconnect();
}
2009-08-11 12:17:38 +00:00
}
void GameClient::HandlePacket( const char *pData, uint16 nLength )
2009-08-11 12:17:38 +00:00
{
2010-02-13 14:32:04 +00:00
if (nLength < 1 || m_validClient == false)
return;
2010-02-13 14:32:04 +00:00
m_lastActivity = getTime();
m_lastPacketReceivedMS = getMSTime();
m_numPackets++;
2009-08-11 12:17:38 +00:00
2010-02-13 14:32:04 +00:00
if (m_encryptionInitialized == false && pData[0] == 0 && nLength == 43)
{
ByteBuffer packetData;
packetData.append(pData,nLength);
packetData.rpos(0x0B);
2010-02-13 14:32:04 +00:00
if (packetData.remaining() < sizeof(m_characterUID))
{
2010-02-13 14:32:04 +00:00
m_validClient = false;
return;
}
2010-02-13 14:32:04 +00:00
packetData >> m_characterUID;
try
{
2010-02-13 14:32:04 +00:00
m_playerGoId = sObjMgr.allocatePlayer(this,m_characterUID);
}
catch (ObjectMgr::ObjectNotAvailable)
{
ERROR_LOG(format("InitialUDPPacket(%1%): Character doesn't exist") % Address() );
m_validClient = false;
return;
}
2010-02-13 14:32:04 +00:00
MarginSocket *marginConn = sMargin.GetSocketByCharacterUID(m_characterUID);
if (marginConn == NULL)
{
2010-02-13 14:32:04 +00:00
ERROR_LOG(format("InitialUDPPacket(%1%): Margin session not found") % Address() );
m_validClient = false;
return;
}
2010-02-13 14:32:04 +00:00
m_sessionId = marginConn->GetSessionId();
m_charWorldId = marginConn->GetWorldCharId();
//initialize encryptors with key from margin
vector<byte> twofishKey = marginConn->GetTwofishKey();
m_tfEngine.Initialize(&twofishKey[0], twofishKey.size());
//now we can verify if session key in this packet is correct
packetData.rpos(packetData.size()-TwofishCryptMethod::BLOCKSIZE);
if (packetData.remaining() < TwofishCryptMethod::BLOCKSIZE)
{
//wat
2010-02-13 14:32:04 +00:00
m_validClient=false;
marginConn->ForceDisconnect();
return;
}
vector<byte> encryptedSessionId(packetData.remaining());
packetData.read(&encryptedSessionId[0],encryptedSessionId.size());
ByteBuffer decryptedData = m_tfEngine.Decrypt(&encryptedSessionId[0],encryptedSessionId.size(),false);
uint32 recoveredSessionId=0;
decryptedData >> recoveredSessionId;
2010-02-13 14:32:04 +00:00
if (recoveredSessionId != m_sessionId)
{
2010-02-13 14:32:04 +00:00
ERROR_LOG(format("InitialUDPPacket(%1%): Session Key Mismatch") % Address() );
m_validClient = false;
marginConn->ForceDisconnect();
return;
}
2010-02-13 14:32:04 +00:00
m_encryptionInitialized=true;
//send latency/loss calibration heartbeats
const int numberOfBeats = 5;
for (int i=0;i<numberOfBeats;i++)
{
ByteBuffer beatPacket;
for (int j=0;j<numberOfBeats;j++)
{
beatPacket << uint8(0);
}
beatPacket << uint16(swap16(numberOfBeats));
m_sock->SendToBuf(*m_address, beatPacket.contents(), beatPacket.size(), 0);
}
//notify margin that udp session is established
2010-02-13 14:32:04 +00:00
if (marginConn->UdpReady(this) == false)
{
2010-02-13 14:32:04 +00:00
ERROR_LOG(format("InitialUDPPacket(%1%): Margin not ready for UDP connection") % Address() );
m_encryptionInitialized=false;
m_validClient = false;
marginConn->ForceDisconnect();
return;
}
2010-02-13 14:32:04 +00:00
sObjMgr.getGOPtr(m_playerGoId)->InitializeWorld();
FlushQueue();
}
2010-02-13 14:32:04 +00:00
if (m_worldLoaded == true && pData[0] != 0x01) // Ping...just reply with the same thing
2009-08-11 12:17:38 +00:00
{
m_sock->SendToBuf(*m_address, pData, nLength, 0);
2009-08-11 12:17:38 +00:00
}
else
{
2010-02-13 14:32:04 +00:00
if (pData[0] == 0x01 && m_encryptionInitialized==true)
2009-08-11 12:17:38 +00:00
{
2009-08-12 19:55:32 +00:00
SequencedPacket packetData=Decrypt(&pData[1],nLength-1);
2010-02-13 14:32:04 +00:00
ByteBuffer dataToParse;
2009-08-11 12:17:38 +00:00
2010-02-14 11:47:57 +00:00
uint32 pktsAcked = AcknowledgePacket(packetData.getRemoteSeq());
assert(pktsAcked <= 1);
2009-08-11 12:17:38 +00:00
2010-02-14 11:47:57 +00:00
uint8 firstByte = packetData.contents()[0];
//normal packet byte
if (firstByte==0x02)
2009-08-12 19:55:32 +00:00
{
2010-02-13 14:32:04 +00:00
dataToParse.append(&packetData.contents()[1],packetData.size()-1);
2009-08-12 19:55:32 +00:00
}
2010-02-13 14:32:04 +00:00
else
2009-08-12 19:55:32 +00:00
{
2010-02-14 15:35:36 +00:00
WARNING_LOG(format("(%1%) First byte of client packet isnt 0x02 !") % Address());
2010-02-13 14:32:04 +00:00
dataToParse.append(&packetData.contents()[0],packetData.size());
2009-08-17 23:43:22 +00:00
}
2010-02-14 15:35:36 +00:00
//DEBUG_LOG( format("(%s) Recv PSS: %x CSeq: %d SSeq: %d |%s|") % Address() % uint32(packetData.getPSS()) % packetData.getLocalSeq() % packetData.getRemoteSeq() % Bin2Hex(dataToParse) );
2010-02-14 11:47:57 +00:00
2010-02-13 14:32:04 +00:00
//add to need to ack list
PacketReceived(packetData.getLocalSeq());
if (m_clientPSS != packetData.getPSS())
2009-08-17 23:43:22 +00:00
{
2010-02-13 14:32:04 +00:00
PSSChanged(m_clientPSS,packetData.getPSS());
}
2010-02-13 14:32:04 +00:00
if (dataToParse.size() > 0)
{
2010-02-13 14:32:04 +00:00
HandleEncrypted(dataToParse);
}
2010-02-13 14:32:04 +00:00
FlushQueue();
}
}
}
2010-02-13 14:32:04 +00:00
void GameClient::HandleEncrypted( ByteBuffer &srcData )
{
ByteBuffer dataCopy(&srcData.contents()[srcData.rpos()],srcData.remaining());
int32 commandOffset = -1;
ByteBuffer zeroFourBlock;
2010-02-13 14:32:04 +00:00
//try to find 04 block
while (dataCopy.remaining() > 0)
{
uint8 theByte;
dataCopy >> theByte;
if (theByte == 0x04)
{
//reverse read of byte
dataCopy.rpos(dataCopy.rpos()-sizeof(theByte));
int32 thePos = dataCopy.rpos();
//try and parse
OrderedPacket testPacket;
bool parseSuccessfull = testPacket.FromBuffer(dataCopy);
if (parseSuccessfull == true && dataCopy.remaining() == 0)
{
2010-02-13 14:32:04 +00:00
dataCopy.rpos(thePos);
zeroFourBlock = ByteBuffer(&dataCopy.contents()[dataCopy.rpos()],dataCopy.remaining());
commandOffset=thePos;
break;
2009-08-11 12:17:38 +00:00
}
2010-02-13 14:32:04 +00:00
}
}
2009-08-17 23:43:22 +00:00
2010-02-13 14:32:04 +00:00
ByteBuffer otherBlock;
if (commandOffset < 0 || zeroFourBlock.size() < 1)
{
otherBlock = ByteBuffer(dataCopy.contents(),dataCopy.size());
}
else if (commandOffset > 0)
{
otherBlock = ByteBuffer(dataCopy.contents(),commandOffset);
}
2010-02-13 14:32:04 +00:00
if (otherBlock.size() > 0)
{
HandleOther(otherBlock);
}
if (zeroFourBlock.size() > 0)
{
HandleOrdered(zeroFourBlock);
}
}
2010-02-13 14:32:04 +00:00
void GameClient::HandleOther( ByteBuffer &otherData )
{
uint8 packetType;
otherData >> packetType;
otherData.rpos(otherData.rpos()-sizeof(packetType));
2010-02-13 14:32:04 +00:00
if (packetType == 0x03)
{
if (m_playerGoId == 0)
{
WARNING_LOG(format("HandleOther(%1%): 03 received but no player object to handle it") % this->Address() );
return;
}
sObjMgr.getGOPtr(m_playerGoId)->HandleStateUpdate(otherData);
}
else
{
WARNING_LOG(format("HandleOther(%1%): Received unknown packet type %2%") % this->Address() % Bin2Hex(otherData) );
}
}
2010-02-13 14:32:04 +00:00
bool msgblock_sequence_lessthan(MsgBlock s2, MsgBlock s1)
{
return ( (s1.sequenceId > s2.sequenceId) && (s1.sequenceId-s2.sequenceId <= 65536/2) ) ||
( (s2.sequenceId > s1.sequenceId) && (s2.sequenceId-s1.sequenceId > 65536/2) );
}
2010-02-13 14:32:04 +00:00
bool msgblock_sequence_greaterthan(MsgBlock s1, MsgBlock s2)
{
return ( (s1.sequenceId > s2.sequenceId) && (s1.sequenceId-s2.sequenceId <= 65536/2) ) ||
( (s2.sequenceId > s1.sequenceId) && (s2.sequenceId-s1.sequenceId > 65536/2) );
}
2010-02-13 14:32:04 +00:00
void GameClient::HandleOrdered( ByteBuffer &orderedData )
{
OrderedPacket bigPacket;
if (bigPacket.FromBuffer(orderedData) == false)
{
2010-02-14 15:35:36 +00:00
ERROR_LOG(format("(%1%) Error creating bigpacket from bytes %2%") % Address() % Bin2Hex(orderedData) );
2010-02-13 14:32:04 +00:00
return;
}
2010-02-13 14:32:04 +00:00
if (bigPacket.msgBlocks.size() < 1)
{
2010-02-14 15:35:36 +00:00
ERROR_LOG(format("(%1%) Bigpacket has no msgblocks") % Address());
2010-02-13 14:32:04 +00:00
return;
}
2010-02-13 14:32:04 +00:00
if (bigPacket.msgBlocks.size() > 1)
{
bigPacket.msgBlocks.sort(msgblock_sequence_lessthan);
}
2010-02-13 14:32:04 +00:00
for (list<MsgBlock>::iterator it1=bigPacket.msgBlocks.begin();it1!=bigPacket.msgBlocks.end();++it1)
{
2010-02-14 15:35:36 +00:00
DEBUG_LOG( format("(%s) 04 client order: %d, our order %d") % Address() % it1->sequenceId % m_clientCommandsReceived);
2010-02-13 14:32:04 +00:00
if ( isSequenceMoreRecent(it1->sequenceId,m_clientCommandsReceived,65536) == true || it1->sequenceId == m_clientCommandsReceived)
{
for (list<ByteBuffer>::iterator it2=it1->subPackets.begin();it2!=it1->subPackets.end();++it2)
{
2010-02-13 14:32:04 +00:00
if (m_playerGoId != 0)
{
2010-02-13 14:32:04 +00:00
sObjMgr.getGOPtr(m_playerGoId)->HandleCommand(*it2);
m_clientCommandsReceived++;
}
}
2010-02-13 14:32:04 +00:00
}
else
{
2010-02-14 15:35:36 +00:00
WARNING_LOG(format("(%1%) Client order %2% smaller than server order %3%") % Address() % it1->sequenceId % m_clientCommandsReceived);
2010-02-13 14:32:04 +00:00
}
}
}
SequencedPacket GameClient::Decrypt(const char *pData, uint16 nLength)
2010-02-13 14:32:04 +00:00
{
TwofishEncryptedPacket decryptedData(ByteBuffer(pData,nLength),m_tfEngine);
2010-02-13 14:32:04 +00:00
return SequencedPacket(decryptedData);
}
2010-02-13 14:32:04 +00:00
void GameClient::SendEncrypted(SequencedPacket withSequences)
{
if (!m_tfEngine.IsValid())
2010-02-13 14:32:04 +00:00
return;
TwofishEncryptedPacket withEncryption(withSequences.getDataWithHeader());
2010-02-13 14:32:04 +00:00
ByteBuffer sendMe;
sendMe << uint8(1);
sendMe.append(withEncryption.toCipherText(m_tfEngine));
2010-02-13 14:32:04 +00:00
m_sock->SendToBuf(*m_address, sendMe.contents(), sendMe.size(), 0);
2010-02-13 14:32:04 +00:00
}
void GameClient::PSSChanged( uint8 oldPSS,uint8 newPSS )
{
m_clientPSS = newPSS;
if (m_clientPSS == 0x01)
{
//skip straight to 0x07
2010-02-14 11:47:57 +00:00
m_clientPSS=0x07;
if (m_worldLoaded==false)
{
sObjMgr.getGOPtr(m_playerGoId)->SpawnSelf();
m_worldLoaded = true;
}
2010-02-13 14:32:04 +00:00
}
else if (m_clientPSS == 0x07)
{
2010-02-14 11:47:57 +00:00
if (m_worldLoaded==false)
{
sObjMgr.getGOPtr(m_playerGoId)->SpawnSelf();
m_worldLoaded = true;
}
2010-02-13 14:32:04 +00:00
}
else if (m_clientPSS == 0x7F)
{
if (m_worldLoaded==false)
{
sObjMgr.getGOPtr(m_playerGoId)->SpawnSelf();
m_worldLoaded = true;
}
2010-02-15 12:52:58 +00:00
if (m_characterSpawned == false)
{
sObjMgr.getGOPtr(m_playerGoId)->PopulateWorld();
m_characterSpawned = true;
}
2010-02-13 14:32:04 +00:00
}
}
2010-02-13 14:32:04 +00:00
void GameClient::MoveMsgsToQueue()
{
//first we send out all the 03
2010-02-15 12:52:58 +00:00
for (stateQueueType::iterator it=m_queuedStates.begin();it!=m_queuedStates.end();++it)
2010-02-13 14:32:04 +00:00
{
//consume an ack if we can
if (m_packetsToAck.size() > 0)
{
uint16 theClientSeq = m_packetsToAck.front();
m_packetsToAck.pop_front();
2010-02-15 12:52:58 +00:00
AddPacketToQueue(theClientSeq,true,it->stateData,it->noResend);
2010-02-13 14:32:04 +00:00
}
else
{
2010-02-15 12:52:58 +00:00
AddPacketToQueue(it->stateData,it->noResend);
2010-02-13 14:32:04 +00:00
}
}
//all queued 03s have been transferred to packet queue, clear the 03 queue
m_queuedStates.clear();
2010-02-14 15:35:36 +00:00
if (/*getMSTime() - m_lastOrderedFlush > 50*/1) //we will not send 04 packets more than 20 times a second
2010-02-13 14:32:04 +00:00
{
//send out subpackets, as much as we got, consuming as much acks as we can
while (m_queuedCommands.size() > 0)
{
MsgBlock currBlock;
currBlock.sequenceId = m_serverCommandsSent;
while (m_queuedCommands.size() > 0)
{
2010-02-13 14:32:04 +00:00
ByteBuffer packetStaticBuf;
try
{
2010-02-13 14:32:04 +00:00
packetStaticBuf = m_queuedCommands.front()->toBuf();
}
2010-02-13 14:32:04 +00:00
catch (MsgBaseClass::PacketNoLongerValid)
{
2010-02-13 14:32:04 +00:00
//just remove the command and go to the next one
m_queuedCommands.front().reset();
m_queuedCommands.pop_front();
}
2010-02-13 14:32:04 +00:00
currBlock.subPackets.push_back(packetStaticBuf);
m_serverCommandsSent++;
m_queuedCommands.front().reset();
m_queuedCommands.pop_front();
if (m_queuedCommands.size() < 1 ||
2010-02-14 15:35:36 +00:00
(currBlock.GetTotalSize() + packetStaticBuf.size() >= 1000) )
{
2010-02-13 14:32:04 +00:00
break;
}
}
2010-02-13 14:32:04 +00:00
//consume an ack if we can
if (m_packetsToAck.size() > 0)
2009-08-12 19:55:32 +00:00
{
2010-02-13 14:32:04 +00:00
uint16 theClientSeq = m_packetsToAck.front();
m_packetsToAck.pop_front();
2009-08-11 12:17:38 +00:00
2010-02-14 15:35:36 +00:00
AddPacketToQueue(theClientSeq,true,make_shared<OrderedPacket>(currBlock));
2009-08-11 12:17:38 +00:00
}
2010-02-13 14:32:04 +00:00
else
2009-08-12 19:55:32 +00:00
{
2010-02-14 15:35:36 +00:00
AddPacketToQueue(make_shared<OrderedPacket>(currBlock));
2009-08-12 19:55:32 +00:00
}
2009-08-11 12:17:38 +00:00
}
2010-02-13 14:32:04 +00:00
m_lastOrderedFlush = getMSTime();
}
2009-08-11 12:17:38 +00:00
2010-02-13 14:32:04 +00:00
//we ran out of packets but there are still more acks to be sent ?
if (m_packetsToAck.size() > 0)
{
for (deque<uint16>::iterator it=m_packetsToAck.begin();it!=m_packetsToAck.end();++it)
2009-08-11 12:17:38 +00:00
{
2010-02-14 15:35:36 +00:00
AddPacketToQueue(*it,true,make_shared<EmptyMsg>());
2009-08-11 12:17:38 +00:00
}
2010-02-13 14:32:04 +00:00
m_packetsToAck.clear();
2009-08-11 12:17:38 +00:00
}
}
2010-02-13 14:32:04 +00:00
void GameClient::FlushQueue()
2009-08-11 12:17:38 +00:00
{
2010-02-13 14:32:04 +00:00
MoveMsgsToQueue();
2009-08-11 12:17:38 +00:00
2010-02-13 14:32:04 +00:00
for(sendQueueList::iterator it=m_sendQueue.begin();it!=m_sendQueue.end();)
{
//skip sent packets
if (it->sent==true)
{
++it;
continue;
}
2010-02-13 14:32:04 +00:00
//serialize data from dynamic packet to a static one
ByteBuffer serializedData;
try
{
serializedData=it->theData->toBuf();
}
catch (MsgBaseClass::PacketNoLongerValid)
{
serializedData.clear();
//remove data from packet in queue, this will leave it to still have an ack if needed
it->theData.reset(new EmptyMsg());
}
2010-02-14 11:47:57 +00:00
ByteBuffer outputData;
//we send simtime synchronization only in the first packet (anything else seems to break the game)
uint32 currTimeMS = getMSTime();
if ( /*(*/m_lastSimTimeMS==0 /*|| currTimeMS-m_lastSimTimeMS>1000)
&& serializedData.size() > 0
&& dynamic_pointer_cast<OrderedPacket>(it->theData) != NULL*/)
{
m_lastSimTimeMS = getMSTime();
outputData << uint8(0x82);
//theirs ticks at 64hz, ours ticks at 1000
double preciseInterval = double(m_lastSimTimeMS)/double(1000/64);
uint32 simTimeToSend = uint32(preciseInterval);
outputData << uint32(simTimeToSend);
}
else
{
//nosimtime byte
outputData << uint8(0x02);
}
//append that to our simtime or nosimtime byte
2010-02-13 14:32:04 +00:00
if (serializedData.size() > 0)
{
outputData.append(serializedData.contents(),serializedData.size());
}
else if (it->ack == false)
{
//if no ack, and data is 0, no reason to send this packet, so remove from queue and carry on
it=m_sendQueue.erase(it);
continue;
}
//prepend sequences
2010-02-14 11:47:57 +00:00
SequencedPacket prepended(it->server_sequence,it->client_sequence,it->clientPSS,outputData);
2010-02-13 14:32:04 +00:00
SendEncrypted(prepended);
2010-02-14 15:35:36 +00:00
// DEBUG_LOG(format("(%s) Flush PSS: %x SSeq: %d CSeq: %d |%s|") % Address() % uint32(prepended.getPSS()) % prepended.getLocalSeq() % prepended.getRemoteSeq() % Bin2Hex(prepended));
2010-02-13 14:32:04 +00:00
//mark packet as sent
it->sent=true;
it->msTimeSent=getMSTime();
2010-02-15 12:52:58 +00:00
//if packet is non resendable, remove it
if (it->noResends==true)
it=m_sendQueue.erase(it);
else
++it;
2010-02-13 14:32:04 +00:00
}
2009-08-11 12:17:38 +00:00
}
2010-02-13 14:32:04 +00:00
void GameClient::CheckAndResend()
{
2010-02-13 14:32:04 +00:00
bool modified = false;
for(sendQueueList::iterator it=m_sendQueue.begin();it!=m_sendQueue.end();)
{
2010-02-13 14:32:04 +00:00
//skip unsent packets
if (it->sent == false)
{
2010-02-13 14:32:04 +00:00
++it;
continue;
}
bool deleted = false;
uint32 currTime = getMSTime();
if (currTime - it->msTimeSent > 200) //200 is timeout for resend
2010-02-13 14:32:04 +00:00
{
//client obviously doesnt want to ack this packet
if (it->resentCounter > 10)
{
2010-02-13 14:32:04 +00:00
ByteBuffer resentPacketDumpedData;
try
{
2010-02-13 14:32:04 +00:00
resentPacketDumpedData = it->theData->toBuf();
}
2010-02-13 14:32:04 +00:00
catch (MsgBaseClass::PacketNoLongerValid)
{
2010-02-14 15:35:36 +00:00
INFO_LOG(format("(%1%) Resent packet %2%'s data is no longer valid") % Address() % it->server_sequence);
}
2010-02-14 15:35:36 +00:00
// INFO_LOG(format("(%1%) Doesn't want packet %2% of size %3%") % Address() % it->server_sequence % resentPacketDumpedData.size());
2010-02-13 14:32:04 +00:00
if (resentPacketDumpedData.size() > 1000)
{
2010-02-14 15:35:36 +00:00
WARNING_LOG(format("(%1%) WTF, WHY IS THIS SO BIG, %2%") % Address() % Bin2Hex(resentPacketDumpedData) );
}
2010-02-13 14:32:04 +00:00
it=m_sendQueue.erase(it);
deleted=true;
}
else
{
2010-02-14 11:47:57 +00:00
bool subdivided=false;
//is it a 04 packet ?
shared_ptr<OrderedPacket> daPacket = dynamic_pointer_cast<OrderedPacket>(it->theData);
2010-02-14 15:35:36 +00:00
if (daPacket != NULL && daPacket->msgBlocks.size() == 1)
2010-02-14 11:47:57 +00:00
{
2010-02-14 15:35:36 +00:00
DEBUG_LOG(format("(%1%) Packet %2% is a 04 packet, with %3% msgblocks %4% msgs(1)") % Address() % it->server_sequence % daPacket->msgBlocks.size() % daPacket->msgBlocks.front().subPackets.size());
2010-02-14 11:47:57 +00:00
shared_ptr<OrderedPacket> newPacket(new OrderedPacket());
for (list<MsgBlock>::iterator blockPtr=daPacket->msgBlocks.begin();blockPtr!=daPacket->msgBlocks.end();++blockPtr)
{
MsgBlock currBlock = *blockPtr;
//send the same subpackets only in smaller chunks
uint16 altCommandsSent = currBlock.sequenceId;
if (currBlock.subPackets.size() > 4)
{
int numAtATime = 2;
if (currBlock.subPackets.size() >= 12)
{
numAtATime = 4;
}
else if (currBlock.subPackets.size() >= 6)
{
numAtATime = 3;
}
for (;;)
{
MsgBlock newBlock;
newBlock.sequenceId = altCommandsSent;
for (int i=0;i<numAtATime;i++)
{
if (currBlock.subPackets.size() < 1)
break;
newBlock.subPackets.push_back(currBlock.subPackets.front());
altCommandsSent++;
currBlock.subPackets.pop_front();
}
if (newBlock.subPackets.size() < 1)
break;
newPacket->msgBlocks.push_back(newBlock);
}
}
}
if (newPacket->msgBlocks.size() > 1)
{
uint16 oldServerSeq = it->server_sequence;
uint16 oldClientSeq = it->client_sequence;
uint8 oldClientPSS = it->clientPSS;
bool oldAck = it->ack;
it = m_sendQueue.erase(it);
deleted=true;
2010-02-14 15:35:36 +00:00
INFO_LOG(format("(%1%) Subdivided packet sseq %2% from 1 msgblocks to %3% msgblocks") % Address() % oldServerSeq % newPacket->msgBlocks.size());
2010-02-14 11:47:57 +00:00
//reverse iterator because push_front inserts into reverse anyway
for (list<MsgBlock>::reverse_iterator hurr=newPacket->msgBlocks.rbegin();hurr!=newPacket->msgBlocks.rend();++hurr)
{
uint16 oldSeqz = m_serverSequence;
2010-02-14 11:47:57 +00:00
increaseServerSequence();
m_sendQueue.push_front( PacketInQueue(oldClientPSS,m_serverSequence,oldClientSeq,oldAck,shared_ptr<OrderedPacket>(new OrderedPacket(*hurr))) );
}
subdivided=true;
}
}
if (subdivided==false)
{
it->resentCounter++;
it->sent = false;
it->msTimeSent=0;
uint16 oldSeq = it->server_sequence;
increaseServerSequence();
it->server_sequence = m_serverSequence;
}
2010-02-14 15:35:36 +00:00
//DEBUG_LOG(format("(%1%) Resending packet sseq %2% under new sseq %3%") % Address() % oldSeq % it->server_sequence);
2010-02-13 14:32:04 +00:00
modified = true;
}
}
2010-02-13 14:32:04 +00:00
if (deleted==false)
{
++it;
}
}
if (modified == true)
{
FlushQueue();
}
}