messagecore.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #ifndef MessagesCore_h
  2. #define MessagesCore_h
  3. #include <dplobby.h>
  4. #include <d3dtypes.h>
  5. // MONOLITHIC_DPLAY means that we want to use a private dplay (MSRGIP.dll, MSRGTRAN.dll) instead
  6. // of the stock dplay, which has private fixes. Only those HOSTING a session will use this, even if
  7. // it's defined, which means that clients will never use it.
  8. // #define MONOLITHIC_DPLAY
  9. #define OBLIVION_CLIENT_REG_KEY "Allegiance"
  10. // Specify which flavor of dplay we're using. Never specify interface explicity anywhere else
  11. #define IDirectPlayX IDirectPlay4A
  12. #define IID_IDirectPlayX IID_IDirectPlay4A
  13. #define IDirectPlayLobbyX IDirectPlayLobby3A
  14. #define IID_IDirectPlayLobbyX IID_IDirectPlayLobby3A
  15. #define FEDMSGID unsigned short
  16. #define CFEDMSGID const FEDMSGID
  17. #define IB unsigned short // index of bytes to var-length data from start of struct
  18. #define CB unsigned short // count of bytes
  19. // ***NOTE: there is code that depends on these being the same size.
  20. typedef unsigned short MsgClsPrio;
  21. /* A FedMessage by itself is never used. It is merely the start of every message.
  22. This way, any message can be coerced to a FedMessage.
  23. */
  24. struct FEDMESSAGE
  25. {
  26. CB cbmsg;
  27. /* Size of message. Messages can be variable length. This means that you
  28. don't create them off the stack. You must calculate cbmsg (sum of all
  29. fixed length fields (just the size of the struct) + all variable length
  30. fields), and allocate a pointer to the message data off the heap. See
  31. below for function to easily create these things
  32. */
  33. FEDMSGID fmid;
  34. // actual message data immediately follows.
  35. };
  36. /* A packet is just an arbitrary number of messages strung together. Since we
  37. know how big each message is, we can easily visit each message. It also
  38. makes it easy for the client to string messages together.
  39. */
  40. /* Message naming:
  41. FM_C_*: Messages that the client sends
  42. FM_S_*: Messages that the server sends
  43. FM_CS_*: Messages that both client and server send.
  44. Coresponding structures are named FMD_*, where * is the same.
  45. Yes, FM_C_* messages and FM_S_* messages could share message numbers, but
  46. let's not, to keep it simple.
  47. */
  48. /*
  49. ************** MESSAGING CLASS **************
  50. Just make one of these FedMessaging (per session), and use it for all your messaging needs
  51. */
  52. class FedMessaging;
  53. class CFMConnection;
  54. class CFMGroup;
  55. /*-------------------------------------------------------------------------
  56. * CFMRecipient
  57. *-------------------------------------------------------------------------
  58. Purpose:
  59. This represents an addressable entity in FedMessaging
  60. */
  61. class CFMRecipient
  62. {
  63. friend CFMConnection;
  64. friend CFMGroup;
  65. public:
  66. const char * GetName() {return m_szName;}
  67. DWORD GetID() {return GetDPID();}
  68. virtual int GetCountConnections() = 0;
  69. protected:
  70. CFMRecipient(const char * szName, DPID dpid) :
  71. m_dpid(dpid)
  72. {
  73. m_szName = new char[lstrlen(szName) + 1];
  74. lstrcpy(m_szName, szName);
  75. }
  76. ~CFMRecipient()
  77. {
  78. delete [] m_szName;
  79. }
  80. DPID GetDPID() {return m_dpid;}
  81. private:
  82. char * m_szName;
  83. protected: // groups set their own dpid since they're not pre-created.
  84. void SetDPID(DPID dpid) {m_dpid = dpid;}
  85. DPID m_dpid;
  86. };
  87. /*-------------------------------------------------------------------------
  88. * CFMConnection
  89. *-------------------------------------------------------------------------
  90. Purpose:
  91. This represents one remote entity (connection). It's mainly useful only on the server, since there's lots of them
  92. */
  93. class CFMConnection : public CFMRecipient// Hungarian prefix: cnxn
  94. {
  95. friend FedMessaging;
  96. public:
  97. void SetPrivateData(DWORD dw) {m_dwPrivate = dw;}
  98. DWORD GetPrivateData() {return m_dwPrivate;}
  99. int IncAbsentCount()
  100. {
  101. return ++m_cAbsentCount;
  102. }
  103. void ResetAbsentCount()
  104. {
  105. m_cAbsentCount = 0;
  106. }
  107. void SetLastComplete(DWORD dwTime)
  108. {
  109. m_dwTimeLastComplete = dwTime;
  110. }
  111. DWORD GetLastComplete()
  112. {
  113. return m_dwTimeLastComplete;
  114. }
  115. virtual int GetCountConnections() {return 1;}
  116. private:
  117. CFMConnection(FedMessaging * fm, const char * szName, DPID dpid); // only FedMessaging::CreateConnection can create these things
  118. ~CFMConnection() {} // you can't delete these directly. You must use Delete()
  119. void Delete(FedMessaging * pfm); // basically the destructor, but with a parameter
  120. int m_cAbsentCount; // for roll call
  121. DWORD m_dwTimeLastComplete;
  122. DWORD m_dwPrivate;
  123. };
  124. typedef TList<CFMConnection*> ListConnections;
  125. /*-------------------------------------------------------------------------
  126. * CMFGroup
  127. *-------------------------------------------------------------------------
  128. Purpose:
  129. Provide group management
  130. */
  131. class CFMGroup : public CFMRecipient
  132. {
  133. friend FedMessaging;
  134. public:
  135. void AddConnection(FedMessaging * pfm, CFMConnection * pcnxn);
  136. void DeleteConnection(FedMessaging * pfm, CFMConnection * pcnxn);
  137. virtual int GetCountConnections() {return m_cPlayers;}
  138. private:
  139. CFMGroup(FedMessaging * pfm, const char * szName);
  140. ~CFMGroup() {}
  141. void PlayerAdded(CFMConnection * pcnxn);
  142. void PlayerDeleted(CFMConnection * pcnxn);
  143. void Delete (FedMessaging * pfm);
  144. int m_cPlayers;
  145. };
  146. typedef TList<CFMGroup*> ListGroups;
  147. class FMSessionDesc
  148. {
  149. public:
  150. FMSessionDesc(LPDPSESSIONDESC2 pdpSessionDesc);
  151. PCC GetGameName() {return m_strGameName;}
  152. REFGUID GetInstance() {return m_guidInstance;}
  153. int GetNumPlayers() {return m_nNumPlayers;}
  154. int GetMaxPlayers() {return m_nMaxPlayers;}
  155. private:
  156. GUID m_guidInstance; // ID for the session instance
  157. ZString m_strGameName;
  158. short m_nNumPlayers;
  159. short m_nMaxPlayers;
  160. };
  161. const CB c_cbBuff = 16<<10; // 16K
  162. enum FMGuaranteed
  163. {
  164. FM_GUARANTEED,
  165. FM_NOT_GUARANTEED,
  166. };
  167. enum FMFlush
  168. {
  169. FM_FLUSH,
  170. FM_DONT_FLUSH,
  171. };
  172. // Outgoing event interface for FedMessaging
  173. class IFedMessagingSite : public IObject
  174. {
  175. public:
  176. virtual HRESULT OnAppMessage(FedMessaging * pthis, CFMConnection & cnxnFrom, FEDMESSAGE * pfm) = 0;
  177. virtual HRESULT OnSysMessage(FedMessaging * pthis) {return S_OK;}
  178. virtual void OnMessageNAK(FedMessaging * pthis, DWORD dwTime, CFMRecipient * prcp) {}
  179. virtual int OnMessageBox(FedMessaging * pthis, const char * strText, const char * strCaption, UINT nType) {return 0;}
  180. virtual HRESULT OnNewConnection(FedMessaging * pthis, CFMConnection & cnxn) {return S_OK;}
  181. virtual HRESULT OnDestroyConnection(FedMessaging * pthis, CFMConnection & cnxn) {return S_OK;}
  182. virtual HRESULT OnSessionLost(FedMessaging * pthis) {return S_OK;}
  183. virtual void OnPreCreate (FedMessaging * pthis) {}
  184. virtual void OnPostCreate(FedMessaging * pthis, IDirectPlayX* pdpIn, IDirectPlayX** pdpOut) {*pdpOut = pdpIn;}
  185. virtual void OnSessionFound(FedMessaging * pthis, FMSessionDesc * pSessionDesc) {} // you cannot save any pointer to session desc
  186. virtual void OnMessageSent(FedMessaging * pthis, CFMRecipient * precip, const void * pv, DWORD cb, FMGuaranteed fmg) {}
  187. #ifndef NO_MSG_CRC
  188. virtual void OnBadCRC(FedMessaging * pthis, CFMConnection & cnxn, BYTE * pMsg, DWORD cbMsg) {}
  189. #endif
  190. };
  191. class FedMessaging
  192. {
  193. public:
  194. static const MsgClsPrio c_mcpDefault;
  195. FedMessaging(IFedMessagingSite * pfmSite);
  196. ~FedMessaging();
  197. HRESULT Connect(const char * szAddress);
  198. HRESULT HostSession(GUID guidApplication, bool fKeepAlive, HANDLE hEventServer, bool fProtocol
  199. #ifdef MONOLITHIC_DPLAY
  200. , bool fMonolithic = true
  201. #endif
  202. );
  203. HRESULT JoinSession(GUID guidApplication, const char * szServer, const char * szName);
  204. HRESULT JoinSessionInstance(GUID guidInstance, const char * szName);
  205. GUID GetHostApplicationGuid()
  206. {
  207. return m_guidApplication;
  208. }
  209. GUID GetSessionGuid()
  210. {
  211. assert(m_pDirectPlay);
  212. return m_guidInstance;
  213. }
  214. int SendMessages(CFMRecipient * precip, FMGuaranteed fmg, FMFlush fmf);
  215. void ForwardMessage(CFMRecipient * precip, const FEDMESSAGE* pfm, FMGuaranteed fmg)
  216. {
  217. GenericSend(precip, pfm, pfm->cbmsg, fmg);
  218. }
  219. HRESULT GenericSend(CFMRecipient * precip, const void * pv, CB cb, FMGuaranteed fmg);
  220. void Shutdown();
  221. inline bool IsConnected()
  222. {
  223. return m_fConnected;
  224. }
  225. bool CheckVersion();
  226. void * PFedMsgCreate(bool fQueueMsg, BYTE * pbFMBuff, FEDMSGID fmid, CB cbfm, ...);
  227. /* The variable parameters are pairings of pointers to the variable length
  228. members, and their lengths (type MUST be CB), followed by FM_END to
  229. terminate the variable length parameter list. Pointers/lengths must
  230. be provided for every variable length member of the message. Pointers
  231. can be null if that member is not used (in which case the length is
  232. ignored, but must still be supplied. It is an error to provide a valid
  233. pointer with a length of zero. The value CB_ZTS may be used for null-
  234. terminated strings, instead of predetermining their length. After
  235. creating a message, you then fill in the fixed length stuff yourself.
  236. The variable length stuff is copied, so you don't have to keep it around.
  237. ***NEVER*** call this function directly. Use the BEGINPFMCREATE,
  238. FM_VAR_PARM, and ENDPFMCREATE macros.
  239. You can always cast PFedMsgCreate() to a FEDMESSAGE*, but I don't return
  240. FEDMESSAGE*, so that you can assign the return value to any message
  241. without requiring additional casting
  242. Since the only reason to create a message is to send it, messages
  243. automagically get recycled after sending them. Hence it is a bug to try
  244. to reference a message once it's been sent. Likewise, there is no need
  245. (or way) to free a message created with this function.
  246. */
  247. HRESULT ReceiveMessages();
  248. BYTE * BuffOut()
  249. {
  250. return m_fSecondaryOut ? m_rgbbuffSecondaryOutPacket : m_rgbbuffOutPacket;
  251. }
  252. CB GetBuffOutSize()
  253. {
  254. return m_fSecondaryOut ? sizeof(m_rgbbuffSecondaryOutPacket) : sizeof(m_rgbbuffOutPacket)
  255. #ifndef NO_MSG_CRC
  256. - sizeof(int) // crc
  257. #endif
  258. ;
  259. }
  260. BYTE * BuffIn()
  261. {
  262. return m_rgbbuffInPacket;
  263. }
  264. DWORD PacketSize()
  265. {
  266. return m_dwcbPacket
  267. #ifndef NO_MSG_CRC
  268. - sizeof(int) // crc
  269. #endif
  270. ;
  271. }
  272. void PurgeOutBox()
  273. {
  274. m_pbFMNext = BuffOut();
  275. m_precipDefault = NULL;
  276. }
  277. CB CbFreeSpaceInOutbox()
  278. {
  279. return GetBuffOutSize() - CbUsedSpaceInOutbox();
  280. }
  281. CB CbUsedSpaceInOutbox()
  282. {
  283. return m_pbFMNext - ((BYTE*) BuffOut());
  284. }
  285. void QueueExistingMsg(const FEDMESSAGE * pfm);
  286. void SetPriority(USHORT priority) {m_priority = priority;}
  287. USHORT GetPriority()
  288. {
  289. return m_priority;
  290. }
  291. static USHORT GetGuaranteedBias()
  292. {
  293. return 1000;
  294. }
  295. Time CheckOdometer(float& flDTime, int& cMsgsOdometer, int& cBytesOdometer);
  296. void SetDefaultRecipient(CFMRecipient * precip, FMGuaranteed fmg);
  297. CFMRecipient * GetDefaultRecipient(FMGuaranteed * pfmg);
  298. int GetConnectionCount()
  299. {
  300. return m_listCnxns.GetCount();
  301. }
  302. ListConnections * GetConnections()
  303. {
  304. return &m_listCnxns;
  305. }
  306. CFMConnection * GetConnectionFromId(DWORD id)
  307. {
  308. return GetConnectionFromDpid((DPID) id);
  309. }
  310. CFMConnection * GetServerConnection()
  311. {
  312. return m_pcnxnServer;
  313. }
  314. CFMGroup * CreateGroup(const char * szName)
  315. {
  316. static CTempTimer tt("in CreateGroup", .01f);
  317. tt.Start();
  318. CFMGroup * pgrp = new CFMGroup(this, szName);
  319. tt.Stop();
  320. m_listGroups.PushFront(pgrp);
  321. return pgrp;
  322. }
  323. void DeleteConnection(CFMConnection & cnxn)
  324. {
  325. static CTempTimer tt("in DeleteConnection", .01f);
  326. tt.Start();
  327. m_pfmSite->OnDestroyConnection(this, cnxn);
  328. tt.Stop();
  329. m_listCnxns.Remove(&cnxn);
  330. cnxn.Delete(this);
  331. }
  332. void DeleteGroup(CFMGroup * pgrp)
  333. {
  334. if (pgrp)
  335. {
  336. m_listGroups.Remove(pgrp);
  337. static CTempTimer tt("in DeleteGroup", .01f);
  338. tt.Start();
  339. pgrp->Delete(this);
  340. tt.Stop();
  341. }
  342. }
  343. void AddConnectionToGroup(CFMGroup * pgrp, CFMConnection * pcnxn)
  344. {
  345. assert(pgrp && pcnxn);
  346. static CTempTimer tt("in AddConnectionToGroup", .01f);
  347. tt.Start();
  348. pgrp->AddConnection(this, pcnxn);
  349. tt.Stop();
  350. }
  351. void DeleteConnectionFromGroup(CFMGroup * pgrp, CFMConnection * pcnxn)
  352. {
  353. assert(pgrp && pcnxn);
  354. static CTempTimer tt("in DeleteConnectionFromGroup", .01f);
  355. tt.Start();
  356. pgrp->DeleteConnection(this, pcnxn);
  357. tt.Stop();
  358. }
  359. HRESULT GetIPAddress(CFMConnection & cnxn, char szRemoteAddress[16]);
  360. HRESULT GetSendQueue(DWORD * pcMsgs, DWORD * pcBytes)
  361. {
  362. return GetDPlay()->GetMessageQueue(0, 0, DPMESSAGEQUEUE_SEND, pcMsgs, pcBytes);
  363. }
  364. HRESULT GetReceiveQueue(DWORD * pcMsgs, DWORD * pcBytes)
  365. {
  366. return GetDPlay()->GetMessageQueue(0, 0, DPMESSAGEQUEUE_RECEIVE, pcMsgs, pcBytes);
  367. }
  368. HRESULT GetConnectionSendQueue(CFMConnection * pcnxn, DWORD * pcMsgs, DWORD * pcBytes)
  369. {
  370. return GetDPlay()->GetMessageQueue(0, pcnxn->GetDPID(), DPMESSAGEQUEUE_SEND, pcMsgs, pcBytes);
  371. }
  372. CFMGroup * Everyone()
  373. {
  374. return m_pgrpEveryone;
  375. }
  376. IDirectPlayX * GetDPlay() // only messaging stuff should need this
  377. {
  378. return m_pDirectPlay;
  379. }
  380. void UseMainOutBox(bool fMain) // set false for one or more messages that don't go to the same recipient as main stream
  381. {
  382. if (fMain == m_fSecondaryOut)
  383. {
  384. BYTE * pbT = m_pbFMNextT;
  385. m_pbFMNextT = m_pbFMNext; // save this for when we switch back
  386. m_pbFMNext = pbT;
  387. m_fSecondaryOut = !fMain;
  388. }
  389. }
  390. DWORD GetCountConnections()
  391. {
  392. DPSESSIONDESC2 * psd = NULL;
  393. DWORD dwSize = 0;
  394. HRESULT hr = m_pDirectPlay->GetSessionDesc(psd, &dwSize);
  395. assert (DPERR_BUFFERTOOSMALL == hr);
  396. psd = (DPSESSIONDESC2 *) new char[dwSize];
  397. ZSucceeded(m_pDirectPlay->GetSessionDesc(psd, &dwSize));
  398. DWORD dwConnections = psd->dwCurrentPlayers - 1; // let's not count the server
  399. delete [] psd;
  400. return dwConnections;
  401. }
  402. Time GetLastMsgTime()
  403. {
  404. return m_timeMsgLast;
  405. }
  406. HRESULT GetLinkDetails(CFMConnection * pcnxn, OUT DWORD * pdwHundredbpsG, OUT DWORD * pdwmsLatencyG,
  407. OUT DWORD * pdwHundredbpsU, OUT DWORD * pdwmsLatencyU)
  408. {
  409. DPCAPS caps;
  410. HRESULT hr = E_FAIL;
  411. if (!pcnxn || !GetDPlay()) // throw error?
  412. return E_FAIL;
  413. caps.dwSize = sizeof(caps);
  414. hr = GetDPlay()->GetPlayerCaps(pcnxn->GetDPID(), &caps, DPGETCAPS_GUARANTEED);
  415. if FAILED(hr)
  416. goto Exit;
  417. if (pdwHundredbpsG)
  418. *pdwHundredbpsG = caps.dwHundredBaud;
  419. if (pdwmsLatencyG)
  420. *pdwmsLatencyG = caps.dwLatency;
  421. hr = GetDPlay()->GetPlayerCaps(pcnxn->GetDPID(), &caps, 0);
  422. if FAILED(hr)
  423. goto Exit;
  424. if (pdwHundredbpsU)
  425. *pdwHundredbpsU = caps.dwHundredBaud;
  426. if (pdwmsLatencyU)
  427. *pdwmsLatencyU = caps.dwLatency;
  428. Exit:
  429. return hr;
  430. }
  431. HRESULT EnumSessions(GUID guidApplication, const char * szServer); // blank for broadcast
  432. void SetSessionDetails(char * szDetails) // tokenized name/value pairs: Name\tValue\nName\tValue...
  433. {
  434. char rgchBuff[10<<10];
  435. LPDPSESSIONDESC2 pdpSession = (LPDPSESSIONDESC2) rgchBuff;
  436. DWORD dw = sizeof(rgchBuff);
  437. assert(m_pDirectPlay);
  438. ZSucceeded(m_pDirectPlay->GetSessionDesc(pdpSession, &dw));
  439. pdpSession->lpszSessionNameA = szDetails;
  440. m_pDirectPlay->SetSessionDesc(pdpSession, 0);
  441. }
  442. void ResetOutBuffer()
  443. {
  444. m_pbFMNextT = m_rgbbuffSecondaryOutPacket; // save this for when we switch back
  445. m_pbFMNext = m_rgbbuffOutPacket;
  446. m_fSecondaryOut = false;
  447. }
  448. private:
  449. Time m_timeMsgLast;
  450. CFMConnection* GetConnectionFromDpid(DPID dpid);
  451. CFMGroup * GetGroupFromDpid(DPID dpid);
  452. CFMConnection * CreateConnection(const char * szName, DPID dpid); // after the physical connection has already been established
  453. FEDMESSAGE * PfmGetNext(FEDMESSAGE * pfm); // Use to run through all messages in a received packet
  454. // returns NULL if no more messages in packet
  455. IDirectPlayLobbyX * GetDPlayLobby()
  456. {
  457. return m_pDirectPlayLobby;
  458. }
  459. int SendToDefault(FMFlush fmf);
  460. HRESULT InitDPlay(
  461. #ifdef MONOLITHIC_DPLAY
  462. bool fMonolithic
  463. #endif
  464. );
  465. bool KillSvr();
  466. HRESULT ConnectToDPAddress(LPVOID pAddress);
  467. HRESULT OnSysMessage(FedMessaging * pthis, LPDPMSG_GENERIC pMsg);
  468. HRESULT EnumSessionsInternal(GUID guidApplication, const char * szServer);
  469. friend BOOL FAR PASCAL EnumSessionsCallback(LPCDPSESSIONDESC2 lpThisSD,
  470. LPDWORD lpdwTimeOut,
  471. DWORD dwFlags,
  472. LPVOID lpContext);
  473. BYTE m_rgbbuffInPacket[c_cbBuff];
  474. BYTE m_rgbbuffOutPacket[c_cbBuff];
  475. BYTE m_rgbbuffSecondaryOutPacket[1<<10];
  476. BYTE m_rgbbuffAlloc[2<<10]; // 2K this is a temp buffer for alloc'd messages
  477. BYTE * m_pbFMNext; // where next message gets queued in the CURRENT outbox
  478. BYTE * m_pbFMNextT; // where next message IN THE OTHER OUTBOX gets queued
  479. DWORD m_dwcbPacket; // size of packet read, not CB because used with DPlay
  480. USHORT m_priority;
  481. Time m_timeOdometerStart;
  482. int m_cMsgsOdometer;
  483. int m_cBytesOdometer;
  484. CFMRecipient * m_precipDefault; // default recipient, if buffer overflows, or DPID_UNKNOWN is specified in SendMessages
  485. FMGuaranteed m_fmGuaranteedDefault;
  486. bool m_fConnected : 1;
  487. bool m_fSecondaryOut : 1;
  488. bool m_fSessionCallback : 1;
  489. CFMConnection * m_pcnxnMe; // this connection is NOT in the list m_listCnxns, and no site events fire on it.
  490. CFMConnection * m_pcnxnServer; // same as above, used only by GetServerConnection
  491. CFMGroup * m_pgrpEveryone;
  492. GUID m_guidInstance;
  493. GUID m_guidApplication; // guid given to HostSession()
  494. IDirectPlayX * m_pDirectPlay;
  495. IDirectPlayLobbyX * m_pDirectPlayLobby;
  496. IFedMessagingSite * m_pfmSite;
  497. // these lists are somewhat redundant, since dplay manages them also, but it's nice to have our own list (maybe)
  498. ListConnections m_listCnxns;
  499. ListGroups m_listGroups;
  500. int m_cbConnection; // sizeof each connection
  501. };
  502. #define CB_ZTS 0xffff // indicates zero terminated string ONLY when creating
  503. // messages via PFedMsgCreate. CBs always hold true value for all var fields
  504. #define FM_END_VAR_PARMS (BYTE*) 0xffffffff // Always last argument passed to PFedMsgCreate.
  505. /* *************** MESSAGE CREATION MACROS ***************
  506. Use these to actually create messages
  507. */
  508. // Use this for messages with a fixed size that will be sent
  509. #define PFM_CREATE_STATIC(FM_VAR, TYPE, SHORTNAME) \
  510. static FMD_##TYPE##_##SHORTNAME FM_VAR; \
  511. FM_VAR.fmid = FM_##TYPE##_##SHORTNAME; \
  512. FM_VAR.cbmsg = sizeof(FMD_##TYPE##_##SHORTNAME);
  513. // main macro use to create a message and queue it.
  514. #define BEGIN_PFM_CREATE(OBJ, FM_VAR, TYPE, SHORTNAME) \
  515. FMD_##TYPE##_##SHORTNAME * FM_VAR = (FMD_##TYPE##_##SHORTNAME *) \
  516. (OBJ).PFedMsgCreate(true, NULL, FM_##TYPE##_##SHORTNAME, sizeof(FMD_##TYPE##_##SHORTNAME),
  517. // Use these to create message without queing them to be sent, and to delete the message
  518. // The OBJ for doesn't reference any class data, so you can use any handy obj
  519. #define BEGIN_PFM_CREATE_ALLOC(OBJ, FM_VAR, TYPE, SHORTNAME) \
  520. FMD_##TYPE##_##SHORTNAME * FM_VAR = (FMD_##TYPE##_##SHORTNAME *) \
  521. (OBJ).PFedMsgCreate(false, NULL, FM_##TYPE##_##SHORTNAME, sizeof(FMD_##TYPE##_##SHORTNAME),
  522. #define PFM_DEALLOC(PFM) (GlobalFreePtr(PFM))
  523. // Use this to create message into prealloc'd memory without queing it to be sent
  524. #define BEGIN_PFM_CREATE_PREALLOC(OBJ, PBFM, TYPE, SHORTNAME) \
  525. (OBJ).PFedMsgCreate(false, (BYTE*)(PBFM), FM_##TYPE##_##SHORTNAME, sizeof(FMD_##TYPE##_##SHORTNAME),
  526. // Use this to make sure they're always given in pairs and typed correctly
  527. #define FM_VAR_PARM(PBLOB, CBBLOB) (BYTE *)(PBLOB), (CB *)(CBBLOB),
  528. #define END_PFM_CREATE FM_END_VAR_PARMS );
  529. #define CASTPFM(FM_NEWVAR, TYPE, SHORTNAME, FM_OLDVAR) \
  530. FMD_##TYPE##_##SHORTNAME * FM_NEWVAR = (FMD_##TYPE##_##SHORTNAME *) (FM_OLDVAR)
  531. // Only use these macros to define new messages
  532. // TYPE is one of C (only client sends this message), S (only server creates),
  533. // or CS (both client and server send it--usually originated by client, rebroadcast by server)
  534. // NUMBER is unique message number. Just use the next available number
  535. #define DEFINE_FEDMSG(TYPE, SHORTNAME, NUMBER) \
  536. CFEDMSGID FM_##TYPE##_##SHORTNAME = NUMBER; \
  537. static AddMsg AM_##TYPE##_##SHORTNAME(NUMBER, "FM_" #TYPE "_" #SHORTNAME); \
  538. struct FMD_##TYPE##_##SHORTNAME : public FEDMESSAGE \
  539. {
  540. #define END_FEDMSG };
  541. // Only use this to create variable length fields. NO fixed-size members can precede this
  542. #define FM_VAR_ITEM(NAME) IB ib##NAME; CB cb##NAME
  543. // Use this to actually reference existing var-length props
  544. #define FM_VAR_REF(PFM, NAME) ((PFM)->cb##NAME ? (char*)(PFM) + (PFM)->ib##NAME : NULL)
  545. /* For each message structure, the variable length items MUST go first, then the
  546. fixed length items
  547. We also need to keep track of the most number of variable length parameters
  548. that any message has (MAXVARPARMS), because it makes creating messages much easier
  549. */
  550. #define MAXVARPARMS 10
  551. /* Pointers to messages (pfm's) can be saved only for subsequent messages within the same packet
  552. The following macro can be used for asserts where you want to ensure that a previous message
  553. pointer is still valid
  554. */
  555. #define IS_VALID_PFM(PFM, TYPE, SHORTNAME) \
  556. (!IsBadReadPtr(PFM, sizeof(FEDMESSAGE)) && \
  557. FM_##TYPE##_##SHORTNAME == ((FEDMESSAGE *)(PFM))->fmid && \
  558. !IsBadReadPtr(PFM, ((FEDMESSAGE *)(PFM))->cbmsg))
  559. extern char * g_rgszMsgNames[];
  560. #define MAXMESSAGES 400
  561. #define ALLOC_MSG_LIST char * g_rgszMsgNames[MAXMESSAGES + 1]
  562. /*-------------------------------------------------------------------------
  563. * AddMsg
  564. *-------------------------------------------------------------------------
  565. * Purpose:
  566. * Automatically build array of message names
  567. *
  568. * Notes:
  569. * Called during global variable initialization, so no call stack
  570. */
  571. class AddMsg
  572. {
  573. public:
  574. AddMsg(FEDMSGID fmid, char * szMsgName)
  575. {
  576. assert (fmid <= MAXMESSAGES);
  577. g_rgszMsgNames[fmid] = szMsgName;
  578. }
  579. };
  580. #endif