⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netevent.h

📁 五行MMORPG引擎系统V1.0
💻 H
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#ifndef _NETEVENT_H_
#define _NETEVENT_H_

//#ifndef _MPOINT_H_
//#include "math/mPoint.h"
//#endif
//#ifndef _NETOBJECT_H_
//#include "sim/netObject.h"
//#endif
//#ifndef _NETSTRINGTABLE_H_
//#include "sim/netStringTable.h"
//#endif
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
//#ifndef _DNET_H_
//#include "core/dnet.h"
//#endif
//
//#ifndef _H_CONNECTIONSTRINGTABLE
//#include "sim/connectionStringTable.h"
//#endif

class EventConnection;
class NetObject;
class BitStream;
class ResizeBitStream;
class Stream;
class Point3F;

struct GhostInfo;
struct SubPacketRef; // defined in EventConnection subclass

//#define TORQUE_DEBUG_NET

#ifdef TORQUE_DEBUG_NET
#define DEBUG_LOG(x) if(mLogging){Con::printf x;}
#else
#define DEBUG_LOG(x)
#endif

//----------------------------------------------------------------------------
/// TGE_RPGSERVER

class NetEvent;

struct NetEventNote
{
   NetEvent *mEvent;
   S32 mSeqCount;
   NetEventNote *mNextEvent;
};

/// An event to be sent over the network.
///
/// @note Torque implements two methods of network data passing; this is one of them.
/// See EventConnection for details of the other, which is referred to as ghosting.
///
/// Torque's network layer lets you pass events to/from the server. There are three
/// types of events:
///      - <b>Unguaranteed events</b> are events which are sent once. If they don't
///        make it through the link, they are not resent. This is good for quick,
///        frequent status updates which are of transient interest, like position
///        updates or voice communication.
///      - <b>Guaranteed events</b> are events which are guaranteed to be
///        delivered. If they don't make it through the link, they are sent as
///        needed. This is good for important, one-time information,
///        like which team a user wants to play on, or the current weather.
///      - <b>GuaranteedOrdered events</b> are events which are guaranteed not
///        only to be delivered, but to be delivered in order. This is good for
///        information which is not only important, but also order-critical, like
///        chat messages.
///
/// There are 6 methods that you need to implement if you want to make a
/// basic NetEvent subclass, and 2 macros you need to call.
///
/// @code
/// // A simple NetEvent to transmit a string over the network.
/// // This is based on the code in netTest.cc
/// class SimpleMessageEvent : public NetEvent
/// {
///    typedef NetEvent Parent;
///    char *msg;
/// public:
///    SimpleMessageEvent(const char *message = NULL);
///    ~SimpleMessageEvent();
///
///    virtual void pack   (EventConnection *conn, BitStream *bstream);
///    virtual void write  (EventConnection *conn, BitStream *bstream);
///    virtual void unpack (EventConnection *conn, BitStream *bstream);
///    virtual void process(EventConnection *conn);
///
///    DECLARE_CONOBJECT(SimpleMessageEvent);
/// };
///
/// IMPLEMENT_CO_NETEVENT_V1(SimpleMessageEvent);
/// @endcode
///
/// Notice the two macros which we call. The first, DECLARE_CONOBJECT() is there
/// because we're a ConsoleObject. The second, IMPLEMENT_CO_NETEVENT_V1(), is there
/// to register this event type with Torque's networking layer, so that it can be
/// properly transmitted over the wire. There are three macros which you might use:
///      - <b>IMPLEMENT_CO_NETEVENT_V1</b>, which indicates an event which may be sent
///        in either direction, from the client to the server, or from the server to the
///        client.
///      - <b>IMPLEMENT_CO_CLIENTEVENT_V1</b>, which indicates an event which may only
///        be sent to the client.
///      - <b>IMPLEMENT_CO_SERVEREVENT_V1</b>, which indicates an event which may only
///        be sent to the server.
///
/// Choosing the right macro is a good way to make your game more resistant to hacking; for instance,
/// PathManager events are marked as CLIENTEVENTs, because they would cause the server to crash if
/// a client sent them.
///
/// @note Torque allows you to call EventConnection::setLastError() on the EventConnection passed to
///       your NetEvent. You can cause the connection to abort if invalid data is received, specifying
///       a reason to the user.
///
/// Now, the 6 methods which we have above; the constructor and destructor need only do
/// whatever book-keeping is needed for your specific implementation. In our case, we
/// just need to allocate/deallocate the space for our string:
///
/// @code
///    SimpleMessageEvent::SimpleMessageEvent(const char *message = NULL)
///    {
///       // If we wanted to make this not be a GuaranteedOrdered event, we'd
///       // put a line like this in the constructor:
///       // mGuaranteeType = Guaranteed;
///       // (or whatever type you wanted.)
///       if(message)
///          msg = dStrdup(message);
///       else
///          msg = NULL;
///    }
///
///    SimpleMessageEvent::~SimpleMessageEvent()
///    {
///      dFree(msg);
///    }
/// @endcode
///
/// Simple as that! Now, onto pack(), write(), unpack(), process().
///
/// <b>pack()</b> is responsible for packing the event over the wire:
///
/// @code
/// void SimpleMessageEvent::pack(EventConnection* conn, BitStream *bstream)
/// {
///   bstream->writeString(msg);
/// }
/// @endcode
///
/// <b>unpack()</b> is responsible for unpacking the event on the other end:
///
/// @code
/// // The networking layer takes care of instantiating a new
/// // SimpleMessageEvent, which saves us a bit of effort.
/// void SimpleMessageEvent::unpack(EventConnection *conn, BitStream *bstream)
/// {
///   char buf[256];
///   bstream->readString(buf);
///   msg = dStrdup(buf);
/// }
/// @endcode
///
/// <b>process()</b> is called when the network layer is finished with things.
/// A typical case is that a GuaranteedOrdered event is unpacked and stored, but
/// not processed until the events preceding it in the sequence have also been
/// dealt with.
///
/// @code
/// // This just prints the event in the console. You might
/// // want to do something more clever here -- BJG
/// void SimpleMessageEvent::process(EventConnection *conn)
/// {
///   Con::printf("RMSG %d  %s", mSourceId, msg);
/// }
/// @endcode
///
/// <b>write()</b> is called if a demo recording is started, and the event has not yet been
/// processed, but it has been unpacked. It should be identical in its output to the bitstream
/// compared to pack(), but since it is called after unpack() some lookups may not need to be
/// performed. In normal demo recording, whole network packets are recorded, meaning that most
/// of the time write() will not be called.
///
/// In our case, it's entirely identical to pack():
///
/// @code
/// virtual void write(EventConnection*, BitStream *bstream)
/// {
///   bstream->writeString(msg);
/// }
/// @endcode
///
/// The NetEvent is sent over the wire in a straightforward way (assuming you have a
/// handle to a EventConnection):
///
/// @code
/// EventConnection *conn; // We assume you have filled this in.
///
/// con->postNetEvent(new SimpleMessageEvent("This is a test!"));
/// @endcode
///
/// @see GhostAlwaysObjectEvent for an example of dissimilar write()/pack() methods.
///
/// Finally, for more advanced applications, notifySent() is called whenever the event is
/// sent over the wire, in EventConnection::eventWritePacket(). notifyDelivered() is called
/// when the packet is finally received or (in the case of Unguaranteed packets) dropped.
///
/// @note IMPLEMENT_CO_NETEVENT_V1 and co. have sibling macros which allow you to specify a
///       groupMask; see ConsoleObject for a further discussion of this.
class NetEvent : public ConsoleObject
{
public:
   /// @name Implementation Details
   ///
   /// These are internal fields which you won't need to manipulate, except for mGuaranteeType.
   /// @{

   ///
   S32 mRefCount;
   typedef ConsoleObject Parent;
   enum {
      GuaranteedOrdered = 0,
      Guaranteed = 1,
      Unguaranteed = 2
   } mGuaranteeType;
   NetConnectionId mSourceId;

   void incRef()
   {
      mRefCount++;
   }
   void decRef()
   {
      mRefCount--;
      if(!mRefCount)
         delete this;
   }

#ifdef TORQUE_DEBUG_NET
   virtual const char *getDebugName();
#endif
   /// @}

   /// @name Things To Subclass
   /// @{

   ///
   NetEvent() { mGuaranteeType = GuaranteedOrdered; mRefCount = 0; }
   virtual ~NetEvent();

   virtual void write(EventConnection *ps, BitStream *bstream) = 0;
   virtual void pack(EventConnection *ps, BitStream *bstream) = 0;
   virtual void unpack(EventConnection *ps, BitStream *bstream) = 0;
   virtual void process(EventConnection *ps) = 0;
   virtual void notifySent(EventConnection *ps);
   virtual void notifyDelivered(EventConnection *ps, bool madeit);
   /// @}
};


#define IMPLEMENT_CO_NETEVENT_V1(className)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep())

#define IMPLEMENT_CO_CLIENTEVENT_V1(className)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep())

#define IMPLEMENT_CO_SERVEREVENT_V1(className)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep())

#define IMPLEMENT_CO_NETEVENT(className,groupMask)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep())

#define IMPLEMENT_CO_CLIENTEVENT(className,groupMask)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep())

#define IMPLEMENT_CO_SERVEREVENT(className,groupMask)                    \
   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
   ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep())



#endif


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -