convert line ends
[canaan.git] / prj / cam / src / framewrk / netmsg.h
blobf4306f0821e2594d6c227e78af3b82f455fb7576
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/framewrk/netmsg.h,v 1.21 2000/01/29 13:21:26 adurant Exp $
7 //
8 // Simple network messaging
9 //
10 // The cNetMsg class provides a relatively straightforward way for normal
11 // network messages to be created and sent. It can't handle every case,
12 // but it *can* deal with most messages needed by the Dark engine; it's
13 // quite flexible. It particularly deals with a lot of the random overhead
14 // that most callers don't care about, like marshalling and unmarshalling
15 // parameters, checking the networking is running, validating objects, and
16 // so on.
18 // It is specifically back-compatible with older network code; systems that
19 // use netman directly can ignore cNetMsg without harm. The intent is that
20 // most messages will eventually migrate to this mechanism, because it is
21 // generally a bit clearer than the old one.
23 // Note that we assume a single-threaded system; Send() is *not* thread-safe.
25 #pragma once
27 #ifndef __NETMSG_H
28 #define __NETMSG_H
30 #include <stdarg.h>
31 #include <comtools.h>
32 #include <objtype.h>
33 #include <nettypes.h>
35 F_DECLARE_INTERFACE(INetManager);
36 F_DECLARE_INTERFACE(IObjectNetworking);
37 F_DECLARE_INTERFACE(IObjectSystem);
39 //////////
41 // Message descriptor information
43 // You initialize a message by constructing a cNetMsg, initializing it with
44 // a message descriptor. This descriptor gives all kinds of information
45 // about how the message works.
48 // The types of parameters that are currently understood. All get passed
49 // into Send() by value, except as noted:
50 typedef enum eNetMsgParamType {
51 // Integer types:
52 kNMPT_Int,
53 kNMPT_UInt,
54 kNMPT_Short,
55 kNMPT_UShort,
56 kNMPT_Byte,
57 kNMPT_UByte,
59 // Normal boolean; param is standard int-width, but transmitted as
60 // a single byte (or bit):
61 kNMPT_BOOL,
63 // Kinds of ObjIDs:
64 // An object owned by the sender:
65 kNMPT_SenderObjID,
66 // An object owned by the receiver:
67 kNMPT_ReceiverObjID,
68 // An abstract object (generally an archetype):
69 kNMPT_AbstractObjID,
70 // An object whose ownership isn't dealt with (only for special
71 // circumstances):
72 kNMPT_ObjID,
73 // An object whose ownership is unknown (might be on any machine):
74 kNMPT_GlobalObjID,
76 // A float:
77 kNMPT_Float,
79 // A vector; pass in as (mxs_vector *):
80 kNMPT_Vector,
82 // Blocks of opaque data. Maximum length of such a block is currently
83 // 65535.
84 // A block whose size is specified at compile-time, in the size field;
85 // pass in a pointer to the block:
86 kNMPT_Block,
87 // A block whose size will be specified at runtime; pass in the size
88 // of the block as an integer, *then* the pointer to the block:
89 kNMPT_DynBlock,
91 // A string; pass in a const char *:
92 kNMPT_String,
94 // A MultiParm, from the script system. This can resolve to an
95 // integer, an object, a float, a string, or a vector. Note that you must
96 // *EXPLICITLY* pass a pointer to the cMultiParm in Send(), rather than
97 // assuming the compiler will deal with it as usual. This is due to
98 // the limitations of variable-length argument lists.
99 kNMPT_MultiParm,
100 // A MultiParm, which should be resolved as an object if it's an integer.
101 // @OBSOLETE: this was formerly used to indicate that the cMultiParm
102 // should be treated as an object. Now, however, we detect which one
103 // the cMultiParm thinks it is...
104 kNMPT_GlobalObjIDMultiParm,
106 // The null parameter, which should be used to indicate the end
107 // of the descriptor:
108 kNMPT_End,
109 } eNetMsgParamType;
111 // Flags controlling the behaviour of how we marshal and unmarshal params:
112 typedef enum eNetMsgParamFlags {
113 // Flags for kNMPT_SenderObjID params
114 kNMPF_None = 0,
115 // Test that the object is owned here, and don't send if not:
116 kNMPF_IfHostedHere = 1 << 0,
117 // Don't assert that the SenderObjID object is owned here:
118 kNMPF_NoAssertHostedHere = 1 << 1,
119 // Permit OBJ_NULL to be sent through this parameter:
120 kNMPF_AllowObjNull = 1 << 2,
122 // Flags for kNMPT_ReceiverObjID params
123 // Messages should be sent to the owner of this param's object:
124 kNMPF_SendToOwner = 1 << 3,
126 // Flags for all params
127 // Suppress this parameter in spews
128 kNMPF_SuppressSpew = 1 << 4,
129 // Don't reject this message if this ObjID doesn't exist. Normally,
130 // if a Sender, Receiver, or GlobalObjID in the message doesn't exist,
131 // the message is rejected. If this is set, it is the handler's
132 // responsibility to check for object existence.
133 kNMPF_AllowNonExistentObj = 1 << 5,
134 } eNetMsgParamFlags;
137 // A single parameter in the network message.
139 // You must specify the type of each parameter. Flags are optional, and
140 // can be left as 0 in all cases to get default behaviour. Size is only
141 // relevant in a few types. Name is the name of the parameter, for printing
142 // in spews, and is always optional.
144 struct sNetMsgParam {
145 eNetMsgParamType type;
146 int flags; // should be from eNetMsgParamFlags
147 const char *name;
148 int size;
151 // Flags controlling message behaviour in general
152 typedef enum eNetMsgFlags {
153 kNMF_None = 0,
154 // This message should be sent non-guaranteed
155 kNMF_Nonguaranteed = 1 << 0,
157 // Send flags. If none are given, then the message is sent
158 // to the player specified in the Send() method:
159 // This message should be sent even during metagame, before synch
160 kNMF_MetagameBroadcast = 1 << 1,
161 // This message gets broadcast to all the other players
162 kNMF_Broadcast = 1 << 2,
163 // This message is sent to the owner of the receive objIDs
164 kNMF_SendToObjOwner = 1 << 3,
165 // This message is sent to the default host
166 kNMF_SendToHost = 1 << 4,
168 // Append the sending player's ObjID onto the receiver's params. This
169 // ObjID comes *before* the pClientData, but *after* all other params.
170 kNMF_AppendSenderID = 1 << 5,
171 // Do not forward this message, if the target object has been rehosted.
172 // This should generally be used if SendToObjOwner is set, which allows
173 // forwarding, and AppendSenderID is set, since the SenderID will be
174 // incorrect. If NoForwarding is set, the handler must be prepared to
175 // cope if the message is received and we don't own the object any
176 // longer.
177 kNMF_NoForwarding = 1 << 6,
178 // *Always* send this message, even if we're in a nominally unnetworked
179 // level. Must be used in conjunction with MetagameBroadcast, and should
180 // be used with extreme care.
181 kNMF_AlwaysBroadcast = 1 << 7,
182 } eNetMsgFlags;
185 // Message handler function type
187 // This should return void, and have a signature that matches the
188 // parameters specified. (Optionally ending with the pClientData passed
189 // in at startup.)
191 typedef void *tMsgHandlerFunc;
194 // The full descriptor of what this message looks like
196 struct sNetMsgDesc {
197 // The general behaviour of this message (mask from eNetMsgFlags)
198 ulong behaviour;
199 // The short name of this message (optional)
200 const char *shortName;
201 // The user-printable name of this message (optional)
202 const char *msgName;
203 // The name of the spew flag for this message (optional)
204 // If omitted, defaults to "net_spew"
205 const char *spewName;
206 // A routine to dispatch to when we get the message. This is optional;
207 // if present, its signature should match the parameters given here.
208 // If pClientData was passed in when the message was created, then that
209 // will be sent as the final parameter.
210 tMsgHandlerFunc msgHandler;
211 // An array of parameters, ending with kNMPT_End
212 sNetMsgParam params[];
215 //////////
217 // The cNetMsg class itself
219 // Instantiate one of these for each kind of message. Pass in an
220 // sNetMsgDesc describing the message.
222 class cNetMsg {
223 public:
224 // The constructor. Desc describes most of the abilities of this
225 // message. pClientData is optional, to use as needed. (Mostly, it
226 // gets filled with pointers to a c++ object.)
227 cNetMsg(sNetMsgDesc *pDesc, void *pClientData = NULL);
228 virtual ~cNetMsg();
230 // Send a message out. Player is ignored if the target of the message
231 // is calculated from the params, or if it is a broadcast message.
232 // The parameters should match the declared params for this message;
233 // however, don't worry about casting between simple numeric types.
235 // This is *not* thread-safe, because we're using a single static
236 // buffer for all messages. If we find that we need to send messages
237 // from multiple threads, then we will either have to put a lock on
238 // Send, or we'll have to go back to having separate (possibly dynamic)
239 // message buffers.
240 virtual void Send(ObjID player, ...);
242 protected:
244 //////////
246 // Internal Methods
250 // Interpret an incoming message. This is the one that instances will
251 // most often want to override. It is called after parameters have
252 // been unmarshalled; you should generally call GetParam to get
253 // the desired parameters and do things with them.
255 // By default, this does nothing.
257 virtual void InterpretMsg(ObjID fromPlayer) {}
260 // Deal with a raw message from the network. This method is responsible
261 // for unmarshalling; you shouldn't override it unless you need to do
262 // custom unmarshalling for this message type.
264 virtual void HandleMsg(const sNetMsg_Generic *pGenericMsg,
265 ulong msgSize,
266 ObjID fromPlayer);
269 // Assemble the actual message into m_pMsgBuffer, based on the given
270 // argument list. The default method will generally do the right thing,
271 // but a custom message could potentially want to do this itself.
272 // Returns FALSE iff we shouldn't send this message, for whatever
273 // reason.
275 virtual BOOL MarshalArguments(va_list pArgs, ObjID *objPlayer, uint *size);
278 // Take apart the raw network message, and put the pieces into the
279 // params array. If, upon return, pForwardTo is not OBJ_NULL, then this
280 // message should be forwarded to that player.
282 virtual BOOL UnmarshalParams(uchar *ptr,
283 ObjID fromPlayer,
284 ObjID *pForwardTo);
286 // Clean up after the marshalling, as needed.
288 virtual void ClearParams();
291 // Loopback
292 // This will get called if we decide that this message is simply going
293 // to the local player, and doesn't need to go through networking.
294 // It eliminates the marshal/unmarshal procedure.
296 // Note that we loopback if the message is going to the default host,
297 // and that's us, or if it's SendToObjOwner and that's us *and* the
298 // ReceiverObjID is the first param. (To make the check fast.) So if
299 // you want to take advantage of loopback, put the ReceiverObjIDs first.
301 virtual void DoLoopback(va_list pArgs);
304 // Forwarding
305 // If a message is SendToObjOwner, but the object's owner changes while
306 // the message is in transit, the old owner needs to pass it along.
307 // This method will send the already-parsed message on to its new owner.
309 virtual void ForwardMsg(ObjID forwardTo);
312 // Spew methods
314 // By default, we spew the parameters as specified in the sNetMsgDesc.
315 // This isn't very aesthetic, though, so you can give a method to
316 // spew more carefully if desired.
318 // Spew a message at send time, based on the given params:
319 virtual void SendSpew(va_list pArgs);
320 // Spew a message at receive time, based on the unmarshall params:
321 virtual void ReceiveSpew(ObjID fromPlayer);
323 // Get a specific parameter. (Zero-based.) The caller is responsible
324 // for casting the value appropriately.
325 DWORD GetParam(int index);
327 // Send the message off to an outside handler
328 void SendToHandler();
330 // Check a proxy's archetype against one that was sent
331 void CheckArchetypes(sGlobalObjID obj, ObjID proxy, ObjID sentArch);
333 //////////
335 // Member variables
338 // The descriptor for the message:
339 sNetMsgDesc *m_pDesc;
340 // The number of parameters, possibly including the player ID:
341 int m_NumDispatchParams;
342 // The number of *real* parameters in the message:
343 int m_NumParams;
345 // The handlerID we got from netman:
346 tNetMsgHandlerID m_handlerID;
348 // The client-specific data, if any:
349 void *m_pClientData;
351 // The unmarshalled parameters. You will generally get at these through
352 // GetParam.
353 DWORD *m_ppParams;
355 // TRUE iff we should always spew this particular message:
356 BOOL m_bSpewMe;
358 // TRUE iff we are in the middle of forwarding a message:
359 BOOL m_bForwarding;
361 private:
363 //////////
365 // Static stuff
369 // Methods
371 // Initialization code for the whole net-message system. Will get called
372 // automatically when the first message gets created:
373 static void InitNetMsgs();
374 // Shutdown code. Will get called when the last message dies:
375 static void TermNetMsgs();
377 // Listener. This will be called by netman whenever something really
378 // interesting happens:
379 static void NetListen(eNetListenMsgs situation,
380 DWORD data,
381 void *pClientData);
383 // Top-level dispatcher. This will send network messages to the right
384 // cNetMsg object.
385 static void NetDispatcher(const sNetMsg_Generic *pMsg,
386 ulong msgSize,
387 ObjID fromPlayer,
388 void *pClientData);
391 // Global Members
394 // The message buffer
395 // Note that we assume that a single message buffer is okay: we assume
396 // that we don't have multiple threads and aren't re-entrant
397 static uchar *gm_pMsgBuffer;
399 // The Network Manager
400 static INetManager *gm_pNetMan;
402 // The Object Networking manager
403 static IObjectNetworking *gm_pObjNet;
405 // The Object System
406 static IObjectSystem *gm_pObjSys;
408 // The number of messages that have been registered through netmsg
409 static int gm_NumMsgs;
411 // Are we currently networking?
412 static BOOL gm_bNetworking;
414 // Should we do archetype checking?
415 static BOOL gm_bAssertArchetypes;
418 //////////
420 inline DWORD cNetMsg::GetParam(int index)
422 return m_ppParams[index];
425 #endif // !__NETMSG_H