Files
FC1/FarCry_WinSV/FarCry_WinSV.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1197 lines
28 KiB
C++

#include "stdafx.h"
#include "DedicatedServer.h" // InitDedicatedServer
#if defined(LINUX)
#include <unistd.h>
#include "CryLibrary.h"
#include <signal.h>
#include <execinfo.h>
#endif
#if defined(LINUX)
extern int MainCON( const char *szCmdLine, const bool cIsDaemon);
#else
extern int MainCON( const char *szCmdLine );
#endif
#if defined(LINUX)
bool g_OnQuit;//do not perform a stack trace on quit
#if defined(LINUX32)
const char *gpBinDir = "bin32linux";
#else
const char *gpBinDir = "bin64linux";
#endif
volatile sig_atomic_t fatal_error_in_progress = 0;
void UnRegisterExceptionHandler(std::map<int,sighandler_t>& rSignalMap)
{
for(std::map<int,sighandler_t>::const_iterator iter = rSignalMap.begin(); iter != rSignalMap.end(); ++iter)
signal(iter->first, iter->second);
rSignalMap.clear();
}
void PrintTrace (int signum)
{
if (fatal_error_in_progress)
return;
fatal_error_in_progress = 1;
if(g_OnQuit || IsOnQuit())
{
abort();//do not perform a stack trace on quit
return;
}
FILE *p = ::fopen("./log_LinuxSV.txt", "a+");
if(p)fprintf(p, "\n");
printf("\n");
switch(signum)
{
case SIGINT:
printf("Received signal SIGINT: 'program interrupt', received INTR character (normally C-c)\n");
fprintf(p, "Received signal SIGINT: 'program interrupt', received INTR character (normally C-c)\n");
break;
case SIGHUP:
printf("Received signal SIGHUP: user's terminal is disconnected\n");
if(p)fprintf(p, "Received signal SIGHUP: user's terminal is disconnected\n");
break;
case SIGTERM:
printf("Received signal SIGTERM: cause program termination\n");
if(p)fprintf(p, "Received signal SIGTERM: cause program termination\n");
break;
case SIGQUIT:
printf("Received signal SIGQUIT: received QUIT character (normally C-\) character\n");
if(p)fprintf(p, "Received signal SIGQUIT: received QUIT character (normally C-\) character\n");
break;
case SIGKILL:
printf("Received signal SIGKILL: cause immediate program termination\n");
if(p)fprintf(p, "Received signal SIGKILL: cause immediate program termination\n");
break;
case SIGILL:
printf("Received signal SIGILL: 'illegal instruction', program is trying to execute garbage or a privileged instruction\n");
if(p)fprintf(p, "Received signal SIGILL: 'illegal instruction', program is trying to execute garbage or a privileged instruction\n");
break;
case SIGBUS:
printf("Received signal SIGBUS: invalid pointer is dereferenced\n");
if(p)fprintf(p, "Received signal SIGBUS: invalid pointer is dereferenced\n");
break;
case SIGSEGV:
printf("Received signal SIGSEGV: program tries to read or write outside the memory that is allocated for it\n");
if(p)fprintf(p, "Received signal SIGSEGV: program tries to read or write outside the memory that is allocated for it\n");
break;
case SIGABRT:
printf("Received signal SIGABRT: error detected by the program itself and reported by calling 'abort'\n");
if(p)fprintf(p, "Received signal SIGABRT: error detected by the program itself and reported by calling 'abort'\n");
break;
}
void *array[10];
size_t size = backtrace (array, 10);
char **strings = backtrace_symbols (array, size);
printf("\n");
printf ("Stack-Trace: obtained %d stack frames.\n", size);
if(p)fprintf(p, "Stack-Trace: obtained %d stack frames.\n", size);
for (size_t i = 0; i < size; i++)
{
printf ("%s\n", strings[i]);
//try to log as well
if(p)fprintf(p, "%s\n", strings[i]);
}
if(p)fclose(p);p=NULL;
free (strings);
printf("\n");
abort();
}
void RegisterExceptionHandler(std::map<int,sighandler_t>& rSignalMap)
{
sighandler_t t;
rSignalMap.clear();
t = signal (SIGINT, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGINT,t));
t = signal (SIGHUP, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGHUP,t));
t = signal (SIGTERM, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGTERM,t));
t = signal (SIGQUIT, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGQUIT,t));
t = signal (SIGKILL, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGKILL,t));
t = signal (SIGILL, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGILL,t));
t = signal (SIGBUS, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGBUS,t));
t = signal (SIGSEGV, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGSEGV,t));
t = signal (SIGABRT, PrintTrace);
rSignalMap.insert(std::pair<int,sighandler_t>(SIGABRT,t));
}
static void RetrievePaths(std::vector<string>& rDirectories, const char* cpPathContents)
{
rDirectories.clear();
//make sure it end with /
string path(cpPathContents);
size_t loc = 0;
while(true)
{
loc = path.find(":",0);
if(loc == string::npos)
break;
string tmp = path.substr(0, loc);
if(loc != string::npos)
path = path.substr(loc+1, (path.size()-1 - loc));
if(tmp.c_str()[tmp.size()-1] != '/')
tmp += "/";
rDirectories.push_back(tmp);
}
}
static void SetMasterCDFolder(const char* pExecutableName)
{
char szExeFileName[_MAX_PATH];
// Get the path of the executable
GetCurrentDirectory(sizeof(szExeFileName), szExeFileName);
string currentDir(szExeFileName); currentDir += '/';//temp storage
string DllPath = szExeFileName;
//check whether this is a correct path
DllPath += "/";
SetModulePath(DllPath.c_str());
string masterCDPath(GetModulePath());
masterCDPath += "..";
SetCurrentDirectory( masterCDPath.c_str() );
//get name without ..
GetCurrentDirectory(sizeof(szExeFileName), szExeFileName);
SetFileAttributes(szExeFileName, 0x777);//set full access to current directory
string t(szExeFileName);
if(t.size() > 0 && (t.c_str()[t.size()-1] != '/'))
t += "/";
//test with directory name bin??linux
string s("./");
s += gpBinDir;
DIR *pTest = opendir(s.c_str());
if(pTest == NULL)
{
//resolve symlink
string execFilename(pExecutableName);
string str(currentDir);
str += execFilename;
string realExecName;
const char* pRealName = canonicalize_file_name(str.c_str());
if(!pRealName)
{
//now try the executable name itself
const char* pRealName2 = canonicalize_file_name(pExecutableName);
if(!pRealName2)
{
//okay last attempt, check all $PATH to find the executable in
const char *cpPATH = getenv("PATH");
if(cpPATH)
{
//parse it
std::vector<string> directories;
RetrievePaths(directories, cpPATH);
//iterate all entries
bool found = false;
for(std::vector<string>::iterator iter = directories.begin(); iter != directories.end(); ++iter)
{
string tmp(*iter);
tmp += pExecutableName;
const char* pRealNameTest = canonicalize_file_name(tmp.c_str());
if(pRealNameTest)
{
realExecName = pRealNameTest;
found = true;
break;
}
}
if(!found)
{
printf("could not find valid MasterCD folder, could not resolve directory where it is located\n");
exit(1);
}
}
else
{
printf("could not find valid MasterCD folder, could not resolve directory where it is located\n");
exit(1);
}
}
else
{
realExecName = pRealName2;
}
}
else
{
realExecName = pRealName;
}
//OK, link has been resolved, now get directory
string::size_type loc = realExecName.find(gpBinDir);
if(loc == string::npos)
{
printf("could not find valid binary(binxxlinux) folder in the executable path, could not resolve directory where it is located\n");
exit(1);
}
//ok now compose mastercd folder
char pNewMasterCDPath[256];
memset(pNewMasterCDPath, '\0',256);
memcpy(pNewMasterCDPath, realExecName.c_str(), loc);
pNewMasterCDPath[loc + 1] = '\0';//terminate string
SetCurrentDirectory(pNewMasterCDPath);
DIR *pNewTest = opendir(s.c_str());
if(pNewTest)
{
//adapt module path
string s(pNewMasterCDPath);
if(s.c_str()[s.size()-1] != '/')
s += "/";
s += gpBinDir;
if(s.c_str()[s.size()-1] != '/')
s += "/";
SetModulePath(s.c_str());
printf("setting MasterCD folder to: %s\n",pNewMasterCDPath);
SetFileAttributes(pNewMasterCDPath, 0x777);//set full access to current directory
closedir(pNewTest);
}
else
{
printf("could not find valid MasterCD folder\n");
exit(1);
}
}
else
{
printf("setting MasterCD folder to: %s\n",t.c_str());
closedir(pTest);
}
SetFileAttributes(".", 0x777);//set full access to current directory
}
const int CopyFile(const string& crSource, const string& crDest)
{
FILE *fs = ::fopen(crSource.c_str(), "rb");
int success = 0 ;
if (fs != NULL)
{
FILE *ft = ::fopen(crDest.c_str(), "wb");
if ( ft != NULL )
{
fseek(fs , 0, SEEK_END);
const int siz = ftell(fs);
if ( siz > 0 )
{
char *buf = new char[siz];
if(buf != NULL)
{
fseek(fs, 0, SEEK_SET);
int rb = fread(buf, 1, siz, fs);
int wb = fwrite(buf, 1, rb, ft);
delete buf; buf = NULL;
if(wb == siz)
success = 1;
}
}
fclose ( ft ) ;
}
fclose ( fs ) ;
}
return success;
}
void CopyPunkBusterFiles()
{
//copies punkbuster libraries if needed
const string sourceDir(GetModulePath());
char szExeFileName[_MAX_PATH];
GetCurrentDirectory(sizeof(szExeFileName), szExeFileName);
string destDir(szExeFileName); if(destDir.c_str()[destDir.size()-1] != '/') destDir += "/";
string linuxDestDir(destDir); linuxDestDir += "pb";
DIR *dirp = ::opendir(linuxDestDir.c_str());
//create symlink ./pb/ to ./PB/
if(dirp == NULL)
{
string dirTest(destDir);
dirTest += "PB";
DIR *d = ::opendir(dirTest.c_str());
if(d)
{
destDir += "PB";
closedir(d);
SetFileAttributes("./PB/", 0x777);//set full access to current directory
}
else
{
string dirTest(destDir);
dirTest += "Pb";
DIR *d1 = ::opendir(dirTest.c_str());
if(d1)
{
destDir += "Pb";
closedir(d1);
SetFileAttributes("./Pb/", 0x777);//set full access to current directory
}
else
{
string dirTest(destDir);
dirTest += "Pb";
DIR *d2 = ::opendir(dirTest.c_str());
if(d2)
{
destDir += "pB";
closedir(d2);
SetFileAttributes("./pB/", 0x777);//set full access to current directory
}
}
}
//create symlink
if(symlink(destDir.c_str(), linuxDestDir.c_str()) == -1)
{
printf("Cannot create symlink to Punkbuster directory %s: ",linuxDestDir.c_str());
int error = errno;
switch(error)
{
case EACCES:
printf("The process does not have search permission for a directory component of the file name\n");
break;
case ENAMETOOLONG :
printf("Either the total length of a file name is greater than PATH_MAX or an individual file name component has a length greater than NAME_MAX\n");
break;
case ENOENT:
printf("File referenced as a directory component in the file name doesn't exist\n");
break;
case ENOTDIR:
printf("A file that is referenced as a directory component in the file name exists, but it isn't a directory\n");
break;
case EEXIST:
printf("There is already an existing file named %s\n",linuxDestDir.c_str());
break;
case EROFS:
printf("The file would exist on a read-only file system\n");
break;
case ENOSPC:
printf("The directory or file system cannot be extended to make the new link\n");
break;
case EIO:
printf("A hardware error occurred while reading or writing data on the disk\n");
break;
}
}
dirp = ::opendir(linuxDestDir.c_str());
if(dirp == NULL)
{
printf("Cannot read symlink to Punkbuster directory: %s , Punkbuster won't work\n. Please create a symlink 'pb' pointing to 'PB' in the mastercd folder manually to make it work. Check access rights too.\n",linuxDestDir.c_str());
return;
}
}
else
{
destDir = linuxDestDir;
destDir += '/';
}
if(dirp)
{
SetFileAttributes(linuxDestDir.c_str(), 0x777);//set full access to current directory
closedir(dirp);
}
destDir += "/";
string s(sourceDir);
s += "pbag.so";
string d(destDir);
d += "pbag.so";
FILE *p = ::fopen(d.c_str(), "r");
if(p == NULL)
{
if(!CopyFile(s.c_str(), d.c_str()))
printf("Failed to copy Punkbuster files to working folder: from %s to %s\n", s.c_str(), d.c_str());
}
else
fclose(p);
s = sourceDir;
s += "pbcl.so";
d = destDir;
d += "pbcl.so";
p = ::fopen(d.c_str(), "r");
if(p == NULL)
{
if(!CopyFile(s.c_str(), d.c_str()))
printf("Failed to copy Punkbuster files to working folder: from %s to %s\n", s.c_str(), d.c_str());
}
else
fclose(p);
s = sourceDir;
s += "pbsv.so";
d = destDir;
d += "pbsv.so";
p = ::fopen(d.c_str(), "r");
if(p == NULL)
{
if(!CopyFile(s.c_str(), d.c_str()))
printf("Failed to copy Punkbuster files to working folder: from %s to %s\n", s.c_str(), d.c_str());
}
else
fclose(p);
}
int main(int argc, char **argv)
{
//change the file mode mask
umask(0);
std::map<int,sighandler_t> signalMap;
string cmdLine;
g_OnQuit = false;
bool bIsDaemon = false;
for(int i=1; i<argc; ++i)
{
const string argument(argv[i]);
if(argument.find("-daemon") != string::npos)
{
bIsDaemon = true;
continue;
}
cmdLine += string("\"")+argument+string("\"");
cmdLine += " ";
}
if(bIsDaemon)
{
//our process ID and Session ID
pid_t pid, sid;
//fork off the parent process
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
//if we got a good PID, then we can exit the parent process
if (pid > 0)
exit(EXIT_SUCCESS);
//open any logs here
//create a new SID for the child process
sid = setsid();
if (sid < 0)
//log the failure
exit(EXIT_FAILURE);
//close out the standard file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
RegisterExceptionHandler(signalMap);
assert(argc > 0);
SetMasterCDFolder(argv[0]);
//copy punkbuster libraries if needed
#ifndef NOT_USE_PUNKBUSTER_SDK
CopyPunkBusterFiles();
#endif
const int ret = MainCON(cmdLine.c_str(), bIsDaemon);
UnRegisterExceptionHandler(signalMap);
return ret;
}
#else //LINUX
//#ifndef NONWIN32TESTCOMPILE
#ifdef WIN32
#include <windows.h>
#include <ShellApi.h>
#include <process.h>
#endif
#include <vector>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <string>
#include <algorithm>
#include <platform.h>
#include "Cry_Math.h"
#include <Cry_Camera.h>
#include <IRenderer.h>
#include <ILog.h>
#include <ISystem.h>
#include <ITimer.h>
#include <IGame.h>
#include <IConsole.h> // IOutputPrintSink
#include <IInput.h>
#include <crtdbg.h>
#include "resource.h" // IDI_ICON
int MainWin32( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow );
//! Sink for ParseArguments()
struct ICmdlineArgumentSink
{
//! used for early command e.g. "-DEVMODE", "-IP:123.22.23.1", "-MOD:CS"
//! or for console command e.g. "map mp_airstrip", "name test"
//! \param inszArgument must not be 0
virtual void ReturnArgument( const char *inszArgument )=0;
};
void ParseArguments( const char *inszCommandLine, ICmdlineArgumentSink *pEarlyCommands, ICmdlineArgumentSink *pConsoleCommands )
{
assert(inszCommandLine);
// int iArgNo=0;
char *src=(char *)inszCommandLine;
char Arg[1024];
while(*src)
{
char *dst=Arg;
while(*src<=' ' && *src!=0)
src++; // jump over whitespace
if(*src=='\"')
{
src++;
while(*src!='\"' && *src!=0)
*dst++=*src++;
if(*src=='\"')
src++;
}
else
{
while(*src!=' ' && *src!=0)
*dst++=*src++;
}
*dst=0;
if(*Arg!=0)
{
// if(iArgNo!=0) // ignore .exe name
{
if(Arg[0]=='-')
{
if(pEarlyCommands)
pEarlyCommands->ReturnArgument(&Arg[1]);
}
else
{
if(pConsoleCommands)
pConsoleCommands->ReturnArgument(Arg);
}
}
// iArgNo++;
}
}
}
class CDetectEarlyCommand :public ICmdlineArgumentSink
{
public:
//! constructor
CDetectEarlyCommand()
{
m_bActivateCON=false;
}
virtual void ReturnArgument( const char *inszArgument )
{
if(strcmp("CON",inszArgument)==0)
m_bActivateCON=true;
}
bool m_bActivateCON; //!< true=simple stdio application, false=Win32 application
};
int APIENTRY _tWinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow )
{
CDetectEarlyCommand EarlyCommands;
ParseArguments(lpCmdLine,&EarlyCommands,0);
if(EarlyCommands.m_bActivateCON)
return MainCON(lpCmdLine);
else
{
FreeConsole();
return MainWin32(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
}
}
//////////////////////////////////////////////////////////////////////////
// Call to set correct root folder when running from Bin32
//////////////////////////////////////////////////////////////////////////
static void SetMasterCDFolder()
{
char szExeFileName[_MAX_PATH];
// Get the path of the executable
GetModuleFileName( GetModuleHandle(NULL), szExeFileName, sizeof(szExeFileName));
char path_buffer[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( szExeFileName, drive, dir, fname, ext );
_makepath( path_buffer, drive,dir,NULL,NULL );
strcat( path_buffer,".." );
SetCurrentDirectory( path_buffer );
}
//-------------------------------------------------------------------------------------------------
// tray icon stuff
#define WM_TRAYICON (WM_USER+5)
#define MENUID_SHOW (0x1001)
#define MENUID_QUIT (0x1002)
NOTIFYICONDATA g_NotifyIconData = {0};
HMENU g_hTrayMenu = 0;
void AddTrayIcon();
void RemoveTrayIcon();
void ShowTrayMenu(int x, int y);
void HideFromTaskBar();
void ShowOnTaskBar();
//-------------------------------------------------------------------------------------------------
TCHAR g_szWindowClass[]=_T("FarCry_WinSV"); //!< the main window class name
HWND g_WndMain=NULL; //!<
HWND g_WndIn=NULL; //!<
HWND g_WndOut=NULL; //!<
WNDPROC g_pfOldWindowProcOfWndIn( 0 );
const unsigned long g_dwInnerWidth=800;
const unsigned long g_dwInnerHeight=600;
const unsigned long g_dwEditLineHeight=16;
const unsigned long g_dwLineHeight=16;
class COutputPrintSink :public IOutputPrintSink
{
public:
//! constructor
COutputPrintSink(): m_dwFirstLine(0) {};
//! destructor
virtual ~COutputPrintSink() {};
unsigned int m_dwFirstLine; //!< used to be able to scroll the window with the Page up/down keys
// interface IOutputPrintSink ------------------------
virtual void Print( const char *inszText )
{
Redraw();
}
void Redraw()
{
InvalidateRect(g_WndOut,0,false);
UpdateWindow(g_WndOut);
}
// ---------------------------------------------------
void DrawHDC( HDC inHdc )
{
RECT rect;
GetClientRect(g_WndOut,&rect);
FillRect(inHdc, &rect,(HBRUSH)GetStockObject(BLACK_BRUSH));
HFONT hFont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
SelectObject(inHdc, hFont);
SetBkColor(inHdc, 0); // black
SetTextColor(inHdc, 0xaaaaaa); // BGR
TEXTMETRIC metric;
GetTextMetrics(inHdc, &metric);
if(!GetISystem())
{
const char *szInitString = "Initializing...";
const int szInitStringLen = (const int)strlen(szInitString);
unsigned long x = ((rect.right - rect.left) - szInitStringLen * metric.tmMaxCharWidth) >> 1;
unsigned long y = ((rect.bottom - rect.top) - metric.tmHeight) >> 1;
TextOut(inHdc, x, y, szInitString, szInitStringLen);
m_dwFirstLine = 0;
return;
}
IConsole *pConsole = GetISystem()->GetIConsole();
assert(pConsole);
unsigned long dwLineNo=m_dwFirstLine;
char szBuffer[256];
unsigned long y = g_dwInnerHeight - g_dwEditLineHeight-2;
while(pConsole->GetLineNo(dwLineNo++, szBuffer, 256))
{
y -= metric.tmHeight;
const char *szStripped = Strip(szBuffer);
TextOut(inHdc, 4, y, szStripped, (int)strlen(szStripped));
if(y < 0)
break;
}
}
};
COutputPrintSink g_Output;
bool OnWinInKeyDown( unsigned int uiChar, unsigned int uiRepCnt, unsigned int uiFlags )
{
IConsole* pConsole( ( 0 != GetISystem() ) ? GetISystem()->GetIConsole() : 0 );
assert( GetISystem() );
assert( pConsole );
if( 0 != pConsole )
{
if( VK_TAB != uiChar )
{
pConsole->ResetAutoCompletion();
}
switch( uiChar )
{
case VK_RETURN:
{
char szInput[ 512] ;
GetWindowText( g_WndIn, szInput, 511 );
SetWindowText( g_WndIn, "" );
UpdateWindow( g_WndIn );
pConsole->ExecuteString(szInput);
pConsole->AddCommandToHistory(szInput);
return true;
}
case VK_TAB:
{
char szInput[ 512 ];
GetWindowText( g_WndIn, szInput, 511 );
// don't use SendMessage( g_WndIn, WM_KEYDOWN, VK_END, 0 ) here as it will reset auto completion!
SendMessage( g_WndIn, EM_SETSEL, 0, -1 );
SendMessage( g_WndIn, EM_REPLACESEL, (WPARAM) TRUE, (LPARAM) pConsole->ProcessCompletion( szInput ) + 1 );
SendMessage( g_WndIn, EM_SETSEL, -1, -1 );
return( true );
}
case VK_PRIOR:
{
if( g_Output.m_dwFirstLine + 1 < (unsigned long) pConsole->GetLineCount() )
{
++g_Output.m_dwFirstLine;
g_Output.Redraw();
}
return( true );
}
case VK_NEXT:
{
if( 0 < g_Output.m_dwFirstLine )
{
--g_Output.m_dwFirstLine;
g_Output.Redraw();
}
return( true );
}
case VK_UP:
{
const char *szHistoryLine=pConsole->GetHistoryElement(true); // true=UP
if(szHistoryLine)
{
SetWindowText(g_WndIn,szHistoryLine);
SendMessage( g_WndIn, WM_KEYDOWN, VK_END, 0 ); // set the cursor to the end
}
return true;
}
case VK_DOWN:
{
const char *szHistoryLine=pConsole->GetHistoryElement(false); // false=DOWN
if(szHistoryLine)
{
SetWindowText(g_WndIn,szHistoryLine);
SendMessage( g_WndIn, WM_KEYDOWN, VK_END, 0 ); // set the cursor to the end
}
return true;
}
default:
{
return( false );
}
}
}
return( false );
}
bool
OnWinInChar( unsigned int uiChar, unsigned int uiRepCnt, unsigned int uiFlags )
{
switch( uiChar )
{
case VK_TAB:
case VK_RETURN:
{
return( true );
}
default:
{
break;
}
}
return( false );
}
LRESULT CALLBACK
WndInWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_KEYDOWN:
{
if( false != OnWinInKeyDown( (unsigned int) wParam, (unsigned int) LOWORD( lParam ), (unsigned int) HIWORD( lParam ) ) )
{
return( 0 );
}
}
case WM_CHAR:
{
if( false != OnWinInChar( (unsigned int) wParam, (unsigned int) LOWORD( lParam ), (unsigned int) HIWORD( lParam ) ) )
{
return( 0 );
}
}
}
return( CallWindowProc( g_pfOldWindowProcOfWndIn, hWnd, message, wParam, lParam ) );
}
LRESULT CALLBACK
WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case MENUID_SHOW:
ShowWindow(g_WndMain, SW_RESTORE);
SetForegroundWindow(g_WndMain);
SetActiveWindow(g_WndMain);
break;
case MENUID_QUIT:
PostQuitMessage(0);
break;
}
}
return 0;
case WM_SIZE:
{
if (wParam == SIZE_MINIMIZED)
{
AddTrayIcon();
HideFromTaskBar();
}
else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
{
RemoveTrayIcon();
ShowOnTaskBar();
}
}
break;
case WM_TRAYICON:
{
if (lParam == WM_RBUTTONUP)
{
POINT pt;
GetCursorPos(&pt);
ShowTrayMenu(pt.x, pt.y);
}
else if (lParam == WM_LBUTTONDBLCLK)
{
ShowWindow(g_WndMain, SW_RESTORE);
SetForegroundWindow(g_WndMain);
SetActiveWindow(g_WndMain);
}
}
return 0;
case WM_SETFOCUS:
{
SetFocus(g_WndIn); // only out input window can have focus
}
return 0;
case WM_PAINT:
{
if(hWnd == g_WndOut)
{
hdc = BeginPaint(hWnd, &ps);
g_Output.DrawHDC(hdc);
EndPaint(hWnd, &ps);
return 0;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_ICON);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(0); // black (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = g_szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_ICON);
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
#ifdef WIN32
g_WndMain = CreateWindow(g_szWindowClass, "Far Cry dedicated server", WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU,
CW_USEDEFAULT, 0,
g_dwInnerWidth+2*GetSystemMetrics(SM_CXFIXEDFRAME),
g_dwInnerHeight+2*GetSystemMetrics(SM_CYFIXEDFRAME)+GetSystemMetrics(SM_CYCAPTION),
NULL, NULL, hInstance, NULL);
if (!g_WndMain)
return FALSE;
// g_WndOut = CreateWindow("EDIT", "",WS_CHILD|WS_VISIBLE|WS_DISABLED,
// 0,0, g_dwInnerWidth, g_dwInnerHeight-g_dwEditLineHeight, g_WndMain, NULL, hInstance, NULL);
g_WndOut = CreateWindow(g_szWindowClass, "",WS_CHILD|WS_VISIBLE|WS_DISABLED,
0,0, g_dwInnerWidth, g_dwInnerHeight-g_dwEditLineHeight, g_WndMain, HMENU(), hInstance, NULL);
g_WndIn = CreateWindow("EDIT", "",WS_CHILD|WS_VISIBLE,
0,g_dwInnerHeight-g_dwEditLineHeight, g_dwInnerWidth, g_dwEditLineHeight, g_WndMain, HMENU(), hInstance, NULL);
// subclass input window of console
g_pfOldWindowProcOfWndIn = reinterpret_cast<WNDPROC>( SetWindowLongPtr( g_WndIn, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>( WndInWindowProc ) ) );
SendMessage( g_WndIn, WM_SETFONT, (WPARAM) GetStockObject( ANSI_FIXED_FONT ), 1 );
SetFocus( g_WndIn );
ShowWindow(g_WndMain, nCmdShow);
UpdateWindow( g_WndMain );
#endif
return TRUE;
}
int MainWin32( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
SetMasterCDFolder();
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
return FALSE;
// initialize the system
bool bRelaunch=false;
do
{
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF);
DeInitDedicatedServer();
Shell_NotifyIcon(NIM_DELETE, &g_NotifyIconData);
// parse and execute the early CmdLine arguments
InitDedicatedServer_System(lpCmdLine);
ISystem *pSysten = GetISystem();
if(!pSysten)
return FALSE; // if init failed
IConsole *pConsole = pSysten->GetIConsole();
assert(pConsole);
pConsole->AddOutputPrintSink(&g_Output);
PrintDedicatedServerStatus();
SetForegroundWindow( g_WndMain );
InitDedicatedServer_Game(lpCmdLine);
IGame *pGame = GetISystem()->GetIGame();
PrintWelcomeMessage();
while( pGame->Run( bRelaunch ) )
{
#ifdef WIN32
// Main message loop:
MSG msg;
while( 0 != PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
#endif
SleepIfNeeded();
#ifdef WIN32
if( WM_QUIT == msg.message )
{
break;
}
#endif // #ifdef WIN32
}
//#ifdef WIN32
// ::FreeLibrary(g_hSystemHandle);
//#endif
DeInitDedicatedServer();
} while(bRelaunch);
PrintGoodbyeMessage();
#ifdef WIN32
RemoveTrayIcon();
#endif
return true;
}
#ifdef WIN32
void AddTrayIcon()
{
RemoveTrayIcon(); // make sure we have only one icon at a time
// add a tray icon
memset(&g_NotifyIconData, 0, sizeof(NOTIFYICONDATA));
g_NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
g_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
g_NotifyIconData.hWnd = g_WndMain;
g_NotifyIconData.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON));
g_NotifyIconData.uCallbackMessage = WM_TRAYICON;
strncpy(g_NotifyIconData.szTip, "Far Cry Dedicated Server", 64);
Shell_NotifyIcon(NIM_ADD, &g_NotifyIconData);
g_hTrayMenu = CreatePopupMenu();
AppendMenu(g_hTrayMenu, MF_STRING, MENUID_SHOW, "Show Console");
AppendMenu(g_hTrayMenu, MF_SEPARATOR, 0, 0);
AppendMenu(g_hTrayMenu, MF_STRING, MENUID_QUIT, "Quit");
}
void RemoveTrayIcon()
{
Shell_NotifyIcon(NIM_DELETE, &g_NotifyIconData);
DestroyMenu(g_hTrayMenu);
}
void HideFromTaskBar()
{
ShowWindow(g_WndMain, SW_HIDE);
SetWindowLong(g_WndMain, GWL_EXSTYLE, GetWindowLong(g_WndMain, GWL_EXSTYLE) & ~WS_EX_APPWINDOW);
}
void ShowOnTaskBar()
{
SetWindowLong(g_WndMain, GWL_EXSTYLE, GetWindowLong(g_WndMain, GWL_EXSTYLE) | WS_EX_APPWINDOW);
ShowWindow(g_WndMain, SW_SHOW);
}
void ShowTrayMenu(int x, int y)
{
TrackPopupMenu(g_hTrayMenu, TPM_LEFTALIGN, x, y, 0, g_WndMain, 0);
}
#endif // WIN32
#endif //LINUX
//#endif // NONWIN32TESTCOMPILE