Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1089 lines
27 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: player.c
  6. * Content: Methods for player management
  7. *
  8. * History:
  9. * Date By Reason
  10. * ======= ======= ======
  11. * 2/27/97 myronth Created it
  12. * 3/17/97 myronth Create/DestroyPlayer, Removed unnecessary Enum fn's
  13. * 3/21/97 myronth SetPlayerName, Get/SetPlayerData, Removed more
  14. * unnecessary functions
  15. * 3/25/97 myronth Fixed GetPlayer prototype (1 new parameter)
  16. * 3/31/97 myronth Removed dead code, Implemented Send, Added
  17. * CreateAndMapNewPlayer function
  18. * 4/3/97 myronth Changed CALLSP macro to CALL_LP
  19. * 4/10/97 myronth Added support for GetPlayerCaps
  20. * 5/8/97 myronth Drop lobby lock when calling LP, Propagate player's
  21. * receive event on CreatePlayer call
  22. * 5/12/97 myronth Handle remote players properly, create a lobby
  23. * system player for all remote players & groups
  24. * 5/17/97 myronth SendChatMessage
  25. * 5/20/97 myronth Made AddPlayerToGroup & DeletePlayerFromGroup return
  26. * DPERR_ACCESSDENIED on remote players (#8679),
  27. * Fixed a bunch of other lock bugs, Changed debug levels
  28. * 6/3/97 myronth Added support for player flags in CreatePlayer
  29. * 9/29/97 myronth Send local SetPlayerName/Data msgs after call to
  30. * lobby server succeeds (#12554)
  31. * 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
  32. ***************************************************************************/
  33. #include "dplobpr.h"
  34. //--------------------------------------------------------------------------
  35. //
  36. // Functions
  37. //
  38. //--------------------------------------------------------------------------
  39. #undef DPF_MODNAME
  40. #define DPF_MODNAME "PRV_CreatePlayer"
  41. HRESULT DPLAPI PRV_CreatePlayer(LPDPLOBBYI_DPLOBJECT this, LPDPID lpidPlayer,
  42. LPDPNAME lpName, HANDLE hEvent, LPVOID lpData,
  43. DWORD dwDataSize, DWORD dwFlags)
  44. {
  45. SPDATA_CREATEPLAYER cp;
  46. HRESULT hr = DP_OK;
  47. DWORD dwPlayerFlags;
  48. DPF(7, "Entering PRV_CreatePlayer");
  49. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x",
  50. this, lpidPlayer, lpName, hEvent, lpData, dwDataSize, dwFlags);
  51. ENTER_DPLOBBY();
  52. TRY
  53. {
  54. if( !VALID_DPLOBBY_PTR( this ) )
  55. {
  56. LEAVE_DPLOBBY();
  57. return DPERR_INVALIDOBJECT;
  58. }
  59. }
  60. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  61. {
  62. LEAVE_DPLOBBY();
  63. DPF_ERR( "Exception encountered validating parameters" );
  64. return DPERR_INVALIDPARAMS;
  65. }
  66. // Setup our SPDATA struct
  67. memset(&cp, 0, sizeof(SPDATA_CREATEPLAYER));
  68. cp.dwSize = sizeof(SPDATA_CREATEPLAYER);
  69. cp.lpName = lpName;
  70. cp.lpData = lpData;
  71. cp.dwDataSize = dwDataSize;
  72. cp.dwFlags = dwFlags;
  73. // Call the CreatePlayer method in the SP
  74. if(CALLBACK_EXISTS(CreatePlayer))
  75. {
  76. cp.lpISP = PRV_GetDPLobbySPInterface(this);
  77. // Drop the lock so the lobby provider's receive thread can get back
  78. // in with other messages if they show up in the queue before our
  79. // CreatePlayer response (which always happens)
  80. LEAVE_DPLOBBY();
  81. hr = CALL_LP(this, CreatePlayer, &cp);
  82. ENTER_DPLOBBY();
  83. }
  84. else
  85. {
  86. // CreatePlayer is required
  87. DPF_ERR("The Lobby Provider callback for CreatePlayer doesn't exist -- it's required");
  88. ASSERT(FALSE);
  89. LEAVE_DPLOBBY();
  90. return DPERR_UNAVAILABLE;
  91. }
  92. if(FAILED(hr))
  93. {
  94. DPF_ERRVAL("Failed calling CreatePlayer in the Lobby Provider, hr = 0x%08x", hr);
  95. LEAVE_DPLOBBY();
  96. return hr;
  97. }
  98. // Fix up the player flags
  99. dwPlayerFlags = DPLAYI_PLAYER_PLAYERLOCAL;
  100. if(dwFlags & DPPLAYER_SPECTATOR)
  101. dwPlayerFlags |= DPLAYI_PLAYER_SPECTATOR;
  102. // Add the player to dplay's nametable and put it in our map table
  103. hr = PRV_CreateAndMapNewPlayer(this, lpidPlayer, lpName, hEvent, lpData,
  104. dwDataSize, dwPlayerFlags, cp.dwPlayerID, FALSE);
  105. if(FAILED(hr))
  106. {
  107. DPF_ERRVAL("Failed creating a new local player, hr = 0x%08x", hr);
  108. // REVIEW!!!! -- We need to send a message back to the server saying
  109. // we couldn't complete the deal on our end.
  110. }
  111. LEAVE_DPLOBBY();
  112. return hr;
  113. } // PRV_CreatePlayer
  114. #undef DPF_MODNAME
  115. #define DPF_MODNAME "PRV_DestroyPlayer"
  116. HRESULT DPLAPI PRV_DestroyPlayer(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
  117. {
  118. SPDATA_DESTROYPLAYER dp;
  119. LPDPLAYI_PLAYER lpPlayer = NULL;
  120. HRESULT hr = DP_OK;
  121. DPF(7, "Entering PRV_DestroyPlayer");
  122. DPF(9, "Parameters: 0x%08x, 0x%08x", this, dwLobbyID);
  123. ENTER_DPLOBBY();
  124. TRY
  125. {
  126. if( !VALID_DPLOBBY_PTR( this ) )
  127. {
  128. LEAVE_DPLAY();
  129. return DPERR_INVALIDOBJECT;
  130. }
  131. }
  132. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  133. {
  134. LEAVE_DPLAY();
  135. DPF_ERR( "Exception encountered validating parameters" );
  136. return DPERR_INVALIDPARAMS;
  137. }
  138. // Take the dplay lock since we'll be looking at a dplay internal struct
  139. ENTER_DPLAY();
  140. // Make sure the player is a local player, otherwise return AccessDenied
  141. lpPlayer = PlayerFromID(this->lpDPlayObject, dwLobbyID);
  142. if(!lpPlayer)
  143. {
  144. LEAVE_DPLAY();
  145. DPF_ERR("Unable to find player in nametable");
  146. hr = DPERR_INVALIDPLAYER;
  147. goto EXIT_DESTROYPLAYER;
  148. }
  149. if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  150. {
  151. LEAVE_DPLAY();
  152. DPF_ERR("Cannot add a remote player to a group");
  153. hr = DPERR_ACCESSDENIED;
  154. goto EXIT_DESTROYPLAYER;
  155. }
  156. // Drop the dplay lock since we're done
  157. LEAVE_DPLAY();
  158. // Setup our SPDATA struct
  159. memset(&dp, 0, sizeof(SPDATA_DESTROYPLAYER));
  160. dp.dwSize = sizeof(SPDATA_DESTROYPLAYER);
  161. dp.dwPlayerID = dwLobbyID;
  162. // Call the DestroyPlayer method in the SP
  163. if(CALLBACK_EXISTS(DestroyPlayer))
  164. {
  165. dp.lpISP = PRV_GetDPLobbySPInterface(this);
  166. // Drop the lock so the lobby provider's receive thread can get back
  167. // in with other messages if they show up in the queue before our
  168. // CreatePlayer response (which always happens)
  169. LEAVE_DPLOBBY();
  170. hr = CALL_LP(this, DestroyPlayer, &dp);
  171. ENTER_DPLOBBY();
  172. }
  173. else
  174. {
  175. // DestroyPlayer is required
  176. DPF_ERR("The Lobby Provider callback for DestroyPlayer doesn't exist -- it's required");
  177. ASSERT(FALSE);
  178. hr = DPERR_UNAVAILABLE;
  179. goto EXIT_DESTROYPLAYER;
  180. }
  181. if(FAILED(hr))
  182. {
  183. DPF_ERRVAL("Failed calling DestroyPlayer in the Lobby Provider, hr = 0x%08x", hr);
  184. goto EXIT_DESTROYPLAYER;
  185. }
  186. // The dplay InternalDestroyPlayer code will take care of the rest of
  187. // the internal cleanup (nametable, groups, etc.), so we can just return
  188. // from here.
  189. EXIT_DESTROYPLAYER:
  190. LEAVE_DPLOBBY();
  191. return hr;
  192. } // PRV_DestroyPlayer
  193. #undef DPF_MODNAME
  194. #define DPF_MODNAME "PRV_GetPlayerCaps"
  195. HRESULT DPLAPI PRV_GetPlayerCaps(LPDPLOBBYI_DPLOBJECT this, DWORD dwFlags,
  196. DWORD dwPlayerID, LPDPCAPS lpcaps)
  197. {
  198. SPDATA_GETPLAYERCAPS gcd;
  199. HRESULT hr = DP_OK;
  200. DPF(7, "Entering PRV_GetPlayerCaps");
  201. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu, 0x%08x",
  202. this, dwFlags, dwPlayerID, lpcaps);
  203. ENTER_DPLOBBY();
  204. TRY
  205. {
  206. if( !VALID_DPLOBBY_PTR( this ) )
  207. {
  208. LEAVE_DPLAY();
  209. return DPERR_INVALIDOBJECT;
  210. }
  211. }
  212. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  213. {
  214. LEAVE_DPLAY();
  215. DPF_ERR( "Exception encountered validating parameters" );
  216. return DPERR_INVALIDPARAMS;
  217. }
  218. // Setup our SPDATA struct
  219. memset(&gcd, 0, sizeof(SPDATA_GETCAPS));
  220. gcd.dwSize = sizeof(SPDATA_GETCAPS);
  221. gcd.dwFlags = dwFlags;
  222. gcd.dwPlayerID = dwPlayerID;
  223. gcd.lpcaps = lpcaps;
  224. // Call the GetPlayerCaps method in the LP
  225. if(CALLBACK_EXISTS(GetPlayerCaps))
  226. {
  227. gcd.lpISP = PRV_GetDPLobbySPInterface(this);
  228. // Drop the lock so the lobby provider's receive thread can get back
  229. // in with other messages if they show up in the queue before our
  230. // CreatePlayer response (which always happens)
  231. LEAVE_DPLOBBY();
  232. hr = CALL_LP(this, GetPlayerCaps, &gcd);
  233. ENTER_DPLOBBY();
  234. }
  235. else
  236. {
  237. // GetPlayerCaps is required
  238. DPF_ERR("The Lobby Provider callback for GetPlayerCaps doesn't exist -- it's required");
  239. ASSERT(FALSE);
  240. hr = DPERR_UNAVAILABLE;
  241. goto EXIT_GETPLAYERCAPS;
  242. }
  243. if(FAILED(hr))
  244. {
  245. DPF_ERRVAL("Failed calling GetPlayerCaps in the Lobby Provider, hr = 0x%08x", hr);
  246. }
  247. EXIT_GETPLAYERCAPS:
  248. LEAVE_DPLOBBY();
  249. return hr;
  250. } // PRV_GetPlayerCaps
  251. #undef DPF_MODNAME
  252. #define DPF_MODNAME "PRV_GetPlayerData"
  253. HRESULT DPLAPI PRV_GetPlayerData(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
  254. LPVOID lpData, LPDWORD lpdwDataSize)
  255. {
  256. SPDATA_GETPLAYERDATA gpd;
  257. HRESULT hr = DP_OK;
  258. DPF(7, "Entering DPL_GetPlayerData");
  259. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
  260. this, dwPlayerID, lpData, lpdwDataSize);
  261. ENTER_DPLOBBY();
  262. TRY
  263. {
  264. if( !VALID_DPLOBBY_PTR( this ) )
  265. {
  266. LEAVE_DPLAY();
  267. return DPERR_INVALIDOBJECT;
  268. }
  269. }
  270. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  271. {
  272. LEAVE_DPLAY();
  273. DPF_ERR( "Exception encountered validating parameters" );
  274. return DPERR_INVALIDPARAMS;
  275. }
  276. // Setup our SPDATA struct
  277. memset(&gpd, 0, sizeof(SPDATA_GETPLAYERDATA));
  278. gpd.dwSize = sizeof(SPDATA_GETPLAYERDATA);
  279. gpd.dwPlayerID = dwPlayerID;
  280. gpd.lpdwDataSize = lpdwDataSize;
  281. gpd.lpData = lpData;
  282. // Call the GetPlayerData method in the SP
  283. if(CALLBACK_EXISTS(GetPlayerData))
  284. {
  285. gpd.lpISP = PRV_GetDPLobbySPInterface(this);
  286. // Drop the lock so the lobby provider's receive thread can get back
  287. // in with other messages if they show up in the queue before our
  288. // CreatePlayer response (which always happens)
  289. LEAVE_DPLOBBY();
  290. hr = CALL_LP(this, GetPlayerData, &gpd);
  291. ENTER_DPLOBBY();
  292. }
  293. else
  294. {
  295. // GetPlayerData is required
  296. DPF_ERR("The Lobby Provider callback for GetPlayerData doesn't exist -- it's required");
  297. ASSERT(FALSE);
  298. hr = DPERR_UNAVAILABLE;
  299. goto EXIT_GETPLAYERDATA;
  300. }
  301. if(FAILED(hr))
  302. {
  303. DPF_ERRVAL("Failed calling GetPlayerData in the Lobby Provider, hr = 0x%08x", hr);
  304. }
  305. EXIT_GETPLAYERDATA:
  306. LEAVE_DPLOBBY();
  307. return hr;
  308. } // PRV_GetPlayerData
  309. #undef DPF_MODNAME
  310. #define DPF_MODNAME "PRV_Send"
  311. HRESULT DPLAPI PRV_Send(LPDPLOBBYI_DPLOBJECT this, DWORD dwFromID, DWORD dwToID,
  312. DWORD dwFlags, LPVOID lpBuffer, DWORD dwBufSize)
  313. {
  314. SPDATA_SEND sd;
  315. HRESULT hr = DP_OK;
  316. DPF(7, "Entering PRV_Send");
  317. DPF(9, "Parameters: 0x%08x, %lu, %lu, 0x%08x, 0x%08x, %lu",
  318. this, dwFromID, dwToID, dwFlags, lpBuffer, dwBufSize);
  319. ENTER_DPLOBBY();
  320. TRY
  321. {
  322. if( !VALID_DPLOBBY_PTR( this ) )
  323. {
  324. LEAVE_DPLAY();
  325. return DPERR_INVALIDOBJECT;
  326. }
  327. }
  328. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  329. {
  330. LEAVE_DPLAY();
  331. DPF_ERR( "Exception encountered validating parameters" );
  332. return DPERR_INVALIDPARAMS;
  333. }
  334. // Setup our SPDATA structure
  335. memset(&sd, 0, sizeof(SPDATA_SEND));
  336. sd.dwSize = sizeof(SPDATA_SEND);
  337. sd.dwFromID = dwFromID;
  338. sd.dwToID = dwToID;
  339. sd.dwFlags = dwFlags;
  340. sd.lpBuffer = lpBuffer;
  341. sd.dwBufSize = dwBufSize;
  342. // Call the Send method in the SP
  343. if(CALLBACK_EXISTS(Send))
  344. {
  345. sd.lpISP = PRV_GetDPLobbySPInterface(this);
  346. // Drop the lock so the lobby provider's receive thread can get back
  347. // in with other messages if they show up in the queue before our
  348. // CreatePlayer response (which always happens)
  349. LEAVE_DPLOBBY();
  350. hr = CALL_LP(this, Send, &sd);
  351. ENTER_DPLOBBY();
  352. }
  353. else
  354. {
  355. // Send is required
  356. DPF_ERR("The Lobby Provider callback for Send doesn't exist -- it's required");
  357. ASSERT(FALSE);
  358. LEAVE_DPLOBBY();
  359. return DPERR_UNAVAILABLE;
  360. }
  361. LEAVE_DPLOBBY();
  362. return hr;
  363. } // PRV_Send
  364. #undef DPF_MODNAME
  365. #define DPF_MODNAME "PRV_SendChatMessage"
  366. HRESULT DPLAPI PRV_SendChatMessage(LPDPLOBBYI_DPLOBJECT this, DWORD dwFromID,
  367. DWORD dwToID, DWORD dwFlags, LPDPCHAT lpChat)
  368. {
  369. SPDATA_CHATMESSAGE sd;
  370. HRESULT hr = DP_OK;
  371. DPF(7, "Entering PRV_SendChatMessage");
  372. DPF(9, "Parameters: 0x%08x, %lu, %lu, 0x%08x, 0x%08x",
  373. this, dwFromID, dwToID, dwFlags, lpChat);
  374. ENTER_DPLOBBY();
  375. TRY
  376. {
  377. if( !VALID_DPLOBBY_PTR( this ) )
  378. {
  379. LEAVE_DPLAY();
  380. return DPERR_INVALIDOBJECT;
  381. }
  382. }
  383. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  384. {
  385. LEAVE_DPLAY();
  386. DPF_ERR( "Exception encountered validating parameters" );
  387. return DPERR_INVALIDPARAMS;
  388. }
  389. // Setup our SPDATA structure
  390. memset(&sd, 0, sizeof(SPDATA_CHATMESSAGE));
  391. sd.dwSize = sizeof(SPDATA_CHATMESSAGE);
  392. sd.dwFromID = dwFromID;
  393. sd.dwToID = dwToID;
  394. sd.dwFlags = dwFlags;
  395. sd.lpChat = lpChat;
  396. // Call the SendChatMessage method in the SP
  397. if(CALLBACK_EXISTS(SendChatMessage))
  398. {
  399. sd.lpISP = PRV_GetDPLobbySPInterface(this);
  400. // Drop the lock so the lobby provider's receive thread can get back
  401. // in with other messages if they show up in the queue before our
  402. // CreatePlayer response (which always happens)
  403. LEAVE_DPLOBBY();
  404. hr = CALL_LP(this, SendChatMessage, &sd);
  405. ENTER_DPLOBBY();
  406. }
  407. else
  408. {
  409. // SendChatMessage is required
  410. DPF_ERR("The Lobby Provider callback for SendChatMessage doesn't exist -- it's required");
  411. ASSERT(FALSE);
  412. hr = DPERR_UNAVAILABLE;
  413. goto EXIT_SENDCHATMESSAGE;
  414. }
  415. EXIT_SENDCHATMESSAGE:
  416. LEAVE_DPLOBBY();
  417. return hr;
  418. } // PRV_SendChatMessage
  419. #undef DPF_MODNAME
  420. #define DPF_MODNAME "PRV_SetPlayerData"
  421. HRESULT DPLAPI PRV_SetPlayerData(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
  422. LPVOID lpData, DWORD dwDataSize, DWORD dwFlags)
  423. {
  424. SPDATA_SETPLAYERDATA spd;
  425. LPDPLAYI_PLAYER lpPlayer = NULL;
  426. HRESULT hr = DP_OK;
  427. DPF(7, "Entering PRV_SetPlayerData");
  428. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu, 0x%08x",
  429. this, dwPlayerID, lpData, dwDataSize, dwFlags);
  430. ENTER_DPLOBBY();
  431. TRY
  432. {
  433. if( !VALID_DPLOBBY_PTR( this ) )
  434. {
  435. LEAVE_DPLAY();
  436. return DPERR_INVALIDOBJECT;
  437. }
  438. }
  439. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  440. {
  441. LEAVE_DPLAY();
  442. DPF_ERR( "Exception encountered validating parameters" );
  443. return DPERR_INVALIDPARAMS;
  444. }
  445. // Take the dplay lock since we'll be looking at a dplay internal struct
  446. ENTER_DPLAY();
  447. // Make sure the player is a local player, otherwise return AccessDenied
  448. lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
  449. if(!lpPlayer)
  450. {
  451. LEAVE_DPLAY();
  452. DPF_ERR("Unable to find player in nametable");
  453. hr = DPERR_INVALIDPLAYER;
  454. goto EXIT_SETPLAYERDATA;
  455. }
  456. if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  457. {
  458. LEAVE_DPLAY();
  459. DPF_ERR("Cannot add a remote player to a group");
  460. hr = DPERR_ACCESSDENIED;
  461. goto EXIT_SETPLAYERDATA;
  462. }
  463. // Drop the dplay lock since we're finished
  464. LEAVE_DPLAY();
  465. // Setup our SPDATA struct
  466. memset(&spd, 0, sizeof(SPDATA_SETPLAYERDATA));
  467. spd.dwSize = sizeof(SPDATA_SETPLAYERDATA);
  468. spd.dwPlayerID = dwPlayerID;
  469. spd.dwDataSize = dwDataSize;
  470. spd.lpData = lpData;
  471. spd.dwFlags = dwFlags;
  472. // Call the SetPlayerData method in the SP
  473. if(CALLBACK_EXISTS(SetPlayerData))
  474. {
  475. spd.lpISP = PRV_GetDPLobbySPInterface(this);
  476. // Drop the lock so the lobby provider's receive thread can get back
  477. // in with other messages if they show up in the queue before our
  478. // CreatePlayer response (which always happens)
  479. LEAVE_DPLOBBY();
  480. hr = CALL_LP(this, SetPlayerData, &spd);
  481. ENTER_DPLOBBY();
  482. }
  483. else
  484. {
  485. // SetPlayerData is required
  486. DPF_ERR("The Lobby Provider callback for SetPlayerData doesn't exist -- it's required");
  487. ASSERT(FALSE);
  488. hr = DPERR_UNAVAILABLE;
  489. goto EXIT_SETPLAYERDATA;
  490. }
  491. // If it succeeded, send the SetPlayerData message to our local players
  492. if(SUCCEEDED(hr))
  493. {
  494. hr = PRV_SendDataChangedMessageLocally(this, dwPlayerID, lpData, dwDataSize);
  495. }
  496. else
  497. {
  498. DPF_ERRVAL("Failed calling SetPlayerData in the Lobby Provider, hr = 0x%08x", hr);
  499. }
  500. EXIT_SETPLAYERDATA:
  501. LEAVE_DPLOBBY();
  502. return hr;
  503. } // PRV_SetPlayerData
  504. #undef DPF_MODNAME
  505. #define DPF_MODNAME "PRV_SetPlayerName"
  506. HRESULT DPLAPI PRV_SetPlayerName(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
  507. LPDPNAME lpName, DWORD dwFlags)
  508. {
  509. SPDATA_SETPLAYERNAME spn;
  510. LPDPLAYI_PLAYER lpPlayer = NULL;
  511. HRESULT hr = DP_OK;
  512. DPF(7, "Entering DPL_SetPlayerName");
  513. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
  514. this, dwPlayerID, lpName, dwFlags);
  515. ENTER_DPLOBBY();
  516. TRY
  517. {
  518. if( !VALID_DPLOBBY_PTR( this ) )
  519. {
  520. LEAVE_DPLAY();
  521. return DPERR_INVALIDOBJECT;
  522. }
  523. }
  524. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  525. {
  526. LEAVE_DPLAY();
  527. DPF_ERR( "Exception encountered validating parameters" );
  528. return DPERR_INVALIDPARAMS;
  529. }
  530. // Take the dplay lock since we'll be looking at a dplay internal struct
  531. ENTER_DPLAY();
  532. // Make sure the player is a local player, otherwise return AccessDenied
  533. lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
  534. if(!lpPlayer)
  535. {
  536. LEAVE_DPLAY();
  537. DPF_ERR("Unable to find player in nametable");
  538. hr = DPERR_INVALIDPLAYER;
  539. goto EXIT_SETPLAYERNAME;
  540. }
  541. if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  542. {
  543. LEAVE_DPLAY();
  544. DPF_ERR("Cannot add a remote player to a group");
  545. hr = DPERR_ACCESSDENIED;
  546. goto EXIT_SETPLAYERNAME;
  547. }
  548. // Drop the dplay lock since we're finished
  549. LEAVE_DPLAY();
  550. // Setup our SPDATA struct
  551. memset(&spn, 0, sizeof(SPDATA_SETPLAYERNAME));
  552. spn.dwSize = sizeof(SPDATA_SETPLAYERNAME);
  553. spn.dwPlayerID = dwPlayerID;
  554. spn.lpName = lpName;
  555. spn.dwFlags = dwFlags;
  556. // Call the SetPlayerName method in the SP
  557. if(CALLBACK_EXISTS(SetPlayerName))
  558. {
  559. spn.lpISP = PRV_GetDPLobbySPInterface(this);
  560. // Drop the lock so the lobby provider's receive thread can get back
  561. // in with other messages if they show up in the queue before our
  562. // CreatePlayer response (which always happens)
  563. LEAVE_DPLOBBY();
  564. hr = CALL_LP(this, SetPlayerName, &spn);
  565. ENTER_DPLOBBY();
  566. }
  567. else
  568. {
  569. // SetPlayerName is required
  570. DPF_ERR("The Lobby Provider callback for SetPlayerName doesn't exist -- it's required");
  571. ASSERT(FALSE);
  572. hr = DPERR_UNAVAILABLE;
  573. goto EXIT_SETPLAYERNAME;
  574. }
  575. // If it succeeded, send the SetPlayerName message to our local players
  576. if(SUCCEEDED(hr))
  577. {
  578. hr = PRV_SendNameChangedMessageLocally(this, dwPlayerID, lpName, TRUE);
  579. }
  580. else
  581. {
  582. DPF_ERRVAL("Failed calling SetPlayerName in the Lobby Provider, hr = 0x%08x", hr);
  583. }
  584. EXIT_SETPLAYERNAME:
  585. LEAVE_DPLOBBY();
  586. return hr;
  587. } // PRV_SetPlayerName
  588. #undef DPF_MODNAME
  589. #define DPF_MODNAME "PRV_GrowMapTable"
  590. HRESULT PRV_GrowMapTable(LPDPLOBBYI_DPLOBJECT this)
  591. {
  592. LPDPLOBBYI_MAPIDNODE lpTempMap = NULL;
  593. // If we haven't already allocated a buffer, allocate one with
  594. // DPLOBBYPR_DEFAULTMAPENTRIES entries in it
  595. if(!this->lpMap)
  596. {
  597. this->lpMap = DPMEM_ALLOC(DPLOBBYPR_DEFAULTMAPENTRIES *
  598. sizeof(DPLOBBYI_MAPIDNODE));
  599. if(!this->lpMap)
  600. {
  601. DPF(2, "Unable to allocate memory for ID map table");
  602. return DPERR_OUTOFMEMORY;
  603. }
  604. this->dwTotalMapEntries = DPLOBBYPR_DEFAULTMAPENTRIES;
  605. return DP_OK;
  606. }
  607. // Otherwise, grow the table by the default number of entries
  608. lpTempMap = DPMEM_REALLOC(this->lpMap, (this->dwTotalMapEntries +
  609. DPLOBBYPR_DEFAULTMAPENTRIES * sizeof(DPLOBBYI_MAPIDNODE)));
  610. if(!lpTempMap)
  611. {
  612. DPF(2, "Unable to grow map table");
  613. return DPERR_OUTOFMEMORY;
  614. }
  615. this->lpMap = lpTempMap;
  616. this->dwTotalMapEntries += DPLOBBYPR_DEFAULTMAPENTRIES *
  617. sizeof(DPLOBBYI_MAPIDNODE);
  618. return DP_OK;
  619. } // PRV_GrowMapTable
  620. #undef DPF_MODNAME
  621. #define DPF_MODNAME "PRV_DoesLobbyIDExist"
  622. BOOL PRV_DoesLobbyIDExist(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID,
  623. LPDWORD lpdwIndex)
  624. {
  625. DWORD dwIndex = 0;
  626. if(this->lpMap && this->dwMapEntries)
  627. {
  628. // REVIEW!!!! -- We need to make this faster -- use a sorted array
  629. while(dwIndex < this->dwMapEntries)
  630. {
  631. if(this->lpMap[dwIndex++].dwLobbyID == dwLobbyID)
  632. {
  633. *lpdwIndex = --dwIndex;
  634. return TRUE;
  635. }
  636. }
  637. }
  638. return FALSE;
  639. } // PRV_DoesLobbyIDExist
  640. #undef DPF_MODNAME
  641. #define DPF_MODNAME "PRV_AddMapIDNode"
  642. HRESULT PRV_AddMapIDNode(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID, DPID dpid)
  643. {
  644. HRESULT hr = DP_OK;
  645. DWORD dwIndex = 0;
  646. // Make sure we have room for a new entry
  647. if(this->dwMapEntries == this->dwTotalMapEntries)
  648. {
  649. hr = PRV_GrowMapTable(this);
  650. if(FAILED(hr))
  651. return hr;
  652. }
  653. // Verify that this LobbyID doesn't already exist in the table
  654. if(PRV_DoesLobbyIDExist(this, dwLobbyID, &dwIndex))
  655. {
  656. DPF(2, "Tried to add Lobby ID to map table which already existed, overwriting data");
  657. ASSERT(FALSE);
  658. this->lpMap[dwIndex].dwLobbyID = dwLobbyID;
  659. this->lpMap[dwIndex].dpid = dpid;
  660. return hr;
  661. }
  662. // REVIEW!!!! -- We need to add this in and keep the array sorted to
  663. // make lookups faster, but for now, don't worry about it.
  664. // Fill in a new node at the end of the array
  665. this->lpMap[this->dwMapEntries].dwLobbyID = dwLobbyID;
  666. this->lpMap[this->dwMapEntries].dpid = dpid;
  667. this->dwMapEntries++;
  668. return hr;
  669. } // PRV_AddMapIDNode
  670. #undef DPF_MODNAME
  671. #define DPF_MODNAME "PRV_DeleteMapIDNode"
  672. BOOL PRV_DeleteMapIDNode(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
  673. {
  674. DWORD dwIndex = 0;
  675. // Make sure we have entries
  676. if((this->lpMap) && (this->dwMapEntries))
  677. {
  678. // REVIEW!!!! -- We need to make this faster by using a sorted array
  679. while(dwIndex < this->dwMapEntries)
  680. {
  681. if(this->lpMap[dwIndex].dwLobbyID == dwLobbyID)
  682. {
  683. // Check for the boundary case (last entry)
  684. if((++dwIndex) == this->dwMapEntries)
  685. {
  686. // This is the last entry, so don't do anything but
  687. // decrement the number of entries
  688. this->dwMapEntries--;
  689. return TRUE;
  690. }
  691. else
  692. {
  693. // Move all entries from here to the end of the list
  694. // up one array entry
  695. MoveMemory((LPDPLOBBYI_MAPIDNODE)(&this->lpMap[dwIndex-1]),
  696. (LPDPLOBBYI_MAPIDNODE)(&this->lpMap[dwIndex]),
  697. ((this->dwMapEntries - dwIndex) *
  698. sizeof(DPLOBBYI_MAPIDNODE)));
  699. // Decrement the count of entries
  700. this->dwMapEntries--;
  701. return TRUE;
  702. }
  703. }
  704. else
  705. dwIndex++;
  706. }
  707. }
  708. // We weren't able to delete the entry in the map table
  709. DPF(2, "Trying to delete an entry in the map ID table which doesn't exist");
  710. ASSERT(FALSE);
  711. return FALSE;
  712. } // PRV_DeleteMapIDNode
  713. #undef DPF_MODNAME
  714. #define DPF_MODNAME "PRV_GetDPIDByLobbyID"
  715. BOOL PRV_GetDPIDByLobbyID(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID,
  716. DPID * lpdpid)
  717. {
  718. DWORD dwIndex = 0;
  719. // Take care of the known cases or else look in the map table
  720. switch(dwLobbyID)
  721. {
  722. case DPID_ALLPLAYERS:
  723. case DPID_SERVERPLAYER:
  724. *lpdpid = dwLobbyID;
  725. return TRUE;
  726. default:
  727. // Walk the list look for the ID
  728. while(dwIndex < this->dwMapEntries)
  729. {
  730. if(this->lpMap[dwIndex].dwLobbyID == dwLobbyID)
  731. {
  732. *lpdpid = this->lpMap[dwIndex].dpid;
  733. return TRUE;
  734. }
  735. else
  736. dwIndex++;
  737. }
  738. }
  739. return FALSE;
  740. } // PRV_GetDPIDByLobbyID
  741. #undef DPF_MODNAME
  742. #define DPF_MODNAME "PRV_GetLobbyIDByDPID"
  743. BOOL PRV_GetLobbyIDByDPID(LPDPLOBBYI_DPLOBJECT this, DPID dpid,
  744. LPDWORD lpdwLobbyID)
  745. {
  746. DWORD dwIndex = 0;
  747. // Take care of the known cases or else look in the map table
  748. switch(dpid)
  749. {
  750. case DPID_ALLPLAYERS:
  751. case DPID_SERVERPLAYER:
  752. *lpdwLobbyID = dpid;
  753. return TRUE;
  754. default:
  755. // Walk the list look for the ID
  756. while(dwIndex < this->dwMapEntries)
  757. {
  758. if(this->lpMap[dwIndex].dpid == dpid)
  759. {
  760. *lpdwLobbyID = this->lpMap[dwIndex].dwLobbyID;
  761. return TRUE;
  762. }
  763. else
  764. dwIndex++;
  765. }
  766. break;
  767. }
  768. return FALSE;
  769. } // PRV_GetLobbyIDByDPID
  770. #undef DPF_MODNAME
  771. #define DPF_MODNAME "IsLobbyIDInMapTable"
  772. BOOL IsLobbyIDInMapTable(LPDPLOBBYI_DPLOBJECT this, DWORD dwID)
  773. {
  774. DPID dpidTemp;
  775. // If we can get it, then it's in there
  776. if(PRV_GetDPIDByLobbyID(this, dwID, &dpidTemp))
  777. return TRUE;
  778. // Otherwise, return FALSE
  779. return FALSE;
  780. } // IsLobbyIDInMapTable
  781. #undef DPF_MODNAME
  782. #define DPF_MODNAME "IsValidLobbyID"
  783. BOOL IsValidLobbyID(DWORD dwID)
  784. {
  785. // If it's in our reserved range, it's invalid. Otherwise, it's valid
  786. if(dwID <= DPID_RESERVEDRANGE)
  787. return FALSE;
  788. else
  789. return TRUE;
  790. } // IsValidLobbyID
  791. #undef DPF_MODNAME
  792. #define DPF_MODNAME "PRV_CreateAndMapNewPlayer"
  793. HRESULT PRV_CreateAndMapNewPlayer(LPDPLOBBYI_DPLOBJECT this,
  794. DPID * lpdpid, LPDPNAME lpName, HANDLE hEvent, LPVOID lpData,
  795. DWORD dwDataSize, DWORD dwFlags, DWORD dwLobbyID,
  796. BOOL bSystemPlayer)
  797. {
  798. LPDPLAYI_PLAYER lpPlayer = NULL, lpSysPlayer = NULL;
  799. HRESULT hr = DP_OK;
  800. DPID dpidPlayer = 0, dpidSysPlayer = 0;
  801. // Take the dplay lock
  802. ENTER_DPLAY();
  803. // Make sure the lobby ID is valid, but only if it's not a system player
  804. if((!bSystemPlayer) && (!IsValidLobbyID(dwLobbyID)))
  805. {
  806. DPF_ERRVAL("ID %lu is reserved, cannot create new player", dwLobbyID);
  807. hr = DPERR_INVALIDPLAYER;
  808. goto EXIT_CREATEANDMAPNEWPLAYER;
  809. }
  810. // If this is a remote player, we need allocate a new nametable entry
  811. // for them and set the correct system player ID
  812. if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  813. {
  814. // Allocate a new ID for the player
  815. hr = NS_AllocNameTableEntry(this->lpDPlayObject, &dpidPlayer);
  816. if(FAILED(hr))
  817. {
  818. DPF_ERRVAL("Unable to allocate new nametable id, hr = 0x%08x", hr);
  819. goto EXIT_CREATEANDMAPNEWPLAYER;
  820. }
  821. // Make sure we have a lobby system player (for all remote players)
  822. // If we don't then allocate a new one, unless we are creating
  823. // the system player currently
  824. if((!(this->dpidSysPlayer)) && (!(dwFlags & DPLAYI_PLAYER_SYSPLAYER)))
  825. {
  826. hr = PRV_CreateAndMapNewPlayer(this, &dpidSysPlayer, NULL, NULL, NULL,
  827. 0, DPLAYI_PLAYER_SYSPLAYER,
  828. DPID_LOBBYREMOTESYSTEMPLAYER, TRUE);
  829. if(FAILED(hr))
  830. {
  831. DPF_ERRVAL("Unable to create lobby system player, hr = 0x%08x", hr);
  832. ASSERT(FALSE);
  833. goto EXIT_CREATEANDMAPNEWPLAYER;
  834. }
  835. // Set the lobby system player ID pointer to the new ID
  836. this->dpidSysPlayer = dpidSysPlayer;
  837. }
  838. }
  839. // Get a player struct for the player (if it's local, this will add it
  840. // to the nametable. If it's remote, we need to add it below)
  841. hr = GetPlayer(this->lpDPlayObject, &lpPlayer, lpName, hEvent, lpData,
  842. dwDataSize, dwFlags, NULL, dwLobbyID);
  843. if(FAILED(hr))
  844. {
  845. DPF_ERRVAL("Failed trying to add player to the nametable, hr = 0x%08x", hr);
  846. goto EXIT_CREATEANDMAPNEWPLAYER;
  847. }
  848. // If the player is remote, set the player's ID to the new one we
  849. // allocated and then set the system player ID to the lobby system player
  850. if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  851. {
  852. // Set the player's system player
  853. lpPlayer->dwIDSysPlayer = this->dpidSysPlayer;
  854. // Add the player to the nametable
  855. hr = AddItemToNameTable(this->lpDPlayObject, (DWORD_PTR)lpPlayer,
  856. &dpidPlayer, TRUE, dwLobbyID);
  857. if (FAILED(hr))
  858. {
  859. DPF_ERRVAL("Unable to add new player to the nametable, hr = 0x%08x", hr);
  860. ASSERT(FALSE);
  861. goto EXIT_CREATEANDMAPNEWPLAYER;
  862. }
  863. // Set the player's ID
  864. lpPlayer->dwID = dpidPlayer;
  865. }
  866. // Set the output dpid pointer
  867. *lpdpid = lpPlayer->dwID;
  868. EXIT_CREATEANDMAPNEWPLAYER:
  869. LEAVE_DPLAY();
  870. return hr;
  871. } // PRV_CreateAndMapNewPlayer