?? winmain.cpp
字號:
/**************************************************
WinMain.cpp
Chapter 19 Multiplayer Server Demo
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
Required libraries:
D3D8.LIB, D3DX8.LIB, DINPUT8.LIB, D3DXOF.LIB,
DXGUID.LIB, DPNET.LIB, DPLAY.LIB, and DPNADDR.LIB
**************************************************/
#include "Core_Global.h"
#include "Server.h"
#include "WinMain.h"
#include "resource.h"
cApp *g_Application; // Global application pointer
cNetworkAdapter *g_Adapters; // Global adapter list pointer
///////////////////////////////////////////////////////////
// cApp overidden virtual functions
///////////////////////////////////////////////////////////
cApp::cApp()
{
// Setup main window information
m_Width = 320;
m_Height = 212;
m_Style = WS_BORDER | WS_CAPTION | \
WS_MINIMIZEBOX | WS_SYSMENU;
m_wcex.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
strcpy(m_Class, "ServerClass");
strcpy(m_Caption, "Network Server Demo by Jim Adams");
// Clear class data
m_Messages = NULL;
m_Players = NULL;
m_guidAdapter = NULL;
g_Application = this;
g_Adapters = &m_Adapters;
// Initialize a critical section for messaging
InitializeCriticalSection(&m_MessageCS);
}
BOOL cApp::Init()
{
// Select a network adapter to use (or quit if selected)
if(SelectAdapter() == FALSE)
return FALSE;
// Setup the main interface window
SetupApplicationWindow();
// Initialize the game, set video mode, load data, etc
if(InitializeGame() == FALSE) {
Error(FALSE, "Unable to initialize game.");
return FALSE;
}
// Begin hosting the game session
if(HostGame() == FALSE) {
Error(FALSE, "Unable to host network server.");
return FALSE;
}
return TRUE;
}
BOOL cApp::Shutdown()
{
// Disconnect network and free interfaces
m_Adapters.Shutdown();
m_Server.Disconnect();
m_Server.Shutdown();
// Shutdown graphics
m_LevelMesh.Free();
m_Graphics.Shutdown();
// Delete message array
delete [] m_Messages;
m_Messages = NULL;
// Delete players
delete [] m_Players;
m_Players = NULL;
// Free the critical section
DeleteCriticalSection(&m_MessageCS);
return TRUE;
}
BOOL cApp::Frame()
{
static DWORD PlayerCounter = timeGetTime();
static DWORD NetworkCounter = timeGetTime();
static DWORD LatencyCounter = timeGetTime();
// Process some queued network messages
ProcessQueuedMessages();
// Update players every 33ms (30 times a second)
if(timeGetTime() > PlayerCounter + 33) {
UpdatePlayers();
PlayerCounter = timeGetTime(); // Reset counter
}
// Send out network updates every 100ms (10 times a second)
if(timeGetTime() > NetworkCounter + 100) {
UpdateNetwork();
NetworkCounter = timeGetTime(); // Reset counter
}
// Update player latency values every 10 seconds
if(timeGetTime() > LatencyCounter + 10000) {
UpdateLatency();
LatencyCounter = timeGetTime(); // Reset counter
}
return TRUE;
}
FAR PASCAL cApp::MsgProc(HWND hWnd, UINT uMsg, \
WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, \
LPSTR szCmdLine, int nCmdShow)
{
cApp App;
return App.Run(); // Run the application instance
}
///////////////////////////////////////////////////////////
// Select adapter dialog and other functions
///////////////////////////////////////////////////////////
BOOL CALLBACK ConfigDialogProc(HWND hWnd, UINT uMsg, \
WPARAM wParam, LPARAM lParam)
{
long i;
char Text[256];
int Selection;
static HWND hAdapters;
switch(uMsg) {
case WM_INITDIALOG:
// Get adapter list window handle
hAdapters = GetDlgItem(hWnd, IDC_ADAPTERS);
// Add adapter names to list
for(i=0;i<g_Adapters->GetNumAdapters();i++) {
g_Adapters->GetName(i, Text);
SendMessage(hAdapters, CB_INSERTSTRING,i,(LPARAM)Text);
}
// Select first adapter in list
SendMessage(hAdapters, CB_SETCURSEL, 0, 0);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_OK:
// Make sure an adapter was selected
if((Selection = SendMessage(hAdapters, \
CB_GETCURSEL, \
0, 0)) == LB_ERR)
break;
// Assign adapter
if(g_Application != NULL)
g_Application->SetAdapter( \
g_Adapters->GetGUID(Selection));
// Quit dialog
EndDialog(hWnd, TRUE);
return TRUE;
case IDC_CANCEL:
EndDialog(hWnd, FALSE);
return TRUE;
}
}
return FALSE;
}
void cApp::SetAdapter(GUID *Adapter)
{
m_guidAdapter = Adapter;
}
///////////////////////////////////////////////////////////
// Misc. application functions
///////////////////////////////////////////////////////////
void cApp::ListPlayers()
{
long i;
char Text[256];
// Error checking
if(m_Players == NULL)
return;
// Clear player list
SendMessage(m_Controls[2], LB_RESETCONTENT, 0, 0);
// Count all players and add names to list
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].Connected == TRUE)
SendMessage(m_Controls[2], LB_ADDSTRING, 0, \
(LPARAM)m_Players[i].Name);
}
// Display player count
if(!m_NumPlayers)
SetWindowText(m_Controls[1], "No Connected Players");
else {
sprintf(Text, "%lu Players Connected", m_NumPlayers);
SetWindowText(m_Controls[1], Text);
}
}
///////////////////////////////////////////////////////////
// Network send and receive functions
///////////////////////////////////////////////////////////
BOOL cApp::SendNetworkMessage(void *Msg, long SendFlags, int To)
{
sMessageHeader *mh = (sMessageHeader*)Msg;
unsigned long Size;
// Get size of message to send
if((Size = mh->Size) == 0)
return FALSE;
// Set destination to all players if To == -1
if(To == -1)
To = DPNID_ALL_PLAYERS_GROUP;
// Send the message
return m_Server.Send(To, Msg, Size, SendFlags);
}
BOOL cApp::CreatePlayer(DPNMSG_CREATE_PLAYER *Msg)
{
sCreatePlayerMessage cpm;
// Setup message data
cpm.Header.Type = MSG_CREATE_PLAYER;
cpm.Header.Size = sizeof(sCreatePlayerMessage);
cpm.Header.PlayerID = Msg->dpnidPlayer;
QueueMessage(&cpm); // Queue the message
return TRUE;
}
BOOL cApp::DestroyPlayer(DPNMSG_DESTROY_PLAYER *Msg)
{
sDestroyPlayerMessage dpm;
// Setup message data
dpm.Header.Type = MSG_DESTROY_PLAYER;
dpm.Header.Size = sizeof(sDestroyPlayerMessage);
dpm.Header.PlayerID = Msg->dpnidPlayer;
QueueMessage(&dpm); // Queue the message
return TRUE;
}
BOOL cApp::Receive(DPNMSG_RECEIVE *Msg)
{
sMessageHeader *mh = (sMessageHeader*)Msg->pReceiveData;
// Make sure it's a valid message type and queue it
switch(mh->Type) {
case MSG_ASSIGNID:
// Store player ID before continuing
mh->PlayerID = Msg->dpnidSender;
case MSG_PLAYER_INFO:
case MSG_STATE_CHANGE:
// Add message to queue
QueueMessage((void*)Msg->pReceiveData);
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Message queue functions
///////////////////////////////////////////////////////////
BOOL cApp::QueueMessage(void *Msg)
{
sMessageHeader *mh = (sMessageHeader*)Msg;
// Error checking - make sure there's a message array
if(m_Messages == NULL)
return FALSE;
// Return if no room left in queue
if(((m_MsgHead+1) % NUM_MESSAGES) == m_MsgTail)
return FALSE;
// Stuff message into queue
if(mh->Size <= sizeof(sMessage)) {
// Start the critical section
EnterCriticalSection(&m_MessageCS);
memcpy(&m_Messages[m_MsgHead], Msg, mh->Size);
// Go to next empty message (flip around if at end)
m_MsgHead++;
if(m_MsgHead >= NUM_MESSAGES)
m_MsgHead = 0;
// Leave the critical section
LeaveCriticalSection(&m_MessageCS);
}
return TRUE;
}
BOOL cApp::PlayerID(sMessage *Msg, DPNID To)
{
sAssignPlayerIDMessage apidm;
apidm.Header.Type = MSG_ASSIGNID;
apidm.Header.Size = sizeof(sAssignPlayerIDMessage);
apidm.Header.PlayerID = To;
SendNetworkMessage(&apidm, DPNSEND_NOLOOPBACK, To);
return TRUE;
}
BOOL cApp::PlayerInfo(sMessage *Msg, DPNID To)
{
sRequestPlayerInfoMessage *rpim;
sCreatePlayerMessage cpm;
long i;
// Error checking
if(m_Players == NULL)
return FALSE;
// Get pointer to request info
rpim = (sRequestPlayerInfoMessage*)Msg;
for(i=0;i<MAX_PLAYERS;i++) {
// Only send if found in list
if(m_Players[i].dpnidPlayer == rpim->PlayerID && \
m_Players[i].Connected == TRUE) {
// Send player info to requesting player
cpm.Header.Type = MSG_PLAYER_INFO;
cpm.Header.Size = sizeof(sCreatePlayerMessage);
cpm.Header.PlayerID = rpim->PlayerID;
cpm.XPos = m_Players[i].XPos;
cpm.YPos = m_Players[i].YPos;
cpm.ZPos = m_Players[i].ZPos;
cpm.Direction = m_Players[i].Direction;
SendNetworkMessage(&cpm, DPNSEND_NOLOOPBACK, To);
break;
}
}
return TRUE;
}
BOOL cApp::AddPlayer(sMessage *Msg)
{
long i;
DWORD Size = 0;
DPN_PLAYER_INFO *dpi = NULL;
HRESULT hr;
DPNID PlayerID;
// Error checking
if(m_Players == NULL)
return FALSE;
// Get the player ID #
PlayerID = Msg->Header.PlayerID;
// Get the player information
hr = m_Server.GetServerCOM()->GetClientInfo(PlayerID, dpi, \
&Size, 0);
// Return on error or if adding server
if(FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL)
return FALSE;
// Allocate player data buffer and try again
if((dpi = (DPN_PLAYER_INFO*)new BYTE[Size]) == NULL)
return FALSE;
ZeroMemory(dpi, Size);
dpi->dwSize = sizeof(DPN_PLAYER_INFO);
if(FAILED(m_Server.GetServerCOM()->GetClientInfo( \
PlayerID, dpi, &Size, 0))) {
delete [] dpi;
return FALSE;
}
// Make sure not already in list
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].dpnidPlayer == PlayerID && \
m_Players[i].Connected == TRUE) {
delete [] dpi;
m_Server.DisconnectPlayer(PlayerID);
return FALSE;
}
}
// Search for an empty slot to put player
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].Connected == FALSE) {
m_Players[i].Connected = TRUE; // Flag as connected
// Save DirectPlay DPNID # and name of player
m_Players[i].dpnidPlayer = PlayerID;
wcstombs(m_Players[i].Name, dpi->pwszName, 256);
// Setup player data
m_Players[i].XPos = 0.0f;
m_Players[i].YPos = 0.0f;
m_Players[i].ZPos = 0.0f;
m_Players[i].Direction = 0.0f;
m_Players[i].Speed = 512.0f;
m_Players[i].State = STATE_IDLE;
m_Players[i].Latency = 0;
// Send add player info to all players in area
sCreatePlayerMessage cpm;
cpm.Header.Type = MSG_CREATE_PLAYER;
cpm.Header.Size = sizeof(sCreatePlayerMessage);
cpm.Header.PlayerID = PlayerID;
cpm.XPos = m_Players[i].XPos;
cpm.YPos = m_Players[i].YPos;
cpm.ZPos = m_Players[i].ZPos;
cpm.Direction = m_Players[i].Direction;
SendNetworkMessage(&cpm, DPNSEND_NOLOOPBACK, -1);
ListPlayers(); // List all players
delete [] dpi; // Free player data
return TRUE; // Return success
}
}
delete[] dpi; // Free player data
// Disconnect player - not allowed to connect
m_Server.DisconnectPlayer(PlayerID);
return FALSE; // Return failure
}
BOOL cApp::RemovePlayer(sMessage *Msg)
{
long i;
// Error checking
if(m_Players == NULL)
return FALSE;
// Search for player in list
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].dpnidPlayer == Msg->Header.PlayerID && \
m_Players[i].Connected == TRUE) {
m_Players[i].Connected = FALSE; // Disconnect player
// Send remove player message to all players in area
sDestroyPlayerMessage dpm;
dpm.Header.Type = MSG_DESTROY_PLAYER;
dpm.Header.Size = sizeof(sDestroyPlayerMessage);
dpm.Header.PlayerID = Msg->Header.PlayerID;
SendNetworkMessage(&dpm, DPNSEND_NOLOOPBACK, -1);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -