|
static const char * | lookupClassName (const U32 in_classTag) |
| Get the classname from a class tag. More...
|
|
static void | initPersistFields () |
|
static void | consoleInit () |
|
static ConsoleObject * | create (const char *in_pClassName) |
|
static ConsoleObject * | create (const U32 groupId, const U32 typeId, const U32 in_classId) |
|
static AbstractClassRep * | getStaticClassRep () |
| Get the abstract class information for this class. More...
|
|
static AbstractClassRep * | getParentStaticClassRep () |
| Get the abstract class information for this class's superclass. More...
|
|
| ConsoleObject () |
|
| ConsoleObject (const ConsoleObject &) |
|
static void | addGroup (const char *in_pGroupname, const char *in_pGroupDocs=NULL) |
|
static void | endGroup (const char *in_pGroupname) |
|
static void | addField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, const U32 in_elementCount=1, EnumTable *in_table=NULL, const char *in_pFieldDocs=NULL) |
|
static void | addField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::WriteDataNotify in_writeDataFn, const U32 in_elementCount=1, EnumTable *in_table=NULL, const char *in_pFieldDocs=NULL) |
|
static void | addField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, const char *in_pFieldDocs) |
|
static void | addField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::WriteDataNotify in_writeDataFn, const char *in_pFieldDocs) |
|
static void | addFieldV (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, ConsoleTypeValidator *v, const char *in_pFieldDocs=NULL) |
|
static void | addProtectedField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn=&defaultProtectedGetFn, const U32 in_elementCount=1, EnumTable *in_table=NULL, const char *in_pFieldDocs=NULL) |
|
static void | addProtectedField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn=&defaultProtectedGetFn, AbstractClassRep::WriteDataNotify in_writeDataFn=&defaultProtectedWriteFn, const U32 in_elementCount=1, EnumTable *in_table=NULL, const char *in_pFieldDocs=NULL) |
|
static void | addProtectedField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn=&defaultProtectedGetFn, const char *in_pFieldDocs=NULL) |
|
static void | addProtectedField (const char *in_pFieldname, const U32 in_fieldType, const dsize_t in_fieldOffset, AbstractClassRep::SetDataNotify in_setDataFn, AbstractClassRep::GetDataNotify in_getDataFn=&defaultProtectedGetFn, AbstractClassRep::WriteDataNotify in_writeDataFn=&defaultProtectedWriteFn, const char *in_pFieldDocs=NULL) |
|
static void | addDepricatedField (const char *fieldName) |
|
static bool | removeField (const char *in_pFieldname) |
|
An event to be sent over the network.
- Note
- Torque implements two methods of network data passing; this is one of them. See NetConnection 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:
- Unguaranteed events 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.
- Guaranteed events 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.
- GuaranteedOrdered events 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.
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:
- IMPLEMENT_CO_NETEVENT_V1, which indicates an event which may be sent in either direction, from the client to the server, or from the server to the client.
- IMPLEMENT_CO_CLIENTEVENT_V1, which indicates an event which may only be sent to the client.
- IMPLEMENT_CO_SERVEREVENT_V1, 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 NetConnection::setLastError() on the NetConnection 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:
{
if(message)
msg = dStrdup(message);
else
msg = NULL;
}
{
dFree(msg);
}
Simple as that! Now, onto pack(), write(), unpack(), process().
pack() is responsible for packing the event over the wire:
unpack() is responsible for unpacking the event on the other end:
process() 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.
write() 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():
The NetEvent is sent over the wire in a straightforward way (assuming you have a handle to a NetConnection):
- See Also
- 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 NetConnection::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.