/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
// Filename : ODPLAY.CPP
// Description : MultiPlayerDP, multiplayer class using directPlay
// Onwer : Gilbert
#ifndef IMAGICMP
// #define INITGUID
// #define INITGUID for dplay.h to define IID_IDirectPlay3A
#include
// #undef INITGUID
#include
#include
#include
#include
#include
#include
// Define constant
GUID GAME_GUID =
{ 0x12f70d44, 0x68be, 0x11d0, { 0xaa, 0xb6, 0x0, 0x0, 0xe9, 0xf9, 0xd, 0x5d } };
// To enable a lobby to launch a DirectPlay application, the application must add
// the following entries to the system registry.
//[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectPlay\Applications\SevenKingdoms]
//"Guid"="{12F70D44-68BE-11D0-AAB6-0000E9F90D5D}"
//"File"="7k.exe"
//"CommandLine"="-!lobby!"
//"Path"="C:\Seven Kingdoms"
//"CurrentDirectory"="C:\Seven Kingdoms"
// note that [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectPlay\Applications]
// folder may not exist after installed dx5
HANDLE PLAYER_MESSAGE_HANDLE = NULL; // ???
DPSessionDesc::DPSessionDesc()
{
lpszSessionNameA = session_name;
lpszPasswordA = pass_word;
}
DPSessionDesc::DPSessionDesc(const DPSESSIONDESC2 &dpSessionDesc) : DPSESSIONDESC2(dpSessionDesc)
{
after_copy();
}
DPSessionDesc::DPSessionDesc(const DPSessionDesc &dpSessionDesc) : DPSESSIONDESC2(dpSessionDesc)
{
after_copy();
}
DPSessionDesc& DPSessionDesc::operator= (const DPSessionDesc &src)
{
memcpy(this, &src, sizeof( DPSessionDesc ) );
after_copy();
return *this;
}
void DPSessionDesc::after_copy()
{
if( lpszSessionNameA )
{
strcpy(session_name, lpszSessionNameA);
session_name[strlen(lpszSessionNameA)] = '\0';
}
else
{
session_name[0] = '\0';
}
lpszSessionNameA = session_name;
if( lpszPasswordA)
{
strcpy(pass_word, lpszPasswordA);
pass_word[strlen(lpszPasswordA)] = '\0';
}
else
{
pass_word[0] = '\0';
}
lpszPasswordA = pass_word;
}
DPSessionDesc *DPSessionDesc::before_use()
{
lpszSessionNameA = session_name;
lpszPasswordA = pass_word;
return this;
}
// to start a multiplayer game, first check if it is called from a
// lobbied (MultiPlayerDP::is_lobbied)
// if it is a lobbied, call init_lobbied before create_player
// if not, call poll_service_provider; display them and let
// user to select, call init and pass the guid of the selected
// service; create_session or poll_sessions+join_session;
// finally create_player.
// ------- begin of function MultiPlayerDP::MultiPlayerDP -------//
MultiPlayerDP::MultiPlayerDP() : service_providers(sizeof(DPServiceProvider), 10 ),
current_sessions(sizeof(DPSessionDesc), 10 ), player_pool(sizeof(DPPlayer), 8 ),
recv_buffer(new char[MP_RECV_BUFFER_SIZE])
{
init_flag = 0;
direct_play_lobby = NULL;
direct_play1 = NULL;
direct_play3 = NULL;
recv_buffer_size = MP_RECV_BUFFER_SIZE;
host_flag = 0;
lobbied_flag = 0;
connection_string = NULL;
}
// ------- end of function MultiPlayerDP::MultiPlayerDP -------//
// ------- begin of function MultiPlayerDP::~MultiPlayerDP -------//
MultiPlayerDP::~MultiPlayerDP()
{
deinit();
delete[] recv_buffer;
}
// ------- end of function MultiPlayerDP::~MultiPlayerDP -------//
// ------- begin of function MultiPlayerDP::pre_init -------//
void MultiPlayerDP::pre_init()
{
// nothing, for compatibilities with MultiPlayerIM
lobbied_flag = 0;
}
// ------- begin of function MultiPlayerDP::pre_init -------//
// ------- begin of function MultiPlayerDP::init -------//
void MultiPlayerDP::init(GUID serviceProviderGUID)
{
VgaFrontLock vlock;
if( !DirectPlayCreate( &serviceProviderGUID, &direct_play1, NULL) )
{
if( !direct_play1->QueryInterface( IID_IDirectPlay3A, (void **)&direct_play3) )
{
init_flag = 1;
}
else
{
direct_play3 = NULL;
direct_play1->Release();
direct_play1 = NULL;
}
}
else
{
direct_play1 = NULL;
}
host_flag = 0;
// ######## patch begin Gilbert 24/11 ######//
my_player_id = DPID_ALLPLAYERS; // no player
// ######## patch end Gilbert 24/11 ######//
}
// ------- end of function MultiPlayerDP::init -------//
// ------- begin of function MultiPlayerDP::deinit -------//
void MultiPlayerDP::deinit()
{
host_flag = 0;
lobbied_flag = 0;
if(init_flag)
{
// ######## patch begin Gilbert 24/11 ######//
if( my_player_id != DPID_ALLPLAYERS)
{
destroy_player( my_player_id );
Sleep(2000); // 2 seconds
}
// ######## patch end Gilbert 24/11 ######//
VgaFrontLock vgaLock;
if( direct_play3 )
{
direct_play3->Release();
direct_play3 = NULL;
}
if( direct_play1 )
{
direct_play1->Release();
direct_play1 = NULL;
}
// ######## patch begin Gilbert 24/11 ######//
my_player_id = DPID_ALLPLAYERS; // mark player deleted
// ######## patch end Gilbert 24/11 ######//
init_flag = 0;
}
if( direct_play_lobby )
{
VgaFrontLock vgaLock;
direct_play_lobby->Release();
direct_play_lobby = NULL;
}
if( connection_string )
{
mem_del(connection_string);
connection_string = NULL;
}
}
// ------- end of function MultiPlayerDP::deinit -------//
// ----- begin of function MultiPlayerDP::init_lobbied ------//
void MultiPlayerDP::init_lobbied(int maxPlayers, char *)
{
HRESULT hr;
VgaFrontLock vlock;
// ------- create DirectPlayLobby, if necessary ------//
if( direct_play_lobby == NULL)
{
LPDIRECTPLAYLOBBYA directPlayLobby = NULL;
hr = DirectPlayLobbyCreate( NULL, &directPlayLobby, NULL, NULL, 0);
if( hr == DP_OK )
{
hr = directPlayLobby->QueryInterface(IID_IDirectPlayLobby2A, (void **)&direct_play_lobby);
directPlayLobby->Release();
if( hr != DP_OK )
return;
}
else
{
return;
}
}
// ------ get connection setting ---------//
DWORD bufferSize = 0;
hr = direct_play_lobby->GetConnectionSettings(0, NULL, &bufferSize);
if( hr == DP_OK || hr == DPERR_BUFFERTOOSMALL)
{
bufferSize += 0x80; // give them a little more
connection_string = (DPLCONNECTION *)mem_resize(connection_string, bufferSize);
hr = direct_play_lobby->GetConnectionSettings(0, connection_string, &bufferSize);
if( hr == DP_OK )
{
// ------ modify connectString.lpSessionDesc here -------//
connection_string->lpSessionDesc->dwFlags = DPSESSION_KEEPALIVE | DPSESSION_NODATAMESSAGES;
connection_string->lpSessionDesc->dwMaxPlayers = maxPlayers;
hr = direct_play_lobby->SetConnectionSettings(0,0, connection_string);
if( hr != DP_OK )
return;
joined_session = *connection_string->lpSessionDesc;
// ------ obtain direct play interface --------//
direct_play1 = NULL;
LPDIRECTPLAY2A directPlay2;
hr = direct_play_lobby->Connect(0, &directPlay2, NULL);
if( hr != DP_OK )
return;
// query DIRECTPLAY3A interface
hr = directPlay2->QueryInterface( IID_IDirectPlay3A, (void **)&direct_play3);
if( hr != DP_OK )
{
direct_play3 = NULL;
directPlay2->Release();
directPlay2 = NULL;
return;
}
directPlay2->Release();
directPlay2 = NULL;
init_flag = 1;
if( connection_string->dwFlags & DPLCONNECTION_CREATESESSION )
lobbied_flag = 1; // auto create
else if( connection_string->dwFlags & DPLCONNECTION_JOINSESSION )
lobbied_flag = 2; // auto join
else
lobbied_flag = 4; // user selectable
bufferSize = sizeof(DPSESSIONDESC2);
direct_play3->GetSessionDesc( &joined_session, &bufferSize);
joined_session.after_copy();
}
else
{
if( hr != DPERR_NOTLOBBIED )
err.run("Cannot get connection string from lobby");
}
}
else
{
if( hr != DPERR_NOTLOBBIED )
err.run("Cannot get connection string from lobby");
}
}
// ----- end of function MultiPlayerDP::init_lobbied ------//
// ----- begin of function MultiPlayerDP::is_lobbied -----//
// return 0=not lobbied, 1=auto create, 2=auto join, 4=selectable
int MultiPlayerDP::is_lobbied()
{
return lobbied_flag;
}
// ----- end of function MultiPlayerDP::is_lobbied -----//
// ----- begin of function MultiPlayerDP::get_lobbied_name -----//
char *MultiPlayerDP::get_lobbied_name()
{
err_when(!is_lobbied());
// ------ get connection setting ---------//
if( connection_string )
return connection_string->lpPlayerName->lpszShortNameA;
else
return NULL;
}
// ----- end of function MultiPlayerDP::get_lobbied_name -----//
// ----- begin of function MultiPlayerDP::poll_service_providers -----//
//
// store all possible service provider (TCPIP, IPX, modem, null modem ... )
// into service_provider_array
//
// need not call init before get_service_provider
//
// called by DirectPlayEnumerate() for each DirectPlay Service Provider
static BOOL FAR PASCAL directPlayEnumerateCallback( LPGUID lpSPGuid, LPTSTR lpszSPName,
DWORD dwMajorVersion, DWORD dwMinorVersion, LPVOID mpPtr)
{
DPServiceProvider sp;
MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
sp.guid = *lpSPGuid;
strncpy(sp.description,lpszSPName, MP_SERVICE_PROVIDER_NAME_LEN);
sp.description[MP_SERVICE_PROVIDER_NAME_LEN] = '\0';
mpdpPtr->service_providers.linkin(&sp);
return TRUE;
}
void MultiPlayerDP::poll_service_providers()
{
service_providers.zap();
// ------ allocate spaces for service_provider_array -------//
VgaFrontLock vgaLock;
DirectPlayEnumerateA( directPlayEnumerateCallback, this );
}
// ----- end of function MultiPlayerDP::poll_service_providers -----//
// ----- begin of function MultiPlayerDP::get_service_provder -----//
// return a service provider
//
// i i-th service provider (i start from 1)
// return pointer to a DPServiceProvider, NULL if no more
DPServiceProvider* MultiPlayerDP::get_service_provider(int i)
{
if( i <= 0 || i > service_providers.size() )
return NULL;
return (DPServiceProvider *) service_providers.get(i);
}
// ----- end of function MultiPlayerDP::get_service_provder -----//
// ----- begin of function MultiPlayerDP::poll_sessions ------//
//
// store all available sessions (TCPIP, IPX, modem, null modem ... )
// into current_sessions
//
static BOOL FAR PASCAL EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc,
LPDWORD timeOut, DWORD flags, LPVOID mpPtr)
{
if( flags & DPESC_TIMEDOUT )
return FALSE;
if( memcmp(&lpSessionDesc->guidApplication, &GAME_GUID, sizeof(GUID)) == 0 )
{
MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
DPSessionDesc sessionDesc(*lpSessionDesc);
mpdpPtr->current_sessions.linkin(&sessionDesc);
}
return TRUE;
}
int MultiPlayerDP::poll_sessions()
{
err_when(!init_flag);
current_sessions.zap();
DPSESSIONDESC2 sessionDesc;
memset(&sessionDesc, 0, sizeof( sessionDesc ) );
sessionDesc.dwSize = sizeof( sessionDesc );
sessionDesc.guidApplication = GAME_GUID;
MouseDispCount showMouse;
// ##### patch begin Gilbert 9/1 #########//
// VgaFrontLock vgaLock; // MouseDispCount unlock vga_front
// ##### end begin Gilbert 9/1 #########//
VgaCustomPalette vgaCPal(DIR_RES"PAL_WIN.RES");
return DP_OK == direct_play3->EnumSessions(&sessionDesc , 0, EnumSessionsCallback, this,
DPENUMSESSIONS_AVAILABLE | DPENUMSESSIONS_ASYNC);
}
// ----- end of function MultiPlayerDP::poll_sessions ------//
// ----- begin of function MultiPlayerDP::get_session ------//
// return a session description
//
// i i-th session (i start from 1)
// return pointer to a session, NULL if no more
DPSessionDesc *MultiPlayerDP::get_session(int i)
{
if( i <= 0 || i > current_sessions.size() )
return NULL;
return ((DPSessionDesc *) current_sessions.get(i))->before_use();
}
// ----- end of function MultiPlayerDP::get_session ------//
// ----- begin of function MultiPlayerDP::create_session ----//
//
// create a new session
//
// sessionName arbitary name to identify a session, input from user
// maxPlayers maximum no. of players in a session
//
// return TRUE if success
int MultiPlayerDP::create_session(char *sessionName, int maxPlayers)
{
if(!init_flag || maxPlayers < 1)
return FALSE;
if( is_lobbied() == 1 )
{
host_flag = 1;
return TRUE;
}
memset(&joined_session, 0, sizeof( joined_session) );
joined_session.dwSize = sizeof( DPSESSIONDESC2 );
// DPSESSION_NODATAMESSAGES disable personal data
// remove DPSESSION_MIGRATEHOST
joined_session.dwFlags = DPSESSION_KEEPALIVE | DPSESSION_NODATAMESSAGES ;
joined_session.guidApplication = GAME_GUID;
joined_session.dwMaxPlayers = maxPlayers;
strncpy(joined_session.session_name, sessionName, MP_SESSION_NAME_LEN );
joined_session.session_name[MP_SESSION_NAME_LEN]= '\0';
joined_session.lpszSessionNameA = joined_session.session_name;
MouseDispCount showMouse;
// ##### patch begin Gilbert 9/1 #########//
// VgaFrontLock vgaLock; // MouseDispCount unlock vga_front
// ##### end begin Gilbert 9/1 #########//
VgaCustomPalette vgaCPal(DIR_RES"PAL_WIN.RES");
if( !direct_play3->Open(&joined_session, DPOPEN_CREATE) )
{
host_flag = 1;
return TRUE;
}
return FALSE;
}
// ----- end of function MultiPlayerDP::create_session ----//
// ------ begin of function MultiPlayerDP::join_session ------//
// join a session, by passing the DPSessionDesc pointer
//
// pointer to a DPSessionDesc
//
// return TRUE if success
int MultiPlayerDP::join_session(DPSessionDesc* sessionDesc)
{
if( !init_flag)
return FALSE;
if( is_lobbied() == 2 )
{
host_flag = 0;
return TRUE;
}
joined_session = *sessionDesc;
VgaFrontLock vgaLock;
if(!direct_play3->Open(&joined_session, DPOPEN_JOIN))
{
host_flag = 0;
return TRUE;
}
return FALSE;
}
// join a session, by passing the index passed into get_session()
// note : do not call poll_sessions between get_session and join_session
//
// currentSessionIndex the index passed into get_session()
//
// currentSessionIndex start from 1
int MultiPlayerDP::join_session(int currentSessionIndex)
{
if( !init_flag)
return FALSE;
if( is_lobbied() == 2 )
{
host_flag = 0;
return TRUE;
}
VgaFrontLock vgaLock;
joined_session = *get_session(currentSessionIndex);
if(!direct_play3->Open(&joined_session, DPOPEN_JOIN))
{
host_flag = 0;
return TRUE;
}
return FALSE;
}
// ------ end of function MultiPlayerDP::join_session ------//
// ------ begin of function MultiPlayerDP::close_session ------//
void MultiPlayerDP::close_session()
{
VgaFrontLock vgaLock;
if( init_flag)
direct_play3->Close();
host_flag = 0;
}
// ------ end of function MultiPlayerDP::close_session ------//
// ------ begin of function MultiPlayerDP::disable_join_session ------//
void MultiPlayerDP::disable_join_session()
{
// called by host only!
err_when( !host_flag );
if( init_flag && host_flag )
{
joined_session.dwFlags |= DPSESSION_JOINDISABLED | DPSESSION_NEWPLAYERSDISABLED;
VgaFrontLock vgaLock;
direct_play3->SetSessionDesc( &joined_session, 0 );
}
}
// ------ end of function MultiPlayerDP::disable_join_session ------//
// ------ begin of function MultiPlayerDP::create_player ------//
// create a local player
//
// friendlyName short name of the player, best to be one word only
// [char *] formalName long name of the player, take friendlyName if NULL (default: NULL)
// [void *] lpData, [DWORD] dataSize pointer and size of any data sent the remote (default: NULL, 0)
// [DWORD] flags not use reserved (default:0)
//
// return TRUE if success
//
int MultiPlayerDP::create_player(char *friendlyName, char *formalName,
LPVOID lpData, DWORD dataSize, DWORD flags)
{
if(!init_flag)
return FALSE;
DPNAME dpName;
memset(&dpName, 0, sizeof(dpName) );
dpName.dwSize = sizeof(dpName);
dpName.lpszShortNameA = friendlyName;
dpName.lpszLongNameA = formalName ? formalName : friendlyName;
VgaFrontLock vgaLock;
return !direct_play3->CreatePlayer(&my_player_id, &dpName, PLAYER_MESSAGE_HANDLE,
lpData, dataSize, flags);
}
// ------ end of function MultiPlayerDP::create_player -----//
// ------ begin of function MultiPlayerDP::destroy_player ------//
// destroy player, (for remove from joining a session, before playing)
//
void MultiPlayerDP::destroy_player( DPID playerId )
{
VgaFrontLock vgaLock;
direct_play3->DestroyPlayer(playerId);
}
// ------ end of function MultiPlayerDP::destroy_player ------//
// -------- begin of function MultiPlayerDP::poll_players ------//
// collect all players in the session into player_pool
// get each player by calling get_player
//
static BOOL FAR PASCAL EnumPlayerCallback(DPID dpId, DWORD dwPlayerType,
LPCDPNAME lpName, DWORD dwFlags, LPVOID mpPtr)
{
MultiPlayerDP *mpdpPtr = (MultiPlayerDP *)mpPtr;
DPPlayer dpPlayer;
dpPlayer.player_id = dpId;
strncpy(dpPlayer.friendly_name, lpName->lpszShortNameA, MP_FRIENDLY_NAME_LEN );
dpPlayer.friendly_name[MP_FRIENDLY_NAME_LEN] = '\0';
strncpy(dpPlayer.formal_name, lpName->lpszLongNameA, MP_FORMAL_NAME_LEN );
dpPlayer.formal_name[MP_FORMAL_NAME_LEN] = '\0';
dpPlayer.connecting = 1;
mpdpPtr->player_pool.linkin(&dpPlayer);
return TRUE;
}
void MultiPlayerDP::poll_players()
{
player_pool.zap();
VgaFrontLock vgaLock;
// direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, DPENUMPLAYERS_LOCAL );
// direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, DPENUMPLAYERS_REMOTE);
if(init_flag)
direct_play3->EnumPlayers(NULL, EnumPlayerCallback, this, 0 );
}
// -------- end of function MultiPlayerDP::poll_players ------//
// -------- begin of function MultiPlayerDP::get_player -----//
//
// return the i-th player in the player_pool
//
DPPlayer *MultiPlayerDP::get_player(int i)
{
if( i <= 0 || i > player_pool.size() )
return NULL;
return (DPPlayer *)player_pool.get(i);
}
// -------- end of function MultiPlayerDP::get_player -----//
// -------- begin of function MultiPlayerDP::search_player -----//
//
// search player by playerID
//
DPPlayer *MultiPlayerDP::search_player(DPID playerId)
{
DPPlayer *player;
int i = 0;
while( (player = get_player(++i)) != NULL )
if( player->player_id == playerId )
return player;
return NULL;
}
//
// search player by formal name, case insensitive
//
DPPlayer *MultiPlayerDP::search_player(char *name)
{
DPPlayer *player;
int i = 0;
while( (player = get_player(++i)) != NULL )
if( strnicmp(player->formal_name, name, MP_FORMAL_NAME_LEN)== 0)
return player;
return NULL;
}
// -------- end of function MultiPlayerDP::get_player -----//
// ------- begin of function MultiPlayerDP::is_host --------//
int MultiPlayerDP::is_host(DPID playerID)
{
err_here(); // not supported
return 0;
}
// ------- end of function MultiPlayerDP::is_host --------//
// ------- begin of function MultiPlayerDP::am_I_host --------//
int MultiPlayerDP::am_I_host()
{
return host_flag;
}
// ------- end of function MultiPlayerDP::am_I_host --------//
// ----- begin of function MultiPlayerDP::is_player_connecting ----//
//
// determine whether a player is lost
//
// MultiPlayerDP::received must be called (or remote.poll_msg) ,
// so if a player is really lost, the system message from
// directPlay is received
//
int MultiPlayerDP::is_player_connecting(DPID playerId)
{
for( int p = 1; p <= player_pool.size(); ++p)
{
DPPlayer *dpPlayer = (DPPlayer *) player_pool.get(p);
if( dpPlayer->player_id == playerId )
{
return dpPlayer->connecting;
}
}
return 0;
}
// ----- end of function MultiPlayerDP::is_player_connecting ----//
// ----- begin of function MultiPlayerDP::update_public_data ----//
// update a player's public data
//
// return TRUE on success
//
int MultiPlayerDP::update_public_data(DPID playerId, LPVOID lpData, DWORD dataSize)
{
VgaFrontLock vgaLock;
return !direct_play3->SetPlayerData(playerId, lpData, dataSize, DPSET_REMOTE | DPSET_GUARANTEED);
}
// ----- end of function MultiPlayerDP::update_public_data ----//
// ----- begin of function MultiPlayerDP::retrieve_public_data ----//
// retrieve a player's public data
// prepare an allocated memory and pass its address as lpData,
// store its size in a DWORD, pass the pointer of the DWORD as lpDataSize
//
// if lpData is NULL, the function can get the size of the data
//
// return TRUE on success, *lpDataSize is updated to the size of the data
//
int MultiPlayerDP::retrieve_public_data(DPID playerId, LPVOID lpData, LPDWORD lpDataSize)
{
VgaFrontLock vgaLock;
return !direct_play3->GetPlayerData(playerId, lpData, lpDataSize, DPSET_REMOTE | DPSET_GUARANTEED);
}
// ----- end of function MultiPlayerDP::retrieve_public_data ----//
// ----- begin of function MultiPlayerDP::update_private_data ----//
// update a player's private data
//
// return TRUE on success
//
int MultiPlayerDP::update_private_data(DPID playerId, LPVOID lpData, DWORD dataSize)
{
VgaFrontLock vgaLock;
return !direct_play3->SetPlayerData(playerId, lpData, dataSize, DPSET_LOCAL | DPSET_GUARANTEED);
}
// ----- end of function MultiPlayerDP::update_private_data ----//
// ----- begin of function MultiPlayerDP::retrieve_private_data ----//
// retrieve a player's private data
// prepare an allocated memory and pass its address as lpData,
// store its size in a DWORD, pass the pointer of the DWORD as lpDataSize
//
// if lpData is NULL, the function can get the size of the data
//
// return TRUE on success, *lpDataSize is updated to the size of the data
//
int MultiPlayerDP::retrieve_private_data(DPID playerId, LPVOID lpData, LPDWORD lpDataSize)
{
VgaFrontLock vgaLock;
return !direct_play3->GetPlayerData(playerId, lpData, lpDataSize, DPSET_LOCAL | DPSET_GUARANTEED);
}
// ----- end of function MultiPlayerDP::retrieve_private_data ----//
// --------- begin of function MultiPlayerDP::send ---------//
// send message
//
// must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
// or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
// pass DPID_ALLPLAYERS as toId to all players
//
// return TRUE on success
//
int MultiPlayerDP::send(DPID toId, LPVOID lpData, DWORD dataSize)
{
err_when(!init_flag);
HRESULT hr;
{
VgaFrontLock vgaLock;
hr = direct_play3->Send(my_player_id, toId, 0, lpData, dataSize);
}
// see if any player lost
if( hr == DPERR_INVALIDPLAYER )
{
for( int p = 1; p <= player_pool.size(); ++p)
{
DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
if( dpPlayer->player_id == toId )
{
dpPlayer->connecting = 0;
}
}
}
err_when(hr == DPERR_SENDTOOBIG);
return hr == DP_OK;
}
// --------- end of function MultiPlayerDP::send ---------//
// ------- begin of function MultiPlayerDP::begin_stream -----//
// signal start of a lot of guaranteed messages being sent to this player
//
// note : call end_stream to finish begin_stream
//
void MultiPlayerDP::begin_stream(DPID toId)
{
err_when(!init_flag);
VgaFrontLock vgaLock;
direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED | DPSEND_OPENSTREAM, NULL,0);
}
// ------- end of function MultiPlayerDP::begin_stream -----//
// --------- begin of function MultiPlayerDP::send_stream ---------//
// send message
//
// must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
// or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
// pass DPID_ALLPLAYERS as toId to all players
//
// return TRUE on success
//
int MultiPlayerDP::send_stream(DPID toId, LPVOID lpData, DWORD dataSize)
{
err_when(!init_flag);
HRESULT hr;
{
VgaFrontLock vgaLock;
hr = direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED, lpData, dataSize);
}
// see if any player lost
if( hr == DPERR_INVALIDPLAYER )
{
for( int p = 1; p <= player_pool.size(); ++p)
{
DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
if( dpPlayer->player_id == toId )
{
dpPlayer->connecting = 0;
}
}
}
err_when(hr == DPERR_SENDTOOBIG);
return hr == DP_OK;
}
// --------- end of function MultiPlayerDP::send_stream ---------//
// ------- begin of function MultiPlayerDP::end_stream -----//
// signal end of a lot of guaranteed messages being sent to this player
//
void MultiPlayerDP::end_stream(DPID toId)
{
err_when(!init_flag);
VgaFrontLock vgaLock;
direct_play3->Send(my_player_id, toId, DPSEND_GUARANTEED | DPSEND_CLOSESTREAM, NULL,0);
}
// ------- end of function MultiPlayerDP::end_stream -----//
// ------- begin of function MultiPlayerDP::get_msg_count ------//
//
// get the number of outstanding message to receive
//
// return -1 if fail
//
int MultiPlayerDP::get_msg_count()
{
err_when(!init_flag);
DWORD count = 0;
VgaFrontLock vgaLock;
if(direct_play3->GetMessageCount(my_player_id, &count))
return -1;
return (int)count;
}
// ------- end of function MultiPlayerDP::get_msg_count ------//
// ------- begin of function MultiPlayerDP::receive ------//
// return NULL if fails
// sysMsgCount records how many system messages have been handled
// notice : *sysMsgCount may be != 0, but return NULL
//
char *MultiPlayerDP::receive(LPDPID from, LPDPID to, LPDWORD dSize, int *sysMsgCount)
{
err_when(!init_flag);
DPID fromId, toId;
DWORD dataSize;
int retryFlag;
HRESULT hr;
VgaFrontLock vgaLock;
if( sysMsgCount )
*sysMsgCount = 0;
do
{
retryFlag = 0;
dataSize = recv_buffer_size;
hr=direct_play3->Receive(&fromId, &toId, DPRECEIVE_ALL, recv_buffer, &dataSize);
switch(hr)
{
case 0:
if(fromId == DPID_SYSMSG)
{
handle_system_msg(recv_buffer, dataSize);
if( sysMsgCount )
(*sysMsgCount)++;
retryFlag = 1;
}
else
{
*from = fromId;
*to = toId;
*dSize = dataSize;
}
break;
case DPERR_BUFFERTOOSMALL: // assume now dataSize > recv_buffer_size
delete[] recv_buffer;
recv_buffer_size = dataSize + 0x400;
recv_buffer = new char[recv_buffer_size];
retryFlag = 1; // direct_play3->receive may not return the same message, so keep retrying
break;
default:
return NULL;
}
} while (retryFlag);
return recv_buffer;
}
// ------- end of function MultiPlayerDP::receive ------//
// ------- begin of function MultiPlayerDP::handle_system_msg ------//
void MultiPlayerDP::handle_system_msg(LPVOID lpData, DWORD dSize)
{
switch( ((DPMSG_GENERIC *)lpData)->dwType )
{
case DPSYS_ADDPLAYERTOGROUP:
{
DPMSG_ADDPLAYERTOGROUP *dpmsg = (DPMSG_ADDPLAYERTOGROUP *)lpData;
}
break;
case DPSYS_CREATEPLAYERORGROUP:
{
DPMSG_CREATEPLAYERORGROUP *dpmsg = (DPMSG_CREATEPLAYERORGROUP *)lpData;
}
break;
case DPSYS_DELETEPLAYERFROMGROUP:
{
DPMSG_DELETEPLAYERFROMGROUP *dpmsg = (DPMSG_DELETEPLAYERFROMGROUP *)lpData;
}
break;
case DPSYS_DESTROYPLAYERORGROUP:
{
DPMSG_DESTROYPLAYERORGROUP *dpmsg = (DPMSG_DESTROYPLAYERORGROUP *)lpData;
if( dpmsg->dwPlayerType == DPPLAYERTYPE_PLAYER)
{
for( int p = 1; p <= player_pool.size(); ++p)
{
DPPlayer *dpPlayer = (DPPlayer *)player_pool.get(p);
if( dpPlayer->player_id == dpmsg->dpId )
{
dpPlayer->connecting = 0;
}
}
}
}
break;
case DPSYS_HOST:
{
DPMSG_HOST *dpmsg = (DPMSG_HOST *)lpData;
}
break;
case DPSYS_SESSIONLOST:
{
DPMSG_SESSIONLOST *dpmsg = (DPMSG_SESSIONLOST *)lpData;
}
break;
case DPSYS_SETPLAYERORGROUPDATA:
{
DPMSG_SETPLAYERORGROUPDATA *dpmsg = (DPMSG_SETPLAYERORGROUPDATA *)lpData;
}
break;
case DPSYS_SETPLAYERORGROUPNAME:
{
DPMSG_SETPLAYERORGROUPNAME *dpmsg = (DPMSG_SETPLAYERORGROUPNAME *)lpData;
}
break;
case DPSYS_SETSESSIONDESC:
{
DPMSG_SETSESSIONDESC *dpmsg = (DPMSG_SETSESSIONDESC *)lpData;
joined_session = dpmsg->dpDesc;
}
break;
}
}
// ------- end of function MultiPlayerDP::handle_system_msg ------//
// --------- begin of function MultiPlayerDP::send_lobby ---------//
// send message
//
// must not call it between IDirectDrawSurface2::Lock and IDirectDrawSurface2::Unlock,
// or between IDirectDrawSurface2::GetDC and IDirectDrawSurface2::ReleaseDC
//
// return TRUE on success
//
int MultiPlayerDP::send_lobby(LPVOID lpData, DWORD dataSize)
{
err_when(!init_flag);
VgaFrontLock vgaLock;
return !direct_play_lobby->SendLobbyMessage(0, 0, lpData, dataSize);
}
// --------- end of function MultiPlayerDP::send_lobby ---------//
// ------- begin of function MultiPlayerDP::receive_lobby ------//
// return NULL if fails
char *MultiPlayerDP::receive_lobby(LPDWORD dSize)
{
err_when(!init_flag);
DWORD dataSize, msgFlag;
int retryFlag;
HRESULT hr;
VgaFrontLock vgaLock;
do
{
retryFlag = 0;
dataSize = recv_buffer_size;
hr=direct_play_lobby->ReceiveLobbyMessage(0,0, &msgFlag, recv_buffer, &dataSize);
switch(hr)
{
case 0:
if(msgFlag == DPLAD_SYSTEM)
{
handle_lobby_system_msg(recv_buffer, dataSize);
retryFlag = 1;
}
else
{
*dSize = dataSize;
}
break;
case DPERR_BUFFERTOOSMALL: // assume now dataSize > recv_buffer_size
delete[] recv_buffer;
recv_buffer_size = dataSize + 0x400;
recv_buffer = new char[recv_buffer_size];
retryFlag = 1; // direct_play3->receive may not return the same message, so keep retrying
break;
default:
return NULL;
}
} while (retryFlag);
return recv_buffer;
}
// ------- end of function MultiPlayerDP::receive_lobby ------//
// ------- begin of function MultiPlayerDP::handle_lobby_system_msg ------//
void MultiPlayerDP::handle_lobby_system_msg(LPVOID lpData, DWORD dSize)
{
switch( ((DPLMSG_GENERIC *)lpData)->dwType )
{
case DPLSYS_APPTERMINATED:
{
// DPLMSG_APPTERMINATED *dplmsg = (DPLMSG_APPTERMINATED *)lpData;
}
break;
case DPLSYS_CONNECTIONSETTINGSREAD:
{
// DPLMSG_CONNECTIONSETTINGSREAD *dplmsg = (DPLMSG_CONNECTIONSETTINGREAD *)lpData;
}
break;
case DPLSYS_DPLAYCONNECTFAILED:
{
// DPLMSG_DPLAYCONNECTFAILED *dplmsg = (DPLMSG_DPLAYCONNECTFAILED *)lpData;
}
break;
case DPLSYS_DPLAYCONNECTSUCCEEDED:
{
// DPLMSG_DPLAYCONNECTSUCCEEDED *dplmsg = (DPLMSG_DPLAYCONNECTSUCCEEDED *)lpData;
}
break;
}
}
// ------- end of function MultiPlayerDP::handle_lobby_system_msg ------//
// ------ Begin of function MultiPlayerDP::sort_sessions -------//
static int sort_session_id(const void *a, const void *b)
{
return memcmp( &((DPSessionDesc *)a)->guidInstance, &((DPSessionDesc *)b)->guidInstance,
sizeof(GUID) );
}
static int sort_session_name(const void *a, const void *b)
{
return strcmp( ((DPSessionDesc *)a)->name_str(), ((DPSessionDesc *)b)->name_str() );
}
// sort current_sessions
// sortType, 1=sort by GUID, 2=sort by session name
void MultiPlayerDP::sort_sessions(int sortType )
{
// BUGHERE : quick_sort is a DynArray function but current_sessions is DynArrayB
switch(sortType)
{
case 1:
current_sessions.quick_sort(sort_session_id);
break;
case 2:
current_sessions.quick_sort(sort_session_name);
break;
default:
err_here();
}
for( int s = 1; get_session(s); ++s)
{
get_session(s)->before_use(); // let lpszSessionNameA point to its own session_name
}
}
// ------ End of function MultiPlayerDP::sort_sessions -------//
#endif