2004-08-23 00:15:46 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2010-12-15 12:29:58 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2005-02-28 07:16:19 +00:00
# include "qwsvdef.h"
2004-08-23 00:15:46 +00:00
# include <sys/types.h>
# include <sys/timeb.h>
2004-09-04 17:59:22 +00:00
# ifdef SERVERONLY
2004-08-23 00:15:46 +00:00
# include <winsock.h>
# include <conio.h>
2007-12-30 20:05:49 +00:00
# ifdef MULTITHREAD
# include <process.h>
# endif
2004-08-23 00:15:46 +00:00
# ifndef MINIMAL
2004-12-13 00:44:43 +00:00
//#define USESERVICE
2004-08-23 00:15:46 +00:00
# endif
2005-11-14 01:32:21 +00:00
# define SERVICENAME DISTRIBUTION"SV"
2004-08-23 00:15:46 +00:00
2004-12-13 00:44:43 +00:00
2005-10-04 21:16:47 +00:00
static HANDLE hconsoleout ;
2009-03-07 05:05:54 +00:00
2010-07-18 08:42:59 +00:00
# ifdef _DEBUG
# if _MSC_VER >= 1300
# define CATCHCRASH
# endif
# endif
# ifdef CATCHCRASH
# include "dbghelp.h"
typedef BOOL ( WINAPI * MINIDUMPWRITEDUMP ) (
HANDLE hProcess ,
DWORD ProcessId ,
HANDLE hFile ,
MINIDUMP_TYPE DumpType ,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam ,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam ,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
) ;
DWORD CrashExceptionHandler ( DWORD exceptionCode , LPEXCEPTION_POINTERS exceptionInfo )
{
char dumpPath [ 1024 ] ;
HANDLE hProc = GetCurrentProcess ( ) ;
DWORD procid = GetCurrentProcessId ( ) ;
HANDLE dumpfile ;
HMODULE hDbgHelp ;
MINIDUMPWRITEDUMP fnMiniDumpWriteDump ;
HMODULE hKernel ;
BOOL ( WINAPI * pIsDebuggerPresent ) ( void ) ;
hKernel = LoadLibrary ( " kernel32 " ) ;
pIsDebuggerPresent = ( void * ) GetProcAddress ( hKernel , " IsDebuggerPresent " ) ;
# ifdef GLQUAKE
GLVID_Crashed ( ) ;
# endif
if ( pIsDebuggerPresent ( ) )
{
/*if we have a current window, minimize it to bring us out of fullscreen*/
return EXCEPTION_CONTINUE_SEARCH ;
}
hDbgHelp = LoadLibrary ( " DBGHELP " ) ;
if ( hDbgHelp )
fnMiniDumpWriteDump = ( MINIDUMPWRITEDUMP ) GetProcAddress ( hDbgHelp , " MiniDumpWriteDump " ) ;
else
fnMiniDumpWriteDump = NULL ;
if ( fnMiniDumpWriteDump )
{
if ( MessageBox ( NULL , " KABOOM! We crashed! \n Blame the monkey in the corner. \n I hope you saved your work. \n Would you like to take a dump now? " , DISTRIBUTION " Sucks " , MB_ICONSTOP | MB_YESNO ) ! = IDYES )
return EXCEPTION_EXECUTE_HANDLER ;
/*take a dump*/
GetTempPath ( sizeof ( dumpPath ) - 16 , dumpPath ) ;
Q_strncatz ( dumpPath , DISTRIBUTION " CrashDump.dmp " , sizeof ( dumpPath ) ) ;
dumpfile = CreateFile ( dumpPath , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( dumpfile )
{
MINIDUMP_EXCEPTION_INFORMATION crashinfo ;
crashinfo . ClientPointers = TRUE ;
crashinfo . ExceptionPointers = exceptionInfo ;
crashinfo . ThreadId = GetCurrentThreadId ( ) ;
if ( fnMiniDumpWriteDump ( hProc , procid , dumpfile , MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs , & crashinfo , NULL , NULL ) )
{
CloseHandle ( dumpfile ) ;
MessageBox ( NULL , va ( " You can find the crashdump at \n %s \n Please send this file to someone. \n \n Warning: sensitive information (like your current user name) might be present in the dump. \n You will probably want to compress it. " , dumpPath ) , DISTRIBUTION " Sucks " , 0 ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
}
}
else
MessageBox ( NULL , " Kaboom! Sorry. No MiniDumpWriteDump function. " , DISTRIBUTION " Sucks " , 0 ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
# endif
2009-03-07 05:05:54 +00:00
void Sys_CloseLibrary ( dllhandle_t * lib )
{
FreeLibrary ( ( HMODULE ) lib ) ;
}
2009-11-04 21:16:50 +00:00
dllhandle_t * Sys_LoadLibrary ( const char * name , dllfunction_t * funcs )
2009-03-07 05:05:54 +00:00
{
int i ;
HMODULE lib ;
lib = LoadLibrary ( name ) ;
if ( ! lib )
return NULL ;
2011-05-30 21:48:32 +00:00
if ( funcs )
2009-03-07 05:05:54 +00:00
{
2011-05-30 21:48:32 +00:00
for ( i = 0 ; funcs [ i ] . name ; i + + )
{
* funcs [ i ] . funcptr = GetProcAddress ( lib , funcs [ i ] . name ) ;
if ( ! * funcs [ i ] . funcptr )
break ;
}
if ( funcs [ i ] . name )
{
Sys_CloseLibrary ( ( dllhandle_t * ) lib ) ;
lib = NULL ;
}
2009-03-07 05:05:54 +00:00
}
return ( dllhandle_t * ) lib ;
}
2009-11-04 21:16:50 +00:00
void * Sys_GetAddressForName ( dllhandle_t * module , const char * exportname )
2009-03-07 05:05:54 +00:00
{
if ( ! module )
return NULL ;
return GetProcAddress ( ( HINSTANCE ) module , exportname ) ;
}
# ifdef HLSERVER
char * Sys_GetNameForAddress ( dllhandle_t * module , void * address )
{
//windows doesn't provide a function to do this, so we have to do it ourselves.
//this isn't the fastest way...
//halflife needs this function.
char * base = ( char * ) module ;
IMAGE_DATA_DIRECTORY * datadir ;
IMAGE_EXPORT_DIRECTORY * block ;
IMAGE_NT_HEADERS * ntheader ;
IMAGE_DOS_HEADER * dosheader = ( void * ) base ;
int i , j ;
DWORD * funclist ;
DWORD * namelist ;
SHORT * ordilist ;
if ( ! dosheader | | dosheader - > e_magic ! = IMAGE_DOS_SIGNATURE )
return NULL ; //yeah, that wasn't an exe
ntheader = ( void * ) ( base + dosheader - > e_lfanew ) ;
if ( ! dosheader - > e_lfanew | | ntheader - > Signature ! = IMAGE_NT_SIGNATURE )
return NULL ; //urm, wait, a 16bit dos exe?
datadir = & ntheader - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] ;
2010-12-15 12:29:58 +00:00
2009-03-07 05:05:54 +00:00
block = ( IMAGE_EXPORT_DIRECTORY * ) ( base + datadir - > VirtualAddress ) ;
funclist = ( DWORD * ) ( base + block - > AddressOfFunctions ) ;
namelist = ( DWORD * ) ( base + block - > AddressOfNames ) ;
ordilist = ( SHORT * ) ( base + block - > AddressOfNameOrdinals ) ;
for ( i = 0 ; i < block - > NumberOfFunctions ; i + + )
{
if ( base + funclist [ i ] = = address )
{
for ( j = 0 ; j < block - > NumberOfNames ; j + + )
{
if ( ordilist [ j ] = = i )
{
return base + namelist [ i ] ;
}
}
//it has no name. huh?
return NULL ;
}
}
return NULL ;
}
# endif
# ifdef Q2SERVER
2004-12-13 00:44:43 +00:00
static HINSTANCE game_library ;
/*
= = = = = = = = = = = = = = = = =
Sys_UnloadGame
= = = = = = = = = = = = = = = = =
*/
void Sys_UnloadGame ( void )
{
if ( ! FreeLibrary ( game_library ) )
Sys_Error ( " FreeLibrary failed for game library " ) ;
game_library = NULL ;
}
/*
= = = = = = = = = = = = = = = = =
Sys_GetGameAPI
Loads the game dll
= = = = = = = = = = = = = = = = =
*/
void * Sys_GetGameAPI ( void * parms )
{
2012-02-27 12:23:15 +00:00
void * ( VARGS * GetGameAPI ) ( void * ) ;
2004-12-13 00:44:43 +00:00
char name [ MAX_OSPATH ] ;
char * path ;
char cwd [ MAX_OSPATH ] ;
2010-12-15 12:29:58 +00:00
// _M_X64 should be really loading gamex64.dll
# if defined _M_IX86 || defined _M_X64
2004-12-13 00:44:43 +00:00
const char * gamename = " gamex86.dll " ;
# ifdef NDEBUG
const char * debugdir = " release " ;
# else
const char * debugdir = " debug " ;
# endif
2007-09-02 19:55:17 +00:00
# elif defined __amd64__
const char * gamename = " gameamd.dll " ;
# ifdef NDEBUG
const char * debugdir = " release " ;
# else
const char * debugdir = " debug " ;
# endif
2004-12-13 00:44:43 +00:00
# elif defined _M_ALPHA
const char * gamename = " gameaxp.dll " ;
# ifdef NDEBUG
const char * debugdir = " releaseaxp " ;
# else
const char * debugdir = " debugaxp " ;
# endif
# endif
if ( game_library )
Sys_Error ( " Sys_GetGameAPI without Sys_UnloadingGame " ) ;
// check the current debug directory first for development purposes
# ifdef _WIN32
GetCurrentDirectory ( sizeof ( cwd ) , cwd ) ;
# else
_getcwd ( cwd , sizeof ( cwd ) ) ;
# endif
2006-03-11 04:39:16 +00:00
snprintf ( name , sizeof ( name ) , " %s/%s/%s " , cwd , debugdir , gamename ) ;
2004-12-13 00:44:43 +00:00
game_library = LoadLibrary ( name ) ;
if ( game_library )
{
Con_DPrintf ( " LoadLibrary (%s) \n " , name ) ;
}
else
{
# ifdef DEBUG
// check the current directory for other development purposes
_snprintf ( name , sizeof ( name ) , " %s/%s " , cwd , gamename ) ;
game_library = LoadLibrary ( name ) ;
if ( game_library )
{
Con_DPrintf ( " LoadLibrary (%s) \n " , name ) ;
}
else
# endif
{
// now run through the search paths
path = NULL ;
while ( 1 )
{
path = COM_NextPath ( path ) ;
if ( ! path )
return NULL ; // couldn't find one anywhere
2006-03-11 04:39:16 +00:00
snprintf ( name , sizeof ( name ) , " %s/%s " , path , gamename ) ;
2004-12-13 00:44:43 +00:00
game_library = LoadLibrary ( name ) ;
if ( game_library )
{
Con_DPrintf ( " LoadLibrary (%s) \n " , name ) ;
break ;
}
}
}
}
GetGameAPI = ( void * ) GetProcAddress ( game_library , " GetGameAPI " ) ;
if ( ! GetGameAPI )
{
2010-12-15 12:29:58 +00:00
Sys_UnloadGame ( ) ;
2004-12-13 00:44:43 +00:00
return NULL ;
}
return GetGameAPI ( parms ) ;
}
2009-03-07 05:05:54 +00:00
# endif
2004-12-13 00:44:43 +00:00
2004-08-23 00:15:46 +00:00
# include <fcntl.h>
# include <io.h>
# include <signal.h>
# include <shellapi.h>
# ifdef USESERVICE
qboolean asservice ;
2010-12-15 12:29:58 +00:00
SERVICE_STATUS_HANDLE ServerServiceStatusHandle ;
SERVICE_STATUS MyServiceStatus ;
2004-08-23 00:15:46 +00:00
void CreateSampleService ( qboolean create ) ;
# endif
void PR_Deinit ( void ) ;
cvar_t sys_nostdout = { " sys_nostdout " , " 0 " } ;
2005-10-04 21:16:47 +00:00
cvar_t sys_colorconsole = { " sys_colorconsole " , " 1 " } ;
2004-08-23 00:15:46 +00:00
HWND consolewindowhandle ;
HWND hiddenwindowhandler ;
2005-12-06 01:38:31 +00:00
int Sys_DebugLog ( char * file , char * fmt , . . . )
2004-08-23 00:15:46 +00:00
{
2010-12-15 12:29:58 +00:00
va_list argptr ;
2004-08-23 00:15:46 +00:00
static char data [ 1024 ] ;
int fd ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
va_start ( argptr , fmt ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( data , sizeof ( data ) - 1 , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
fd = open ( file , O_WRONLY | O_CREAT | O_APPEND , 0666 ) ;
2005-12-05 16:47:29 +00:00
if ( fd )
{
write ( fd , data , strlen ( data ) ) ;
close ( fd ) ;
return 0 ;
}
return 1 ; // error
2004-08-23 00:15:46 +00:00
} ;
/*
= = = = = = = = = = = = = = = =
Sys_FileTime
= = = = = = = = = = = = = = = =
*/
int Sys_FileTime ( char * path )
{
FILE * f ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
f = fopen ( path , " rb " ) ;
if ( f )
{
fclose ( f ) ;
return 1 ;
}
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
return - 1 ;
}
/*
= = = = = = = = = = = = = = = =
Sys_mkdir
= = = = = = = = = = = = = = = =
*/
int _mkdir ( const char * path ) ; ;
void Sys_mkdir ( char * path )
{
_mkdir ( path ) ;
}
qboolean Sys_remove ( char * path )
{
remove ( path ) ;
return true ;
}
2009-04-01 22:03:56 +00:00
int Sys_EnumerateFiles ( const char * gpath , const char * match , int ( * func ) ( const char * , int , void * ) , void * parm )
2004-08-23 00:15:46 +00:00
{
HANDLE r ;
2010-12-15 12:29:58 +00:00
WIN32_FIND_DATA fd ;
2004-08-23 00:15:46 +00:00
char apath [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
char * s ;
int go ;
2006-05-19 19:15:52 +00:00
Q_strncpyz ( apath , match , sizeof ( apath ) ) ;
2004-08-23 00:15:46 +00:00
// sprintf(apath, "%s%s", gpath, match);
for ( s = apath + strlen ( apath ) - 1 ; s > = apath ; s - - )
{
2010-12-15 12:29:58 +00:00
if ( * s = = ' / ' )
2004-08-23 00:15:46 +00:00
break ;
}
s + + ;
2010-12-15 12:29:58 +00:00
* s = ' \0 ' ;
2004-08-23 00:15:46 +00:00
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s/%s " , gpath , match ) ;
2004-08-23 00:15:46 +00:00
r = FindFirstFile ( file , & fd ) ;
if ( r = = ( HANDLE ) - 1 )
return 1 ;
go = true ;
do
{
2005-05-30 12:30:41 +00:00
if ( fd . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) //is a directory
2004-08-23 00:15:46 +00:00
{
if ( * fd . cFileName ! = ' . ' )
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s/ " , apath , fd . cFileName ) ;
2004-08-23 00:15:46 +00:00
go = func ( file , fd . nFileSizeLow , parm ) ;
}
}
2005-05-30 12:30:41 +00:00
else
{
2006-05-19 19:15:52 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s " , apath , fd . cFileName ) ;
2005-05-30 12:30:41 +00:00
go = func ( file , fd . nFileSizeLow , parm ) ;
}
2004-08-23 00:15:46 +00:00
}
while ( FindNextFile ( r , & fd ) & & go ) ;
FindClose ( r ) ;
return go ;
}
/*
= = = = = = = = = = = = = = = =
Sys_Error
= = = = = = = = = = = = = = = =
*/
# include <process.h>
void Sys_Error ( const char * error , . . . )
{
va_list argptr ;
char text [ 1024 ] ;
double end ;
2006-05-13 21:11:06 +00:00
STARTUPINFO startupinfo ;
PROCESS_INFORMATION processinfo ;
2004-08-23 00:15:46 +00:00
va_start ( argptr , error ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( text , sizeof ( text ) - 1 , error , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
// MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
Sys_Printf ( " ERROR: %s \n " , text ) ;
2005-09-26 08:07:26 +00:00
Con_Log ( text ) ;
2004-08-23 00:15:46 +00:00
NET_Shutdown ( ) ; //free sockets and stuff.
# ifdef USESERVICE
if ( asservice )
Sys_Quit ( ) ;
# endif
2006-01-02 22:36:12 +00:00
if ( COM_CheckParm ( " -noreset " ) )
Sys_Quit ( ) ;
2004-08-23 00:15:46 +00:00
Sys_Printf ( " A new server will be started in 10 seconds unless you press a key \n " ) ;
//check for a key press, quitting if we get one in 10 secs
end = Sys_DoubleTime ( ) + 10 ;
while ( Sys_DoubleTime ( ) < end )
{
2006-05-13 21:11:06 +00:00
Sleep ( 500 ) ; // don't burn up CPU with polling
2004-08-23 00:15:46 +00:00
if ( _kbhit ( ) )
Sys_Quit ( ) ;
}
2006-05-13 21:11:06 +00:00
Sys_Printf ( " \n Loading new instance of FTE... \n \n \n " ) ;
2004-08-23 00:15:46 +00:00
PR_Deinit ( ) ; //this takes a bit more mem
Rank_Flush ( ) ;
# ifndef MINGW
fcloseall ( ) ; //make sure all files are written.
# endif
VirtualFree ( host_parms . membase , 0 , MEM_RELEASE ) ;
// free(host_parms.membase); //get rid of the mem. We don't need it now.
// system("dqwsv.exe"); //spawn a new server to take over. This way, if debugging, then any key will quit, otherwise the server will just spawn a new one.
2006-05-13 21:11:06 +00:00
memset ( & startupinfo , 0 , sizeof ( startupinfo ) ) ;
memset ( & processinfo , 0 , sizeof ( processinfo ) ) ;
CreateProcess ( NULL ,
GetCommandLine ( ) ,
NULL ,
NULL ,
false ,
0 ,
NULL ,
NULL ,
& startupinfo ,
& processinfo ) ;
CloseHandle ( processinfo . hProcess ) ;
CloseHandle ( processinfo . hThread ) ;
2004-08-23 00:15:46 +00:00
Sys_Quit ( ) ;
2011-05-19 13:34:07 +00:00
exit ( 1 ) ; // this function is NORETURN type, complains without this
2004-08-23 00:15:46 +00:00
}
2007-10-02 15:17:22 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Milliseconds
= = = = = = = = = = = = = = = =
*/
unsigned int Sys_Milliseconds ( void )
{
static DWORD starttime ;
static qboolean first = true ;
DWORD now ;
// double t;
now = timeGetTime ( ) ;
if ( first ) {
first = false ;
starttime = now ;
return 0.0 ;
}
/*
if ( now < starttime ) // wrapped?
{
double r ;
r = ( now ) + ( LONG_MAX - starttime ) ;
starttime = now ;
return r ;
}
if ( now - starttime = = 0 )
return 0.0 ;
*/
return ( now - starttime ) ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_DoubleTime
= = = = = = = = = = = = = = = =
*/
double Sys_DoubleTime ( void )
{
double t ;
struct _timeb tstruct ;
static int starttime ;
_ftime ( & tstruct ) ;
2006-09-17 00:59:22 +00:00
2004-08-23 00:15:46 +00:00
if ( ! starttime )
starttime = tstruct . time ;
t = ( tstruct . time - starttime ) + tstruct . millitm * 0.001 ;
2010-12-15 12:29:58 +00:00
2004-08-23 00:15:46 +00:00
return t ;
}
/*
= = = = = = = = = = = = = = = =
Sys_ConsoleInput
= = = = = = = = = = = = = = = =
*/
2005-10-04 21:16:47 +00:00
char coninput_text [ 256 ] ;
int coninput_len ;
2004-08-23 00:15:46 +00:00
char * Sys_ConsoleInput ( void )
{
int c ;
if ( consolewindowhandle )
{
MSG msg ;
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_NOREMOVE ) )
{
if ( ! GetMessage ( & msg , NULL , 0 , 0 ) )
return NULL ;
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return NULL ;
}
// read a line out
while ( _kbhit ( ) )
{
c = _getch ( ) ;
if ( c = = ' \r ' )
{
2005-10-04 21:16:47 +00:00
coninput_text [ coninput_len ] = 0 ;
2004-08-23 00:15:46 +00:00
putch ( ' \n ' ) ;
2005-10-04 21:16:47 +00:00
putch ( ' ] ' ) ;
coninput_len = 0 ;
return coninput_text ;
2004-08-23 00:15:46 +00:00
}
if ( c = = 8 )
{
2005-10-04 21:16:47 +00:00
if ( coninput_len )
2004-08-23 00:15:46 +00:00
{
2005-10-04 21:16:47 +00:00
putch ( c ) ;
2004-08-23 00:15:46 +00:00
putch ( ' ' ) ;
putch ( c ) ;
2005-10-04 21:16:47 +00:00
coninput_len - - ;
coninput_text [ coninput_len ] = 0 ;
}
continue ;
}
if ( c = = ' \t ' )
{
int i ;
char * s = Cmd_CompleteCommand ( coninput_text , true , true , 0 ) ;
if ( s )
{
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
strcpy ( coninput_text , s ) ;
coninput_len = strlen ( coninput_text ) ;
printf ( " %s " , coninput_text ) ;
2004-08-23 00:15:46 +00:00
}
continue ;
}
2005-10-04 21:16:47 +00:00
putch ( c ) ;
coninput_text [ coninput_len ] = c ;
coninput_len + + ;
coninput_text [ coninput_len ] = 0 ;
if ( coninput_len = = sizeof ( coninput_text ) )
coninput_len = 0 ;
2004-08-23 00:15:46 +00:00
}
return NULL ;
}
2005-10-04 21:16:47 +00:00
void ApplyColour ( unsigned int chr )
{
2006-01-01 09:01:15 +00:00
static int oldchar = CON_WHITEMASK ;
chr & = CON_FLAGSMASK ;
2005-10-04 21:16:47 +00:00
if ( oldchar = = chr )
return ;
oldchar = chr ;
if ( hconsoleout )
{
2006-01-01 09:01:15 +00:00
unsigned short val = 0 ;
2010-12-15 12:29:58 +00:00
// bits 28-31 of the console chars match up to the attributes for
2006-01-01 09:01:15 +00:00
// the CHAR_INFO struct exactly
if ( chr & CON_NONCLEARBG )
2006-07-29 21:09:43 +00:00
val = ( ( chr & ( CON_FGMASK | CON_BGMASK ) ) > > CON_FGSHIFT ) ;
2006-01-01 09:01:15 +00:00
else
2005-10-04 21:16:47 +00:00
{
2006-01-01 09:01:15 +00:00
int fg = ( chr & CON_FGMASK ) > > CON_FGSHIFT ;
switch ( fg )
{
case COLOR_BLACK : // reverse ^0 like the Linux version
val = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE ;
break ;
case COLOR_WHITE : // reset to defaults?
val = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE ; // use grey
break ;
case COLOR_GREY :
val = FOREGROUND_INTENSITY ; // color light grey as dark grey
break ;
default :
val = fg ; // send RGBI value as is
break ;
}
2005-10-04 21:16:47 +00:00
}
2006-01-01 09:01:15 +00:00
if ( ( chr & CON_HALFALPHA ) & & ( val & ~ FOREGROUND_INTENSITY ) )
val & = ~ FOREGROUND_INTENSITY ; // strip intensity to fake alpha
2005-10-04 21:16:47 +00:00
SetConsoleTextAttribute ( hconsoleout , val ) ;
}
}
void Sys_PrintColouredChar ( unsigned int chr )
{
ApplyColour ( chr ) ;
2006-01-01 09:01:15 +00:00
printf ( " %c " , chr & CON_CHARMASK ) ;
2005-10-04 21:16:47 +00:00
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Printf
= = = = = = = = = = = = = = = =
*/
2005-10-04 21:16:47 +00:00
# define MAXPRINTMSG 4096
2004-08-23 00:15:46 +00:00
void Sys_Printf ( char * fmt , . . . )
{
2010-12-15 12:29:58 +00:00
va_list argptr ;
2004-08-23 00:15:46 +00:00
if ( sys_nostdout . value )
return ;
2005-10-04 21:16:47 +00:00
if ( 1 )
{
char msg [ MAXPRINTMSG ] ;
unsigned char * t ;
va_start ( argptr , fmt ) ;
2006-03-11 04:39:16 +00:00
vsnprintf ( msg , sizeof ( msg ) - 1 , fmt , argptr ) ;
2005-10-04 21:16:47 +00:00
va_end ( argptr ) ;
{
int i ;
2010-12-15 12:29:58 +00:00
2005-10-04 21:16:47 +00:00
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
}
for ( t = ( unsigned char * ) msg ; * t ; t + + )
{
if ( * t > = 146 & & * t < 156 )
* t = * t - 146 + ' 0 ' ;
if ( * t > = 0x12 & & * t < = 0x1b )
* t = * t - 0x12 + ' 0 ' ;
if ( * t = = 143 )
* t = ' . ' ;
if ( * t = = 157 | | * t = = 158 | | * t = = 159 )
* t = ' - ' ;
if ( * t > = 128 )
* t - = 128 ;
if ( * t = = 16 )
* t = ' [ ' ;
if ( * t = = 17 )
* t = ' ] ' ;
if ( * t = = 0x1c )
* t = 249 ;
}
if ( sys_colorconsole . value & & hconsoleout )
{
2006-01-01 09:01:15 +00:00
int ext = CON_WHITEMASK ;
2005-10-04 21:16:47 +00:00
int extstack [ 4 ] ;
int extstackdepth = 0 ;
unsigned char * str = ( unsigned char * ) msg ;
while ( * str )
{
if ( * str = = ' ^ ' )
{
str + + ;
2006-01-01 09:01:15 +00:00
if ( * str > = ' 0 ' & & * str < = ' 9 ' )
2005-10-04 21:16:47 +00:00
{
2006-01-01 09:01:15 +00:00
ext = q3codemasks [ * str + + - ' 0 ' ] | ( ext & ~ CON_Q3MASK ) ; //change colour only.
2005-10-04 21:16:47 +00:00
continue ;
}
2006-01-11 07:23:31 +00:00
else if ( * str = = ' & ' ) // extended code
{
2006-04-06 08:42:24 +00:00
if ( isextendedcode ( str [ 1 ] ) & & isextendedcode ( str [ 2 ] ) )
2006-01-11 07:23:31 +00:00
{
str + + ; // foreground char
if ( * str = = ' - ' ) // default for FG
ext = ( COLOR_WHITE < < CON_FGSHIFT ) | ( ext & ~ CON_FGMASK ) ;
else if ( * str > = ' A ' )
ext = ( ( * str - ( ' A ' - 10 ) ) < < CON_FGSHIFT ) | ( ext & ~ CON_FGMASK ) ;
else
ext = ( ( * str - ' 0 ' ) < < CON_FGSHIFT ) | ( ext & ~ CON_FGMASK ) ;
str + + ; // background char
if ( * str = = ' - ' ) // default (clear) for BG
ext & = ~ CON_BGMASK & ~ CON_NONCLEARBG ;
else if ( * str > = ' A ' )
ext = ( ( * str - ( ' A ' - 10 ) ) < < CON_BGSHIFT ) | ( ext & ~ CON_BGMASK ) | CON_NONCLEARBG ;
else
ext = ( ( * str - ' 0 ' ) < < CON_BGSHIFT ) | ( ext & ~ CON_BGMASK ) | CON_NONCLEARBG ;
2006-04-06 20:57:46 +00:00
str + + ;
2006-01-11 07:23:31 +00:00
continue ;
}
2006-04-06 08:21:17 +00:00
Sys_PrintColouredChar ( ' ^ ' | ext ) ;
// else invalid code
2006-01-11 07:23:31 +00:00
}
2005-10-04 21:16:47 +00:00
else if ( * str = = ' a ' )
{
str + + ;
2006-01-01 09:01:15 +00:00
ext ^ = CON_2NDCHARSETTEXT ;
2005-10-04 21:16:47 +00:00
continue ;
}
else if ( * str = = ' b ' )
{
str + + ;
2006-01-01 09:01:15 +00:00
ext ^ = CON_BLINKTEXT ;
2005-10-04 21:16:47 +00:00
continue ;
}
2006-01-11 07:23:31 +00:00
else if ( * str = = ' h ' )
{
str + + ;
ext ^ = CON_HALFALPHA ;
continue ;
}
2005-10-04 21:16:47 +00:00
else if ( * str = = ' s ' ) //store on stack (it's great for names)
{
str + + ;
if ( extstackdepth < sizeof ( extstack ) / sizeof ( extstack [ 0 ] ) )
{
extstack [ extstackdepth ] = ext ;
extstackdepth + + ;
}
continue ;
}
else if ( * str = = ' r ' ) //restore from stack (it's great for names)
{
str + + ;
if ( extstackdepth )
{
extstackdepth - - ;
ext = extstack [ extstackdepth ] ;
}
continue ;
}
else if ( * str = = ' ^ ' )
{
2006-01-01 09:01:15 +00:00
Sys_PrintColouredChar ( ' ^ ' | ext ) ;
2005-10-04 21:16:47 +00:00
str + + ;
}
else
{
2006-01-01 09:01:15 +00:00
Sys_PrintColouredChar ( ' ^ ' | ext ) ;
Sys_PrintColouredChar ( ( * str + + ) | ext ) ;
2005-10-04 21:16:47 +00:00
}
continue ;
}
2006-01-01 09:01:15 +00:00
Sys_PrintColouredChar ( ( * str + + ) | ext ) ;
2005-10-04 21:16:47 +00:00
}
2006-01-01 09:01:15 +00:00
ApplyColour ( CON_WHITEMASK ) ;
2005-10-04 21:16:47 +00:00
}
else
printf ( " %s " , msg ) ;
if ( coninput_len )
printf ( " ]%s " , coninput_text ) ;
else
putch ( ' ] ' ) ;
}
else
{
va_start ( argptr , fmt ) ;
vprintf ( fmt , argptr ) ;
va_end ( argptr ) ;
}
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = =
Sys_Quit
= = = = = = = = = = = = = = = =
*/
void Sys_Quit ( void )
{
# ifdef USESERVICE
if ( asservice )
{
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
2004-08-23 00:15:46 +00:00
}
# endif
exit ( 0 ) ;
}
int restorecode ;
LRESULT ( CALLBACK Sys_WindowHandler ) ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
if ( uMsg = = WM_USER )
{
if ( lParam & 1 )
{
}
else if ( ( lParam & 2 & & restorecode = = 0 ) | |
( lParam & 4 & & restorecode = = 1 ) | |
( lParam & 4 & & restorecode = = 2 ) )
{
// MessageBox(NULL, "Hello", "", 0);
restorecode + + ;
}
else if ( lParam & 2 & & restorecode = = 3 )
{
DestroyWindow ( hWnd ) ;
ShowWindow ( consolewindowhandle , SW_SHOWNORMAL ) ;
consolewindowhandle = NULL ;
Cbuf_AddText ( " status \n " , RESTRICT_LOCAL ) ;
}
else if ( lParam & 6 )
{
restorecode = ( lParam & 2 ) > 0 ;
}
return 0 ;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
void Sys_HideConsole ( void )
{
HMODULE kernel32dll ;
HWND ( WINAPI * GetConsoleWindow ) ( void ) ;
if ( consolewindowhandle )
return ; //err... already hidden... ?
restorecode = 0 ;
GetConsoleWindow = NULL ;
kernel32dll = LoadLibrary ( " kernel32.dll " ) ;
consolewindowhandle = NULL ;
if ( kernel32dll )
{
GetConsoleWindow = ( void * ) GetProcAddress ( kernel32dll , " GetConsoleWindow " ) ;
if ( GetConsoleWindow )
consolewindowhandle = GetConsoleWindow ( ) ;
FreeModule ( kernel32dll ) ; //works because the underlying code uses kernel32, so this decreases the reference count rather than closing it.
}
if ( ! consolewindowhandle )
{
char old [ 512 ] ;
2005-03-10 03:55:18 +00:00
# define STRINGH "Trying to hide" //msvc sucks
2004-08-23 00:15:46 +00:00
GetConsoleTitle ( old , sizeof ( old ) ) ;
2005-03-10 03:55:18 +00:00
SetConsoleTitle ( STRINGH ) ;
consolewindowhandle = FindWindow ( NULL , STRINGH ) ;
2004-08-23 00:15:46 +00:00
SetConsoleTitle ( old ) ;
2005-03-10 03:55:18 +00:00
# undef STRINGH
2004-08-23 00:15:46 +00:00
}
if ( consolewindowhandle )
{
WNDCLASS wc ;
NOTIFYICONDATA d ;
/* Register the frame class */
memset ( & wc , 0 , sizeof ( wc ) ) ;
wc . style = 0 ;
wc . lpfnWndProc = Sys_WindowHandler ;
wc . cbClsExtra = 0 ;
wc . cbWndExtra = 0 ;
wc . hInstance = GetModuleHandle ( NULL ) ;
wc . hIcon = 0 ;
wc . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wc . hbrBackground = NULL ;
wc . lpszMenuName = 0 ;
wc . lpszClassName = " DeadQuake " ;
RegisterClass ( & wc ) ;
hiddenwindowhandler = CreateWindow ( wc . lpszClassName , " DeadQuake " , 0 , 0 , 0 , 16 , 16 , NULL , NULL , GetModuleHandle ( NULL ) , NULL ) ;
if ( ! hiddenwindowhandler )
{
Con_Printf ( " Failed to create window \n " ) ;
return ;
}
ShowWindow ( consolewindowhandle , SW_HIDE ) ;
d . cbSize = sizeof ( NOTIFYICONDATA ) ;
d . hWnd = hiddenwindowhandler ;
d . uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE ;
d . hIcon = NULL ;
d . uCallbackMessage = WM_USER ;
d . uID = 0 ;
strcpy ( d . szTip , " " ) ;
Shell_NotifyIcon ( NIM_ADD , & d ) ;
}
else
Con_Printf ( " Your OS doesn't seem to properly support the way this was implemented \n " ) ;
}
void Sys_ServerActivity ( void )
{
HMODULE kernel32dll ;
HWND ( WINAPI * GetConsoleWindow ) ( void ) ;
HWND wnd ;
restorecode = 0 ;
GetConsoleWindow = NULL ;
kernel32dll = LoadLibrary ( " kernel32.dll " ) ;
wnd = NULL ;
if ( kernel32dll )
{
GetConsoleWindow = ( void * ) GetProcAddress ( kernel32dll , " GetConsoleWindow " ) ;
if ( GetConsoleWindow )
wnd = GetConsoleWindow ( ) ;
FreeModule ( kernel32dll ) ; //works because the underlying code uses kernel32, so this decreases the reference count rather than closing it.
}
if ( ! wnd )
{
char old [ 512 ] ;
2005-03-10 03:55:18 +00:00
# define STRINGF "About To Flash" //msvc sucks
2004-08-23 00:15:46 +00:00
GetConsoleTitle ( old , sizeof ( old ) ) ;
2005-03-10 03:55:18 +00:00
SetConsoleTitle ( STRINGF ) ;
wnd = FindWindow ( NULL , STRINGF ) ;
2004-08-23 00:15:46 +00:00
SetConsoleTitle ( old ) ;
2005-03-10 03:55:18 +00:00
# undef STRINGF
2004-08-23 00:15:46 +00:00
}
2009-04-18 23:48:35 +00:00
if ( wnd & & GetActiveWindow ( ) ! = wnd )
2004-08-23 00:15:46 +00:00
FlashWindow ( wnd , true ) ;
}
/*
= = = = = = = = = = = = =
Sys_Init
Quake calls this so the system can register variables before host_hunklevel
is marked
= = = = = = = = = = = = =
*/
void Sys_Init ( void )
{
Cvar_Register ( & sys_nostdout , " System controls " ) ;
2005-10-04 21:16:47 +00:00
Cvar_Register ( & sys_colorconsole , " System controls " ) ;
2004-08-23 00:15:46 +00:00
Cmd_AddCommand ( " hide " , Sys_HideConsole ) ;
2005-10-04 21:16:47 +00:00
hconsoleout = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
2004-08-23 00:15:46 +00:00
}
2011-04-30 17:21:10 +00:00
void Sys_Shutdown ( void )
{
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
main
= = = = = = = = = = = = = = = = = =
*/
char * newargv [ 256 ] ;
void Signal_Error_Handler ( int sig )
{
Sys_Error ( " Illegal error occured " ) ;
}
void StartQuakeServer ( void )
{
quakeparms_t parms ;
2011-05-19 13:34:07 +00:00
//static char cwd[1024]; //unused variable
2004-08-23 00:15:46 +00:00
int t ;
TL_InitLanguages ( ) ;
parms . argc = com_argc ;
parms . argv = com_argv ;
2005-04-26 16:04:12 +00:00
parms . memsize = 32 * 1024 * 1024 ;
2004-08-23 00:15:46 +00:00
if ( ( t = COM_CheckParm ( " -heapsize " ) ) ! = 0 & &
t + 1 < com_argc )
parms . memsize = Q_atoi ( com_argv [ t + 1 ] ) * 1024 ;
if ( ( t = COM_CheckParm ( " -mem " ) ) ! = 0 & &
t + 1 < com_argc )
parms . memsize = Q_atoi ( com_argv [ t + 1 ] ) * 1024 * 1024 ;
parms . membase = VirtualAlloc ( NULL , parms . memsize , MEM_RESERVE , PAGE_NOACCESS ) ;
// parms.membase = malloc (parms.memsize);
if ( ! parms . membase )
Sys_Error ( " Insufficient memory. \n " ) ;
parms . basedir = " . " ;
SV_Init ( & parms ) ;
// run one frame immediately for first heartbeat
2010-12-15 12:29:58 +00:00
SV_Frame ( ) ;
2004-08-23 00:15:46 +00:00
}
# ifdef USESERVICE
int servicecontrol ;
# endif
void ServerMainLoop ( void )
{
double newtime , time , oldtime ;
2011-06-05 23:53:33 +00:00
int delay = 1 ;
2004-08-23 00:15:46 +00:00
//
// main loop
//
oldtime = Sys_DoubleTime ( ) - 0.1 ;
while ( 1 )
{
2011-06-05 23:53:33 +00:00
NET_Sleep ( delay , false ) ;
2004-08-23 00:15:46 +00:00
// find time passed since last cycle
newtime = Sys_DoubleTime ( ) ;
time = newtime - oldtime ;
oldtime = newtime ;
2011-06-05 23:53:33 +00:00
delay = SV_Frame ( ) * 1000 ;
2004-08-23 00:15:46 +00:00
# ifdef USESERVICE
switch ( servicecontrol )
{
case SERVICE_CONTROL_PAUSE :
2010-12-15 12:29:58 +00:00
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_PAUSED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
2004-08-23 00:15:46 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
sv . paused | = 2 ;
break ;
case SERVICE_CONTROL_CONTINUE :
2010-12-15 12:29:58 +00:00
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_RUNNING ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
2004-08-23 00:15:46 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
sv . paused & = ~ 2 ;
break ;
case SERVICE_CONTROL_STOP : //leave the loop
return ;
default :
break ;
}
# endif
}
}
# ifdef USESERVICE
VOID WINAPI MyServiceCtrlHandler ( DWORD dwControl )
{
servicecontrol = dwControl ;
}
void WINAPI StartQuakeServerService ( DWORD argc , LPTSTR * argv )
{
HKEY hk ;
char path [ MAX_OSPATH ] ;
DWORD pathlen ;
DWORD type ;
asservice = true ;
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS ;
MyServiceStatus . dwCurrentState = SERVICE_START_PENDING ;
MyServiceStatus . dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
ServerServiceStatusHandle = RegisterServiceCtrlHandler (
SERVICENAME ,
MyServiceCtrlHandler ) ;
if ( ServerServiceStatusHandle = = ( SERVICE_STATUS_HANDLE ) 0 )
{
printf ( " [MY_SERVICE] RegisterServiceCtrlHandler failed %d \n " , GetLastError ( ) ) ;
return ;
2004-11-13 17:39:26 +00:00
}
2004-08-23 00:15:46 +00:00
2008-09-11 03:39:34 +00:00
RegOpenKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
2004-08-23 00:15:46 +00:00
RegQueryValueEx ( hk , " servicepath " , 0 , & type , NULL , & pathlen ) ;
if ( type = = REG_SZ & & pathlen < sizeof ( path ) )
RegQueryValueEx ( hk , " servicepath " , 0 , NULL , path , & pathlen ) ;
RegCloseKey ( hk ) ;
SetCurrentDirectory ( path ) ;
COM_InitArgv ( argc , argv ) ;
StartQuakeServer ( ) ;
2010-12-15 12:29:58 +00:00
// Handle error condition
2004-08-23 00:15:46 +00:00
if ( ! sv . state )
2010-12-15 12:29:58 +00:00
{
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
return ;
}
// Initialization complete - report running status.
MyServiceStatus . dwCurrentState = SERVICE_RUNNING ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
if ( ! SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) )
{
printf ( " [MY_SERVICE] SetServiceStatus error %ld \n " , GetLastError ( ) ) ;
}
2004-08-23 00:15:46 +00:00
ServerMainLoop ( ) ;
2010-12-15 12:29:58 +00:00
MyServiceStatus . dwCurrentState = SERVICE_STOPPED ;
MyServiceStatus . dwCheckPoint = 0 ;
MyServiceStatus . dwWaitHint = 0 ;
MyServiceStatus . dwWin32ExitCode = 0 ;
MyServiceStatus . dwServiceSpecificExitCode = 0 ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
SetServiceStatus ( ServerServiceStatusHandle , & MyServiceStatus ) ;
2004-08-23 00:15:46 +00:00
2010-12-15 12:29:58 +00:00
return ;
2004-08-23 00:15:46 +00:00
}
2010-12-15 12:29:58 +00:00
SERVICE_TABLE_ENTRY DispatchTable [ ] =
{
{ SERVICENAME , StartQuakeServerService } ,
{ NULL , NULL }
} ;
2004-08-23 00:15:46 +00:00
# endif
qboolean NET_Sleep ( int msec , qboolean stdinissocket ) ;
int main ( int argc , char * * argv )
{
# ifdef USESERVICE
2010-12-15 12:29:58 +00:00
if ( StartServiceCtrlDispatcher ( DispatchTable ) )
{
2004-08-23 00:15:46 +00:00
return true ;
}
# endif
2010-07-18 08:42:59 +00:00
# ifdef CATCHCRASH
__try
2004-08-23 00:15:46 +00:00
# endif
2010-07-18 08:42:59 +00:00
{
2011-05-19 13:34:07 +00:00
COM_InitArgv ( argc , ( const char * * ) argv ) ;
2010-07-18 08:42:59 +00:00
# ifdef USESERVICE
if ( COM_CheckParm ( " -register " ) )
{
CreateSampleService ( 1 ) ;
return true ;
}
if ( COM_CheckParm ( " -unregister " ) )
{
CreateSampleService ( 0 ) ;
return true ;
}
# endif
2004-11-13 17:39:26 +00:00
2010-07-18 08:42:59 +00:00
# ifndef _DEBUG
if ( COM_CheckParm ( " -noreset " ) )
{
signal ( SIGFPE , Signal_Error_Handler ) ;
signal ( SIGILL , Signal_Error_Handler ) ;
signal ( SIGSEGV , Signal_Error_Handler ) ;
}
# endif
StartQuakeServer ( ) ;
ServerMainLoop ( ) ;
}
# ifdef CATCHCRASH
__except ( CrashExceptionHandler ( GetExceptionCode ( ) , GetExceptionInformation ( ) ) )
2004-11-13 17:39:26 +00:00
{
2010-07-18 08:42:59 +00:00
return 1 ;
2004-11-13 17:39:26 +00:00
}
# endif
2004-08-23 00:15:46 +00:00
return true ;
}
# ifdef USESERVICE
2010-12-15 12:29:58 +00:00
void CreateSampleService ( qboolean create )
{
2004-08-23 00:15:46 +00:00
BOOL deleted ;
char path [ MAX_OSPATH ] ;
char exe [ MAX_OSPATH ] ;
SC_HANDLE schService ;
SC_HANDLE schSCManager ;
2010-12-15 12:29:58 +00:00
// Open a handle to the SC Manager database.
schSCManager = OpenSCManager (
NULL , // local machine
NULL , // ServicesActive database
SC_MANAGER_ALL_ACCESS ) ; // full access rights
if ( NULL = = schSCManager )
2004-08-23 00:15:46 +00:00
{
Con_Printf ( " Failed to open SCManager (%d) \n " , GetLastError ( ) ) ;
return ;
}
if ( ! GetModuleFileName ( NULL , exe + 1 , sizeof ( exe ) - 2 ) )
{
Con_Printf ( " Path too long \n " ) ;
return ;
}
GetCurrentDirectory ( sizeof ( path ) , path ) ;
exe [ 0 ] = ' \" ' ;
exe [ strlen ( path ) + 1 ] = ' \0 ' ;
exe [ strlen ( path ) ] = ' \" ' ;
if ( ! create )
{
schService = OpenServiceA ( schSCManager , SERVICENAME , SERVICE_ALL_ACCESS ) ;
if ( schService )
{
deleted = DeleteService ( schService ) ;
}
}
else
{
HKEY hk ;
2008-09-11 03:39:34 +00:00
RegOpenKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
if ( ! hk ) RegCreateKey ( HKEY_LOCAL_MACHINE , " Software \\ " DISTRIBUTIONLONG " \\ " FULLENGINENAME , & hk ) ;
2004-08-23 00:15:46 +00:00
RegSetValueEx ( hk , " servicepath " , 0 , REG_SZ , path , strlen ( path ) ) ;
RegCloseKey ( hk ) ;
2010-12-15 12:29:58 +00:00
schService = CreateService (
schSCManager , // SCManager database
SERVICENAME , // name of service
FULLENGINENAME " Server " , // service name to display
SERVICE_ALL_ACCESS , // desired access
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS , // service type
SERVICE_AUTO_START , // start type
SERVICE_ERROR_NORMAL , // error control type
exe , // service's binary
NULL , // no load ordering group
NULL , // no tag identifier
NULL , // no dependencies
NULL , // LocalSystem account
NULL ) ; // no password
2004-08-23 00:15:46 +00:00
}
2010-12-15 12:29:58 +00:00
if ( schService = = NULL )
2004-08-23 00:15:46 +00:00
{
2010-12-15 12:29:58 +00:00
Con_Printf ( " CreateService failed. \n " ) ;
2004-08-23 00:15:46 +00:00
return ;
}
else
{
2010-12-15 12:29:58 +00:00
CloseServiceHandle ( schService ) ;
2004-08-23 00:15:46 +00:00
return ;
}
}
2004-09-04 17:59:22 +00:00
# endif
2007-12-30 00:09:34 +00:00
# ifdef MULTITHREAD
/* Thread creation calls */
typedef struct threadwrap_s
{
void ( * func ) ( void * ) ;
void * args ;
} threadwrap_t ;
// the thread call is wrapped so we don't need WINAPI everywhere
DWORD WINAPI threadwrapper ( void * args )
{
threadwrap_t tw ;
tw . func = ( ( threadwrap_t * ) args ) - > func ;
tw . args = ( ( threadwrap_t * ) args ) - > args ;
free ( args ) ;
2010-12-15 12:29:58 +00:00
tw . func ( tw . args ) ;
2007-12-30 00:09:34 +00:00
2007-12-30 20:05:49 +00:00
# ifndef WIN32CRTDLL
_endthreadex ( 0 ) ;
# endif
2007-12-30 00:09:34 +00:00
return 0 ;
}
2011-07-03 16:24:53 +00:00
void * Sys_CreateThread ( int ( * func ) ( void * ) , void * args , int priority , int stacksize )
2007-12-30 00:09:34 +00:00
{
threadwrap_t * tw = ( threadwrap_t * ) malloc ( sizeof ( threadwrap_t ) ) ;
2007-12-30 20:05:49 +00:00
HANDLE handle ;
2010-12-15 12:29:58 +00:00
2007-12-30 20:05:49 +00:00
if ( ! tw )
return NULL ;
2007-12-30 00:09:34 +00:00
stacksize + = 128 ; // wrapper overhead, also prevent default stack size
tw - > func = func ;
tw - > args = args ;
2007-12-30 20:05:49 +00:00
# ifdef WIN32CRTDLL
handle = ( HANDLE ) CreateThread ( NULL , stacksize , & threadwrapper , ( void * ) tw , 0 , NULL ) ;
# else
handle = ( HANDLE ) _beginthreadex ( NULL , stacksize , & threadwrapper , ( void * ) tw , 0 , NULL ) ;
# endif
if ( ! handle )
2007-12-30 00:09:34 +00:00
{
free ( tw ) ;
2007-12-30 20:05:49 +00:00
return NULL ;
2007-12-30 00:09:34 +00:00
}
2007-12-30 20:05:49 +00:00
return ( void * ) handle ;
}
void Sys_WaitOnThread ( void * thread )
2010-12-15 12:29:58 +00:00
{
2007-12-30 20:05:49 +00:00
WaitForSingleObject ( ( HANDLE ) thread , INFINITE ) ;
CloseHandle ( ( HANDLE ) thread ) ;
2007-12-30 00:09:34 +00:00
}
/* Mutex calls */
2008-06-01 05:42:23 +00:00
void * Sys_CreateMutex ( void )
2007-12-30 00:09:34 +00:00
{
return ( void * ) CreateMutex ( NULL , 0 , NULL ) ;
}
qboolean Sys_TryLockMutex ( void * mutex )
{
return WaitForSingleObject ( mutex , 0 ) = = WAIT_OBJECT_0 ;
}
qboolean Sys_LockMutex ( void * mutex )
{
return WaitForSingleObject ( mutex , INFINITE ) = = WAIT_OBJECT_0 ;
}
qboolean Sys_UnlockMutex ( void * mutex )
{
return ! ! ReleaseMutex ( mutex ) ;
}
void Sys_DestroyMutex ( void * mutex )
{
CloseHandle ( mutex ) ;
}
2008-06-01 05:42:23 +00:00
/* Conditional wait calls */
/*
TODO : Windows Vista has condition variables as documented here :
http : //msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
Note this uses Slim Reader / Writer locks ( Vista + exclusive )
or critical sections .
The condition variable implementation is based on the libSDL implementation .
This code could probably be made more efficient with the use of events or
different mechanisms but for now the main concern is a correct and
complete solution .
*/
typedef struct condvar_s
{
int waiting ;
int signals ;
CRITICAL_SECTION countlock ;
CRITICAL_SECTION mainlock ;
HANDLE wait_sem ;
HANDLE wait_done ;
} condvar_t ;
2010-12-15 12:29:58 +00:00
void * Sys_CreateConditional ( void )
{
2008-06-01 05:42:23 +00:00
condvar_t * cv ;
cv = ( condvar_t * ) malloc ( sizeof ( condvar_t ) ) ;
if ( ! cv )
return NULL ;
cv - > waiting = 0 ;
cv - > signals = 0 ;
InitializeCriticalSection ( & cv - > mainlock ) ;
InitializeCriticalSection ( & cv - > countlock ) ;
cv - > wait_sem = CreateSemaphore ( NULL , 0 , 0x7fffffff , NULL ) ;
cv - > wait_done = CreateSemaphore ( NULL , 0 , 0x7fffffff , NULL ) ;
if ( cv - > wait_sem & & cv - > wait_done )
return ( void * ) cv ;
// something failed so deallocate everything
if ( cv - > wait_done )
CloseHandle ( cv - > wait_done ) ;
if ( cv - > wait_sem )
CloseHandle ( cv - > wait_sem ) ;
DeleteCriticalSection ( & cv - > countlock ) ;
DeleteCriticalSection ( & cv - > mainlock ) ;
free ( cv ) ;
return NULL ;
}
2010-12-15 12:29:58 +00:00
qboolean Sys_LockConditional ( void * condv )
{
2008-06-01 05:42:23 +00:00
EnterCriticalSection ( & ( ( condvar_t * ) condv ) - > mainlock ) ;
2010-12-15 12:29:58 +00:00
return true ;
2008-06-01 05:42:23 +00:00
}
2010-12-15 12:29:58 +00:00
qboolean Sys_UnlockConditional ( void * condv )
{
2008-06-01 05:42:23 +00:00
LeaveCriticalSection ( & ( ( condvar_t * ) condv ) - > mainlock ) ;
2010-12-15 12:29:58 +00:00
return true ;
2008-06-01 05:42:23 +00:00
}
qboolean Sys_ConditionWait ( void * condv )
{
condvar_t * cv = ( condvar_t * ) condv ;
qboolean success ;
// increase count for non-signaled waiting threads
EnterCriticalSection ( & cv - > countlock ) ;
cv - > waiting + + ;
LeaveCriticalSection ( & cv - > countlock ) ;
LeaveCriticalSection ( & cv - > mainlock ) ; // unlock as per condition variable definition
// wait on a signal
success = ( WaitForSingleObject ( cv - > wait_sem , INFINITE ) ! = WAIT_FAILED ) ;
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection ( & cv - > countlock ) ;
2010-12-15 12:29:58 +00:00
if ( cv - > signals > 0 )
2008-06-01 05:42:23 +00:00
{
ReleaseSemaphore ( cv - > wait_done , cv - > signals , NULL ) ;
cv - > signals = 0 ;
}
cv - > waiting - - ;
LeaveCriticalSection ( & cv - > countlock ) ;
EnterCriticalSection ( & cv - > mainlock ) ; // lock as per condition variable definition
return success ;
}
2010-12-15 12:29:58 +00:00
qboolean Sys_ConditionSignal ( void * condv )
2008-06-01 05:42:23 +00:00
{
condvar_t * cv = ( condvar_t * ) condv ;
// if there are non-signaled waiting threads, we signal one and wait on the response
EnterCriticalSection ( & cv - > countlock ) ;
if ( cv - > waiting > cv - > signals )
{
cv - > signals + + ;
ReleaseSemaphore ( cv - > wait_sem , 1 , NULL ) ;
LeaveCriticalSection ( & cv - > countlock ) ;
WaitForSingleObject ( cv - > wait_done , INFINITE ) ;
}
else
LeaveCriticalSection ( & cv - > countlock ) ;
return true ;
}
2010-12-15 12:29:58 +00:00
qboolean Sys_ConditionBroadcast ( void * condv )
2008-06-01 05:42:23 +00:00
{
condvar_t * cv = ( condvar_t * ) condv ;
// if there are non-signaled waiting threads, we signal all of them and wait on all the responses back
EnterCriticalSection ( & cv - > countlock ) ;
2010-12-15 12:29:58 +00:00
if ( cv - > waiting > cv - > signals )
2008-06-01 05:42:23 +00:00
{
int i , num_waiting ;
num_waiting = ( cv - > waiting - cv - > signals ) ;
cv - > signals = cv - > waiting ;
2010-12-15 12:29:58 +00:00
2008-06-01 05:42:23 +00:00
ReleaseSemaphore ( cv - > wait_sem , num_waiting , NULL ) ;
LeaveCriticalSection ( & cv - > countlock ) ;
// there's no call to wait for the same object multiple times so we need to loop through
// and burn up the semaphore count
2010-12-15 12:29:58 +00:00
for ( i = 0 ; i < num_waiting ; i + + )
2008-06-01 05:42:23 +00:00
WaitForSingleObject ( cv - > wait_done , INFINITE ) ;
}
else
LeaveCriticalSection ( & cv - > countlock ) ;
return true ;
}
void Sys_DestroyConditional ( void * condv )
{
condvar_t * cv = ( condvar_t * ) condv ;
CloseHandle ( cv - > wait_done ) ;
CloseHandle ( cv - > wait_sem ) ;
DeleteCriticalSection ( & cv - > countlock ) ;
DeleteCriticalSection ( & cv - > mainlock ) ;
free ( cv ) ;
}
2011-07-06 01:01:13 +00:00
# endif
2011-07-03 16:24:53 +00:00
2011-07-06 01:01:13 +00:00
void Sys_Sleep ( double seconds )
2011-07-03 16:24:53 +00:00
{
2011-07-06 01:01:13 +00:00
Sleep ( seconds * 1000 ) ;
2011-07-03 16:24:53 +00:00
}
2007-12-30 00:09:34 +00:00
# endif