NetConnection

Engine/source/sim/netConnection.h

Torque network connection.

More...

Classes:

class

Structure to track ghost references in packets.

class

Structure to track ghost-always objects and their ghost indices.

class

Structure to track packets and what we sent over them.

Ghost manager

enum
GhostConstants {
  GhostIdBitSize = 18
  MaxGhostCount = 1 << GhostIdBitSize
  GhostLookupTableSize = 1 << GhostIdBitSize
  GhostIndexBitSize = 4
}

Some configuration values.

enum
GhostStates {
  GhostAlwaysDone 
  ReadyForNormalGhosts 
  EndGhosting 
  GhostAlwaysStarting 
  SendNextDownloadRequest 
  FileDownloadSizeMessage 
  NumConnectionMessages 
}
bool

Are we ghosting to someone?

bool

Are we ghosting from someone?

Called by onRemove, to shut down the ghost subsystem.

Called when we're done with normal scoping.

Set the object around which we are currently scoping network traffic.

Get the object around which we are currently scoping network traffic.

Add an object to scope.

Add an object to scope, marking that it should always be scoped to this connection.

Mark an object that is being ghosted as not always needing to be scoped.

Get a NetObject* from a ghost ID (on client side).

Get a NetObject* from a ghost index (on the server side).

Get the ghost index corresponding to a given NetObject.

Move a GhostInfo into the nonzero portion of the list (so that we know to update it).

Move a GhostInfo into the zero portion of the list (so that we know not to update it).

Move a GhostInfo from the zero portion of the list to the free portion.

Move a GhostInfo from the free portion of the list to the zero portion.

Stop all ghosting activity and inform the other side about this.

Activate ghosting, once it's enabled.

bool

Are we ghosting?

Begin to stop ghosting an object.

Mark an object to be always ghosted. Index is the ghost index of the object.

sendConnectionMessage(U32 message, U32 sequence, U32 ghostCount)

Send ghost connection handshake message.

handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount)

Handle message from sendConnectionMessage().

ghostReadExtra(NetObject * , BitStream * , bool newGhost)
ghostPreRead(NetObject * , bool newGhost)

Called when 'EndGhosting' message is received from server.

Linked list of ghostInfos ghosted by this side of the connection.

Index in mGhostArray of first ghost with 0 update mask.

Index in mGhostArray of first free ghost.

bool

Am I currently ghosting objects?

bool

am I currently scoping objects?

Sequence number describing this ghosting session.

Local ghost for remote object.

Allocated array of ghostInfos. Null if ghostFrom is false.

Table indexed by object id to GhostInfo. Null if ghostFrom is false.

The object around which we are scoping this connection.

Sends a signal to any object that needs to wait till everything has been ghosted before performing an operation.

Demo Recording

enum
DemoBlockTypes {
  BlockTypePacket 
  BlockTypeSendPacket 
  NetConnectionBlockTypeCount 
}
enum
DemoConstants {
  MaxNumBlockTypes = 16
  MaxBlockSize = 0x1000
}

Global Connection List

Next item in list.

Previous item in list.

Statistics

State

NetRate
NetRate

If we're doing a "short circuited" connection, this stores a pointer to the other side.

Connection Table

We store our connections on a hash table so we can quickly find them.

File transfer

bool
startSendingFile(const char * fileName)

Start sending the specified file over the link.

chunkReceived(U8 * chunkData, U32 chunkLen)

Called when we receive a FileChunkEvent.

Get the next file...

Called when we finish downloading file data.

loadNextGhostAlwaysObject(bool hadNewFiles)

This is part of the file transfer logic; basically, we call this every time we finish downloading new files.

Vector< char * >

List of files missing for this connection.

Stream for currently uploading file (if any).

void *

Storage for currently downloading file.

Size of currently downloading file in bytes.

Our position in the currently downloading file in bytes.

Number of files we have downloaded.

Error storage for file transfers.

List of objects to ghost-always.

Public Types

enum
Constants {  HashTableSize = 127
}
enum
NetConnectionFlags {
  ConnectionToServer = BIT(0)
  ConnectionToClient = BIT(1)
  LocalClientConnection = BIT(2)
  NetworkConnection = BIT(3)
}
enum
NetConnectionState {
  NotConnected 
  AwaitingChallengeResponse 
  AwaitingConnectRequest 
  AwaitingConnectResponse 
  Connected 
}

Private Types

Parent 

Public Friends

Private Attributes

The NetClassGroup of this connection.

Public Static Attributes

Public Attributes

number of connection messages we've sent.

State of the connection, from NetConnectionState.

Head of packet notify list.

Tail of packet notify list.

Public Functions

checkPacketSend(bool force)
bool

returns true if the connection timed out

DECLARE_INSCOPE(NetAPI )
handleNotify(bool recvd)
handleStartupError(const char * errorString)
bool

Is the connection established?

onConnectionEstablished(bool isInitiator)
onDisconnect(const char * reason)

Called when the object is removed from the sim.

bool
readConnectAccept(BitStream * stream, const char ** errorString)
bool
readConnectRequest(BitStream * stream, const char ** errorString)
setGhostFrom(bool ghostFrom)

Sets whether ghosts transmit from this side of the connection.

setGhostTo(bool ghostTo)

Sets whether ghosts are allowed from the other side of the connection.

Sets the group of NetClasses this connection traffics in.

setProtocolVersion(U32 protocolVersion)

Call this if the "connection" is local to this app. This short-circuits the protocol layer.

setSendingEvents(bool sending)

Sets whether this side actually sends the events that are posted to it.

setSequence(U32 connectSequence)
setSimulatedNetParams(F32 packetLoss, U32 ping)

Sets whether this connection is capable of translating strings.

Detailed Description

Torque network connection.

Introduction

NetConnection is the glue that binds a networked Torque game together. It combines the low-level notify protocol implemented in ConnectionProtocol with a SimGroup to provide a powerful basis for implementing a multiplayer game protocol.

On top of this basis it implements several distinct subsystems:

  • Event manager, which is responsible for transmitting NetEvents over the wire. It deals with ensuring that the various types of NetEvents are delivered appropriately, and with notifying the event of its delivery status.

  • Move manager, which is responsible for transferring a Move to the server 32 times a second (on the client) and applying it to the control object (on the server).

  • Ghost manager, which is responsible for doing scoping calculations (on the server side) and transmitting most-recent ghost information to the client.

  • File transfer; it is often the case that clients will lack important files when connecting to a server which is running a mod or new map. This subsystem allows the server to transfer such files to the client.

  • Networked String Table; string data can easily soak up network bandwidth, so for efficiency, we implement a networked string table. We can then notify the connection of strings we will reference often, such as player names, and transmit only a tag, instead of the whole string.

  • Demo Recording is also implemented in NetConnection. A demo in Torque is a log of the network traffic between client and server; when a NetConnection records a demo, it simply logs this data to a file. When it plays a demo back, it replays the logged data.

  • The Connection Database is used to keep track of all the NetConnections; it can be iterated over (for instance, to send an event to all active connections), or queried by address.

On Events

The Event Manager is exposed to the outside world via postNetEvent(), which accepts NetEvents.

see:

NetEvent for a more thorough explanation of how to use events.

On Ghosting and Scoping

Ghosting is the most complex, and most powerful, part of Torque's networking capabilities. It allows the information sent to clients to be very precisely matched to what they need, so that no excess bandwidth is wasted. The control object's onCameraScopeQuery() is called, to determine scoping information for the client; then objects which are in scope are then transmitted to the client, prioritized by the results of their getPriority() method.

There is a cap on the maximum number of ghosts; ghost IDs are currently sent via a 12-bit field, ergo, there is a cap of 4096 objects ghosted per client. This can be easily raised; see the GhostConstants enum.

Each object ghosted is assigned a ghost ID; the client is only aware of the ghost ID. This acts to enhance game security, as it becomes difficult to map objects from one connection to another, or to reliably identify objects from ID alone. IDs are also reassigned based on need, making it hard to track objects that have fallen out of scope (as any object which the player shouldn't see would).

resolveGhost() is used on the client side, and resolveObjectFromGhostIndex() on the server side, to turn ghost IDs into object references.

The NetConnection is a SimGroup. On the client side, it contains all the objects which have been ghosted to that client. On the server side, it is empty; it can be used (typically in script) to hold objects related to the connection. For instance, you might place an observation camera in the NetConnnection. In both cases, when the connection is destroyed, so are the contained objects.

see:

NetObject, which is the superclass for ghostable objects, and ShapeBase, which is the base for player and vehicle classes.

Ghost manager

GhostConstants

Enumerator

GhostIdBitSize = 18
MaxGhostCount = 1 << GhostIdBitSize
GhostLookupTableSize = 1 << GhostIdBitSize
GhostIndexBitSize = 4

Some configuration values.

GhostStates

Enumerator

GhostAlwaysDone
ReadyForNormalGhosts
EndGhosting
GhostAlwaysStarting
SendNextDownloadRequest
FileDownloadSizeMessage
NumConnectionMessages
getGhostsActive()

isGhostingTo()

Are we ghosting to someone?

isGhostingFrom()

Are we ghosting from someone?

ghostOnRemove()

Called by onRemove, to shut down the ghost subsystem.

doneScopingScene()

Called when we're done with normal scoping.

This gives subclasses a chance to shove things into scope, such as the results of a sensor network calculation, that would otherwise be awkward to add.

Reimplemented by: GameConnection

setScopeObject(NetObject * object)

Set the object around which we are currently scoping network traffic.

getScopeObject()

Get the object around which we are currently scoping network traffic.

objectInScope(NetObject * object)

Add an object to scope.

objectLocalScopeAlways(NetObject * object)

Add an object to scope, marking that it should always be scoped to this connection.

objectLocalClearAlways(NetObject * object)

Mark an object that is being ghosted as not always needing to be scoped.

This undoes objectLocalScopeAlways(), but doesn't immediately flush it from scope.

Instead, the standard scoping mechanisms will clear it from scope when it is appropos to do so.

resolveGhost(S32 id)

Get a NetObject* from a ghost ID (on client side).

resolveObjectFromGhostIndex(S32 id)

Get a NetObject* from a ghost index (on the server side).

getGhostIndex(NetObject * object)

Get the ghost index corresponding to a given NetObject.

This is only meaningful on the server side.

ghostPushNonZero(GhostInfo * gi)

Move a GhostInfo into the nonzero portion of the list (so that we know to update it).

ghostPushToZero(GhostInfo * gi)

Move a GhostInfo into the zero portion of the list (so that we know not to update it).

ghostPushZeroToFree(GhostInfo * gi)

Move a GhostInfo from the zero portion of the list to the free portion.

ghostPushFreeToZero(GhostInfo * info)

Move a GhostInfo from the free portion of the list to the zero portion.

resetGhosting()

Stop all ghosting activity and inform the other side about this.

Turns off ghosting.

activateGhosting()

Activate ghosting, once it's enabled.

isGhosting()

Are we ghosting?

detachObject(GhostInfo * info)

Begin to stop ghosting an object.

setGhostAlwaysObject(NetObject * object, U32 index)

Mark an object to be always ghosted. Index is the ghost index of the object.

sendConnectionMessage(U32 message, U32 sequence, U32 ghostCount)

Send ghost connection handshake message.

As part of the ghost connection process, extensive hand-shaking must be performed.

This is done by passing ConnectionMessageEvents; this is a helper function to more effectively perform this task. Messages are dealt with by handleConnectionMessage().

Parameters:

message

One of GhostStates

sequence

A sequence number, if any.

ghostCount

A count of ghosts relating to this message.

handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount)

Handle message from sendConnectionMessage().

This is called to handle messages sent via sendConnectionMessage.

Parameters:

message

One of GhostStates

sequence

A sequence number, if any.

ghostCount

A count of ghosts relating to this message.

Reimplemented by: GameConnection

clearGhostInfo()

validateGhostArray()

ghostPacketDropped(PacketNotify * notify)

ghostPacketReceived(PacketNotify * notify)

ghostWritePacket(BitStream * bstream, PacketNotify * notify)

ghostReadPacket(BitStream * bstream)

freeGhostInfo(GhostInfo * )

