Initial commit: ROW Client source code
Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,845 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// File: dplay8client.cpp
|
||||
//
|
||||
// Desc: see main.cpp
|
||||
//
|
||||
// Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <windows.h>
|
||||
#include <d3dx.h>
|
||||
#include <process.h>
|
||||
#include <tchar.h>
|
||||
#include <assert.h>
|
||||
#include <dxerr8.h>
|
||||
#include <stdio.h>
|
||||
#include <dplay8.h>
|
||||
#include <dpaddr.h>
|
||||
#include "DummyConnector.h"
|
||||
#include "StressMazeGUID.h"
|
||||
#include "DXUtil.h"
|
||||
#include "MazeApp.h"
|
||||
#include "DPlay8Client.h"
|
||||
|
||||
|
||||
#define DPMAZESERVER_PORT 2309
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
CDPlay8Client::CDPlay8Client()
|
||||
{
|
||||
m_dwNumSessions = 0;
|
||||
|
||||
m_wActiveThreadCount = 0;
|
||||
m_wMaxThreadCount = 0;
|
||||
m_fAvgThreadCount = 0;
|
||||
m_fAvgThreadTime = 0;
|
||||
m_fMaxThreadTime = 0;
|
||||
|
||||
m_pClient = NULL;
|
||||
m_pDPlay = NULL;
|
||||
m_dpnhEnum = NULL;
|
||||
m_bSessionLost = TRUE;
|
||||
m_dwSessionLostReason = DISCONNNECT_REASON_UNKNOWN;
|
||||
|
||||
for( DWORD dwIndex = 0; dwIndex < MAX_SESSIONS; dwIndex++ )
|
||||
{
|
||||
m_pHostAddresses[dwIndex] = NULL;
|
||||
m_pDeviceAddresses[dwIndex] = NULL;
|
||||
}
|
||||
|
||||
InitializeCriticalSection( &m_csLock );
|
||||
InitializeCriticalSection( &m_csThreadCountLock );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
CDPlay8Client::~CDPlay8Client()
|
||||
{
|
||||
DeleteCriticalSection( &m_csLock );
|
||||
DeleteCriticalSection( &m_csThreadCountLock );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::Init(MazeConfig* pMazeConfig)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
||||
m_MazeConfig = pMazeConfig;
|
||||
|
||||
Shutdown();
|
||||
|
||||
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Client, NULL,
|
||||
CLSCTX_ALL, IID_IDirectPlay8Client,
|
||||
(LPVOID*) &m_pDPlay ) ) )
|
||||
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
|
||||
|
||||
if( FAILED( hr = m_pDPlay->Initialize( this, StaticReceiveHandler, 0 ) ) )
|
||||
return DXTRACE_ERR( TEXT("Initialize"), hr );
|
||||
|
||||
// If between Range, attempt to set SPThreads.
|
||||
if((m_MazeConfig->dwSPThreads >= MIN_SP_THREADS) && (m_MazeConfig->dwSPThreads <= MAX_SP_THREADS))
|
||||
{
|
||||
SetNumSPThreads(m_MazeConfig->dwSPThreads);
|
||||
}
|
||||
|
||||
// If less than MAX, set our SP Buffer.
|
||||
if(m_MazeConfig->dwSPBufferSize <= MAX_SP_BUFFER)
|
||||
{
|
||||
SetSPBuffer(m_MazeConfig->dwSPBufferSize);
|
||||
}
|
||||
|
||||
m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
m_bSessionLost = TRUE;
|
||||
m_dwNumSessions = 0;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD CDPlay8Client::GetNumSPThreads()
|
||||
{
|
||||
|
||||
HRESULT hr = DPN_OK;
|
||||
|
||||
DPN_SP_CAPS dnSPCaps;
|
||||
DWORD dwFlags = NULL;
|
||||
DWORD dwNumSPThreads = NULL;
|
||||
|
||||
DXTRACE_MSG( TEXT("Attempting to Get SP Thread Count.") );
|
||||
|
||||
dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
|
||||
|
||||
hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr != DPN_OK)
|
||||
{
|
||||
DXTRACE_ERR( TEXT("GetSPCaps error"), hr );
|
||||
dwNumSPThreads = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwNumSPThreads = dnSPCaps.dwNumThreads;
|
||||
}
|
||||
|
||||
return dwNumSPThreads;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDPlay8Client::SetNumSPThreads(DWORD dwNumSPThreads)
|
||||
{
|
||||
HRESULT hr = DPN_OK;
|
||||
|
||||
DPN_SP_CAPS dnSPCaps;
|
||||
DWORD dwFlags = NULL;
|
||||
|
||||
dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
|
||||
hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr == DPN_OK)
|
||||
{
|
||||
if((dwNumSPThreads >= MIN_SP_THREADS) && (dwNumSPThreads <= MAX_SP_THREADS))
|
||||
{
|
||||
dnSPCaps.dwNumThreads = dwNumSPThreads;
|
||||
|
||||
// Attempt to set the number of SP Threads.
|
||||
hr = m_pDPlay->SetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr != DPN_OK)
|
||||
{
|
||||
DXTRACE_ERR( TEXT("SetSPCaps error."), hr );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DXTRACE_ERR( TEXT("GetSPCaps error."), hr );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD CDPlay8Client::GetSPBuffer()
|
||||
{
|
||||
|
||||
HRESULT hr = DPN_OK;
|
||||
|
||||
DPN_SP_CAPS dnSPCaps;
|
||||
DWORD dwFlags = NULL;
|
||||
DWORD dwSPBufferSize = NULL;
|
||||
|
||||
DXTRACE_MSG( TEXT("Attempting to Get SP Buffer Size.") );
|
||||
|
||||
dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
|
||||
|
||||
hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr != DPN_OK)
|
||||
{
|
||||
DXTRACE_ERR( TEXT("GetSPCaps error"), hr );
|
||||
dwSPBufferSize = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwSPBufferSize = dnSPCaps.dwSystemBufferSize;
|
||||
}
|
||||
|
||||
return dwSPBufferSize;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDPlay8Client::SetSPBuffer(DWORD dwSPBufferSize)
|
||||
{
|
||||
HRESULT hr = DPN_OK;
|
||||
|
||||
DPN_SP_CAPS dnSPCaps;
|
||||
DWORD dwFlags = NULL;
|
||||
|
||||
dnSPCaps.dwSize = sizeof(DPN_SP_CAPS);
|
||||
hr = m_pDPlay->GetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr == DPN_OK)
|
||||
{
|
||||
if(dwSPBufferSize <= MAX_SP_BUFFER)
|
||||
dnSPCaps.dwSystemBufferSize = dwSPBufferSize;
|
||||
|
||||
// Attempt to set the number of SP Threads.
|
||||
hr = m_pDPlay->SetSPCaps(&CLSID_DP8SP_TCPIP, &dnSPCaps, dwFlags);
|
||||
if(hr != DPN_OK)
|
||||
{
|
||||
DXTRACE_ERR( TEXT("SetSPCaps error."), hr );
|
||||
}
|
||||
}
|
||||
else // !GetSPCase != DPN_OK
|
||||
{
|
||||
DXTRACE_ERR( TEXT("GetSPCaps error."), hr );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDPlay8Client::Shutdown()
|
||||
{
|
||||
for( DWORD dwIndex = 0; dwIndex < MAX_SESSIONS; dwIndex++ )
|
||||
{
|
||||
SAFE_RELEASE( m_pHostAddresses[dwIndex] );
|
||||
SAFE_RELEASE( m_pDeviceAddresses[dwIndex] );
|
||||
}
|
||||
|
||||
if( m_dpnhEnum != NULL )
|
||||
{
|
||||
// Cancel the enumeration if its in progress, and ignore any errors
|
||||
m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
|
||||
m_dpnhEnum = NULL;
|
||||
}
|
||||
|
||||
if( m_pDPlay != NULL )
|
||||
m_pDPlay->Close(0);
|
||||
|
||||
SAFE_RELEASE( m_pDPlay );
|
||||
m_bSessionLost = TRUE;
|
||||
m_dwNumSessions = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::StartSessionEnum( const TCHAR* ipaddress )
|
||||
{
|
||||
if( NULL == m_pDPlay )
|
||||
return E_FAIL;
|
||||
|
||||
DPN_APPLICATION_DESC dpnAppDesc;
|
||||
IDirectPlay8Address* pDP8AddressHost = NULL;
|
||||
IDirectPlay8Address* pDP8AddressLocal = NULL;
|
||||
WCHAR* wszHostName = NULL;
|
||||
HRESULT hr;
|
||||
DWORD dwPort;
|
||||
|
||||
m_dwNumSessions = 0;
|
||||
|
||||
if( m_dpnhEnum != NULL )
|
||||
{
|
||||
// If an enumeration is already running, cancel
|
||||
// it and start a new one. Ignore any errors from CancelAsyncOperation
|
||||
m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
|
||||
m_dpnhEnum = NULL;
|
||||
}
|
||||
|
||||
// Create the local device address object
|
||||
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
|
||||
CLSCTX_ALL, IID_IDirectPlay8Address,
|
||||
(LPVOID*) &pDP8AddressLocal ) ) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Set IP service provider
|
||||
if( FAILED( hr = pDP8AddressLocal->SetSP( &CLSID_DP8SP_TCPIP ) ) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("SetSP"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
|
||||
// Create the remote host address object
|
||||
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
|
||||
CLSCTX_ALL, IID_IDirectPlay8Address,
|
||||
(LPVOID*) &pDP8AddressHost ) ) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Set IP service provider
|
||||
if( FAILED( hr = pDP8AddressHost->SetSP( &CLSID_DP8SP_TCPIP ) ) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("SetSP"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Maze uses a fixed port, so add it to the host address
|
||||
dwPort = DPMAZESERVER_PORT;
|
||||
hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT,
|
||||
&dwPort, sizeof(dwPort),
|
||||
DPNA_DATATYPE_DWORD );
|
||||
if( FAILED(hr) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("AddComponent"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Set the remote host name (if provided)
|
||||
if( ipaddress != NULL && ipaddress[0] != 0 )
|
||||
{
|
||||
wszHostName = new WCHAR[_tcslen(ipaddress)+1];
|
||||
|
||||
DXUtil_ConvertGenericStringToWide( wszHostName, ipaddress );
|
||||
|
||||
hr = pDP8AddressHost->AddComponent( DPNA_KEY_HOSTNAME, wszHostName,
|
||||
(wcslen(wszHostName)+1)*sizeof(WCHAR),
|
||||
DPNA_DATATYPE_STRING );
|
||||
if( FAILED(hr) )
|
||||
{
|
||||
DXTRACE_ERR( TEXT("AddComponent"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) );
|
||||
dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
|
||||
dpnAppDesc.guidApplication = StressMazeAppGUID;
|
||||
|
||||
// Enumerate all StressMazeApp hosts running on IP service providers
|
||||
hr = m_pDPlay->EnumHosts( &dpnAppDesc, pDP8AddressHost,
|
||||
pDP8AddressLocal, NULL,
|
||||
0, INFINITE, 0, INFINITE, NULL,
|
||||
&m_dpnhEnum, 0 );
|
||||
if( hr != DPNERR_PENDING && FAILED(hr) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("EnumHosts"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
LCleanup:
|
||||
SAFE_RELEASE( pDP8AddressHost);
|
||||
SAFE_RELEASE( pDP8AddressLocal );
|
||||
SAFE_DELETE( wszHostName );
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::StopSessionEnum()
|
||||
{
|
||||
if( NULL == m_pDPlay )
|
||||
return E_FAIL;
|
||||
|
||||
// If an enumeration is already running, cancel it and ignore
|
||||
// any errors from CancelAsyncOperation
|
||||
if( m_dpnhEnum != NULL )
|
||||
{
|
||||
m_pDPlay->CancelAsyncOperation( m_dpnhEnum, 0 );
|
||||
m_dpnhEnum = NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CDPlay8Client::EnumSessionCallback( const DPN_APPLICATION_DESC *pdesc,
|
||||
IDirectPlay8Address* pDP8AddressHost,
|
||||
IDirectPlay8Address* pDP8AddressDevice )
|
||||
{
|
||||
if( NULL == m_pDPlay )
|
||||
return DPN_OK;
|
||||
|
||||
EnterCriticalSection( &m_csLock );
|
||||
|
||||
if( m_dwNumSessions < MAX_SESSIONS )
|
||||
{
|
||||
// Search for existing record for this session, if
|
||||
// there is one, break this loop so we just update
|
||||
// the current entry.
|
||||
for( DWORD dwIndex = 0; dwIndex < m_dwNumSessions; dwIndex++ )
|
||||
{
|
||||
if( m_Sessions[dwIndex].guidInstance == pdesc->guidInstance )
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy( &m_Sessions[dwIndex], pdesc, sizeof( DPN_APPLICATION_DESC ) );
|
||||
|
||||
// Copy pDP8AddressHost to m_pHostAddresses[dwIndex]
|
||||
SAFE_RELEASE( m_pHostAddresses[dwIndex] );
|
||||
pDP8AddressHost->QueryInterface( IID_IDirectPlay8Address,
|
||||
(LPVOID*) &m_pHostAddresses[dwIndex] );
|
||||
|
||||
// Copy pDP8AddressDevice to m_pDeviceAddresses[dwIndex]
|
||||
SAFE_RELEASE( m_pDeviceAddresses[dwIndex] );
|
||||
pDP8AddressDevice->QueryInterface( IID_IDirectPlay8Address,
|
||||
(LPVOID*) &m_pDeviceAddresses[dwIndex] );
|
||||
|
||||
if( pdesc->pwszSessionName != NULL )
|
||||
{
|
||||
DXUtil_ConvertWideStringToGeneric( m_szSessionNames[dwIndex],
|
||||
pdesc->pwszSessionName );
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcscpy( m_szSessionNames[dwIndex], TEXT("Untitled") );
|
||||
}
|
||||
|
||||
if( m_dwNumSessions == dwIndex )
|
||||
m_dwNumSessions++;
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &m_csLock );
|
||||
|
||||
return DPN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::JoinSession( DWORD num )
|
||||
{
|
||||
HRESULT hr;
|
||||
IDirectPlay8Address* pHostAddress = NULL;
|
||||
IDirectPlay8Address* pDeviceAddress = NULL;
|
||||
|
||||
if( m_pDPlay == NULL )
|
||||
return E_FAIL;
|
||||
|
||||
DXTRACE( TEXT("MazeClient: Trying to connect to server\n") );
|
||||
|
||||
DPN_APPLICATION_DESC dpnAppDesc;
|
||||
ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) );
|
||||
dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
|
||||
dpnAppDesc.guidApplication = StressMazeAppGUID;
|
||||
dpnAppDesc.guidInstance = m_Sessions[num].guidInstance;
|
||||
|
||||
EnterCriticalSection( &m_csLock );
|
||||
|
||||
// Copy the host and device address pointers, and addref them.
|
||||
// If this is not done, then there is a rare chance that
|
||||
// EnumSessionCallback() may be called during the Connect() call
|
||||
// and destory the address before DirectPlay gets a chance to copy them.
|
||||
pHostAddress = m_pHostAddresses[num];
|
||||
pHostAddress->AddRef();
|
||||
|
||||
pDeviceAddress = m_pDeviceAddresses[num];
|
||||
pDeviceAddress->AddRef();
|
||||
|
||||
LeaveCriticalSection( &m_csLock );
|
||||
|
||||
// Connect to the remote host
|
||||
// The enumeration is automatically canceled after Connect is called
|
||||
if( FAILED( hr = m_pDPlay->Connect( &dpnAppDesc, // Application description
|
||||
pHostAddress, // Session host address
|
||||
pDeviceAddress, // Address of device used to connect to the host
|
||||
NULL, NULL, // Security descriptions & credientials (MBZ in DPlay8)
|
||||
NULL, 0, // User data & its size
|
||||
NULL, // Asynchronous connection context (returned with DPNMSG_CONNECT_COMPLETE in async handshaking)
|
||||
NULL, // Asynchronous connection handle (used to cancel connection process)
|
||||
DPNOP_SYNC ) ) ) // Connect synchronously
|
||||
{
|
||||
if( hr == DPNERR_NORESPONSE || hr == DPNERR_ABORTED )
|
||||
goto LCleanup; // These are possible if the server exits while joining
|
||||
|
||||
if( hr == DPNERR_INVALIDINSTANCE )
|
||||
goto LCleanup; // This is possible if the original server exits and another server comes online while we are connecting
|
||||
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("Connect"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
m_bSessionLost = FALSE;
|
||||
|
||||
DXTRACE( TEXT("MazeClient: Connected to server. Enum automatically canceled\n") );
|
||||
|
||||
UpdateConnectionInfo();
|
||||
m_fLastUpdateConnectInfoTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
|
||||
|
||||
LCleanup:
|
||||
SAFE_RELEASE( pHostAddress );
|
||||
SAFE_RELEASE( pDeviceAddress );
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::SendPacket( void* pData, DWORD dwSize,
|
||||
BOOL bGuaranteed, DWORD dwTimeout )
|
||||
{
|
||||
if( NULL == m_pDPlay )
|
||||
return S_OK;
|
||||
|
||||
DPNHANDLE hAsync;
|
||||
DWORD dwFlags;
|
||||
DPNHANDLE* phAsync;
|
||||
|
||||
if( bGuaranteed )
|
||||
{
|
||||
// If we are guaranteed then we must specify
|
||||
// DPNSEND_NOCOMPLETE and pass in non-null for the
|
||||
// pvAsyncContext
|
||||
dwFlags = DPNSEND_GUARANTEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we aren't guaranteed then we can
|
||||
// specify DPNSEND_NOCOMPLETE. And when
|
||||
// DPNSEND_NOCOMPLETE is on pvAsyncContext
|
||||
// must be NULL.
|
||||
dwFlags = DPNSEND_NOCOMPLETE;
|
||||
}
|
||||
|
||||
// Must pass in a value for the Asyn handle. Will be thrown when proc completes.
|
||||
phAsync = &hAsync;
|
||||
|
||||
DPN_BUFFER_DESC dpnBufferDesc;
|
||||
dpnBufferDesc.dwBufferSize = dwSize;
|
||||
dpnBufferDesc.pBufferData = (PBYTE) pData;
|
||||
|
||||
// Update the throughput counter
|
||||
m_dwThroughputBytes += dwSize;
|
||||
|
||||
// DirectPlay will tell via the message handler
|
||||
// if there are any severe errors, so ignore any errors
|
||||
m_pDPlay->Send( &dpnBufferDesc, 1, dwTimeout,
|
||||
NULL, phAsync, dwFlags );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::StaticReceiveHandler( void *pvContext, DWORD dwMessageType,
|
||||
void *pvMessage )
|
||||
{
|
||||
CDPlay8Client* pThisObject = (CDPlay8Client*) pvContext;
|
||||
|
||||
return pThisObject->ReceiveHandler( pvContext, dwMessageType, pvMessage );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::ReceiveHandler( void *pvContext, DWORD dwMessageType,
|
||||
void *pvMessage )
|
||||
{
|
||||
// Increment our Active Thread Counter.
|
||||
EnterCriticalSection( &m_csThreadCountLock );
|
||||
|
||||
//Get the time when we entered the Message Handler
|
||||
FLOAT fStartTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
|
||||
m_wActiveThreadCount++;
|
||||
|
||||
if(m_wActiveThreadCount > m_wMaxThreadCount)
|
||||
m_wMaxThreadCount = m_wActiveThreadCount;
|
||||
|
||||
|
||||
// Calculate an average.
|
||||
FLOAT fdiff = m_wActiveThreadCount - m_fAvgThreadCount;
|
||||
m_fAvgThreadCount += fdiff/8;
|
||||
|
||||
LeaveCriticalSection( &m_csThreadCountLock );
|
||||
|
||||
|
||||
switch( dwMessageType )
|
||||
{
|
||||
case DPN_MSGID_RECEIVE:
|
||||
{
|
||||
PDPNMSG_RECEIVE pRecvData = (PDPNMSG_RECEIVE) pvMessage;
|
||||
|
||||
// Update the throughput counter
|
||||
m_dwThroughputBytes += pRecvData->dwReceiveDataSize;
|
||||
|
||||
if( m_pClient != NULL )
|
||||
{
|
||||
m_pClient->OnPacket( pRecvData->dpnidSender,
|
||||
pRecvData->pReceiveData,
|
||||
pRecvData->dwReceiveDataSize );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DPN_MSGID_TERMINATE_SESSION:
|
||||
{
|
||||
m_dwSessionLostReason = DISCONNNECT_REASON_UNKNOWN;
|
||||
PDPNMSG_TERMINATE_SESSION pTermMsg = (PDPNMSG_TERMINATE_SESSION) pvMessage;
|
||||
|
||||
// The MazeServer passes a DWORD in pvTerminateData if
|
||||
// it disconnected us, otherwise it will be null.
|
||||
if( pTermMsg->pvTerminateData != NULL )
|
||||
{
|
||||
DWORD* pdw = (DWORD*) pTermMsg->pvTerminateData;
|
||||
m_dwSessionLostReason = *pdw;
|
||||
}
|
||||
|
||||
if( m_pClient != NULL )
|
||||
m_pClient->OnSessionLost( m_dwSessionLostReason );
|
||||
|
||||
// Now that the session is lost we need to restart DirectPlay by calling
|
||||
// Close() and Init() on m_pDPlay, however this can not be
|
||||
// done in the DirectPlay message callback, so the main thread will
|
||||
// do this when IsSessionLost() returns TRUE
|
||||
m_bSessionLost = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case DPN_MSGID_ENUM_HOSTS_RESPONSE:
|
||||
{
|
||||
PDPNMSG_ENUM_HOSTS_RESPONSE pEnumResponse = (PDPNMSG_ENUM_HOSTS_RESPONSE) pvMessage;
|
||||
|
||||
EnumSessionCallback( pEnumResponse->pApplicationDescription,
|
||||
pEnumResponse->pAddressSender,
|
||||
pEnumResponse->pAddressDevice );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EnterCriticalSection( &m_csThreadCountLock );
|
||||
|
||||
m_wActiveThreadCount-- ;
|
||||
|
||||
// Calculate an average.
|
||||
|
||||
FLOAT fDiffTime = ( DXUtil_Timer( TIMER_GETAPPTIME ) - fStartTime ) - m_fAvgThreadTime;
|
||||
m_fAvgThreadTime += fDiffTime/8;
|
||||
|
||||
//Get the Max time in the thread.
|
||||
if ( fDiffTime > m_fMaxThreadTime )
|
||||
{
|
||||
m_fMaxThreadTime = fDiffTime;
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &m_csThreadCountLock );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::UpdateConnectionInfo()
|
||||
{
|
||||
if( NULL == m_pDPlay )
|
||||
return E_FAIL;
|
||||
|
||||
// Update the DPN_CONNECTION_INFO every 1/2 second...
|
||||
float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
if( fCurTime - m_fLastUpdateConnectInfoTime > 0.5f )
|
||||
{
|
||||
// Call GetConnectionInfo to get DirectPlay stats about connection
|
||||
ZeroMemory( &m_dpnConnectionInfo, sizeof(DPN_CONNECTION_INFO) );
|
||||
m_dpnConnectionInfo.dwSize = sizeof(DPN_CONNECTION_INFO);
|
||||
m_pDPlay->GetConnectionInfo( &m_dpnConnectionInfo, 0 );
|
||||
|
||||
// Call GetSendQueueInfo to get DirectPlay stats about messages
|
||||
m_pDPlay->GetSendQueueInfo( &m_dwHighPriMessages, &m_dwHighPriBytes,
|
||||
DPNGETSENDQUEUEINFO_PRIORITY_HIGH );
|
||||
m_pDPlay->GetSendQueueInfo( &m_dwNormalPriMessages, &m_dwNormalPriBytes,
|
||||
DPNGETSENDQUEUEINFO_PRIORITY_NORMAL );
|
||||
m_pDPlay->GetSendQueueInfo( &m_dwLowPriMessages, &m_dwLowPriBytes,
|
||||
DPNGETSENDQUEUEINFO_PRIORITY_LOW );
|
||||
|
||||
m_fLastUpdateConnectInfoTime = fCurTime;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD CDPlay8Client::GetThroughputBPS()
|
||||
{
|
||||
static float s_fLastThroughputBPSTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
float fCurTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
||||
if( fCurTime - s_fLastThroughputBPSTime > 1.0f )
|
||||
{
|
||||
m_fThroughputBPS = (float) m_dwThroughputBytes / (fCurTime - s_fLastThroughputBPSTime);
|
||||
|
||||
s_fLastThroughputBPSTime = fCurTime;
|
||||
m_dwThroughputBytes = 0;
|
||||
}
|
||||
|
||||
return (DWORD) m_fThroughputBPS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD CDPlay8Client::GetRoundTripLatencyMS()
|
||||
{
|
||||
UpdateConnectionInfo();
|
||||
return m_dpnConnectionInfo.dwRoundTripLatencyMS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name:
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CDPlay8Client::GetConnectionInfo( TCHAR* strConnectionInfo )
|
||||
{
|
||||
UpdateConnectionInfo();
|
||||
|
||||
_stprintf( strConnectionInfo,
|
||||
TEXT(" Thread Count: Current=%d Avg= %.2f Max=%d\n") \
|
||||
TEXT(" Thread Time: Avg= %.4f Max=%.4f(s)\n") \
|
||||
\
|
||||
TEXT(" Round Trip Latency MS=%dms\n") \
|
||||
TEXT(" Throughput BPS: Current=%d Peak=%d\n") \
|
||||
\
|
||||
TEXT(" Messages Received=%d\n") \
|
||||
\
|
||||
TEXT(" Sent: GB=%d GP=%d NGB=%d NGP=%d\n") \
|
||||
TEXT(" Received: GB=%d GP=%d NGB=%d NGP=%d\n") \
|
||||
\
|
||||
TEXT(" Messages Transmitted: HP=%d NP=%d LP=%d\n") \
|
||||
TEXT(" Messages Timed Out: HP=%d NP=%d LP=%d\n") \
|
||||
\
|
||||
TEXT(" Retried: GB=%d GP=%d\n") \
|
||||
TEXT(" Dropped: NGB=%d NGP=%d\n") \
|
||||
\
|
||||
TEXT(" Send Queue Messages: HP=%d NP=%d LP=%d\n") \
|
||||
TEXT(" Send Queue Bytes: HP=%d NP=%d LP=%d\n"), \
|
||||
\
|
||||
\
|
||||
\
|
||||
m_wActiveThreadCount, m_fAvgThreadCount, m_wMaxThreadCount,
|
||||
m_fAvgThreadTime, m_fMaxThreadTime,
|
||||
m_dpnConnectionInfo.dwRoundTripLatencyMS,
|
||||
m_dpnConnectionInfo.dwThroughputBPS,
|
||||
m_dpnConnectionInfo.dwPeakThroughputBPS,
|
||||
|
||||
m_dpnConnectionInfo.dwMessagesReceived,
|
||||
|
||||
m_dpnConnectionInfo.dwBytesSentGuaranteed,
|
||||
m_dpnConnectionInfo.dwPacketsSentGuaranteed,
|
||||
m_dpnConnectionInfo.dwBytesSentNonGuaranteed,
|
||||
m_dpnConnectionInfo.dwPacketsSentNonGuaranteed,
|
||||
|
||||
m_dpnConnectionInfo.dwBytesReceivedGuaranteed,
|
||||
m_dpnConnectionInfo.dwPacketsReceivedGuaranteed,
|
||||
m_dpnConnectionInfo.dwBytesReceivedNonGuaranteed,
|
||||
m_dpnConnectionInfo.dwPacketsReceivedNonGuaranteed,
|
||||
|
||||
m_dpnConnectionInfo.dwMessagesTransmittedHighPriority,
|
||||
m_dpnConnectionInfo.dwMessagesTransmittedNormalPriority,
|
||||
m_dpnConnectionInfo.dwMessagesTransmittedLowPriority,
|
||||
|
||||
m_dpnConnectionInfo.dwMessagesTimedOutHighPriority,
|
||||
m_dpnConnectionInfo.dwMessagesTimedOutNormalPriority,
|
||||
m_dpnConnectionInfo.dwMessagesTimedOutLowPriority,
|
||||
|
||||
m_dpnConnectionInfo.dwBytesRetried,
|
||||
m_dpnConnectionInfo.dwPacketsRetried,
|
||||
|
||||
m_dpnConnectionInfo.dwBytesDropped,
|
||||
m_dpnConnectionInfo.dwPacketsDropped,
|
||||
|
||||
m_dwHighPriMessages, m_dwNormalPriMessages, m_dwLowPriMessages,
|
||||
m_dwHighPriBytes, m_dwNormalPriBytes, m_dwLowPriBytes
|
||||
);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user