📄 client.cpp
字号:
//-----------------------------------------------------------------------------
// 名称: RenderSene.cpp
//
// 功能: 进行3D场景的渲染——使用显示内存的顶点缓冲区。
//
//-----------------------------------------------------------------------------
#include <tchar.h>
#include <windows.h>
#include <basetsd.h>
#include <objbase.h>
// 包含Direct3D头文件
#include <d3d8.h>
#include <d3dx8.h>
#include <dinput.h>
#include <dplay8.h>
#include <dpaddr.h>
#include <dxerr8.h>
#include <dpaddr.h>
// Windows类的名称宏定义
#define MY_WINCLASS_NAME "Direct3D"
struct PLAYER
{
D3DXVECTOR3 LookAt[3];
};
// 定义个表示顶点的结构
struct CUSTOMVERTEX
{
FLOAT x, y, z; // x,y,z表示点的三维坐标值,
DWORD color; // 顶点颜色
};
// 自定义的顶点格式
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
// 定义全局变量
LPDIRECT3D8 g_pMyD3D = NULL; // 定义Direct3D对象的指针
LPDIRECT3DDEVICE8 g_pMyd3dDevice = NULL; // 定义Direct3D设备指针
LPDIRECT3DVERTEXBUFFER8 g_pMyVxBufferRec = NULL; // 定义顶点缓冲区对象指针
LPDIRECT3DVERTEXBUFFER8 g_pMyVxBufferLine = NULL;
PLAYER g_Player;
float g_Angle = 0;
#define LINE_VECTOR_NUM 20
// 定义包含4个顶点的顶点数组
CUSTOMVERTEX g_Vertices[] =
{
{ -1.5f, 0.0f, 0.0f, 0xffff0000, },
{ -1.5f, 2.0f, 0.0f, 0xffff0000, },
{ 1.5f, 0.0f, 0.0f, 0xffff0000, },
{ 1.5f, 2.0f, 0.0f, 0xffff0000, },
};
#define GRID_WIDTH 20.0f
#define NUM_GRID 20
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define SAMPLE_BUFFER_SIZE 8
#define TIME2FRAME 15
#define KEYDOWN(name, key) (name[key] & 0x80)
LPDIRECTINPUT8 g_pDI = NULL;
LPDIRECTINPUTDEVICE8 g_pKeyboard = NULL;
IDirectPlay8Client* g_pDPClient = NULL;
DWORD g_dwPort;
GUID g_guidApp = { 0xede9493e, 0x6ac8, 0x4f15, { 0x8d, 0x1, 0x8b, 0x16, 0x32, 0x0, 0xb9, 0x66 } };
struct APP_PLAYER_INFO
{
LONG lRefCount; // Ref count so we can cleanup when all threads
// are done w/ this object
DPNID dpnidPlayer; // DPNID of player
TCHAR strPlayerName[20]; // Player name
};
#define GAME_MSGID_MESSAGE 1
#define GAME_MSGID_CREATE_PLAYER 2
#define GAME_MSGID_DESTROY_PLAYER 3
#define GAME_MSGID_SET_ID 4
struct GAMEMSG_GENERIC
{
DWORD dwType;
char buffer[256];
};
struct DPHostInfo
{
DWORD dwRef;
DPN_APPLICATION_DESC* pAppDesc;
IDirectPlay8Address* pHostAddr;
IDirectPlay8Address* pDeviceAddr;
TCHAR szSession[MAX_PATH];
DWORD dwLastPollTime;
BOOL bValid;
};
struct DPHostInfo *g_pDPHostInfo = new DPHostInfo;
//-----------------------------------------------------------------------------
// 名称: NetClientSendData()
// 功能: 发送数据。
//
//-----------------------------------------------------------------------------
HRESULT NetClientSendData( struct GAMEMSG_GENERIC *pData )
{
DPN_BUFFER_DESC bufferDesc;
bufferDesc.dwBufferSize = sizeof(struct GAMEMSG_GENERIC);
bufferDesc.pBufferData = (BYTE*) pData;
DPNHANDLE hAsync;
g_pDPClient->Send( &bufferDesc, 1, 0, NULL, &hAsync, 0 );
return S_OK;
}
//-----------------------------------------------------------------------------
// 名称: NetHostEnumResponse()
// 功能: 处理枚举会话应答消息。
//
//-----------------------------------------------------------------------------
HRESULT NetClientHostEnumResponse( PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg )
{
HRESULT hr = S_OK;
DPHostInfo* pDPHostEnum = g_pDPHostInfo;
const DPN_APPLICATION_DESC* pResponseMsgAppDesc =
pEnumHostsResponseMsg->pApplicationDescription;
ZeroMemory( pDPHostEnum, sizeof(DPHostInfo) );
// Update the pDPHostEnum with new information
TCHAR strName[MAX_PATH];
if( pResponseMsgAppDesc->pwszSessionName )
{
wcscpy( (unsigned short *)strName, pResponseMsgAppDesc->pwszSessionName );
}
//
// Duplicate pEnumHostsResponseMsg->pAddressSender in pDPHostEnum->pHostAddr.
// Duplicate pEnumHostsResponseMsg->pAddressDevice in pDPHostEnum->pDeviceAddr.
//
if( FAILED( hr = pEnumHostsResponseMsg->pAddressSender->Duplicate( &pDPHostEnum->pHostAddr ) ) )
{
DXTRACE_ERR( TEXT("Duplicate"), hr );
goto LCleanup;
}
if( FAILED( hr = pEnumHostsResponseMsg->pAddressDevice->Duplicate( &pDPHostEnum->pDeviceAddr ) ) )
{
DXTRACE_ERR( TEXT("Duplicate"), hr );
goto LCleanup;
}
// Deep copy the DPN_APPLICATION_DESC from
pDPHostEnum->pAppDesc = new DPN_APPLICATION_DESC;
ZeroMemory( pDPHostEnum->pAppDesc, sizeof(DPN_APPLICATION_DESC) );
memcpy( pDPHostEnum->pAppDesc, pResponseMsgAppDesc, sizeof(DPN_APPLICATION_DESC) );
if( pResponseMsgAppDesc->pwszSessionName )
{
pDPHostEnum->pAppDesc->pwszSessionName = new WCHAR[ wcslen(pResponseMsgAppDesc->pwszSessionName)+1 ];
wcscpy( pDPHostEnum->pAppDesc->pwszSessionName,
pResponseMsgAppDesc->pwszSessionName );
}
// Update the time this was done, so that we can expire this host
// if it doesn't refresh w/in a certain amount of time
pDPHostEnum->dwLastPollTime = timeGetTime();
// Check to see if the current number of players changed
TCHAR szSessionTemp[MAX_PATH];
if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
{
wsprintf( szSessionTemp, TEXT("%s (%d/%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers - 1, // ignore the host player
pResponseMsgAppDesc->dwMaxPlayers - 1, // ignore the host player
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
}
else
{
wsprintf( szSessionTemp, TEXT("%s (%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers - 1, // ignore the host player
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
}
_tcscpy( pDPHostEnum->szSession, szSessionTemp );
// This host is now valid
pDPHostEnum->bValid = TRUE;
LCleanup:
return hr;
}
//-----------------------------------------------------------------------------
// 名称: NetClientMessageHandler()
// 功能: 处理消息接收。
//
//-----------------------------------------------------------------------------
HRESULT WINAPI NetClientMessageHandler( PVOID pvUserContext,
DWORD dwMessageId,
PVOID pMsgBuffer )
{
switch( dwMessageId )
{
case DPN_MSGID_ENUM_HOSTS_RESPONSE:
{
PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
// Take note of the host response
NetClientHostEnumResponse( pEnumHostsResponseMsg );
break;
}
case DPN_MSGID_CREATE_PLAYER:
{
break;
}
case DPN_MSGID_DESTROY_PLAYER:
{
break;
}
case DPN_MSGID_TERMINATE_SESSION:
{
break;
}
case DPN_MSGID_RECEIVE:
{
PDPNMSG_RECEIVE pReceiveMsg;
pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
// 接收数据
break;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// 名称: NetSessionsEnumHosts()
// 功能: 枚举会话中的宿主。
//
//-----------------------------------------------------------------------------
HRESULT NetClientEnumHosts( HWND hWnd )
{
HRESULT hr;
DPN_APPLICATION_DESC dpnAppDesc;
IDirectPlay8Address* pDP8AddressHost = NULL;
IDirectPlay8Address* pDP8AddressLocal = NULL;
WCHAR* wszHostName = NULL;
DPNHANDLE m_hEnumAsyncOp = NULL;
// 设置服务器的IP地址
TCHAR strIPAddress[MAX_PATH] = TEXT("127.0.0.1");
// 创建本地地址对象
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
CLSCTX_ALL, IID_IDirectPlay8Address,
(LPVOID*) &pDP8AddressLocal ) ) )
{
DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
goto LCleanup;
}
// 设置地址对象的网络协议为TCP/IP协议
if( FAILED( hr = pDP8AddressLocal->SetSP( &CLSID_DP8SP_TCPIP ) ) )
{
DXTRACE_ERR( TEXT("SetSP"), hr );
goto LCleanup;
}
// 创建服务器的地址对象
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
CLSCTX_ALL, IID_IDirectPlay8Address,
(LPVOID*) &pDP8AddressHost ) ) )
{
DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
goto LCleanup;
}
// 设置地址对象的网络协议为TCP/IP协议
if( FAILED( hr = pDP8AddressHost->SetSP( &CLSID_DP8SP_TCPIP ) ) )
{
DXTRACE_ERR( TEXT("SetSP"), hr );
goto LCleanup;
}
if( strIPAddress != NULL && strIPAddress[0] != 0 )
{
DWORD dwPort = 0;
wszHostName = new WCHAR[_tcslen(strIPAddress)+1];
int cchDestChar;
cchDestChar = strlen(strIPAddress)+1;
MultiByteToWideChar( CP_ACP, 0, strIPAddress, -1,
wszHostName, cchDestChar-1 );
wszHostName[cchDestChar-1] = 0;
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;
}
// If a port was specified in the IP string, then add it.
// Games will typically hard code the port so the user need not know it
if( dwPort != 0 )
{
hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT,
&dwPort, sizeof(dwPort),
DPNA_DATATYPE_DWORD );
if( FAILED(hr) )
{
DXTRACE_ERR( TEXT("AddComponent"), hr );
goto LCleanup;
}
}
}
ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) );
dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
dpnAppDesc.guidApplication = g_guidApp;
// 枚举会话宿主
hr = g_pDPClient->EnumHosts( &dpnAppDesc, pDP8AddressHost,
pDP8AddressLocal, NULL,
0, 0, 0, 0, NULL,
NULL, DPNENUMHOSTS_SYNC );
if( FAILED(hr) )
{
if( hr != DPNERR_INVALIDDEVICEADDRESS &&
hr != DPNERR_ADDRESSING )
DXTRACE_ERR( TEXT("EnumHosts"), hr );
goto LCleanup;
}
LCleanup:
SAFE_RELEASE( pDP8AddressHost);
SAFE_RELEASE( pDP8AddressLocal );
SAFE_DELETE( wszHostName );
if( hr == DPNERR_PENDING )
hr = DPN_OK;
return hr;
}
//-----------------------------------------------------------------------------
// 名称: NetClientStart()
// 功能: 启动服务器。
//
//-----------------------------------------------------------------------------
HRESULT NetClientStart( HWND hWnd )
{
HRESULT hr;
WCHAR wszPeerName[MAX_PATH];
// 创建 IDirectPlay8Client
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Client, NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Client,
(LPVOID*) &g_pDPClient ) ) )
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
// 初始化 IDirectPlay8Client
if( FAILED( hr = g_pDPClient->Initialize( NULL, NetClientMessageHandler, 0 ) ) )
return DXTRACE_ERR( TEXT("Initialize"), hr );
if(FAILED(hr = NetClientEnumHosts(hWnd )))
return DXTRACE_ERR( TEXT("EnumHost Err"), hr );
DPN_PLAYER_INFO dpPlayerInfo;
ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
dpPlayerInfo.pwszName = wszPeerName;
// 设置本地游戏主机信息
if( FAILED( hr = g_pDPClient->SetClientInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
// 连接到会话中的服务器
hr = g_pDPClient->Connect( g_pDPHostInfo->pAppDesc, // the application desc
g_pDPHostInfo->pHostAddr, // address of the host of the session
g_pDPHostInfo->pDeviceAddr, // address of the local device the enum responses were received on
NULL, NULL, // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
NULL, 0, // user data, user data size
NULL, NULL, // async context, async handle,
DPNCONNECT_SYNC ); // flags
if( hr != E_PENDING && FAILED(hr) )
return DXTRACE_ERR( TEXT("Connect"), hr );
return S_OK;
}
//-----------------------------------------------------------------------------
// 名称: NetClientStop()
// 功能: 关闭会话。
//
//-----------------------------------------------------------------------------
VOID NetClientStop( )
{
if( g_pDPClient )
{
g_pDPClient->Close(0);
SAFE_RELEASE( g_pDPClient );
}
}
//-----------------------------------------------------------------------------
// 名称: FreeDirectInput()
// 功能: 释放键盘设备。
//
//-----------------------------------------------------------------------------
VOID KeyboardFree()
{
// 释放设备
if( g_pKeyboard )
g_pKeyboard->Unacquire();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -