1489 lines
49 KiB
C
1489 lines
49 KiB
C
/*
|
|
* L0DPlay.c
|
|
*
|
|
* universal multiplayer library level 0 implementation file
|
|
* transport layer: DirectPlay lobby aware PC-windows 95
|
|
*/
|
|
|
|
/*
|
|
* Author: Christophe Roguet
|
|
*
|
|
* Creation Date: 04/08/97
|
|
*
|
|
*/
|
|
|
|
|
|
#include "warnings.h"
|
|
|
|
#include <stdlib.h>
|
|
/*
|
|
* we need this one to fill the interface structure
|
|
* with pointers to the correct functions
|
|
*/
|
|
#include "PrivNetDef.h"
|
|
#include "l0GlDef.h"
|
|
#include "NetMemCo.h"
|
|
#include "NetEnd.h"
|
|
#include "PrivNetSer.h"
|
|
#include <NET\Netdebug.h>
|
|
#include <NET\l0DPlay.h>
|
|
|
|
#define IDIRECTPLAY2_OR_GREATER
|
|
#include <dplobby.h>
|
|
|
|
#define DPLAY_MAXBUF 250
|
|
|
|
static char gs_bL0PCWin95DPlayInitState;
|
|
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
|
|
typedef struct
|
|
{
|
|
DPID DPlayPlayerId; /* DPlay ID of the local player*/
|
|
NetLib_tduxPlayerId uxNetLibPlayerId; /* NetLib ID of the local player */
|
|
NetLib_tduwJoinType joinType; /* Create, Join or Watch. */
|
|
}NetLib_tdstInfoPlayer;
|
|
|
|
static NetLib_tdstInfoPlayer gs_InfoLocal; /* Informations of the local player. */
|
|
static long SendBufSize; /* Virtual buffer size. */
|
|
static unsigned long LastTime; /* Time for the last eL0PCWin95DPlayEngine. */
|
|
static unsigned long SendMaxRate; /* Maximum rate. */
|
|
static unsigned short NbrPlayer; /* Number of player. */
|
|
static NetLib_tdstInfoPlayer *TabPlayer; /* Table of player. */
|
|
|
|
typedef struct {
|
|
NetLib_tduxPlayerId uxNetLibPlayerId;
|
|
DPID DPlayPlayerId;
|
|
NetLib_tdstAddPlayerDesc *pstPlDesc;
|
|
char *pcDPlayPlayerName;
|
|
} tdstConvLine;
|
|
|
|
typedef struct {
|
|
unsigned short uwMaxSize;
|
|
unsigned short uwSize;
|
|
tdstConvLine *dastConv;
|
|
} tdstConvTable;
|
|
|
|
static tdstConvTable gs_stConvTable;
|
|
|
|
typedef struct stFIFO
|
|
{
|
|
struct stFIFO *next; /* Next message of FIFO. */
|
|
unsigned long size; /* Size of message. */
|
|
DPID DPlayIdFrom; /* Direct Play ID of sender. */
|
|
NetLib_tduxPlayerId uxSenderId; /* NetLib ID of sender */
|
|
}FIFO;
|
|
|
|
static FIFO *FIFObegin; /* First message of file. */
|
|
static FIFO **FIFOend; /* Last pointer of the file. */
|
|
|
|
static unsigned short gs_uwCallBack;
|
|
static NetLib_tduwJoinType gs_JoinType;
|
|
|
|
typedef struct {
|
|
NetLib_uxReadReceiptId m_ulReadReceiptId;
|
|
unsigned long uxPriority:7;
|
|
unsigned long uxReplaceType:7;
|
|
unsigned long uxReplace:1;
|
|
unsigned long eMessageType:5;
|
|
unsigned long uxHeadBigEndian:1;
|
|
unsigned long uxBodyBigEndian:1;
|
|
unsigned long uxDPlaySpecific:2;
|
|
} DPlayHead;
|
|
|
|
typedef enum {
|
|
NetLib_ePureNetLib, NetLib_eNewPlayerId, NetLib_eIdTable
|
|
} tdeDPlayMsgType;
|
|
|
|
typedef struct {
|
|
DPID DPlayPlayerId;
|
|
NetLib_tduxPlayerId uxNetLibPlayerId;
|
|
} tdstConversionMsg;
|
|
|
|
enum { NetLib_DPlayWaiting, NetLib_DPlayGo };
|
|
|
|
#pragma pack(pop)
|
|
|
|
static LPDIRECTPLAY3 glpDP; /* directplay object pointer*/
|
|
|
|
static LPDPLCONNECTION glpdplConnection; /* connection settings*/
|
|
|
|
static LPDIRECTPLAYLOBBY2 glpDPL; /* lobby object pointer*/
|
|
|
|
static DPID pidLocalPlayer; /* Id of local player*/
|
|
|
|
static NetLib_tduxPlayerId gs_uxPlayerIdGen; /* used to generate player ids */
|
|
|
|
BOOL FAR PASCAL NewPlayerCallback(DPID PlayerId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext);
|
|
|
|
void NetLib_RegisterNewPlayer1(DPID PlayerId, char *lpName);
|
|
|
|
void NetLib_RegisterNewPlayer2(DPID DPlayPlayerId, NetLib_tduxPlayerId uxNetLibPlayerId);
|
|
|
|
void NetLib_InitConversionTable(unsigned short uwMaxSize);
|
|
|
|
void NetLib_DeinitConversionTable();
|
|
|
|
void NetLib_AddConversionEntry(DPID DPlayPlayerId, NetLib_tdstAddPlayerDesc *pstPlDesc, char *);
|
|
|
|
void NetLib_SuppressConversionEntry(DPID DPlayerId);
|
|
|
|
DPlayHead *NetLib_BuildConversionMsg(DPID IdTo, unsigned short *);
|
|
|
|
DPID NetLib_NetLibToDPlay(NetLib_tduxPlayerId uxNetLibPlayerId);
|
|
NetLib_tduxPlayerId NetLib_DPlayToNetLib(DPID DPlayPlayerId);
|
|
NetLib_tduxPlayerId GeneratePlayerId(void);
|
|
|
|
void NetLib_DPlayHandleNewMsg(FIFO *pstFIFOCell, DPID IdTo);
|
|
void NetLib_DPlayHandleNewPlayerMsg(FIFO *pstFIFOCell, DPID IdTo);
|
|
void NetLib_DPlayHandlePlayerLeftMsg(FIFO *pstFIFOCell, DPID IdTo);
|
|
void NetLib_DPlayHandleSpecificMsg(FIFO *pstFIFOCell, DPID IdTo);
|
|
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPLobbyCreate
|
|
*
|
|
* Wrapper for DirectPlayLobby DirectPlayLobbyCreate API.
|
|
*/
|
|
HRESULT DPLobbyCreate(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
LPDIRECTPLAYLOBBY local_lpDPL; /* directplay object pointer*/
|
|
|
|
hr = DirectPlayLobbyCreate(NULL, &local_lpDPL, NULL, NULL, 0);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyCreate : DPLCreate : error %lx", hr);
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
hr = IDirectPlayLobby_QueryInterface(local_lpDPL, &IID_IDirectPlayLobby2A, (LPVOID *)&glpDPL);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyCreate : DPLQueryInterface : error %lx", hr);
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
hr = IDirectPlayLobby_Release(local_lpDPL);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyCreate : DPLRelease : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPClose
|
|
*
|
|
* Wrapper for DirectPlay Close API
|
|
*/
|
|
HRESULT DPClose(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
/* release the direct play object*/
|
|
if (glpDP)
|
|
{
|
|
hr = IDirectPlay3_Close(glpDP);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPClose : error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPRelease
|
|
*
|
|
* Wrapper for DirectPlay Release API
|
|
*/
|
|
HRESULT DPRelease(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
/* release the lobby object*/
|
|
if (glpDP)
|
|
{
|
|
hr = IDirectPlay3_Release(glpDP);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPRelease : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
glpDP = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPLobbyRelease
|
|
*
|
|
* Wrapper for DirectPlayLobby Release API
|
|
*/
|
|
HRESULT DPLobbyRelease(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
/* free our connection settings*/
|
|
if (glpdplConnection)
|
|
{
|
|
vFree(glpdplConnection);
|
|
glpdplConnection = NULL;
|
|
}
|
|
|
|
/* release the lobby object*/
|
|
if (glpDPL)
|
|
{
|
|
hr = IDirectPlayLobby_Release(glpDPL);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyRelease : DPLRelease : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
glpDPL = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
/*
|
|
* DPLobbyGetConnectionSettings
|
|
*
|
|
* Wrapper for DirectPlayLobby GetConnectionSettings API
|
|
*/
|
|
|
|
HRESULT DPLobbyGetConnectionSettings(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
DWORD dwSize;
|
|
|
|
if (glpDPL)
|
|
{
|
|
/* get size for the connection settings structure*/
|
|
hr = IDirectPlayLobby_GetConnectionSettings(glpDPL, 0, NULL, &dwSize);
|
|
|
|
if (DPERR_BUFFERTOOSMALL == hr)
|
|
{
|
|
/* if we already have one, free it*/
|
|
if (glpdplConnection)
|
|
{
|
|
vFree(glpdplConnection);
|
|
glpdplConnection = NULL;
|
|
}
|
|
|
|
/* allocate memory for the new one*/
|
|
glpdplConnection = (LPDPLCONNECTION) pMalloc(dwSize);
|
|
|
|
/* get the connection settings*/
|
|
if (glpdplConnection)
|
|
hr = IDirectPlayLobby_GetConnectionSettings(glpDPL, 0, glpdplConnection, &dwSize);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyGetConnectionSettings : DPLGetConnectionSettings : error %lx", hr);
|
|
#endif
|
|
}
|
|
} else if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyGetConnectionSettings : DPLGetConnectionSettings : error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPLobbyConnect
|
|
*
|
|
* Wrapper for DirectPlayLobby Connect API.
|
|
*/
|
|
|
|
HRESULT DPLobbyConnect(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
static LPDIRECTPLAY2 local_lpDP; /* directplay object pointer*/
|
|
|
|
if(glpDPL) {
|
|
/* connect and retrieve a DirectPlay2 interface */
|
|
|
|
hr = IDirectPlayLobby_Connect(glpDPL, 0, &local_lpDP, NULL) ;
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyConnect : DPLConnect : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
hr = IDirectPlayLobby_Release(glpDPL);
|
|
glpDPL=NULL;
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLConnect : DPLRelease : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
/* retrieve a DirectPlay3 interface from the DirectPlay2 interface */
|
|
|
|
if(local_lpDP) {
|
|
|
|
hr = IDirectPlay2_QueryInterface(local_lpDP, &IID_IDirectPlay3A, (LPVOID *)&glpDP);
|
|
|
|
if(hr != DP_OK) {
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLConnect : DP2QueryInterface : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
hr = IDirectPlay2_Release(local_lpDP);
|
|
|
|
if(hr != DP_OK) {
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLConnect : DP2Release: error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPCreatePlayer
|
|
* wrapper for CreatePlayer
|
|
*/
|
|
|
|
HRESULT DPCreatePlayer(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
if(glpDP) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPCreatePlayer : ConnectionSettings");
|
|
vDebugFormat(Net_C_Debug_DPlay, "dwFlags: %lx", glpdplConnection->dwFlags);
|
|
if(glpdplConnection->dwFlags==DPLCONNECTION_CREATESESSION)
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLCONNECTION_CREATESESSION");
|
|
if(glpdplConnection->dwFlags==DPLCONNECTION_JOINSESSION)
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLCONNECTION_JOINSESSION");
|
|
vDebugFormat(Net_C_Debug_DPlay, "PlayerName: %s", glpdplConnection->lpPlayerName->lpszShortNameA);
|
|
#endif
|
|
|
|
hr = IDirectPlay3_CreatePlayer(glpDP, &pidLocalPlayer, glpdplConnection->lpPlayerName, NULL, NULL, 0, 0);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPCreatePlayer : error %lu", hr);
|
|
#endif
|
|
}
|
|
|
|
if(glpdplConnection->dwFlags==DPLCONNECTION_CREATESESSION)
|
|
gs_JoinType=NetLib_Join_Create;
|
|
else if(glpdplConnection->dwFlags==DPLCONNECTION_JOINSESSION)
|
|
gs_JoinType=NetLib_Join_Join;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/******************************************************************************************/
|
|
|
|
/*
|
|
* DPEnumPlayers
|
|
* wrapper for DPEnumPlayers
|
|
*/
|
|
|
|
HRESULT DPEnumPlayers(void)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
|
|
if(glpDP) {
|
|
|
|
hr = IDirectPlay3_EnumPlayers(glpDP, NULL, (LPDPENUMPLAYERSCALLBACK2)NewPlayerCallback, 0, 0);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPEnumPlayers : DP3EnumPLayers : error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************************/
|
|
|
|
BOOL FAR PASCAL NewPlayerCallback(DPID PlayerId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext)
|
|
|
|
{
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"NewPlayerCallBack : %lx", PlayerId);
|
|
#endif
|
|
|
|
if (PlayerId == pidLocalPlayer) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"Is me");
|
|
#endif
|
|
gs_InfoLocal.DPlayPlayerId = PlayerId;
|
|
gs_InfoLocal.joinType = gs_JoinType;
|
|
gs_uwCallBack|=1;
|
|
}
|
|
|
|
NetLib_RegisterNewPlayer1(PlayerId, lpName->lpszShortNameA);
|
|
|
|
/* if we are the session host, we can finish registering ourself */
|
|
|
|
if (gs_JoinType==NetLib_Join_Create)
|
|
NetLib_RegisterNewPlayer2(PlayerId, GeneratePlayerId());
|
|
|
|
return TRUE; /* request next player */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_RegisterNewPlayer1(DPID PlayerId, char *lpName)
|
|
|
|
{
|
|
NetLib_tdstAddPlayerDesc *pstPlDesc;
|
|
char *acDPlayPlayerName;
|
|
|
|
/* register a new player: first part */
|
|
/* add an entry to the conversion table */
|
|
/* and wait for the NetLib Player Id */
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Register New Player 1: %lx / %s", PlayerId, lpName);
|
|
#endif
|
|
|
|
pstPlDesc=(NetLib_tdstAddPlayerDesc *)pMalloc(sizeof(NetLib_tdstAddPlayerDesc));
|
|
|
|
pstPlDesc->m_tduxPlayerId=C_uxNetInvalidId;
|
|
pstPlDesc->m_pPlayerDescriptionData=C_pNull; /* at first, let's not deal with player description */
|
|
pstPlDesc->m_uxPlayerDesciptionLength=0;
|
|
pstPlDesc->m_stL1AddPlayerDesc.m_eProtocol=E_Net_pr_Windows95DPlayProtocol;
|
|
pstPlDesc->m_stL1AddPlayerDesc.m_vL0Param=NULL;
|
|
pstPlDesc->IsYou=PlayerId == pidLocalPlayer;
|
|
|
|
pstPlDesc->JoinType=gs_JoinType;
|
|
|
|
pstPlDesc->Options=NULL;
|
|
|
|
acDPlayPlayerName=strdup(lpName);
|
|
|
|
NetLib_AddConversionEntry(PlayerId, pstPlDesc, acDPlayPlayerName);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_RegisterNewPlayer2(DPID DPlayPlayerId, NetLib_tduxPlayerId uxNetLibPlayerId)
|
|
|
|
{
|
|
/* register a new player: part 2 */
|
|
/* complete the conversion table entry */
|
|
/* and transmit the information to higher levels */
|
|
|
|
unsigned short i;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Register New Player 2: %lx / %lu", DPlayPlayerId, uxNetLibPlayerId);
|
|
#endif
|
|
|
|
if(DPlayPlayerId==gs_InfoLocal.DPlayPlayerId)
|
|
gs_InfoLocal.uxNetLibPlayerId = uxNetLibPlayerId;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].DPlayPlayerId == DPlayPlayerId) {
|
|
gs_stConvTable.dastConv[i].uxNetLibPlayerId=uxNetLibPlayerId;
|
|
if(gs_stConvTable.dastConv[i].pstPlDesc) {
|
|
gs_stConvTable.dastConv[i].pstPlDesc->m_tduxPlayerId=uxNetLibPlayerId;
|
|
NetLib_eAddNewPlayer(gs_stConvTable.dastConv[i].pstPlDesc);
|
|
vFree(gs_stConvTable.dastConv[i].pstPlDesc);
|
|
gs_stConvTable.dastConv[i].pstPlDesc=(NetLib_tdstAddPlayerDesc *)C_pNull;
|
|
NbrPlayer++;
|
|
} else {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Register New Player 2: no description for %lx / (i=%hu) ???", DPlayPlayerId, i);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_InitConversionTable(unsigned short uwMaxSize)
|
|
|
|
{
|
|
gs_stConvTable.uwSize=0;
|
|
gs_stConvTable.uwMaxSize=uwMaxSize;
|
|
gs_stConvTable.dastConv=(tdstConvLine *)pMalloc(gs_stConvTable.uwMaxSize*sizeof(tdstConvLine));
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_DeinitConversionTable()
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].pstPlDesc != (NetLib_tdstAddPlayerDesc*)C_pNull) {
|
|
vFree(gs_stConvTable.dastConv[i].pstPlDesc);
|
|
gs_stConvTable.dastConv[i].pstPlDesc=(NetLib_tdstAddPlayerDesc*)C_pNull;
|
|
}
|
|
|
|
vFree(gs_stConvTable.dastConv);
|
|
gs_stConvTable.dastConv=(tdstConvLine *)C_pNull;
|
|
|
|
gs_stConvTable.uwSize=gs_stConvTable.uwMaxSize=0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_AddConversionEntry(DPID DPlayPlayerId, NetLib_tdstAddPlayerDesc *pstPlDesc, char *pcDPlayPlayerName)
|
|
|
|
{
|
|
tdstConvLine *pstConvLine;
|
|
tdstConvLine *pstConvTable;
|
|
|
|
if(gs_stConvTable.uwSize==gs_stConvTable.uwMaxSize) {
|
|
/* reallocate table */
|
|
pstConvTable=(tdstConvLine *)pRealloc(gs_stConvTable.dastConv, (gs_stConvTable.uwSize+1)*sizeof(tdstConvLine));
|
|
|
|
if(pstConvTable != (tdstConvLine *)C_pNull) {
|
|
gs_stConvTable.uwMaxSize++;
|
|
gs_stConvTable.dastConv=pstConvTable;
|
|
} else
|
|
return;
|
|
}
|
|
|
|
pstConvLine=&gs_stConvTable.dastConv[gs_stConvTable.uwSize];
|
|
|
|
pstConvLine->uxNetLibPlayerId=C_uxNetInvalidId;
|
|
pstConvLine->DPlayPlayerId=DPlayPlayerId;
|
|
pstConvLine->pstPlDesc=pstPlDesc;
|
|
pstConvLine->pcDPlayPlayerName=pcDPlayPlayerName;
|
|
|
|
gs_stConvTable.uwSize++;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
void NetLib_SuppressConversionEntry(DPID DPlayPlayerId)
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].DPlayPlayerId == DPlayPlayerId) {
|
|
if(gs_stConvTable.dastConv[i].pstPlDesc != (NetLib_tdstAddPlayerDesc *)C_pNull)
|
|
vFree(gs_stConvTable.dastConv[i].pstPlDesc);
|
|
vFree(gs_stConvTable.dastConv[i].pcDPlayPlayerName);
|
|
memmove(&gs_stConvTable.dastConv[i],
|
|
&gs_stConvTable.dastConv[i+1],
|
|
(gs_stConvTable.uwMaxSize-gs_stConvTable.uwSize)*sizeof(tdstConvLine));
|
|
gs_stConvTable.uwSize--;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
DPlayHead *NetLib_BuildConversionMsg(DPID IdTo, unsigned short *p_uxSize)
|
|
|
|
{
|
|
|
|
tdstConversionMsg *ConversionInfo;
|
|
DPlayHead *pstSpecificMsg;
|
|
unsigned short i;
|
|
|
|
/* build a message that contains the conversion info for all players except the adressee */
|
|
/* the adressee is normally the last entry in the conversion table */
|
|
|
|
*p_uxSize=sizeof(DPlayHead)+sizeof(tdstConversionMsg)*(gs_stConvTable.uwSize-1);
|
|
|
|
pstSpecificMsg=(DPlayHead *)pMalloc(*p_uxSize);
|
|
|
|
if(pstSpecificMsg != (DPlayHead *)C_pNull) {
|
|
|
|
pstSpecificMsg->uxDPlaySpecific=NetLib_eIdTable;
|
|
|
|
ConversionInfo=(tdstConversionMsg *)(pstSpecificMsg+1);
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize-1; i++) /*if(gs_stConvTable.dastConv[i].DPlayPlayerId != IdTo)*/ {
|
|
ConversionInfo->DPlayPlayerId=gs_stConvTable.dastConv[i].DPlayPlayerId;
|
|
ConversionInfo->uxNetLibPlayerId=gs_stConvTable.dastConv[i].uxNetLibPlayerId;
|
|
ConversionInfo++;
|
|
}
|
|
}
|
|
|
|
return pstSpecificMsg;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
DPID NetLib_NetLibToDPlay(NetLib_tduxPlayerId uxNetLibPlayerId)
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].uxNetLibPlayerId == uxNetLibPlayerId)
|
|
return gs_stConvTable.dastConv[i].DPlayPlayerId;
|
|
|
|
return DPID_UNKNOWN;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
NetLib_tduxPlayerId NetLib_DPlayToNetLib(DPID DPlayPlayerId)
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].DPlayPlayerId == DPlayPlayerId)
|
|
return gs_stConvTable.dastConv[i].uxNetLibPlayerId;
|
|
|
|
return C_uxNetInvalidId;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
NetLib_tduxPlayerId GeneratePlayerId(void)
|
|
|
|
{
|
|
if(gs_uxPlayerIdGen==127) { /* hope this never happens ... */
|
|
gs_uxPlayerIdGen=0;
|
|
return 0;
|
|
}
|
|
|
|
return gs_uxPlayerIdGen++;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int CheckPlayerNbr()
|
|
|
|
{
|
|
if(NbrPlayer < glpdplConnection->lpSessionDesc->dwMaxPlayers)
|
|
return NetLib_DPlayWaiting;
|
|
else
|
|
return NetLib_DPlayGo;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Description: vL0PCWin95DPlayCloseChannel
|
|
* frees a slot in the channel table
|
|
*****************************************************************************
|
|
* Input: identifier of the channel
|
|
* Output: none
|
|
*****************************************************************************/
|
|
void vL0PCWin95DPlayCloseChannel(tduwNetChannel uwChannel)
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: uwL0PCWin95DPlayStartChannelScan
|
|
* returns the identification number of the first channel for the protocol
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: 0
|
|
*****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95DPlayStartChannelScan(void)
|
|
{
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x02))
|
|
return C_uwNetInvalidChannel;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: uwL0PCWin95DPlayNextChannel
|
|
* returns the identification number of the channel following the last
|
|
*****************************************************************************
|
|
* Input: uwLastScannedChannel, index returned by the previous call
|
|
* Output: C_uwNetInvalidChannel
|
|
*****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95DPlayNextChannel(tduwNetChannel uwLastScannedChannel)
|
|
{
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: uwL0PCWin95DPlayStartBroadcastChannelScan
|
|
* returns the identification number of the first broadcast channel
|
|
* for the protocol
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: 0
|
|
*****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95DPlayStartBroadcastChannelScan(void)
|
|
{
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x02))
|
|
return C_uwNetInvalidChannel;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: uwL0PCWin95DPlayNextBroadcastChannel
|
|
* returns the identification number of the broadcast channel following
|
|
* the specified one
|
|
*****************************************************************************
|
|
* Input: uwLastScannedChannel, index returned by the previous call
|
|
* Output: identification of the channel following the specified one
|
|
*****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95DPlayNextBroadcastChannel(tduwNetChannel uwLastScannedChannel)
|
|
{
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: wL0PCWin95DPlayGetMessage
|
|
*****************************************************************************
|
|
* Input: ppData, address of the pointer to retrieve a full message if
|
|
* necessary.
|
|
* Output: return 1 if getting a message and 0 otherwise.
|
|
*****************************************************************************/
|
|
short wL0PCWin95DPlayGetMessage(tdstNetMessage **ppMes)
|
|
{
|
|
FIFO *currentFIFOCell;
|
|
tdstNetMessage *pstMessage;
|
|
DPlayHead *pstDPlayHead;
|
|
if (FIFObegin==NULL)
|
|
{
|
|
*ppMes=NULL;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* avant tout, tester si l'expediteur est connu pour NetLib */
|
|
/* (et si on connait son propre id NetLib en local) */
|
|
pstMessage=(tdstNetMessage *)pMalloc(FIFObegin->size+sizeof(tdstNetMessage)-sizeof(DPlayHead));
|
|
|
|
pstDPlayHead=(DPlayHead *)(FIFObegin+1);
|
|
|
|
if (pstMessage==NULL) {
|
|
*ppMes=NULL;
|
|
return -1;
|
|
}
|
|
|
|
pstMessage->m_uxReadReceiptId=pstDPlayHead->m_ulReadReceiptId;
|
|
pstMessage->uxPriority=pstDPlayHead->uxPriority;
|
|
pstMessage->uxReplace=pstDPlayHead->uxReplace;
|
|
pstMessage->uxReplaceType=pstDPlayHead->uxReplaceType;
|
|
pstMessage->eMessageType=pstDPlayHead->eMessageType;
|
|
pstMessage->uxHeadBigEndian=pstDPlayHead->uxHeadBigEndian;
|
|
pstMessage->uxBodyBigEndian=pstDPlayHead->uxBodyBigEndian;
|
|
pstMessage->uwMessageSizeInBytes=(unsigned short)(FIFObegin->size-sizeof(DPlayHead));
|
|
pstMessage->uxSessionId=0;
|
|
pstMessage->uxSenderId=FIFObegin->uxSenderId;
|
|
pstMessage->uxRecipientId=gs_InfoLocal.uxNetLibPlayerId;
|
|
memcpy(pstMessage+1, pstDPlayHead+1, pstMessage->uwMessageSizeInBytes);
|
|
pstMessage->ulReserved=M_ulMakeReserved(M_uwProcessCheckSum(pstMessage),
|
|
M_uwProcessCheckSumBody(pstMessage));
|
|
|
|
currentFIFOCell=FIFObegin->next;
|
|
vFree((char *)FIFObegin);
|
|
FIFObegin=currentFIFOCell;
|
|
|
|
if (currentFIFOCell==NULL) FIFOend=&FIFObegin;
|
|
*ppMes=pstMessage;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "GetMessage(): Type %d, Size %d, Recipient %d",
|
|
pstMessage->eMessageType,
|
|
pstMessage->uwMessageSizeInBytes,
|
|
pstMessage->uxRecipientId);
|
|
#endif /* NET_USE_DEBUG */
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlayReadData
|
|
*****************************************************************************
|
|
* Input: p_uwChannel, pointer on a field to store the identification of
|
|
* a new channel in case of access to a newly created broacast channel
|
|
* (irrelevant for the serial layer)
|
|
* ppData, address of the pointer to retrieve a full message if
|
|
* necessary.
|
|
* Output: an error condition.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95DPlayReadData(tduwNetChannel *p_uwChannel, tdpPointer *ppData)
|
|
{
|
|
short r;
|
|
/* verify the validity of the Channel */
|
|
if(*p_uwChannel>1) return NetLib_E_es_InvalidChannel;
|
|
|
|
/* no : try to get a message from the FIFO */
|
|
r=wL0PCWin95DPlayGetMessage((tdstNetMessage **)ppData);
|
|
if (r>0) return NetLib_E_es_NoError;
|
|
else if (r==0) return NetLib_E_es_FIFOIsEmpty;
|
|
else return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlaySendData
|
|
*****************************************************************************
|
|
* Input: uwChannel, channel to send the message into.
|
|
* pData, pointer on the block to send
|
|
* Output: an error condition.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95DPlaySendData(tduwNetChannel uwChannel, tdpPointer pData)
|
|
{
|
|
unsigned long ulBytestoSend;
|
|
tdstNetMessage *pMes=(tdstNetMessage *)pData;
|
|
DPlayHead *pSend;
|
|
unsigned long NewTime;
|
|
DPID DPlayDestinationId;
|
|
DWORD dwFlags;
|
|
HRESULT hr;
|
|
|
|
/* verify that the system has been initialized */
|
|
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x02))
|
|
return NetLib_E_es_ProtocolNotInitialized;
|
|
|
|
/* verify the validity of the Channel */
|
|
if(uwChannel>1)
|
|
{
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Invalid channel %ud", uwChannel);
|
|
#endif
|
|
return NetLib_E_es_InvalidChannel;
|
|
}
|
|
|
|
if (pMes->uxRecipientId==C_uxNetBroadcastId) uwChannel=1;
|
|
|
|
ulBytestoSend= pMes->uwMessageSizeInBytes + sizeof(DPlayHead);
|
|
|
|
NewTime=GetTickCount();
|
|
SendBufSize-=((NewTime-LastTime)*(float)SendMaxRate)/1000;
|
|
LastTime=NewTime;
|
|
if (SendBufSize<0) SendBufSize=0;
|
|
if (SendBufSize>=DPLAY_MAXBUF) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"limiting throughput");
|
|
#endif
|
|
return NetLib_E_es_BufferIsFull;
|
|
}
|
|
|
|
SendBufSize+=ulBytestoSend+20;
|
|
|
|
pSend=(DPlayHead *)pMalloc(ulBytestoSend);
|
|
if (!pSend) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"out of memory");
|
|
#endif
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
|
|
memcpy(pSend+1,pMes+1,pMes->uwMessageSizeInBytes);
|
|
|
|
pSend->m_ulReadReceiptId=pMes->m_uxReadReceiptId;
|
|
pSend->uxPriority=pMes->uxPriority;
|
|
pSend->uxReplace=pMes->uxReplace;
|
|
pSend->uxReplaceType=pMes->uxReplaceType;
|
|
pSend->eMessageType=pMes->eMessageType;
|
|
pSend->uxHeadBigEndian=pMes->uxHeadBigEndian;
|
|
pSend->uxBodyBigEndian=pMes->uxBodyBigEndian;
|
|
|
|
pSend->uxDPlaySpecific=NetLib_ePureNetLib;
|
|
|
|
if (uwChannel!=1) {
|
|
DPlayDestinationId=NetLib_NetLibToDPlay(pMes->uxRecipientId);
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Send to one player. Type %d, Size %d, Recipient %d / %lx", pMes->eMessageType, pMes->uwMessageSizeInBytes, pMes->uxRecipientId, DPlayDestinationId);
|
|
#endif
|
|
dwFlags=DPSEND_GUARANTEED | DPSEND_OPENSTREAM;
|
|
} else {
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Send to all players. Type %d, Size %d, Recipient %d", pMes->eMessageType, pMes->uwMessageSizeInBytes, pMes->uxRecipientId);
|
|
#endif
|
|
DPlayDestinationId=DPID_ALLPLAYERS;
|
|
dwFlags=DPSEND_GUARANTEED;
|
|
}
|
|
|
|
hr=E_FAIL;
|
|
|
|
if(glpDP) {
|
|
hr=IDirectPlay3_Send( glpDP,
|
|
gs_InfoLocal.DPlayPlayerId,
|
|
DPlayDestinationId,
|
|
dwFlags,
|
|
(LPVOID)pSend,
|
|
ulBytestoSend);
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "SendData : DP3Send : error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
vFree((char *)pSend);
|
|
|
|
if (hr==DPERR_BUSY)
|
|
{
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"emission failure: send queue is full");
|
|
#endif
|
|
return NetLib_E_es_BufferIsFull;
|
|
} else if(hr<0) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"emission failure: %lx", hr);
|
|
#endif
|
|
return NetLib_E_es_UnknownError;
|
|
}
|
|
|
|
/* free the message buffer */
|
|
vFree(pData);
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlayQueryChannelStatus
|
|
* returns the current status of the channel
|
|
*****************************************************************************
|
|
* Input: uwChannel, channel to query
|
|
* Output: an error condition.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95DPlayQueryChannelStatus(tduwNetChannel uwChannel)
|
|
{
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlayEngine
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************/
|
|
void eL0PCWin95DPlayEngine(void)
|
|
{
|
|
|
|
DPID IdFrom, IdTo;
|
|
unsigned long ulBytesToRead;
|
|
FIFO *pstFIFOCell;
|
|
HRESULT hr;
|
|
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x02))
|
|
return;
|
|
|
|
if(!glpDP)
|
|
return;
|
|
|
|
do {
|
|
hr=IDirectPlay3_Receive(glpDP,
|
|
&IdFrom, &IdTo,
|
|
DPRECEIVE_ALL | DPRECEIVE_PEEK,
|
|
NULL,
|
|
&ulBytesToRead);
|
|
if(hr==DPERR_BUFFERTOOSMALL) {
|
|
pstFIFOCell=(FIFO *)pMalloc(ulBytesToRead+sizeof(FIFO));
|
|
|
|
if(pstFIFOCell==(FIFO *)C_pNull)
|
|
return;
|
|
|
|
hr=IDirectPlay3_Receive(glpDP,
|
|
&IdFrom, &IdTo,
|
|
DPRECEIVE_ALL,
|
|
pstFIFOCell+1,
|
|
&ulBytesToRead);
|
|
|
|
pstFIFOCell->size=ulBytesToRead;
|
|
pstFIFOCell->DPlayIdFrom=IdFrom;
|
|
pstFIFOCell->next=(FIFO *)C_pNull;
|
|
|
|
NetLib_DPlayHandleNewMsg(pstFIFOCell, IdTo);
|
|
} else if(hr != DPERR_NOMESSAGES) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay,"reception failure: %lx", hr);
|
|
#endif /* NET_USE_DEBUG */
|
|
}
|
|
|
|
} while(hr==DP_OK); /* introduire une limite sur le nombre de messages lus par appel */
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void NetLib_DPlayHandleNewMsg(FIFO *pstFIFOCell, DPID IdTo)
|
|
|
|
{
|
|
DPlayHead *pstDPlayMsg;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"HandleNewMsg()");
|
|
#endif
|
|
|
|
/* first, handle Direct Play system messages */
|
|
|
|
if(pstFIFOCell->DPlayIdFrom==DPID_SYSMSG) {
|
|
switch(((LPDPMSG_GENERIC)(pstFIFOCell+1))->dwType) {
|
|
case DPSYS_CREATEPLAYERORGROUP:
|
|
NetLib_DPlayHandleNewPlayerMsg(pstFIFOCell, IdTo);
|
|
break;
|
|
case DPSYS_DESTROYPLAYERORGROUP:
|
|
NetLib_DPlayHandlePlayerLeftMsg(pstFIFOCell, IdTo);
|
|
break;
|
|
default:
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"HandleNewMsg() : unhandled system message %lx", ((LPDPMSG_GENERIC)(pstDPlayMsg+1))->dwType);
|
|
#endif
|
|
|
|
;
|
|
}
|
|
vFree(pstFIFOCell);
|
|
|
|
} else {
|
|
|
|
pstDPlayMsg=(DPlayHead *)(pstFIFOCell+1);
|
|
|
|
if(pstDPlayMsg->uxDPlaySpecific != NetLib_ePureNetLib) {
|
|
/* this is a message specific to the Direct Play subsystem: interpret it */
|
|
NetLib_DPlayHandleSpecificMsg(pstFIFOCell, IdTo);
|
|
vFree(pstFIFOCell);
|
|
} else {
|
|
/* this is a normal NetLib message: */
|
|
/* translate the player Id and enqueue the message */
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"Received: Type %lu, Size %lu, Source %lx",
|
|
pstDPlayMsg->eMessageType,
|
|
pstFIFOCell->size-sizeof(DPlayHead),
|
|
pstFIFOCell->DPlayIdFrom);
|
|
#endif
|
|
pstFIFOCell->uxSenderId=NetLib_DPlayToNetLib(pstFIFOCell->DPlayIdFrom);
|
|
*FIFOend=pstFIFOCell;
|
|
|
|
FIFOend=&(pstFIFOCell->next);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void NetLib_DPlayHandleNewPlayerMsg(FIFO *pstFIFOCell, DPID IdTo)
|
|
|
|
{
|
|
HRESULT hr;
|
|
LPDPMSG_CREATEPLAYERORGROUP pSysMsg;
|
|
NetLib_tduxPlayerId uxNetLibPlayerId;
|
|
tdstConversionMsg *ConversionInfo;
|
|
DPlayHead *pstSpecificMsg;
|
|
unsigned short uxSize;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"HandleNewPlayerMsg()");
|
|
#endif
|
|
|
|
pSysMsg = (LPDPMSG_CREATEPLAYERORGROUP) (pstFIFOCell+1);
|
|
|
|
/* if we host the session, then we have to generate a NetLib identifier for this player */
|
|
/* send this identifier to all other players */
|
|
/* and then send the list of all identifiers to this new player */
|
|
/* if we don't host the session, we remember that a new play has come */
|
|
/* and wait for a message from the host to know its NetLib identifier */
|
|
|
|
NetLib_RegisterNewPlayer1(pSysMsg->dpId, pSysMsg->dpnName.lpszShortNameA);
|
|
|
|
if(gs_InfoLocal.joinType==NetLib_Join_Create) {
|
|
/* we host the session: generate a new identifier for this player */
|
|
uxNetLibPlayerId=GeneratePlayerId();
|
|
|
|
NetLib_RegisterNewPlayer2(pSysMsg->dpId, uxNetLibPlayerId);
|
|
|
|
/* send the new NetLib id to everyone */
|
|
|
|
pstSpecificMsg=(DPlayHead *)pMalloc(sizeof(DPlayHead)+sizeof(tdstConversionMsg));
|
|
|
|
if(pstSpecificMsg) {
|
|
pstSpecificMsg->uxDPlaySpecific=NetLib_eNewPlayerId;
|
|
|
|
ConversionInfo=(tdstConversionMsg *)(pstSpecificMsg+1);
|
|
|
|
ConversionInfo->DPlayPlayerId=pSysMsg->dpId;
|
|
ConversionInfo->uxNetLibPlayerId=uxNetLibPlayerId;
|
|
|
|
|
|
hr=IDirectPlay3_Send( glpDP,
|
|
gs_InfoLocal.DPlayPlayerId,
|
|
DPID_ALLPLAYERS,
|
|
DPSEND_GUARANTEED,
|
|
(LPVOID)pstSpecificMsg,
|
|
sizeof(DPlayHead)+sizeof(tdstConversionMsg));
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "HandleNewPlayerMsg : DP3Send : error %lx", hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* send all NetLib ids to the new player */
|
|
|
|
pstSpecificMsg=NetLib_BuildConversionMsg(pSysMsg->dpId, &uxSize);
|
|
|
|
if(pstSpecificMsg) {
|
|
hr=IDirectPlay3_Send( glpDP,
|
|
gs_InfoLocal.DPlayPlayerId,
|
|
pSysMsg->dpId,
|
|
DPSEND_GUARANTEED,
|
|
(LPVOID)pstSpecificMsg,
|
|
uxSize);
|
|
|
|
if(hr != DP_OK) {
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "HandleNewPlayerMsg : DP3Send : error %lx", hr);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void NetLib_DPlayHandlePlayerLeftMsg(FIFO *pstFIFOCell, DPID IdTo)
|
|
|
|
{
|
|
LPDPMSG_DELETEPLAYERFROMGROUP pSysMsg;
|
|
|
|
pSysMsg=(LPDPMSG_DELETEPLAYERFROMGROUP)(pstFIFOCell+1);
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"HandlePlayerLeftMsg(): Player %lx", pSysMsg->dpIdPlayer);
|
|
#endif
|
|
|
|
NetLib_SuppressConversionEntry(pSysMsg->dpIdPlayer);
|
|
|
|
NbrPlayer--;
|
|
|
|
/* in normal conditions (i.e. the remote player made a call to DisconnectFromSession() */
|
|
/* the higher levels already have suppressed this player upon reception of the */
|
|
/* disconnection message */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void NetLib_DPlayHandleSpecificMsg(FIFO *pstFIFOCell, DPID IdTo)
|
|
|
|
{
|
|
DPlayHead *pstMsg;
|
|
tdstConversionMsg *pstConversionMsg;
|
|
unsigned int i, uwNbrOfLines;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugFormat(Net_C_Debug_DPlay,"HandleSpecificMsg()");
|
|
#endif
|
|
|
|
pstMsg=(DPlayHead *)(pstFIFOCell+1);
|
|
|
|
switch(pstMsg->uxDPlaySpecific) {
|
|
|
|
case NetLib_eNewPlayerId:
|
|
pstConversionMsg=(tdstConversionMsg *)(pstMsg+1);
|
|
NetLib_RegisterNewPlayer2(pstConversionMsg->DPlayPlayerId,
|
|
pstConversionMsg->uxNetLibPlayerId);
|
|
break;
|
|
/* the message contains the NetLib ID of a new player */
|
|
|
|
case NetLib_eIdTable:
|
|
pstConversionMsg=(tdstConversionMsg *)(pstMsg+1);
|
|
uwNbrOfLines=(pstFIFOCell->size - sizeof(DPlayHead)) / sizeof(tdstConversionMsg);
|
|
for(i=0; i<uwNbrOfLines; i++)
|
|
NetLib_RegisterNewPlayer2(pstConversionMsg[i].DPlayPlayerId,
|
|
pstConversionMsg[i].uxNetLibPlayerId);
|
|
|
|
break;
|
|
/* the message contains a table of the NetLib IDs for all players except the local player */
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description : vL0PCWin95DPlayCloseProtocol(void)
|
|
* DPlay-Level 0 closing function
|
|
*****************************************************************************
|
|
* Input : none
|
|
* Output : none
|
|
*****************************************************************************/
|
|
void vL0PCWin95DPlayCloseProtocol(void)
|
|
{
|
|
FIFO *p;
|
|
while (FIFObegin)
|
|
{
|
|
p=FIFObegin->next;
|
|
vFree((char*)FIFObegin);
|
|
FIFObegin=p;
|
|
}
|
|
FIFObegin=NULL;
|
|
FIFOend=&FIFObegin;
|
|
|
|
vLevel1RemoveProtocol(E_Net_pr_Windows95DPlayProtocol);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vL0PCWin95DPlayAddNewPlayer
|
|
*****************************************************************************
|
|
* Input: pChanel : adress of returned chanel.
|
|
* par : extern parameter.
|
|
* Output: error code.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus vL0PCWin95DPlayAddNewPlayer(tduwNetChannel *pChannel,void *par)
|
|
{
|
|
*pChannel=0;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vL0PCWin95DPlayOpenProtocol
|
|
* initialize the specified interface structure with the correct function
|
|
* pointers to enable a protocol-independent data transmission process.
|
|
*****************************************************************************
|
|
* Input: p_stProtocolInterface, pointer to the interface structure
|
|
* uwPortNumber, port number to bind the socket to
|
|
* Output: none
|
|
*****************************************************************************/
|
|
void _NET_CALLING_CONV_ vL0PCWin95DPlayOpenProtocol(void)
|
|
{
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugClear(Net_C_Debug_DPlay);
|
|
vDebugS(Net_C_Debug_DPlay,"SetupInterface");
|
|
#endif
|
|
|
|
p_stProtocolInterface=pstLevel1AddProtocol();
|
|
|
|
FIFObegin=NULL;
|
|
FIFOend=&FIFObegin;
|
|
|
|
/* logical identification of the protocol */
|
|
p_stProtocolInterface->eProtocol = E_Net_pr_Windows95DPlayProtocol;
|
|
|
|
/* setup the function pointers */
|
|
p_stProtocolInterface->fn_uwStartChannelScan = uwL0PCWin95DPlayStartChannelScan;
|
|
p_stProtocolInterface->fn_uwStartBroadcastChannelScan= uwL0PCWin95DPlayStartBroadcastChannelScan;
|
|
p_stProtocolInterface->fn_uwNextChannel= uwL0PCWin95DPlayNextChannel;
|
|
p_stProtocolInterface->fn_uwNextBroadcastChannel= uwL0PCWin95DPlayNextBroadcastChannel;
|
|
p_stProtocolInterface->fn_eReadData= eL0PCWin95DPlayReadData;
|
|
p_stProtocolInterface->fn_eSendData= eL0PCWin95DPlaySendData;
|
|
p_stProtocolInterface->fn_eQueryChannelStatus= eL0PCWin95DPlayQueryChannelStatus;
|
|
p_stProtocolInterface->fn_vLevel0NetEngine = eL0PCWin95DPlayEngine;
|
|
p_stProtocolInterface->fn_vCloseChannel = vL0PCWin95DPlayCloseChannel;
|
|
p_stProtocolInterface->fn_vLevel0CloseProtocol = vL0PCWin95DPlayCloseProtocol;
|
|
p_stProtocolInterface->fn_eAddNewPlayer = vL0PCWin95DPlayAddNewPlayer;
|
|
|
|
gs_bL0PCWin95DPlayInitState = 0x01;
|
|
|
|
gs_uxPlayerIdGen=0;
|
|
NetLib_InitConversionTable(8);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlayStart
|
|
* Start a game with DPlay
|
|
*****************************************************************************
|
|
* Input: ppGameOptions : Adresse of a pointer wich receive the adresse of
|
|
* game options.
|
|
* Output: join type.
|
|
*****************************************************************************/
|
|
_NET_EXPORT_ NetLib_tduwJoinType _NET_CALLING_CONV_ eL0PCWin95DPlayStart(char cMode)
|
|
{
|
|
int Status;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"Start");
|
|
#endif
|
|
|
|
SendMaxRate=1000L;
|
|
NbrPlayer=0;
|
|
SendBufSize=0;
|
|
TabPlayer=NULL;
|
|
LastTime=GetTickCount();
|
|
FIFObegin=NULL;
|
|
FIFOend=&FIFObegin;
|
|
|
|
/* obtain a directplay lobby interface*/
|
|
|
|
if(DPLobbyCreate() != DP_OK)
|
|
return -1;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyCreate: OK");
|
|
#endif
|
|
|
|
/* retrieve the session information */
|
|
|
|
if(DPLobbyGetConnectionSettings() != DP_OK)
|
|
return -1;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyGetConnectionSettings: OK");
|
|
#endif
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "session name : %s", glpdplConnection->lpSessionDesc->lpszSessionNameA);
|
|
vDebugFormat(Net_C_Debug_DPlay, "max # players : %ld", glpdplConnection->lpSessionDesc->dwMaxPlayers);
|
|
vDebugFormat(Net_C_Debug_DPlay, "current # players : %ld", glpdplConnection->lpSessionDesc->dwCurrentPlayers);
|
|
#endif
|
|
|
|
/* connect to the session */
|
|
|
|
if(DPLobbyConnect() != DP_OK)
|
|
return -1;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPLobbyConnect: OK");
|
|
#endif
|
|
|
|
/* create the local player */
|
|
|
|
if(DPCreatePlayer() != DP_OK)
|
|
return -1;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPCreatePlayer: OK");
|
|
#endif
|
|
|
|
/* wait for other players ? or not ? */
|
|
|
|
if(DPEnumPlayers() != DP_OK)
|
|
return -1;
|
|
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_DPlay, "DPEnumPlayers: OK");
|
|
#endif
|
|
|
|
if(cMode==NetLib_DPlayClosed)
|
|
/* wait for all players to arrive*/
|
|
|
|
do {
|
|
eL0PCWin95DPlayEngine();
|
|
Status=CheckPlayerNbr();
|
|
} while(Status==NetLib_DPlayWaiting);
|
|
|
|
gs_bL0PCWin95DPlayInitState|=0x02;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"Start: returning");
|
|
#endif
|
|
|
|
return gs_JoinType;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95DPlayFinish
|
|
* Finish a game with DPlay.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************/
|
|
_NET_EXPORT_ void _NET_CALLING_CONV_ eL0PCWin95DPlayFinish(void)
|
|
{
|
|
FIFO *p;
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_DPlay,"Finish");
|
|
#endif
|
|
vFree((char *)TabPlayer);
|
|
while (FIFObegin)
|
|
{
|
|
p=FIFObegin->next;
|
|
vFree((char*)FIFObegin);
|
|
FIFObegin=p;
|
|
}
|
|
FIFObegin=NULL;
|
|
FIFOend=&FIFObegin;
|
|
gs_bL0PCWin95DPlayInitState&=~0x02;
|
|
NetLib_eFlushSendingList(500);
|
|
NetLib_vDisconnectAllRemotePlayers();
|
|
|
|
DPClose();
|
|
DPRelease();
|
|
DPLobbyRelease();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
NetLib_tdeErrorStatus eL0PCWin95DPlayGetPlayerName(NetLib_tduxPlayerId uxPlayerId, char *pcString, unsigned short uwSize)
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_stConvTable.uwSize; i++)
|
|
if(gs_stConvTable.dastConv[i].uxNetLibPlayerId == uxPlayerId) {
|
|
strncpy(pcString, gs_stConvTable.dastConv[i].pcDPlayPlayerName, uwSize-1);
|
|
pcString[uwSize]='\0';
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
return NetLib_E_es_UnknownPlayerId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description : eL0PCWin95DPlayIsProtocolSet
|
|
* Check if the protocol is correctly initialize or not
|
|
*****************************************************************************
|
|
* Input : none
|
|
* Output : NetLib_E_es_True
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95DPlayIsProtocolSet(void)
|
|
{
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x01)) return NetLib_E_es_ProtocolNotInitialized;
|
|
return NetLib_E_es_True;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description : eL0PCWin95DPlayIsProtocolAvailable
|
|
* Check if the protocol is avaible for use or not
|
|
*****************************************************************************
|
|
* Input : A port number to test
|
|
* Output : NetLib_E_es_True if the port is avaible
|
|
* An error code otherwise
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95DPlayIsProtocolAvailable(void)
|
|
{
|
|
if(!(gs_bL0PCWin95DPlayInitState&0x01)) return NetLib_E_es_ProtocolNotInitialized;
|
|
return NetLib_E_es_True;
|
|
}
|