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

1089 lines
27 KiB

/*==========================================================================
*
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
*
* File: player.c
* Content: Methods for player management
*
* History:
* Date By Reason
* ======= ======= ======
* 2/27/97 myronth Created it
* 3/17/97 myronth Create/DestroyPlayer, Removed unnecessary Enum fn's
* 3/21/97 myronth SetPlayerName, Get/SetPlayerData, Removed more
* unnecessary functions
* 3/25/97 myronth Fixed GetPlayer prototype (1 new parameter)
* 3/31/97 myronth Removed dead code, Implemented Send, Added
* CreateAndMapNewPlayer function
* 4/3/97 myronth Changed CALLSP macro to CALL_LP
* 4/10/97 myronth Added support for GetPlayerCaps
* 5/8/97 myronth Drop lobby lock when calling LP, Propagate player's
* receive event on CreatePlayer call
* 5/12/97 myronth Handle remote players properly, create a lobby
* system player for all remote players & groups
* 5/17/97 myronth SendChatMessage
* 5/20/97 myronth Made AddPlayerToGroup & DeletePlayerFromGroup return
* DPERR_ACCESSDENIED on remote players (#8679),
* Fixed a bunch of other lock bugs, Changed debug levels
* 6/3/97 myronth Added support for player flags in CreatePlayer
* 9/29/97 myronth Send local SetPlayerName/Data msgs after call to
* lobby server succeeds (#12554)
* 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_CreatePlayer"
HRESULT DPLAPI PRV_CreatePlayer(LPDPLOBBYI_DPLOBJECT this, LPDPID lpidPlayer,
LPDPNAME lpName, HANDLE hEvent, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags)
{
SPDATA_CREATEPLAYER cp;
HRESULT hr = DP_OK;
DWORD dwPlayerFlags;
DPF(7, "Entering PRV_CreatePlayer");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x",
this, lpidPlayer, lpName, hEvent, lpData, dwDataSize, dwFlags);
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(&cp, 0, sizeof(SPDATA_CREATEPLAYER));
cp.dwSize = sizeof(SPDATA_CREATEPLAYER);
cp.lpName = lpName;
cp.lpData = lpData;
cp.dwDataSize = dwDataSize;
cp.dwFlags = dwFlags;
// Call the CreatePlayer method in the SP
if(CALLBACK_EXISTS(CreatePlayer))
{
cp.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, CreatePlayer, &cp);
ENTER_DPLOBBY();
}
else
{
// CreatePlayer is required
DPF_ERR("The Lobby Provider callback for CreatePlayer doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling CreatePlayer in the Lobby Provider, hr = 0x%08x", hr);
LEAVE_DPLOBBY();
return hr;
}
// Fix up the player flags
dwPlayerFlags = DPLAYI_PLAYER_PLAYERLOCAL;
if(dwFlags & DPPLAYER_SPECTATOR)
dwPlayerFlags |= DPLAYI_PLAYER_SPECTATOR;
// Add the player to dplay's nametable and put it in our map table
hr = PRV_CreateAndMapNewPlayer(this, lpidPlayer, lpName, hEvent, lpData,
dwDataSize, dwPlayerFlags, cp.dwPlayerID, FALSE);
if(FAILED(hr))
{
DPF_ERRVAL("Failed creating a new local player, 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.
}
LEAVE_DPLOBBY();
return hr;
} // PRV_CreatePlayer
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DestroyPlayer"
HRESULT DPLAPI PRV_DestroyPlayer(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
{
SPDATA_DESTROYPLAYER dp;
LPDPLAYI_PLAYER lpPlayer = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_DestroyPlayer");
DPF(9, "Parameters: 0x%08x, 0x%08x", this, dwLobbyID);
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, dwLobbyID);
if(!lpPlayer)
{
LEAVE_DPLAY();
DPF_ERR("Unable to find player in nametable");
hr = DPERR_INVALIDPLAYER;
goto EXIT_DESTROYPLAYER;
}
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
LEAVE_DPLAY();
DPF_ERR("Cannot add a remote player to a group");
hr = DPERR_ACCESSDENIED;
goto EXIT_DESTROYPLAYER;
}
// Drop the dplay lock since we're done
LEAVE_DPLAY();
// Setup our SPDATA struct
memset(&dp, 0, sizeof(SPDATA_DESTROYPLAYER));
dp.dwSize = sizeof(SPDATA_DESTROYPLAYER);
dp.dwPlayerID = dwLobbyID;
// Call the DestroyPlayer method in the SP
if(CALLBACK_EXISTS(DestroyPlayer))
{
dp.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, DestroyPlayer, &dp);
ENTER_DPLOBBY();
}
else
{
// DestroyPlayer is required
DPF_ERR("The Lobby Provider callback for DestroyPlayer doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_DESTROYPLAYER;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling DestroyPlayer in the Lobby Provider, hr = 0x%08x", hr);
goto EXIT_DESTROYPLAYER;
}
// The dplay InternalDestroyPlayer code will take care of the rest of
// the internal cleanup (nametable, groups, etc.), so we can just return
// from here.
EXIT_DESTROYPLAYER:
LEAVE_DPLOBBY();
return hr;
} // PRV_DestroyPlayer
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetPlayerCaps"
HRESULT DPLAPI PRV_GetPlayerCaps(LPDPLOBBYI_DPLOBJECT this, DWORD dwFlags,
DWORD dwPlayerID, LPDPCAPS lpcaps)
{
SPDATA_GETPLAYERCAPS gcd;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_GetPlayerCaps");
DPF(9, "Parameters: 0x%08x, 0x%08x, %lu, 0x%08x",
this, dwFlags, dwPlayerID, lpcaps);
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(&gcd, 0, sizeof(SPDATA_GETCAPS));
gcd.dwSize = sizeof(SPDATA_GETCAPS);
gcd.dwFlags = dwFlags;
gcd.dwPlayerID = dwPlayerID;
gcd.lpcaps = lpcaps;
// Call the GetPlayerCaps method in the LP
if(CALLBACK_EXISTS(GetPlayerCaps))
{
gcd.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, GetPlayerCaps, &gcd);
ENTER_DPLOBBY();
}
else
{
// GetPlayerCaps is required
DPF_ERR("The Lobby Provider callback for GetPlayerCaps doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_GETPLAYERCAPS;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling GetPlayerCaps in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_GETPLAYERCAPS:
LEAVE_DPLOBBY();
return hr;
} // PRV_GetPlayerCaps
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetPlayerData"
HRESULT DPLAPI PRV_GetPlayerData(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
LPVOID lpData, LPDWORD lpdwDataSize)
{
SPDATA_GETPLAYERDATA gpd;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_GetPlayerData");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
this, dwPlayerID, lpData, lpdwDataSize);
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(&gpd, 0, sizeof(SPDATA_GETPLAYERDATA));
gpd.dwSize = sizeof(SPDATA_GETPLAYERDATA);
gpd.dwPlayerID = dwPlayerID;
gpd.lpdwDataSize = lpdwDataSize;
gpd.lpData = lpData;
// Call the GetPlayerData method in the SP
if(CALLBACK_EXISTS(GetPlayerData))
{
gpd.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, GetPlayerData, &gpd);
ENTER_DPLOBBY();
}
else
{
// GetPlayerData is required
DPF_ERR("The Lobby Provider callback for GetPlayerData doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_GETPLAYERDATA;
}
if(FAILED(hr))
{
DPF_ERRVAL("Failed calling GetPlayerData in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_GETPLAYERDATA:
LEAVE_DPLOBBY();
return hr;
} // PRV_GetPlayerData
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_Send"
HRESULT DPLAPI PRV_Send(LPDPLOBBYI_DPLOBJECT this, DWORD dwFromID, DWORD dwToID,
DWORD dwFlags, LPVOID lpBuffer, DWORD dwBufSize)
{
SPDATA_SEND sd;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_Send");
DPF(9, "Parameters: 0x%08x, %lu, %lu, 0x%08x, 0x%08x, %lu",
this, dwFromID, dwToID, dwFlags, lpBuffer, dwBufSize);
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 structure
memset(&sd, 0, sizeof(SPDATA_SEND));
sd.dwSize = sizeof(SPDATA_SEND);
sd.dwFromID = dwFromID;
sd.dwToID = dwToID;
sd.dwFlags = dwFlags;
sd.lpBuffer = lpBuffer;
sd.dwBufSize = dwBufSize;
// Call the Send method in the SP
if(CALLBACK_EXISTS(Send))
{
sd.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, Send, &sd);
ENTER_DPLOBBY();
}
else
{
// Send is required
DPF_ERR("The Lobby Provider callback for Send doesn't exist -- it's required");
ASSERT(FALSE);
LEAVE_DPLOBBY();
return DPERR_UNAVAILABLE;
}
LEAVE_DPLOBBY();
return hr;
} // PRV_Send
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SendChatMessage"
HRESULT DPLAPI PRV_SendChatMessage(LPDPLOBBYI_DPLOBJECT this, DWORD dwFromID,
DWORD dwToID, DWORD dwFlags, LPDPCHAT lpChat)
{
SPDATA_CHATMESSAGE sd;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_SendChatMessage");
DPF(9, "Parameters: 0x%08x, %lu, %lu, 0x%08x, 0x%08x",
this, dwFromID, dwToID, dwFlags, lpChat);
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 structure
memset(&sd, 0, sizeof(SPDATA_CHATMESSAGE));
sd.dwSize = sizeof(SPDATA_CHATMESSAGE);
sd.dwFromID = dwFromID;
sd.dwToID = dwToID;
sd.dwFlags = dwFlags;
sd.lpChat = lpChat;
// Call the SendChatMessage method in the SP
if(CALLBACK_EXISTS(SendChatMessage))
{
sd.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, SendChatMessage, &sd);
ENTER_DPLOBBY();
}
else
{
// SendChatMessage is required
DPF_ERR("The Lobby Provider callback for SendChatMessage doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_SENDCHATMESSAGE;
}
EXIT_SENDCHATMESSAGE:
LEAVE_DPLOBBY();
return hr;
} // PRV_SendChatMessage
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SetPlayerData"
HRESULT DPLAPI PRV_SetPlayerData(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
LPVOID lpData, DWORD dwDataSize, DWORD dwFlags)
{
SPDATA_SETPLAYERDATA spd;
LPDPLAYI_PLAYER lpPlayer = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering PRV_SetPlayerData");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, %lu, 0x%08x",
this, dwPlayerID, 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;
}
// 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_SETPLAYERDATA;
}
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
LEAVE_DPLAY();
DPF_ERR("Cannot add a remote player to a group");
hr = DPERR_ACCESSDENIED;
goto EXIT_SETPLAYERDATA;
}
// Drop the dplay lock since we're finished
LEAVE_DPLAY();
// Setup our SPDATA struct
memset(&spd, 0, sizeof(SPDATA_SETPLAYERDATA));
spd.dwSize = sizeof(SPDATA_SETPLAYERDATA);
spd.dwPlayerID = dwPlayerID;
spd.dwDataSize = dwDataSize;
spd.lpData = lpData;
spd.dwFlags = dwFlags;
// Call the SetPlayerData method in the SP
if(CALLBACK_EXISTS(SetPlayerData))
{
spd.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, SetPlayerData, &spd);
ENTER_DPLOBBY();
}
else
{
// SetPlayerData is required
DPF_ERR("The Lobby Provider callback for SetPlayerData doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_SETPLAYERDATA;
}
// If it succeeded, send the SetPlayerData message to our local players
if(SUCCEEDED(hr))
{
hr = PRV_SendDataChangedMessageLocally(this, dwPlayerID, lpData, dwDataSize);
}
else
{
DPF_ERRVAL("Failed calling SetPlayerData in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_SETPLAYERDATA:
LEAVE_DPLOBBY();
return hr;
} // PRV_SetPlayerData
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_SetPlayerName"
HRESULT DPLAPI PRV_SetPlayerName(LPDPLOBBYI_DPLOBJECT this, DWORD dwPlayerID,
LPDPNAME lpName, DWORD dwFlags)
{
SPDATA_SETPLAYERNAME spn;
LPDPLAYI_PLAYER lpPlayer = NULL;
HRESULT hr = DP_OK;
DPF(7, "Entering DPL_SetPlayerName");
DPF(9, "Parameters: 0x%08x, %lu, 0x%08x, 0x%08x",
this, dwPlayerID, 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;
}
// 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_SETPLAYERNAME;
}
if(!(lpPlayer->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
LEAVE_DPLAY();
DPF_ERR("Cannot add a remote player to a group");
hr = DPERR_ACCESSDENIED;
goto EXIT_SETPLAYERNAME;
}
// Drop the dplay lock since we're finished
LEAVE_DPLAY();
// Setup our SPDATA struct
memset(&spn, 0, sizeof(SPDATA_SETPLAYERNAME));
spn.dwSize = sizeof(SPDATA_SETPLAYERNAME);
spn.dwPlayerID = dwPlayerID;
spn.lpName = lpName;
spn.dwFlags = dwFlags;
// Call the SetPlayerName method in the SP
if(CALLBACK_EXISTS(SetPlayerName))
{
spn.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, SetPlayerName, &spn);
ENTER_DPLOBBY();
}
else
{
// SetPlayerName is required
DPF_ERR("The Lobby Provider callback for SetPlayerName doesn't exist -- it's required");
ASSERT(FALSE);
hr = DPERR_UNAVAILABLE;
goto EXIT_SETPLAYERNAME;
}
// If it succeeded, send the SetPlayerName message to our local players
if(SUCCEEDED(hr))
{
hr = PRV_SendNameChangedMessageLocally(this, dwPlayerID, lpName, TRUE);
}
else
{
DPF_ERRVAL("Failed calling SetPlayerName in the Lobby Provider, hr = 0x%08x", hr);
}
EXIT_SETPLAYERNAME:
LEAVE_DPLOBBY();
return hr;
} // PRV_SetPlayerName
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GrowMapTable"
HRESULT PRV_GrowMapTable(LPDPLOBBYI_DPLOBJECT this)
{
LPDPLOBBYI_MAPIDNODE lpTempMap = NULL;
// If we haven't already allocated a buffer, allocate one with
// DPLOBBYPR_DEFAULTMAPENTRIES entries in it
if(!this->lpMap)
{
this->lpMap = DPMEM_ALLOC(DPLOBBYPR_DEFAULTMAPENTRIES *
sizeof(DPLOBBYI_MAPIDNODE));
if(!this->lpMap)
{
DPF(2, "Unable to allocate memory for ID map table");
return DPERR_OUTOFMEMORY;
}
this->dwTotalMapEntries = DPLOBBYPR_DEFAULTMAPENTRIES;
return DP_OK;
}
// Otherwise, grow the table by the default number of entries
lpTempMap = DPMEM_REALLOC(this->lpMap, (this->dwTotalMapEntries +
DPLOBBYPR_DEFAULTMAPENTRIES * sizeof(DPLOBBYI_MAPIDNODE)));
if(!lpTempMap)
{
DPF(2, "Unable to grow map table");
return DPERR_OUTOFMEMORY;
}
this->lpMap = lpTempMap;
this->dwTotalMapEntries += DPLOBBYPR_DEFAULTMAPENTRIES *
sizeof(DPLOBBYI_MAPIDNODE);
return DP_OK;
} // PRV_GrowMapTable
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DoesLobbyIDExist"
BOOL PRV_DoesLobbyIDExist(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID,
LPDWORD lpdwIndex)
{
DWORD dwIndex = 0;
if(this->lpMap && this->dwMapEntries)
{
// REVIEW!!!! -- We need to make this faster -- use a sorted array
while(dwIndex < this->dwMapEntries)
{
if(this->lpMap[dwIndex++].dwLobbyID == dwLobbyID)
{
*lpdwIndex = --dwIndex;
return TRUE;
}
}
}
return FALSE;
} // PRV_DoesLobbyIDExist
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_AddMapIDNode"
HRESULT PRV_AddMapIDNode(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID, DPID dpid)
{
HRESULT hr = DP_OK;
DWORD dwIndex = 0;
// Make sure we have room for a new entry
if(this->dwMapEntries == this->dwTotalMapEntries)
{
hr = PRV_GrowMapTable(this);
if(FAILED(hr))
return hr;
}
// Verify that this LobbyID doesn't already exist in the table
if(PRV_DoesLobbyIDExist(this, dwLobbyID, &dwIndex))
{
DPF(2, "Tried to add Lobby ID to map table which already existed, overwriting data");
ASSERT(FALSE);
this->lpMap[dwIndex].dwLobbyID = dwLobbyID;
this->lpMap[dwIndex].dpid = dpid;
return hr;
}
// REVIEW!!!! -- We need to add this in and keep the array sorted to
// make lookups faster, but for now, don't worry about it.
// Fill in a new node at the end of the array
this->lpMap[this->dwMapEntries].dwLobbyID = dwLobbyID;
this->lpMap[this->dwMapEntries].dpid = dpid;
this->dwMapEntries++;
return hr;
} // PRV_AddMapIDNode
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_DeleteMapIDNode"
BOOL PRV_DeleteMapIDNode(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID)
{
DWORD dwIndex = 0;
// Make sure we have entries
if((this->lpMap) && (this->dwMapEntries))
{
// REVIEW!!!! -- We need to make this faster by using a sorted array
while(dwIndex < this->dwMapEntries)
{
if(this->lpMap[dwIndex].dwLobbyID == dwLobbyID)
{
// Check for the boundary case (last entry)
if((++dwIndex) == this->dwMapEntries)
{
// This is the last entry, so don't do anything but
// decrement the number of entries
this->dwMapEntries--;
return TRUE;
}
else
{
// Move all entries from here to the end of the list
// up one array entry
MoveMemory((LPDPLOBBYI_MAPIDNODE)(&this->lpMap[dwIndex-1]),
(LPDPLOBBYI_MAPIDNODE)(&this->lpMap[dwIndex]),
((this->dwMapEntries - dwIndex) *
sizeof(DPLOBBYI_MAPIDNODE)));
// Decrement the count of entries
this->dwMapEntries--;
return TRUE;
}
}
else
dwIndex++;
}
}
// We weren't able to delete the entry in the map table
DPF(2, "Trying to delete an entry in the map ID table which doesn't exist");
ASSERT(FALSE);
return FALSE;
} // PRV_DeleteMapIDNode
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetDPIDByLobbyID"
BOOL PRV_GetDPIDByLobbyID(LPDPLOBBYI_DPLOBJECT this, DWORD dwLobbyID,
DPID * lpdpid)
{
DWORD dwIndex = 0;
// Take care of the known cases or else look in the map table
switch(dwLobbyID)
{
case DPID_ALLPLAYERS:
case DPID_SERVERPLAYER:
*lpdpid = dwLobbyID;
return TRUE;
default:
// Walk the list look for the ID
while(dwIndex < this->dwMapEntries)
{
if(this->lpMap[dwIndex].dwLobbyID == dwLobbyID)
{
*lpdpid = this->lpMap[dwIndex].dpid;
return TRUE;
}
else
dwIndex++;
}
}
return FALSE;
} // PRV_GetDPIDByLobbyID
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_GetLobbyIDByDPID"
BOOL PRV_GetLobbyIDByDPID(LPDPLOBBYI_DPLOBJECT this, DPID dpid,
LPDWORD lpdwLobbyID)
{
DWORD dwIndex = 0;
// Take care of the known cases or else look in the map table
switch(dpid)
{
case DPID_ALLPLAYERS:
case DPID_SERVERPLAYER:
*lpdwLobbyID = dpid;
return TRUE;
default:
// Walk the list look for the ID
while(dwIndex < this->dwMapEntries)
{
if(this->lpMap[dwIndex].dpid == dpid)
{
*lpdwLobbyID = this->lpMap[dwIndex].dwLobbyID;
return TRUE;
}
else
dwIndex++;
}
break;
}
return FALSE;
} // PRV_GetLobbyIDByDPID
#undef DPF_MODNAME
#define DPF_MODNAME "IsLobbyIDInMapTable"
BOOL IsLobbyIDInMapTable(LPDPLOBBYI_DPLOBJECT this, DWORD dwID)
{
DPID dpidTemp;
// If we can get it, then it's in there
if(PRV_GetDPIDByLobbyID(this, dwID, &dpidTemp))
return TRUE;
// Otherwise, return FALSE
return FALSE;
} // IsLobbyIDInMapTable
#undef DPF_MODNAME
#define DPF_MODNAME "IsValidLobbyID"
BOOL IsValidLobbyID(DWORD dwID)
{
// If it's in our reserved range, it's invalid. Otherwise, it's valid
if(dwID <= DPID_RESERVEDRANGE)
return FALSE;
else
return TRUE;
} // IsValidLobbyID
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CreateAndMapNewPlayer"
HRESULT PRV_CreateAndMapNewPlayer(LPDPLOBBYI_DPLOBJECT this,
DPID * lpdpid, LPDPNAME lpName, HANDLE hEvent, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, DWORD dwLobbyID,
BOOL bSystemPlayer)
{
LPDPLAYI_PLAYER lpPlayer = NULL, lpSysPlayer = NULL;
HRESULT hr = DP_OK;
DPID dpidPlayer = 0, dpidSysPlayer = 0;
// Take the dplay lock
ENTER_DPLAY();
// Make sure the lobby ID is valid, but only if it's not a system player
if((!bSystemPlayer) && (!IsValidLobbyID(dwLobbyID)))
{
DPF_ERRVAL("ID %lu is reserved, cannot create new player", dwLobbyID);
hr = DPERR_INVALIDPLAYER;
goto EXIT_CREATEANDMAPNEWPLAYER;
}
// 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, &dpidPlayer);
if(FAILED(hr))
{
DPF_ERRVAL("Unable to allocate new nametable id, hr = 0x%08x", hr);
goto EXIT_CREATEANDMAPNEWPLAYER;
}
// Make sure we have a lobby system player (for all remote players)
// If we don't then allocate a new one, unless we are creating
// the system player currently
if((!(this->dpidSysPlayer)) && (!(dwFlags & DPLAYI_PLAYER_SYSPLAYER)))
{
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_CREATEANDMAPNEWPLAYER;
}
// Set the lobby system player ID pointer to the new ID
this->dpidSysPlayer = dpidSysPlayer;
}
}
// Get a player struct for the player (if it's local, this will add it
// to the nametable. If it's remote, we need to add it below)
hr = GetPlayer(this->lpDPlayObject, &lpPlayer, lpName, hEvent, lpData,
dwDataSize, dwFlags, NULL, dwLobbyID);
if(FAILED(hr))
{
DPF_ERRVAL("Failed trying to add player to the nametable, hr = 0x%08x", hr);
goto EXIT_CREATEANDMAPNEWPLAYER;
}
// If the player is remote, set the player's ID to the new one we
// allocated and then set the system player ID to the lobby system player
if(!(dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
{
// Set the player's system player
lpPlayer->dwIDSysPlayer = this->dpidSysPlayer;
// Add the player to the nametable
hr = AddItemToNameTable(this->lpDPlayObject, (DWORD_PTR)lpPlayer,
&dpidPlayer, TRUE, dwLobbyID);
if (FAILED(hr))
{
DPF_ERRVAL("Unable to add new player to the nametable, hr = 0x%08x", hr);
ASSERT(FALSE);
goto EXIT_CREATEANDMAPNEWPLAYER;
}
// Set the player's ID
lpPlayer->dwID = dpidPlayer;
}
// Set the output dpid pointer
*lpdpid = lpPlayer->dwID;
EXIT_CREATEANDMAPNEWPLAYER:
LEAVE_DPLAY();
return hr;
} // PRV_CreateAndMapNewPlayer