ghostWriteStartBlock(ResizeBitStream * stream)

ghostReadStartBlock(BitStream * stream)

ghostWriteExtra(NetObject * , BitStream * )

Reimplemented by: GameConnection

ghostReadExtra(NetObject * , BitStream * , bool newGhost)

Reimplemented by: GameConnection

ghostPreRead(NetObject * , bool newGhost)

Reimplemented by: GameConnection

onEndGhosting()

Called when 'EndGhosting' message is received from server.

Reimplemented by: GameConnection

GhostInfo ** mGhostArray 

Linked list of ghostInfos ghosted by this side of the connection.

U32 mGhostZeroUpdateIndex 

Index in mGhostArray of first ghost with 0 update mask.

U32 mGhostFreeIndex 

Index in mGhostArray of first free ghost.

U32 mGhostsActive 
bool mGhosting 

Am I currently ghosting objects?

  • Track actve ghosts on client side

bool mScoping 

am I currently scoping objects?

U32 mGhostingSequence 

Sequence number describing this ghosting session.

NetObject ** mLocalGhosts 

Local ghost for remote object.

mLocalGhosts pointer is NULL if mGhostTo is false

GhostInfo * mGhostRefs 

Allocated array of ghostInfos. Null if ghostFrom is false.

GhostInfo ** mGhostLookupTable 

Table indexed by object id to GhostInfo. Null if ghostFrom is false.

SimObjectPtr< NetObject > mScopeObject 

The object around which we are scoping this connection.

This is usually the player object, or a related object, like a vehicle that the player is driving.

Signal< void()> smGhostAlwaysDone 

Sends a signal to any object that needs to wait till everything has been ghosted before performing an operation.

Demo Recording

DemoBlockTypes

Enumerator

BlockTypePacket
BlockTypeSendPacket
NetConnectionBlockTypeCount
DemoConstants

Enumerator

MaxNumBlockTypes = 16
MaxBlockSize = 0x1000
isRecording()

isPlayingBack()

getNextBlockType()

recordBlock(U32 type, U32 size, void * data)

handleRecordedBlock(U32 type, U32 size, void * data)

Reimplemented by: GameConnection

processNextBlock()

startDemoRecord(const char * fileName)

replayDemoRecord(const char * fileName)

startDemoRead()

stopRecording()

stopDemoPlayback()

writeDemoStartBlock(ResizeBitStream * stream)

Reimplemented from: ConnectionProtocol

Reimplemented by: GameConnection

readDemoStartBlock(BitStream * stream)

Reimplemented from: ConnectionProtocol

Reimplemented by: GameConnection

demoPlaybackComplete()

Reimplemented by: GameConnection

Stream * mDemoWriteStream 
Stream * mDemoReadStream 
U32 mDemoNextBlockType 
U32 mDemoNextBlockSize 
U32 mDemoWriteStartTime 
U32 mDemoReadStartTime 
U32 mDemoLastWriteTime 
U32 mDemoRealStartTime 

Event Manager

NetEventConstants

Enumerator

InvalidSendEventSeq = -1
FirstValidSendEventSeq = 0
postNetEvent(NetEvent * event)

Post an event to this connection.

eventOnRemove()

eventPacketDropped(PacketNotify * notify)

eventPacketReceived(PacketNotify * notify)

eventWritePacket(BitStream * bstream, PacketNotify * notify)

eventReadPacket(BitStream * bstream)

eventWriteStartBlock(ResizeBitStream * stream)

eventReadStartBlock(BitStream * stream)

NetEventNote * mSendEventQueueHead 
NetEventNote * mSendEventQueueTail 
NetEventNote * mUnorderedSendEventQueueHead 
NetEventNote * mUnorderedSendEventQueueTail 
NetEventNote * mWaitSeqEvents 
NetEventNote * mNotifyEventList 
bool mSendingEvents 
S32 mNextSendEventSeq 
S32 mNextRecvEventSeq 
S32 mLastAckedEventSeq 
FreeListChunker< NetEventNote > mEventNoteChunker 

Global Connection List

getNext()

getConnectionList()

NetConnection * mNextConnection 

Next item in list.

NetConnection * mPrevConnection 

Previous item in list.

NetConnection * mConnectionList 

Head of list.

Statistics

U32 mLastUpdateTime 

Last time a packet was sent in milliseconds.

F32 mRoundTripTime 
F32 mPacketLoss 
U32 mSimulatedPing 
F32 mSimulatedPacketLoss 

State

U32 mProtocolVersion 
U32 mSendDelayCredit 
U32 mConnectSequence 
U32 mAddressDigest [4]
bool mEstablished 
bool mMissionPathsSent 
NetRate mCurRate 
NetRate mMaxRate 
SimObjectPtr< NetConnection > mRemoteConnection 

If we're doing a "short circuited" connection, this stores a pointer to the other side.

NetAddress mNetAddress 

Timeout Management

U32 mPingSendCount 
U32 mPingRetryCount 
U32 mLastPingSendTime 

Connection Table

We store our connections on a hash table so we can quickly find them.

NetConnection * mNextTableHash 
NetConnection * mHashTable [HashTableSize]

Networked string table

mapString(U32 netId, NetStringHandle & string)

checkString(NetStringHandle & string, bool * isOnOtherSide)

getNetSendId(NetStringHandle & string)

confirmStringReceived(NetStringHandle & string, U32 index)

translateRemoteStringId(U32 id)

validateSendString(const char * str)

packString(BitStream * stream, const char * str)

unpackString(BitStream * stream, char readBuffer)

packNetStringHandleU(BitStream * stream, NetStringHandle & h)

unpackNetStringHandleU(BitStream * stream)

bool mTranslateStrings 
ConnectionStringTable * mStringTable 

File transfer

startSendingFile(const char * fileName)

Start sending the specified file over the link.

chunkReceived(U8 * chunkData, U32 chunkLen)

Called when we receive a FileChunkEvent.

sendNextFileDownloadRequest()

Get the next file...

sendFileChunk()

Post the next FileChunkEvent.

fileDownloadSegmentComplete()

Called when we finish downloading file data.

Reimplemented by: GameConnection

loadNextGhostAlwaysObject(bool hadNewFiles)

This is part of the file transfer logic; basically, we call this every time we finish downloading new files.

It attempts to load the GhostAlways objects; if they fail, it marks an error and we have chance to retry.

Vector< char * > mMissingFileList 

List of files missing for this connection.

The currently downloading file is always first in the list (ie, [0]).

Stream * mCurrentDownloadingFile 

Stream for currently uploading file (if any).

void * mCurrentFileBuffer 

Storage for currently downloading file.

U32 mCurrentFileBufferSize 

Size of currently downloading file in bytes.

U32 mCurrentFileBufferOffset 

Our position in the currently downloading file in bytes.

U32 mNumDownloadedFiles 

Number of files we have downloaded.

String mLastFileErrorBuffer 

Error storage for file transfers.

Vector< GhostSave > mGhostAlwaysSaveList 

List of objects to ghost-always.

Public Types

Constants

Enumerator

HashTableSize = 127
NetConnectionFlags

Enumerator

ConnectionToServer = BIT(0)
ConnectionToClient = BIT(1)
LocalClientConnection = BIT(2)
NetworkConnection = BIT(3)
NetConnectionState

Enumerator

NotConnected
AwaitingChallengeResponse

We've sent a challenge request, awaiting the response.

AwaitingConnectRequest

We've received a challenge request and sent a challenge response.

AwaitingConnectResponse

We've received a challenge response and sent a connect request.

Connected

We've accepted a connect request, or we've received a connect response accept.

Private Types

typedef SimGroup Parent 

Public Friends

Private Attributes

U32 mNetClassGroup 

The NetClassGroup of this connection.

BitSet32 mTypeFlags 

Protected Static Attributes

bool mFilesWereDownloaded 
SimObjectPtr< NetConnection > mLocalClientConnection 
SimObjectPtr< NetConnection > mServerConnection 

Protected Attributes

U32 mConnectLastSendTime 
U32 mConnectSendCount 

Public Static Attributes

String mErrorBuffer 

Public Attributes

U32 mConnectionSendCount 

number of connection messages we've sent.

U32 mConnectionState 

