📄 gameservdlg.cpp
字号:
// GameServDlg.cpp : implementation file
//
// Includes...
#include "stdafx.h"
#include "coolserv.h"
#include "GameServDlg.h"
#include "NetStart.h"
#include "Sparam.h"
#include "Utils.h"
#include "mmsystem.h"
// Defines...
#define DEFAULT_PORT 27888
#define USE_POSTMSG 0
// Debug...
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Macros...
#define DEC_TIMER(t, d) if (d >= t) t = 0; else t -= d;
// Externs...
extern ServerInfo g_ServerInfo;
extern ServerOptions g_ServerOptions;
extern NetGame g_NetGame;
extern BOOL g_bEmptyExit;
// Globals...
DWORD g_timeCur = 0;
DWORD g_timeLast = 0;
DWORD g_timeDelta = 0;
DWORD g_timeStart = 0;
DWORD g_dwPosted = 0;
DWORD g_dwHandled = 0;
DWORD g_dwRemoved = 0;
BOOL g_bDoEmptyExit = FALSE;
int g_nEmptyExitDelay = 60;
DWORD g_timerEmptyExit = 0;
BOOL g_bNoExitConfirm = FALSE;
CString g_sFullTcpIpAddress;
WORD g_wPort = 0;
#define SERVER_VERSION "2.1"
#define DEFAULT_PORT 27888
CString g_sSpyGameName;
CString g_sSpyGameVer;
CString g_sSpyGameKey;
CString g_sWebGameName;
CString g_sWebGameVer;
CString g_sWebRegUrl;
// Statics...
static DWORD s_timerWebRegUpdate = 400;
static BOOL s_bThreadDone = FALSE;
// Classes...
class CGameServerAppHandler : public ServerAppHandler
{
public:
DRESULT ShellMessageFn(char* pInfo);
DRESULT ConsoleOutputFn(char* pInfo);
DRESULT OutOfMemory();
DRESULT ProcessPacket(char *pData, DDWORD dataLen, DBYTE senderAddr[4], D_WORD senderPort);
};
// Globals...
CGameServDlg* g_pDialog = NULL;
CGameServerAppHandler g_AppHandler;
// Prototypes...
DWORD WINAPI ThreadUpdate(LPVOID lpParameter);
// Functions...
DRESULT CGameServerAppHandler::ShellMessageFn(char* pInfo)
{
if (g_pDialog)
{
g_pDialog->OnShellMessage(pInfo);
}
return(LT_OK);
}
DRESULT CGameServerAppHandler::ConsoleOutputFn(char* pInfo)
{
if (g_pDialog)
{
g_pDialog->OnConsoleOutput(pInfo);
}
return(LT_OK);
}
DRESULT CGameServerAppHandler::OutOfMemory()
{
if (g_pDialog)
{
g_pDialog->OnOutOfMemory();
}
return(LT_OK);
}
DRESULT CGameServerAppHandler::ProcessPacket(char *pData, DDWORD dataLen, DBYTE senderAddr[4], D_WORD senderPort)
{
if(g_pDialog)
{
g_pDialog->OnProcessNetPacket(pData, dataLen, senderAddr, senderPort);
}
return LT_OK;
}
// ----------------------------------------------------------------------- //
// Replacement for MFC's trace. Doesn't ASSERT.
// ----------------------------------------------------------------------- //
void SS_Trace(const char *pMsg, ...)
{
#ifdef _DEBUG
char buf[1024*16];
va_list marker;
va_start(marker, pMsg);
vsprintf(buf, pMsg, marker);
va_end(marker);
OutputDebugString(buf);
#endif
}
/////////////////////////////////////////////////////////////////////////////
// CGameServSendHandler
/////////////////////////////////////////////////////////////////////////////
void CGameServSendHandler::SendTo(const void *pData, unsigned long len, const char *sAddr, unsigned long port)
{
ServerInterface *pMgr;
if(m_pDlg && (pMgr = m_pDlg->GetServerMgr()))
{
pMgr->SendTo(pData, len, sAddr, port);
}
}
/////////////////////////////////////////////////////////////////////////////
// CGameServDlg dialog
CGameServDlg::CGameServDlg(CWnd* pParent /*=NULL*/)
: CDialog(CGameServDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CGameServDlg)
//}}AFX_DATA_INIT
Clear();
m_pConfigFilename = NULL;
g_pDialog = this;
m_SendHandler.SetDlg(this);
m_sGameSpyGameMode = "openplaying";
m_sGameSpyGameType = "deathmatch";
}
void CGameServDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGameServDlg)
DDX_Control(pDX, IDC_PLAYERS_LIST, m_lbPlayers);
DDX_Control(pDX, IDC_LEVELS_LIST, m_lbLevels);
DDX_Control(pDX, IDC_CONSOLE_WINDOW, m_edConsole);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGameServDlg, CDialog)
//{{AFX_MSG_MAP(CGameServDlg)
ON_WM_SHOWWINDOW()
ON_WM_CLOSE()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_QUIT, OnQuit)
ON_BN_CLICKED(IDC_SERVER, OnServer)
ON_BN_CLICKED(IDC_CONSOLE_SEND, OnConsoleSend)
ON_BN_CLICKED(IDC_CONSOLE_CLEAR, OnConsoleClear)
ON_BN_CLICKED(IDC_COMMANDS_NEXTLEVEL, OnCommandsNextLevel)
ON_BN_CLICKED(IDC_PLAYERS_BOOT, OnPlayersBoot)
ON_LBN_SELCHANGE(IDC_PLAYERS_LIST, OnSelchangePlayersList)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_COMMANDS_OPTIONS, OnCommandsOptions)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CGameServDlg::Init()
{
if(!m_bCSInitted)
{
InitializeCriticalSection(&m_CS);
m_bCSInitted = TRUE;
}
// Display a console message...
WriteConsoleString(IDS_CONSOLE_INITSERVER);
// Get the server interface...
m_pServerMgr = GetServerInterface();
if (!m_pServerMgr) return(FALSE);
// Set our app handler...
m_pServerMgr->SetAppHandler(&g_AppHandler);
// Set the tab stops for the player list box...
int nTabs[10] = { 30, 116, 181, 84, 86, 88, 90, 92, 94, 96 };
m_lbPlayers.SetTabStops(10, nTabs);
// Load some strings...
g_sSpyGameName.LoadString(IDS_SPYGAMENAME);
g_sSpyGameKey.LoadString(IDS_SPYGAMEKEY);
g_sWebRegUrl.LoadString(IDS_WEBREGURL);
#ifdef _ADDON
g_sSpyGameVer.LoadString(IDS_SPYGAMEVER_AO);
g_sWebGameName.LoadString(IDS_WEBGAMENAME_AO);
g_sWebGameVer.LoadString(IDS_WEBGAMEVER_AO);
#else
g_sSpyGameVer.LoadString(IDS_SPYGAMEVER);
g_sWebGameName.LoadString(IDS_WEBGAMENAME);
g_sWebGameVer.LoadString(IDS_WEBGAMEVER);
#endif
// All done...
WriteConsoleString(IDS_CONSOLE_SERVERINITED);
return(TRUE);
}
void CGameServDlg::Term()
{
if(m_bCSInitted)
{
DeleteCriticalSection(&m_CS);
m_bCSInitted = FALSE;
}
Clear();
g_pDialog = NULL;
Sleep(2);
SS_Trace("Updates posted = %lu\n", g_dwPosted);
SS_Trace("Updates handled = %lu\n", g_dwHandled);
SS_Trace("Updates removed = %lu\n", g_dwRemoved);
SS_Trace("Updates per sec = %i\n", (int)((float)(g_dwHandled / (float)(timeGetTime() - g_timeStart)) * 1000));
}
void CGameServDlg::Clear()
{
m_bCSInitted = FALSE;
memset(&m_CS, 0, sizeof(m_CS));
m_pServerMgr = NULL;
g_pDialog = NULL;
m_bRunning = FALSE;
m_bLevelChanging = FALSE;
m_timeServerRunning = 0;
m_timeServerStart = 0;
m_timeServerLast = 0;
m_timeLevelRunning = 0;
m_timeLevelStart = 0;
m_timeLevelLast = 0;
m_cPlayers = 0;
m_nCurLevel = 0;
m_hThread = NULL;
m_dwThreadID = NULL;
m_sCurLevel.Empty();
}
BOOL CGameServDlg::StartServer()
{
// Sanity checks...
if (!m_pServerMgr) return(FALSE);
// Set the debug level...
m_pServerMgr->RunConsoleString("debuglevel 0");
// Set the server options...
NetStart_RunServerOptions(m_pServerMgr, &g_ServerOptions);
// Set the game type string based on the game type...
int nStringID = IDS_GAMETYPE_DEATHMATCH;
switch (g_NetGame.m_byType)
{
case NGT_CAPTUREFLAG: nStringID = IDS_GAMETYPE_CAPTUREFLAG; break;
case NGT_COOPERATIVE: nStringID = IDS_GAMETYPE_COOPERATIVE; break;
case NGT_TEAMS: nStringID = IDS_GAMETYPE_TEAM; break;
#ifdef _ADDON
case NGT_SOCCER: nStringID = IDS_GAMETYPE_SOCCER; break;
#endif
}
m_sGameSpyGameType.LoadString(nStringID);
// Look at some console vars...
HCONSOLEVAR hVar = NULL;
DRESULT dr = m_pServerMgr->GetConsoleVar("WebRegUpdate", &hVar, NULL);
if (dr == LT_OK && hVar)
{
float fVal = 0;
dr = m_pServerMgr->GetVarValueFloat(hVar, &fVal);
if (dr == LT_OK && fVal > 1)
{
s_timerWebRegUpdate = (DWORD)fVal;
}
}
hVar = NULL;
dr = m_pServerMgr->GetConsoleVar("EmptyExit", &hVar, NULL);
if (dr == LT_OK && hVar)
{
float fVal = 0;
dr = m_pServerMgr->GetVarValueFloat(hVar, &fVal);
if (dr == LT_OK && fVal >= 1)
{
g_bEmptyExit = TRUE;
}
}
hVar = NULL;
dr = m_pServerMgr->GetConsoleVar("EmptyExitDelay", &hVar, NULL);
if (dr == LT_OK && hVar)
{
float fVal = 0;
dr = m_pServerMgr->GetVarValueFloat(hVar, &fVal);
if (dr == LT_OK && fVal >= 1)
{
g_nEmptyExitDelay = (int)fVal;
}
}
hVar = NULL;
dr = m_pServerMgr->GetConsoleVar("SpyGameType", &hVar, NULL);
if (dr == LT_OK && hVar)
{
char sTemp[64] = { "" };
dr = m_pServerMgr->GetVarValueString(hVar, sTemp, 64);
if (dr == LT_OK && sTemp[0] != '\0')
{
m_sGameSpyGameType = sTemp;
}
}
hVar = NULL;
dr = m_pServerMgr->GetConsoleVar("SpyGameMode", &hVar, NULL);
if (dr == LT_OK && hVar)
{
char sTemp[64] = { "" };
dr = m_pServerMgr->GetVarValueString(hVar, sTemp, 64);
if (dr == LT_OK && sTemp[0] != '\0')
{
m_sGameSpyGameMode = sTemp;
}
}
// Host the game...
CWaitCursor wc;
NetHost nh;
memset(&nh, 0, sizeof(nh));
nh.m_dwMaxPlayers = g_ServerInfo.m_dwMaxPlayers;
nh.m_Port = NetStart_GetPort();
CString sHost;
#ifdef _ADDON
sHost.LoadString(IDS_APPNAME_AO);
#else
sHost.LoadString(IDS_APPNAME);
#endif
Sparam_Add(nh.m_sName, NST_GAMENAME, g_ServerInfo.m_sName);
Sparam_Add(nh.m_sName, NST_GAMEHOST, sHost);
Sparam_Add(nh.m_sName, NST_GAMELEVEL, g_NetGame.m_sLevels[0]);
Sparam_Add(nh.m_sName, NST_GAMETYPE, g_NetGame.m_byType);
if (m_pServerMgr->HostGame(&nh) != DTRUE)
{
WriteConsoleString(IDS_CONSOLE_UNABLETOHOST);
StopServer();
return(FALSE);
}
// Start the world...
StartGameRequest req;
memset(&req, 0, sizeof(req));
req.m_Type = STARTGAME_HOST;
req.m_pGameInfo = &g_NetGame;
req.m_GameInfoLen = sizeof(NetGame_t);
strcpy(req.m_WorldName, g_NetGame.m_sLevels[0]);
if (m_pServerMgr->StartWorld(&req) != DTRUE)
{
WriteConsoleString(IDS_CONSOLE_UNABLETOSTARTWORLD);
WriteConsoleString(req.m_WorldName);
StopServer();
return(FALSE);
}
// Update the service info with the tcp/ip address if available...
g_ServerInfo.m_sAddress[0] = '\0';
g_wPort = 0;
m_pServerMgr->GetTcpIpAddress(g_ServerInfo.m_sAddress, 128, g_wPort);
CString sService = g_ServerInfo.m_sService;
g_sFullTcpIpAddress = "";
if (g_ServerInfo.m_sAddress[0] != '\0')
{
sService += " ";
g_sFullTcpIpAddress = g_ServerInfo.m_sAddress;
if (g_wPort > 0 && g_wPort != DEFAULT_PORT)
{
char sTemp[32];
wsprintf(sTemp, ":%i", g_wPort);
g_sFullTcpIpAddress += sTemp;
}
sService += "[";
sService += g_sFullTcpIpAddress;
sService += "]";
}
SetDlgItemText(IDC_SERVER_SERVICE, sService);
// Tell the server shell to update the game info parameters...
m_pServerMgr->SendToServerShell("GAMEINIT");
// Tell the server that this is a stand-alone server hosted game...
m_pServerMgr->SendToServerShell("SERVHOST");
// Init some stuff now that we're running...
m_bRunning = TRUE;
m_timeServerStart = timeGetTime();
g_timeStart = timeGetTime();
m_timeLevelStart = m_timeServerStart;
// Init the GameSpy manager...
if (g_ServerInfo.m_bUseGameSpy)
{
if (m_GameSpyMgr.Init(g_sSpyGameName, g_sSpyGameVer, g_sSpyGameKey, 0, g_wPort, (g_wPort+166), GSMF_USEGAMEPORTFORHEARTBEAT))
{
m_GameSpyMgr.SetSendHandler(&m_SendHandler);
}
else
{
g_ServerInfo.m_bUseGameSpy = FALSE;
}
}
// Create the thread to do our updating...
m_hThread = CreateThread(NULL, 0, ThreadUpdate, (void*)g_pDialog, 0, &m_dwThreadID);
// All done...
WriteConsoleString(IDS_CONSOLE_SERVERRUNNING);
return(TRUE);
}
BOOL CGameServDlg::StopServer()
{
// Unregister the server if necessary...
if (m_bRunning)
{
UnregisterServer();
}
// Terminate the GameSpy manager...
m_GameSpyMgr.Term();
// Flag that we are done...
m_bRunning = FALSE;
// Wait for the thread to stop...
if (m_hThread)
{
Sleep(0);
DWORD dwRet = WaitForSingleObject(m_hThread, 1000);
Sleep(0);
if (dwRet == WAIT_OBJECT_0)
{
CloseHandle(m_hThread);
}
else
{
TerminateThread(m_hThread, 0);
}
m_hThread = NULL;
}
// All done...
return(TRUE);
}
void CGameServDlg::WriteConsoleString(LPCTSTR pMsg, ...)
{
TCHAR str[500];
va_list marker;
int nLen;
static int nMax = 500;
if(m_edConsole.GetLineCount() > nMax)
{
// Nuke the oldest 75%.
int iLine = (m_edConsole.GetLineCount()*75) / 100;
int iChar = m_edConsole.LineIndex(iLine);
m_edConsole.SetRedraw(FALSE);
m_edConsole.SetSel(0, iChar);
m_edConsole.ReplaceSel("", FALSE);
m_edConsole.SetRedraw(TRUE);
}
va_start(marker, pMsg);
vsprintf(str, pMsg, marker);
va_end(marker);
int len = strlen(str);
if (len <= 0) return;
if (len > 0 && str[len-1] < 32) str[len-1] = '\0';
strcat(str, "\r\n");
nLen = m_edConsole.SendMessage(EM_GETLIMITTEXT, 0, 0);
m_edConsole.SetSel(nLen, nLen);
m_edConsole.ReplaceSel(str);
}
void CGameServDlg::WriteConsoleString(int nStringID)
{
CString sMsg;
if (!sMsg.LoadString(nStringID)) return;
WriteConsoleString(sMsg);
}
/////////////////////////////////////////////////////////////////////////////
// CGameServDlg message handlers
BOOL CGameServDlg::OnInitDialog()
{
// Let the base class do it's thing...
CDialog::OnInitDialog();
// Set the window title if necessary...
#ifdef _ADDON
CString sTitle;
sTitle.LoadString(IDS_DIALOGTITLE_AO);
SetWindowText(sTitle);
#endif
// Fill in some of the text info...
SetDlgItemText(IDC_SERVER_NAME, g_ServerInfo.m_sName);
SetDlgItemText(IDC_SERVER_TIME, "0:00");
CString sService(g_ServerInfo.m_sService);
if (g_ServerInfo.m_sAddress[0] != '\0')
{
sService += " (";
sService += g_ServerInfo.m_sAddress;
sService += ")";
}
SetDlgItemText(IDC_SERVER_SERVICE, sService);
SetDlgItemText(IDC_GAME_PLAYERS, "0");
SetDlgItemText(IDC_GAME_CURLEVEL, g_NetGame.m_sLevels[0]);
SetDlgItemText(IDC_GAME_TIME, "0:00");
m_sCurLevel = g_NetGame.m_sLevels[0];
if (g_NetGame.m_byNumLevels > 1) SetDlgItemText(IDC_GAME_NEXTLEVEL, g_NetGame.m_sLevels[1]);
else SetDlgItemText(IDC_GAME_NEXTLEVEL, "");
CString sBuf;
if (g_NetGame.m_byEnd == NGE_FRAGS) sBuf.Format("%i Frags", g_NetGame.m_dwEndFrags);
else if (g_NetGame.m_byEnd == NGE_TIME) sBuf.Format("%i Minutes", g_NetGame.m_dwEndTime);
else if (g_NetGame.m_byEnd == NGE_FRAGSANDTIME) sBuf.Format("%i Frags or %i Minutes", g_NetGame.m_dwEndFrags, g_NetGame.m_dwEndTime);
else sBuf = "None. Level never ends.";
SetDlgItemText(IDC_GAME_GOAL, sBuf);
for (int i = 0; i < g_NetGame.m_byNumLevels; i++)
{
m_lbLevels.AddString(g_NetGame.m_sLevels[i]);
}
// Set the icon...
HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(hIcon, TRUE);
SetIcon(hIcon, FALSE);
for(i=0; i < 30; i++)
{
if(SetTimer((UINT)i, 500, NULL))
break;
}
// All done...
return(TRUE);
}
BOOL CGameServDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case ID_INIT:
{
if (!Init())
{
return(TRUE);
}
if (!StartServer())
{
return(TRUE);
}
return(TRUE);
}
case ID_UPDATE:
{
OnUpdate();
return(TRUE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -