cadetplay.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. #include "pch.h"
  2. #include "dplay.h"
  3. #include "dplobby.h"
  4. // {BF062CD6-D0EE-11d2-99B6-00E0291AB536}
  5. static const GUID CLSID_CADET =
  6. { 0xbf062cd6, 0xd0ee, 0x11d2, { 0x99, 0xb6, 0x0, 0xe0, 0x29, 0x1a, 0xb5, 0x36 } };
  7. static const GUID GUID_NULL =
  8. { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00 } };
  9. static const DPCOMPORTADDRESS cDPCPA =
  10. {
  11. #ifdef DREAMCAST
  12. 1,
  13. CBR_115200,
  14. #else
  15. 4,
  16. CBR_115200,
  17. #endif
  18. ONESTOPBIT,
  19. NOPARITY,
  20. DPCPA_RTSFLOW,
  21. };
  22. BOOL FAR PASCAL GetFirstSession(LPCDPSESSIONDESC2 lpThisSD, LPDWORD lpdwTimeOut, DWORD dwFlags, LPVOID lpContext)
  23. {
  24. LPDPSESSIONDESC2 lpdpsd = (LPDPSESSIONDESC2)lpContext;
  25. if (dwFlags==DPESC_TIMEDOUT)
  26. { // No sessions found
  27. debugf("Session enumeration timed out\r\n");
  28. return (FALSE);
  29. }
  30. memcpy(lpdpsd, lpThisSD, sizeof(DPSESSIONDESC2));
  31. #ifdef DREAMCAST
  32. int length = wcslen(lpThisSD->lpszSessionName) + 1;
  33. lpdpsd->lpszSessionName = new WCHAR[length];
  34. memcpy(lpdpsd->lpszSessionName, lpThisSD->lpszSessionName, length * 2);
  35. #else
  36. int length = strlen(lpThisSD->lpszSessionNameA) + 1;
  37. lpdpsd->lpszSessionNameA = new char[length];
  38. memcpy(lpdpsd->lpszSessionNameA, lpThisSD->lpszSessionNameA, length);
  39. #endif
  40. return (FALSE);
  41. };
  42. static TCHAR szPhone1[] = TEXT("101");
  43. static TCHAR szPhone2[] = TEXT("202");
  44. class CadetPlayImpl : public CadetPlay
  45. {
  46. private:
  47. DPID m_dpid;
  48. TRef<IDirectPlay3> m_pDirectPlay;
  49. TRef<IDirectPlayLobby2> m_pDirectPlayLobby;
  50. TRef<CadetPlaySite> m_pCadetPlaySite;
  51. CadetMode m_cm;
  52. Time m_timeLastUpdate;
  53. public:
  54. CadetPlayImpl():
  55. m_cm(cmSinglePlayer)
  56. {
  57. m_timeLastUpdate = Time::Now();
  58. }
  59. void SetCadetPlaySite(CadetPlaySite* psite)
  60. {
  61. m_pCadetPlaySite = psite;
  62. }
  63. void SetCadetMode(CadetMode cm)
  64. {
  65. m_cm = cm;
  66. }
  67. virtual CadetMode GetCadetMode()
  68. {
  69. return m_cm;
  70. }
  71. TRef<IDirectPlay3> CreateDirectPlay()
  72. {
  73. //!!!dc#ifdef DREAMCAST
  74. // TRef<IUnknown> pdplay;
  75. //#else
  76. TRef<IDirectPlay> pdplay;
  77. //#endif
  78. TRef<IDirectPlay3> pdplay3;
  79. GUID guidNull = GUID_NULL;
  80. if (FAILED(DirectPlayCreate(&guidNull, &pdplay, NULL)))
  81. return NULL;
  82. if (FAILED(pdplay->QueryInterface(IID_IDirectPlay3,(LPVOID*)&pdplay3)))
  83. return NULL;
  84. return pdplay3;
  85. }
  86. TRef<IDirectPlayLobby2> CreateDirectPlayLobby()
  87. {
  88. TRef<IDirectPlayLobby> plobby;
  89. TRef<IDirectPlayLobby2> plobby2;
  90. if (FAILED(DirectPlayLobbyCreate(NULL,&plobby,NULL,NULL,0)))
  91. return NULL;
  92. #ifdef UNICODE
  93. if (FAILED(plobby->QueryInterface(IID_IDirectPlayLobby2,(LPVOID*)&plobby2)))
  94. return NULL;
  95. #else
  96. if (FAILED(plobby->QueryInterface(IID_IDirectPlayLobby2A,(LPVOID*)&plobby2)))
  97. return NULL;
  98. #endif
  99. return plobby2;
  100. }
  101. HRESULT InitializeModemConnection()
  102. {
  103. DPCOMPOUNDADDRESSELEMENT dpcae[2];
  104. DWORD dwConnBuffSize = 0;
  105. BYTE* pbuf = NULL;
  106. HRESULT hr = S_OK;
  107. // Load service provider chunk
  108. dpcae[0].guidDataType=DPAID_ServiceProvider;
  109. dpcae[0].dwDataSize=sizeof(GUID);
  110. dpcae[0].lpData=(LPVOID)&DPSPGUID_MODEM;
  111. // and phone chunk
  112. dpcae[0].lpData = (GetCadetMode()==cmJoinModemNum1) ? (LPVOID)szPhone1 : (LPVOID)szPhone2;
  113. #ifdef UNICODE
  114. dpcae[1].guidDataType=DPAID_PhoneW;
  115. #else
  116. dpcae[1].guidDataType=DPAID_Phone;
  117. #endif
  118. dpcae[1].dwDataSize=sizeof(TCHAR)*(4);
  119. if (DPERR_BUFFERTOOSMALL !=
  120. (hr = m_pDirectPlayLobby->CreateCompoundAddress(
  121. dpcae,2,NULL, &dwConnBuffSize)))
  122. {
  123. ZAssert(FAILED(hr));
  124. return hr;
  125. }
  126. if (NULL == (pbuf = (BYTE*)LocalAlloc(0,dwConnBuffSize)))
  127. return E_FAIL;
  128. if (FAILED(hr = m_pDirectPlayLobby->CreateCompoundAddress(
  129. dpcae, 2, pbuf, &dwConnBuffSize)))
  130. goto quit;
  131. hr = m_pDirectPlay->InitializeConnection(pbuf,0);
  132. quit:
  133. if (pbuf)
  134. LocalFree(pbuf);
  135. return hr;
  136. }
  137. HRESULT InitializeSerialConnection()
  138. {
  139. DPCOMPOUNDADDRESSELEMENT dpcae[2];
  140. DWORD dwConnBuffSize = 0;
  141. BYTE* pbuf = NULL;
  142. HRESULT hr = S_OK;
  143. // Load service provider chunk
  144. dpcae[0].guidDataType=DPAID_ServiceProvider;
  145. dpcae[0].dwDataSize=sizeof(GUID);
  146. dpcae[0].lpData=(LPVOID)&DPSPGUID_SERIAL;
  147. // and comport chunk
  148. dpcae[1].guidDataType=DPAID_ComPort;
  149. dpcae[1].dwDataSize=sizeof(DPCOMPORTADDRESS);
  150. dpcae[1].lpData=(LPVOID)&cDPCPA;
  151. if (DPERR_BUFFERTOOSMALL !=
  152. (hr = m_pDirectPlayLobby->CreateCompoundAddress(
  153. dpcae,2,NULL, &dwConnBuffSize)))
  154. {
  155. ZAssert(FAILED(hr));
  156. return hr;
  157. }
  158. if (NULL == (pbuf = (BYTE*)LocalAlloc(0,dwConnBuffSize)))
  159. return E_FAIL;
  160. if (FAILED(hr = m_pDirectPlayLobby->CreateCompoundAddress(
  161. dpcae, 2, pbuf, &dwConnBuffSize)))
  162. goto quit;
  163. hr = m_pDirectPlay->InitializeConnection(pbuf,0);
  164. quit:
  165. if (pbuf)
  166. LocalFree(pbuf);
  167. return hr;
  168. }
  169. HRESULT HostSession()
  170. {
  171. HRESULT hr = S_OK;
  172. m_pDirectPlay = CreateDirectPlay();
  173. m_pDirectPlayLobby = CreateDirectPlayLobby();
  174. if (!m_pDirectPlay || !m_pDirectPlayLobby)
  175. return E_FAIL;
  176. if (GetCadetMode() == cmHostSerial)
  177. {
  178. if (FAILED(hr = InitializeSerialConnection()))
  179. return hr;
  180. }
  181. else
  182. {
  183. ZAssert(GetCadetMode() == cmHostModem);
  184. if (FAILED(hr = InitializeModemConnection()))
  185. return hr;
  186. }
  187. DPSESSIONDESC2 sessionDesc;
  188. memset(&sessionDesc, 0, sizeof(DPSESSIONDESC2));
  189. sessionDesc.dwSize = sizeof(DPSESSIONDESC2);
  190. sessionDesc.dwFlags = DPSESSION_MIGRATEHOST | DPSESSION_KEEPALIVE;
  191. sessionDesc.guidApplication = CLSID_CADET;
  192. sessionDesc.dwMaxPlayers = 2;
  193. sessionDesc.lpszSessionNameA = "Cadet Default Session";
  194. if (FAILED(hr = m_pDirectPlay->Open(&sessionDesc, DPOPEN_CREATE)))
  195. return hr;
  196. if (FAILED(hr = m_pDirectPlay->CreatePlayer(&m_dpid, NULL, NULL, NULL, 0, 0)))
  197. return hr;
  198. return hr;
  199. }
  200. HRESULT JoinSession(ImissionIGC* pmission)
  201. {
  202. HRESULT hr = S_OK;
  203. m_pDirectPlay = CreateDirectPlay();
  204. m_pDirectPlayLobby = CreateDirectPlayLobby();
  205. if (!m_pDirectPlay || !m_pDirectPlayLobby)
  206. return E_FAIL;
  207. if (GetCadetMode() == cmJoinSerial)
  208. {
  209. if (FAILED(hr = InitializeSerialConnection()))
  210. return hr;
  211. }
  212. else
  213. {
  214. ZAssert(GetCadetMode() == cmJoinModemNum1 || GetCadetMode() == cmJoinModemNum2);
  215. if (FAILED(hr = InitializeModemConnection()))
  216. return hr;
  217. }
  218. DPSESSIONDESC2 sessionDescFilter;
  219. memset(&sessionDescFilter, 0, sizeof(DPSESSIONDESC2));
  220. sessionDescFilter.dwSize = sizeof(DPSESSIONDESC2);
  221. sessionDescFilter.guidApplication = CLSID_CADET;
  222. DPSESSIONDESC2 sessionDescFirst;
  223. memset(&sessionDescFirst, 0, sizeof(DPSESSIONDESC2));
  224. if (FAILED(hr = m_pDirectPlay->EnumSessions(&sessionDescFilter, 0, GetFirstSession, (LPVOID)&sessionDescFirst, DPENUMSESSIONS_ALL)))
  225. return hr;
  226. if (sessionDescFirst.dwSize == 0)
  227. return E_FAIL;
  228. if (FAILED(hr = m_pDirectPlay->Open(&sessionDescFirst, DPOPEN_JOIN)))
  229. return hr;
  230. if (FAILED(hr = m_pDirectPlay->CreatePlayer(&m_dpid, NULL, NULL, NULL, 0, 0)))
  231. return hr;
  232. for (ShipLinkIGC* l = pmission->GetShips()->first(); (l != NULL); l = l->next())
  233. {
  234. IshipIGC* pship = l->data();
  235. ZAssert(pship->GetObjectID() < 100);
  236. SendNewShipInstanceMessage(pship);
  237. }
  238. LogonMessage logonMsg;
  239. logonMsg.msgID = LogonMessageID;
  240. logonMsg.cbMsg = sizeof(LogonMessage);
  241. SendMessage(&logonMsg, true);
  242. return hr;
  243. }
  244. HRESULT ReceiveMessages()
  245. {
  246. HRESULT hr = S_OK;
  247. DWORD dwMsgBufferSize = 0;
  248. DPID dpidFrom, dpidTo;
  249. BYTE rgbuf[1024];
  250. ULONG cbPacket = 1024;
  251. while (SUCCEEDED(hr))
  252. {
  253. dpidFrom = 0;
  254. dpidTo = 0;
  255. if (SUCCEEDED(hr = m_pDirectPlay->Receive(&dpidFrom, &dpidTo, DPRECEIVE_ALL, rgbuf, &cbPacket)))
  256. {
  257. // check for system message
  258. if (dpidFrom == DPID_SYSMSG)
  259. ;//m_pCadetPlaySite->OnSysMessage((LPDPMSG_GENERIC)rgbuf);
  260. else
  261. {
  262. CadetMessage* pcm = (CadetMessage*)rgbuf;
  263. if (m_pCadetPlaySite)
  264. m_pCadetPlaySite->OnAppMessage(pcm);
  265. }
  266. }
  267. }
  268. return S_OK;
  269. }
  270. void SendMessage(CadetMessage* pmsg, bool fGuaranteed)
  271. {
  272. m_pDirectPlay->Send(m_dpid, DPID_ALLPLAYERS, fGuaranteed ? DPSEND_GUARANTEED : 0, pmsg, pmsg->cbMsg);
  273. }
  274. void HandleIGCMessage(ImissionIGC* pmission, CadetMessage* pmsg)
  275. {
  276. switch (pmsg->msgID)
  277. {
  278. case NewShipInstanceMessageID:
  279. {
  280. NewShipInstanceMessage* pnewShipMsg = (NewShipInstanceMessage*)pmsg;
  281. DWORD cbExport = pnewShipMsg->cbMsg - sizeof(NewShipInstanceMessage);
  282. BYTE* pExport = ((BYTE*)pnewShipMsg) + sizeof(NewShipInstanceMessage);
  283. ((DataShipIGC*)pExport)->shipID += 100;
  284. IshipIGC* pship = (IshipIGC*)pmission->CreateObject(Time::Now(),
  285. OT_ship, pExport, cbExport);
  286. ZAssert(pship);
  287. pship->SetCluster(pmission->GetCluster(0));
  288. pship->Release();
  289. break;
  290. }
  291. case ShipUpdateMessageID:
  292. {
  293. ShipUpdateMessage* pshipUpdateMsg = (ShipUpdateMessage*)pmsg;
  294. pshipUpdateMsg->shipUpdate.shipID += 100;
  295. IshipIGC* pship = pmission->GetShip(pshipUpdateMsg->shipUpdate.shipID);
  296. if (pship)
  297. pship->ProcessShipUpdate(Time::Now(), pshipUpdateMsg->shipUpdate);
  298. break;
  299. }
  300. case LogonMessageID:
  301. {
  302. for (ShipLinkIGC* l = pmission->GetShips()->first(); (l != NULL); l = l->next())
  303. {
  304. IshipIGC* pship = l->data();
  305. if (pship->GetObjectID() < 100)
  306. SendNewShipInstanceMessage(pship);
  307. }
  308. break;
  309. }
  310. case FireMissileMessageID:
  311. {
  312. FireMissileMessage* pfireMissileMsg = (FireMissileMessage*)pmsg;
  313. DataMissileIGC dm;
  314. pfireMissileMsg->launcherID += 100;
  315. dm.pLauncher = pmission->GetShip(pfireMissileMsg->launcherID);
  316. if (dm.pLauncher)
  317. {
  318. dm.position = pfireMissileMsg->position;
  319. dm.velocity = pfireMissileMsg->velocity;
  320. dm.forward = pfireMissileMsg->forward;
  321. dm.pmissiletype = (ImissileTypeIGC*)(pmission->GetExpendableType(pfireMissileMsg->missiletypeID));
  322. dm.pTarget = pmission->GetModel(pfireMissileMsg->targetType,
  323. pfireMissileMsg->targetID);
  324. dm.pCluster = pmission->GetCluster(pfireMissileMsg->clusterID);
  325. dm.lock = pfireMissileMsg->lock;
  326. dm.missileID = pmission->GenerateNewMissileID();
  327. Time timeFired = Time::Now();
  328. ImissileIGC* m = (ImissileIGC*)(pmission->CreateObject(timeFired, OT_missile,
  329. &dm, sizeof(dm)));
  330. if (m)
  331. m->Release();
  332. /* //The player immediately adjusts their own count on launching the missile so don't update
  333. //their count.
  334. if (pfireMissileMsg->launcherID != m_ship->GetObjectID())
  335. {
  336. ImagazineIGC* pmagazine = (ImagazineIGC*)(dm.pLauncher->GetMountedPart(ET_Magazine, 0));
  337. if (pmagazine)
  338. {
  339. short amount = pmagazine->GetAmount() - 1;
  340. if (amount == 0)
  341. {
  342. //Nothing left ... nuke it (which may also cause it to be released & deleted).
  343. pmagazine->Terminate();
  344. }
  345. else
  346. {
  347. assert (amount > 0);
  348. pmagazine->SetAmount(amount);
  349. }
  350. }
  351. }
  352. */
  353. }
  354. }
  355. break;
  356. }
  357. }
  358. void SendShipUpdateMessages(ImissionIGC* pmission)
  359. {
  360. if (Time::Now() - m_timeLastUpdate > .25f) //send updates every 1/4 sec
  361. {
  362. for (ShipLinkIGC* l = pmission->GetShips()->first(); (l != NULL); l = l->next())
  363. {
  364. IshipIGC* pship = l->data();
  365. if (pship->GetObjectID() < 100)
  366. SendShipUpdateMessage(pship);
  367. }
  368. m_timeLastUpdate = Time::Now();
  369. }
  370. }
  371. void SendShipUpdateMessage(IshipIGC* pship)
  372. {
  373. ShipUpdateMessage msg;
  374. msg.msgID = ShipUpdateMessageID;
  375. msg.cbMsg = sizeof(ShipUpdateMessage);
  376. pship->ExportShipUpdate(&msg.shipUpdate);
  377. SendMessage(&msg, false);
  378. }
  379. void SendNewShipInstanceMessage(IshipIGC* pship)
  380. {
  381. BYTE buf[4096];
  382. NewShipInstanceMessage* pmsg = (NewShipInstanceMessage*)&buf;
  383. pmsg->msgID = NewShipInstanceMessageID;
  384. void* pExport = (void*)(pmsg+1);
  385. int cbExport = pship->Export(pExport);
  386. pmsg->cbMsg = sizeof(NewShipInstanceMessage) + cbExport;
  387. SendMessage(pmsg, true);
  388. }
  389. void SendFireMissileMessage(DataMissileIGC* pdataMissile)
  390. {
  391. FireMissileMessage msg;
  392. msg.msgID = FireMissileMessageID;
  393. msg.cbMsg = sizeof(FireMissileMessage);
  394. msg.position = pdataMissile->position;
  395. msg.velocity = pdataMissile->velocity;
  396. msg.forward = pdataMissile->forward;
  397. msg.launcherID = pdataMissile->pLauncher->GetObjectID();
  398. if (NULL != pdataMissile->pTarget)
  399. {
  400. msg.targetType = pdataMissile->pTarget->GetObjectType();
  401. msg.targetID = pdataMissile->pTarget->GetObjectID();
  402. }
  403. else
  404. {
  405. msg.targetType = OT_invalid;
  406. msg.targetID = NA;
  407. }
  408. msg.clusterID = pdataMissile->pCluster->GetObjectID();
  409. msg.lock = pdataMissile->lock;
  410. msg.missiletypeID = pdataMissile->pmissiletype->GetObjectID();
  411. msg.timeFired = Time::Now();
  412. SendMessage(&msg, true);
  413. }
  414. };
  415. TRef<CadetPlay> CadetPlay::Create()
  416. {
  417. return new CadetPlayImpl();
  418. }