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
2694 lines
77 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dplsp.c
|
|
* Content: DirectPlayLobby Service Provider interface code
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======= ======= ======
|
|
* 10/23/96 myronth Created it
|
|
* 11/20/96 myronth Added DPLAPI to function declarations
|
|
* 2/12/97 myronth Mass DX5 changes
|
|
* 2/18/97 myronth Implemented GetObjectCaps
|
|
* 2/26/97 myronth #ifdef'd out DPASYNCDATA stuff (removed dependency)
|
|
* 3/31/97 myronth Implemented all IDPLobbySP methods without putting
|
|
* player management message in the message queue.
|
|
* Removed dead code
|
|
* 4/4/97 myronth Changed IDPLobbySP methods' structure names and
|
|
* implemented system messages for all of them
|
|
* 4/27/97 sohailm Updated calls to HandlePlayerMessage to reflect new params
|
|
* 5/8/97 myronth All remote subgroup functions for IDPLobbySP
|
|
* including StartSession, Purged dead code
|
|
* 5/12/97 myronth Extra semi-colon bug fixes, Fixed group player count
|
|
* decrement that was in the wrong place
|
|
* 5/14/97 myronth Allow CreateGroup message to pass even if the
|
|
* Group ID is in the map table (bug #8354).
|
|
* 5/17/97 myronth Fixed HandleMessage, Added SendChatMessage
|
|
* 5/17/97 myronth Filtered some message to certain groups, Fixed calls
|
|
* to CreateAndMapNewGroup which needed a parent ID
|
|
* 5/20/97 myronth Changed DPLP_DeleteRemotePlayerFromGroup to use
|
|
* InternalDeletePlayerFromGroup instead of
|
|
* RemovedPlayerFromGroup (now includes system player)
|
|
* (Bug #8586)
|
|
* 5/21/97 myronth Fixed the player name for players joining a session
|
|
* (#8798), Changed to new DPMSG_CHAT format (#8642)
|
|
* 5/22/97 myronth Fixed flag propagation in DPLP_CreateGroup (#8813)
|
|
* 5/23/97 myronth Send messages locally for CreateGroup and
|
|
* CreateGroupInGroup (#8870)
|
|
* 6/3/97 myronth Added support for player flags in AddPlayerToGroup
|
|
* (#9091) and added PRV_RemoveSubgroupsAndPlayers-
|
|
* FromGroup function (#9134)
|
|
* 6/5/97 myronth Fixed AddGroupToGroup & DeleteGroupFromGroup by
|
|
* adding heirarchy creating & deletion. (#8731)
|
|
* 6/6/97 myronth Moved code from PRV_DeleteRemoteGroupFromGroup to
|
|
* PRV_DestroyGroupAndParents in group.c, Changed all
|
|
* DistributeGroupMessage calls to go to all players
|
|
* 6/16/97 myronth Fixed call to InternalAddGroupToGroup (#9745) and
|
|
* fixed Delete messages for shortcuts on DestroyGroup
|
|
* (#9739)
|
|
* 6/20/97 myronth Changed AddGroupToGroup to check if a group exists
|
|
* and not send a duplicate message (#10139)
|
|
* 6/24/97 myronth Changed AddPlayerToGroup to check if a player exists
|
|
* and not send a duplicate message (#10287)
|
|
* 7/30/97 myronth Added support for standard lobby messaging
|
|
* 8/11/97 myronth Added guidInstance handling in standard lobby requests
|
|
* 8/19/97 myronth Removed bogus assert
|
|
* 9/29/97 myronth Ignore SetPlayerName/Data msgs for local players (#12554)
|
|
* 10/3/97 myronth Fixed player & group data for remote players/groups (#10961)
|
|
* 10/7/97 myronth Fixed LP version checking for player & group data (regresssion)
|
|
* 10/8/97 myronth Rolled back fix for #10961 (group & player data)
|
|
* 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 DPLP_SetGroupOwner
|
|
* 11/5/97 myronth Expose lobby ID's as DPID's in lobby sessions
|
|
* 11/6/97 myronth Made SendChatMessage handle a dwFromID of
|
|
* DPID_SERVERPLAYER (#12843)
|
|
* 11/19/97 myronth Fixed VALID_DPLAY_GROUP macro (#12841)
|
|
* 2/13/98 aarono changed InternalDeletePlayer, added flag.
|
|
* 8/30/00 aarono B#43812 improper construction of DATA CHANGED.
|
|
* in SendDataChangedLocally.
|
|
***************************************************************************/
|
|
#include "dplobpr.h"
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Functions
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SendBuildParentalHeirarchyMessage"
|
|
void PRV_SendBuildParentalHeirarchyMessage(LPDPLOBBYI_DPLOBJECT this,
|
|
DWORD dwGroupID, DWORD dwParentID)
|
|
{
|
|
SPDATA_BUILDPARENTALHEIRARCHY bph;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_SendBuildParentalHeirarchyMessage");
|
|
DPF(9, "Parameters: 0x%08x, %lu, %lu", this, dwGroupID, dwParentID);
|
|
|
|
// Setup the SPDATA structure
|
|
memset(&bph, 0, sizeof(SPDATA_BUILDPARENTALHEIRARCHY));
|
|
bph.dwSize = sizeof(SPDATA_BUILDPARENTALHEIRARCHY);
|
|
bph.lpISP = PRV_GetDPLobbySPInterface(this);
|
|
bph.dwGroupID = dwGroupID;
|
|
bph.dwMessage = DPSYS_ADDGROUPTOGROUP;
|
|
bph.dwParentID = dwParentID;
|
|
|
|
// Call the BuildParentalHeirarchy method in the SP
|
|
if(CALLBACK_EXISTS(BuildParentalHeirarchy))
|
|
{
|
|
// 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, BuildParentalHeirarchy, &bph);
|
|
ENTER_DPLOBBY();
|
|
}
|
|
else
|
|
{
|
|
// BuildParentalHeirarchy is required
|
|
DPF_ERR("The Lobby Provider callback for BuildParentalHeirarchy doesn't exist -- it's required");
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
} // PRV_SendBuildParentalHeirarchyMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_AddGroupToGroup"
|
|
HRESULT DPLAPI DPLP_AddGroupToGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_ADDREMOTEGROUPTOGROUP lpd)
|
|
{
|
|
SPDATA_CREATEREMOTEGROUPINGROUP cgig;
|
|
SPDATA_DESTROYREMOTEGROUP dg;
|
|
SPDATA_CREATEREMOTEGROUP cg;
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
LPDPLAYI_GROUP lpAnchor = NULL;
|
|
LPDPLAYI_SUBGROUP lpSubgroup = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
BOOL bCreated = FALSE;
|
|
|
|
|
|
DPF(7, "Entering DPLP_AddGroupToGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_ADDREMOTEGROUPTOGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwAnchorID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved AddGroupToGroup message for unknown anchor group, dwGroupID = %lu, discarding message", lpd->dwAnchorID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Now see if the group is in our map table. If it is, we
|
|
// probably want to update the name. If it's not, we need to
|
|
// add them to the nametable and the map table
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
// See if the group is a root group (remember hidden groups won't
|
|
// get pushed down to us). If it is, then just create it.
|
|
if(!(lpd->dwParentID))
|
|
{
|
|
// Setup the SPDATA struct for CreateRemoteGroup
|
|
memset(&cg, 0, sizeof(SPDATA_CREATEREMOTEGROUP));
|
|
cg.dwSize = sizeof(SPDATA_CREATEREMOTEGROUP);
|
|
cg.dwGroupID = lpd->dwGroupID;
|
|
cg.lpName = lpd->lpName;
|
|
cg.dwFlags = lpd->dwGroupFlags;
|
|
|
|
if(this->dwLPVersion > DPLSP_DX5VERSION)
|
|
cg.dwGroupOwnerID = lpd->dwGroupOwnerID;
|
|
else
|
|
cg.dwGroupOwnerID = DPID_SERVERPLAYER;
|
|
|
|
// Call our internal remote create
|
|
hr = DPLP_CreateGroup((LPDPLOBBYSP)this->lpInterfaces, &cg);
|
|
if(FAILED(hr))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERRVAL("Failed creating remote parent group, hr = 0x%08x", hr);
|
|
return hr;
|
|
}
|
|
|
|
bCreated = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// See if it's parent shows up in the map table, if it doesn't,
|
|
// we need to send a message to the server to tell it to build
|
|
// the entire tree for us
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
|
|
{
|
|
DPF(8, "Sending message to server to build parental heirarchy, ignoring AddGroupToGroup message");
|
|
PRV_SendBuildParentalHeirarchyMessage(this, lpd->dwGroupID,
|
|
lpd->dwAnchorID);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Setup the SPDATA struct for CreateRemoteGroupInGroup
|
|
memset(&cgig, 0, sizeof(SPDATA_CREATEREMOTEGROUPINGROUP));
|
|
cgig.dwSize = sizeof(SPDATA_CREATEREMOTEGROUPINGROUP);
|
|
cgig.dwParentID = lpd->dwParentID;
|
|
cgig.dwGroupID = lpd->dwGroupID;
|
|
cgig.lpName = lpd->lpName;
|
|
cgig.dwFlags = lpd->dwGroupFlags;
|
|
|
|
if(this->dwLPVersion > DPLSP_DX5VERSION)
|
|
cgig.dwGroupOwnerID = lpd->dwGroupOwnerID;
|
|
else
|
|
cgig.dwGroupOwnerID = DPID_SERVERPLAYER;
|
|
|
|
// Call our internal remote create
|
|
hr = DPLP_CreateGroupInGroup((LPDPLOBBYSP)this->lpInterfaces, &cgig);
|
|
if(FAILED(hr))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERRVAL("Failed creating remote group in group, hr = 0x%08x", hr);
|
|
return hr;
|
|
}
|
|
|
|
bCreated = TRUE;
|
|
}
|
|
}
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Make sure the group isn't already in the parent group. If it is,
|
|
// we just want to return DP_OK and exit so that we don't send any
|
|
// duplicate messages.
|
|
lpAnchor = GroupFromID(this->lpDPlayObject, lpd->dwAnchorID);
|
|
if(!lpAnchor)
|
|
{
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_ADDGROUPTOGROUP;
|
|
}
|
|
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_ADDGROUPTOGROUP;
|
|
}
|
|
|
|
lpSubgroup = lpAnchor->pSubgroups;
|
|
while(lpSubgroup)
|
|
{
|
|
if (lpSubgroup->pGroup == lpGroup)
|
|
{
|
|
DPF(2,"Group already in group!");
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_ADDGROUPTOGROUP;
|
|
}
|
|
// check next node
|
|
lpSubgroup = lpSubgroup->pNextSubgroup;
|
|
}
|
|
|
|
// So now we should have a valid group and valid player in both
|
|
// the map table and the nametable, so call dplay's AGtoG function
|
|
hr = InternalAddGroupToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwAnchorID, lpd->dwGroupID, DPGROUP_SHORTCUT, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
// If we created the player and mapped it, then destroy the
|
|
// player and unmap it.
|
|
if(bCreated)
|
|
{
|
|
// Setup the SPDATA struct for DestroyRemoteGroup
|
|
memset(&dg, 0, sizeof(SPDATA_DESTROYREMOTEGROUP));
|
|
dg.dwSize = sizeof(SPDATA_DESTROYREMOTEGROUP);
|
|
dg.dwGroupID = lpd->dwGroupID;
|
|
|
|
// Call our internal remote create
|
|
hr = DPLP_DestroyGroup((LPDPLOBBYSP)this->lpInterfaces, &dg);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed destroying remote group, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_ADDGROUPTOGROUP;
|
|
}
|
|
}
|
|
|
|
// If we failed, don't send the system message
|
|
DPF_ERRVAL("Failed adding remote group to group from the lobby, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_ADDGROUPTOGROUP;
|
|
}
|
|
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_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 = lpd->dwGroupID;
|
|
msg.dwGroupID = lpd->dwAnchorID;
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
ERROR_DPLP_ADDGROUPTOGROUP:
|
|
|
|
// Drop the lock
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPLP_AddGroupToGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_AddPlayerToGroup"
|
|
HRESULT DPLAPI DPLP_AddPlayerToGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_ADDREMOTEPLAYERTOGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
DPID dpidPlayer;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg, cpmsg;
|
|
BOOL bCreated = FALSE;
|
|
DWORD dwPlayerFlags = 0;
|
|
|
|
|
|
DPF(7, "Entering DPLP_AddPlayerToGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_ADDREMOTEPLAYERTOGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved AddPlayerToGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Fix up the player flags
|
|
if(lpd->dwPlayerFlags & DPPLAYER_SPECTATOR)
|
|
dwPlayerFlags |= DPLAYI_PLAYER_SPECTATOR;
|
|
if(lpd->dwPlayerFlags & DPPLAYER_SERVERPLAYER)
|
|
dwPlayerFlags |= DPLAYI_PLAYER_APPSERVER;
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// Now see if the player is in our map table. If it is, we
|
|
// probably want to update the name. If it's not, we need to
|
|
// add them to the nametable and the map table
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
|
|
{
|
|
// It doesn't show up in our map table, so create a new
|
|
// nametable entry for them and put them in our map table.
|
|
hr = PRV_CreateAndMapNewPlayer(this, &dpidPlayer, lpd->lpName,
|
|
NULL, NULL, 0, dwPlayerFlags,
|
|
lpd->dwPlayerID, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Unable to add player to nametable or map table, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
bCreated = TRUE;
|
|
}
|
|
|
|
// Make sure the player isn't already in the group. If it is,
|
|
// we just want to return DP_OK and exit so that we don't send any
|
|
// duplicate messages.
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
DPF_ERR("Unable to find group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
|
|
if(!lpPlayer)
|
|
{
|
|
DPF_ERR("Unable to find player in nametable");
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
lpGroupnode = lpGroup->pGroupnodes;
|
|
while(lpGroupnode)
|
|
{
|
|
if(lpGroupnode->pPlayer == lpPlayer)
|
|
{
|
|
DPF(2, "Player already in group!");
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
// check next node
|
|
lpGroupnode = lpGroupnode->pNextGroupnode;
|
|
}
|
|
|
|
// So now we should have a valid group and valid player in both
|
|
// the map table and the nametable, so call dplay with the add message
|
|
hr = InternalAddPlayerToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwGroupID, lpd->dwPlayerID, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
// If we created the player and mapped it, then destroy the
|
|
// player and unmap it.
|
|
if(bCreated)
|
|
{
|
|
// Remove the player from the nametable
|
|
InternalDestroyPlayer(this->lpDPlayObject, lpPlayer, FALSE, FALSE);
|
|
}
|
|
|
|
// If we failed, don't send the system message
|
|
DPF_ERRVAL("Failed adding remote player to group from the lobby, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_ADDPLAYER;
|
|
}
|
|
|
|
// If we created this player, we need to send a CreatePlayer message ahead
|
|
// of the AddPlayerToGroup message
|
|
if(bCreated)
|
|
{
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&cpmsg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&cpmsg);
|
|
SET_MESSAGE_COMMAND(&cpmsg, DPSP_MSG_CREATEPLAYER);
|
|
cpmsg.dwPlayerID = lpd->dwPlayerID;
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&cpmsg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding CreatePlayer message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
// Now build the system message for AddPlayerToGroup
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_ADDPLAYERTOGROUP);
|
|
msg.dwPlayerID = lpd->dwPlayerID;
|
|
msg.dwGroupID = lpd->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);
|
|
}
|
|
|
|
// We need to see if this player is the group owner. If it is,
|
|
// we need to send a SetGroupOwner message as well.
|
|
if(lpd->dwPlayerID == lpGroup->dwOwnerID)
|
|
{
|
|
// Now send the message
|
|
PRV_SendGroupOwnerMessageLocally(this, lpd->dwGroupID,
|
|
lpd->dwPlayerID, 0);
|
|
}
|
|
|
|
ERROR_DPLP_ADDPLAYER:
|
|
|
|
// Drop the lock
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPLP_AddPlayerToGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_CreateGroup"
|
|
HRESULT DPLAPI DPLP_CreateGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_CREATEREMOTEGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
DPID dpidGroup;
|
|
DWORD dwInternalFlags = 0;
|
|
DWORD dwOwnerID;
|
|
|
|
|
|
DPF(7, "Entering DPLP_CreateGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_CREATEREMOTEGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Fix the flags from external to internal
|
|
if(lpd->dwFlags & DPGROUP_STAGINGAREA)
|
|
dwInternalFlags = DPLAYI_GROUP_STAGINGAREA;
|
|
if(lpd->dwFlags & DPGROUP_HIDDEN)
|
|
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// First see if the group is in our map table. If it is,
|
|
// we just want to return. If it's not, we want to add
|
|
// them and send the appropriate message
|
|
if(IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
DPF(2, "Received a CreateGroup message for a group we already know about");
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_CREATEGROUP;
|
|
}
|
|
else
|
|
{
|
|
// Make the owner default to the server player if we have a problem
|
|
dwOwnerID = DPID_SERVERPLAYER;
|
|
|
|
// If we are talking to at least a DX6 lobby provider, we should
|
|
// be able to use the GroupOwnerID element
|
|
if(this->dwLPVersion > DPLSP_DX5VERSION)
|
|
dwOwnerID = lpd->dwGroupOwnerID;
|
|
|
|
// Create a new entry in the nametable and map the ID's
|
|
hr = PRV_CreateAndMapNewGroup(this, &dpidGroup, lpd->lpName,
|
|
lpd->lpData, lpd->dwDataSize, dwInternalFlags,
|
|
lpd->dwGroupID, 0, dwOwnerID);
|
|
if(FAILED(hr))
|
|
{
|
|
// If we fail, we don't want to send the system message
|
|
DPF_ERRVAL("Unable to add group to nametable or map table, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_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 = lpd->dwGroupID;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_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(8, "Failed adding CreateGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
ERROR_DPLP_CREATEGROUP:
|
|
|
|
// Drop the lock
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPLP_CreateGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_CreateGroupInGroup"
|
|
HRESULT DPLAPI DPLP_CreateGroupInGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_CREATEREMOTEGROUPINGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
DPID dpidGroup;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
BOOL bCreated = FALSE;
|
|
DWORD dwInternalFlags = 0;
|
|
DWORD dwOwnerID;
|
|
|
|
|
|
DPF(7, "Entering DPLP_CreateGroupInGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_CREATEREMOTEGROUPINGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERRVAL("Recieved CreateGroupInGroup message for unknown parent group, dwGroupID = %lu, discarding message", lpd->dwParentID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Take the dplay lock
|
|
ENTER_DPLAY();
|
|
|
|
// First see if the group is in our map table. If it is,
|
|
// we just want to return. If it's not, we want to add
|
|
// them and send the appropriate message
|
|
if(IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
DPF(2, "Received a CreateGroupInGroup message for a group we already know about");
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_CREATEGROUPINGROUP;
|
|
}
|
|
else
|
|
{
|
|
// Setup the internal flags
|
|
if(lpd->dwFlags & DPGROUP_STAGINGAREA)
|
|
dwInternalFlags = DPLAYI_GROUP_STAGINGAREA;
|
|
if(lpd->dwFlags & DPGROUP_HIDDEN)
|
|
dwInternalFlags |= DPLAYI_GROUP_HIDDEN;
|
|
|
|
// Make the owner default to the server player if we have a problem
|
|
dwOwnerID = DPID_SERVERPLAYER;
|
|
|
|
// If we are talking to at least a DX6 lobby provider, we should
|
|
// be able to use the GroupOwnerID element
|
|
if(this->dwLPVersion > DPLSP_DX5VERSION)
|
|
dwOwnerID = lpd->dwGroupOwnerID;
|
|
|
|
// It doesn't show up in our map table, so create a new
|
|
// nametable entry for them and put them in our map table.
|
|
hr = PRV_CreateAndMapNewGroup(this, &dpidGroup, lpd->lpName,
|
|
NULL, 0, dwInternalFlags,
|
|
lpd->dwGroupID, lpd->dwParentID, dwOwnerID);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Unable to add group to nametable or map table, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_CREATEGROUPINGROUP;
|
|
}
|
|
|
|
bCreated = TRUE;
|
|
}
|
|
|
|
// So now we should have a valid group and valid player in both
|
|
// the map table and the nametable, so call dplay with the add message
|
|
hr = InternalAddGroupToGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwParentID, lpd->dwGroupID, lpd->dwFlags, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
// If we created the player and mapped it, then destroy the
|
|
// player and unmap it.
|
|
if(bCreated)
|
|
{
|
|
// Get a pointer to dplay's group struct
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
|
|
// Remove the group from the nametable
|
|
if(lpGroup){
|
|
InternalDestroyGroup(this->lpDPlayObject, lpGroup, FALSE);
|
|
}
|
|
}
|
|
|
|
// If we failed, don't send the system message
|
|
DPF_ERRVAL("Failed creating remote group in group from the lobby, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_CREATEGROUPINGROUP;
|
|
}
|
|
|
|
|
|
// 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 = lpd->dwGroupID;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_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(8, "Failed adding CreateGroupInGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
|
|
ERROR_DPLP_CREATEGROUPINGROUP:
|
|
|
|
// Drop the lock
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPLP_CreateGroupInGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DeleteRemoteGroupFromGroup"
|
|
HRESULT PRV_DeleteRemoteGroupFromGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
LPSPDATA_DELETEREMOTEGROUPFROMGROUP lpd, BOOL fPropagate,
|
|
LPDPLAYI_GROUP lpStopParent)
|
|
{
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL, lpParentGroup = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_DeleteRemoteGroupFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu, 0x%08x",
|
|
this, lpd, fPropagate, lpStopParent);
|
|
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwParentID))
|
|
{
|
|
DPF(8, "Recieved DeleteGroupFromGroup message for unknown parent group, dwGroupID = %lu, discarding message", lpd->dwParentID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Now make sure the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we don't know about.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
DPF(8, "Recieved DeleteGroupFromGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Get dplay's internal group structures
|
|
lpParentGroup = GroupFromID(this->lpDPlayObject, lpd->dwParentID);
|
|
if(!lpParentGroup)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF(8, "Unable to find parent group in nametable");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF(8, "Unable to find group in nametable");
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Call dplay's internal removegroupfromgroup to remove the attachment
|
|
// in the nametable
|
|
hr = RemoveGroupFromGroup(lpParentGroup, lpGroup);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed removing group from group, hr = 0x%08x", hr);
|
|
goto EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP;
|
|
}
|
|
|
|
// If the fPropagate flag is not set, we don't want to send this message
|
|
if(fPropagate)
|
|
{
|
|
// 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 = lpd->dwGroupID;
|
|
msg.dwGroupID = lpd->dwParentID;
|
|
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF(8, "Unable to find system group in nametable");
|
|
goto EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
// Even if we couldn't send the message above, destroy the group anyway
|
|
|
|
EXIT_DPLP_DELETEREMOTEGROUPFROMGROUP:
|
|
|
|
// Destroy the group and any of it's parents if there are no more local
|
|
// references to it or any of it's heirarchy
|
|
PRV_DestroyGroupAndParents(this, lpGroup, lpStopParent);
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
return hr;
|
|
|
|
} // PRV_DeleteRemoteGroupFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_DeleteGroupFromGroup"
|
|
HRESULT DPLAPI DPLP_DeleteGroupFromGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_DELETEREMOTEGROUPFROMGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPLP_DeleteGroupFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_DELETEREMOTEGROUPFROMGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Call our internal routine, setting the propagate flag to TRUE so that
|
|
// we post the appropriate message in the player's receive queue
|
|
hr = PRV_DeleteRemoteGroupFromGroup(this, lpd, TRUE, NULL);
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // DPLP_DeleteGroupFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_DeleteRemotePlayerFromGroup"
|
|
HRESULT PRV_DeleteRemotePlayerFromGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
LPSPDATA_DELETEREMOTEPLAYERFROMGROUP lpd, BOOL fPropagate)
|
|
{
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
MSG_PLAYERMGMTMESSAGE msg, dpmsg;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_DeleteRemotePlayerFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu", this, lpd, fPropagate);
|
|
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
DPF(8, "Recieved DeletePlayerFromGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Now make sure the player is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// player we don't know about.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
|
|
{
|
|
DPF(8, "Recieved DeletePlayerFromGroup message for unknown player, dwPlayerID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDPLAYER;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Call dplay's internal removeplayerfromgroup to remove the attachment
|
|
// in the nametable
|
|
hr = InternalDeletePlayerFromGroup((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwGroupID, lpd->dwPlayerID, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed removing player from group, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// If the fPropagate flag is not set, we don't want to send this message
|
|
if(fPropagate)
|
|
{
|
|
// 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 = lpd->dwPlayerID;
|
|
msg.dwGroupID = lpd->dwGroupID;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// 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 DeletePlayerFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
// Get dplay's internal group & player structures
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
|
|
if(!lpPlayer)
|
|
{
|
|
// So if this fails, the above call to InternalDeletePlayerFromGroup
|
|
// shouldn't have succeeded either
|
|
DPF_ERR("Unable to find player in nametable");
|
|
ASSERT(FALSE);
|
|
goto ERROR_DPLP_DELETEPLAYERFROMGROUP;
|
|
}
|
|
|
|
// Now we need to decide if this is the last group this player was in. If
|
|
// it is, then we need to destroy the player as well, and remove them from
|
|
// our map table. Of course, only destroy the player if it is a remote player.
|
|
if((!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)) &&
|
|
(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERINGROUP)))
|
|
{
|
|
// However, before we do this, we need to send a DestroyPlayer
|
|
// message to all the people who got the DeletePlayerFromGroup
|
|
if(lpGroupTo && fPropagate)
|
|
{
|
|
// Now build the system message (at least the parts we need)
|
|
memset(&dpmsg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&dpmsg);
|
|
SET_MESSAGE_COMMAND(&dpmsg, DPSP_MSG_DELETEPLAYER);
|
|
dpmsg.dwPlayerID = lpd->dwPlayerID;
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&dpmsg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding DestroyPlayer message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
// Destroy the player and remove it from the nametable
|
|
InternalDestroyPlayer(this->lpDPlayObject, lpPlayer, FALSE, FALSE);
|
|
}
|
|
|
|
|
|
ERROR_DPLP_DELETEPLAYERFROMGROUP:
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
return hr;
|
|
|
|
} // PRV_DeleteRemotePlayerFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_DeletePlayerFromGroup"
|
|
HRESULT DPLAPI DPLP_DeletePlayerFromGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_DELETEREMOTEPLAYERFROMGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPLP_DeletePlayerFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_DELETEREMOTEPLAYERFROMGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Call our internal routine, setting the propagate flag to TRUE so that
|
|
// we post the appropriate message in the player's receive queue
|
|
hr = PRV_DeleteRemotePlayerFromGroup(this, lpd, TRUE);
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // DPLP_DeletePlayerFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_BroadcastDestroyGroupMessage"
|
|
HRESULT DPLAPI PRV_BroadcastDestroyGroupMessage(LPDPLOBBYI_DPLOBJECT this,
|
|
DWORD dwGroupID)
|
|
{
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
// 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_DELETEGROUP);
|
|
msg.dwGroupID = dwGroupID;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERR("Unable to find system group in nametable");
|
|
hr = DPERR_INVALIDGROUP;
|
|
}
|
|
else
|
|
{
|
|
// Call dplay's DistributeGroupMessage function to put the message in the queue
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)&msg, sizeof(MSG_PLAYERMGMTMESSAGE), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding DestroyGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // PRV_BroadcastDestroyGroupMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_RemoveSubgroupsAndPlayersFromGroup"
|
|
void PRV_RemoveSubgroupsAndPlayersFromGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLAYI_GROUP lpGroup, DWORD dwGroupID, BOOL bRemoteOnly)
|
|
{
|
|
SPDATA_DELETEREMOTEPLAYERFROMGROUP dpd;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
LPDPLAYI_GROUPNODE lpNextGroupnode = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering PRV_RemoveSubgroupsAndPlayersFromGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
|
|
|
|
ASSERT(lpGroup);
|
|
|
|
// Destroy any subgroups hanging off of this group
|
|
PRV_DestroySubgroups(this, lpGroup, bRemoteOnly);
|
|
|
|
// Walk the list of nodes, removing each player from the group manually.
|
|
// The reason for doing this manually is so that the lobby gets a chance
|
|
// to remove every remote player out of the nametable whose only existence
|
|
// was inside this room. It also allows the lobby to remove the player's
|
|
// ID from the map table. Do this by calling the lobby's
|
|
// DPLP_DeletePlayerFromGroup function which responds to that message.
|
|
|
|
// Setup the DeletePlayerFromGroup data structure
|
|
memset(&dpd, 0, sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP));
|
|
dpd.dwSize = sizeof(SPDATA_DELETEREMOTEPLAYERFROMGROUP);
|
|
dpd.dwGroupID = dwGroupID;
|
|
|
|
// Walk the list of groupnodes, deleting all of the remote players
|
|
lpGroupnode = lpGroup->pGroupnodes;
|
|
while(lpGroupnode)
|
|
{
|
|
// Save the next groupnode
|
|
lpNextGroupnode = lpGroupnode->pNextGroupnode;
|
|
|
|
// If the player is local, skip them
|
|
if(lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)
|
|
{
|
|
lpGroupnode = lpNextGroupnode;
|
|
continue;
|
|
}
|
|
|
|
// Get the lobby ID for the player
|
|
dpd.dwPlayerID = lpGroup->pGroupnodes->pPlayer->dwID;
|
|
|
|
// Now call the lobby's delete function, setting the fPropagate flag
|
|
// to true so we put a delete message in the player's queue
|
|
hr = PRV_DeleteRemotePlayerFromGroup(this, &dpd, TRUE);
|
|
if(FAILED(hr))
|
|
{
|
|
// Same here, if this fails, something is tragically wrong
|
|
// with the map table, so just continue;
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
// Move to the next node
|
|
lpGroupnode = lpNextGroupnode;
|
|
}
|
|
|
|
} // PRV_RemoveSubgroupsAndPlayersFromGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SendDeleteShortcutMessageForExitingGroup"
|
|
void PRV_SendDeleteShortcutMessageForExitingGroup(LPDPLOBBYI_DPLOBJECT this,
|
|
LPDPLAYI_GROUP lpGroup)
|
|
{
|
|
MSG_PLAYERMGMTMESSAGE msg;
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
LPDPLAYI_GROUP lpGroupTemp = NULL;
|
|
LPDPLAYI_SUBGROUP lpSubgroupTemp = NULL;
|
|
UINT nGroupsIn;
|
|
HRESULT hr;
|
|
|
|
|
|
DPF(7, "Entering PRV_SendDeleteShortcutMessageForExitingGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", this, lpGroup);
|
|
|
|
// Take the dplay lock since we will be walking dplay's group list
|
|
ENTER_DPLAY();
|
|
|
|
// Get the number of subgroups this group is in
|
|
nGroupsIn = lpGroup->nGroups;
|
|
|
|
// Setup the static parts of the message, and get a pointer to the system group
|
|
if(nGroupsIn)
|
|
{
|
|
// Build the message struct
|
|
memset(&msg, 0, sizeof(MSG_PLAYERMGMTMESSAGE));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_DELETEGROUPFROMGROUP);
|
|
msg.dwPlayerID = lpGroup->dwID;
|
|
|
|
// Get a pointer to the system group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Unable to get a pointer to the system group - not sending deletegroupfromgroup messages");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Walk the list of groups, and send a DeleteGroupFromGroup message
|
|
// for each shortcut
|
|
lpGroupTemp = this->lpDPlayObject->pGroups;
|
|
while(nGroupsIn && lpGroupTemp)
|
|
{
|
|
// Walk the list of subgroups for the group
|
|
lpSubgroupTemp = lpGroupTemp->pSubgroups;
|
|
while(nGroupsIn && lpSubgroupTemp)
|
|
{
|
|
// If the group is our group, send a message, but only if
|
|
// it is not the parent group (since we will never do a
|
|
// DeleteGroupFromGroup on a parent-child)
|
|
if(lpSubgroupTemp->pGroup == lpGroup)
|
|
{
|
|
// Make sure it's not the group's parent
|
|
if(lpGroup->dwIDParent != lpGroupTemp->dwID)
|
|
{
|
|
// Send the message
|
|
msg.dwGroupID = lpGroupTemp->dwID;
|
|
|
|
// 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 DeleteGroupFromGroup message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
}
|
|
|
|
// Decrement the count of subgroups
|
|
nGroupsIn--;
|
|
}
|
|
|
|
// Move to the next subgroup
|
|
lpSubgroupTemp = lpSubgroupTemp->pNextSubgroup;
|
|
}
|
|
|
|
// Move to the next group
|
|
lpGroupTemp = lpGroupTemp->pNextGroup;
|
|
}
|
|
|
|
ASSERT(!nGroupsIn);
|
|
|
|
// Drop the dplay lock since we're done
|
|
LEAVE_DPLAY();
|
|
|
|
} // PRV_SendDeleteShortcutMessageForExitingGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_DestroyGroup"
|
|
HRESULT DPLAPI DPLP_DestroyGroup(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_DESTROYREMOTEGROUP lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
LPDPLAYI_GROUPNODE lpGroupNode = NULL;
|
|
|
|
|
|
DPF(7, "Entering DPLP_DestroyGroup");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_DESTROYGROUP structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// First see if the group is in our map table. If it's not,
|
|
// we should just ignore this message because it's for a
|
|
// group we are not currently in.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved DestroyGroup message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// This is either a group we are in, or it is a root group. If it has
|
|
// any players, it's a group we are in, so we need to delete all remote
|
|
// players from the nametable and map table (if this is the only group
|
|
// they are in).
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// So, get dplay's internal group structure
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
// If we don't have an lpGroup, we need to fail because some of
|
|
// the functions below will crash if lpGroup is invalid.
|
|
DPF(8, "Unable to find group in nametable, dpidGroup = %lu", lpd->dwGroupID);
|
|
LEAVE_LOBBY_ALL();
|
|
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 remote subgroups and players
|
|
PRV_RemoveSubgroupsAndPlayersFromGroup(this, lpGroup, lpd->dwGroupID, FALSE);
|
|
|
|
// Now send a DestroyGroup system message to all the local players
|
|
hr = PRV_BroadcastDestroyGroupMessage(this, lpd->dwGroupID);
|
|
|
|
// Now call dplay's destroy group
|
|
hr = InternalDestroyGroup(this->lpDPlayObject, lpGroup, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed destroying group from nametable, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Drop the locks
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
return hr;
|
|
|
|
} // DPLP_DestroyGroup
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_GetSPDataPointer"
|
|
HRESULT DPLAPI DPLP_GetSPDataPointer(LPDPLOBBYSP lpDPLSP, LPVOID * lplpData)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
|
|
|
|
// Make sure the SP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpDPLSP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Go ahead and save the pointer
|
|
*lplpData = this->lpSPData;
|
|
|
|
return DP_OK;
|
|
|
|
} // DPLP_GetSPDataPointer
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_HandleLobbySystemMessage"
|
|
HRESULT PRV_HandleLobbySystemMessage(LPDPLOBBYI_DPLOBJECT this,
|
|
LPSPDATA_HANDLEMESSAGE lpd)
|
|
{
|
|
LPDPLMSG_GENERIC lpmsg = lpd->lpBuffer;
|
|
LPDPLMSG_GETPROPERTYRESPONSE lpgpr = NULL;
|
|
LPDPLOBBYI_REQUESTNODE lprn = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
// If it's a property message, we need to deal with the request
|
|
switch(lpmsg->dwType)
|
|
{
|
|
case DPLSYS_GETPROPERTYRESPONSE:
|
|
case DPLSYS_SETPROPERTYRESPONSE:
|
|
{
|
|
// Cast it to a GetPropertyResponse message
|
|
lpgpr = (LPDPLMSG_GETPROPERTYRESPONSE)lpmsg;
|
|
|
|
// Find the request ID in our list of pending requests
|
|
lprn = this->lprnHead;
|
|
while(lprn)
|
|
{
|
|
if(lprn->dwRequestID == lpgpr->dwRequestID)
|
|
break;
|
|
else
|
|
lprn = lprn->lpNext;
|
|
}
|
|
|
|
// Print some debug spew if we didn't find it, but return DP_OK since
|
|
// we "handled" the message
|
|
if(!lprn)
|
|
{
|
|
DPF(5, "Unable to find request ID in pending request list");
|
|
return DP_OK;
|
|
}
|
|
|
|
// See if we slammed the guid, and replace it with GUID_NULL if we did
|
|
if(lprn->dwFlags & GN_SLAMMED_GUID)
|
|
lpgpr->guidPlayer = GUID_NULL;
|
|
|
|
// If we found it, swap out the request ID, and send it to the
|
|
// appropriate place
|
|
lpgpr->dwRequestID = lprn->dwAppRequestID;
|
|
if(lprn->dwFlags & GN_SELF_LOBBIED)
|
|
{
|
|
// Put the message in the lobby message receive queue
|
|
hr = PRV_InjectMessageInQueue(lprn->lpgn, DPLMSG_STANDARD,
|
|
lpgpr, lpd->dwBufSize, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed to put message in lobby receive queue, hr = 0x%08x", hr);
|
|
goto EXIT_HANDLELOBBYSYSTEMMESSAGE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Call SendLobbyMessage to send the message to the game
|
|
hr = PRV_WriteClientData(lprn->lpgn, DPLMSG_STANDARD,
|
|
lpgpr, lpd->dwBufSize);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed to forward message to game, hr = 0x%08x", hr);
|
|
goto EXIT_HANDLELOBBYSYSTEMMESSAGE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
EXIT_HANDLELOBBYSYSTEMMESSAGE:
|
|
|
|
// Remove the pending request node if we serviced it (which would have
|
|
// happened if we have a valid pointer to it)
|
|
if(lprn)
|
|
PRV_RemoveRequestNode(this, lprn);
|
|
|
|
return hr;
|
|
|
|
} // PRV_HandleLobbySystemMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_HandleMessage"
|
|
HRESULT DPLAPI DPLP_HandleMessage(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_HANDLEMESSAGE lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
LPMSG_PLAYERMESSAGE lpmsg = NULL;
|
|
LPBYTE lpByte = NULL;
|
|
DWORD dwSize;
|
|
BOOL bAllocBuffer = FALSE;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
|
|
|
|
DPF(7, "Entering DPLP_HandleMessage");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_HANDLEMESSAGE structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// If the message is a lobby system message, process it
|
|
// NOTE: Make sure the size of the SPDATA_HANDLEMESSAGE is big enough
|
|
// to contain a flags field (the shipping 5.0 bits did not have
|
|
// this field, but the 5.1 bits did).
|
|
if((lpd->dwSize > DPLOBBYPR_SIZE_HANDLEMESSAGE_DX50) &&
|
|
(lpd->dwFlags & DPSEND_LOBBYSYSTEMMESSAGE))
|
|
{
|
|
hr = PRV_HandleLobbySystemMessage(this, lpd);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Unable to handle lobby system message, hr = 0x%08x", hr);
|
|
}
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
}
|
|
|
|
// REVIEW!!!! -- We should be able to handle a generic send to a group
|
|
// as well as a player. Currently, I don't think we do.
|
|
|
|
// If this session is using naked messages, we can just send the buffer.
|
|
// Otherwise, we need to allocate a MSG_PLAYERMESSAGE struct and fill
|
|
// in the header.
|
|
if(this->lpDPlayObject->lpsdDesc->dwFlags & DPSESSION_NOMESSAGEID)
|
|
{
|
|
lpmsg = lpd->lpBuffer;
|
|
dwSize = lpd->dwBufSize;
|
|
}
|
|
else
|
|
{
|
|
// Calculate the size of the message
|
|
dwSize = sizeof(MSG_PLAYERMESSAGE) + lpd->dwBufSize;
|
|
|
|
// Allocate memory for a message buffer
|
|
lpmsg = DPMEM_ALLOC(dwSize);
|
|
if(!lpmsg)
|
|
{
|
|
DPF_ERR("Unable to allocate temporary message buffer");
|
|
hr = DPERR_OUTOFMEMORY;
|
|
goto ERROR_DPLP_HANDLEMESSAGE;
|
|
}
|
|
|
|
// Copy in the message header
|
|
lpmsg->idFrom = lpd->dwFromID;
|
|
lpmsg->idTo = lpd->dwToID;
|
|
|
|
// Copy in the message
|
|
lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERMESSAGE);
|
|
memcpy(lpByte, lpd->lpBuffer, lpd->dwBufSize);
|
|
|
|
// Set our flag indicating that we allocated a buffer
|
|
bAllocBuffer = TRUE;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Find dplay's internal player struct for the To player
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwToID);
|
|
if(!lpPlayer)
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERRVAL("Unable to find player in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto ERROR_DPLP_HANDLEMESSAGE;
|
|
}
|
|
|
|
// Call dplay's handleplayermessage function to put the message in the queue
|
|
hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg, dwSize, TRUE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
|
|
ERROR_DPLP_HANDLEMESSAGE:
|
|
if(bAllocBuffer && lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // DPLP_HandleMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SendChatMessage"
|
|
HRESULT DPLAPI DPLP_SendChatMessage(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_CHATMESSAGE lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
LPMSG_CHAT lpmsg = NULL;
|
|
LPBYTE lpByte = NULL;
|
|
DWORD dwSize;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
DWORD dwStringSize;
|
|
BOOL bToGroup = FALSE;
|
|
|
|
|
|
|
|
DPF(7, "Entering DPLP_SendChatMessage");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_HANDLEMESSAGE structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// Calculate the size of the message
|
|
dwStringSize = WSTRLEN_BYTES(lpd->lpChat->lpszMessage);
|
|
dwSize = sizeof(MSG_CHAT) + dwStringSize;
|
|
|
|
// Allocate memory for a message buffer
|
|
lpmsg = DPMEM_ALLOC(dwSize);
|
|
if(!lpmsg)
|
|
{
|
|
DPF_ERR("Unable to allocate temporary message buffer");
|
|
hr = DPERR_OUTOFMEMORY;
|
|
goto ERROR_DPLP_SENDCHATMESSAGE;
|
|
}
|
|
|
|
// Copy in the message header
|
|
SET_MESSAGE_HDR(lpmsg);
|
|
SET_MESSAGE_COMMAND(lpmsg,DPSP_MSG_CHAT);
|
|
lpmsg->dwIDFrom = lpd->dwFromID;
|
|
lpmsg->dwIDTo = lpd->dwToID;
|
|
lpmsg->dwFlags = lpd->lpChat->dwFlags;
|
|
lpmsg->dwMessageOffset = sizeof(MSG_CHAT);
|
|
|
|
// Copy in the message
|
|
lpByte = (LPBYTE)lpmsg + sizeof(MSG_CHAT);
|
|
memcpy(lpByte, lpd->lpChat->lpszMessage, dwStringSize);
|
|
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Make sure it's from a valid player or the server player
|
|
if(lpd->dwFromID != DPID_SERVERPLAYER)
|
|
{
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwFromID);
|
|
if(!VALID_DPLAY_PLAYER(lpPlayer))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Received chat message FROM invalid player id!!");
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto ERROR_DPLP_SENDCHATMESSAGE;
|
|
}
|
|
}
|
|
|
|
// See who the message is for
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwToID);
|
|
if(!VALID_DPLAY_PLAYER(lpPlayer))
|
|
{
|
|
// See if it's to a group
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwToID);
|
|
if(!VALID_DPLAY_GROUP(lpGroup))
|
|
{
|
|
LEAVE_DPLAY();
|
|
DPF_ERR("Received chat message for invalid player / group");
|
|
hr = DPERR_INVALIDPLAYER;
|
|
goto ERROR_DPLP_SENDCHATMESSAGE;
|
|
}
|
|
bToGroup = TRUE;
|
|
}
|
|
|
|
// Send it out
|
|
if(bToGroup)
|
|
{
|
|
// Send the message
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroup,
|
|
(LPBYTE)lpmsg, dwSize, FALSE, 0);
|
|
}
|
|
else
|
|
{
|
|
// Send the message
|
|
hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg, dwSize, FALSE, 0);
|
|
}
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
|
|
ERROR_DPLP_SENDCHATMESSAGE:
|
|
if(lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // DPLP_SendChatMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SendDataChangedMessageLocally"
|
|
HRESULT PRV_SendDataChangedMessageLocally(LPDPLOBBYI_DPLOBJECT this,
|
|
DPID dpidPlayer, LPVOID lpData, DWORD dwDataSize)
|
|
{
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
LPMSG_PLAYERDATA lpmsg = NULL;
|
|
LPBYTE lpByte = NULL;
|
|
DWORD dwSize;
|
|
|
|
|
|
DPF(7, "Entering PRV_SendDataChangedMessageLocally");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu",
|
|
this, dpidPlayer, lpData, dwDataSize);
|
|
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Setup the message to put in the player's queue
|
|
// Calculate the size of the message
|
|
dwSize = sizeof(MSG_PLAYERDATA) + dwDataSize;
|
|
|
|
// Allocate memory for the message
|
|
lpmsg = DPMEM_ALLOC(dwSize);
|
|
if(!lpmsg)
|
|
{
|
|
DPF_ERR("Unable to allocate memory for temporary message structure");
|
|
// Since the name has been changed, we'll just return success here
|
|
hr = DP_OK;
|
|
goto EXIT_SENDDATACHANGED;
|
|
}
|
|
|
|
// Now build the system message
|
|
SET_MESSAGE_HDR(lpmsg);
|
|
SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_PLAYERDATACHANGED);
|
|
lpmsg->dwPlayerID = dpidPlayer;
|
|
lpmsg->dwDataSize = dwDataSize;
|
|
lpmsg->dwDataOffset = sizeof(MSG_PLAYERDATA);
|
|
|
|
// Copy in the data
|
|
lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERDATA);
|
|
memcpy(lpByte, lpData, dwDataSize);
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_SENDDATACHANGED;
|
|
}
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)lpmsg, dwSize, FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding SetGroupData message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
EXIT_SENDDATACHANGED:
|
|
|
|
// Free our message
|
|
if(lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
return hr;
|
|
|
|
} // PRV_SendDataChangedMessageLocally
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SendNameChangedMessageLocally"
|
|
HRESULT PRV_SendNameChangedMessageLocally(LPDPLOBBYI_DPLOBJECT this,
|
|
DPID dpidPlayer, LPDPNAME lpName, BOOL bPlayer)
|
|
{
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
LPMSG_PLAYERNAME lpmsg = NULL;
|
|
DWORD dwSize, dwShortSize = 0, dwLongSize = 0;
|
|
LPBYTE lpByte = NULL;
|
|
|
|
DPF(7, "Entering PRV_SendNameChangedMessageLocally");
|
|
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
|
|
this, dpidPlayer, lpName, bPlayer);
|
|
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Setup the message to put in the player's queue
|
|
// Calculate the size of the message
|
|
if(lpName->lpszShortName)
|
|
dwShortSize = WSTRLEN_BYTES(lpName->lpszShortName);
|
|
if(lpName->lpszLongName)
|
|
dwLongSize = WSTRLEN_BYTES(lpName->lpszLongName);
|
|
dwSize = sizeof(MSG_PLAYERNAME) + dwShortSize + dwLongSize;
|
|
|
|
// Allocate memory for the message
|
|
lpmsg = DPMEM_ALLOC(dwSize);
|
|
if(!lpmsg)
|
|
{
|
|
DPF_ERR("Unable to allocate memory for temporary message structure");
|
|
// Since the name has been changed, we'll just return success here
|
|
hr = DP_OK;
|
|
goto EXIT_SENDNAMECHANGED;
|
|
}
|
|
|
|
// Now build the system message
|
|
SET_MESSAGE_HDR(lpmsg);
|
|
if(bPlayer)
|
|
SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_PLAYERNAMECHANGED);
|
|
else
|
|
SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_GROUPNAMECHANGED);
|
|
lpmsg->dwPlayerID = dpidPlayer;
|
|
lpmsg->dwShortOffset = sizeof(MSG_PLAYERNAME);
|
|
lpmsg->dwLongOffset = sizeof(MSG_PLAYERNAME) + dwShortSize;
|
|
|
|
// Copy in the names
|
|
lpByte = (LPBYTE)lpmsg + sizeof(MSG_PLAYERNAME);
|
|
memcpy(lpByte, lpName->lpszShortName, dwShortSize);
|
|
lpByte += dwShortSize;
|
|
memcpy(lpByte, lpName->lpszLongName, dwLongSize);
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_SENDNAMECHANGED;
|
|
}
|
|
|
|
// Call dplay's DistributeGroupMessage function to put the message
|
|
// in the queues of all the appropriate players
|
|
hr = DistributeGroupMessage(this->lpDPlayObject, lpGroupTo,
|
|
(LPBYTE)lpmsg, dwSize, FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding SetGroupName message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
|
|
EXIT_SENDNAMECHANGED:
|
|
|
|
// Free our message
|
|
if(lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
return hr;
|
|
|
|
} // PRV_SendNameChangedMessageLocally
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SetGroupName"
|
|
HRESULT DPLAPI DPLP_SetGroupName(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_SETREMOTEGROUPNAME lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPLP_SetGroupName");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_SETGROUPNAME structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// First see if the group is in our map table. If it is not,
|
|
// we should just ignore this message because it's for a
|
|
// group we don't know about.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved SetGroupName message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// See if the group is local or remote. If it's local, ignore this message
|
|
// and just return DP_OK becuase we've already sent this message locally.
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if((!lpGroup) || (lpGroup->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_SETGROUPNAME;
|
|
}
|
|
|
|
// Call dplay's internalsetname function to update the name in the cache
|
|
hr = InternalSetName((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwGroupID, lpd->lpName, FALSE, lpd->dwFlags, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed to SetGroupName internally for remote group, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_SETGROUPNAME;
|
|
}
|
|
|
|
// Send the message to all the local players
|
|
hr = PRV_SendNameChangedMessageLocally(this, lpd->dwGroupID, lpd->lpName, FALSE);
|
|
|
|
ERROR_DPLP_SETGROUPNAME:
|
|
|
|
// Drop the locks
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
return hr;
|
|
|
|
} // DPLP_SetGroupName
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_SendGroupOwnerMessageLocally"
|
|
HRESULT PRV_SendGroupOwnerMessageLocally(LPDPLOBBYI_DPLOBJECT this,
|
|
DPID dpidGroup, DPID dpidNewOwner, DPID dpidOldOwner)
|
|
{
|
|
LPDPLAYI_GROUP lpGroupTo = NULL;
|
|
HRESULT hr = DP_OK;
|
|
MSG_GROUPOWNERCHANGED msg;
|
|
|
|
|
|
DPF(7, "Entering PRV_SendGroupOwnerMessageLocally");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
|
this, dpidGroup, dpidNewOwner, dpidOldOwner);
|
|
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// Now build the system message
|
|
memset(&msg, 0, sizeof(MSG_GROUPOWNERCHANGED));
|
|
SET_MESSAGE_HDR(&msg);
|
|
SET_MESSAGE_COMMAND(&msg, DPSP_MSG_GROUPOWNERCHANGED);
|
|
msg.dwIDGroup = dpidGroup;
|
|
msg.dwIDNewOwner = dpidNewOwner;
|
|
msg.dwIDOldOwner = dpidOldOwner;
|
|
|
|
// Find dplay's internal group struct for the To group
|
|
lpGroupTo = GroupFromID(this->lpDPlayObject, DPID_ALLPLAYERS);
|
|
if(!lpGroupTo)
|
|
{
|
|
DPF_ERRVAL("Unable to find group in nametable, hr = 0x%08x", hr);
|
|
hr = DPERR_INVALIDGROUP;
|
|
goto EXIT_SENDGROUPOWNER;
|
|
}
|
|
|
|
// 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_GROUPOWNERCHANGED), FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding SetGroupOwner message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
|
|
EXIT_SENDGROUPOWNER:
|
|
|
|
// Drop the lock
|
|
LEAVE_DPLAY();
|
|
|
|
return hr;
|
|
|
|
} // PRV_SendGroupOwnerMessageLocally
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SetGroupOwner"
|
|
HRESULT DPLAPI DPLP_SetGroupOwner(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_SETREMOTEGROUPOWNER lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
HRESULT hr = DP_OK;
|
|
DWORD dwOldOwnerID;
|
|
|
|
|
|
DPF(7, "Entering DPLP_SetGroupOwner");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_SETGROUPNAME structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// First see if the group is in our map table. If it is not,
|
|
// we should just ignore this message because it's for a
|
|
// group we don't know about.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved SetGroupOwner message for unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// See if the group is local or remote. If it's local, ignore this message
|
|
// and just return DP_OK becuase we've already sent this message locally.
|
|
lpGroup = GroupFromID(this->lpDPlayObject, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_SETGROUPOWNER;
|
|
}
|
|
|
|
// If the player is already the owner of the group, we don't need
|
|
// to do any processing (this is the buffer in case the server
|
|
// sends us duplicate messages for stuff we've already sent locally)
|
|
if(lpGroup->dwOwnerID == lpd->dwOwnerID)
|
|
{
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_SETGROUPOWNER;
|
|
}
|
|
|
|
// Make sure the old owner is in our map table, otherwise just set
|
|
// it to zero (the default)
|
|
dwOldOwnerID = lpGroup->dwOwnerID;
|
|
|
|
// Change the owner locally
|
|
lpGroup->dwOwnerID = lpd->dwOwnerID;
|
|
|
|
// Send a SetGroupOwner message locally
|
|
PRV_SendGroupOwnerMessageLocally(this, lpd->dwGroupID,
|
|
lpd->dwOwnerID, dwOldOwnerID);
|
|
|
|
ERROR_DPLP_SETGROUPOWNER:
|
|
|
|
// Drop the locks
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
return hr;
|
|
|
|
} // DPLP_SetGroupOwner
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SetPlayerName"
|
|
HRESULT DPLAPI DPLP_SetPlayerName(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_SETREMOTEPLAYERNAME lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
|
|
|
|
DPF(7, "Entering DPLP_SetPlayerName");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_SETPLAYERNAME structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
// First see if the player is in our map table. If it is not,
|
|
// we should just ignore this message because it's for a
|
|
// player we don't know about.
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwPlayerID))
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF(8, "Recieved SetPlayerName message for unknown player, dwPlayerID = %lu, discarding message", lpd->dwPlayerID);
|
|
return DPERR_INVALIDPLAYER;
|
|
}
|
|
|
|
// Take the lock
|
|
ENTER_DPLAY();
|
|
|
|
// See if the player is local or remote. If it's local, ignore this message
|
|
// and just return DP_OK becuase we've already sent this message locally.
|
|
lpPlayer = PlayerFromID(this->lpDPlayObject, lpd->dwPlayerID);
|
|
if((!lpPlayer) || (lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
hr = DP_OK;
|
|
goto ERROR_DPLP_SETPLAYERNAME;
|
|
}
|
|
|
|
// Call dplay's internalsetname function to update the name in the cache
|
|
hr = InternalSetName((LPDIRECTPLAY)this->lpDPlayObject->pInterfaces,
|
|
lpd->dwPlayerID, lpd->lpName, TRUE, lpd->dwFlags, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed to SetPlayerName internally for remote group, hr = 0x%08x", hr);
|
|
goto ERROR_DPLP_SETPLAYERNAME;
|
|
}
|
|
|
|
// Send the message to all the local players
|
|
hr = PRV_SendNameChangedMessageLocally(this, lpd->dwPlayerID, lpd->lpName, TRUE);
|
|
|
|
|
|
ERROR_DPLP_SETPLAYERNAME:
|
|
|
|
// Drop the lock
|
|
LEAVE_LOBBY_ALL();
|
|
|
|
return hr;
|
|
|
|
} // DPLP_SetPlayerName
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SetSessionDesc"
|
|
HRESULT DPLAPI DPLP_SetSessionDesc(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_SETSESSIONDESC lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
DPF(7, "Entering DPLP_SetSessionDesc");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_SETSESSIONDESC structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
LEAVE_DPLOBBY();
|
|
return hr;
|
|
|
|
} // DPLP_SetSessionDesc
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_SetSPDataPointer"
|
|
HRESULT DPLAPI DPLP_SetSPDataPointer(LPDPLOBBYSP lpDPLSP, LPVOID lpData)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this;
|
|
|
|
|
|
// Make sure the SP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpDPLSP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Go ahead and save the pointer
|
|
this->lpSPData = lpData;
|
|
|
|
return DP_OK;
|
|
|
|
} // DPLP_SetSPDataPointer
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PRV_BuildStartSessionMessage"
|
|
HRESULT PRV_BuildStartSessionMessage(LPVOID * lplpmsg, LPDWORD lpdwSize,
|
|
LPDPLCONNECTION lpConn, LPDPLAYI_PLAYER lpPlayer)
|
|
{
|
|
LPMSG_STARTSESSION lpmsg = NULL;
|
|
DWORD dwPackageSize;
|
|
DWORD dwSize;
|
|
LPBYTE lpTemp = NULL;
|
|
DPNAME dpn;
|
|
HRESULT hr;
|
|
|
|
|
|
// Setup a local DPNAME struct for the player if the names exist
|
|
if((lpPlayer->lpszShortName) || (lpPlayer->lpszLongName))
|
|
{
|
|
// Setup the struct
|
|
memset(&dpn, 0, sizeof(DPNAME));
|
|
dpn.dwSize = sizeof(DPNAME);
|
|
dpn.lpszShortName = lpPlayer->lpszShortName;
|
|
dpn.lpszLongName = lpPlayer->lpszLongName;
|
|
lpConn->lpPlayerName = &dpn;
|
|
}
|
|
else
|
|
{
|
|
// Make sure the PlayerName pointer is NULL
|
|
lpConn->lpPlayerName = NULL;
|
|
}
|
|
|
|
// Calculate the size of our message in Unicode
|
|
PRV_GetDPLCONNECTIONPackageSize(lpConn, &dwPackageSize, NULL);
|
|
dwSize = sizeof(MSG_STARTSESSION) + dwPackageSize -
|
|
sizeof(DPLOBBYI_PACKEDCONNHEADER);
|
|
|
|
// Allocate memory for the message
|
|
lpmsg = DPMEM_ALLOC(dwSize);
|
|
if(!lpmsg)
|
|
{
|
|
DPF_ERR("Unable to allocate memory for temporary message structure");
|
|
return DPERR_OUTOFMEMORY;
|
|
}
|
|
|
|
// Now build the system message
|
|
SET_MESSAGE_HDR(lpmsg);
|
|
SET_MESSAGE_COMMAND(lpmsg, DPSP_MSG_STARTSESSION);
|
|
|
|
// Set the DPLCONNECTION pointer
|
|
lpmsg->dwConnOffset = sizeof(MSG_STARTSESSION);
|
|
lpTemp = (LPBYTE)lpmsg + lpmsg->dwConnOffset;
|
|
|
|
// Copy in the package
|
|
hr = PRV_PackageDPLCONNECTION(lpConn, lpTemp, FALSE);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Unable to pack DPLCONNECTION struct, hr = 0x%08x", hr);
|
|
DPMEM_FREE(lpmsg);
|
|
return hr;
|
|
}
|
|
|
|
// Set the output pointers
|
|
*lpdwSize = dwSize;
|
|
*lplpmsg = lpmsg;
|
|
|
|
return DP_OK;
|
|
|
|
} // PRV_BuildStartSessionMessage
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DPLP_StartSession"
|
|
HRESULT DPLAPI DPLP_StartSession(LPDPLOBBYSP lpILP,
|
|
LPSPDATA_STARTSESSIONCOMMAND lpd)
|
|
{
|
|
LPDPLOBBYI_DPLOBJECT this = NULL;
|
|
LPDPLAYI_DPLAY lpDP = NULL;
|
|
DPLCONNECTION conn;
|
|
LPBYTE lpmsg = NULL;
|
|
HRESULT hr = DP_OK;
|
|
LPDPLAYI_PLAYER lpPlayer = NULL;
|
|
LPDPLAYI_GROUP lpGroup = NULL;
|
|
DWORD dwMessageSize;
|
|
LPDPLAYI_GROUPNODE lpGroupnode = NULL;
|
|
UINT nPlayers;
|
|
|
|
|
|
DPF(7, "Entering DPLP_StartSession");
|
|
DPF(9, "Parameters: 0x%08x, 0x%08x", lpILP, lpd);
|
|
|
|
ENTER_DPLOBBY();
|
|
|
|
// Make sure the LP doesn't throw us a curve
|
|
TRY
|
|
{
|
|
this = DPLOBJECT_FROM_INTERFACE(lpILP);
|
|
if( !VALID_DPLOBBY_PTR( this ) )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("Lobby Provider passed invalid DPLobby object!");
|
|
return DPERR_INVALIDOBJECT;
|
|
}
|
|
|
|
// Validate the struct pointer
|
|
if(!lpd)
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR("SPDATA_STARTSESSIONCOMMAND structure pointer cannot be NULL");
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
LEAVE_DPLOBBY();
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
return DPERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Make a local copy of the DPLCONNECTION structure since we will
|
|
// be modifying some elements of it. We are currently only modifying
|
|
// elements in the DPLCONNECTION structure itself, so we can get
|
|
// away with using it's pointers to SessionDesc and PlayerName structs,
|
|
// but if we modify those in the future, we need to copy them as well
|
|
memcpy(&conn, lpd->lpConn, sizeof(DPLCONNECTION));
|
|
|
|
// Make a local variable pointer to the dplay object
|
|
lpDP = this->lpDPlayObject;
|
|
|
|
// Make sure we know about this group
|
|
if(!IsLobbyIDInMapTable(this, lpd->dwGroupID))
|
|
{
|
|
DPF(8, "Received StartSessionCommand message for an unknown group, dwGroupID = %lu, discarding message", lpd->dwGroupID);
|
|
LEAVE_DPLOBBY();
|
|
return DPERR_INVALIDGROUP;
|
|
}
|
|
|
|
// Take the dplay lock since we'll be looking at it's structures
|
|
ENTER_DPLAY();
|
|
|
|
// See if the host is even in our nametable, if it isn't, we'll assume
|
|
// we're not the host
|
|
// See if the host is a local player, if it is, send separate messages
|
|
if(IsLobbyIDInMapTable(this, lpd->dwHostID))
|
|
{
|
|
// Get dplay's player struct for the host player
|
|
lpPlayer = PlayerFromID(lpDP, lpd->dwHostID);
|
|
|
|
// If we know the host player (we should) and he's local, we
|
|
// want to send the host message first
|
|
if((lpPlayer) && (lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
|
|
{
|
|
// So set the host bit
|
|
conn.dwFlags |= DPLCONNECTION_CREATESESSION;
|
|
|
|
// Build the StartSession message for the host
|
|
hr = PRV_BuildStartSessionMessage(&lpmsg, &dwMessageSize,
|
|
&conn, lpPlayer);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF_ERRVAL("Failed building StartSessionCommand message, hr = 0x%08x", hr);
|
|
goto EXIT_DPLP_STARTSESSION;
|
|
}
|
|
|
|
// Now send the message to the host player alone
|
|
hr = HandlePlayerMessage(lpPlayer, (LPBYTE)lpmsg,
|
|
dwMessageSize, FALSE, 0);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(8, "Failed adding message to player's receive queue from lobby, hr = 0x%08x", hr);
|
|
}
|
|
|
|
// Free our message since we're done with it
|
|
DPMEM_FREE(lpmsg);
|
|
lpmsg = NULL;
|
|
|
|
// Now fall through and send the join message to everyone else
|
|
// in the group
|
|
}
|
|
}
|
|
|
|
// We must be joining, so set the join bit, and make sure the host
|
|
// bit isn't still set from above
|
|
conn.dwFlags &= ~DPLCONNECTION_CREATESESSION;
|
|
conn.dwFlags |= DPLCONNECTION_JOINSESSION;
|
|
|
|
// Get a pointer to dplay's internal group structure
|
|
lpGroup = GroupFromID(lpDP, lpd->dwGroupID);
|
|
if(!lpGroup)
|
|
{
|
|
DPF(5, "Unable to find group in nametable, idGroup = %lu", lpd->dwGroupID);
|
|
goto EXIT_DPLP_STARTSESSION;
|
|
}
|
|
|
|
|
|
// Figure out how many players we are looking for
|
|
lpGroupnode = FindPlayerInGroupList(lpGroup->pSysPlayerGroupnodes,lpDP->pSysPlayer->dwID);
|
|
if (!lpGroupnode)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_UNEXPECTED;
|
|
}
|
|
nPlayers = lpGroupnode->nPlayers;
|
|
|
|
// Walk the list of groupnodes, looking for nPlayers local players to give
|
|
// the message to, excluding the host
|
|
lpGroupnode = lpGroup->pGroupnodes;
|
|
while ((nPlayers > 0) && (lpGroupnode))
|
|
{
|
|
if ((lpGroupnode->pPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL) &&
|
|
(lpGroupnode->pPlayer->dwID != lpd->dwHostID))
|
|
{
|
|
// Build the StartSession (join) message for this player
|
|
hr = PRV_BuildStartSessionMessage(&lpmsg, &dwMessageSize,
|
|
&conn, lpGroupnode->pPlayer);
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(5, "Failed building StartSessionCommand message, hr = 0x%08x", hr);
|
|
goto EXIT_DPLP_STARTSESSION;
|
|
}
|
|
|
|
// Send the message to this player
|
|
hr = HandlePlayerMessage(lpGroupnode->pPlayer, lpmsg,
|
|
dwMessageSize, FALSE, 0);
|
|
|
|
// Free our message
|
|
if(lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
lpmsg = NULL;
|
|
|
|
nPlayers--;
|
|
} // local & !host
|
|
|
|
lpGroupnode = lpGroupnode->pNextGroupnode;
|
|
|
|
} // while
|
|
|
|
|
|
EXIT_DPLP_STARTSESSION:
|
|
|
|
if(lpmsg)
|
|
DPMEM_FREE(lpmsg);
|
|
|
|
LEAVE_LOBBY_ALL();
|
|
return hr;
|
|
|
|
} // DPLP_StartSession
|
|
|
|
|
|
|