State of the connection, from NetConnectionState.

PacketNotify * mNotifyQueueHead 

Head of packet notify list.

PacketNotify * mNotifyQueueTail 

Tail of packet notify list.

Public Functions

NetConnection()

~NetConnection()

allocNotify()

Reimplemented by: GameConnection

canRemoteCreate()

Reimplemented by: GameConnection

checkMaxRate()

checkPacketSend(bool force)

checkTimeout(U32 time)

returns true if the connection timed out

connect(const NetAddress * address)

DECLARE_CONOBJECT(NetConnection )

DECLARE_INSCOPE(NetAPI )

getAddressDigest(U32 digest)

getConnectionState()

getCurRatePacketSize()

getMaxRatePacketSize()

getNetAddress()

getNetClassGroup()

getPacketLoss()

getProtocolVersion()

getRoundTripTime()

getSequence()

handleConnectionEstablished()

Reimplemented from: ConnectionProtocol

handleNotify(bool recvd)

Reimplemented from: ConnectionProtocol

handlePacket(BitStream * stream)

Reimplemented from: ConnectionProtocol

handleStartupError(const char * errorString)

Reimplemented by: GameConnection

isConnectionToServer()

isEstablished()

Is the connection established?

isLocalConnection()

isNetworkConnection()

keepAlive()

Reimplemented from: ConnectionProtocol

missionPathsSent()

onConnectionEstablished(bool isInitiator)

Reimplemented by: GameConnection

onConnectionRejected(const char * reason)

Reimplemented by: GameConnection

onConnectTimedOut()

Reimplemented by: GameConnection

onDisconnect(const char * reason)

Reimplemented by: GameConnection

onRemove()

Reimplemented from: SimGroup

Reimplemented by: GameConnection

onTimedOut()

Reimplemented by: GameConnection

processRawPacket(BitStream * stream)

Reimplemented from: ConnectionProtocol

readConnectAccept(BitStream * stream, const char ** errorString)

Reimplemented by: GameConnection

readConnectRequest(BitStream * stream, const char ** errorString)

Reimplemented by: GameConnection

sendDisconnectPacket(const char * reason)

sendPacket(BitStream * stream)

Reimplemented from: ConnectionProtocol

setAddressDigest(U32 digest)

setConnectionState(U32 state)

setEstablished()

setGhostFrom(bool ghostFrom)

Sets whether ghosts transmit from this side of the connection.

setGhostTo(bool ghostTo)

Sets whether ghosts are allowed from the other side of the connection.

setIsConnectionToServer()

setIsLocalClientConnection()

setMissionPathsSent(const bool s)

setNetAddress(const NetAddress * address)

setNetClassGroup(U32 group)

Sets the group of NetClasses this connection traffics in.

setNetworkConnection(bool net)

setProtocolVersion(U32 protocolVersion)

setRemoteConnectionObject(NetConnection * connection)

Call this if the "connection" is local to this app. This short-circuits the protocol layer.

setSendingEvents(bool sending)

Sets whether this side actually sends the events that are posted to it.

setSequence(U32 connectSequence)

setSimulatedNetParams(F32 packetLoss, U32 ping)

setTranslatesStrings(bool xl)

Sets whether this connection is capable of translating strings.

writeConnectAccept(BitStream * stream)

Reimplemented by: GameConnection

writeConnectRequest(BitStream * stream)

Reimplemented by: GameConnection

Public Static Functions

consoleInit()

filesWereDownloaded()

getConnectionToServer()

getErrorBuffer()

getLocalClientConnection()

lookup(const NetAddress * remoteAddress)

Find a NetConnection, if any, with the specified address.

setLastError(const char * fmt, ... )

setLocalClientConnection(NetConnection * conn)

Protected Functions

connectionError(const char * errorString)

Reimplemented by: GameConnection

getRemoteConnection()

packetDropped(PacketNotify * note)

Reimplemented by: GameConnection

packetReceived(PacketNotify * note)

Reimplemented by: GameConnection

readPacket(BitStream * bstream)

Reimplemented by: GameConnection

writePacket(BitStream * bstream, PacketNotify * note)

Reimplemented by: GameConnection