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