📄 netconnection.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifdef _USE_TGE_NETCONNTION_
#include "platform/platform.h"
#include "core/dnet.h"
#include "console/simBase.h"
#include "sim/netConnection.h"
#include "core/bitStream.h"
#include "sim/pathManager.h"
#include "core/fileStream.h"
#include "core/resManager.h"
#include "sim/pathManager.h"
#include "console/consoleTypes.h"
#include "sim/netInterface.h"
#include <stdarg.h>
S32 gNetBitsSent = 0;
extern S32 gNetBitsReceived;
U32 gGhostUpdates = 0;
enum NetConnectionConstants {
PingTimeout = 4500, ///< milliseconds
DefaultPingRetryCount = 15,
};
SimObjectPtr<NetConnection> NetConnection::mServerConnection;
SimObjectPtr<NetConnection> NetConnection::mLocalClientConnection;
//----------------------------------------------------------------------
/// ConnectionMessageEvent
///
/// This event is used inside by the connection and subclasses to message
/// itself when sequencing events occur. Right now, the message event
/// only uses 6 bits to transmit the message, so
class ConnectionMessageEvent : public NetEvent
{
U32 sequence;
U32 message;
U32 ghostCount;
public:
ConnectionMessageEvent(U32 msg=0, U32 seq=0, U32 gc=0)
{ message = msg; sequence = seq; ghostCount = gc;}
void pack(NetConnection *, BitStream *bstream)
{
bstream->write(sequence);
bstream->writeInt(message, 3);
bstream->writeInt(ghostCount, GhostConnection::GhostIdBitSize + 1);
}
void write(NetConnection *, BitStream *bstream)
{
bstream->write(sequence);
bstream->writeInt(message, 3);
bstream->writeInt(ghostCount, GhostConnection::GhostIdBitSize + 1);
}
void unpack(NetConnection *, BitStream *bstream)
{
bstream->read(&sequence);
message = bstream->readInt(3);
ghostCount = bstream->readInt(GhostConnection::GhostIdBitSize + 1);
}
void process(NetConnection *ps)
{
ps->handleConnectionMessage(message, sequence, ghostCount);
}
DECLARE_CONOBJECT(ConnectionMessageEvent);
};
IMPLEMENT_CO_NETEVENT_V1(ConnectionMessageEvent);
void NetConnection::sendConnectionMessage(U32 message, U32 sequence, U32 ghostCount)
{
postNetEvent(new ConnectionMessageEvent(message, sequence, ghostCount));
}
//--------------------------------------------------------------------
IMPLEMENT_CONOBJECT(NetConnection);
NetConnection* NetConnection::mConnectionList = NULL;
NetConnection* NetConnection::mHashTable[NetConnection::HashTableSize] = { NULL, };
bool NetConnection::mFilesWereDownloaded = false;
static inline U32 HashNetAddress(const NetAddress *addr)
{
return *((U32 *)addr->netNum) % NetConnection::HashTableSize;
}
NetConnection *NetConnection::lookup(const NetAddress *addr)
{
U32 hashIndex = HashNetAddress(addr);
for(NetConnection *walk = mHashTable[hashIndex]; walk; walk = walk->mNextTableHash)
if(Net::compareAddresses(addr, walk->getNetAddress()))
return walk;
return NULL;
}
void NetConnection::netAddressTableInsert()
{
U32 hashIndex = HashNetAddress(&mNetAddress);
mNextTableHash = mHashTable[hashIndex];
mHashTable[hashIndex] = this;
}
void NetConnection::netAddressTableRemove()
{
U32 hashIndex = HashNetAddress(&mNetAddress);
NetConnection **walk = &mHashTable[hashIndex];
while(*walk)
{
if(*walk == this)
{
*walk = mNextTableHash;
mNextTableHash = NULL;
return;
}
walk = &((*walk)->mNextTableHash);
}
}
void NetConnection::setNetAddress(const NetAddress *addr)
{
mNetAddress = *addr;
}
const NetAddress *NetConnection::getNetAddress()
{
return &mNetAddress;
}
void NetConnection::setSequence(U32 sequence)
{
mConnectSequence = sequence;
}
U32 NetConnection::getSequence()
{
return mConnectSequence;
}
static U32 gPacketRateToServer = 32;
static U32 gPacketUpdateDelayToServer = 32;
static U32 gPacketRateToClient = 10;
static U32 gPacketSize = 200;
void NetConnection::consoleInit()
{
Con::addVariable("pref::Net::PacketRateToServer", TypeS32, &gPacketRateToServer);
Con::addVariable("pref::Net::PacketRateToClient", TypeS32, &gPacketRateToClient);
Con::addVariable("pref::Net::PacketSize", TypeS32, &gPacketSize);
Con::addVariable("Stats::netBitsSent", TypeS32, &gNetBitsSent);
Con::addVariable("Stats::netBitsReceived", TypeS32, &gNetBitsReceived);
Con::addVariable("Stats::netGhostUpdates", TypeS32, &gGhostUpdates);
}
void NetConnection::checkMaxRate()
{
// Limit packet rate to server.
if(gPacketRateToServer > 32)
gPacketRateToServer = 32;
if(gPacketRateToServer < 8)
gPacketRateToServer = 8;
// Limit packet rate to client.
if(gPacketRateToClient > 32)
gPacketRateToClient = 32;
if(gPacketRateToClient < 1)
gPacketRateToClient = 1;
// Limit packet size.
if(gPacketSize > 450)
gPacketSize = 450;
if(gPacketSize < 100)
gPacketSize = 100;
gPacketUpdateDelayToServer = 1024 / gPacketRateToServer;
U32 toClientUpdateDelay = 1024 / gPacketRateToClient;
if(mMaxRate.updateDelay != toClientUpdateDelay || mMaxRate.packetSize != gPacketSize)
{
mMaxRate.updateDelay = toClientUpdateDelay;
mMaxRate.packetSize = gPacketSize;
mMaxRate.changed = true;
}
}
void NetConnection::setSendingEvents(bool sending)
{
AssertFatal(!mEstablished, "Error, cannot change event behavior after a connection has been established.");
mSendingEvents = sending;
}
void NetConnection::setTranslatesStrings(bool xl)
{
AssertFatal(!mEstablished, "Error, cannot change event behavior after a connection has been established.");
mTranslateStrings = xl;
if(mTranslateStrings)
mStringTable = new ConnectionStringTable(this);
}
void NetConnection::setNetClassGroup(U32 grp)
{
AssertFatal(!mEstablished, "Error, cannot change net class group after a connection has been established.");
mNetClassGroup = grp;
}
NetConnection::NetConnection()
{
mTranslateStrings = false;
mConnectSequence = 0;
mStringTable = NULL;
mSendingEvents = true;
mNetClassGroup = NetClassGroupGame;
AssertFatal(mNetClassGroup >= NetClassGroupGame && mNetClassGroup < NetClassGroupsCount,
"Invalid net event class type.");
mSimulatedPing = 0;
mSimulatedPacketLoss = 0;
#ifdef TORQUE_DEBUG_NET
mLogging = false;
#endif
mEstablished = false;
mLastUpdateTime = 0;
mRoundTripTime = 0;
mPacketLoss = 0;
mNextTableHash = NULL;
mSendDelayCredit = 0;
mConnectionState = NotConnected;
mCurrentDownloadingFile = NULL;
mCurrentFileBuffer = NULL;
mNextConnection = NULL;
mPrevConnection = NULL;
mNotifyQueueHead = NULL;
mNotifyQueueTail = NULL;
mCurRate.updateDelay = 102;
mCurRate.packetSize = 200;
mCurRate.changed = false;
mMaxRate.updateDelay = 102;
mMaxRate.packetSize = 200;
mMaxRate.changed = false;
checkMaxRate();
// event management data:
mNotifyEventList = NULL;
mSendEventQueueHead = NULL;
mSendEventQueueTail = NULL;
mUnorderedSendEventQueueHead = NULL;
mUnorderedSendEventQueueTail = NULL;
mWaitSeqEvents = NULL;
mNextSendEventSeq = FirstValidSendEventSeq;
mNextRecvEventSeq = FirstValidSendEventSeq;
mLastAckedEventSeq = -1;
// ghost management data:
mScopeObject = NULL;
mGhostingSequence = 0;
mGhosting = false;
mScoping = false;
mGhostArray = NULL;
mGhostRefs = NULL;
mGhostLookupTable = NULL;
mLocalGhosts = NULL;
mGhostsActive = 0;
mMissionPathsSent = false;
mDemoWriteStream = NULL;
mDemoReadStream = NULL;
mPingSendCount = 0;
mPingRetryCount = DefaultPingRetryCount;
mLastPingSendTime = Platform::getVirtualMilliseconds();
mCurrentDownloadingFile = NULL;
mCurrentFileBuffer = NULL;
mCurrentFileBufferSize = 0;
mCurrentFileBufferOffset = 0;
mNumDownloadedFiles = 0;
}
NetConnection::~NetConnection()
{
AssertFatal(mNotifyQueueHead == NULL, "Uncleared notifies remain.");
netAddressTableRemove();
dFree(mCurrentFileBuffer);
if(mCurrentDownloadingFile)
ResourceManager->closeStream(mCurrentDownloadingFile);
delete[] mLocalGhosts;
delete[] mGhostLookupTable;
delete[] mGhostRefs;
delete[] mGhostArray;
delete mStringTable;
if(mDemoWriteStream)
delete mDemoWriteStream;
if(mDemoReadStream)
ResourceManager->closeStream(mDemoReadStream);
}
NetConnection::PacketNotify::PacketNotify()
{
rateChanged = false;
maxRateChanged = false;
sendTime = 0;
eventList = 0;
ghostList = 0;
}
bool NetConnection::checkTimeout(U32 time)
{
#ifdef TORQUE_DEBUG
return false;/// TGE_Net 取消超时处理
#endif
if(!isNetworkConnection())
return false;
if(time > mLastPingSendTime + PingTimeout)
{
if(mPingSendCount >= mPingRetryCount)
return true;
mLastPingSendTime = time;
mPingSendCount++;
sendPingPacket();
}
return false;
}
void NetConnection::keepAlive()
{
mLastPingSendTime = Platform::getVirtualMilliseconds();
mPingSendCount = 0;
}
void NetConnection::handleConnectionEstablished()
{
}
//--------------------------------------------------------------------------
ConsoleMethod(NetConnection,transmitPaths,void,2,2,"conn.transmitPaths();")
{
argc; argv;
gServerPathManager->transmitPaths(object);
object->setMissionPathsSent(true);
}
ConsoleMethod(NetConnection,clearPaths,void,2,2,"conn.clearPaths();")
{
argc; argv;
object->setMissionPathsSent(false);
}
ConsoleMethod(NetConnection,getAddress,const char *,2,2,"Returns the address we're connected to.")
{
argc; argv;
if(object->isLocalConnection())
return "local";
char *buffer = Con::getReturnBuffer(256);
Net::addressToString(object->getNetAddress(), buffer);
return buffer;
}
ConsoleMethod(NetConnection,setSimulatedNetParams,void,4, 4,"(float packetLoss, int delay)")
{
argc;
object->setSimulatedNetParams(dAtof(argv[2]), dAtoi(argv[3]));
}
ConsoleMethod( NetConnection, getPing, S32, 2, 2, "conn.getPing()" )
{
argc; argv;
return( S32( object->getRoundTripTime() ) );
}
ConsoleMethod( NetConnection, getPacketLoss, S32, 2, 2, "conn.getPacketLoss()" )
{
argc; argv;
return( S32( 100 * object->getPacketLoss() ) );
}
ConsoleMethod( NetConnection, checkMaxRate, void, 2, 2, "conn.checkMaxRate()")
{
argc; argv;
object->checkMaxRate();
}
#ifdef TORQUE_DEBUG_NET
ConsoleMethod( NetConnection, setLogging, void, 3, 3, "conn.setLogging(bool)")
{
argc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -