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.

2694 lines
77 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dplsp.c
  6. * Content: DirectPlayLobby Service Provider interface code
  7. *
  8. * History:
  9. * Date By Reason
  10. * ======= ======= ======
  11. * 10/23/96 myronth Created it
  12. * 11/20/96 myronth Added DPLAPI to function declarations
  13. * 2/12/97 myronth Mass DX5 changes
  14. * 2/18/97 myronth Implemented GetObjectCaps
  15. * 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
  16. * 3/31/97 myronth Implemented all IDPLobbySP methods without putting
  17. * player management message in the message queue.
  18. * Removed dead code
  19. * 4/4/97 myronth Changed IDPLobbySP methods' structure names and
  20. * implemented system messages for all of them
  21. * 4/27/97 sohailm Updated calls to HandlePlayerMessage to reflect new params
  22. * 5/8/97 myronth All remote subgroup functions for IDPLobbySP
  23. * including StartSession, Purged dead code
  24. * 5/12/97 myronth Extra semi-colon bug fixes, Fixed group player count
  25. * decrement that was in the wrong place
  26. * 5/14/97 myronth Allow CreateGroup message to pass even if the
  27. * Group ID is in the map table (bug #8354).
  28. * 5/17/97 myronth Fixed HandleMessage, Added SendChatMessage
  29. * 5/17/97 myronth Filtered some message to certain groups, Fixed calls
  30. * to CreateAndMapNewGroup which needed a parent ID
  31. * 5/20/97 myronth Changed DPLP_DeleteRemotePlayerFromGroup to use
  32. * InternalDeletePlayerFromGroup instead of
  33. * RemovedPlayerFromGroup (now includes system player)
  34. * (Bug #8586)
  35. * 5/21/97 myronth Fixed the player name for players joining a session
  36. * (#8798), Changed to new DPMSG_CHAT format (#8642)
  37. * 5/22/97 myronth Fixed flag propagation in DPLP_CreateGroup (#8813)
  38. * 5/23/97 myronth Send messages locally for CreateGroup and
  39. * CreateGroupInGroup (#8870)
  40. * 6/3/97 myronth Added support for player flags in AddPlayerToGroup
  41. * (#9091) and added PRV_RemoveSubgroupsAndPlayers-
  42. * FromGroup function (#9134)
  43. * 6/5/97 myronth Fixed AddGroupToGroup & DeleteGroupFromGroup by
  44. * adding heirarchy creating & deletion. (#8731)
  45. * 6/6/97 myronth Moved code from PRV_DeleteRemoteGroupFromGroup to
  46. * PRV_DestroyGroupAndParents in group.c, Changed all
  47. * DistributeGroupMessage calls to go to all players
  48. * 6/16/97 myronth Fixed call to InternalAddGroupToGroup (#9745) and
  49. * fixed Delete messages for shortcuts on DestroyGroup
  50. * (#9739)
  51. * 6/20/97 myronth Changed AddGroupToGroup to check if a group exists
  52. * and not send a duplicate message (#10139)
  53. * 6/24/97 myronth Changed AddPlayerToGroup to check if a player exists
  54. * and not send a duplicate message (#10287)
  55. * 7/30/97 myronth Added support for standard lobby messaging
  56. * 8/11/97 myronth Added guidInstance handling in standard lobby requests
  57. * 8/19/97 myronth Removed bogus assert
  58. * 9/29/97 myronth Ignore SetPlayerName/Data msgs for local players (#12554)
  59. * 10/3/97 myronth Fixed player & group data for remote players/groups (#10961)
  60. * 10/7/97 myronth Fixed LP version checking for player & group data (regresssion)
  61. * 10/8/97 myronth Rolled back fix for #10961 (group & player data)
  62. * 10/23/97 myronth Added hidden group support (#12688), fixed crashing
  63. * bug on DeletePlayerFromGroup (#12885)
  64. * 10/29/97 myronth Added support for group owners, including DPLP_SetGroupOwner
  65. * 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
  66. * 11/6/97 myronth Made SendChatMessage handle a dwFromID of
  67. * DPID_SERVERPLAYER (#12843)
  68. * 11/19/97 myronth Fixed VALID_DPLAY_GROUP macro (#12841)
  69. * 2/13/98 aarono changed InternalDeletePlayer, added flag.
  70. * 8/30/00 aarono B#43812 improper construction of DATA CHANGED.
  71. * in SendDataChangedLocally.
  72. ***************************************************************************/
  73. #include "dplobpr.h"
  74. //--------------------------------------------------------------------------
  75. //
  76. // Functions
  77. //
  78. //--------------------------------------------------------------------------
  79. #undef DPF_MODNAME
  80. #define DPF_MODNAME "PRV_SendBuildParentalHeirarchyMessage"
  81. void PRV_SendBuildParentalHeirarchyMessage(LPDPLOBBYI_DPLOBJECT this,
  82. DWORD dwGroupID, DWORD dwParentID)
  83. {
  84. SPDATA_BUILDPARENTALHEIRARCHY bph;
  85. HRESULT hr;
  86. DPF(7, "Entering PRV_SendBuildParentalHeirarchyMessage");
  87. DPF(9, "Parameters: 0x%08x, %lu, %lu", this, dwGroupID, dwParentID);
  88. // Setup the SPDATA structure
  89. memset(&bph, 0, sizeof(SPDATA_BUILDPARENTALHEIRARCHY));
  90. bph.dwSize = sizeof(SPDATA_BUILDPARENTALHEIRARCHY);
  91. bph.lpISP = PRV_GetDPLobbySPInterface(this);
  92. bph.dwGroupID = dwGroupID;
  93. bph.dwMessage = DPSYS_ADDGROUPTOGROUP;
  94. bph.dwParentID = dwParentID;
  95. // Call the BuildParentalHeirarchy method in the SP
  96. if(CALLBACK_EXISTS(BuildParentalHeirarchy))
  97. {
  98. // Drop the lock so the lobby provider's receive thread can get back
  99. // in with other messages if they show up in the queue before our
  100. // CreatePlayer response (which always happens)
  101. LEAVE_DPLOBBY();
  102. hr = CALL_LP(this, BuildParentalHeirarchy, &bph);
  103. ENTER_DPLOBBY();
  104. }
  105. else
  106. {
  107. // BuildParentalHeirarchy is required
  108. DPF_ERR("The Lobby Provider callback for BuildParentalHeirarchy doesn't exist -- it's required");
  109. ASSERT(FALSE);
  110. }
  111. } // PRV_SendBuildParentalHeirarchyMessage
  112. #undef DPF_MODNAME
  113. #define DPF_MODNAME "DPLP_AddGroupToGroup"
  114. HRESULT DPLAPI DPLP_AddGroupToGroup(LPDPLOBBYSP lpILP,
  115. LPSPDATA_ADDREMOTEGROUPTOGROUP lpd)
  116. {
  117. SPDATA_CREATEREMOTEGROUPINGROUP cgig;
  118. SPDATA_DESTROYREMOTEGROUP dg;
  119. SPDATA_CREATEREMOTEGROUP cg;
  120. LPDPLOBBYI_DPLOBJECT this;
  121. HRESULT hr = DP_OK;
  122. LPDPLAYI_PLAYER lpPlayer = NULL;
  123. LPDPLAYI_GROUP lpGroup = NULL;
  124. LPDPLAYI_GROUP lpGroupTo = NULL;
  125. LPDPLAYI_GROUP lpAnchor = NULL;
  126. LPDPLAYI_SUBGROUP lpSubgroup = NULL;
  127. MSG_PLAYERMGMTMESSAGE msg;
  128. BOOL bCreated = FALSE;
  129. DPF(7, "Entering DPLP_AddGroupToGroup");
  130. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  131. ENTER_DPLOBBY();
  132. // Make sure the LP doesn't throw us a curve
  133. TRY
  134. {
  135. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  136. if( !VALID_DPLOBBY_PTR( this ) )
  137. {
  138. LEAVE_DPLOBBY();
  139. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  140. return DPERR_INVALIDOBJECT;
  141. }
  142. // Validate the struct pointer
  143. if(!lpd)
  144. {
  145. LEAVE_DPLOBBY();
  146. DPF_ERR("SPDATA_ADDREMOTEGROUPTOGROUP structure pointer cannot be NULL");
  147. return DPERR_INVALIDPARAMS;
  148. }
  149. }
  150. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  151. {
  152. LEAVE_DPLOBBY();
  153. DPF_ERR( "Exception encountered validating parameters" );
  154. return DPERR_INVALIDPARAMS;
  155. }
  156. // First see if the group is in our map table. If it's not,
  157. // we should just ignore this message because it's for a
  158. // group we are not currently in.
  159. if(!IsLobbyIDInMapTable(this, lpd->dwAnchorID))
  160. {
  161. LEAVE_DPLOBBY();
  162. DPF(8, "Recieved AddGroupToGroup message for unknown anchor group, dwGroupID = %lu, discarding message", lpd->dwAnchorID);
  163. return DPERR_INVALIDGROUP;
  164. }
  165. // Now see if the group is in our map table. If it is, we
  166. // probably want to update the name. If it's not, we need to
  167. // add them to the nametable and the map table
  168. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  169. {
  170. // See if the group is a root group (remember hidden groups won't
  171. // get pushed down to us). If it is, then just create it.
  172. if(!(lpd->dwParentID))
  173. {
  174. // Setup the SPDATA struct for CreateRemoteGroup
  175. memset(&cg, 0, sizeof(SPDATA_CREATEREMOTEGROUP));
  176. cg.dwSize = sizeof(SPDATA_CREATEREMOTEGROUP);
  177. cg.dwGroupID = lpd->dwGroupID;
  178. cg.lpName = lpd->lpName;
  179. cg.dwFlags = lpd->dwGroupFlags;
  180. if(this->dwLPVersion > DPLSP_DX5VERSION)
  181. cg.dwGroupOwnerID = lpd->dwGroupOwnerID;
  182. else
  183. cg.dwGroupOwnerID = DPID_SERVERPLAYER;
  184. // Call our internal remote create
  185. hr = DPLP_CreateGroup((LPDPLOBBYSP)this->lpInterfaces, &cg);
  186. if(FAILED(hr))
  187. {
  188. LEAVE_DPLOBBY();
  189. DPF_ERRVAL("Failed creating remote parent group, hr = 0x%08x", hr);
  190. return hr;
  191. }
  192. bCreated = TRUE;
  193. }
  194. else
  195. {
  196. // See if it's parent shows up in the map table, if it doesn't,
  197. // we need to send a message to the server to tell it to build
  198. // the entire tree for us
  199. if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
  200. {
  201. DPF(8, "Sending message to server to build parental heirarchy, ignoring AddGroupToGroup message");
  202. PRV_SendBuildParentalHeirarchyMessage(this, lpd->dwGroupID,
  203. lpd->dwAnchorID);
  204. LEAVE_DPLOBBY();
  205. return DPERR_INVALIDGROUP;
  206. }
  207. // Setup the SPDATA struct for CreateRemoteGroupInGroup
  208. memset(&cgig, 0, sizeof(SPDATA_CREATEREMOTEGROUPINGROUP));
  209. cgig.dwSize = sizeof(SPDATA_CREATEREMOTEGROUPINGROUP);
  210. cgig.dwParentID = lpd->dwParentID;
  211. cgig.dwGroupID = lpd->dwGroupID;
  212. cgig.lpName = lpd->lpName;
  213. cgig.dwFlags = lpd->dwGroupFlags;
  214. if(this->dwLPVersion > DPLSP_DX5VERSION)
  215. cgig.dwGroupOwnerID = lpd->dwGroupOwnerID;
  216. else
  217. cgig.dwGroupOwnerID = DPID_SERVERPLAYER;
  218. // Call our internal remote create
  219. hr = DPLP_CreateGroupInGroup((LPDPLOBBYSP)this->lpInterfaces, &cgig);
  220. if(FAILED(hr))
  221. {
  222. LEAVE_DPLOBBY();
  223. DPF_ERRVAL("Failed creating remote group in group, hr = 0x%08x", hr);
  224. return hr;
  225. }
  226. bCreated = TRUE;
  227. }
  228. }
  229. // Take the dplay lock
  230. ENTER_DPLAY();
  231. // Make sure the group isn't already in the parent group. If it is,
  232. // we just want to return DP_OK and exit so that we don't send any
  233. // duplicate messages.
  234. lpAnchor = GroupFromID(this->lpDPlayObject, lpd->dwAnchorID);
  235. if(!lpAnchor)
  236. {
  237. DPF_ERR("Unable to find group in nametable");
  238. hr = DPERR_INVALIDGROUP;
  239. goto ERROR_DPLP_ADDGROUPTOGROUP;
  240. }
  241. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  242. if(!lpGroup)
  243. {
  244. DPF_ERR("Unable to find group in nametable");
  245. hr = DPERR_INVALIDGROUP;
  246. goto ERROR_DPLP_ADDGROUPTOGROUP;
  247. }
  248. lpSubgroup = lpAnchor->pSubgroups;
  249. while(lpSubgroup)
  250. {
  251. if (lpSubgroup->pGroup == lpGroup)
  252. {
  253. DPF(2,"Group already in group!");
  254. hr = DP_OK;
  255. goto ERROR_DPLP_ADDGROUPTOGROUP;
  256. }
  257. // check next node
  258. lpSubgroup = lpSubgroup->pNextSubgroup;
  259. }
  260. // So now we should have a valid group and valid player in both
  261. // the map table and the nametable, so call dplay's AGtoG function
  262. hr = InternalAddGroupToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  263. lpd->dwAnchorID, lpd->dwGroupID, DPGROUP_SHORTCUT, FALSE);
  264. if(FAILED(hr))
  265. {
  266. // If we created the player and mapped it, then destroy the
  267. // player and unmap it.
  268. if(bCreated)
  269. {
  270. // Setup the SPDATA struct for DestroyRemoteGroup
  271. memset(&dg, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
  272. dg.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
  273. dg.dwGroupID = lpd->dwGroupID;
  274. // Call our internal remote create
  275. hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dg);
  276. if(FAILED(hr))
  277. {
  278. DPF_ERRVAL("Failed destroying remote group, hr = 0x%08x", hr);
  279. goto ERROR_DPLP_ADDGROUPTOGROUP;
  280. }
  281. }
  282. // If we failed, don't send the system message
  283. DPF_ERRVAL("Failed adding remote group to group from the lobby, hr = 0x%08x", hr);
  284. goto ERROR_DPLP_ADDGROUPTOGROUP;
  285. }
  286. // Find dplay's internal group struct for the To group
  287. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  288. if(!lpGroupTo)
  289. {
  290. DPF_ERR("Unable to find group in nametable");
  291. hr = DPERR_INVALIDGROUP;
  292. goto ERROR_DPLP_ADDGROUPTOGROUP;
  293. }
  294. // Now build the system message (at least the parts we need)
  295. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  296. SET_MESSAGE_HDR(&msg);
  297. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDSHORTCUTTOGROUP);
  298. msg.dwPlayerID = lpd->dwGroupID;
  299. msg.dwGroupID = lpd->dwAnchorID;
  300. // Call dplay's DistributeGroupMessage function to put the message
  301. // in the queues of all the appropriate players
  302. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  303. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  304. if(FAILED(hr))
  305. {
  306. DPF(8, "Failed adding AddGroupToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  307. }
  308. ERROR_DPLP_ADDGROUPTOGROUP:
  309. // Drop the lock
  310. LEAVE_LOBBY_ALL();
  311. return hr;
  312. } // DPLP_AddGroupToGroup
  313. #undef DPF_MODNAME
  314. #define DPF_MODNAME "DPLP_AddPlayerToGroup"
  315. HRESULT DPLAPI DPLP_AddPlayerToGroup(LPDPLOBBYSP lpILP,
  316. LPSPDATA_ADDREMOTEPLAYERTOGROUP lpd)
  317. {
  318. LPDPLOBBYI_DPLOBJECT this;
  319. HRESULT hr = DP_OK;
  320. DPID dpidPlayer;
  321. LPDPLAYI_PLAYER lpPlayer = NULL;
  322. LPDPLAYI_GROUP lpGroupTo = NULL;
  323. LPDPLAYI_GROUP lpGroup = NULL;
  324. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  325. MSG_PLAYERMGMTMESSAGE msg, cpmsg;
  326. BOOL bCreated = FALSE;
  327. DWORD dwPlayerFlags = 0;
  328. DPF(7, "Entering DPLP_AddPlayerToGroup");
  329. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  330. ENTER_DPLOBBY();
  331. // Make sure the LP doesn't throw us a curve
  332. TRY
  333. {
  334. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  335. if( !VALID_DPLOBBY_PTR( this ) )
  336. {
  337. LEAVE_DPLOBBY();
  338. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  339. return DPERR_INVALIDOBJECT;
  340. }
  341. // Validate the struct pointer
  342. if(!lpd)
  343. {
  344. LEAVE_DPLOBBY();
  345. DPF_ERR("SPDATA_ADDREMOTEPLAYERTOGROUP structure pointer cannot be NULL");
  346. return DPERR_INVALIDPARAMS;
  347. }
  348. }
  349. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  350. {
  351. LEAVE_DPLOBBY();
  352. DPF_ERR( "Exception encountered validating parameters" );
  353. return DPERR_INVALIDPARAMS;
  354. }
  355. // First see if the group is in our map table. If it's not,
  356. // we should just ignore this message because it's for a
  357. // group we are not currently in.
  358. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  359. {
  360. LEAVE_DPLOBBY();
  361. DPF(8, "Recieved AddPlayerToGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  362. return DPERR_INVALIDGROUP;
  363. }
  364. // Fix up the player flags
  365. if(lpd->dwPlayerFlags & DPPLAYER_SPECTATOR)
  366. dwPlayerFlags |= DPLAYI_PLAYER_SPECTATOR;
  367. if(lpd->dwPlayerFlags & DPPLAYER_SERVERPLAYER)
  368. dwPlayerFlags |= DPLAYI_PLAYER_APPSERVER;
  369. // Take the dplay lock
  370. ENTER_DPLAY();
  371. // Now see if the player is in our map table. If it is, we
  372. // probably want to update the name. If it's not, we need to
  373. // add them to the nametable and the map table
  374. if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
  375. {
  376. // It doesn't show up in our map table, so create a new
  377. // nametable entry for them and put them in our map table.
  378. hr = PRV_CreateAndMapNewPlayer(this, &dpidPlayer, lpd->lpName,
  379. NULL, NULL, 0, dwPlayerFlags,
  380. lpd->dwPlayerID, FALSE);
  381. if(FAILED(hr))
  382. {
  383. DPF(8, "Unable to add player to nametable or map table, hr = 0x%08x", hr);
  384. goto ERROR_DPLP_ADDPLAYER;
  385. }
  386. bCreated = TRUE;
  387. }
  388. // Make sure the player isn't already in the group. If it is,
  389. // we just want to return DP_OK and exit so that we don't send any
  390. // duplicate messages.
  391. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  392. if(!lpGroup)
  393. {
  394. DPF_ERR("Unable to find group in nametable");
  395. hr = DPERR_INVALIDGROUP;
  396. goto ERROR_DPLP_ADDPLAYER;
  397. }
  398. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
  399. if(!lpPlayer)
  400. {
  401. DPF_ERR("Unable to find player in nametable");
  402. hr = DPERR_INVALIDPLAYER;
  403. goto ERROR_DPLP_ADDPLAYER;
  404. }
  405. lpGroupnode = lpGroup->pGroupnodes;
  406. while(lpGroupnode)
  407. {
  408. if(lpGroupnode->pPlayer == lpPlayer)
  409. {
  410. DPF(2, "Player already in group!");
  411. hr = DP_OK;
  412. goto ERROR_DPLP_ADDPLAYER;
  413. }
  414. // check next node
  415. lpGroupnode = lpGroupnode->pNextGroupnode;
  416. }
  417. // So now we should have a valid group and valid player in both
  418. // the map table and the nametable, so call dplay with the add message
  419. hr = InternalAddPlayerToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  420. lpd->dwGroupID, lpd->dwPlayerID, FALSE);
  421. if(FAILED(hr))
  422. {
  423. // If we created the player and mapped it, then destroy the
  424. // player and unmap it.
  425. if(bCreated)
  426. {
  427. // Remove the player from the nametable
  428. InternalDestroyPlayer(this->lpDPlayObject, lpPlayer, FALSE, FALSE);
  429. }
  430. // If we failed, don't send the system message
  431. DPF_ERRVAL("Failed adding remote player to group from the lobby, hr = 0x%08x", hr);
  432. goto ERROR_DPLP_ADDPLAYER;
  433. }
  434. // Find dplay's internal group struct for the To group
  435. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  436. if(!lpGroupTo)
  437. {
  438. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  439. hr = DPERR_INVALIDGROUP;
  440. goto ERROR_DPLP_ADDPLAYER;
  441. }
  442. // If we created this player, we need to send a CreatePlayer message ahead
  443. // of the AddPlayerToGroup message
  444. if(bCreated)
  445. {
  446. // Now build the system message (at least the parts we need)
  447. memset(&cpmsg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  448. SET_MESSAGE_HDR(&cpmsg);
  449. SET_MESSAGE_COMMAND(&cpmsg, DPSP_MSG_CREATEPLAYER);
  450. cpmsg.dwPlayerID = lpd->dwPlayerID;
  451. // Call dplay's DistributeGroupMessage function to put the message
  452. // in the queues of all the appropriate players
  453. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  454. (LPBYTE)&cpmsg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  455. if(FAILED(hr))
  456. {
  457. DPF(8, "Failed adding CreatePlayer message to player's receive queue from lobby, hr = 0x%08x", hr);
  458. }
  459. }
  460. // Now build the system message for AddPlayerToGroup
  461. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  462. SET_MESSAGE_HDR(&msg);
  463. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDPLAYERTOGROUP);
  464. msg.dwPlayerID = lpd->dwPlayerID;
  465. msg.dwGroupID = lpd->dwGroupID;
  466. // Call dplay's DistributeGroupMessage function to put the message
  467. // in the queues of all the appropriate players
  468. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  469. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  470. if(FAILED(hr))
  471. {
  472. DPF(8, "Failed adding AddPlayerToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  473. }
  474. // We need to see if this player is the group owner. If it is,
  475. // we need to send a SetGroupOwner message as well.
  476. if(lpd->dwPlayerID == lpGroup->dwOwnerID)
  477. {
  478. // Now send the message
  479. PRV_SendGroupOwnerMessageLocally(this, lpd->dwGroupID,
  480. lpd->dwPlayerID, 0);
  481. }
  482. ERROR_DPLP_ADDPLAYER:
  483. // Drop the lock
  484. LEAVE_LOBBY_ALL();
  485. return hr;
  486. } // DPLP_AddPlayerToGroup
  487. #undef DPF_MODNAME
  488. #define DPF_MODNAME "DPLP_CreateGroup"
  489. HRESULT DPLAPI DPLP_CreateGroup(LPDPLOBBYSP lpILP,
  490. LPSPDATA_CREATEREMOTEGROUP lpd)
  491. {
  492. LPDPLOBBYI_DPLOBJECT this;
  493. MSG_PLAYERMGMTMESSAGE msg;
  494. LPDPLAYI_GROUP lpGroupTo = NULL;
  495. HRESULT hr = DP_OK;
  496. DPID dpidGroup;
  497. DWORD dwInternalFlags = 0;
  498. DWORD dwOwnerID;
  499. DPF(7, "Entering DPLP_CreateGroup");
  500. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  501. ENTER_DPLOBBY();
  502. // Make sure the LP doesn't throw us a curve
  503. TRY
  504. {
  505. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  506. if( !VALID_DPLOBBY_PTR( this ) )
  507. {
  508. LEAVE_DPLOBBY();
  509. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  510. return DPERR_INVALIDOBJECT;
  511. }
  512. // Validate the struct pointer
  513. if(!lpd)
  514. {
  515. LEAVE_DPLOBBY();
  516. DPF_ERR("SPDATA_CREATEREMOTEGROUP structure pointer cannot be NULL");
  517. return DPERR_INVALIDPARAMS;
  518. }
  519. }
  520. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  521. {
  522. LEAVE_DPLOBBY();
  523. DPF_ERR( "Exception encountered validating parameters" );
  524. return DPERR_INVALIDPARAMS;
  525. }
  526. // Fix the flags from external to internal
  527. if(lpd->dwFlags & DPGROUP_STAGINGAREA)
  528. dwInternalFlags = DPLAYI_GROUP_STAGINGAREA;
  529. if(lpd->dwFlags & DPGROUP_HIDDEN)
  530. dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
  531. // Take the lock
  532. ENTER_DPLAY();
  533. // First see if the group is in our map table. If it is,
  534. // we just want to return. If it's not, we want to add
  535. // them and send the appropriate message
  536. if(IsLobbyIDInMapTable(this, lpd->dwGroupID))
  537. {
  538. DPF(2, "Received a CreateGroup message for a group we already know about");
  539. hr = DP_OK;
  540. goto ERROR_DPLP_CREATEGROUP;
  541. }
  542. else
  543. {
  544. // Make the owner default to the server player if we have a problem
  545. dwOwnerID = DPID_SERVERPLAYER;
  546. // If we are talking to at least a DX6 lobby provider, we should
  547. // be able to use the GroupOwnerID element
  548. if(this->dwLPVersion > DPLSP_DX5VERSION)
  549. dwOwnerID = lpd->dwGroupOwnerID;
  550. // Create a new entry in the nametable and map the ID's
  551. hr = PRV_CreateAndMapNewGroup(this, &dpidGroup, lpd->lpName,
  552. lpd->lpData, lpd->dwDataSize, dwInternalFlags,
  553. lpd->dwGroupID, 0, dwOwnerID);
  554. if(FAILED(hr))
  555. {
  556. // If we fail, we don't want to send the system message
  557. DPF_ERRVAL("Unable to add group to nametable or map table, hr = 0x%08x", hr);
  558. goto ERROR_DPLP_CREATEGROUP;
  559. }
  560. }
  561. // Now build the system message (at least the parts we need
  562. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  563. SET_MESSAGE_HDR(&msg);
  564. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
  565. msg.dwPlayerID = lpd->dwGroupID;
  566. // Find dplay's internal group struct for the To group
  567. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  568. if(!lpGroupTo)
  569. {
  570. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  571. hr = DPERR_INVALIDGROUP;
  572. goto ERROR_DPLP_CREATEGROUP;
  573. }
  574. // Call dplay's DistributeGroupMessage function to put the message in
  575. // the queues of all the appropriate players
  576. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo, (LPBYTE)&msg,
  577. sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  578. if(FAILED(hr))
  579. {
  580. DPF(8, "Failed adding CreateGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  581. }
  582. ERROR_DPLP_CREATEGROUP:
  583. // Drop the lock
  584. LEAVE_LOBBY_ALL();
  585. return hr;
  586. } // DPLP_CreateGroup
  587. #undef DPF_MODNAME
  588. #define DPF_MODNAME "DPLP_CreateGroupInGroup"
  589. HRESULT DPLAPI DPLP_CreateGroupInGroup(LPDPLOBBYSP lpILP,
  590. LPSPDATA_CREATEREMOTEGROUPINGROUP lpd)
  591. {
  592. LPDPLOBBYI_DPLOBJECT this;
  593. HRESULT hr = DP_OK;
  594. DPID dpidGroup;
  595. LPDPLAYI_PLAYER lpPlayer = NULL;
  596. LPDPLAYI_GROUP lpGroup = NULL;
  597. LPDPLAYI_GROUP lpGroupTo = NULL;
  598. MSG_PLAYERMGMTMESSAGE msg;
  599. BOOL bCreated = FALSE;
  600. DWORD dwInternalFlags = 0;
  601. DWORD dwOwnerID;
  602. DPF(7, "Entering DPLP_CreateGroupInGroup");
  603. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  604. ENTER_DPLOBBY();
  605. // Make sure the LP doesn't throw us a curve
  606. TRY
  607. {
  608. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  609. if( !VALID_DPLOBBY_PTR( this ) )
  610. {
  611. LEAVE_DPLOBBY();
  612. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  613. return DPERR_INVALIDOBJECT;
  614. }
  615. // Validate the struct pointer
  616. if(!lpd)
  617. {
  618. LEAVE_DPLOBBY();
  619. DPF_ERR("SPDATA_CREATEREMOTEGROUPINGROUP structure pointer cannot be NULL");
  620. return DPERR_INVALIDPARAMS;
  621. }
  622. }
  623. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  624. {
  625. LEAVE_DPLOBBY();
  626. DPF_ERR( "Exception encountered validating parameters" );
  627. return DPERR_INVALIDPARAMS;
  628. }
  629. // First see if the group is in our map table. If it's not,
  630. // we should just ignore this message because it's for a
  631. // group we are not currently in.
  632. if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
  633. {
  634. LEAVE_DPLOBBY();
  635. DPF_ERRVAL("Recieved CreateGroupInGroup message for unknown parent group, dwGroupID = %lu, discarding message", lpd->dwParentID);
  636. return DPERR_INVALIDGROUP;
  637. }
  638. // Take the dplay lock
  639. ENTER_DPLAY();
  640. // First see if the group is in our map table. If it is,
  641. // we just want to return. If it's not, we want to add
  642. // them and send the appropriate message
  643. if(IsLobbyIDInMapTable(this, lpd->dwGroupID))
  644. {
  645. DPF(2, "Received a CreateGroupInGroup message for a group we already know about");
  646. hr = DP_OK;
  647. goto ERROR_DPLP_CREATEGROUPINGROUP;
  648. }
  649. else
  650. {
  651. // Setup the internal flags
  652. if(lpd->dwFlags & DPGROUP_STAGINGAREA)
  653. dwInternalFlags = DPLAYI_GROUP_STAGINGAREA;
  654. if(lpd->dwFlags & DPGROUP_HIDDEN)
  655. dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
  656. // Make the owner default to the server player if we have a problem
  657. dwOwnerID = DPID_SERVERPLAYER;
  658. // If we are talking to at least a DX6 lobby provider, we should
  659. // be able to use the GroupOwnerID element
  660. if(this->dwLPVersion > DPLSP_DX5VERSION)
  661. dwOwnerID = lpd->dwGroupOwnerID;
  662. // It doesn't show up in our map table, so create a new
  663. // nametable entry for them and put them in our map table.
  664. hr = PRV_CreateAndMapNewGroup(this, &dpidGroup, lpd->lpName,
  665. NULL, 0, dwInternalFlags,
  666. lpd->dwGroupID, lpd->dwParentID, dwOwnerID);
  667. if(FAILED(hr))
  668. {
  669. DPF(8, "Unable to add group to nametable or map table, hr = 0x%08x", hr);
  670. goto ERROR_DPLP_CREATEGROUPINGROUP;
  671. }
  672. bCreated = TRUE;
  673. }
  674. // So now we should have a valid group and valid player in both
  675. // the map table and the nametable, so call dplay with the add message
  676. hr = InternalAddGroupToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  677. lpd->dwParentID, lpd->dwGroupID, lpd->dwFlags, FALSE);
  678. if(FAILED(hr))
  679. {
  680. // If we created the player and mapped it, then destroy the
  681. // player and unmap it.
  682. if(bCreated)
  683. {
  684. // Get a pointer to dplay's group struct
  685. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  686. // Remove the group from the nametable
  687. if(lpGroup){
  688. InternalDestroyGroup(this->lpDPlayObject, lpGroup, FALSE);
  689. }
  690. }
  691. // If we failed, don't send the system message
  692. DPF_ERRVAL("Failed creating remote group in group from the lobby, hr = 0x%08x", hr);
  693. goto ERROR_DPLP_CREATEGROUPINGROUP;
  694. }
  695. // Now build the system message (at least the parts we need)
  696. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  697. SET_MESSAGE_HDR(&msg);
  698. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
  699. msg.dwPlayerID = lpd->dwGroupID;
  700. // Find dplay's internal group struct for the To group
  701. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  702. if(!lpGroupTo)
  703. {
  704. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  705. hr = DPERR_INVALIDGROUP;
  706. goto ERROR_DPLP_CREATEGROUPINGROUP;
  707. }
  708. // Call dplay's DistributeGroupMessage function to put the message
  709. // in the queues of all the appropriate players
  710. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  711. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  712. if(FAILED(hr))
  713. {
  714. DPF(8, "Failed adding CreateGroupInGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  715. }
  716. ERROR_DPLP_CREATEGROUPINGROUP:
  717. // Drop the lock
  718. LEAVE_LOBBY_ALL();
  719. return hr;
  720. } // DPLP_CreateGroupInGroup
  721. #undef DPF_MODNAME
  722. #define DPF_MODNAME "PRV_DeleteRemoteGroupFromGroup"
  723. HRESULT PRV_DeleteRemoteGroupFromGroup(LPDPLOBBYI_DPLOBJECT this,
  724. LPSPDATA_DELETEREMOTEGROUPFROMGROUP lpd, BOOL fPropagate,
  725. LPDPLAYI_GROUP lpStopParent)
  726. {
  727. LPDPLAYI_GROUP lpGroupTo = NULL;
  728. LPDPLAYI_GROUP lpGroup = NULL, lpParentGroup = NULL;
  729. MSG_PLAYERMGMTMESSAGE msg;
  730. HRESULT hr = DP_OK;
  731. DPF(7, "Entering PRV_DeleteRemoteGroupFromGroup");
  732. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu, 0x%08x",
  733. this, lpd, fPropagate, lpStopParent);
  734. // First see if the group is in our map table. If it's not,
  735. // we should just ignore this message because it's for a
  736. // group we are not currently in.
  737. if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
  738. {
  739. DPF(8, "Recieved DeleteGroupFromGroup message for unknown parent group, dwGroupID = %lu, discarding message", lpd->dwParentID);
  740. return DPERR_INVALIDGROUP;
  741. }
  742. // Now make sure the group is in our map table. If it's not,
  743. // we should just ignore this message because it's for a
  744. // group we don't know about.
  745. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  746. {
  747. DPF(8, "Recieved DeleteGroupFromGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  748. return DPERR_INVALIDGROUP;
  749. }
  750. // Take the lock
  751. ENTER_DPLAY();
  752. // Get dplay's internal group structures
  753. lpParentGroup = GroupFromID(this->lpDPlayObject, lpd->dwParentID);
  754. if(!lpParentGroup)
  755. {
  756. LEAVE_DPLAY();
  757. DPF(8, "Unable to find parent group in nametable");
  758. return DPERR_INVALIDGROUP;
  759. }
  760. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  761. if(!lpGroup)
  762. {
  763. LEAVE_DPLAY();
  764. DPF(8, "Unable to find group in nametable");
  765. return DPERR_INVALIDGROUP;
  766. }
  767. // Call dplay's internal removegroupfromgroup to remove the attachment
  768. // in the nametable
  769. hr = RemoveGroupFromGroup(lpParentGroup, lpGroup);
  770. if(FAILED(hr))
  771. {
  772. DPF(8, "Failed removing group from group, hr = 0x%08x", hr);
  773. goto EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP;
  774. }
  775. // If the fPropagate flag is not set, we don't want to send this message
  776. if(fPropagate)
  777. {
  778. // Now build the system message (at least the parts we need)
  779. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  780. SET_MESSAGE_HDR(&msg);
  781. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
  782. msg.dwPlayerID = lpd->dwGroupID;
  783. msg.dwGroupID = lpd->dwParentID;
  784. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  785. if(!lpGroupTo)
  786. {
  787. DPF(8, "Unable to find system group in nametable");
  788. goto EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP;
  789. }
  790. // Call dplay's DistributeGroupMessage function to put the message
  791. // in the queues of all the appropriate players
  792. DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  793. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  794. if(FAILED(hr))
  795. {
  796. DPF(8, "Failed adding DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  797. }
  798. }
  799. // Even if we couldn't send the message above, destroy the group anyway
  800. EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP:
  801. // Destroy the group and any of it's parents if there are no more local
  802. // references to it or any of it's heirarchy
  803. PRV_DestroyGroupAndParents(this, lpGroup, lpStopParent);
  804. // Drop the lock
  805. LEAVE_DPLAY();
  806. return hr;
  807. } // PRV_DeleteRemoteGroupFromGroup
  808. #undef DPF_MODNAME
  809. #define DPF_MODNAME "DPLP_DeleteGroupFromGroup"
  810. HRESULT DPLAPI DPLP_DeleteGroupFromGroup(LPDPLOBBYSP lpILP,
  811. LPSPDATA_DELETEREMOTEGROUPFROMGROUP lpd)
  812. {
  813. LPDPLOBBYI_DPLOBJECT this;
  814. HRESULT hr = DP_OK;
  815. DPF(7, "Entering DPLP_DeleteGroupFromGroup");
  816. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  817. ENTER_DPLOBBY();
  818. // Make sure the LP doesn't throw us a curve
  819. TRY
  820. {
  821. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  822. if( !VALID_DPLOBBY_PTR( this ) )
  823. {
  824. LEAVE_DPLOBBY();
  825. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  826. return DPERR_INVALIDOBJECT;
  827. }
  828. // Validate the struct pointer
  829. if(!lpd)
  830. {
  831. LEAVE_DPLOBBY();
  832. DPF_ERR("SPDATA_DELETEREMOTEGROUPFROMGROUP structure pointer cannot be NULL");
  833. return DPERR_INVALIDPARAMS;
  834. }
  835. }
  836. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  837. {
  838. LEAVE_DPLOBBY();
  839. DPF_ERR( "Exception encountered validating parameters" );
  840. return DPERR_INVALIDPARAMS;
  841. }
  842. // Call our internal routine, setting the propagate flag to TRUE so that
  843. // we post the appropriate message in the player's receive queue
  844. hr = PRV_DeleteRemoteGroupFromGroup(this, lpd, TRUE, NULL);
  845. LEAVE_DPLOBBY();
  846. return hr;
  847. } // DPLP_DeleteGroupFromGroup
  848. #undef DPF_MODNAME
  849. #define DPF_MODNAME "PRV_DeleteRemotePlayerFromGroup"
  850. HRESULT PRV_DeleteRemotePlayerFromGroup(LPDPLOBBYI_DPLOBJECT this,
  851. LPSPDATA_DELETEREMOTEPLAYERFROMGROUP lpd, BOOL fPropagate)
  852. {
  853. LPDPLAYI_PLAYER lpPlayer = NULL;
  854. LPDPLAYI_GROUP lpGroupTo = NULL;
  855. MSG_PLAYERMGMTMESSAGE msg, dpmsg;
  856. HRESULT hr;
  857. DPF(7, "Entering PRV_DeleteRemotePlayerFromGroup");
  858. DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpd, fPropagate);
  859. // First see if the group is in our map table. If it's not,
  860. // we should just ignore this message because it's for a
  861. // group we are not currently in.
  862. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  863. {
  864. DPF(8, "Recieved DeletePlayerFromGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  865. return DPERR_INVALIDGROUP;
  866. }
  867. // Now make sure the player is in our map table. If it's not,
  868. // we should just ignore this message because it's for a
  869. // player we don't know about.
  870. if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
  871. {
  872. DPF(8, "Recieved DeletePlayerFromGroup message for unknown player, dwPlayerID = %lu, discarding message", lpd->dwGroupID);
  873. return DPERR_INVALIDPLAYER;
  874. }
  875. // Take the lock
  876. ENTER_DPLAY();
  877. // Call dplay's internal removeplayerfromgroup to remove the attachment
  878. // in the nametable
  879. hr = InternalDeletePlayerFromGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  880. lpd->dwGroupID, lpd->dwPlayerID, FALSE);
  881. if(FAILED(hr))
  882. {
  883. DPF_ERRVAL("Failed removing player from group, hr = 0x%08x", hr);
  884. goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
  885. }
  886. // If the fPropagate flag is not set, we don't want to send this message
  887. if(fPropagate)
  888. {
  889. // Now build the system message (at least the parts we need)
  890. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  891. SET_MESSAGE_HDR(&msg);
  892. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEPLAYERFROMGROUP);
  893. msg.dwPlayerID = lpd->dwPlayerID;
  894. msg.dwGroupID = lpd->dwGroupID;
  895. // Find dplay's internal group struct for the To group
  896. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  897. if(!lpGroupTo)
  898. {
  899. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  900. hr = DPERR_INVALIDGROUP;
  901. goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
  902. }
  903. // Call dplay's DistributeGroupMessage function to put the message
  904. // in the queues of all the appropriate players
  905. DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  906. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  907. if(FAILED(hr))
  908. {
  909. DPF(8, "Failed adding DeletePlayerFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  910. }
  911. }
  912. // Get dplay's internal group & player structures
  913. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
  914. if(!lpPlayer)
  915. {
  916. // So if this fails, the above call to InternalDeletePlayerFromGroup
  917. // shouldn't have succeeded either
  918. DPF_ERR("Unable to find player in nametable");
  919. ASSERT(FALSE);
  920. goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
  921. }
  922. // Now we need to decide if this is the last group this player was in. If
  923. // it is, then we need to destroy the player as well, and remove them from
  924. // our map table. Of course, only destroy the player if it is a remote player.
  925. if((!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)) &&
  926. (!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERINGROUP)))
  927. {
  928. // However, before we do this, we need to send a DestroyPlayer
  929. // message to all the people who got the DeletePlayerFromGroup
  930. if(lpGroupTo && fPropagate)
  931. {
  932. // Now build the system message (at least the parts we need)
  933. memset(&dpmsg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  934. SET_MESSAGE_HDR(&dpmsg);
  935. SET_MESSAGE_COMMAND(&dpmsg, DPSP_MSG_DELETEPLAYER);
  936. dpmsg.dwPlayerID = lpd->dwPlayerID;
  937. // Call dplay's DistributeGroupMessage function to put the message
  938. // in the queues of all the appropriate players
  939. DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  940. (LPBYTE)&dpmsg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  941. if(FAILED(hr))
  942. {
  943. DPF(8, "Failed adding DestroyPlayer message to player's receive queue from lobby, hr = 0x%08x", hr);
  944. }
  945. }
  946. // Destroy the player and remove it from the nametable
  947. InternalDestroyPlayer(this->lpDPlayObject, lpPlayer, FALSE, FALSE);
  948. }
  949. ERROR_DPLP_DELETEPLAYERFROMGROUP:
  950. // Drop the lock
  951. LEAVE_DPLAY();
  952. return hr;
  953. } // PRV_DeleteRemotePlayerFromGroup
  954. #undef DPF_MODNAME
  955. #define DPF_MODNAME "DPLP_DeletePlayerFromGroup"
  956. HRESULT DPLAPI DPLP_DeletePlayerFromGroup(LPDPLOBBYSP lpILP,
  957. LPSPDATA_DELETEREMOTEPLAYERFROMGROUP lpd)
  958. {
  959. LPDPLOBBYI_DPLOBJECT this;
  960. HRESULT hr = DP_OK;
  961. DPF(7, "Entering DPLP_DeletePlayerFromGroup");
  962. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  963. ENTER_DPLOBBY();
  964. // Make sure the LP doesn't throw us a curve
  965. TRY
  966. {
  967. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  968. if( !VALID_DPLOBBY_PTR( this ) )
  969. {
  970. LEAVE_DPLOBBY();
  971. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  972. return DPERR_INVALIDOBJECT;
  973. }
  974. // Validate the struct pointer
  975. if(!lpd)
  976. {
  977. LEAVE_DPLOBBY();
  978. DPF_ERR("SPDATA_DELETEREMOTEPLAYERFROMGROUP structure pointer cannot be NULL");
  979. return DPERR_INVALIDPARAMS;
  980. }
  981. }
  982. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  983. {
  984. LEAVE_DPLOBBY();
  985. DPF_ERR( "Exception encountered validating parameters" );
  986. return DPERR_INVALIDPARAMS;
  987. }
  988. // Call our internal routine, setting the propagate flag to TRUE so that
  989. // we post the appropriate message in the player's receive queue
  990. hr = PRV_DeleteRemotePlayerFromGroup(this, lpd, TRUE);
  991. LEAVE_DPLOBBY();
  992. return hr;
  993. } // DPLP_DeletePlayerFromGroup
  994. #undef DPF_MODNAME
  995. #define DPF_MODNAME "PRV_BroadcastDestroyGroupMessage"
  996. HRESULT DPLAPI PRV_BroadcastDestroyGroupMessage(LPDPLOBBYI_DPLOBJECT this,
  997. DWORD dwGroupID)
  998. {
  999. MSG_PLAYERMGMTMESSAGE msg;
  1000. LPDPLAYI_GROUP lpGroupTo = NULL;
  1001. HRESULT hr;
  1002. // Now build the system message (at least the parts we need)
  1003. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  1004. SET_MESSAGE_HDR(&msg);
  1005. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUP);
  1006. msg.dwGroupID = dwGroupID;
  1007. // Find dplay's internal group struct for the To group
  1008. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  1009. if(!lpGroupTo)
  1010. {
  1011. DPF_ERR("Unable to find system group in nametable");
  1012. hr = DPERR_INVALIDGROUP;
  1013. }
  1014. else
  1015. {
  1016. // Call dplay's DistributeGroupMessage function to put the message in the queue
  1017. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  1018. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  1019. if(FAILED(hr))
  1020. {
  1021. DPF(8, "Failed adding DestroyGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  1022. }
  1023. }
  1024. return hr;
  1025. } // PRV_BroadcastDestroyGroupMessage
  1026. #undef DPF_MODNAME
  1027. #define DPF_MODNAME "PRV_RemoveSubgroupsAndPlayersFromGroup"
  1028. void PRV_RemoveSubgroupsAndPlayersFromGroup(LPDPLOBBYI_DPLOBJECT this,
  1029. LPDPLAYI_GROUP lpGroup, DWORD dwGroupID, BOOL bRemoteOnly)
  1030. {
  1031. SPDATA_DELETEREMOTEPLAYERFROMGROUP dpd;
  1032. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  1033. LPDPLAYI_GROUPNODE lpNextGroupnode = NULL;
  1034. HRESULT hr = DP_OK;
  1035. DPF(7, "Entering PRV_RemoveSubgroupsAndPlayersFromGroup");
  1036. DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
  1037. ASSERT(lpGroup);
  1038. // Destroy any subgroups hanging off of this group
  1039. PRV_DestroySubgroups(this, lpGroup, bRemoteOnly);
  1040. // Walk the list of nodes, removing each player from the group manually.
  1041. // The reason for doing this manually is so that the lobby gets a chance
  1042. // to remove every remote player out of the nametable whose only existence
  1043. // was inside this room. It also allows the lobby to remove the player's
  1044. // ID from the map table. Do this by calling the lobby's
  1045. // DPLP_DeletePlayerFromGroup function which responds to that message.
  1046. // Setup the DeletePlayerFromGroup data structure
  1047. memset(&dpd, 0, sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP));
  1048. dpd.dwSize = sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP);
  1049. dpd.dwGroupID = dwGroupID;
  1050. // Walk the list of groupnodes, deleting all of the remote players
  1051. lpGroupnode = lpGroup->pGroupnodes;
  1052. while(lpGroupnode)
  1053. {
  1054. // Save the next groupnode
  1055. lpNextGroupnode = lpGroupnode->pNextGroupnode;
  1056. // If the player is local, skip them
  1057. if(lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)
  1058. {
  1059. lpGroupnode = lpNextGroupnode;
  1060. continue;
  1061. }
  1062. // Get the lobby ID for the player
  1063. dpd.dwPlayerID = lpGroup->pGroupnodes->pPlayer->dwID;
  1064. // Now call the lobby's delete function, setting the fPropagate flag
  1065. // to true so we put a delete message in the player's queue
  1066. hr = PRV_DeleteRemotePlayerFromGroup(this, &dpd, TRUE);
  1067. if(FAILED(hr))
  1068. {
  1069. // Same here, if this fails, something is tragically wrong
  1070. // with the map table, so just continue;
  1071. ASSERT(FALSE);
  1072. break;
  1073. }
  1074. // Move to the next node
  1075. lpGroupnode = lpNextGroupnode;
  1076. }
  1077. } // PRV_RemoveSubgroupsAndPlayersFromGroup
  1078. #undef DPF_MODNAME
  1079. #define DPF_MODNAME "PRV_SendDeleteShortcutMessageForExitingGroup"
  1080. void PRV_SendDeleteShortcutMessageForExitingGroup(LPDPLOBBYI_DPLOBJECT this,
  1081. LPDPLAYI_GROUP lpGroup)
  1082. {
  1083. MSG_PLAYERMGMTMESSAGE msg;
  1084. LPDPLAYI_GROUP lpGroupTo = NULL;
  1085. LPDPLAYI_GROUP lpGroupTemp = NULL;
  1086. LPDPLAYI_SUBGROUP lpSubgroupTemp = NULL;
  1087. UINT nGroupsIn;
  1088. HRESULT hr;
  1089. DPF(7, "Entering PRV_SendDeleteShortcutMessageForExitingGroup");
  1090. DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
  1091. // Take the dplay lock since we will be walking dplay's group list
  1092. ENTER_DPLAY();
  1093. // Get the number of subgroups this group is in
  1094. nGroupsIn = lpGroup->nGroups;
  1095. // Setup the static parts of the message, and get a pointer to the system group
  1096. if(nGroupsIn)
  1097. {
  1098. // Build the message struct
  1099. memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
  1100. SET_MESSAGE_HDR(&msg);
  1101. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
  1102. msg.dwPlayerID = lpGroup->dwID;
  1103. // Get a pointer to the system group
  1104. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  1105. if(!lpGroupTo)
  1106. {
  1107. LEAVE_DPLAY();
  1108. DPF_ERR("Unable to get a pointer to the system group - not sending deletegroupfromgroup messages");
  1109. return;
  1110. }
  1111. }
  1112. // Walk the list of groups, and send a DeleteGroupFromGroup message
  1113. // for each shortcut
  1114. lpGroupTemp = this->lpDPlayObject->pGroups;
  1115. while(nGroupsIn && lpGroupTemp)
  1116. {
  1117. // Walk the list of subgroups for the group
  1118. lpSubgroupTemp = lpGroupTemp->pSubgroups;
  1119. while(nGroupsIn && lpSubgroupTemp)
  1120. {
  1121. // If the group is our group, send a message, but only if
  1122. // it is not the parent group (since we will never do a
  1123. // DeleteGroupFromGroup on a parent-child)
  1124. if(lpSubgroupTemp->pGroup == lpGroup)
  1125. {
  1126. // Make sure it's not the group's parent
  1127. if(lpGroup->dwIDParent != lpGroupTemp->dwID)
  1128. {
  1129. // Send the message
  1130. msg.dwGroupID = lpGroupTemp->dwID;
  1131. // Call dplay's DistributeGroupMessage function to put the message
  1132. // in the queues of all the appropriate players
  1133. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  1134. (LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
  1135. if(FAILED(hr))
  1136. {
  1137. DPF(8, "Failed adding DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
  1138. }
  1139. }
  1140. // Decrement the count of subgroups
  1141. nGroupsIn--;
  1142. }
  1143. // Move to the next subgroup
  1144. lpSubgroupTemp = lpSubgroupTemp->pNextSubgroup;
  1145. }
  1146. // Move to the next group
  1147. lpGroupTemp = lpGroupTemp->pNextGroup;
  1148. }
  1149. ASSERT(!nGroupsIn);
  1150. // Drop the dplay lock since we're done
  1151. LEAVE_DPLAY();
  1152. } // PRV_SendDeleteShortcutMessageForExitingGroup
  1153. #undef DPF_MODNAME
  1154. #define DPF_MODNAME "DPLP_DestroyGroup"
  1155. HRESULT DPLAPI DPLP_DestroyGroup(LPDPLOBBYSP lpILP,
  1156. LPSPDATA_DESTROYREMOTEGROUP lpd)
  1157. {
  1158. LPDPLOBBYI_DPLOBJECT this;
  1159. HRESULT hr = DP_OK;
  1160. LPDPLAYI_GROUP lpGroup = NULL;
  1161. LPDPLAYI_GROUPNODE lpGroupNode = NULL;
  1162. DPF(7, "Entering DPLP_DestroyGroup");
  1163. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1164. ENTER_DPLOBBY();
  1165. // Make sure the LP doesn't throw us a curve
  1166. TRY
  1167. {
  1168. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1169. if( !VALID_DPLOBBY_PTR( this ) )
  1170. {
  1171. LEAVE_DPLOBBY();
  1172. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1173. return DPERR_INVALIDOBJECT;
  1174. }
  1175. // Validate the struct pointer
  1176. if(!lpd)
  1177. {
  1178. LEAVE_DPLOBBY();
  1179. DPF_ERR("SPDATA_DESTROYGROUP structure pointer cannot be NULL");
  1180. return DPERR_INVALIDPARAMS;
  1181. }
  1182. }
  1183. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1184. {
  1185. LEAVE_DPLOBBY();
  1186. DPF_ERR( "Exception encountered validating parameters" );
  1187. return DPERR_INVALIDPARAMS;
  1188. }
  1189. // First see if the group is in our map table. If it's not,
  1190. // we should just ignore this message because it's for a
  1191. // group we are not currently in.
  1192. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  1193. {
  1194. LEAVE_DPLOBBY();
  1195. DPF(8, "Recieved DestroyGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  1196. return DPERR_INVALIDGROUP;
  1197. }
  1198. // This is either a group we are in, or it is a root group. If it has
  1199. // any players, it's a group we are in, so we need to delete all remote
  1200. // players from the nametable and map table (if this is the only group
  1201. // they are in).
  1202. // Take the lock
  1203. ENTER_DPLAY();
  1204. // So, get dplay's internal group structure
  1205. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  1206. if(!lpGroup)
  1207. {
  1208. // If we don't have an lpGroup, we need to fail because some of
  1209. // the functions below will crash if lpGroup is invalid.
  1210. DPF(8, "Unable to find group in nametable, dpidGroup = %lu", lpd->dwGroupID);
  1211. LEAVE_LOBBY_ALL();
  1212. return DPERR_INVALIDGROUP;
  1213. }
  1214. // Send messages to remove shortcuts to this group (since dplay won't
  1215. // do it for us)
  1216. PRV_SendDeleteShortcutMessageForExitingGroup(this, lpGroup);
  1217. // Destroy all the remote subgroups and players
  1218. PRV_RemoveSubgroupsAndPlayersFromGroup(this, lpGroup, lpd->dwGroupID, FALSE);
  1219. // Now send a DestroyGroup system message to all the local players
  1220. hr = PRV_BroadcastDestroyGroupMessage(this, lpd->dwGroupID);
  1221. // Now call dplay's destroy group
  1222. hr = InternalDestroyGroup(this->lpDPlayObject, lpGroup, FALSE);
  1223. if(FAILED(hr))
  1224. {
  1225. DPF(8, "Failed destroying group from nametable, hr = 0x%08x", hr);
  1226. }
  1227. // Drop the locks
  1228. LEAVE_LOBBY_ALL();
  1229. return hr;
  1230. } // DPLP_DestroyGroup
  1231. #undef DPF_MODNAME
  1232. #define DPF_MODNAME "DPLP_GetSPDataPointer"
  1233. HRESULT DPLAPI DPLP_GetSPDataPointer(LPDPLOBBYSP lpDPLSP, LPVOID * lplpData)
  1234. {
  1235. LPDPLOBBYI_DPLOBJECT this;
  1236. // Make sure the SP doesn't throw us a curve
  1237. TRY
  1238. {
  1239. this = DPLOBJECT_FROM_INTERFACE(lpDPLSP);
  1240. if( !VALID_DPLOBBY_PTR( this ) )
  1241. {
  1242. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1243. return DPERR_INVALIDOBJECT;
  1244. }
  1245. }
  1246. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1247. {
  1248. DPF_ERR( "Exception encountered validating parameters" );
  1249. return DPERR_INVALIDPARAMS;
  1250. }
  1251. // Go ahead and save the pointer
  1252. *lplpData = this->lpSPData;
  1253. return DP_OK;
  1254. } // DPLP_GetSPDataPointer
  1255. #undef DPF_MODNAME
  1256. #define DPF_MODNAME "PRV_HandleLobbySystemMessage"
  1257. HRESULT PRV_HandleLobbySystemMessage(LPDPLOBBYI_DPLOBJECT this,
  1258. LPSPDATA_HANDLEMESSAGE lpd)
  1259. {
  1260. LPDPLMSG_GENERIC lpmsg = lpd->lpBuffer;
  1261. LPDPLMSG_GETPROPERTYRESPONSE lpgpr = NULL;
  1262. LPDPLOBBYI_REQUESTNODE lprn = NULL;
  1263. HRESULT hr = DP_OK;
  1264. // If it's a property message, we need to deal with the request
  1265. switch(lpmsg->dwType)
  1266. {
  1267. case DPLSYS_GETPROPERTYRESPONSE:
  1268. case DPLSYS_SETPROPERTYRESPONSE:
  1269. {
  1270. // Cast it to a GetPropertyResponse message
  1271. lpgpr = (LPDPLMSG_GETPROPERTYRESPONSE)lpmsg;
  1272. // Find the request ID in our list of pending requests
  1273. lprn = this->lprnHead;
  1274. while(lprn)
  1275. {
  1276. if(lprn->dwRequestID == lpgpr->dwRequestID)
  1277. break;
  1278. else
  1279. lprn = lprn->lpNext;
  1280. }
  1281. // Print some debug spew if we didn't find it, but return DP_OK since
  1282. // we "handled" the message
  1283. if(!lprn)
  1284. {
  1285. DPF(5, "Unable to find request ID in pending request list");
  1286. return DP_OK;
  1287. }
  1288. // See if we slammed the guid, and replace it with GUID_NULL if we did
  1289. if(lprn->dwFlags & GN_SLAMMED_GUID)
  1290. lpgpr->guidPlayer = GUID_NULL;
  1291. // If we found it, swap out the request ID, and send it to the
  1292. // appropriate place
  1293. lpgpr->dwRequestID = lprn->dwAppRequestID;
  1294. if(lprn->dwFlags & GN_SELF_LOBBIED)
  1295. {
  1296. // Put the message in the lobby message receive queue
  1297. hr = PRV_InjectMessageInQueue(lprn->lpgn, DPLMSG_STANDARD,
  1298. lpgpr, lpd->dwBufSize, FALSE);
  1299. if(FAILED(hr))
  1300. {
  1301. DPF_ERRVAL("Failed to put message in lobby receive queue, hr = 0x%08x", hr);
  1302. goto EXIT_HANDLELOBBYSYSTEMMESSAGE;
  1303. }
  1304. }
  1305. else
  1306. {
  1307. // Call SendLobbyMessage to send the message to the game
  1308. hr = PRV_WriteClientData(lprn->lpgn, DPLMSG_STANDARD,
  1309. lpgpr, lpd->dwBufSize);
  1310. if(FAILED(hr))
  1311. {
  1312. DPF_ERRVAL("Failed to forward message to game, hr = 0x%08x", hr);
  1313. goto EXIT_HANDLELOBBYSYSTEMMESSAGE;
  1314. }
  1315. }
  1316. break;
  1317. }
  1318. default:
  1319. break;
  1320. }
  1321. EXIT_HANDLELOBBYSYSTEMMESSAGE:
  1322. // Remove the pending request node if we serviced it (which would have
  1323. // happened if we have a valid pointer to it)
  1324. if(lprn)
  1325. PRV_RemoveRequestNode(this, lprn);
  1326. return hr;
  1327. } // PRV_HandleLobbySystemMessage
  1328. #undef DPF_MODNAME
  1329. #define DPF_MODNAME "DPLP_HandleMessage"
  1330. HRESULT DPLAPI DPLP_HandleMessage(LPDPLOBBYSP lpILP,
  1331. LPSPDATA_HANDLEMESSAGE lpd)
  1332. {
  1333. LPDPLOBBYI_DPLOBJECT this;
  1334. HRESULT hr = DP_OK;
  1335. LPMSG_PLAYERMESSAGE lpmsg = NULL;
  1336. LPBYTE lpByte = NULL;
  1337. DWORD dwSize;
  1338. BOOL bAllocBuffer = FALSE;
  1339. LPDPLAYI_PLAYER lpPlayer = NULL;
  1340. DPF(7, "Entering DPLP_HandleMessage");
  1341. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1342. ENTER_DPLOBBY();
  1343. // Make sure the LP doesn't throw us a curve
  1344. TRY
  1345. {
  1346. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1347. if( !VALID_DPLOBBY_PTR( this ) )
  1348. {
  1349. LEAVE_DPLOBBY();
  1350. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1351. return DPERR_INVALIDOBJECT;
  1352. }
  1353. // Validate the struct pointer
  1354. if(!lpd)
  1355. {
  1356. LEAVE_DPLOBBY();
  1357. DPF_ERR("SPDATA_HANDLEMESSAGE structure pointer cannot be NULL");
  1358. return DPERR_INVALIDPARAMS;
  1359. }
  1360. }
  1361. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1362. {
  1363. LEAVE_DPLOBBY();
  1364. DPF_ERR( "Exception encountered validating parameters" );
  1365. return DPERR_INVALIDPARAMS;
  1366. }
  1367. // If the message is a lobby system message, process it
  1368. // NOTE: Make sure the size of the SPDATA_HANDLEMESSAGE is big enough
  1369. // to contain a flags field (the shipping 5.0 bits did not have
  1370. // this field, but the 5.1 bits did).
  1371. if((lpd->dwSize > DPLOBBYPR_SIZE_HANDLEMESSAGE_DX50) &&
  1372. (lpd->dwFlags & DPSEND_LOBBYSYSTEMMESSAGE))
  1373. {
  1374. hr = PRV_HandleLobbySystemMessage(this, lpd);
  1375. if(FAILED(hr))
  1376. {
  1377. DPF_ERRVAL("Unable to handle lobby system message, hr = 0x%08x", hr);
  1378. }
  1379. LEAVE_DPLOBBY();
  1380. return hr;
  1381. }
  1382. // REVIEW!!!! -- We should be able to handle a generic send to a group
  1383. // as well as a player. Currently, I don't think we do.
  1384. // If this session is using naked messages, we can just send the buffer.
  1385. // Otherwise, we need to allocate a MSG_PLAYERMESSAGE struct and fill
  1386. // in the header.
  1387. if(this->lpDPlayObject->lpsdDesc->dwFlags & DPSESSION_NOMESSAGEID)
  1388. {
  1389. lpmsg = lpd->lpBuffer;
  1390. dwSize = lpd->dwBufSize;
  1391. }
  1392. else
  1393. {
  1394. // Calculate the size of the message
  1395. dwSize = sizeof(MSG_PLAYERMESSAGE) + lpd->dwBufSize;
  1396. // Allocate memory for a message buffer
  1397. lpmsg = DPMEM_ALLOC(dwSize);
  1398. if(!lpmsg)
  1399. {
  1400. DPF_ERR("Unable to allocate temporary message buffer");
  1401. hr = DPERR_OUTOFMEMORY;
  1402. goto ERROR_DPLP_HANDLEMESSAGE;
  1403. }
  1404. // Copy in the message header
  1405. lpmsg->idFrom = lpd->dwFromID;
  1406. lpmsg->idTo = lpd->dwToID;
  1407. // Copy in the message
  1408. lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERMESSAGE);
  1409. memcpy(lpByte, lpd->lpBuffer, lpd->dwBufSize);
  1410. // Set our flag indicating that we allocated a buffer
  1411. bAllocBuffer = TRUE;
  1412. }
  1413. // Take the lock
  1414. ENTER_DPLAY();
  1415. // Find dplay's internal player struct for the To player
  1416. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwToID);
  1417. if(!lpPlayer)
  1418. {
  1419. LEAVE_DPLAY();
  1420. DPF_ERRVAL("Unable to find player in nametable, hr = 0x%08x", hr);
  1421. hr = DPERR_INVALIDPLAYER;
  1422. goto ERROR_DPLP_HANDLEMESSAGE;
  1423. }
  1424. // Call dplay's handleplayermessage function to put the message in the queue
  1425. hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg, dwSize, TRUE, 0);
  1426. if(FAILED(hr))
  1427. {
  1428. DPF(8, "Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
  1429. }
  1430. // Drop the lock
  1431. LEAVE_DPLAY();
  1432. ERROR_DPLP_HANDLEMESSAGE:
  1433. if(bAllocBuffer && lpmsg)
  1434. DPMEM_FREE(lpmsg);
  1435. LEAVE_DPLOBBY();
  1436. return hr;
  1437. } // DPLP_HandleMessage
  1438. #undef DPF_MODNAME
  1439. #define DPF_MODNAME "DPLP_SendChatMessage"
  1440. HRESULT DPLAPI DPLP_SendChatMessage(LPDPLOBBYSP lpILP,
  1441. LPSPDATA_CHATMESSAGE lpd)
  1442. {
  1443. LPDPLOBBYI_DPLOBJECT this;
  1444. HRESULT hr = DP_OK;
  1445. LPMSG_CHAT lpmsg = NULL;
  1446. LPBYTE lpByte = NULL;
  1447. DWORD dwSize;
  1448. LPDPLAYI_PLAYER lpPlayer = NULL;
  1449. LPDPLAYI_GROUP lpGroup = NULL;
  1450. DWORD dwStringSize;
  1451. BOOL bToGroup = FALSE;
  1452. DPF(7, "Entering DPLP_SendChatMessage");
  1453. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1454. ENTER_DPLOBBY();
  1455. // Make sure the LP doesn't throw us a curve
  1456. TRY
  1457. {
  1458. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1459. if( !VALID_DPLOBBY_PTR( this ) )
  1460. {
  1461. LEAVE_DPLOBBY();
  1462. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1463. return DPERR_INVALIDOBJECT;
  1464. }
  1465. // Validate the struct pointer
  1466. if(!lpd)
  1467. {
  1468. LEAVE_DPLOBBY();
  1469. DPF_ERR("SPDATA_HANDLEMESSAGE structure pointer cannot be NULL");
  1470. return DPERR_INVALIDPARAMS;
  1471. }
  1472. }
  1473. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1474. {
  1475. LEAVE_DPLOBBY();
  1476. DPF_ERR( "Exception encountered validating parameters" );
  1477. return DPERR_INVALIDPARAMS;
  1478. }
  1479. // Calculate the size of the message
  1480. dwStringSize = WSTRLEN_BYTES(lpd->lpChat->lpszMessage);
  1481. dwSize = sizeof(MSG_CHAT) + dwStringSize;
  1482. // Allocate memory for a message buffer
  1483. lpmsg = DPMEM_ALLOC(dwSize);
  1484. if(!lpmsg)
  1485. {
  1486. DPF_ERR("Unable to allocate temporary message buffer");
  1487. hr = DPERR_OUTOFMEMORY;
  1488. goto ERROR_DPLP_SENDCHATMESSAGE;
  1489. }
  1490. // Copy in the message header
  1491. SET_MESSAGE_HDR(lpmsg);
  1492. SET_MESSAGE_COMMAND(lpmsg,DPSP_MSG_CHAT);
  1493. lpmsg->dwIDFrom = lpd->dwFromID;
  1494. lpmsg->dwIDTo = lpd->dwToID;
  1495. lpmsg->dwFlags = lpd->lpChat->dwFlags;
  1496. lpmsg->dwMessageOffset = sizeof(MSG_CHAT);
  1497. // Copy in the message
  1498. lpByte = (LPBYTE)lpmsg + sizeof(MSG_CHAT);
  1499. memcpy(lpByte, lpd->lpChat->lpszMessage, dwStringSize);
  1500. // Take the lock
  1501. ENTER_DPLAY();
  1502. // Make sure it's from a valid player or the server player
  1503. if(lpd->dwFromID != DPID_SERVERPLAYER)
  1504. {
  1505. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwFromID);
  1506. if(!VALID_DPLAY_PLAYER(lpPlayer))
  1507. {
  1508. LEAVE_DPLAY();
  1509. DPF_ERR("Received chat message FROM invalid player id!!");
  1510. hr = DPERR_INVALIDPLAYER;
  1511. goto ERROR_DPLP_SENDCHATMESSAGE;
  1512. }
  1513. }
  1514. // See who the message is for
  1515. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwToID);
  1516. if(!VALID_DPLAY_PLAYER(lpPlayer))
  1517. {
  1518. // See if it's to a group
  1519. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwToID);
  1520. if(!VALID_DPLAY_GROUP(lpGroup))
  1521. {
  1522. LEAVE_DPLAY();
  1523. DPF_ERR("Received chat message for invalid player / group");
  1524. hr = DPERR_INVALIDPLAYER;
  1525. goto ERROR_DPLP_SENDCHATMESSAGE;
  1526. }
  1527. bToGroup = TRUE;
  1528. }
  1529. // Send it out
  1530. if(bToGroup)
  1531. {
  1532. // Send the message
  1533. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroup,
  1534. (LPBYTE)lpmsg, dwSize, FALSE, 0);
  1535. }
  1536. else
  1537. {
  1538. // Send the message
  1539. hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg, dwSize, FALSE, 0);
  1540. }
  1541. // Drop the lock
  1542. LEAVE_DPLAY();
  1543. ERROR_DPLP_SENDCHATMESSAGE:
  1544. if(lpmsg)
  1545. DPMEM_FREE(lpmsg);
  1546. LEAVE_DPLOBBY();
  1547. return hr;
  1548. } // DPLP_SendChatMessage
  1549. #undef DPF_MODNAME
  1550. #define DPF_MODNAME "PRV_SendDataChangedMessageLocally"
  1551. HRESULT PRV_SendDataChangedMessageLocally(LPDPLOBBYI_DPLOBJECT this,
  1552. DPID dpidPlayer, LPVOID lpData, DWORD dwDataSize)
  1553. {
  1554. LPDPLAYI_GROUP lpGroupTo = NULL;
  1555. HRESULT hr = DP_OK;
  1556. LPMSG_PLAYERDATA lpmsg = NULL;
  1557. LPBYTE lpByte = NULL;
  1558. DWORD dwSize;
  1559. DPF(7, "Entering PRV_SendDataChangedMessageLocally");
  1560. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu",
  1561. this, dpidPlayer, lpData, dwDataSize);
  1562. // Take the lock
  1563. ENTER_DPLAY();
  1564. // Setup the message to put in the player's queue
  1565. // Calculate the size of the message
  1566. dwSize = sizeof(MSG_PLAYERDATA) + dwDataSize;
  1567. // Allocate memory for the message
  1568. lpmsg = DPMEM_ALLOC(dwSize);
  1569. if(!lpmsg)
  1570. {
  1571. DPF_ERR("Unable to allocate memory for temporary message structure");
  1572. // Since the name has been changed, we'll just return success here
  1573. hr = DP_OK;
  1574. goto EXIT_SENDDATACHANGED;
  1575. }
  1576. // Now build the system message
  1577. SET_MESSAGE_HDR(lpmsg);
  1578. SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_PLAYERDATACHANGED);
  1579. lpmsg->dwPlayerID = dpidPlayer;
  1580. lpmsg->dwDataSize = dwDataSize;
  1581. lpmsg->dwDataOffset = sizeof(MSG_PLAYERDATA);
  1582. // Copy in the data
  1583. lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERDATA);
  1584. memcpy(lpByte, lpData, dwDataSize);
  1585. // Find dplay's internal group struct for the To group
  1586. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  1587. if(!lpGroupTo)
  1588. {
  1589. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  1590. hr = DPERR_INVALIDGROUP;
  1591. goto EXIT_SENDDATACHANGED;
  1592. }
  1593. // Call dplay's DistributeGroupMessage function to put the message
  1594. // in the queues of all the appropriate players
  1595. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  1596. (LPBYTE)lpmsg, dwSize, FALSE, 0);
  1597. if(FAILED(hr))
  1598. {
  1599. DPF(8, "Failed adding SetGroupData message to player's receive queue from lobby, hr = 0x%08x", hr);
  1600. }
  1601. EXIT_SENDDATACHANGED:
  1602. // Free our message
  1603. if(lpmsg)
  1604. DPMEM_FREE(lpmsg);
  1605. // Drop the lock
  1606. LEAVE_DPLAY();
  1607. return hr;
  1608. } // PRV_SendDataChangedMessageLocally
  1609. #undef DPF_MODNAME
  1610. #define DPF_MODNAME "PRV_SendNameChangedMessageLocally"
  1611. HRESULT PRV_SendNameChangedMessageLocally(LPDPLOBBYI_DPLOBJECT this,
  1612. DPID dpidPlayer, LPDPNAME lpName, BOOL bPlayer)
  1613. {
  1614. LPDPLAYI_GROUP lpGroupTo = NULL;
  1615. HRESULT hr = DP_OK;
  1616. LPMSG_PLAYERNAME lpmsg = NULL;
  1617. DWORD dwSize, dwShortSize = 0, dwLongSize = 0;
  1618. LPBYTE lpByte = NULL;
  1619. DPF(7, "Entering PRV_SendNameChangedMessageLocally");
  1620. DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
  1621. this, dpidPlayer, lpName, bPlayer);
  1622. // Take the lock
  1623. ENTER_DPLAY();
  1624. // Setup the message to put in the player's queue
  1625. // Calculate the size of the message
  1626. if(lpName->lpszShortName)
  1627. dwShortSize = WSTRLEN_BYTES(lpName->lpszShortName);
  1628. if(lpName->lpszLongName)
  1629. dwLongSize = WSTRLEN_BYTES(lpName->lpszLongName);
  1630. dwSize = sizeof(MSG_PLAYERNAME) + dwShortSize + dwLongSize;
  1631. // Allocate memory for the message
  1632. lpmsg = DPMEM_ALLOC(dwSize);
  1633. if(!lpmsg)
  1634. {
  1635. DPF_ERR("Unable to allocate memory for temporary message structure");
  1636. // Since the name has been changed, we'll just return success here
  1637. hr = DP_OK;
  1638. goto EXIT_SENDNAMECHANGED;
  1639. }
  1640. // Now build the system message
  1641. SET_MESSAGE_HDR(lpmsg);
  1642. if(bPlayer)
  1643. SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_PLAYERNAMECHANGED);
  1644. else
  1645. SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_GROUPNAMECHANGED);
  1646. lpmsg->dwPlayerID = dpidPlayer;
  1647. lpmsg->dwShortOffset = sizeof(MSG_PLAYERNAME);
  1648. lpmsg->dwLongOffset = sizeof(MSG_PLAYERNAME) + dwShortSize;
  1649. // Copy in the names
  1650. lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERNAME);
  1651. memcpy(lpByte, lpName->lpszShortName, dwShortSize);
  1652. lpByte += dwShortSize;
  1653. memcpy(lpByte, lpName->lpszLongName, dwLongSize);
  1654. // Find dplay's internal group struct for the To group
  1655. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  1656. if(!lpGroupTo)
  1657. {
  1658. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  1659. hr = DPERR_INVALIDGROUP;
  1660. goto EXIT_SENDNAMECHANGED;
  1661. }
  1662. // Call dplay's DistributeGroupMessage function to put the message
  1663. // in the queues of all the appropriate players
  1664. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  1665. (LPBYTE)lpmsg, dwSize, FALSE, 0);
  1666. if(FAILED(hr))
  1667. {
  1668. DPF(8, "Failed adding SetGroupName message to player's receive queue from lobby, hr = 0x%08x", hr);
  1669. }
  1670. EXIT_SENDNAMECHANGED:
  1671. // Free our message
  1672. if(lpmsg)
  1673. DPMEM_FREE(lpmsg);
  1674. // Drop the lock
  1675. LEAVE_DPLAY();
  1676. return hr;
  1677. } // PRV_SendNameChangedMessageLocally
  1678. #undef DPF_MODNAME
  1679. #define DPF_MODNAME "DPLP_SetGroupName"
  1680. HRESULT DPLAPI DPLP_SetGroupName(LPDPLOBBYSP lpILP,
  1681. LPSPDATA_SETREMOTEGROUPNAME lpd)
  1682. {
  1683. LPDPLOBBYI_DPLOBJECT this;
  1684. LPDPLAYI_GROUP lpGroup = NULL;
  1685. HRESULT hr = DP_OK;
  1686. DPF(7, "Entering DPLP_SetGroupName");
  1687. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1688. ENTER_DPLOBBY();
  1689. // Make sure the LP doesn't throw us a curve
  1690. TRY
  1691. {
  1692. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1693. if( !VALID_DPLOBBY_PTR( this ) )
  1694. {
  1695. LEAVE_DPLOBBY();
  1696. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1697. return DPERR_INVALIDOBJECT;
  1698. }
  1699. // Validate the struct pointer
  1700. if(!lpd)
  1701. {
  1702. LEAVE_DPLOBBY();
  1703. DPF_ERR("SPDATA_SETGROUPNAME structure pointer cannot be NULL");
  1704. return DPERR_INVALIDPARAMS;
  1705. }
  1706. }
  1707. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1708. {
  1709. LEAVE_DPLOBBY();
  1710. DPF_ERR( "Exception encountered validating parameters" );
  1711. return DPERR_INVALIDPARAMS;
  1712. }
  1713. // First see if the group is in our map table. If it is not,
  1714. // we should just ignore this message because it's for a
  1715. // group we don't know about.
  1716. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  1717. {
  1718. LEAVE_DPLOBBY();
  1719. DPF(8, "Recieved SetGroupName message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  1720. return DPERR_INVALIDGROUP;
  1721. }
  1722. // Take the lock
  1723. ENTER_DPLAY();
  1724. // See if the group is local or remote. If it's local, ignore this message
  1725. // and just return DP_OK becuase we've already sent this message locally.
  1726. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  1727. if((!lpGroup) || (lpGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  1728. {
  1729. hr = DP_OK;
  1730. goto ERROR_DPLP_SETGROUPNAME;
  1731. }
  1732. // Call dplay's internalsetname function to update the name in the cache
  1733. hr = InternalSetName((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  1734. lpd->dwGroupID, lpd->lpName, FALSE, lpd->dwFlags, FALSE);
  1735. if(FAILED(hr))
  1736. {
  1737. DPF(8, "Failed to SetGroupName internally for remote group, hr = 0x%08x", hr);
  1738. goto ERROR_DPLP_SETGROUPNAME;
  1739. }
  1740. // Send the message to all the local players
  1741. hr = PRV_SendNameChangedMessageLocally(this, lpd->dwGroupID, lpd->lpName, FALSE);
  1742. ERROR_DPLP_SETGROUPNAME:
  1743. // Drop the locks
  1744. LEAVE_LOBBY_ALL();
  1745. return hr;
  1746. } // DPLP_SetGroupName
  1747. #undef DPF_MODNAME
  1748. #define DPF_MODNAME "PRV_SendGroupOwnerMessageLocally"
  1749. HRESULT PRV_SendGroupOwnerMessageLocally(LPDPLOBBYI_DPLOBJECT this,
  1750. DPID dpidGroup, DPID dpidNewOwner, DPID dpidOldOwner)
  1751. {
  1752. LPDPLAYI_GROUP lpGroupTo = NULL;
  1753. HRESULT hr = DP_OK;
  1754. MSG_GROUPOWNERCHANGED msg;
  1755. DPF(7, "Entering PRV_SendGroupOwnerMessageLocally");
  1756. DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
  1757. this, dpidGroup, dpidNewOwner, dpidOldOwner);
  1758. // Take the lock
  1759. ENTER_DPLAY();
  1760. // Now build the system message
  1761. memset(&msg, 0, sizeof(MSG_GROUPOWNERCHANGED));
  1762. SET_MESSAGE_HDR(&msg);
  1763. SET_MESSAGE_COMMAND(&msg, DPSP_MSG_GROUPOWNERCHANGED);
  1764. msg.dwIDGroup = dpidGroup;
  1765. msg.dwIDNewOwner = dpidNewOwner;
  1766. msg.dwIDOldOwner = dpidOldOwner;
  1767. // Find dplay's internal group struct for the To group
  1768. lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
  1769. if(!lpGroupTo)
  1770. {
  1771. DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
  1772. hr = DPERR_INVALIDGROUP;
  1773. goto EXIT_SENDGROUPOWNER;
  1774. }
  1775. // Call dplay's DistributeGroupMessage function to put the message
  1776. // in the queues of all the appropriate players
  1777. hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
  1778. (LPBYTE)&msg, sizeof(MSG_GROUPOWNERCHANGED), FALSE, 0);
  1779. if(FAILED(hr))
  1780. {
  1781. DPF(8, "Failed adding SetGroupOwner message to player's receive queue from lobby, hr = 0x%08x", hr);
  1782. }
  1783. EXIT_SENDGROUPOWNER:
  1784. // Drop the lock
  1785. LEAVE_DPLAY();
  1786. return hr;
  1787. } // PRV_SendGroupOwnerMessageLocally
  1788. #undef DPF_MODNAME
  1789. #define DPF_MODNAME "DPLP_SetGroupOwner"
  1790. HRESULT DPLAPI DPLP_SetGroupOwner(LPDPLOBBYSP lpILP,
  1791. LPSPDATA_SETREMOTEGROUPOWNER lpd)
  1792. {
  1793. LPDPLOBBYI_DPLOBJECT this;
  1794. LPDPLAYI_GROUP lpGroup = NULL;
  1795. HRESULT hr = DP_OK;
  1796. DWORD dwOldOwnerID;
  1797. DPF(7, "Entering DPLP_SetGroupOwner");
  1798. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1799. ENTER_DPLOBBY();
  1800. // Make sure the LP doesn't throw us a curve
  1801. TRY
  1802. {
  1803. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1804. if( !VALID_DPLOBBY_PTR( this ) )
  1805. {
  1806. LEAVE_DPLOBBY();
  1807. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1808. return DPERR_INVALIDOBJECT;
  1809. }
  1810. // Validate the struct pointer
  1811. if(!lpd)
  1812. {
  1813. LEAVE_DPLOBBY();
  1814. DPF_ERR("SPDATA_SETGROUPNAME structure pointer cannot be NULL");
  1815. return DPERR_INVALIDPARAMS;
  1816. }
  1817. }
  1818. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1819. {
  1820. LEAVE_DPLOBBY();
  1821. DPF_ERR( "Exception encountered validating parameters" );
  1822. return DPERR_INVALIDPARAMS;
  1823. }
  1824. // First see if the group is in our map table. If it is not,
  1825. // we should just ignore this message because it's for a
  1826. // group we don't know about.
  1827. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  1828. {
  1829. LEAVE_DPLOBBY();
  1830. DPF(8, "Recieved SetGroupOwner message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  1831. return DPERR_INVALIDGROUP;
  1832. }
  1833. // Take the lock
  1834. ENTER_DPLAY();
  1835. // See if the group is local or remote. If it's local, ignore this message
  1836. // and just return DP_OK becuase we've already sent this message locally.
  1837. lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
  1838. if(!lpGroup)
  1839. {
  1840. hr = DP_OK;
  1841. goto ERROR_DPLP_SETGROUPOWNER;
  1842. }
  1843. // If the player is already the owner of the group, we don't need
  1844. // to do any processing (this is the buffer in case the server
  1845. // sends us duplicate messages for stuff we've already sent locally)
  1846. if(lpGroup->dwOwnerID == lpd->dwOwnerID)
  1847. {
  1848. hr = DP_OK;
  1849. goto ERROR_DPLP_SETGROUPOWNER;
  1850. }
  1851. // Make sure the old owner is in our map table, otherwise just set
  1852. // it to zero (the default)
  1853. dwOldOwnerID = lpGroup->dwOwnerID;
  1854. // Change the owner locally
  1855. lpGroup->dwOwnerID = lpd->dwOwnerID;
  1856. // Send a SetGroupOwner message locally
  1857. PRV_SendGroupOwnerMessageLocally(this, lpd->dwGroupID,
  1858. lpd->dwOwnerID, dwOldOwnerID);
  1859. ERROR_DPLP_SETGROUPOWNER:
  1860. // Drop the locks
  1861. LEAVE_LOBBY_ALL();
  1862. return hr;
  1863. } // DPLP_SetGroupOwner
  1864. #undef DPF_MODNAME
  1865. #define DPF_MODNAME "DPLP_SetPlayerName"
  1866. HRESULT DPLAPI DPLP_SetPlayerName(LPDPLOBBYSP lpILP,
  1867. LPSPDATA_SETREMOTEPLAYERNAME lpd)
  1868. {
  1869. LPDPLOBBYI_DPLOBJECT this;
  1870. HRESULT hr = DP_OK;
  1871. LPDPLAYI_PLAYER lpPlayer = NULL;
  1872. DPF(7, "Entering DPLP_SetPlayerName");
  1873. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1874. ENTER_DPLOBBY();
  1875. // Make sure the LP doesn't throw us a curve
  1876. TRY
  1877. {
  1878. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1879. if( !VALID_DPLOBBY_PTR( this ) )
  1880. {
  1881. LEAVE_DPLOBBY();
  1882. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1883. return DPERR_INVALIDOBJECT;
  1884. }
  1885. // Validate the struct pointer
  1886. if(!lpd)
  1887. {
  1888. LEAVE_DPLOBBY();
  1889. DPF_ERR("SPDATA_SETPLAYERNAME structure pointer cannot be NULL");
  1890. return DPERR_INVALIDPARAMS;
  1891. }
  1892. }
  1893. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1894. {
  1895. LEAVE_DPLOBBY();
  1896. DPF_ERR( "Exception encountered validating parameters" );
  1897. return DPERR_INVALIDPARAMS;
  1898. }
  1899. // First see if the player is in our map table. If it is not,
  1900. // we should just ignore this message because it's for a
  1901. // player we don't know about.
  1902. if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
  1903. {
  1904. LEAVE_DPLOBBY();
  1905. DPF(8, "Recieved SetPlayerName message for unknown player, dwPlayerID = %lu, discarding message", lpd->dwPlayerID);
  1906. return DPERR_INVALIDPLAYER;
  1907. }
  1908. // Take the lock
  1909. ENTER_DPLAY();
  1910. // See if the player is local or remote. If it's local, ignore this message
  1911. // and just return DP_OK becuase we've already sent this message locally.
  1912. lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
  1913. if((!lpPlayer) || (lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  1914. {
  1915. hr = DP_OK;
  1916. goto ERROR_DPLP_SETPLAYERNAME;
  1917. }
  1918. // Call dplay's internalsetname function to update the name in the cache
  1919. hr = InternalSetName((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
  1920. lpd->dwPlayerID, lpd->lpName, TRUE, lpd->dwFlags, FALSE);
  1921. if(FAILED(hr))
  1922. {
  1923. DPF(8, "Failed to SetPlayerName internally for remote group, hr = 0x%08x", hr);
  1924. goto ERROR_DPLP_SETPLAYERNAME;
  1925. }
  1926. // Send the message to all the local players
  1927. hr = PRV_SendNameChangedMessageLocally(this, lpd->dwPlayerID, lpd->lpName, TRUE);
  1928. ERROR_DPLP_SETPLAYERNAME:
  1929. // Drop the lock
  1930. LEAVE_LOBBY_ALL();
  1931. return hr;
  1932. } // DPLP_SetPlayerName
  1933. #undef DPF_MODNAME
  1934. #define DPF_MODNAME "DPLP_SetSessionDesc"
  1935. HRESULT DPLAPI DPLP_SetSessionDesc(LPDPLOBBYSP lpILP,
  1936. LPSPDATA_SETSESSIONDESC lpd)
  1937. {
  1938. LPDPLOBBYI_DPLOBJECT this;
  1939. HRESULT hr = DP_OK;
  1940. DPF(7, "Entering DPLP_SetSessionDesc");
  1941. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  1942. ENTER_DPLOBBY();
  1943. // Make sure the LP doesn't throw us a curve
  1944. TRY
  1945. {
  1946. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  1947. if( !VALID_DPLOBBY_PTR( this ) )
  1948. {
  1949. LEAVE_DPLOBBY();
  1950. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1951. return DPERR_INVALIDOBJECT;
  1952. }
  1953. // Validate the struct pointer
  1954. if(!lpd)
  1955. {
  1956. LEAVE_DPLOBBY();
  1957. DPF_ERR("SPDATA_SETSESSIONDESC structure pointer cannot be NULL");
  1958. return DPERR_INVALIDPARAMS;
  1959. }
  1960. }
  1961. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1962. {
  1963. LEAVE_DPLOBBY();
  1964. DPF_ERR( "Exception encountered validating parameters" );
  1965. return DPERR_INVALIDPARAMS;
  1966. }
  1967. LEAVE_DPLOBBY();
  1968. return hr;
  1969. } // DPLP_SetSessionDesc
  1970. #undef DPF_MODNAME
  1971. #define DPF_MODNAME "DPLP_SetSPDataPointer"
  1972. HRESULT DPLAPI DPLP_SetSPDataPointer(LPDPLOBBYSP lpDPLSP, LPVOID lpData)
  1973. {
  1974. LPDPLOBBYI_DPLOBJECT this;
  1975. // Make sure the SP doesn't throw us a curve
  1976. TRY
  1977. {
  1978. this = DPLOBJECT_FROM_INTERFACE(lpDPLSP);
  1979. if( !VALID_DPLOBBY_PTR( this ) )
  1980. {
  1981. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  1982. return DPERR_INVALIDOBJECT;
  1983. }
  1984. }
  1985. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1986. {
  1987. DPF_ERR( "Exception encountered validating parameters" );
  1988. return DPERR_INVALIDPARAMS;
  1989. }
  1990. // Go ahead and save the pointer
  1991. this->lpSPData = lpData;
  1992. return DP_OK;
  1993. } // DPLP_SetSPDataPointer
  1994. #undef DPF_MODNAME
  1995. #define DPF_MODNAME "PRV_BuildStartSessionMessage"
  1996. HRESULT PRV_BuildStartSessionMessage(LPVOID * lplpmsg, LPDWORD lpdwSize,
  1997. LPDPLCONNECTION lpConn, LPDPLAYI_PLAYER lpPlayer)
  1998. {
  1999. LPMSG_STARTSESSION lpmsg = NULL;
  2000. DWORD dwPackageSize;
  2001. DWORD dwSize;
  2002. LPBYTE lpTemp = NULL;
  2003. DPNAME dpn;
  2004. HRESULT hr;
  2005. // Setup a local DPNAME struct for the player if the names exist
  2006. if((lpPlayer->lpszShortName) || (lpPlayer->lpszLongName))
  2007. {
  2008. // Setup the struct
  2009. memset(&dpn, 0, sizeof(DPNAME));
  2010. dpn.dwSize = sizeof(DPNAME);
  2011. dpn.lpszShortName = lpPlayer->lpszShortName;
  2012. dpn.lpszLongName = lpPlayer->lpszLongName;
  2013. lpConn->lpPlayerName = &dpn;
  2014. }
  2015. else
  2016. {
  2017. // Make sure the PlayerName pointer is NULL
  2018. lpConn->lpPlayerName = NULL;
  2019. }
  2020. // Calculate the size of our message in Unicode
  2021. PRV_GetDPLCONNECTIONPackageSize(lpConn, &dwPackageSize, NULL);
  2022. dwSize = sizeof(MSG_STARTSESSION) + dwPackageSize -
  2023. sizeof(DPLOBBYI_PACKEDCONNHEADER);
  2024. // Allocate memory for the message
  2025. lpmsg = DPMEM_ALLOC(dwSize);
  2026. if(!lpmsg)
  2027. {
  2028. DPF_ERR("Unable to allocate memory for temporary message structure");
  2029. return DPERR_OUTOFMEMORY;
  2030. }
  2031. // Now build the system message
  2032. SET_MESSAGE_HDR(lpmsg);
  2033. SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_STARTSESSION);
  2034. // Set the DPLCONNECTION pointer
  2035. lpmsg->dwConnOffset = sizeof(MSG_STARTSESSION);
  2036. lpTemp = (LPBYTE)lpmsg + lpmsg->dwConnOffset;
  2037. // Copy in the package
  2038. hr = PRV_PackageDPLCONNECTION(lpConn, lpTemp, FALSE);
  2039. if(FAILED(hr))
  2040. {
  2041. DPF_ERRVAL("Unable to pack DPLCONNECTION struct, hr = 0x%08x", hr);
  2042. DPMEM_FREE(lpmsg);
  2043. return hr;
  2044. }
  2045. // Set the output pointers
  2046. *lpdwSize = dwSize;
  2047. *lplpmsg = lpmsg;
  2048. return DP_OK;
  2049. } // PRV_BuildStartSessionMessage
  2050. #undef DPF_MODNAME
  2051. #define DPF_MODNAME "DPLP_StartSession"
  2052. HRESULT DPLAPI DPLP_StartSession(LPDPLOBBYSP lpILP,
  2053. LPSPDATA_STARTSESSIONCOMMAND lpd)
  2054. {
  2055. LPDPLOBBYI_DPLOBJECT this = NULL;
  2056. LPDPLAYI_DPLAY lpDP = NULL;
  2057. DPLCONNECTION conn;
  2058. LPBYTE lpmsg = NULL;
  2059. HRESULT hr = DP_OK;
  2060. LPDPLAYI_PLAYER lpPlayer = NULL;
  2061. LPDPLAYI_GROUP lpGroup = NULL;
  2062. DWORD dwMessageSize;
  2063. LPDPLAYI_GROUPNODE lpGroupnode = NULL;
  2064. UINT nPlayers;
  2065. DPF(7, "Entering DPLP_StartSession");
  2066. DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
  2067. ENTER_DPLOBBY();
  2068. // Make sure the LP doesn't throw us a curve
  2069. TRY
  2070. {
  2071. this = DPLOBJECT_FROM_INTERFACE(lpILP);
  2072. if( !VALID_DPLOBBY_PTR( this ) )
  2073. {
  2074. LEAVE_DPLOBBY();
  2075. DPF_ERR("Lobby Provider passed invalid DPLobby object!");
  2076. return DPERR_INVALIDOBJECT;
  2077. }
  2078. // Validate the struct pointer
  2079. if(!lpd)
  2080. {
  2081. LEAVE_DPLOBBY();
  2082. DPF_ERR("SPDATA_STARTSESSIONCOMMAND structure pointer cannot be NULL");
  2083. return DPERR_INVALIDPARAMS;
  2084. }
  2085. }
  2086. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  2087. {
  2088. LEAVE_DPLOBBY();
  2089. DPF_ERR( "Exception encountered validating parameters" );
  2090. return DPERR_INVALIDPARAMS;
  2091. }
  2092. // Make a local copy of the DPLCONNECTION structure since we will
  2093. // be modifying some elements of it. We are currently only modifying
  2094. // elements in the DPLCONNECTION structure itself, so we can get
  2095. // away with using it's pointers to SessionDesc and PlayerName structs,
  2096. // but if we modify those in the future, we need to copy them as well
  2097. memcpy(&conn, lpd->lpConn, sizeof(DPLCONNECTION));
  2098. // Make a local variable pointer to the dplay object
  2099. lpDP = this->lpDPlayObject;
  2100. // Make sure we know about this group
  2101. if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
  2102. {
  2103. DPF(8, "Received StartSessionCommand message for an unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
  2104. LEAVE_DPLOBBY();
  2105. return DPERR_INVALIDGROUP;
  2106. }
  2107. // Take the dplay lock since we'll be looking at it's structures
  2108. ENTER_DPLAY();
  2109. // See if the host is even in our nametable, if it isn't, we'll assume
  2110. // we're not the host
  2111. // See if the host is a local player, if it is, send separate messages
  2112. if(IsLobbyIDInMapTable(this, lpd->dwHostID))
  2113. {
  2114. // Get dplay's player struct for the host player
  2115. lpPlayer = PlayerFromID(lpDP, lpd->dwHostID);
  2116. // If we know the host player (we should) and he's local, we
  2117. // want to send the host message first
  2118. if((lpPlayer) && (lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  2119. {
  2120. // So set the host bit
  2121. conn.dwFlags |= DPLCONNECTION_CREATESESSION;
  2122. // Build the StartSession message for the host
  2123. hr = PRV_BuildStartSessionMessage(&lpmsg, &dwMessageSize,
  2124. &conn, lpPlayer);
  2125. if(FAILED(hr))
  2126. {
  2127. DPF_ERRVAL("Failed building StartSessionCommand message, hr = 0x%08x", hr);
  2128. goto EXIT_DPLP_STARTSESSION;
  2129. }
  2130. // Now send the message to the host player alone
  2131. hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg,
  2132. dwMessageSize, FALSE, 0);
  2133. if(FAILED(hr))
  2134. {
  2135. DPF(8, "Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
  2136. }
  2137. // Free our message since we're done with it
  2138. DPMEM_FREE(lpmsg);
  2139. lpmsg = NULL;
  2140. // Now fall through and send the join message to everyone else
  2141. // in the group
  2142. }
  2143. }
  2144. // We must be joining, so set the join bit, and make sure the host
  2145. // bit isn't still set from above
  2146. conn.dwFlags &= ~DPLCONNECTION_CREATESESSION;
  2147. conn.dwFlags |= DPLCONNECTION_JOINSESSION;
  2148. // Get a pointer to dplay's internal group structure
  2149. lpGroup = GroupFromID(lpDP, lpd->dwGroupID);
  2150. if(!lpGroup)
  2151. {
  2152. DPF(5, "Unable to find group in nametable, idGroup = %lu", lpd->dwGroupID);
  2153. goto EXIT_DPLP_STARTSESSION;
  2154. }
  2155. // Figure out how many players we are looking for
  2156. lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,lpDP->pSysPlayer->dwID);
  2157. if (!lpGroupnode)
  2158. {
  2159. ASSERT(FALSE);
  2160. return E_UNEXPECTED;
  2161. }
  2162. nPlayers = lpGroupnode->nPlayers;
  2163. // Walk the list of groupnodes, looking for nPlayers local players to give
  2164. // the message to, excluding the host
  2165. lpGroupnode = lpGroup->pGroupnodes;
  2166. while ((nPlayers > 0) && (lpGroupnode))
  2167. {
  2168. if ((lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL) &&
  2169. (lpGroupnode->pPlayer->dwID != lpd->dwHostID))
  2170. {
  2171. // Build the StartSession (join) message for this player
  2172. hr = PRV_BuildStartSessionMessage(&lpmsg, &dwMessageSize,
  2173. &conn, lpGroupnode->pPlayer);
  2174. if(FAILED(hr))
  2175. {
  2176. DPF(5, "Failed building StartSessionCommand message, hr = 0x%08x", hr);
  2177. goto EXIT_DPLP_STARTSESSION;
  2178. }
  2179. // Send the message to this player
  2180. hr = HandlePlayerMessage(lpGroupnode->pPlayer, lpmsg,
  2181. dwMessageSize, FALSE, 0);
  2182. // Free our message
  2183. if(lpmsg)
  2184. DPMEM_FREE(lpmsg);
  2185. lpmsg = NULL;
  2186. nPlayers--;
  2187. } // local & !host
  2188. lpGroupnode = lpGroupnode->pNextGroupnode;
  2189. } // while
  2190. EXIT_DPLP_STARTSESSION:
  2191. if(lpmsg)
  2192. DPMEM_FREE(lpmsg);
  2193. LEAVE_LOBBY_ALL();
  2194. return hr;
  2195. } // DPLP_StartSession