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.
2269 lines
63 KiB
2269 lines
63 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: group.c
|
|
* Content: Methods for managing groups
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======= ======= ======
|
|
* 2/27/97 myronth Created it
|
|
* 3/17/97 myronth Create/DestroyGroup, Removed unnecessary Enum functions
|
|
* 3/20/97 myronth AddPlayerToGroup, DeletePlayerFromGroup
|
|
* 3/21/97 myronth SetGroupName, Get/SetGroupData
|
|
* 3/31/97 myronth Removed dead code, Added CreateAndMapNewGroup function
|
|
* 4/3/97 myronth Changed CALLSP macro to CALL_LP
|
|
* 5/6/97 kipo GetGroup() now takes a parent ID
|
|
* 5/8/97 myronth Subgroup support, GroupConnSettings, StartSession,
|
|
* and drop the lobby lock when calling the LP
|
|
* 5/12/97 myronth Handle remote groups properly
|
|
* 5/17/97 myronth Added parent ID to CreateAndMapNewGroup calls,
|
|
* Added send message code for DestroyGroup and
|
|
* DeletePlayerFromGroup on the local machine
|
|
* 5/20/97 myronth Send Delete & DestroyPlayer messages for remote
|
|
* players when a local player leaves a group (#8586)
|
|
* Made AddPlayerToGroup & DeletePlayerFromGroup return
|
|
* DPERR_ACCESSDENIED on remote players (#8679),
|
|
* Fixed a bunch of other lock bugs, Changed debug levels
|
|
* 5/21/97 myronth Pass CreateGroup flags through the lobby (#8813)
|
|
* 5/22/97 myronth Added functions to destroy remote subgroups when
|
|
* a local player leaves a group (#8810)
|
|
* 5/23/97 myronth Send messages locally for CreateGroup and
|
|
* CreateGroupInGroup (#8870)
|
|
* 6/3/97 myronth Added PRV_DestroySubgroups function (#9134) and
|
|
* rearranged some of the DestroyGroup code
|
|
* 6/5/97 myronth Added shortcut checking to PRV_DestroySubgroups by
|
|
* adding the PRV_AreSubgroupsShortcuts function
|
|
* 6/6/97 myronth Added PRV_DestroyGroupAndParents and PRV_Destroy-
|
|
* ShortcutsForExitingPlayer, cleaned up PRV_Delete-
|
|
* PlayerFromGroup, Fixed StartSession bugs (#9573,#9574)
|
|
* 6/9/97 myronth Only delete shortcuts (don't destroy the subgoup)
|
|
* in the PRV_DestroySubgroups function
|
|
* 6/16/97 myronth Fixed bad deletion of uncle groups & some subgroups
|
|
* during DeletePlayerFromGroup (#9655)
|
|
* 6/20/97 myronth Send AddGroupToGroup message locally to avoid
|
|
* sending duplicate messages. Also added code to
|
|
* send local DeleteGroupFromGroup messages (#10139)
|
|
* 6/24/97 myronth Send AddPlayerToGroup message locally to avoid
|
|
* sending duplicate messages (#10287)
|
|
* 8/22/97 myronth Force guidInstance to NULL in SetGroupConnectionSettings
|
|
* 9/29/97 myronth Send local SetGroupName/Data msgs after call to
|
|
* lobby server succeeds (#12554)
|
|
* 10/23/97 myronth Added hidden group support (#12688), fixed crashing
|
|
* bug on DeletePlayerFromGroup (#12885)
|
|
* 10/29/97 myronth Added support for group owners, including
|
|
* DPL_SetGroupOwner and DPL_GetGroupOwner
|
|
* 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
|
|
***************************************************************************/
|
|
#include "dplobpr.h"
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Functions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_AddGroupToGroup"
|
|
HRESULT DPLAPI PRV_AddGroupToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
|
|
DWORD dwGroupID)
|
|
{
|
|
SPDATA_ADDGROUPTOGROUP ad;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_AddGroupToGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, dwParentID, dwGroupID);
|
|
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLAY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&ad, 0, sizeof(SPDATA_ADDGROUPTOGROUP));
|
|
ad.dwSize = sizeof(SPDATA_ADDGROUPTOGROUP);
|
|
ad.dwParentID = dwParentID;
|
|
ad.dwGroupID = dwGroupID;
|
|
|
|
// Call the AddGroupToGroup method in the SP
|
|
if(CALLBACK_EXISTS(AddGroupToGroup))
|
|
{
|
|
ad.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, AddGroupToGroup, &ad);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// AddGroupToGroup is required
|
|
DPF_ERR("The Lobby Provider callback for AddGroupToGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto EXIT_ADDGROUPTOGROUP;
|
|
}
|
|
|
|
// If it succeeded, send the AddGroupToGroup message to our local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_ADDGROUPTOGROUP;
|
|
}
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDSHORTCUTTOGROUP);
|
|
msg.dwPlayerID = dwGroupID;
|
|
msg.dwGroupID = dwParentID;
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding AddGroupToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Drop the dplay lock
|
|
LEAVE_DPLAY();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling AddGroupToGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_ADDGROUPTOGROUP:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_AddGroupToGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_AddPlayerToGroup"
|
|
HRESULT DPLAPI PRV_AddPlayerToGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
|
|
DWORD dwPlayerID)
|
|
{
|
|
SPDATA_ADDPLAYERTOGROUP ad;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_AddPlayerToGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, dwGroupID, dwPlayerID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLAY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Take the dplay lock since we'll be looking at a dplay internal struct
|
|
ENTER_DPLAY();
|
|
|
|
// Make sure the player is a local player, otherwise return AccessDenied
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
|
|
if(!lpPlayer)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Unable to find player in nametable");
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto EXIT_ADDPLAYERTOGROUP;
|
|
}
|
|
|
|
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Cannot add a remote player to a group");
|
|
hr = DPERR_ACCESSDENIED;
|
|
goto EXIT_ADDPLAYERTOGROUP;
|
|
}
|
|
|
|
// Drop the dplay lock since we're done
|
|
LEAVE_DPLAY();
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&ad, 0, sizeof(SPDATA_ADDPLAYERTOGROUP));
|
|
ad.dwSize = sizeof(SPDATA_ADDPLAYERTOGROUP);
|
|
ad.dwGroupID = dwGroupID;
|
|
ad.dwPlayerID = dwPlayerID;
|
|
|
|
// Call the AddPlayerToGroup method in the SP
|
|
if(CALLBACK_EXISTS(AddPlayerToGroup))
|
|
{
|
|
ad.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, AddPlayerToGroup, &ad);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// AddPlayerToGroup is required
|
|
DPF_ERR("The Lobby Provider callback for AddPlayerToGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto EXIT_ADDPLAYERTOGROUP;
|
|
}
|
|
|
|
// If it succeeded, send the AddPlayerToGroup message to our local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_ADDPLAYERTOGROUP;
|
|
}
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDPLAYERTOGROUP);
|
|
msg.dwPlayerID = dwPlayerID;
|
|
msg.dwGroupID = dwGroupID;
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding AddPlayerToGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
else
|
|
{
|
|
// We need to see if this player is the group owner. If it is,
|
|
// we need to send a SetGroupOwner message as well.
|
|
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
|
|
if(lpGroup && (dwPlayerID == lpGroup->dwOwnerID))
|
|
{
|
|
// Now send the message
|
|
PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwPlayerID, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// Drop the dplay lock
|
|
LEAVE_DPLAY();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling AddPlayerToGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_ADDPLAYERTOGROUP:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_AddPlayerToGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_CreateGroup"
|
|
HRESULT DPLAPI PRV_CreateGroup(LPDPLOBBYI_DPLOBJECT this, LPDPID lpidGroup,
|
|
LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags,
|
|
DWORD dwOwnerID)
|
|
{
|
|
SPDATA_CREATEGROUP cg;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
DWORD dwInternalFlags;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_CreateGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
|
|
this, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&cg, 0, sizeof(SPDATA_CREATEGROUP));
|
|
cg.dwSize = sizeof(SPDATA_CREATEGROUP);
|
|
cg.lpName = lpName;
|
|
cg.lpData = lpData;
|
|
cg.dwDataSize = dwDataSize;
|
|
cg.dwFlags = dwFlags;
|
|
cg.dwGroupOwnerID = dwOwnerID;
|
|
|
|
// Call the CreateGroup method in the SP
|
|
if(CALLBACK_EXISTS(CreateGroup))
|
|
{
|
|
cg.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, CreateGroup, &cg);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// CreateGroup is required
|
|
DPF_ERR("The Lobby Provider callback for CreateGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling CreateGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
goto EXIT_CREATEGROUP;
|
|
}
|
|
|
|
// Setup the flags to pass to GetGroup
|
|
dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
|
|
if(dwFlags & DPGROUP_STAGINGAREA)
|
|
dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
|
|
if(dwFlags & DPGROUP_HIDDEN)
|
|
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
|
|
|
|
// Add the player to dplay's nametable and put it in our map table
|
|
hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
|
|
dwDataSize, dwInternalFlags, cg.dwGroupID, 0, dwOwnerID);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
|
|
// REVIEW!!!! -- We need to send a message back to the server saying
|
|
// we couldn't complete the deal on our end.
|
|
goto EXIT_CREATEGROUP;
|
|
}
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
|
|
msg.dwPlayerID = *lpidGroup;
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERRVAL("Unable to find system group in nametable, hr = 0x%08x", hr);
|
|
goto EXIT_CREATEGROUP;
|
|
}
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message in
|
|
// the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo, (LPBYTE)&msg,
|
|
sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(2, "Failed adding CreateGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
LEAVE_DPLAY();
|
|
|
|
EXIT_CREATEGROUP:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_CreateGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_CreateGroupInGroup"
|
|
HRESULT DPLAPI PRV_CreateGroupInGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwParentID,
|
|
LPDPID lpidGroup, LPDPNAME lpName, LPVOID lpData, DWORD dwDataSize,
|
|
DWORD dwFlags, DWORD dwOwnerID)
|
|
{
|
|
SPDATA_CREATEGROUPINGROUP cgig;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
DWORD dwInternalFlags;
|
|
|
|
|
|
DPF(7, "Entering PRV_CreateGroupInGroup");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
|
|
this, dwParentID, lpidGroup, lpName, lpData, dwDataSize, dwFlags, dwOwnerID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&cgig, 0, sizeof(SPDATA_CREATEGROUPINGROUP));
|
|
cgig.dwSize = sizeof(SPDATA_CREATEGROUPINGROUP);
|
|
cgig.dwParentID = dwParentID;
|
|
cgig.lpName = lpName;
|
|
cgig.lpData = lpData;
|
|
cgig.dwDataSize = dwDataSize;
|
|
cgig.dwFlags = dwFlags;
|
|
cgig.dwGroupOwnerID = dwOwnerID;
|
|
|
|
// Call the CreateGroupInGroup method in the SP
|
|
if(CALLBACK_EXISTS(CreateGroupInGroup))
|
|
{
|
|
cgig.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, CreateGroupInGroup, &cgig);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// CreateGroupInGroup is required
|
|
DPF_ERR("The Lobby Provider callback for CreateGroupInGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling CreateGroupInGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Setup the flags to pass to GetGroup
|
|
dwInternalFlags = DPLAYI_PLAYER_PLAYERLOCAL;
|
|
if(dwFlags & DPGROUP_STAGINGAREA)
|
|
dwInternalFlags |= DPLAYI_GROUP_STAGINGAREA;
|
|
if(dwFlags & DPGROUP_HIDDEN)
|
|
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
|
|
|
|
|
|
// Add the group to dplay's nametable and put it in our map table
|
|
hr = PRV_CreateAndMapNewGroup(this, lpidGroup, lpName, lpData,
|
|
dwDataSize, dwInternalFlags, cgig.dwGroupID, dwParentID, dwOwnerID);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed creating a new local group, hr = 0x%08x", hr);
|
|
// REVIEW!!!! -- We need to send a message back to the server saying
|
|
// we couldn't complete the deal on our end.
|
|
goto EXIT_CREATEGROUPINGROUP;
|
|
}
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_CREATEGROUP);
|
|
msg.dwPlayerID = *lpidGroup;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
// Since this is local, send it to all players
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERRVAL("Unable to find parent group in nametable, hr = 0x%08x", hr);
|
|
goto EXIT_CREATEGROUPINGROUP;
|
|
}
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(2, "Failed adding CreateGroupInGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Drop the dplay lock
|
|
LEAVE_DPLAY();
|
|
|
|
|
|
EXIT_CREATEGROUPINGROUP:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_CreateGroupInGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DeleteGroupFromGroup"
|
|
HRESULT DPLAPI PRV_DeleteGroupFromGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
DWORD dwParentID, DWORD dwGroupID)
|
|
{
|
|
SPDATA_DELETEGROUPFROMGROUP dgd;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_DeleteGroupFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, dwParentID, dwGroupID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&dgd, 0, sizeof(SPDATA_DELETEGROUPFROMGROUP));
|
|
dgd.dwSize = sizeof(SPDATA_DELETEGROUPFROMGROUP);
|
|
dgd.dwParentID = dwParentID;
|
|
dgd.dwGroupID = dwGroupID;
|
|
|
|
// Call the DeleteGroupFromGroup method in the SP
|
|
if(CALLBACK_EXISTS(DeleteGroupFromGroup))
|
|
{
|
|
dgd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, DeleteGroupFromGroup, &dgd);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// DeleteGroupFromGroup is required
|
|
DPF_ERR("The Lobby Provider callback for DeleteGroupFromGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
// If it succeeded, send the DeleteGroupFromGroup message to all local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Get a pointer to dplay's system group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERR("Unable to find system group in nametable, not sending DeleteGroupFromGroup message");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
|
|
msg.dwPlayerID = dwGroupID;
|
|
msg.dwGroupID = dwParentID;
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Drop the dplay lock
|
|
LEAVE_DPLAY();
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling DeleteGroupFromGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// The dplay InternalDeletePlayerFromGroup code will take care of the rest of
|
|
// the internal cleanup (nametable, players, etc.), so we can just return
|
|
// from here.
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_DeleteGroupFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DoSubgroupsContainLocalPlayers"
|
|
BOOL PRV_DoSubgroupsContainLocalPlayers(LPDPLAYI_GROUP lpGroup,
|
|
BOOL bIncludeGroup)
|
|
{
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
|
|
|
|
|
|
DPF(7, "Entering PRV_DoSubgroupsContainLocalPlayers");
|
|
DPF(9, "Parameters: 0x%08x, %lu", lpGroup, bIncludeGroup);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Figure out how many local players are in this group. If it's
|
|
// nonzero, just return true from this function. If the bIncludeGroup
|
|
// parameter is set to FALSE, then don't look at the group passed in
|
|
lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
|
|
lpGroup->lpDP->pSysPlayer->dwID);
|
|
if(lpGroupnode && (lpGroupnode->nPlayers > 0) && bIncludeGroup)
|
|
return TRUE;
|
|
|
|
// Walk the list of subgroups
|
|
lpSubgroup = lpGroup->pSubgroups;
|
|
while(lpSubgroup)
|
|
{
|
|
// We're going recursive here to do the entire heirarchy
|
|
// Check out any of it's subgroups
|
|
if((!(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
|
|
(PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)))
|
|
return TRUE;
|
|
else
|
|
lpSubgroup = lpSubgroup->pNextSubgroup;
|
|
|
|
} // while subgroups
|
|
|
|
return FALSE;
|
|
|
|
} // PRV_DoSubgroupsContainLocalPlayers
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_AreSubgroupsShortcuts"
|
|
BOOL PRV_AreSubgroupsShortcuts(LPDPLAYI_GROUP lpGroup)
|
|
{
|
|
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
|
|
|
|
|
|
DPF(7, "Entering PRV_AreSubgroupsShortcuts");
|
|
DPF(9, "Parameters: 0x%08x", lpGroup);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// If the group is one of the following, then we want to return TRUE so
|
|
// it doesn't get nuked:
|
|
// 1) Root group, nGroups > 0
|
|
// 2) Root group, hidden, nGroups = 0
|
|
// 2) Non-root group, nGroups > 1
|
|
// Otherwise, we can check it's subgroups and return FALSE as appropriate
|
|
if(((lpGroup->dwIDParent == 0) && ((lpGroup->nGroups > 0) ||
|
|
(!(lpGroup->dwFlags & DPLAYI_GROUP_HIDDEN)) && (lpGroup->nGroups == 0))) ||
|
|
((lpGroup->dwIDParent != 0) && (lpGroup->nGroups > 1)))
|
|
return TRUE;
|
|
|
|
// Walk the list of subgroups
|
|
lpSubgroup = lpGroup->pSubgroups;
|
|
while(lpSubgroup)
|
|
{
|
|
// We're going recursive here to do the entire heirarchy
|
|
// Check out any of it's subgroups
|
|
if(PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))
|
|
return TRUE;
|
|
else
|
|
lpSubgroup = lpSubgroup->pNextSubgroup;
|
|
|
|
} // while subgroups
|
|
|
|
return FALSE;
|
|
|
|
} // PRV_AreSubgroupsShortcuts
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyGroupAndParents"
|
|
void PRV_DestroyGroupAndParents(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLAYI_GROUP lpGroup, LPDPLAYI_GROUP lpStopParent)
|
|
{
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
LPDPLAYI_GROUP lpParentGroup = NULL;
|
|
SPDATA_DESTROYREMOTEGROUP dg;
|
|
DPID dpidParent;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyGroupAndParents");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, lpGroup, lpStopParent);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Now we need to decide if this is the last group this group was in. If
|
|
// it is, then we need to destroy the group as well, and remove them from
|
|
// our map table. Of course, only destroy the group if it is a remote group.
|
|
// ALSO, we need to walk the heirarchy backward (up the tree) to the root
|
|
// node and delete all groups that were only created to get to our shortcut.
|
|
if(!(lpGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
// Walk our parental heirarchy until we reach a a root group.
|
|
dpidParent = lpGroup->dwIDParent;
|
|
while(dpidParent)
|
|
{
|
|
// Get dplay's internal group structures
|
|
lpParentGroup = GroupFromID(this->lpDPlayObject, dpidParent);
|
|
if(!lpParentGroup)
|
|
{
|
|
ASSERT(FALSE);
|
|
DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dpidParent);
|
|
return;
|
|
}
|
|
|
|
// If there are any local players in the parent group, we don't want to
|
|
// destroy it or any of it's subgroups (since players in the group will
|
|
// be able to see subgroups)
|
|
lpGroupnode = FindPlayerInGroupList(lpParentGroup->pSysPlayerGroupnodes,
|
|
this->lpDPlayObject->pSysPlayer->dwID);
|
|
if((lpGroupnode) && (lpGroupnode->nPlayers > 0))
|
|
return;
|
|
|
|
// Make sure we haven't reached our stop parent group if the caller
|
|
// passed one in. This will keep us from recursively destroying
|
|
// a subgroup's parent, which we might be spinning on, deleting all
|
|
// of it's subgroups.
|
|
if(lpStopParent && (lpStopParent == lpParentGroup))
|
|
return;
|
|
|
|
// Destroy the subgroups
|
|
PRV_DestroySubgroups(this, lpParentGroup, TRUE);
|
|
|
|
// Get the next parent
|
|
dpidParent = lpParentGroup->dwIDParent;
|
|
}
|
|
|
|
// See if we processed any parents, or if we already have a root
|
|
// group. If lpParentGroup is NULL, we have a root group, so just
|
|
// stuff our group pointer in the parent group pointer
|
|
if(!lpParentGroup)
|
|
lpParentGroup = lpGroup;
|
|
|
|
// Now see if our root group is hidden, and if it doesn't contain any
|
|
// references, then we want to destroy it as well.
|
|
if((!PRV_DoSubgroupsContainLocalPlayers(lpParentGroup, TRUE)) &&
|
|
(!PRV_AreSubgroupsShortcuts(lpParentGroup)) &&
|
|
(lpParentGroup->dwFlags & DPLAYI_GROUP_HIDDEN))
|
|
{
|
|
// Setup the SPDATA struct for DestroyRemoteGroup
|
|
memset(&dg, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
|
|
dg.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
|
|
dg.dwGroupID = lpParentGroup->dwID;
|
|
|
|
// Call our internal remote create
|
|
hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dg);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed destroying remote root group, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // PRV_DestroyGroupAndParents
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyRemoteShortcutsForExitingPlayer"
|
|
void PRV_DestroyRemoteShortcutsForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
|
|
{
|
|
SPDATA_DELETEREMOTEGROUPFROMGROUP drgd;
|
|
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
|
|
LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyRemoteShortcutsForExitingPlayer");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, dwGroupID);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
|
|
memset(&drgd, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
|
|
drgd.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
|
|
drgd.dwParentID = dwGroupID;
|
|
|
|
// Walk the list of subgroups, destroying all remote shortcuts
|
|
lpSubgroup = lpGroup->pSubgroups;
|
|
while(lpSubgroup)
|
|
{
|
|
// Save the next subgroup
|
|
lpNextSubgroup = lpSubgroup->pNextSubgroup;
|
|
|
|
// Make sure the group is remote and that this is really
|
|
// a shortcut and not a child
|
|
if(((lpSubgroup->dwFlags & DPGROUP_SHORTCUT)) &&
|
|
(!(lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)))
|
|
{
|
|
// Get the subgroup's lobby ID
|
|
drgd.dwGroupID = lpSubgroup->pGroup->dwID;
|
|
|
|
// Call our internal DeleteGroupFromGroup routine to delete
|
|
// the shortcut and send the appropriate messages
|
|
// NOTE: It is imperative that we pass in a pointer to the
|
|
// group who's shortcuts we are removing as the stop parent.
|
|
// If we do not, we run the risk of deleting it or one of
|
|
// it's children that we haven't yet looped through, which
|
|
// will result in a crash as we continue to walk the
|
|
// subgroup list.
|
|
hr = PRV_DeleteRemoteGroupFromGroup(this, &drgd, TRUE, lpGroup);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
|
|
// Go to the next one
|
|
lpSubgroup = lpNextSubgroup;
|
|
}
|
|
|
|
} // PRV_DestroyRemoteShortcutsForExitingPlayer
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyRemotePlayersForExitingPlayer"
|
|
void PRV_DestroyRemotePlayersForExitingPlayer(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLAYI_GROUP lpGroup, DWORD dwGroupID)
|
|
{
|
|
SPDATA_DELETEREMOTEPLAYERFROMGROUP drpd;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
LPDPLAYI_GROUPNODE lpNextGroupnode = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyRemotePlayersForExitingPlayer");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Setup the SPDATA_DELETEREMOTEPLAYERFROMGROUP data struct
|
|
memset(&drpd, 0, sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP));
|
|
drpd.dwSize = sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP);
|
|
drpd.dwGroupID = dwGroupID;
|
|
|
|
// Walk the list of groupnodes, deleting remote players that are not in
|
|
// any other groups
|
|
lpGroupnode = lpGroup->pGroupnodes;
|
|
while(lpGroupnode)
|
|
{
|
|
// Save our next groupnode pointer since our current groupnode
|
|
// will be gone when we come back from the delete
|
|
lpNextGroupnode = lpGroupnode->pNextGroupnode;
|
|
|
|
// Delete the player from the group if it's remote and then
|
|
// destroy the player if he is in no other groups
|
|
if (!(lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
// Get the remote player's ID
|
|
drpd.dwPlayerID = lpGroupnode->pPlayer->dwID;
|
|
|
|
// Delete the player from the group
|
|
hr = PRV_DeleteRemotePlayerFromGroup(this, &drpd, TRUE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed deleting remote player from group, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
lpGroupnode = lpNextGroupnode;
|
|
|
|
} // while
|
|
|
|
} // PRV_DestroyRemotePlayersForExitingPlayer
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroySubgroups"
|
|
void PRV_DestroySubgroups(LPDPLOBBYI_DPLOBJECT this, LPDPLAYI_GROUP lpGroup,
|
|
BOOL bRemoteOnly)
|
|
{
|
|
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
|
|
LPDPLAYI_SUBGROUP lpNextSubgroup = NULL;
|
|
SPDATA_DESTROYREMOTEGROUP dgd;
|
|
SPDATA_DELETEREMOTEGROUPFROMGROUP drg;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroySubgroups");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpGroup, bRemoteOnly);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Setup the static part of the SPDATA structures
|
|
memset(&dgd, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
|
|
dgd.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
|
|
|
|
memset(&drg, 0, sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP));
|
|
drg.dwSize = sizeof(SPDATA_DELETEREMOTEGROUPFROMGROUP);
|
|
drg.dwParentID = lpGroup->dwID;
|
|
|
|
// Walk the list of subgroups
|
|
lpSubgroup = lpGroup->pSubgroups;
|
|
while(lpSubgroup)
|
|
{
|
|
// Save the next subgroup
|
|
lpNextSubgroup = lpSubgroup->pNextSubgroup;
|
|
|
|
// Make sure it's a remote group if the flag is set
|
|
if((bRemoteOnly) &&
|
|
(lpSubgroup->pGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
lpSubgroup = lpNextSubgroup;
|
|
continue;
|
|
}
|
|
|
|
// If the subgroup doesn't contain any local players,
|
|
// nor do any of it's subgroups, then destroy it
|
|
if((!bRemoteOnly) ||
|
|
((!PRV_DoSubgroupsContainLocalPlayers(lpSubgroup->pGroup, TRUE)) &&
|
|
(!PRV_AreSubgroupsShortcuts(lpSubgroup->pGroup))))
|
|
{
|
|
// If the group is a shortcut, just delete the link. If it's a child,
|
|
// destroy the subgroup.
|
|
if(lpSubgroup->dwFlags & DPGROUP_SHORTCUT)
|
|
{
|
|
// Finish setting up the SPDATA structure
|
|
drg.dwGroupID = lpSubgroup->pGroup->dwID;
|
|
|
|
// Destroy the subgroup
|
|
hr = DPLP_DeleteGroupFromGroup((LPDPLOBBYSP)this->lpInterfaces, &drg);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed deleting remote group from group, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Finish setting up the SPDATA structure
|
|
dgd.dwGroupID = lpSubgroup->pGroup->dwID;
|
|
|
|
// Destroy the subgroup
|
|
hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dgd);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed destroying remote group, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
lpSubgroup = lpNextSubgroup;
|
|
|
|
} // while lpSubgroups
|
|
|
|
} // PRV_DestroySubgroups
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DeletePlayerFromGroup"
|
|
HRESULT DPLAPI PRV_DeletePlayerFromGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
DWORD dwGroupID, DWORD dwPlayerID)
|
|
{
|
|
SPDATA_DELETEPLAYERFROMGROUP dpd;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroup =NULL;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_DeletePlayerFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
this, dwGroupID, dwPlayerID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Take the dplay lock since we'll be looking at a dplay internal struct
|
|
ENTER_DPLAY();
|
|
|
|
// Make sure the player is a local player, otherwise return AccessDenied
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
|
|
if(!lpPlayer)
|
|
{
|
|
DPF_ERR("Unable to find player in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
DPF_ERR("Cannot delete a remote player from a group");
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto EXIT_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// Drop the dplay lock since we're done
|
|
LEAVE_DPLAY();
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&dpd, 0, sizeof(SPDATA_DELETEPLAYERFROMGROUP));
|
|
dpd.dwSize = sizeof(SPDATA_DELETEPLAYERFROMGROUP);
|
|
dpd.dwGroupID = dwGroupID;
|
|
dpd.dwPlayerID = dwPlayerID;
|
|
|
|
// Call the DeletePlayerFromGroup method in the SP
|
|
if(CALLBACK_EXISTS(DeletePlayerFromGroup))
|
|
{
|
|
dpd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, DeletePlayerFromGroup, &dpd);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// DeletePlayerFromGroup is required
|
|
DPF_ERR("The Lobby Provider callback for DeletePlayerFromGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling DeletePlayerFromGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
}
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// We need to remove all other players in the group and send the appropriate
|
|
// message to the player we are about to delete because he won't see the
|
|
// system messages for them once he leaves the group. However, if any other
|
|
// local players are in the group, we don't want to remove the remote players
|
|
// from the nametable because the other local players need to see them.
|
|
|
|
// Get a pointer to dplay's internal group structure
|
|
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, idGroup = %lu", dwGroupID);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// Get a pointer to dplay's internal player structure
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, dwPlayerID);
|
|
if(!lpPlayer)
|
|
{
|
|
DPF_ERRVAL("Unable to find player in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto EXIT_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// We need to send a DeletePlayerFromGroup message to the player who
|
|
// was deleted since he won't get the group message once he's gone
|
|
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEPLAYERFROMGROUP);
|
|
msg.dwPlayerID = dwPlayerID;
|
|
msg.dwGroupID = dwGroupID;
|
|
|
|
// Call dplay's handleplayermessage function to put the message in the queue
|
|
hr = HandlePlayerMessage(lpPlayer, (LPBYTE)&msg,
|
|
sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
// Set the hresult back to DP_OK since only the message failed
|
|
hr = DP_OK;
|
|
}
|
|
|
|
// Figure out how many local players are in this group. If it's only 1,
|
|
// then delete all the remote players.
|
|
lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,
|
|
this->lpDPlayObject->pSysPlayer->dwID);
|
|
if((!lpGroupnode) || (lpGroupnode->nPlayers == 0))
|
|
{
|
|
// Destroy all remote players that are only in this group
|
|
PRV_DestroyRemotePlayersForExitingPlayer(this, lpGroup, dwGroupID);
|
|
|
|
// Destroy all the remote shortcut groups, making sure we are
|
|
// not in them, and removing their entire parental heirarchy
|
|
PRV_DestroyRemoteShortcutsForExitingPlayer(this, lpGroup, dwGroupID);
|
|
|
|
// Destroy all remote subgroups of this group, making sure we're
|
|
// not in them for some reason
|
|
PRV_DestroySubgroups(this, lpGroup, TRUE);
|
|
|
|
// Destroy the group we're leaving if it is remote as well as it's
|
|
// parental chain.
|
|
PRV_DestroyGroupAndParents(this, lpGroup, NULL);
|
|
}
|
|
|
|
|
|
EXIT_DELETEPLAYERFROMGROUP:
|
|
|
|
// The dplay InternalDeletePlayerFromGroup code will take care of the rest of
|
|
// the internal cleanup (nametable, players, etc.), so we can just return
|
|
// from here.
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // PRV_DeletePlayerFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DestroyGroup"
|
|
HRESULT DPLAPI PRV_DestroyGroup(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
|
|
{
|
|
SPDATA_DESTROYGROUP dg;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_DestroyGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, dwLobbyID);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&dg, 0, sizeof(SPDATA_DESTROYGROUP));
|
|
dg.dwSize = sizeof(SPDATA_DESTROYGROUP);
|
|
dg.dwGroupID = dwLobbyID;
|
|
|
|
// Call the DestroyGroup method in the SP
|
|
if(CALLBACK_EXISTS(DestroyGroup))
|
|
{
|
|
dg.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, DestroyGroup, &dg);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// DestroyGroup is required
|
|
DPF_ERR("The Lobby Provider callback for DestroyGroup doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling DestroyGroup in the Lobby Provider, hr = 0x%08x", hr);
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// So, get dplay's internal group structure
|
|
lpGroup = GroupFromID(this->lpDPlayObject, dwLobbyID);
|
|
if(!lpGroup)
|
|
{
|
|
// This shouldn't ever happen. If the groups isn't in the nametable,
|
|
// we should never get this far.
|
|
ASSERT(FALSE);
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERRVAL("Unable to find group in nametable, dpidGroup = %lu", dwLobbyID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Send messages to remove shortcuts to this group (since dplay won't
|
|
// do it for us)
|
|
PRV_SendDeleteShortcutMessageForExitingGroup(this, lpGroup);
|
|
|
|
// Destroy all the subgroups and remote players
|
|
PRV_RemoveSubgroupsAndPlayersFromGroup(this, lpGroup, dwLobbyID, FALSE);
|
|
|
|
// Drop the dplay lock since we're done mucking around with it's structures
|
|
LEAVE_DPLAY();
|
|
|
|
// Broadcast the DestroyGroup message
|
|
hr = PRV_BroadcastDestroyGroupMessage(this, dwLobbyID);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed to send DestroyGroup message to local players, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// The dplay InternalDestroyGroup code will take care of the rest of
|
|
// the internal cleanup (nametable, players, etc.), so we can just return
|
|
// from here.
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_DestroyGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_GetGroupConnectionSettings"
|
|
HRESULT PRV_GetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
|
|
DWORD dwGroupID, LPVOID lpData, LPDWORD lpdwSize)
|
|
{
|
|
SPDATA_GETGROUPCONNECTIONSETTINGS gcs;
|
|
LPDPLOBBYI_DPLOBJECT this = NULL;
|
|
LPDPLAYI_DPLAY lpDPObject = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_GetGroupConnectionSettings");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwFlags, dwGroupID, lpData, lpdwSize);
|
|
|
|
TRY
|
|
{
|
|
lpDPObject = DPLAY_FROM_INT(lpDP);
|
|
hr = VALID_DPLAY_PTR( lpDPObject );
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
|
|
return hr;
|
|
}
|
|
|
|
if(!IS_LOBBY_OWNED(lpDPObject))
|
|
{
|
|
DPF_ERR("GetGroupConnectionSettings is only supported for lobby connections");
|
|
return DPERR_UNSUPPORTED;
|
|
}
|
|
|
|
this = lpDPObject->lpLobbyObject;
|
|
if(!VALID_DPLOBBY_PTR(this))
|
|
{
|
|
DPF_ERR("Bad DPLobby object");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
lpGroup = GroupFromID(lpDPObject, dwGroupID);
|
|
if (!VALID_DPLAY_GROUP(lpGroup))
|
|
{
|
|
DPF_ERR("Invalid group id");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
if( !VALID_DWORD_PTR( lpdwSize ) )
|
|
{
|
|
DPF_ERR("lpdwSize was not a valid dword pointer!");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if(lpData)
|
|
{
|
|
if( !VALID_WRITE_PTR(lpData, *lpdwSize) )
|
|
{
|
|
DPF_ERR("lpData is not a valid output buffer of the size specified in *lpdwSize");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
// We haven't defined any flags for this release
|
|
if( (dwFlags) )
|
|
{
|
|
return DPERR_INVALIDFLAGS;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&gcs, 0, sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS));
|
|
gcs.dwSize = sizeof(SPDATA_GETGROUPCONNECTIONSETTINGS);
|
|
gcs.dwFlags = dwFlags;
|
|
gcs.dwGroupID = dwGroupID;
|
|
gcs.lpdwBufferSize = lpdwSize;
|
|
gcs.lpBuffer = lpData;
|
|
|
|
// Call the GetGroupConnectionSettings method in the SP
|
|
if(CALLBACK_EXISTS(GetGroupConnectionSettings))
|
|
{
|
|
gcs.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the dplay lock since we are going to send a guaranteed message
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
hr = CALL_LP(this, GetGroupConnectionSettings, &gcs);
|
|
|
|
// Take the lock back
|
|
ENTER_LOBBY_ALL();
|
|
}
|
|
else
|
|
{
|
|
// GetGroupConnectionSettings is required
|
|
DPF_ERR("The Lobby Provider callback for GetGroupConnectionSettings doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr) && (hr != DPERR_BUFFERTOOSMALL))
|
|
{
|
|
DPF_ERRVAL("Failed calling GetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // PRV_GetGroupConnectionSettings
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_GetGroupConnectionSettings"
|
|
HRESULT DPLAPI DPL_GetGroupConnectionSettings(LPDIRECTPLAY lpDP,
|
|
DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwSize)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering DPL_GetGroupConnectionSettings");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwFlags, idGroup, lpData, lpdwSize);
|
|
|
|
ENTER_LOBBY_ALL();
|
|
|
|
// Set the ANSI flag to TRUE and call the internal function
|
|
hr = PRV_GetGroupConnectionSettings(lpDP, dwFlags, idGroup,
|
|
lpData, lpdwSize);
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPL_GetGroupConnectionSettings
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_GetGroupData"
|
|
HRESULT DPLAPI PRV_GetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
|
|
LPVOID lpData, LPDWORD lpdwDataSize)
|
|
{
|
|
SPDATA_GETGROUPDATA ggd;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_GetGroupData");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
|
|
this, dwGroupID, lpData, lpdwDataSize);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&ggd, 0, sizeof(SPDATA_GETGROUPDATA));
|
|
ggd.dwSize = sizeof(SPDATA_GETGROUPDATA);
|
|
ggd.dwGroupID = dwGroupID;
|
|
ggd.lpdwDataSize = lpdwDataSize;
|
|
ggd.lpData = lpData;
|
|
|
|
// Call the GetGroupData method in the SP
|
|
if(CALLBACK_EXISTS(GetGroupData))
|
|
{
|
|
ggd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, GetGroupData, &ggd);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// GetGroupData is required
|
|
DPF_ERR("The Lobby Provider callback for GetGroupData doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling GetGroupData in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_GetGroupData
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_GetGroupOwner"
|
|
HRESULT DPAPI DPL_GetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
|
|
LPDPID lpidOwner)
|
|
{
|
|
LPDPLAYI_DPLAY this;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering DPL_GetGroupOwner");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwGroupID, lpidOwner);
|
|
|
|
ENTER_DPLAY();
|
|
|
|
TRY
|
|
{
|
|
this = DPLAY_FROM_INT(lpDP);
|
|
hr = VALID_DPLAY_PTR( this );
|
|
if (FAILED(hr))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
|
|
return hr;
|
|
}
|
|
|
|
lpGroup = GroupFromID(this, dwGroupID);
|
|
if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Invalid group id");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
if (!VALID_DWORD_PTR(lpidOwner))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Invalid owner id pointer");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// This method is only valid in lobby session
|
|
if(IS_LOBBY_OWNED(this))
|
|
{
|
|
*lpidOwner = lpGroup->dwOwnerID;
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("GetGroupOwner is only supported for lobby sessions");
|
|
hr = DPERR_UNSUPPORTED;
|
|
}
|
|
|
|
LEAVE_DPLAY();
|
|
return hr;
|
|
|
|
} // DPL_GetGroupOwner
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SetGroupConnectionSettings"
|
|
HRESULT PRV_SetGroupConnectionSettings(LPDIRECTPLAY lpDP, DWORD dwFlags,
|
|
DWORD dwGroupID, LPDPLCONNECTION lpConn, BOOL bAnsi)
|
|
{
|
|
SPDATA_SETGROUPCONNECTIONSETTINGS scs;
|
|
LPDPLOBBYI_DPLOBJECT this = NULL;
|
|
LPDPLAYI_DPLAY lpDPObject = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_SetGroupConnectionSettings");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu",
|
|
lpDP, dwFlags, dwGroupID, lpConn, bAnsi);
|
|
|
|
TRY
|
|
{
|
|
lpDPObject = DPLAY_FROM_INT(lpDP);
|
|
hr = VALID_DPLAY_PTR( lpDPObject );
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
|
|
return hr;
|
|
}
|
|
|
|
if(!IS_LOBBY_OWNED(lpDPObject))
|
|
{
|
|
DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
|
|
return DPERR_UNSUPPORTED;
|
|
}
|
|
|
|
this = lpDPObject->lpLobbyObject;
|
|
if(!VALID_DPLOBBY_PTR(this))
|
|
{
|
|
DPF_ERR("Bad DPLobby object");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
lpGroup = GroupFromID(lpDPObject, dwGroupID);
|
|
if (!VALID_DPLAY_GROUP(lpGroup))
|
|
{
|
|
DPF_ERR("Invalid group id");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
hr = PRV_ValidateDPLCONNECTION(lpConn, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERR("Invalid DPLCONNECTION structure");
|
|
return hr;
|
|
}
|
|
|
|
// We haven't defined any flags for this release
|
|
if( (dwFlags) )
|
|
{
|
|
return DPERR_INVALIDFLAGS;
|
|
}
|
|
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&scs, 0, sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS));
|
|
scs.dwSize = sizeof(SPDATA_SETGROUPCONNECTIONSETTINGS);
|
|
scs.dwFlags = dwFlags;
|
|
scs.dwGroupID = dwGroupID;
|
|
scs.lpConn = lpConn;
|
|
|
|
// Ensure that the guidInstance in the DPLCONNECTION structure is NULL
|
|
lpConn->lpSessionDesc->guidInstance = GUID_NULL;
|
|
|
|
// Call the SetGroupConnectionSettings method in the SP
|
|
if(CALLBACK_EXISTS(SetGroupConnectionSettings))
|
|
{
|
|
scs.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the dplay lock since we're sending a guaranteed message
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
hr = CALL_LP(this, SetGroupConnectionSettings, &scs);
|
|
|
|
// Take the lock back
|
|
ENTER_LOBBY_ALL();
|
|
}
|
|
else
|
|
{
|
|
// SetGroupConnectionSettings is required
|
|
DPF_ERR("The Lobby Provider callback for SetGroupConnectionSettings doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
return DPERR_UNAVAILABLE;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling SetGroupConnectionSettings in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // PRV_SetGroupConnectionSettings
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_SetGroupConnectionSettings"
|
|
HRESULT DPLAPI DPL_SetGroupConnectionSettings(LPDIRECTPLAY lpDP,
|
|
DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConn)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering DPL_SetGroupConnectionSettings");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwFlags, idGroup, lpConn);
|
|
|
|
ENTER_LOBBY_ALL();
|
|
|
|
// Set the ANSI flag to TRUE and call the internal function
|
|
hr = PRV_SetGroupConnectionSettings(lpDP, dwFlags, idGroup, lpConn, FALSE);
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPL_SetGroupConnectionSettings
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SetGroupData"
|
|
HRESULT DPLAPI PRV_SetGroupData(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
|
|
LPVOID lpData, DWORD dwDataSize, DWORD dwFlags)
|
|
{
|
|
SPDATA_SETGROUPDATA sgd;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_SetGroupData");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu, 0x%08x",
|
|
this, dwGroupID, lpData, dwDataSize, dwFlags);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLAY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&sgd, 0, sizeof(SPDATA_SETGROUPDATA));
|
|
sgd.dwSize = sizeof(SPDATA_SETGROUPDATA);
|
|
sgd.dwGroupID = dwGroupID;
|
|
sgd.dwDataSize = dwDataSize;
|
|
sgd.lpData = lpData;
|
|
sgd.dwFlags = dwFlags;
|
|
|
|
// Call the SetGroupData method in the SP
|
|
if(CALLBACK_EXISTS(SetGroupData))
|
|
{
|
|
sgd.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, SetGroupData, &sgd);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// SetGroupData is required
|
|
DPF_ERR("The Lobby Provider callback for SetGroupData doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto EXIT_SETGROUPDATA;
|
|
}
|
|
|
|
// If it succeeded, send the SetGroupData message to our local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = PRV_SendDataChangedMessageLocally(this, dwGroupID, lpData, dwDataSize);
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling SetGroupData in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_SETGROUPDATA:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_SetGroupData
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SetGroupName"
|
|
HRESULT DPLAPI PRV_SetGroupName(LPDPLOBBYI_DPLOBJECT this, DWORD dwGroupID,
|
|
LPDPNAME lpName, DWORD dwFlags)
|
|
{
|
|
SPDATA_SETGROUPNAME sgn;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_SetGroupName");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
|
|
this, dwGroupID, lpName, dwFlags);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLAY();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&sgn, 0, sizeof(SPDATA_SETGROUPNAME));
|
|
sgn.dwSize = sizeof(SPDATA_SETGROUPNAME);
|
|
sgn.dwGroupID = dwGroupID;
|
|
sgn.lpName = lpName;
|
|
sgn.dwFlags = dwFlags;
|
|
|
|
// Call the SetGroupName method in the SP
|
|
if(CALLBACK_EXISTS(SetGroupName))
|
|
{
|
|
sgn.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// CreatePlayer response (which always happens)
|
|
LEAVE_DPLOBBY();
|
|
hr = CALL_LP(this, SetGroupName, &sgn);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// SetGroupName is required
|
|
DPF_ERR("The Lobby Provider callback for SetGroupName doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto EXIT_SETGROUPNAME;
|
|
}
|
|
|
|
// If it succeeded, send the SetGroupName message to our local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = PRV_SendNameChangedMessageLocally(this, dwGroupID, lpName, FALSE);
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling SetGroupName in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_SETGROUPNAME:
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // PRV_SetGroupName
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_SetGroupOwner"
|
|
HRESULT DPLAPI DPL_SetGroupOwner(LPDIRECTPLAY lpDP, DWORD dwGroupID,
|
|
DWORD dwOwnerID)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
LPDPLAYI_DPLAY lpDPlayObject;
|
|
SPDATA_SETGROUPOWNER sgo;
|
|
LPDPLAYI_PLAYER lpNewOwner = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
DWORD dwOldOwnerID;
|
|
|
|
|
|
DPF(7, "Entering DPL_SetGroupOwner");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwGroupID, dwOwnerID);
|
|
|
|
ENTER_LOBBY_ALL();
|
|
|
|
TRY
|
|
{
|
|
lpDPlayObject = DPLAY_FROM_INT(lpDP);
|
|
hr = VALID_DPLAY_PTR( lpDPlayObject );
|
|
if (FAILED(hr))
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERRVAL("bad dplay ptr - hr = 0x%08lx\n",hr);
|
|
return hr;
|
|
}
|
|
|
|
this = lpDPlayObject->lpLobbyObject;
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
lpGroup = GroupFromID(lpDPlayObject, dwGroupID);
|
|
if ((!VALID_DPLAY_GROUP(lpGroup)) || (DPID_ALLPLAYERS == dwGroupID))
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERR("Invalid group id");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// DPID_SERVERPLAYER is valid here
|
|
if(dwOwnerID != DPID_SERVERPLAYER)
|
|
{
|
|
lpNewOwner = PlayerFromID(lpDPlayObject, dwOwnerID);
|
|
if (!VALID_DPLAY_PLAYER(lpNewOwner))
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERR("Invalid new owner player id");
|
|
return DPERR_INVALIDPLAYER;
|
|
}
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_LOBBY_ALL();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// do the send
|
|
if(!IS_LOBBY_OWNED(lpDPlayObject))
|
|
{
|
|
DPF_ERR("SetGroupOwner is only supported for lobby sessions");
|
|
hr = DPERR_UNSUPPORTED;
|
|
goto EXIT_SETGROUPOWNER;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&sgo, 0, sizeof(SPDATA_SETGROUPOWNER));
|
|
sgo.dwSize = sizeof(SPDATA_SETGROUPOWNER);
|
|
sgo.dwGroupID = dwGroupID;
|
|
sgo.dwOwnerID = dwOwnerID;
|
|
|
|
// Call the SetGroupOwner method in the SP
|
|
if(CALLBACK_EXISTS(SetGroupOwner))
|
|
{
|
|
sgo.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the lock so the lobby provider's receive thread can get back
|
|
// in with other messages if they show up in the queue before our
|
|
// response (which always happens)
|
|
LEAVE_LOBBY_ALL();
|
|
hr = CALL_LP(this, SetGroupOwner, &sgo);
|
|
ENTER_LOBBY_ALL();
|
|
}
|
|
else
|
|
{
|
|
// SetGroupOwner is required
|
|
DPF_ERR("The Lobby Provider callback for SetGroupOwner doesn't exist");
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto EXIT_SETGROUPOWNER;
|
|
}
|
|
|
|
// If it succeeded, send the SetGroupOwner message to our local players
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Get a pointer to our internal data struct for the group, just in
|
|
// case it changed for some reason while we had dropped the locks
|
|
lpGroup = GroupFromID(this->lpDPlayObject, dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
DPF_ERR("Unable to find group in nametable -- local nametable will be incorrect");
|
|
goto EXIT_SETGROUPOWNER;
|
|
}
|
|
|
|
// Save the old owner so we can put it in the message
|
|
dwOldOwnerID = lpGroup->dwOwnerID;
|
|
|
|
// Change the owner
|
|
lpGroup->dwOwnerID = dwOwnerID;
|
|
|
|
// Send a SetGroupOwner message locally
|
|
PRV_SendGroupOwnerMessageLocally(this, dwGroupID, dwOwnerID, dwOldOwnerID);
|
|
}
|
|
else
|
|
{
|
|
DPF_ERRVAL("Failed calling SetGroupOwner in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_SETGROUPOWNER:
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPL_SetGroupOwner
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPL_StartSession"
|
|
HRESULT DPLAPI DPL_StartSession(LPDIRECTPLAY lpDP, DWORD dwFlags, DWORD dwGroupID)
|
|
{
|
|
SPDATA_STARTSESSION ss;
|
|
LPDPLOBBYI_DPLOBJECT this = NULL;
|
|
LPDPLAYI_DPLAY lpDPObject = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPL_StartSession");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
|
|
lpDP, dwFlags, dwGroupID);
|
|
|
|
ENTER_LOBBY_ALL();
|
|
|
|
TRY
|
|
{
|
|
lpDPObject = DPLAY_FROM_INT(lpDP);
|
|
hr = VALID_DPLAY_PTR( lpDPObject );
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Bad DPlay interface pointer - hr = 0x%08lx\n",hr);
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
if(!IS_LOBBY_OWNED(lpDPObject))
|
|
{
|
|
DPF_ERR("SetGroupConnectionSettings is only supported for lobby connections");
|
|
hr = DPERR_UNSUPPORTED;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
this = lpDPObject->lpLobbyObject;
|
|
if(!VALID_DPLOBBY_PTR(this))
|
|
{
|
|
DPF_ERR("Bad DPLobby object");
|
|
hr = DPERR_INVALIDOBJECT;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
if(dwFlags)
|
|
{
|
|
DPF_ERR("Invalid flags");
|
|
hr = DPERR_INVALIDFLAGS;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
lpGroup = GroupFromID(lpDPObject, dwGroupID);
|
|
if (!VALID_DPLAY_GROUP(lpGroup))
|
|
{
|
|
DPF_ERR("Invalid group id");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
// Make sure the group is a staging area
|
|
if(!(lpGroup->dwFlags & DPLAYI_GROUP_STAGINGAREA))
|
|
{
|
|
DPF_ERR("StartSession can only be called on a Staging Area");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
}
|
|
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
hr = DPERR_INVALIDPARAMS;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
|
|
// Setup our SPDATA struct
|
|
memset(&ss, 0, sizeof(SPDATA_STARTSESSION));
|
|
ss.dwSize = sizeof(SPDATA_STARTSESSION);
|
|
ss.dwGroupID = dwGroupID;
|
|
ss.dwFlags = dwFlags;
|
|
|
|
// Call the StartSession method in the SP
|
|
if(CALLBACK_EXISTS(StartSession))
|
|
{
|
|
ss.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
|
|
// Drop the dplay lock so we can send a guarateed message
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
hr = CALL_LP(this, StartSession, &ss);
|
|
|
|
// Take the lock back
|
|
ENTER_LOBBY_ALL();
|
|
}
|
|
else
|
|
{
|
|
// StartSession is required
|
|
DPF_ERR("The Lobby Provider callback for StartSession doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
hr = DPERR_UNAVAILABLE;
|
|
goto ERROR_STARTSESSION;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed calling StartSession in the Lobby Provider, hr = 0x%08x", hr);
|
|
}
|
|
|
|
ERROR_STARTSESSION:
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPL_StartSession
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_CreateAndMapNewGroup"
|
|
HRESULT PRV_CreateAndMapNewGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
DPID * lpdpid, LPDPNAME lpName, LPVOID lpData,
|
|
DWORD dwDataSize, DWORD dwFlags, DWORD dwLobbyID,
|
|
DPID dpidParent, DWORD dwOwnerID)
|
|
{
|
|
LPDPLAYI_GROUP lpGroup = NULL, lpSysGroup = NULL;
|
|
HRESULT hr;
|
|
DPID dpidGroup, dpidSysPlayer;
|
|
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Make sure the lobby ID is valid
|
|
if(!IsValidLobbyID(dwLobbyID))
|
|
{
|
|
DPF_ERRVAL("ID %lu is reserved, cannot create new player", dwLobbyID);
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto EXIT_CREATEANDMAPNEWGROUP;
|
|
}
|
|
|
|
// If this is a remote player, we need allocate a new nametable entry
|
|
// for them and set the correct system player ID
|
|
if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
// Allocate a new ID for the player
|
|
hr = NS_AllocNameTableEntry(this->lpDPlayObject, &dpidGroup);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Unable to allocate new nametable id, hr = 0x%08x", hr);
|
|
goto EXIT_CREATEANDMAPNEWGROUP;
|
|
}
|
|
|
|
// Make sure we have a lobby system player (for all remote players
|
|
// & groups). If we don't then allocate a new one.
|
|
if(!(this->dpidSysPlayer))
|
|
{
|
|
hr = PRV_CreateAndMapNewPlayer(this, &dpidSysPlayer, NULL, NULL,
|
|
NULL, 0, DPLAYI_PLAYER_SYSPLAYER,
|
|
DPID_LOBBYREMOTESYSTEMPLAYER, TRUE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Unable to create lobby system player, hr = 0x%08x", hr);
|
|
ASSERT(FALSE);
|
|
goto EXIT_CREATEANDMAPNEWGROUP;
|
|
}
|
|
|
|
// Set the lobby system player ID pointer to the new ID
|
|
this->dpidSysPlayer = dpidSysPlayer;
|
|
}
|
|
}
|
|
|
|
// Get a group struct for the group (if it's local, this will add it
|
|
// to the nametable. If it's remote, we need to add it below)
|
|
hr = GetGroup(this->lpDPlayObject, &lpGroup, lpName, lpData,
|
|
dwDataSize, dwFlags, dpidParent, dwLobbyID);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed trying to add group to the nametable, hr = 0x%08x", hr);
|
|
goto EXIT_CREATEANDMAPNEWGROUP;
|
|
}
|
|
|
|
// Fixup the group's owner
|
|
lpGroup->dwOwnerID = dwOwnerID;
|
|
|
|
// If the group is remote, set the group's ID to the new one we
|
|
// allocated and then set the system group ID to the lobby system group
|
|
if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
//
|
|
lpGroup->dwIDSysPlayer = this->dpidSysPlayer;
|
|
|
|
// Add the group to the nametable
|
|
hr = AddItemToNameTable(this->lpDPlayObject, (DWORD_PTR)lpGroup,
|
|
&dpidGroup, TRUE, dwLobbyID);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Unable to add new group to the nametable, hr = 0x%08x", hr);
|
|
ASSERT(FALSE);
|
|
goto EXIT_CREATEANDMAPNEWGROUP;
|
|
}
|
|
|
|
// Set the group's ID
|
|
lpGroup->dwID = dpidGroup;
|
|
}
|
|
|
|
// Set the output dpid pointer
|
|
*lpdpid = lpGroup->dwID;
|
|
|
|
EXIT_CREATEANDMAPNEWGROUP:
|
|
|
|
LEAVE_DPLAY();
|
|
return hr;
|
|
|
|
} // PRV_CreateAndMapNewGroup
|