📄 netevent.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 + -