Torque3D Documentation / _generateds / netConnection.h

netConnection.h

Engine/source/sim/netConnection.h

More...

Classes:

class

Information about a ghosted object.

class

Torque network connection.

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.

class

An event to be sent over the network.

Public Defines

define
define
IMPLEMENT_CO_CLIENTEVENT(className, groupMask)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
define
IMPLEMENT_CO_CLIENTEVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId,, , , className::getParentStaticClassRep(), &Parent::__description)
define
IMPLEMENT_CO_NETEVENT(className, groupMask)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
define
IMPLEMENT_CO_NETEVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }  \
   <className> className::dynClassRep( #className, "Type" #className, &_smTypeId, , , , className::getParentStaticClassRep(), &Parent::__description)
define
IMPLEMENT_CO_SERVEREVENT(className, groupMask)    ( className, className, __scope,  )                                          \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
define
IMPLEMENT_CO_SERVEREVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, , , , className::getParentStaticClassRep(), &Parent::__description)

Public Functions

DECLARE_SCOPE(NetAPI )

Detailed Description

Public Defines

DEBUG_LOG(x) 
IMPLEMENT_CO_CLIENTEVENT(className, groupMask)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
IMPLEMENT_CO_CLIENTEVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId,, , , className::getParentStaticClassRep(), &Parent::__description)
IMPLEMENT_CO_NETEVENT(className, groupMask)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
IMPLEMENT_CO_NETEVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }  \
   <className> className::dynClassRep( #className, "Type" #className, &_smTypeId, , , , className::getParentStaticClassRep(), &Parent::__description)
IMPLEMENT_CO_SERVEREVENT(className, groupMask)    ( className, className, __scope,  )                                          \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, , , className::getParentStaticClassRep(), &Parent::__description)
IMPLEMENT_CO_SERVEREVENT_V1(className)    ( className,  )                                                              \
   ;                                                                            \
    className::_smTypeId; \
   * className::getClassRep()  { return &className::dynClassRep; } \
   * className::getStaticClassRep() { return &dynClassRep; } \
   * className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   * className::getContainerChildStaticClassRep() { return ; }                 \
    className::getStaticWriteCustomTamlSchema() { return ; }            \
   <className> className::dynClassRep(#className, "Type" #className, &_smTypeId, , , , className::getParentStaticClassRep(), &Parent::__description)

Public Functions

DECLARE_SCOPE(NetAPI )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#ifndef _NETCONNECTION_H_
  25#define _NETCONNECTION_H_
  26
  27#ifndef _MPOINT3_H_
  28#include "math/mPoint3.h"
  29#endif
  30#ifndef _NETOBJECT_H_
  31#include "sim/netObject.h"
  32#endif
  33#ifndef _NETSTRINGTABLE_H_
  34#include "sim/netStringTable.h"
  35#endif
  36#ifndef _DNET_H_
  37#include "core/dnet.h"
  38#endif
  39
  40#ifndef _H_CONNECTIONSTRINGTABLE
  41#include "sim/connectionStringTable.h"
  42#endif
  43
  44class NetConnection;
  45class NetObject;
  46class BitStream;
  47class ResizeBitStream;
  48class Stream;
  49class Point3F;
  50
  51struct GhostInfo;
  52struct SubPacketRef; // defined in NetConnection subclass
  53
  54//#define DEBUG_NET
  55
  56#ifdef TORQUE_DEBUG_NET
  57#define DEBUG_LOG(x) if(mLogging){Con::printf x;}
  58#else
  59#define DEBUG_LOG(x)
  60#endif
  61
  62DECLARE_SCOPE( NetAPI );
  63
  64//----------------------------------------------------------------------------
  65
  66class NetEvent;
  67
  68struct NetEventNote
  69{
  70   NetEvent *mEvent;
  71   S32 mSeqCount;
  72   NetEventNote *mNextEvent;
  73};
  74
  75/// An event to be sent over the network.
  76///
  77/// @note Torque implements two methods of network data passing; this is one of them.
  78/// See NetConnection for details of the other, which is referred to as ghosting.
  79///
  80/// Torque's network layer lets you pass events to/from the server. There are three
  81/// types of events:
  82///      - <b>Unguaranteed events</b> are events which are sent once. If they don't
  83///        make it through the link, they are not resent. This is good for quick,
  84///        frequent status updates which are of transient interest, like position
  85///        updates or voice communication.
  86///      - <b>Guaranteed events</b> are events which are guaranteed to be
  87///        delivered. If they don't make it through the link, they are sent as
  88///        needed. This is good for important, one-time information,
  89///        like which team a user wants to play on, or the current weather.
  90///      - <b>GuaranteedOrdered events</b> are events which are guaranteed not
  91///        only to be delivered, but to be delivered in order. This is good for
  92///        information which is not only important, but also order-critical, like
  93///        chat messages.
  94///
  95/// There are 6 methods that you need to implement if you want to make a
  96/// basic NetEvent subclass, and 2 macros you need to call.
  97///
  98/// @code
  99/// // A simple NetEvent to transmit a string over the network.
 100/// // This is based on the code in netTest.cc
 101/// class SimpleMessageEvent : public NetEvent
 102/// {
 103///    typedef NetEvent Parent;
 104///    char *msg;
 105/// public:
 106///    SimpleMessageEvent(const char *message = NULL);
 107///    ~SimpleMessageEvent();
 108///
 109///    virtual void pack   (NetConnection *conn, BitStream *bstream);
 110///    virtual void write  (NetConnection *conn, BitStream *bstream);
 111///    virtual void unpack (NetConnection *conn, BitStream *bstream);
 112///    virtual void process(NetConnection *conn);
 113///
 114///    DECLARE_CONOBJECT(SimpleMessageEvent);
 115/// };
 116///
 117/// IMPLEMENT_CO_NETEVENT_V1(SimpleMessageEvent);
 118/// @endcode
 119///
 120/// Notice the two macros which we call. The first, DECLARE_CONOBJECT() is there
 121/// because we're a ConsoleObject. The second, IMPLEMENT_CO_NETEVENT_V1(), is there
 122/// to register this event type with Torque's networking layer, so that it can be
 123/// properly transmitted over the wire. There are three macros which you might use:
 124///      - <b>IMPLEMENT_CO_NETEVENT_V1</b>, which indicates an event which may be sent
 125///        in either direction, from the client to the server, or from the server to the
 126///        client.
 127///      - <b>IMPLEMENT_CO_CLIENTEVENT_V1</b>, which indicates an event which may only
 128///        be sent to the client.
 129///      - <b>IMPLEMENT_CO_SERVEREVENT_V1</b>, which indicates an event which may only
 130///        be sent to the server.
 131///
 132/// Choosing the right macro is a good way to make your game more resistant to hacking; for instance,
 133/// PathManager events are marked as CLIENTEVENTs, because they would cause the server to crash if
 134/// a client sent them.
 135///
 136/// @note Torque allows you to call NetConnection::setLastError() on the NetConnection passed to
 137///       your NetEvent. You can cause the connection to abort if invalid data is received, specifying
 138///       a reason to the user.
 139///
 140/// Now, the 6 methods which we have above; the constructor and destructor need only do
 141/// whatever book-keeping is needed for your specific implementation. In our case, we
 142/// just need to allocate/deallocate the space for our string:
 143///
 144/// @code
 145///    SimpleMessageEvent::SimpleMessageEvent(const char *message = NULL)
 146///    {
 147///       // If we wanted to make this not be a GuaranteedOrdered event, we'd
 148///       // put a line like this in the constructor:
 149///       // mGuaranteeType = Guaranteed;
 150///       // (or whatever type you wanted.)
 151///       if(message)
 152///          msg = dStrdup(message);
 153///       else
 154///          msg = NULL;
 155///    }
 156///
 157///    SimpleMessageEvent::~SimpleMessageEvent()
 158///    {
 159///      dFree(msg);
 160///    }
 161/// @endcode
 162///
 163/// Simple as that! Now, onto pack(), write(), unpack(), process().
 164///
 165/// <b>pack()</b> is responsible for packing the event over the wire:
 166///
 167/// @code
 168/// void SimpleMessageEvent::pack(NetConnection* conn, BitStream *bstream)
 169/// {
 170///   bstream->writeString(msg);
 171/// }
 172/// @endcode
 173///
 174/// <b>unpack()</b> is responsible for unpacking the event on the other end:
 175///
 176/// @code
 177/// // The networking layer takes care of instantiating a new
 178/// // SimpleMessageEvent, which saves us a bit of effort.
 179/// void SimpleMessageEvent::unpack(NetConnection *conn, BitStream *bstream)
 180/// {
 181///   char buf[256];
 182///   bstream->readString(buf);
 183///   msg = dStrdup(buf);
 184/// }
 185/// @endcode
 186///
 187/// <b>process()</b> is called when the network layer is finished with things.
 188/// A typical case is that a GuaranteedOrdered event is unpacked and stored, but
 189/// not processed until the events preceding it in the sequence have also been
 190/// dealt with.
 191///
 192/// @code
 193/// // This just prints the event in the console. You might
 194/// // want to do something more clever here -- BJG
 195/// void SimpleMessageEvent::process(NetConnection *conn)
 196/// {
 197///   Con::printf("RMSG %d  %s", mSourceId, msg);
 198/// }
 199/// @endcode
 200///
 201/// <b>write()</b> is called if a demo recording is started, and the event has not yet been
 202/// processed, but it has been unpacked. It should be identical in its output to the bitstream
 203/// compared to pack(), but since it is called after unpack() some lookups may not need to be
 204/// performed. In normal demo recording, whole network packets are recorded, meaning that most
 205/// of the time write() will not be called.
 206///
 207/// In our case, it's entirely identical to pack():
 208///
 209/// @code
 210/// virtual void write(NetConnection*, BitStream *bstream)
 211/// {
 212///   bstream->writeString(msg);
 213/// }
 214/// @endcode
 215///
 216/// The NetEvent is sent over the wire in a straightforward way (assuming you have a
 217/// handle to a NetConnection):
 218///
 219/// @code
 220/// NetConnection *conn; // We assume you have filled this in.
 221///
 222/// con->postNetEvent(new SimpleMessageEvent("This is a test!"));
 223/// @endcode
 224///
 225/// @see GhostAlwaysObjectEvent for an example of dissimilar write()/pack() methods.
 226///
 227/// Finally, for more advanced applications, notifySent() is called whenever the event is
 228/// sent over the wire, in NetConnection::eventWritePacket(). notifyDelivered() is called
 229/// when the packet is finally received or (in the case of Unguaranteed packets) dropped.
 230///
 231/// @note IMPLEMENT_CO_NETEVENT_V1 and co. have sibling macros which allow you to specify a
 232///       groupMask; see ConsoleObject for a further discussion of this.
 233class NetEvent : public ConsoleObject
 234{
 235public:
 236
 237   DECLARE_ABSTRACT_CLASS( NetEvent, ConsoleObject );
 238   DECLARE_INSCOPE( NetAPI );
 239   
 240   /// @name Implementation Details
 241   ///
 242   /// These are internal fields which you won't need to manipulate, except for mGuaranteeType.
 243   /// @{
 244
 245   ///
 246   typedef ConsoleObject Parent;
 247   enum {
 248      GuaranteedOrdered = 0,
 249      Guaranteed = 1,
 250      Unguaranteed = 2
 251   } mGuaranteeType;
 252   NetConnectionId mSourceId;
 253
 254   void incRef()
 255   {
 256      incRefCount();
 257   }
 258   void decRef()
 259   {
 260      decRefCount();
 261   }
 262
 263#ifdef TORQUE_DEBUG_NET
 264   virtual const char *getDebugName();
 265#endif
 266   /// @}
 267
 268   /// @name Things To Subclass
 269   /// @{
 270
 271   ///
 272   NetEvent() { mGuaranteeType = GuaranteedOrdered; }
 273   virtual ~NetEvent();
 274
 275   virtual void write(NetConnection *ps, BitStream *bstream) = 0;
 276   virtual void pack(NetConnection *ps, BitStream *bstream) = 0;
 277   virtual void unpack(NetConnection *ps, BitStream *bstream) = 0;
 278   virtual void process(NetConnection *ps) = 0;
 279   virtual void notifySent(NetConnection *ps);
 280   virtual void notifyDelivered(NetConnection *ps, bool madeit);
 281   /// @}
 282};
 283
 284#define IMPLEMENT_CO_NETEVENT_V1(className)                    \
 285   IMPLEMENT_CLASS( className, NULL )                                                              \
 286   END_IMPLEMENT_CLASS;                                                                            \
 287   S32 className::_smTypeId; \
 288   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 289   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 290   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 291   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 292   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }  \
 293   ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep(), &Parent::__description)
 294
 295#define IMPLEMENT_CO_CLIENTEVENT_V1(className)                    \
 296   IMPLEMENT_CLASS( className, NULL )                                                              \
 297   END_IMPLEMENT_CLASS;                                                                            \
 298   S32 className::_smTypeId; \
 299   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 300   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 301   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 302   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 303   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
 304   ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep(), &Parent::__description)
 305
 306#define IMPLEMENT_CO_SERVEREVENT_V1(className)                    \
 307   IMPLEMENT_CLASS( className, NULL )                                                              \
 308   END_IMPLEMENT_CLASS;                                                                            \
 309   S32 className::_smTypeId; \
 310   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 311   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 312   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 313   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 314   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
 315   ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep(), &Parent::__description)
 316
 317#define IMPLEMENT_CO_NETEVENT(className,groupMask)                    \
 318   IMPLEMENT_CLASS( className, NULL )                                                              \
 319   END_IMPLEMENT_CLASS;                                                                            \
 320   S32 className::_smTypeId; \
 321   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 322   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 323   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 324   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 325   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
 326   ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep(), &Parent::__description)
 327
 328#define IMPLEMENT_CO_CLIENTEVENT(className,groupMask)                    \
 329   IMPLEMENT_CLASS( className, NULL )                                                              \
 330   END_IMPLEMENT_CLASS;                                                                            \
 331   S32 className::_smTypeId; \
 332   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 333   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 334   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 335   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 336   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
 337   ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep(), &Parent::__description)
 338
 339#define IMPLEMENT_CO_SERVEREVENT(className,groupMask)                    \
 340   IMPLEMENT_CLASS( className, className, __scope, NULL )                                          \
 341   END_IMPLEMENT_CLASS;                                                                            \
 342   S32 className::_smTypeId; \
 343   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
 344   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
 345   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
 346   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
 347   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
 348   ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, groupMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep(), &Parent::__description)
 349
 350
 351//----------------------------------------------------------------------------
 352
 353/// Torque network connection.
 354///
 355/// @section NetConnection_intro Introduction
 356///
 357/// NetConnection is the glue that binds a networked Torque game together. It combines
 358/// the low-level notify protocol implemented in ConnectionProtocol with a SimGroup to
 359/// provide a powerful basis for implementing a multiplayer game protocol.
 360///
 361/// On top of this basis it implements several distinct subsystems:
 362///   - <b>Event manager</b>, which is responsible for transmitting NetEvents over the wire.
 363///     It deals with ensuring that the various types of NetEvents are delivered appropriately,
 364///     and with notifying the event of its delivery status.
 365///   - <b>Move manager</b>, which is responsible for transferring a Move to the server 32
 366///     times a second (on the client) and applying it to the control object (on the server).
 367///   - <b>Ghost manager</b>, which is responsible for doing scoping calculations (on the server
 368///     side) and transmitting most-recent ghost information to the client.
 369///   - <b>File transfer</b>; it is often the case that clients will lack important files when
 370///     connecting to a server which is running a mod or new map. This subsystem allows the
 371///     server to transfer such files to the client.
 372///   - <b>Networked String Table</b>; string data can easily soak up network bandwidth, so for
 373///     efficiency, we implement a networked string table. We can then notify the connection
 374///     of strings we will reference often, such as player names, and transmit only a tag,
 375///     instead of the whole string.
 376///   - <b>Demo Recording</b> is also implemented in NetConnection. A demo in Torque is a log
 377///     of the network traffic between client and server; when a NetConnection records a demo,
 378///     it simply logs this data to a file. When it plays a demo back, it replays the logged
 379///     data.
 380///   - The <b>Connection Database</b> is used to keep track of all the NetConnections; it can
 381///     be iterated over (for instance, to send an event to all active connections), or queried
 382///     by address.
 383///
 384/// @section NetConnection_events   On Events
 385///
 386/// The Event Manager is exposed to the outside world via postNetEvent(), which accepts NetEvents.
 387///
 388/// @see NetEvent for a more thorough explanation of how to use events.
 389///
 390/// @section NetConnection_ghosting On Ghosting and Scoping
 391///
 392/// Ghosting is the most complex, and most powerful, part of Torque's networking capabilities. It
 393/// allows the information sent to clients to be very precisely matched to what they need, so that
 394/// no excess bandwidth is wasted. The control object's onCameraScopeQuery() is called, to determine
 395/// scoping information for the client; then objects which are in scope are then transmitted to the
 396/// client, prioritized by the results of their getPriority() method.
 397///
 398/// There is a cap on the maximum number of ghosts; ghost IDs are currently sent via a 12-bit field,
 399/// ergo, there is a cap of 4096 objects ghosted per client. This can be easily raised; see the
 400/// GhostConstants enum.
 401///
 402/// Each object ghosted is assigned a ghost ID; the client is _only_ aware of the ghost ID. This acts
 403/// to enhance game security, as it becomes difficult to map objects from one connection to another, or
 404/// to reliably identify objects from ID alone. IDs are also reassigned based on need, making it hard
 405/// to track objects that have fallen out of scope (as any object which the player shouldn't see would).
 406///
 407/// resolveGhost() is used on the client side, and resolveObjectFromGhostIndex() on the server side, to
 408/// turn ghost IDs into object references.
 409///
 410/// The NetConnection is a SimGroup. On the client side, it contains all the objects which have been
 411/// ghosted to that client. On the server side, it is empty; it can be used (typically in script) to
 412/// hold objects related to the connection. For instance, you might place an observation camera in the
 413/// NetConnnection. In both cases, when the connection is destroyed, so are the contained objects.
 414///
 415/// @see NetObject, which is the superclass for ghostable objects, and ShapeBase, which is the base
 416///      for player and vehicle classes.
 417///
 418/// @nosubgrouping
 419class NetConnection : public SimGroup, public ConnectionProtocol
 420{
 421   friend class NetInterface;
 422
 423   typedef SimGroup Parent;
 424
 425public:
 426   /// Structure to track ghost references in packets.
 427   ///
 428   /// Every packet we send out with an update from a ghost causes one of these to be
 429   /// allocated. mask is used to track what states were sent; that way if a packet is
 430   /// dropped, we can easily manipulate the stored states and figure out what if any data
 431   /// we need to resend.
 432   ///
 433   struct GhostRef
 434   {
 435      U32 mask;                  ///< States we transmitted.
 436      U32 ghostInfoFlags;        ///< Flags from GhostInfo::Flags
 437      GhostInfo *ghost;          ///< Reference to the GhostInfo we're from.
 438      GhostRef *nextRef;         ///< Next GhostRef in this packet.
 439      GhostRef *nextUpdateChain; ///< Next update we sent for this ghost.
 440   };
 441
 442   enum Constants
 443   {
 444      HashTableSize = 127,
 445   };
 446
 447   void sendDisconnectPacket(const char *reason);
 448
 449   virtual bool canRemoteCreate();
 450
 451   virtual void onTimedOut();
 452   virtual void onConnectTimedOut();
 453   virtual void onDisconnect(const char *reason);
 454   virtual void onConnectionRejected(const char *reason);
 455   virtual void onConnectionEstablished(bool isInitiator);
 456   virtual void handleStartupError(const char *errorString);
 457
 458   virtual void writeConnectRequest(BitStream *stream);
 459   virtual bool  readConnectRequest(BitStream *stream, const char **errorString);
 460
 461   virtual void writeConnectAccept(BitStream *stream);
 462   virtual bool  readConnectAccept(BitStream *stream, const char **errorString);
 463
 464   void connect(const NetAddress *address);
 465
 466   //----------------------------------------------------------------
 467   /// @name Global Connection List
 468   /// @{
 469
 470private:
 471   ///
 472   NetConnection *mNextConnection;        ///< Next item in list.
 473   NetConnection *mPrevConnection;        ///< Previous item in list.
 474   static NetConnection *mConnectionList; ///< Head of list.
 475public:
 476   static NetConnection *getConnectionList() { return mConnectionList; }
 477   NetConnection *getNext() { return mNextConnection; }
 478   /// @}
 479   //----------------------------------------------------------------
 480
 481   enum NetConnectionFlags
 482   {
 483      ConnectionToServer      = BIT(0),
 484      ConnectionToClient      = BIT(1),
 485      LocalClientConnection   = BIT(2),
 486      NetworkConnection       = BIT(3),
 487   };
 488
 489private:
 490   BitSet32 mTypeFlags;
 491
 492   U32 mNetClassGroup;  ///< The NetClassGroup of this connection.
 493
 494   /// @name Statistics
 495   /// @{
 496
 497   /// Last time a packet was sent in milliseconds. 
 498   /// @see Platform::getVirtualMilliseconds()
 499   U32 mLastUpdateTime; 
 500
 501   F32 mRoundTripTime;
 502   F32 mPacketLoss;
 503   U32 mSimulatedPing;
 504   F32 mSimulatedPacketLoss;
 505
 506   /// @}
 507
 508   /// @name State
 509   /// @{
 510
 511   U32 mProtocolVersion;
 512   U32 mSendDelayCredit;
 513   U32 mConnectSequence;
 514   U32 mAddressDigest[4];
 515
 516   bool mEstablished;
 517   bool mMissionPathsSent;
 518
 519   struct NetRate
 520   {
 521      U32 updateDelay;
 522      S32 packetSize;
 523      bool changed;
 524   };
 525
 526   NetRate mCurRate;
 527   NetRate mMaxRate;
 528
 529   /// If we're doing a "short circuited" connection, this stores
 530   /// a pointer to the other side.
 531   SimObjectPtr<NetConnection> mRemoteConnection;
 532
 533   NetAddress mNetAddress;
 534
 535   /// @}
 536
 537
 538   /// @name Timeout Management
 539   /// @{
 540
 541   U32 mPingSendCount;
 542   U32 mPingRetryCount;
 543   U32 mLastPingSendTime;
 544   /// @}
 545
 546   /// @name Connection Table
 547   ///
 548   /// We store our connections on a hash table so we can
 549   /// quickly find them.
 550   /// @{
 551
 552   NetConnection *mNextTableHash;
 553   static NetConnection *mHashTable[HashTableSize];
 554
 555   /// @}
 556
 557protected:
 558   static SimObjectPtr<NetConnection> mServerConnection;
 559   static SimObjectPtr<NetConnection> mLocalClientConnection;
 560
 561   static bool mFilesWereDownloaded;
 562
 563   U32 mConnectSendCount;
 564   U32 mConnectLastSendTime;
 565
 566   SimObjectPtr<NetConnection> getRemoteConnection() { return mRemoteConnection; }
 567
 568public:
 569   static NetConnection *getConnectionToServer() { return mServerConnection; }
 570
 571   static NetConnection *getLocalClientConnection() { return mLocalClientConnection; }
 572   static void setLocalClientConnection(NetConnection *conn) { mLocalClientConnection = conn; }
 573
 574   U32 getNetClassGroup() { return mNetClassGroup; }
 575   static bool filesWereDownloaded() { return mFilesWereDownloaded; }
 576   static String &getErrorBuffer() { return mErrorBuffer; }
 577
 578#ifdef TORQUE_DEBUG_NET
 579   bool mLogging;
 580   void setLogging(bool logging) { mLogging = logging; }
 581#endif
 582
 583   void setSimulatedNetParams(F32 packetLoss, U32 ping)
 584      { mSimulatedPacketLoss = packetLoss; mSimulatedPing = ping; }
 585
 586   bool isConnectionToServer()           { return mTypeFlags.test(ConnectionToServer); }
 587   bool isLocalConnection()            { return !mRemoteConnection.isNull() ; }
 588   bool isNetworkConnection()          { return mTypeFlags.test(NetworkConnection); }
 589
 590   void setIsConnectionToServer()        { mTypeFlags.set(ConnectionToServer); }
 591   void setIsLocalClientConnection()   { mTypeFlags.set(LocalClientConnection); }
 592   void setNetworkConnection(bool net) { mTypeFlags.set(BitSet32(NetworkConnection), net); }
 593
 594   virtual void setEstablished();
 595
 596   /// Call this if the "connection" is local to this app. This short-circuits the protocol layer.
 597   void setRemoteConnectionObject(NetConnection *connection) { mRemoteConnection = connection; };
 598
 599   void setSequence(U32 connectSequence);
 600
 601   void setAddressDigest(U32 digest[4]);
 602   void getAddressDigest(U32 digest[4]);
 603
 604   U32 getSequence();
 605
 606   void setProtocolVersion(U32 protocolVersion) { mProtocolVersion = protocolVersion; }
 607   U32 getProtocolVersion()                     { return mProtocolVersion; }
 608   F32 getRoundTripTime()                       { return mRoundTripTime; }
 609   F32 getPacketLoss()                          { return( mPacketLoss ); }
 610
 611   static String mErrorBuffer;
 612   static void setLastError(const char *fmt,...);
 613
 614   void checkMaxRate();
 615   void handlePacket(BitStream *stream);
 616   void processRawPacket(BitStream *stream);
 617   void handleNotify(bool recvd);
 618   void handleConnectionEstablished();
 619   void keepAlive();
 620
 621   const NetAddress *getNetAddress();
 622   void setNetAddress(const NetAddress *address);
 623   Net::Error sendPacket(BitStream *stream);
 624
 625private:
 626   void netAddressTableInsert();
 627   void netAddressTableRemove();
 628
 629public:
 630   /// Find a NetConnection, if any, with the specified address.
 631   static NetConnection *lookup(const NetAddress *remoteAddress);
 632
 633   bool checkTimeout(U32 time); ///< returns true if the connection timed out
 634
 635   void checkPacketSend(bool force);
 636
 637   bool missionPathsSent() const          { return mMissionPathsSent; }
 638   void setMissionPathsSent(const bool s) { mMissionPathsSent = s; }
 639
 640   static void consoleInit();
 641
 642   void onRemove();
 643
 644   NetConnection();
 645   ~NetConnection();
 646
 647public:
 648   enum NetConnectionState
 649   {
 650      NotConnected,
 651      AwaitingChallengeResponse, ///< We've sent a challenge request, awaiting the response.
 652      AwaitingConnectRequest,    ///< We've received a challenge request and sent a challenge response.
 653      AwaitingConnectResponse,   ///< We've received a challenge response and sent a connect request.
 654      Connected,                 ///< We've accepted a connect request, or we've received a connect response accept.
 655   };
 656
 657   U32 mConnectionSendCount;  ///< number of connection messages we've sent.
 658   U32 mConnectionState;      ///< State of the connection, from NetConnectionState.
 659
 660   void setConnectionState(U32 state) { mConnectionState = state; }
 661   U32 getConnectionState() { return mConnectionState; }
 662
 663
 664   void setGhostFrom(bool ghostFrom);     ///< Sets whether ghosts transmit from this side of the connection.
 665   void setGhostTo(bool ghostTo);         ///< Sets whether ghosts are allowed from the other side of the connection.
 666   void setSendingEvents(bool sending);   ///< Sets whether this side actually sends the events that are posted to it.
 667   void setTranslatesStrings(bool xl);    ///< Sets whether this connection is capable of translating strings.
 668   void setNetClassGroup(U32 group);      ///< Sets the group of NetClasses this connection traffics in.
 669   bool isEstablished() { return mEstablished; }   ///< Is the connection established?
 670
 671   DECLARE_CONOBJECT(NetConnection);
 672   DECLARE_INSCOPE( NetAPI );
 673
 674   /// Structure to track packets and what we sent over them.
 675   ///
 676   /// We need to know what is sent in each packet, so that if a packet is
 677   /// dropped, we know what to resend. This is the structure we use to track
 678   /// this data.
 679   struct PacketNotify
 680   {
 681      bool rateChanged;       ///< Did the rate change on this packet?
 682      bool maxRateChanged;    ///< Did the max rate change on this packet?
 683      U32  sendTime;          ///< Timestampe, when we sent this packet.
 684
 685      NetEventNote *eventList;    ///< Linked list of events sent over this packet.
 686      GhostRef *ghostList;    ///< Linked list of ghost updates we sent in this packet.
 687      SubPacketRef *subList;  ///< Defined by subclass - used as desired.
 688
 689      PacketNotify *nextPacket;  ///< Next packet sent.
 690      PacketNotify();
 691   };
 692   virtual PacketNotify *allocNotify();
 693   PacketNotify *mNotifyQueueHead;  ///< Head of packet notify list.
 694   PacketNotify *mNotifyQueueTail;  ///< Tail of packet notify list.
 695
 696protected:
 697   virtual void readPacket(BitStream *bstream);
 698   virtual void writePacket(BitStream *bstream, PacketNotify *note);
 699   virtual void packetReceived(PacketNotify *note);
 700   virtual void packetDropped(PacketNotify *note);
 701   virtual void connectionError(const char *errorString);
 702
 703//----------------------------------------------------------------
 704/// @name Event Manager
 705/// @{
 706
 707private:
 708   NetEventNote *mSendEventQueueHead;
 709   NetEventNote *mSendEventQueueTail;
 710   NetEventNote *mUnorderedSendEventQueueHead;
 711   NetEventNote *mUnorderedSendEventQueueTail;
 712   NetEventNote *mWaitSeqEvents;
 713   NetEventNote *mNotifyEventList;
 714
 715   static FreeListChunker<NetEventNote> mEventNoteChunker;
 716
 717   bool mSendingEvents;
 718
 719   S32 mNextSendEventSeq;
 720   S32 mNextRecvEventSeq;
 721   S32 mLastAckedEventSeq;
 722
 723   enum NetEventConstants {
 724      InvalidSendEventSeq = -1,
 725      FirstValidSendEventSeq = 0
 726   };
 727
 728   void eventOnRemove();
 729
 730   void eventPacketDropped(PacketNotify *notify);
 731   void eventPacketReceived(PacketNotify *notify);
 732
 733   void eventWritePacket(BitStream *bstream, PacketNotify *notify);
 734   void eventReadPacket(BitStream *bstream);
 735
 736   void eventWriteStartBlock(ResizeBitStream *stream);
 737   void eventReadStartBlock(BitStream *stream);
 738public:
 739   /// Post an event to this connection.
 740   bool postNetEvent(NetEvent *event);
 741
 742/// @}
 743
 744//----------------------------------------------------------------
 745/// @name Networked string table
 746/// @{
 747
 748private:
 749   bool mTranslateStrings;
 750   ConnectionStringTable *mStringTable;
 751public:
 752   void mapString(U32 netId, NetStringHandle &string)
 753      { mStringTable->mapString(netId, string); }
 754   U32  checkString(NetStringHandle &string, bool *isOnOtherSide = NULL)
 755      { if(mStringTable) return mStringTable->checkString(string, isOnOtherSide); else return 0; }
 756   U32  getNetSendId(NetStringHandle &string)
 757      { if(mStringTable) return mStringTable->getNetSendId(string); else return 0;}
 758   void confirmStringReceived(NetStringHandle &string, U32 index)
 759      { if(!isRemoved()) mStringTable->confirmStringReceived(string, index); }
 760
 761   NetStringHandle translateRemoteStringId(U32 id) { return mStringTable->lookupString(id); }
 762   void         validateSendString(const char *str);
 763
 764   void   packString(BitStream *stream, const char *str);
 765   void unpackString(BitStream *stream, char readBuffer[1024]);
 766
 767   void           packNetStringHandleU(BitStream *stream, NetStringHandle &h);
 768   NetStringHandle unpackNetStringHandleU(BitStream *stream);
 769/// @}
 770
 771//----------------------------------------------------------------
 772/// @name Ghost manager
 773/// @{
 774
 775protected:
 776   enum GhostStates
 777   {
 778      GhostAlwaysDone,
 779      ReadyForNormalGhosts,
 780      EndGhosting,
 781      GhostAlwaysStarting,
 782      SendNextDownloadRequest,
 783      FileDownloadSizeMessage,
 784      NumConnectionMessages,
 785   };
 786   GhostInfo **mGhostArray;    ///< Linked list of ghostInfos ghosted by this side of the connection
 787
 788   U32 mGhostZeroUpdateIndex;  ///< Index in mGhostArray of first ghost with 0 update mask.
 789   U32 mGhostFreeIndex;        ///< Index in mGhostArray of first free ghost.
 790
 791   U32 mGhostsActive;         ///- Track actve ghosts on client side
 792
 793   bool mGhosting;             ///< Am I currently ghosting objects?
 794   bool mScoping;              ///< am I currently scoping objects?
 795   U32  mGhostingSequence;     ///< Sequence number describing this ghosting session.
 796
 797   NetObject **mLocalGhosts;  ///< Local ghost for remote object.
 798                              ///
 799                              /// mLocalGhosts pointer is NULL if mGhostTo is false
 800
 801   GhostInfo *mGhostRefs;           ///< Allocated array of ghostInfos. Null if ghostFrom is false.
 802   GhostInfo **mGhostLookupTable;   ///< Table indexed by object id to GhostInfo. Null if ghostFrom is false.
 803
 804   /// The object around which we are scoping this connection.
 805   ///
 806   /// This is usually the player object, or a related object, like a vehicle
 807   /// that the player is driving.
 808   SimObjectPtr<NetObject> mScopeObject;
 809
 810   void clearGhostInfo();
 811   bool validateGhostArray();
 812
 813   void ghostPacketDropped(PacketNotify *notify);
 814   void ghostPacketReceived(PacketNotify *notify);
 815
 816   void ghostWritePacket(BitStream *bstream, PacketNotify *notify);
 817   void ghostReadPacket(BitStream *bstream);
 818   void freeGhostInfo(GhostInfo *);
 819
 820   void ghostWriteStartBlock(ResizeBitStream *stream);
 821   void ghostReadStartBlock(BitStream *stream);
 822
 823   virtual void ghostWriteExtra(NetObject *,BitStream *) {}
 824   virtual void ghostReadExtra(NetObject *,BitStream *, bool newGhost) {}
 825   virtual void ghostPreRead(NetObject *, bool newGhost) {}
 826   
 827   /// Called when 'EndGhosting' message is received from server.
 828   virtual void onEndGhosting() {}
 829
 830public:
 831   /// Some configuration values.
 832   enum GhostConstants
 833   {
 834      GhostIdBitSize = 18, //262,144 ghosts
 835      MaxGhostCount = 1 << GhostIdBitSize, //4096,
 836      GhostLookupTableSize = 1 << GhostIdBitSize, //4096
 837      GhostIndexBitSize = 4 // number of bits GhostIdBitSize-3 fits into
 838   };
 839
 840   U32 getGhostsActive() { return mGhostsActive;};
 841
 842   /// Are we ghosting to someone?
 843   bool isGhostingTo() { return mLocalGhosts != NULL; };
 844
 845   /// Are we ghosting from someone?
 846   bool isGhostingFrom() { return mGhostArray != NULL; };
 847
 848   /// Called by onRemove, to shut down the ghost subsystem.
 849   void ghostOnRemove();
 850
 851   /// Called when we're done with normal scoping.
 852   ///
 853   /// This gives subclasses a chance to shove things into scope, such as
 854   /// the results of a sensor network calculation, that would otherwise
 855   /// be awkward to add.
 856   virtual void doneScopingScene() { /* null */ }
 857
 858   /// Set the object around which we are currently scoping network traffic.
 859   void setScopeObject(NetObject *object);
 860
 861   /// Get the object around which we are currently scoping network traffic.
 862   NetObject *getScopeObject();
 863
 864   /// Add an object to scope.
 865   void objectInScope(NetObject *object);
 866
 867   /// Add an object to scope, marking that it should always be scoped to this connection.
 868   void objectLocalScopeAlways(NetObject *object);
 869
 870   /// Mark an object that is being ghosted as not always needing to be scoped.
 871   ///
 872   /// This undoes objectLocalScopeAlways(), but doesn't immediately flush it from scope.
 873   ///
 874   /// Instead, the standard scoping mechanisms will clear it from scope when it is appropos
 875   /// to do so.
 876   void objectLocalClearAlways(NetObject *object);
 877
 878   /// Get a NetObject* from a ghost ID (on client side).
 879   NetObject *resolveGhost(S32 id);
 880
 881   /// Get a NetObject* from a ghost index (on the server side).
 882   NetObject *resolveObjectFromGhostIndex(S32 id);
 883
 884   /// Get the ghost index corresponding to a given NetObject. This is only
 885   /// meaningful on the server side.
 886   S32 getGhostIndex(NetObject *object);
 887
 888   /// Move a GhostInfo into the nonzero portion of the list (so that we know to update it).
 889   void ghostPushNonZero(GhostInfo *gi);
 890
 891   /// Move a GhostInfo into the zero portion of the list (so that we know not to update it).
 892   void ghostPushToZero(GhostInfo *gi);
 893
 894   /// Move a GhostInfo from the zero portion of the list to the free portion.
 895   void ghostPushZeroToFree(GhostInfo *gi);
 896
 897   /// Move a GhostInfo from the free portion of the list to the zero portion.
 898   inline void ghostPushFreeToZero(GhostInfo *info);
 899
 900   /// Stop all ghosting activity and inform the other side about this.
 901   ///
 902   /// Turns off ghosting.
 903   void resetGhosting();
 904
 905   /// Activate ghosting, once it's enabled.
 906   void activateGhosting();
 907
 908   /// Are we ghosting?
 909   bool isGhosting() { return mGhosting; }
 910
 911   /// Begin to stop ghosting an object.
 912   void detachObject(GhostInfo *info);
 913
 914   /// Mark an object to be always ghosted. Index is the ghost index of the object.
 915   void setGhostAlwaysObject(NetObject *object, U32 index);
 916
 917
 918   /// Send ghost connection handshake message.
 919   ///
 920   /// As part of the ghost connection process, extensive hand-shaking must be performed.
 921   ///
 922   /// This is done by passing ConnectionMessageEvents; this is a helper function
 923   /// to more effectively perform this task. Messages are dealt with by
 924   /// handleConnectionMessage().
 925   ///
 926   /// @param  message     One of GhostStates
 927   /// @param  sequence    A sequence number, if any.
 928   /// @param  ghostCount  A count of ghosts relating to this message.
 929   void sendConnectionMessage(U32 message, U32 sequence = 0, U32 ghostCount = 0);
 930
 931   /// Handle message from sendConnectionMessage().
 932   ///
 933   /// This is called to handle messages sent via sendConnectionMessage.
 934   ///
 935   /// @param  message     One of GhostStates
 936   /// @param  sequence    A sequence number, if any.
 937   /// @param  ghostCount  A count of ghosts relating to this message.
 938   virtual void handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount);
 939
 940   /// Sends a signal to any object that needs to wait till everything has been ghosted
 941   /// before performing an operation.
 942   static Signal<void()> smGhostAlwaysDone;
 943
 944   /// @}
 945public:
 946//----------------------------------------------------------------
 947/// @name File transfer
 948/// @{
 949
 950protected:
 951   /// List of files missing for this connection.
 952   ///
 953   /// The currently downloading file is always first in the list (ie, [0]).
 954   Vector<char*> mMissingFileList;
 955
 956   /// Stream for currently uploading file (if any).
 957   Stream *mCurrentDownloadingFile;
 958
 959   /// Storage for currently downloading file.
 960   void *mCurrentFileBuffer;
 961
 962   /// Size of currently downloading file in bytes.
 963   U32 mCurrentFileBufferSize;
 964
 965   /// Our position in the currently downloading file in bytes.
 966   U32 mCurrentFileBufferOffset;
 967
 968   /// Number of files we have downloaded.
 969   U32 mNumDownloadedFiles;
 970
 971   /// Error storage for file transfers.
 972   String mLastFileErrorBuffer;
 973
 974   /// Structure to track ghost-always objects and their ghost indices.
 975   struct GhostSave {
 976      NetObject *ghost;
 977      U32 index;
 978   };
 979
 980   /// List of objects to ghost-always.
 981   Vector<GhostSave> mGhostAlwaysSaveList;
 982
 983public:
 984   /// Start sending the specified file over the link.
 985   bool startSendingFile(const char *fileName);
 986
 987   /// Called when we receive a FileChunkEvent.
 988   void chunkReceived(U8 *chunkData, U32 chunkLen);
 989
 990   /// Get the next file...
 991   void sendNextFileDownloadRequest();
 992
 993   /// Post the next FileChunkEvent.
 994   void sendFileChunk();
 995
 996   /// Called when we finish downloading file data.
 997   virtual void fileDownloadSegmentComplete();
 998
 999   /// This is part of the file transfer logic; basically, we call this
1000   /// every time we finish downloading new files. It attempts to load
1001   /// the GhostAlways objects; if they fail, it marks an error and we
1002   /// have chance to retry.
1003   void loadNextGhostAlwaysObject(bool hadNewFiles);
1004/// @}
1005
1006//----------------------------------------------------------------
1007/// @name Demo Recording
1008/// @{
1009
1010private:
1011   Stream *mDemoWriteStream;
1012   Stream *mDemoReadStream;
1013   U32 mDemoNextBlockType;
1014   U32 mDemoNextBlockSize;
1015
1016   U32 mDemoWriteStartTime;
1017   U32 mDemoReadStartTime;
1018   U32 mDemoLastWriteTime;
1019
1020   U32 mDemoRealStartTime;
1021
1022public:
1023   enum DemoBlockTypes {
1024      BlockTypePacket,
1025      BlockTypeSendPacket,
1026      NetConnectionBlockTypeCount
1027   };
1028
1029   enum DemoConstants {
1030      MaxNumBlockTypes = 16,
1031      MaxBlockSize = 0x1000,
1032   };
1033
1034   bool isRecording()
1035      { return mDemoWriteStream != NULL; }
1036   bool isPlayingBack()
1037      { return mDemoReadStream != NULL; }
1038
1039   U32 getNextBlockType() { return mDemoNextBlockType; }
1040   void recordBlock(U32 type, U32 size, void *data);
1041   virtual void handleRecordedBlock(U32 type, U32 size, void *data);
1042   bool processNextBlock();
1043
1044   bool startDemoRecord(const char *fileName);
1045   bool replayDemoRecord(const char *fileName);
1046   void startDemoRead();
1047   void stopRecording();
1048   void stopDemoPlayback();
1049
1050   virtual void writeDemoStartBlock(ResizeBitStream *stream);
1051   virtual bool readDemoStartBlock(BitStream *stream);
1052   virtual void demoPlaybackComplete();
1053/// @}
1054};
1055
1056
1057//----------------------------------------------------------------------------
1058/// Information about a ghosted object.
1059///
1060/// @note If the size of this structure changes, the
1061///       NetConnection::getGhostIndex function MUST be changed
1062///       to reflect the new size.
1063struct GhostInfo
1064{
1065public:  // required for MSVC
1066   NetObject *obj;                        ///< The object being ghosted.
1067   U32 updateMask;                        ///< Flags indicating what state data needs to be transferred.
1068
1069   U32 updateSkipCount;                   ///< How many updates have we skipped this guy?
1070   U32 flags;                             ///< Flags from GhostInfo::Flags
1071   F32 priority;                          ///< A float value indicating the priority of this object for
1072                                          ///  updates.
1073
1074   /// @name References
1075   ///
1076   /// The GhostInfo structure is used in several linked lists; these members are
1077   /// the implementation for this.
1078   /// @{
1079
1080   NetConnection::GhostRef *updateChain;  ///< List of references in NetConnections to us.
1081
1082   GhostInfo *nextObjectRef;              ///< Next ghosted object.
1083   GhostInfo *prevObjectRef;              ///< Previous ghosted object.
1084   NetConnection *connection;             ///< Connection that we're ghosting over.
1085   GhostInfo *nextLookupInfo;             ///< GhostInfo references are stored in a hash; this is the bucket
1086                                          ///  implementation.
1087
1088   /// @}
1089
1090   U32 index;
1091   U32 arrayIndex;
1092
1093   /// Flags relating to the state of the object.
1094   enum Flags
1095   {
1096      Valid             = BIT(0),
1097      InScope           = BIT(1),
1098      ScopeAlways       = BIT(2),
1099      NotYetGhosted     = BIT(3),
1100      Ghosting          = BIT(4),
1101      KillGhost         = BIT(5),
1102      KillingGhost      = BIT(6),
1103      ScopedEvent       = BIT(7),
1104      ScopeLocalAlways  = BIT(8),
1105   };
1106};
1107
1108inline void NetConnection::ghostPushNonZero(GhostInfo *info)
1109{
1110   AssertFatal(info->arrayIndex >= mGhostZeroUpdateIndex && info->arrayIndex < mGhostFreeIndex, "Out of range arrayIndex.");
1111   AssertFatal(mGhostArray[info->arrayIndex] == info, "Invalid array object.");
1112   if(info->arrayIndex != mGhostZeroUpdateIndex)
1113   {
1114      mGhostArray[mGhostZeroUpdateIndex]->arrayIndex = info->arrayIndex;
1115      mGhostArray[info->arrayIndex] = mGhostArray[mGhostZeroUpdateIndex];
1116      mGhostArray[mGhostZeroUpdateIndex] = info;
1117      info->arrayIndex = mGhostZeroUpdateIndex;
1118   }
1119   mGhostZeroUpdateIndex++;
1120   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
1121}
1122
1123inline void NetConnection::ghostPushToZero(GhostInfo *info)
1124{
1125   AssertFatal(info->arrayIndex < mGhostZeroUpdateIndex, "Out of range arrayIndex.");
1126   AssertFatal(mGhostArray[info->arrayIndex] == info, "Invalid array object.");
1127   mGhostZeroUpdateIndex--;
1128   if(info->arrayIndex != mGhostZeroUpdateIndex)
1129   {
1130      mGhostArray[mGhostZeroUpdateIndex]->arrayIndex = info->arrayIndex;
1131      mGhostArray[info->arrayIndex] = mGhostArray[mGhostZeroUpdateIndex];
1132      mGhostArray[mGhostZeroUpdateIndex] = info;
1133      info->arrayIndex = mGhostZeroUpdateIndex;
1134   }
1135   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
1136}
1137
1138inline void NetConnection::ghostPushZeroToFree(GhostInfo *info)
1139{
1140   AssertFatal(info->arrayIndex >= mGhostZeroUpdateIndex && info->arrayIndex < mGhostFreeIndex, "Out of range arrayIndex.");
1141   AssertFatal(mGhostArray[info->arrayIndex] == info, "Invalid array object.");
1142   mGhostFreeIndex--;
1143   if(info->arrayIndex != mGhostFreeIndex)
1144   {
1145      mGhostArray[mGhostFreeIndex]->arrayIndex = info->arrayIndex;
1146      mGhostArray[info->arrayIndex] = mGhostArray[mGhostFreeIndex];
1147      mGhostArray[mGhostFreeIndex] = info;
1148      info->arrayIndex = mGhostFreeIndex;
1149   }
1150   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
1151}
1152
1153inline void NetConnection::ghostPushFreeToZero(GhostInfo *info)
1154{
1155   AssertFatal(info->arrayIndex >= mGhostFreeIndex, "Out of range arrayIndex.");
1156   AssertFatal(mGhostArray[info->arrayIndex] == info, "Invalid array object.");
1157   if(info->arrayIndex != mGhostFreeIndex)
1158   {
1159      mGhostArray[mGhostFreeIndex]->arrayIndex = info->arrayIndex;
1160      mGhostArray[info->arrayIndex] = mGhostArray[mGhostFreeIndex];
1161      mGhostArray[mGhostFreeIndex] = info;
1162      info->arrayIndex = mGhostFreeIndex;
1163   }
1164   mGhostFreeIndex++;
1165   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
1166}
1167
1168#endif
1169
1170
1171