ODPLAY.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. // Filename : ODPLAY.CPP
  21. // Description : MultiPlayerDP, multiplayer class using directPlay
  22. // Onwer : Gilbert
  23. #ifndef IMAGICMP
  24. // #define INITGUID
  25. // #define INITGUID for dplay.h to define IID_IDirectPlay3A
  26. #include <dplay.h>
  27. // #undef INITGUID
  28. #include <ODPLAY.h>
  29. #include <ALL.h>
  30. #include <string.h>
  31. #include <OVGALOCK.h>
  32. #include <OBLOB.h>
  33. #include <winbase.h>
  34. // Define constant
  35. GUID GAME_GUID =
  36. { 0x12f70d44, 0x68be, 0x11d0, { 0xaa, 0xb6, 0x0, 0x0, 0xe9, 0xf9, 0xd, 0x5d } };
  37. // To enable a lobby to launch a DirectPlay application, the application must add
  38. // the following entries to the system registry.
  39. //[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectPlay\Applications\SevenKingdoms]
  40. //"Guid"="{12F70D44-68BE-11D0-AAB6-0000E9F90D5D}"
  41. //"File"="7k.exe"
  42. //"CommandLine"="-!lobby!"
  43. //"Path"="C:\Seven Kingdoms"
  44. //"CurrentDirectory"="C:\Seven Kingdoms"
  45. // note that [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectPlay\Applications]
  46. // folder may not exist after installed dx5
  47. HANDLE PLAYER_MESSAGE_HANDLE = NULL; // ???
  48. DPSessionDesc::DPSessionDesc()
  49. {
  50. lpszSessionNameA = session_name;
  51. lpszPasswordA = pass_word;
  52. }
  53. DPSessionDesc::DPSessionDesc(const DPSESSIONDESC2 &dpSessionDesc) : DPSESSIONDESC2(dpSessionDesc)
  54. {
  55. after_copy();
  56. }
  57. DPSessionDesc::DPSessionDesc(const DPSessionDesc &dpSessionDesc) : DPSESSIONDESC2(dpSessionDesc)
  58. {
  59. after_copy();
  60. }
  61. DPSessionDesc& DPSessionDesc::operator= (const DPSessionDesc &src)
  62. {
  63. memcpy(this, &src, sizeof( DPSessionDesc ) );
  64. after_copy();
  65. return *this;
  66. }
  67. void DPSessionDesc::after_copy()
  68. {
  69. if( lpszSessionNameA )
  70. {
  71. strcpy(session_name, lpszSessionNameA);
  72. session_name[strlen(lpszSessionNameA)] = '\0';
  73. }
  74. else
  75. {
  76. session_name[0] = '\0';
  77. }
  78. lpszSessionNameA = session_name;
  79. if( lpszPasswordA)
  80. {
  81. strcpy(pass_word, lpszPasswordA);
  82. pass_word[strlen(lpszPasswordA)] = '\0';
  83. }
  84. else
  85. {
  86. pass_word[0] = '\0';
  87. }
  88. lpszPasswordA = pass_word;
  89. }
  90. DPSessionDesc *DPSessionDesc::before_use()
  91. {
  92. lpszSessionNameA = session_name;
  93. lpszPasswordA = pass_word;
  94. return this;
  95. }
  96. // to start a multiplayer game, first check if it is called from a
  97. // lobbied (MultiPlayerDP::is_lobbied)
  98. // if it is a lobbied, call init_lobbied before create_player
  99. // if not, call poll_service_provider; display them and let
  100. // user to select, call init and pass the guid of the selected
  101. // service; create_session or poll_sessions+join_session;
  102. // finally create_player.
  103. // ------- begin of function MultiPlayerDP::MultiPlayerDP -------//
  104. MultiPlayerDP::MultiPlayerDP() : service_providers(sizeof(DPServiceProvider), 10 ),
  105. current_sessions(sizeof(DPSessionDesc), 10 ), player_pool(sizeof(DPPlayer), 8 ),
  106. recv_buffer(new char[MP_RECV_BUFFER_SIZE])
  107. {
  108. init_flag = 0;
  109. direct_play_lobby = NULL;
  110. direct_play1 = NULL;
  111. direct_play3 = NULL;
  112. recv_buffer_size = MP_RECV_BUFFER_SIZE;
  113. host_flag = 0;
  114. lobbied_flag = 0;
  115. connection_string = NULL;
  116. }
  117. // ------- end of function MultiPlayerDP::MultiPlayerDP -------//
  118. // ------- begin of function MultiPlayerDP::~MultiPlayerDP -------//
  119. MultiPlayerDP::~MultiPlayerDP()
  120. {
  121. deinit();
  122. delete[] recv_buffer;
  123. }
  124. // ------- end of function MultiPlayerDP::~MultiPlayerDP -------//
  125. // ------- begin of function MultiPlayerDP::pre_init -------//
  126. void MultiPlayerDP::pre_init()
  127. {
  128. // nothing, for compatibilities with MultiPlayerIM
  129. lobbied_flag = 0;
  130. }
  131. // ------- begin of function MultiPlayerDP::pre_init -------//
  132. // ------- begin of function MultiPlayerDP::init -------//
  133. void MultiPlayerDP::init(GUID serviceProviderGUID)
  134. {
  135. VgaFrontLock vlock;
  136. if( !DirectPlayCreate( &serviceProviderGUID, &direct_play1, NULL) )
  137. {
  138. if( !direct_play1->QueryInterface( IID_IDirectPlay3A, (void **)&direct_play3) )
  139. {
  140. init_flag = 1;
  141. }
  142. else
  143. {
  144. direct_play3 = NULL;
  145. direct_play1->Release();
  146. direct_play1 = NULL;
  147. }
  148. }
  149. else
  150. {
  151. direct_play1 = NULL;
  152. }
  153. host_flag = 0;
  154. // ######## patch begin Gilbert 24/11 ######//
  155. my_player_id = DPID_ALLPLAYERS; // no player
  156. // ######## patch end Gilbert 24/11 ######//
  157. }
  158. // ------- end of function MultiPlayerDP::init -------//
  159. // ------- begin of function MultiPlayerDP::deinit -------//
  160. void MultiPlayerDP::deinit()
  161. {
  162. host_flag = 0;
  163. lobbied_flag = 0;
  164. if(init_flag)
  165. {
  166. // ######## patch begin Gilbert 24/11 ######//
  167. if( my_player_id != DPID_ALLPLAYERS)
  168. {
  169. destroy_player( my_player_id );
  170. Sleep(2000); // 2 seconds
  171. }
  172. // ######## patch end Gilbert 24/11 ######//
  173. VgaFrontLock vgaLock;
  174. if( direct_play3 )
  175. {
  176. direct_play3->Release();
  177. direct_play3 = NULL;
  178. }
  179. if( direct_play1 )
  180. {
  181. direct_play1->Release();
  182. direct_play1 = NULL;
  183. }
  184. // ######## patch begin Gilbert 24/11 ######//
  185. my_player_id = DPID_ALLPLAYERS; // mark player deleted
  186. // ######## patch end Gilbert 24/11 ######//
  187. init_flag = 0;
  188. }
  189. if( direct_play_lobby )
  190. {
  191. VgaFrontLock vgaLock;
  192. direct_play_lobby->Release();
  193. direct_play_lobby = NULL;
  194. }
  195. if( connection_string )
  196. {
  197. mem_del(connection_string);
  198. connection_string = NULL;
  199. }
  200. }
  201. // ------- end of function MultiPlayerDP::deinit -------//
  202. // ----- begin of function MultiPlayerDP::init_lobbied ------//
  203. void MultiPlayerDP::init_lobbied(int maxPlayers, char *)
  204. {
  205. HRESULT hr;
  206. VgaFrontLock vlock;
  207. // ------- create DirectPlayLobby, if necessary ------//
  208. if( direct_play_lobby == NULL)
  209. {
  210. LPDIRECTPLAYLOBBYA directPlayLobby = NULL;
  211. hr = DirectPlayLobbyCreate( NULL, &directPlayLobby, NULL, NULL, 0);
  212. if( hr == DP_OK )
  213. {
  214. hr = directPlayLobby->QueryInterface(IID_IDirectPlayLobby2A, (void **)&direct_play_lobby);
  215. directPlayLobby->Release();
  216. if( hr != DP_OK )
  217. return;
  218. }
  219. else
  220. {
  221. return;
  222. }
  223. }
  224. // ------ get connection setting ---------//
  225. DWORD bufferSize = 0;
  226. hr = direct_play_lobby->GetConnectionSettings(0, NULL, &bufferSize);
  227. if( hr == DP_OK || hr == DPERR_BUFFERTOOSMALL)
  228. {
  229. bufferSize += 0x80; // give them a little more
  230. connection_string = (DPLCONNECTION *)mem_resize(connection_string, bufferSize);
  231. hr = direct_play_lobby->GetConnectionSettings(0, connection_string, &bufferSize);
  232. if( hr == DP_OK )
  233. {
  234. // ------ modify connectString.lpSessionDesc here -------//
  235. connection_string->lpSessionDesc->dwFlags = DPSESSION_KEEPALIVE | DPSESSION_NODATAMESSAGES;
  236. connection_string->lpSessionDesc->dwMaxPlayers = maxPlayers;
  237. hr = direct_play_lobby->SetConnectionSettings(0,0, connection_string);
  238. if( hr != DP_OK )
  239. return;
  240. joined_session = *connection_string->lpSessionDesc;
  241. // ------ obtain direct play interface --------//
  242. direct_play1 = NULL;
  243. LPDIRECTPLAY2A directPlay2;
  244. hr = direct_play_lobby->Connect(0, &directPlay2, NULL);
  245. if( hr != DP_OK )
  246. return;
  247. // query DIRECTPLAY3A interface
  248. hr = directPlay2->QueryInterface( IID_IDirectPlay3A, (void **)&direct_play3);
  249. if( hr != DP_OK )
  250. {
  251. direct_play3 = NULL;
  252. directPlay2->Release();
  253. directPlay2 = NULL;
  254. return;
  255. }
  256. directPlay2->Release();
  257. directPlay2 = NULL;
  258. init_flag = 1;
  259. if( connection_string->dwFlags & DPLCONNECTION_CREATESESSION )
  260. lobbied_flag = 1; // auto create
  261. else if( connection_string->dwFlags & DPLCONNECTION_JOINSESSION )
  262. lobbied_flag = 2; // auto join
  263. else
  264. lobbied_flag = 4; // user selectable
  265. bufferSize = sizeof(DPSESSIONDESC2);
  266. direct_play3->GetSessionDesc( &joined_session, &bufferSize);
  267. joined_session.after_copy();
  268. }
  269. else
  270. {
  271. if( hr != DPERR_NOTLOBBIED )
  272. err.run("Cannot get connection string from lobby");
  273. }
  274. }
  275. else
  276. {
  277. if( hr != DPERR_NOTLOBBIED )
  278. err.run("Cannot get connection string from lobby");
  279. }
  280. }
  281. // ----- end of function MultiPlayerDP::init_lobbied ------//
  282. // ----- begin of function MultiPlayerDP::is_lobbied -----//
  283. // return 0=not lobbied, 1=auto create, 2=auto join, 4=selectable
  284. int MultiPlayerDP::is_lobbied()
  285. {
  286. return lobbied_flag;
  287. }
  288. // ----- end of function MultiPlayerDP::is_lobbied -----//
  289. // ----- begin of function MultiPlayerDP::get_lobbied_name -----//
  290. char *MultiPlayerDP::get_lobbied_name()
  291. {
  292. err_when(!is_lobbied());
  293. // ------ get connection setting ---------//
  294. if( connection_string )
  295. return connection_string->lpPlayerName->lpszShortNameA;
  296. else
  297. return NULL;
  298. }
  299. // ----- end of function MultiPlayerDP::get_lobbied_name -----//
  300. // ----- begin of function MultiPlayerDP::poll_service_providers -----//
  301. //
  302. // store all possible service provider (TCPIP, IPX, modem, null modem ... )
  303. // into service_provider_array
  304. //
  305. // need not call init before get_service_provider
  306. //
  307. // called by DirectPlayEnumerate() for each DirectPlay Service Provider
  308. static BOOL FAR PASCAL directPlayEnumerateCallback( LPGUID lpSPGuid, LPTSTR lpszSPName,
  309. DWORD dwMajorVersion, DWORD dwMinorVersion, LPVOID mpPtr)
  310. {
  311. DPServiceProvider sp;
  312. MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
  313. sp.guid = *lpSPGuid;
  314. strncpy(sp.description,lpszSPName, MP_SERVICE_PROVIDER_NAME_LEN);
  315. sp.description[MP_SERVICE_PROVIDER_NAME_LEN] = '\0';
  316. mpdpPtr->service_providers.linkin(&sp);
  317. return TRUE;
  318. }
  319. void MultiPlayerDP::poll_service_providers()
  320. {
  321. service_providers.zap();
  322. // ------ allocate spaces for service_provider_array -------//
  323. VgaFrontLock vgaLock;
  324. DirectPlayEnumerateA( directPlayEnumerateCallback, this );
  325. }
  326. // ----- end of function MultiPlayerDP::poll_service_providers -----//
  327. // ----- begin of function MultiPlayerDP::get_service_provder -----//
  328. // return a service provider
  329. //
  330. // <int> i i-th service provider (i start from 1)
  331. // return pointer to a DPServiceProvider, NULL if no more
  332. DPServiceProvider* MultiPlayerDP::get_service_provider(int i)
  333. {
  334. if( i <= 0 || i > service_providers.size() )
  335. return NULL;
  336. return (DPServiceProvider *) service_providers.get(i);
  337. }
  338. // ----- end of function MultiPlayerDP::get_service_provder -----//
  339. // ----- begin of function MultiPlayerDP::poll_sessions ------//
  340. //
  341. // store all available sessions (TCPIP, IPX, modem, null modem ... )
  342. // into current_sessions
  343. //
  344. static BOOL FAR PASCAL EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc,
  345. LPDWORD timeOut, DWORD flags, LPVOID mpPtr)
  346. {
  347. if( flags & DPESC_TIMEDOUT )
  348. return FALSE;
  349. if( memcmp(&lpSessionDesc->guidApplication, &GAME_GUID, sizeof(GUID)) == 0 )
  350. {
  351. MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
  352. DPSessionDesc sessionDesc(*lpSessionDesc);
  353. mpdpPtr->current_sessions.linkin(&sessionDesc);
  354. }
  355. return TRUE;
  356. }
  357. int MultiPlayerDP::poll_sessions()
  358. {
  359. err_when(!init_flag);
  360. current_sessions.zap();
  361. DPSESSIONDESC2 sessionDesc;
  362. memset(&sessionDesc, 0, sizeof( sessionDesc ) );
  363. sessionDesc.dwSize = sizeof( sessionDesc );
  364. sessionDesc.guidApplication = GAME_GUID;
  365. MouseDispCount showMouse;
  366. // ##### patch begin Gilbert 9/1 #########//
  367. // VgaFrontLock vgaLock; // MouseDispCount unlock vga_front
  368. // ##### end begin Gilbert 9/1 #########//
  369. VgaCustomPalette vgaCPal(DIR_RES"PAL_WIN.RES");
  370. return DP_OK == direct_play3->EnumSessions(&sessionDesc , 0, EnumSessionsCallback, this,
  371. DPENUMSESSIONS_AVAILABLE | DPENUMSESSIONS_ASYNC);
  372. }
  373. // ----- end of function MultiPlayerDP::poll_sessions ------//
  374. // ----- begin of function MultiPlayerDP::get_session ------//
  375. // return a session description
  376. //
  377. // <int> i i-th session (i start from 1)
  378. // return pointer to a session, NULL if no more
  379. DPSessionDesc *MultiPlayerDP::get_session(int i)
  380. {
  381. if( i <= 0 || i > current_sessions.size() )
  382. return NULL;
  383. return ((DPSessionDesc *) current_sessions.get(i))->before_use();
  384. }
  385. // ----- end of function MultiPlayerDP::get_session ------//
  386. // ----- begin of function MultiPlayerDP::create_session ----//
  387. //
  388. // create a new session
  389. //
  390. // <char *> sessionName arbitary name to identify a session, input from user
  391. // <int> maxPlayers maximum no. of players in a session
  392. //
  393. // return TRUE if success
  394. int MultiPlayerDP::create_session(char *sessionName, int maxPlayers)
  395. {
  396. if(!init_flag || maxPlayers < 1)
  397. return FALSE;
  398. if( is_lobbied() == 1 )
  399. {
  400. host_flag = 1;
  401. return TRUE;
  402. }
  403. memset(&joined_session, 0, sizeof( joined_session) );
  404. joined_session.dwSize = sizeof( DPSESSIONDESC2 );
  405. // DPSESSION_NODATAMESSAGES disable personal data
  406. // remove DPSESSION_MIGRATEHOST
  407. joined_session.dwFlags = DPSESSION_KEEPALIVE | DPSESSION_NODATAMESSAGES ;
  408. joined_session.guidApplication = GAME_GUID;
  409. joined_session.dwMaxPlayers = maxPlayers;
  410. strncpy(joined_session.session_name, sessionName, MP_SESSION_NAME_LEN );
  411. joined_session.session_name[MP_SESSION_NAME_LEN]= '\0';
  412. joined_session.lpszSessionNameA = joined_session.session_name;
  413. MouseDispCount showMouse;
  414. // ##### patch begin Gilbert 9/1 #########//
  415. // VgaFrontLock vgaLock; // MouseDispCount unlock vga_front
  416. // ##### end begin Gilbert 9/1 #########//
  417. VgaCustomPalette vgaCPal(DIR_RES"PAL_WIN.RES");
  418. if( !direct_play3->Open(&joined_session, DPOPEN_CREATE) )
  419. {
  420. host_flag = 1;
  421. return TRUE;
  422. }
  423. return FALSE;
  424. }
  425. // ----- end of function MultiPlayerDP::create_session ----//
  426. // ------ begin of function MultiPlayerDP::join_session ------//
  427. // join a session, by passing the DPSessionDesc pointer
  428. //
  429. // <DPSessionDesc *> pointer to a DPSessionDesc
  430. //
  431. // return TRUE if success
  432. int MultiPlayerDP::join_session(DPSessionDesc* sessionDesc)
  433. {
  434. if( !init_flag)
  435. return FALSE;
  436. if( is_lobbied() == 2 )
  437. {
  438. host_flag = 0;
  439. return TRUE;
  440. }
  441. joined_session = *sessionDesc;
  442. VgaFrontLock vgaLock;
  443. if(!direct_play3->Open(&joined_session, DPOPEN_JOIN))
  444. {
  445. host_flag = 0;
  446. return TRUE;
  447. }
  448. return FALSE;
  449. }
  450. // join a session, by passing the index passed into get_session()
  451. // note : do not call poll_sessions between get_session and join_session
  452. //
  453. // <int> currentSessionIndex the index passed into get_session()
  454. //
  455. // currentSessionIndex start from 1
  456. int MultiPlayerDP::join_session(int currentSessionIndex)
  457. {
  458. if( !init_flag)
  459. return FALSE;
  460. if( is_lobbied() == 2 )
  461. {
  462. host_flag = 0;
  463. return TRUE;
  464. }
  465. VgaFrontLock vgaLock;
  466. joined_session = *get_session(currentSessionIndex);
  467. if(!direct_play3->Open(&joined_session, DPOPEN_JOIN))
  468. {
  469. host_flag = 0;
  470. return TRUE;
  471. }
  472. return FALSE;
  473. }
  474. // ------ end of function MultiPlayerDP::join_session ------//
  475. // ------ begin of function MultiPlayerDP::close_session ------//
  476. void MultiPlayerDP::close_session()
  477. {
  478. VgaFrontLock vgaLock;
  479. if( init_flag)
  480. direct_play3->Close();
  481. host_flag = 0;
  482. }
  483. // ------ end of function MultiPlayerDP::close_session ------//
  484. // ------ begin of function MultiPlayerDP::disable_join_session ------//
  485. void MultiPlayerDP::disable_join_session()
  486. {
  487. // called by host only!
  488. err_when( !host_flag );
  489. if( init_flag && host_flag )
  490. {
  491. joined_session.dwFlags |= DPSESSION_JOINDISABLED | DPSESSION_NEWPLAYERSDISABLED;
  492. VgaFrontLock vgaLock;
  493. direct_play3->SetSessionDesc( &joined_session, 0 );
  494. }
  495. }
  496. // ------ end of function MultiPlayerDP::disable_join_session ------//
  497. // ------ begin of function MultiPlayerDP::create_player ------//
  498. // create a local player
  499. //
  500. // <char *> friendlyName short name of the player, best to be one word only
  501. // [char *] formalName long name of the player, take friendlyName if NULL (default: NULL)
  502. // [void *] lpData, [DWORD] dataSize pointer and size of any data sent the remote (default: NULL, 0)
  503. // [DWORD] flags not use reserved (default:0)
  504. //
  505. // return TRUE if success
  506. //
  507. int MultiPlayerDP::create_player(char *friendlyName, char *formalName,
  508. LPVOID lpData, DWORD dataSize, DWORD flags)
  509. {
  510. if(!init_flag)
  511. return FALSE;
  512. DPNAME dpName;
  513. memset(&dpName, 0, sizeof(dpName) );
  514. dpName.dwSize = sizeof(dpName);
  515. dpName.lpszShortNameA = friendlyName;
  516. dpName.lpszLongNameA = formalName ? formalName : friendlyName;
  517. VgaFrontLock vgaLock;
  518. return !direct_play3->CreatePlayer(&my_player_id, &dpName, PLAYER_MESSAGE_HANDLE,
  519. lpData, dataSize, flags);
  520. }
  521. // ------ end of function MultiPlayerDP::create_player -----//
  522. // ------ begin of function MultiPlayerDP::destroy_player ------//
  523. // destroy player, (for remove from joining a session, before playing)
  524. //
  525. void MultiPlayerDP::destroy_player( DPID playerId )
  526. {
  527. VgaFrontLock vgaLock;
  528. direct_play3->DestroyPlayer(playerId);
  529. }
  530. // ------ end of function MultiPlayerDP::destroy_player ------//
  531. // -------- begin of function MultiPlayerDP::poll_players ------//
  532. // collect all players in the session into player_pool
  533. // get each player by calling get_player
  534. //
  535. static BOOL FAR PASCAL EnumPlayerCallback(DPID dpId, DWORD dwPlayerType,
  536. LPCDPNAME lpName, DWORD dwFlags, LPVOID mpPtr)
  537. {
  538. MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
  539. DPPlayer dpPlayer;
  540. dpPlayer.player_id = dpId;
  541. strncpy(dpPlayer.friendly_name, lpName->lpszShortNameA, MP_FRIENDLY_NAME_LEN );
  542. dpPlayer.friendly_name[MP_FRIENDLY_NAME_LEN] = '\0';
  543. strncpy(dpPlayer.formal_name, lpName->lpszLongNameA, MP_FORMAL_NAME_LEN );
  544. dpPlayer.formal_name[MP_FORMAL_NAME_LEN] = '\0';
  545. dpPlayer.connecting = 1;
  546. mpdpPtr->player_pool.linkin(&dpPlayer);
  547. return TRUE;
  548. }
  549. void MultiPlayerDP::poll_players()
  550. {
  551. player_pool.zap();
  552. VgaFrontLock vgaLock;
  553. // direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, DPENUMPLAYERS_LOCAL );
  554. // direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, DPENUMPLAYERS_REMOTE);
  555. if(init_flag)
  556. direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, 0 );
  557. }
  558. // -------- end of function MultiPlayerDP::poll_players ------//
  559. // -------- begin of function MultiPlayerDP::get_player -----//
  560. //
  561. // return the i-th player in the player_pool
  562. //
  563. DPPlayer *MultiPlayerDP::get_player(int i)
  564. {
  565. if( i <= 0 || i > player_pool.size() )
  566. return NULL;
  567. return (DPPlayer *)player_pool.get(i);
  568. }
  569. // -------- end of function MultiPlayerDP::get_player -----//
  570. // -------- begin of function MultiPlayerDP::search_player -----//
  571. //
  572. // search player by playerID
  573. //
  574. DPPlayer *MultiPlayerDP::search_player(DPID playerId)
  575. {
  576. DPPlayer *player;
  577. int i = 0;
  578. while( (player = get_player(++i)) != NULL )
  579. if( player->player_id == playerId )
  580. return player;
  581. return NULL;
  582. }
  583. //
  584. // search player by formal name, case insensitive
  585. //
  586. DPPlayer *MultiPlayerDP::search_player(char *name)
  587. {
  588. DPPlayer *player;
  589. int i = 0;
  590. while( (player = get_player(++i)) != NULL )
  591. if( strnicmp(player->formal_name, name, MP_FORMAL_NAME_LEN)== 0)
  592. return player;
  593. return NULL;
  594. }
  595. // -------- end of function MultiPlayerDP::get_player -----//
  596. // ------- begin of function MultiPlayerDP::is_host --------//
  597. int MultiPlayerDP::is_host(DPID playerID)
  598. {
  599. err_here(); // not supported
  600. return 0;
  601. }
  602. // ------- end of function MultiPlayerDP::is_host --------//
  603. // ------- begin of function MultiPlayerDP::am_I_host --------//
  604. int MultiPlayerDP::am_I_host()
  605. {
  606. return host_flag;
  607. }
  608. // ------- end of function MultiPlayerDP::am_I_host --------//
  609. // ----- begin of function MultiPlayerDP::is_player_connecting ----//
  610. //
  611. // determine whether a player is lost
  612. //
  613. // MultiPlayerDP::received must be called (or remote.poll_msg) ,
  614. // so if a player is really lost, the system message from
  615. // directPlay is received
  616. //
  617. int MultiPlayerDP::is_player_connecting(DPID playerId)
  618. {
  619. for( int p = 1; p <= player_pool.size(); ++p)
  620. {
  621. DPPlayer *dpPlayer = (DPPlayer *) player_pool.get(p);
  622. if( dpPlayer->player_id == playerId )
  623. {
  624. return dpPlayer->connecting;
  625. }
  626. }
  627. return 0;
  628. }
  629. // ----- end of function MultiPlayerDP::is_player_connecting ----//
  630. // ----- begin of function MultiPlayerDP::update_public_data ----//
  631. // update a player's public data
  632. //
  633. // return TRUE on success
  634. //
  635. int MultiPlayerDP::update_public_data(DPID playerId, LPVOID lpData, DWORD dataSize)
  636. {
  637. VgaFrontLock vgaLock;
  638. return !direct_play3->SetPlayerData(playerId, lpData, dataSize, DPSET_REMOTE | DPSET_GUARANTEED);
  639. }
  640. // ----- end of function MultiPlayerDP::update_public_data ----//
  641. // ----- begin of function MultiPlayerDP::retrieve_public_data ----//
  642. // retrieve a player's public data
  643. // prepare an allocated memory and pass its address as lpData,
  644. // store its size in a DWORD, pass the pointer of the DWORD as lpDataSize
  645. //
  646. // if lpData is NULL, the function can get the size of the data
  647. //
  648. // return TRUE on success, *lpDataSize is updated to the size of the data
  649. //
  650. int MultiPlayerDP::retrieve_public_data(DPID playerId, LPVOID lpData, LPDWORD lpDataSize)
  651. {
  652. VgaFrontLock vgaLock;
  653. return !direct_play3->GetPlayerData(playerId, lpData, lpDataSize, DPSET_REMOTE | DPSET_GUARANTEED);
  654. }
  655. // ----- end of function MultiPlayerDP::retrieve_public_data ----//
  656. // ----- begin of function MultiPlayerDP::update_private_data ----//
  657. // update a player's private data
  658. //
  659. // return TRUE on success
  660. //
  661. int MultiPlayerDP::update_private_data(DPID playerId, LPVOID lpData, DWORD dataSize)
  662. {
  663. VgaFrontLock vgaLock;
  664. return !direct_play3->SetPlayerData(playerId, lpData, dataSize, DPSET_LOCAL | DPSET_GUARANTEED);
  665. }
  666. // ----- end of function MultiPlayerDP::update_private_data ----//
  667. // ----- begin of function MultiPlayerDP::retrieve_private_data ----//
  668. // retrieve a player's private data
  669. // prepare an allocated memory and pass its address as lpData,
  670. // store its size in a DWORD, pass the pointer of the DWORD as lpDataSize
  671. //
  672. // if lpData is NULL, the function can get the size of the data
  673. //
  674. // return TRUE on success, *lpDataSize is updated to the size of the data
  675. //
  676. int MultiPlayerDP::retrieve_private_data(DPID playerId, LPVOID lpData, LPDWORD lpDataSize)
  677. {
  678. VgaFrontLock vgaLock;
  679. return !direct_play3->GetPlayerData(playerId, lpData, lpDataSize, DPSET_LOCAL | DPSET_GUARANTEED);
  680. }
  681. // ----- end of function MultiPlayerDP::retrieve_private_data ----//
  682. // --------- begin of function MultiPlayerDP::send ---------//
  683. // send message
  684. //
  685. // must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
  686. // or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
  687. // pass DPID_ALLPLAYERS as toId to all players
  688. //
  689. // return TRUE on success
  690. //
  691. int MultiPlayerDP::send(DPID toId, LPVOID lpData, DWORD dataSize)
  692. {
  693. err_when(!init_flag);
  694. HRESULT hr;
  695. {
  696. VgaFrontLock vgaLock;
  697. hr = direct_play3->Send(my_player_id, toId, 0, lpData, dataSize);
  698. }
  699. // see if any player lost
  700. if( hr == DPERR_INVALIDPLAYER )
  701. {
  702. for( int p = 1; p <= player_pool.size(); ++p)
  703. {
  704. DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
  705. if( dpPlayer->player_id == toId )
  706. {
  707. dpPlayer->connecting = 0;
  708. }
  709. }
  710. }
  711. err_when(hr == DPERR_SENDTOOBIG);
  712. return hr == DP_OK;
  713. }
  714. // --------- end of function MultiPlayerDP::send ---------//
  715. // ------- begin of function MultiPlayerDP::begin_stream -----//
  716. // signal start of a lot of guaranteed messages being sent to this player
  717. //
  718. // note : call end_stream to finish begin_stream
  719. //
  720. void MultiPlayerDP::begin_stream(DPID toId)
  721. {
  722. err_when(!init_flag);
  723. VgaFrontLock vgaLock;
  724. direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED | DPSEND_OPENSTREAM, NULL,0);
  725. }
  726. // ------- end of function MultiPlayerDP::begin_stream -----//
  727. // --------- begin of function MultiPlayerDP::send_stream ---------//
  728. // send message
  729. //
  730. // must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
  731. // or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
  732. // pass DPID_ALLPLAYERS as toId to all players
  733. //
  734. // return TRUE on success
  735. //
  736. int MultiPlayerDP::send_stream(DPID toId, LPVOID lpData, DWORD dataSize)
  737. {
  738. err_when(!init_flag);
  739. HRESULT hr;
  740. {
  741. VgaFrontLock vgaLock;
  742. hr = direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED, lpData, dataSize);
  743. }
  744. // see if any player lost
  745. if( hr == DPERR_INVALIDPLAYER )
  746. {
  747. for( int p = 1; p <= player_pool.size(); ++p)
  748. {
  749. DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
  750. if( dpPlayer->player_id == toId )
  751. {
  752. dpPlayer->connecting = 0;
  753. }
  754. }
  755. }
  756. err_when(hr == DPERR_SENDTOOBIG);
  757. return hr == DP_OK;
  758. }
  759. // --------- end of function MultiPlayerDP::send_stream ---------//
  760. // ------- begin of function MultiPlayerDP::end_stream -----//
  761. // signal end of a lot of guaranteed messages being sent to this player
  762. //
  763. void MultiPlayerDP::end_stream(DPID toId)
  764. {
  765. err_when(!init_flag);
  766. VgaFrontLock vgaLock;
  767. direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED | DPSEND_CLOSESTREAM, NULL,0);
  768. }
  769. // ------- end of function MultiPlayerDP::end_stream -----//
  770. // ------- begin of function MultiPlayerDP::get_msg_count ------//
  771. //
  772. // get the number of outstanding message to receive
  773. //
  774. // return -1 if fail
  775. //
  776. int MultiPlayerDP::get_msg_count()
  777. {
  778. err_when(!init_flag);
  779. DWORD count = 0;
  780. VgaFrontLock vgaLock;
  781. if(direct_play3->GetMessageCount(my_player_id, &count))
  782. return -1;
  783. return (int)count;
  784. }
  785. // ------- end of function MultiPlayerDP::get_msg_count ------//
  786. // ------- begin of function MultiPlayerDP::receive ------//
  787. // return NULL if fails
  788. // sysMsgCount records how many system messages have been handled
  789. // notice : *sysMsgCount may be != 0, but return NULL
  790. //
  791. char *MultiPlayerDP::receive(LPDPID from, LPDPID to, LPDWORD dSize, int *sysMsgCount)
  792. {
  793. err_when(!init_flag);
  794. DPID fromId, toId;
  795. DWORD dataSize;
  796. int retryFlag;
  797. HRESULT hr;
  798. VgaFrontLock vgaLock;
  799. if( sysMsgCount )
  800. *sysMsgCount = 0;
  801. do
  802. {
  803. retryFlag = 0;
  804. dataSize = recv_buffer_size;
  805. hr=direct_play3->Receive(&fromId, &toId, DPRECEIVE_ALL, recv_buffer, &dataSize);
  806. switch(hr)
  807. {
  808. case 0:
  809. if(fromId == DPID_SYSMSG)
  810. {
  811. handle_system_msg(recv_buffer, dataSize);
  812. if( sysMsgCount )
  813. (*sysMsgCount)++;
  814. retryFlag = 1;
  815. }
  816. else
  817. {
  818. *from = fromId;
  819. *to = toId;
  820. *dSize = dataSize;
  821. }
  822. break;
  823. case DPERR_BUFFERTOOSMALL: // assume now dataSize > recv_buffer_size
  824. delete[] recv_buffer;
  825. recv_buffer_size = dataSize + 0x400;
  826. recv_buffer = new char[recv_buffer_size];
  827. retryFlag = 1; // direct_play3->receive may not return the same message, so keep retrying
  828. break;
  829. default:
  830. return NULL;
  831. }
  832. } while (retryFlag);
  833. return recv_buffer;
  834. }
  835. // ------- end of function MultiPlayerDP::receive ------//
  836. // ------- begin of function MultiPlayerDP::handle_system_msg ------//
  837. void MultiPlayerDP::handle_system_msg(LPVOID lpData, DWORD dSize)
  838. {
  839. switch( ((DPMSG_GENERIC *)lpData)->dwType )
  840. {
  841. case DPSYS_ADDPLAYERTOGROUP:
  842. {
  843. DPMSG_ADDPLAYERTOGROUP *dpmsg = (DPMSG_ADDPLAYERTOGROUP *)lpData;
  844. }
  845. break;
  846. case DPSYS_CREATEPLAYERORGROUP:
  847. {
  848. DPMSG_CREATEPLAYERORGROUP *dpmsg = (DPMSG_CREATEPLAYERORGROUP *)lpData;
  849. }
  850. break;
  851. case DPSYS_DELETEPLAYERFROMGROUP:
  852. {
  853. DPMSG_DELETEPLAYERFROMGROUP *dpmsg = (DPMSG_DELETEPLAYERFROMGROUP *)lpData;
  854. }
  855. break;
  856. case DPSYS_DESTROYPLAYERORGROUP:
  857. {
  858. DPMSG_DESTROYPLAYERORGROUP *dpmsg = (DPMSG_DESTROYPLAYERORGROUP *)lpData;
  859. if( dpmsg->dwPlayerType == DPPLAYERTYPE_PLAYER)
  860. {
  861. for( int p = 1; p <= player_pool.size(); ++p)
  862. {
  863. DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
  864. if( dpPlayer->player_id == dpmsg->dpId )
  865. {
  866. dpPlayer->connecting = 0;
  867. }
  868. }
  869. }
  870. }
  871. break;
  872. case DPSYS_HOST:
  873. {
  874. DPMSG_HOST *dpmsg = (DPMSG_HOST *)lpData;
  875. }
  876. break;
  877. case DPSYS_SESSIONLOST:
  878. {
  879. DPMSG_SESSIONLOST *dpmsg = (DPMSG_SESSIONLOST *)lpData;
  880. }
  881. break;
  882. case DPSYS_SETPLAYERORGROUPDATA:
  883. {
  884. DPMSG_SETPLAYERORGROUPDATA *dpmsg = (DPMSG_SETPLAYERORGROUPDATA *)lpData;
  885. }
  886. break;
  887. case DPSYS_SETPLAYERORGROUPNAME:
  888. {
  889. DPMSG_SETPLAYERORGROUPNAME *dpmsg = (DPMSG_SETPLAYERORGROUPNAME *)lpData;
  890. }
  891. break;
  892. case DPSYS_SETSESSIONDESC:
  893. {
  894. DPMSG_SETSESSIONDESC *dpmsg = (DPMSG_SETSESSIONDESC *)lpData;
  895. joined_session = dpmsg->dpDesc;
  896. }
  897. break;
  898. }
  899. }
  900. // ------- end of function MultiPlayerDP::handle_system_msg ------//
  901. // --------- begin of function MultiPlayerDP::send_lobby ---------//
  902. // send message
  903. //
  904. // must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
  905. // or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
  906. //
  907. // return TRUE on success
  908. //
  909. int MultiPlayerDP::send_lobby(LPVOID lpData, DWORD dataSize)
  910. {
  911. err_when(!init_flag);
  912. VgaFrontLock vgaLock;
  913. return !direct_play_lobby->SendLobbyMessage(0, 0, lpData, dataSize);
  914. }
  915. // --------- end of function MultiPlayerDP::send_lobby ---------//
  916. // ------- begin of function MultiPlayerDP::receive_lobby ------//
  917. // return NULL if fails
  918. char *MultiPlayerDP::receive_lobby(LPDWORD dSize)
  919. {
  920. err_when(!init_flag);
  921. DWORD dataSize, msgFlag;
  922. int retryFlag;
  923. HRESULT hr;
  924. VgaFrontLock vgaLock;
  925. do
  926. {
  927. retryFlag = 0;
  928. dataSize = recv_buffer_size;
  929. hr=direct_play_lobby->ReceiveLobbyMessage(0,0, &msgFlag, recv_buffer, &dataSize);
  930. switch(hr)
  931. {
  932. case 0:
  933. if(msgFlag == DPLAD_SYSTEM)
  934. {
  935. handle_lobby_system_msg(recv_buffer, dataSize);
  936. retryFlag = 1;
  937. }
  938. else
  939. {
  940. *dSize = dataSize;
  941. }
  942. break;
  943. case DPERR_BUFFERTOOSMALL: // assume now dataSize > recv_buffer_size
  944. delete[] recv_buffer;
  945. recv_buffer_size = dataSize + 0x400;
  946. recv_buffer = new char[recv_buffer_size];
  947. retryFlag = 1; // direct_play3->receive may not return the same message, so keep retrying
  948. break;
  949. default:
  950. return NULL;
  951. }
  952. } while (retryFlag);
  953. return recv_buffer;
  954. }
  955. // ------- end of function MultiPlayerDP::receive_lobby ------//
  956. // ------- begin of function MultiPlayerDP::handle_lobby_system_msg ------//
  957. void MultiPlayerDP::handle_lobby_system_msg(LPVOID lpData, DWORD dSize)
  958. {
  959. switch( ((DPLMSG_GENERIC *)lpData)->dwType )
  960. {
  961. case DPLSYS_APPTERMINATED:
  962. {
  963. // DPLMSG_APPTERMINATED *dplmsg = (DPLMSG_APPTERMINATED *)lpData;
  964. }
  965. break;
  966. case DPLSYS_CONNECTIONSETTINGSREAD:
  967. {
  968. // DPLMSG_CONNECTIONSETTINGSREAD *dplmsg = (DPLMSG_CONNECTIONSETTINGREAD *)lpData;
  969. }
  970. break;
  971. case DPLSYS_DPLAYCONNECTFAILED:
  972. {
  973. // DPLMSG_DPLAYCONNECTFAILED *dplmsg = (DPLMSG_DPLAYCONNECTFAILED *)lpData;
  974. }
  975. break;
  976. case DPLSYS_DPLAYCONNECTSUCCEEDED:
  977. {
  978. // DPLMSG_DPLAYCONNECTSUCCEEDED *dplmsg = (DPLMSG_DPLAYCONNECTSUCCEEDED *)lpData;
  979. }
  980. break;
  981. }
  982. }
  983. // ------- end of function MultiPlayerDP::handle_lobby_system_msg ------//
  984. // ------ Begin of function MultiPlayerDP::sort_sessions -------//
  985. static int sort_session_id(const void *a, const void *b)
  986. {
  987. return memcmp( &((DPSessionDesc *)a)->guidInstance, &((DPSessionDesc *)b)->guidInstance,
  988. sizeof(GUID) );
  989. }
  990. static int sort_session_name(const void *a, const void *b)
  991. {
  992. return strcmp( ((DPSessionDesc *)a)->name_str(), ((DPSessionDesc *)b)->name_str() );
  993. }
  994. // sort current_sessions
  995. // <int> sortType, 1=sort by GUID, 2=sort by session name
  996. void MultiPlayerDP::sort_sessions(int sortType )
  997. {
  998. // BUGHERE : quick_sort is a DynArray function but current_sessions is DynArrayB
  999. switch(sortType)
  1000. {
  1001. case 1:
  1002. current_sessions.quick_sort(sort_session_id);
  1003. break;
  1004. case 2:
  1005. current_sessions.quick_sort(sort_session_name);
  1006. break;
  1007. default:
  1008. err_here();
  1009. }
  1010. for( int s = 1; get_session(s); ++s)
  1011. {
  1012. get_session(s)->before_use(); // let lpszSessionNameA point to its own session_name
  1013. }
  1014. }
  1015. // ------ End of function MultiPlayerDP::sort_sessions -------//
  1016. #endif