This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/launch/system.c

1449 lines
39 KiB
C
Raw Normal View History

2010-07-02 22:00:00 +02:00
2007-11-10 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2007 <20>
// utils.c - shared launcher utils
//=======================================================================
#include "launch.h"
2010-03-27 22:00:00 +01:00
#include "library.h"
2008-11-09 22:00:00 +01:00
#include "engine_api.h"
2007-11-27 22:00:00 +01:00
#include "mathlib.h"
2007-11-10 22:00:00 +01:00
2008-07-06 22:00:00 +02:00
#define MAX_QUED_EVENTS 256
#define MASK_QUED_EVENTS (MAX_QUED_EVENTS - 1)
2010-07-26 22:00:00 +02:00
#define LOG_BUFSIZE 131072 // 128 kb
2008-07-06 22:00:00 +02:00
2007-11-11 22:00:00 +01:00
system_t Sys;
2007-11-30 22:00:00 +01:00
stdlib_api_t com;
2007-11-11 22:00:00 +01:00
launch_exp_t *Host; // callback to mainframe
2008-07-06 22:00:00 +02:00
sys_event_t event_que[MAX_QUED_EVENTS];
int event_head, event_tail;
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
dll_info_t xtools_dll = { "xtools.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof( launch_exp_t ), sizeof( stdlib_api_t ) };
dll_info_t engine_dll = { "engine.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof( launch_exp_t ), sizeof( stdlib_api_t ) };
2007-11-10 22:00:00 +01:00
2008-11-03 22:00:00 +01:00
static const char *show_credits = "\n\n\n\n\tCopyright XashXT Group %s <20>\n\t\
2007-11-11 22:00:00 +01:00
All Rights Reserved\n\n\t Visit www.xash.ru\n";
2007-11-18 22:00:00 +01:00
// stubs
2008-07-30 22:00:00 +02:00
void NullInit( int argc, char **argv ) {}
2007-11-18 22:00:00 +01:00
void NullFunc( void ) {}
2008-08-04 22:00:00 +02:00
void NullPrint( const char *msg ) {}
2007-11-18 22:00:00 +01:00
2007-11-11 22:00:00 +01:00
void Sys_GetStdAPI( void )
{
// interface validator
2009-09-10 22:00:00 +02:00
com.api_size = sizeof( stdlib_api_t );
com.com_size = sizeof( stdlib_api_t );
2007-11-11 22:00:00 +01:00
// base events
2008-08-04 22:00:00 +02:00
com.instance = Sys_NewInstance;
2007-11-30 22:00:00 +01:00
com.printf = Sys_Msg;
com.dprintf = Sys_MsgDev;
com.error = Sys_Error;
com.abort = Sys_Break;
com.exit = Sys_Exit;
com.print = Sys_Print;
com.sleep = Sys_Sleep;
com.clipboard = Sys_GetClipboardData;
2008-07-11 22:00:00 +02:00
com.queevent = Sys_QueEvent; // add event to queue
2008-07-06 22:00:00 +02:00
com.getevent = Sys_GetEvent; // get system events
2007-11-11 22:00:00 +01:00
// crclib.c funcs
2007-11-30 22:00:00 +01:00
com.crc_init = CRC_Init;
com.crc_block = CRC_Block;
com.crc_process = CRC_ProcessByte;
com.crc_sequence = CRC_BlockSequence;
com.crc_blockchecksum = Com_BlockChecksum;
com.crc_blockchecksumkey = Com_BlockChecksumKey;
2009-11-23 22:00:00 +01:00
com.crc32_init = CRC32_Init;
com.crc32_block = CRC32_ProcessBuffer;
com.crc32_process = CRC32_ProcessByte;
com.crc32_final = CRC32_Final;
2007-11-11 22:00:00 +01:00
// memlib.c
2008-10-27 22:00:00 +01:00
com.memcpy = _crt_mem_copy; // first time using
com.memset = _crt_mem_set; // first time using
2007-11-30 22:00:00 +01:00
com.realloc = _mem_realloc;
com.move = _mem_move;
com.malloc = _mem_alloc;
com.free = _mem_free;
2009-09-24 22:00:00 +02:00
com.is_allocated = _is_allocated;
2007-11-30 22:00:00 +01:00
com.mallocpool = _mem_allocpool;
com.freepool = _mem_freepool;
com.clearpool = _mem_emptypool;
com.memcheck = _mem_check;
2007-11-11 22:00:00 +01:00
2008-07-06 22:00:00 +02:00
// network.c funcs
com.NET_Init = NET_Init;
com.NET_Shutdown = NET_Shutdown;
2009-06-24 22:00:00 +02:00
com.NET_Sleep = NET_Sleep;
2008-07-06 22:00:00 +02:00
com.NET_Config = NET_Config;
com.NET_AdrToString = NET_AdrToString;
com.NET_StringToAdr = NET_StringToAdr;
com.NET_SendPacket = NET_SendPacket;
2009-06-22 22:00:00 +02:00
com.NET_IsLocalAddress = NET_IsLocalAddress;
com.NET_BaseAdrToString = NET_BaseAdrToString;
com.NET_StringToAdr = NET_StringToAdr;
com.NET_CompareAdr = NET_CompareAdr;
com.NET_CompareBaseAdr = NET_CompareBaseAdr;
com.NET_GetPacket = NET_GetPacket;
com.NET_SendPacket = NET_SendPacket;
2008-07-06 22:00:00 +02:00
2007-11-11 22:00:00 +01:00
// common functions
2007-11-30 22:00:00 +01:00
com.Com_InitRootDir = FS_InitRootDir; // init custom rootdir
com.Com_LoadGameInfo = FS_LoadGameInfo; // gate game info from script file
com.Com_AddGameHierarchy = FS_AddGameHierarchy; // add base directory in search list
2009-01-21 22:00:00 +01:00
com.Com_AllowDirectPaths = FS_AllowDirectPaths; // allow direct paths e.g. C:\windows
2007-11-30 22:00:00 +01:00
com.Com_CheckParm = FS_CheckParm; // get parm from cmdline
com.Com_GetParm = FS_GetParmFromCmdLine; // get filename without path & ext
com.Com_FileBase = FS_FileBase; // get filename without path & ext
com.Com_FileExists = FS_FileExists; // return true if file exist
com.Com_FileSize = FS_FileSize; // same as Com_FileExists but return filesize
2008-06-07 22:00:00 +02:00
com.Com_FileTime = FS_FileTime; // same as Com_FileExists but return filetime
2007-11-30 22:00:00 +01:00
com.Com_FileExtension = FS_FileExtension; // return extension of file
com.Com_RemovePath = FS_FileWithoutPath; // return file without path
2010-09-30 22:00:00 +02:00
com.Com_DiskPath = FS_GetDiskPath; // build fullpath for disk files
2007-11-30 22:00:00 +01:00
com.Com_StripExtension = FS_StripExtension; // remove extension if present
com.Com_StripFilePath = FS_ExtractFilePath; // get file path without filename.ext
com.Com_DefaultExtension = FS_DefaultExtension; // append extension if not present
com.Com_ClearSearchPath = FS_ClearSearchPath; // delete all search pathes
com.Com_CreateThread = Sys_RunThreadsOnIndividual;// run individual thread
com.Com_ThreadLock = Sys_ThreadLock; // lock current thread
com.Com_ThreadUnlock = Sys_ThreadUnlock; // unlock numthreads
com.Com_NumThreads = Sys_GetNumThreads; // returns count of active threads
2008-11-01 22:00:00 +01:00
2010-03-27 22:00:00 +01:00
com.LoadLibrary = Com_LoadLibrary;
com.GetProcAddress = Com_GetProcAddress;
com.NameForFunction = Com_NameForFunction;
com.FunctionFromName = Com_FunctionFromName;
com.FreeLibrary = Com_FreeLibrary;
2008-11-01 22:00:00 +01:00
com.Com_OpenScript = PS_LoadScript; // loading script into buffer
com.Com_CloseScript = PS_FreeScript; // release current script
com.Com_ResetScript = PS_ResetScript; // jump to start of scriptfile
com.Com_EndOfScript = PS_EndOfScript; // returns true if end of script reached
com.Com_SkipBracedSection = PS_SkipBracedSection; // skip braced section with specified depth
com.Com_SkipRestOfLine = PS_SkipRestOfLine; // skip all tokene the rest of line
com.Com_ReadToken = PS_ReadToken; // generic reading
com.Com_SaveToken = PS_SaveToken; // save current token to get it again
// script machine simple user interface
com.Com_ReadString = PS_GetString; // string
com.Com_ReadFloat = PS_GetFloat; // float value
com.Com_ReadDword = PS_GetUnsigned; // unsigned integer
com.Com_ReadLong = PS_GetInteger; // signed integer
2007-12-17 22:00:00 +01:00
com.Com_Search = FS_Search; // returned list of founded files
2008-11-18 22:00:00 +01:00
com.Com_HashKey = Com_HashKey; // returns hash key for a string (generic fucntion)
2007-11-11 22:00:00 +01:00
2007-11-25 22:00:00 +01:00
// console variables
2007-11-30 22:00:00 +01:00
com.Cvar_Get = Cvar_Get;
com.Cvar_FullSet = Cvar_FullSet;
com.Cvar_SetLatched = Cvar_SetLatched;
com.Cvar_SetValue = Cvar_SetValue;
com.Cvar_SetString = Cvar_Set;
2009-09-10 22:00:00 +02:00
com.Cvar_GetInteger = Cvar_VariableInteger;
2007-11-30 22:00:00 +01:00
com.Cvar_GetValue = Cvar_VariableValue;
com.Cvar_GetString = Cvar_VariableString;
com.Cvar_LookupVars = Cvar_LookupVars;
com.Cvar_FindVar = Cvar_FindVar;
2010-08-15 22:00:00 +02:00
com.Cvar_DirectSet = Cvar_DirectSet;
2010-10-22 22:00:00 +02:00
com.Cvar_Register = Cvar_RegisterVariable;
2007-11-25 22:00:00 +01:00
// console commands
2007-11-30 22:00:00 +01:00
com.Cmd_Exec = Cbuf_ExecuteText; // process cmd buffer
com.Cmd_Argc = Cmd_Argc;
com.Cmd_Args = Cmd_Args;
com.Cmd_Argv = Cmd_Argv;
com.Cmd_LookupCmds = Cmd_LookupCmds;
com.Cmd_AddCommand = Cmd_AddCommand;
2010-10-23 22:00:00 +02:00
com.Cmd_AddGameCommand = Cmd_AddGameCommand;
2007-11-30 22:00:00 +01:00
com.Cmd_DelCommand = Cmd_RemoveCommand;
com.Cmd_TokenizeString = Cmd_TokenizeString;
2007-11-27 22:00:00 +01:00
2007-11-11 22:00:00 +01:00
// real filesystem
2007-11-30 22:00:00 +01:00
com.fopen = FS_Open; // same as fopen
com.fclose = FS_Close; // same as fclose
com.fwrite = FS_Write; // same as fwrite
com.fread = FS_Read; // same as fread, can see trough pakfile
com.fprint = FS_Print; // printed message into file
com.fprintf = FS_Printf; // same as fprintf
2008-12-15 22:00:00 +01:00
com.fgetc = FS_Getc; // same as fgetc
2007-11-30 22:00:00 +01:00
com.fgets = FS_Gets; // like a fgets, but can return EOF
com.fseek = FS_Seek; // fseek, can seek in packfiles too
com.ftell = FS_Tell; // like a ftell
2009-07-12 22:00:00 +02:00
com.feof = FS_Eof; // like a feof
2010-03-27 22:00:00 +01:00
com.fremove = FS_Delete; // like remove
com.frename = FS_Rename; // like rename
2007-11-11 22:00:00 +01:00
// virtual filesystem
2007-11-30 22:00:00 +01:00
com.vfcreate = VFS_Create; // create virtual stream
com.vfopen = VFS_Open; // virtual fopen
com.vfclose = VFS_Close; // free buffer or write dump
com.vfwrite = VFS_Write; // write into buffer
com.vfread = VFS_Read; // read from buffer
com.vfgets = VFS_Gets; // read text line
com.vfprint = VFS_Print; // write message
com.vfprintf = VFS_Printf; // write formatted message
com.vfseek = VFS_Seek; // fseek, can seek in packfiles too
2008-08-15 22:00:00 +02:00
com.vfbuffer = VFS_GetBuffer; // get pointer at start vfile buffer
2007-11-30 22:00:00 +01:00
com.vftell = VFS_Tell; // like a ftell
2008-01-05 22:00:00 +01:00
com.vfeof = VFS_Eof; // like a feof
2007-11-11 22:00:00 +01:00
2008-08-14 22:00:00 +02:00
// wadstorag filesystem
2008-08-15 22:00:00 +02:00
com.wfcheck = W_Check; // validate container
2008-08-14 22:00:00 +02:00
com.wfopen = W_Open; // open wad file or create new
com.wfclose = W_Close; // close wadfile
com.wfwrite = W_SaveLump; // dump lump into disk
com.wfread = W_LoadLump; // load lump into memory
2007-11-11 22:00:00 +01:00
// filesystem simply user interface
2007-11-30 22:00:00 +01:00
com.Com_LoadFile = FS_LoadFile; // load file into heap
com.Com_WriteFile = FS_WriteFile; // write file into disk
com.Com_LoadLibrary = Sys_LoadLibrary; // load library
com.Com_FreeLibrary = Sys_FreeLibrary; // free library
com.Com_GetProcAddress = Sys_GetProcAddress; // gpa
2009-09-10 22:00:00 +02:00
com.Com_ShellExecute = Sys_ShellExecute; // shell execute
2007-11-30 22:00:00 +01:00
com.Com_DoubleTime = Sys_DoubleTime; // hi-res timer
2007-11-11 22:00:00 +01:00
2008-08-06 22:00:00 +02:00
// built-in imagelib functions
2008-10-19 22:00:00 +02:00
com.ImageLoad = FS_LoadImage; // load image from disk or wad-file
com.ImageSave = FS_SaveImage; // save image into specified format
com.ImageFree = FS_FreeImage; // release image buffer
com.ImglibSetup = Image_Setup; // set imagelib global features
2008-10-22 22:00:00 +02:00
com.ImagePFDesc = Image_GetPixelFormat; // get some info about current fmt
2008-10-19 22:00:00 +02:00
com.ImageConvert = Image_Process; // flip, rotate, resample etc
2008-08-06 22:00:00 +02:00
2010-04-20 22:00:00 +02:00
// built-in soundlib functions
com.SoundLoad = FS_LoadSound; // load sound from disk or wad-file
com.SoundSave = FS_SaveSound; // save sound into specified format
com.SoundFree = FS_FreeSound; // release sound buffer
com.SndlibSetup = Sound_Setup; // set soundlib global features
com.SoundConvert = Sound_Process; // resample, change resolution etc
2010-04-27 22:00:00 +02:00
com.OpenStream = FS_OpenStream; // open music stream
com.GetStreamInfo = FS_StreamInfo; // get basic stream info
com.ReadStream = FS_ReadStream; // returns num of readed bytes
com.FreeStream = FS_FreeStream; // release stream
2008-06-14 22:00:00 +02:00
com.Com_RandomLong = Com_RandomLong;
com.Com_RandomFloat = Com_RandomFloat;
2008-10-27 22:00:00 +01:00
// changed after called Sys_InitCPU
com.sincos = SinCos; // fast sincos
com.atan2 = atan2f; // fast arctan
com.acos = acosf; // fast arccos
com.asin = asinf; // fast arcsin
com.sqrt = sqrtf; // fast sqrt
com.sin = sinf; // fast sine
com.cos = cosf; // fast cosine
com.tan = tanf; // fast tan
2007-11-11 22:00:00 +01:00
// stdlib.c funcs
2007-11-30 22:00:00 +01:00
com.strnupr = com_strnupr;
com.strnlwr = com_strnlwr;
com.strupr = com_strupr;
com.strlwr = com_strlwr;
com.strlen = com_strlen;
com.cstrlen = com_cstrlen;
com.toupper = com_toupper;
com.tolower = com_tolower;
com.strncat = com_strncat;
com.strcat = com_strcat;
com.strncpy = com_strncpy;
com.strcpy = com_strcpy;
com.stralloc = com_stralloc;
2009-07-12 22:00:00 +02:00
com.is_digit = com_isdigit;
2007-11-30 22:00:00 +01:00
com.atoi = com_atoi;
com.atof = com_atof;
com.atov = com_atov;
com.strchr = com_strchr;
com.strrchr = com_strrchr;
com.strnicmp = com_strnicmp;
com.stricmp = com_stricmp;
com.strncmp = com_strncmp;
com.strcmp = com_strcmp;
com.stristr = com_stristr;
2008-07-31 22:00:00 +02:00
com.strstr = com_strstr;
2007-11-30 22:00:00 +01:00
com.vsprintf = com_vsprintf;
com.sprintf = com_sprintf;
2010-09-10 22:00:00 +02:00
com.stricmpext = com_stricmpext;
2007-11-30 22:00:00 +01:00
com.va = va;
com.vsnprintf = com_vsnprintf;
com.snprintf = com_snprintf;
2008-11-01 22:00:00 +01:00
com.pretifymem = com_pretifymem;
2007-11-30 22:00:00 +01:00
com.timestamp = com_timestamp;
2008-08-15 22:00:00 +02:00
// stringtable.c system
com.st_create = StringTable_CreateNewSystem;
com.st_getstring = StringTable_GetString;
com.st_setstring = StringTable_SetString;
com.st_load = StringTable_LoadSystem;
2009-01-04 22:00:00 +01:00
com.st_getname = StringTable_GetName;
2008-08-15 22:00:00 +02:00
com.st_save = StringTable_SaveSystem;
2009-01-02 22:00:00 +01:00
com.st_clear = StringTable_ClearSystem;
2008-08-15 22:00:00 +02:00
com.st_remove = StringTable_DeleteSystem;
2009-09-10 22:00:00 +02:00
com.SysInfo = &SI;
2007-11-11 22:00:00 +01:00
}
2007-11-10 22:00:00 +01:00
/*
==================
Parse program name to launch and determine work style
2008-07-31 22:00:00 +02:00
NOTE: at this day we have ten instances
2007-11-10 22:00:00 +01:00
2008-12-04 22:00:00 +01:00
0. "offline" - invalid instance
1. "credits" - show engine credits
2. "dedicated" - dedicated server
3. "normal" - normal or dedicated game launch
4. "bsplib" - four BSP compilers in one
2009-11-30 22:00:00 +01:00
5. "sprite" - sprite creator (requires qc. script)
6. "studio" - Half-Life style models creator (requires qc. script)
2010-02-18 22:00:00 +01:00
7. "wadlib" - wad-file maker
2009-11-30 22:00:00 +01:00
8. "ripper" - resource EXTRActor GENeric
9. "ximage" - ImageLib Processng
2007-11-10 22:00:00 +01:00
==================
*/
void Sys_LookupInstance( void )
{
2008-07-31 22:00:00 +02:00
char szTemp[4096];
2008-08-06 22:00:00 +02:00
bool dedicated = false;
2008-07-31 22:00:00 +02:00
2010-07-23 22:00:00 +02:00
// NOTE: we want set "real" work directory
// defined in environment variables, but in some reasons
// we need make some additional checks before set current dir
GetCurrentDirectory( MAX_SYSPATH, sys_rootdir );
2007-11-11 22:00:00 +01:00
Sys.app_name = HOST_OFFLINE;
2008-08-04 22:00:00 +02:00
// we can specified custom name, from Sys_NewInstance
2010-07-29 22:00:00 +02:00
if( GetModuleFileName( NULL, szTemp, MAX_SYSPATH ) && Sys.app_state != SYS_RESTART )
2008-07-31 22:00:00 +02:00
FS_FileBase( szTemp, Sys.ModuleName );
// determine host type
2008-08-04 22:00:00 +02:00
if( Sys.ModuleName[0] == '#' || Sys.ModuleName[0] == '<EFBFBD>' )
2007-11-10 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
if( Sys.ModuleName[0] == '#' ) dedicated = true;
2010-09-10 22:00:00 +02:00
if( Sys.ModuleName[0] == '<EFBFBD>' ) com.strcpy( Sys.progname, "credits" );
2010-07-29 22:00:00 +02:00
2008-08-04 22:00:00 +02:00
// cutoff hidden symbols
2010-07-29 22:00:00 +02:00
com.strncpy( szTemp, Sys.ModuleName + 1, MAX_SYSPATH );
com.strncpy( Sys.ModuleName, szTemp, MAX_SYSPATH );
}
if( Sys.progname[0] == '$' )
{
// custom path came from executable, otherwise can't be modified
com.strncpy( Sys.ModuleName, Sys.progname + 1, MAX_SYSPATH );
com.strncpy( Sys.progname, "normal", MAX_SYSPATH ); // set as "normal"
2007-11-10 22:00:00 +01:00
}
2008-07-31 22:00:00 +02:00
// lookup all instances
2010-07-29 22:00:00 +02:00
if( !com.strcmp( Sys.progname, "credits" ))
2008-01-01 22:00:00 +01:00
{
2008-11-06 22:00:00 +01:00
Sys.app_name = HOST_CREDITS; // easter egg
Sys.linked_dll = NULL; // no need to loading library
Sys.log_active = Sys.developer = 0; // clear all dbg states
2010-09-10 22:00:00 +02:00
com.strcpy( Sys.caption, "About" );
2008-01-05 22:00:00 +01:00
Sys.con_showcredits = true;
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "normal" ))
2008-08-06 22:00:00 +02:00
{
if( dedicated )
{
Sys.app_name = HOST_DEDICATED;
Sys.con_readonly = false;
2010-02-18 22:00:00 +01:00
// check for duplicate dedicated server
Sys.hMutex = CreateMutex( NULL, 0, "Xash Dedicated Server" );
if( !Sys.hMutex )
{
MSGBOX( "Dedicated server already running" );
Sys_Exit();
return;
}
CloseHandle( Sys.hMutex );
Sys.hMutex = CreateSemaphore( NULL, 0, 1, "Xash Dedicated Server" );
2010-07-22 22:00:00 +02:00
if( !Sys.developer ) Sys.developer = 3; // otherwise we see empty console
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "engine.log", com.timestamp( TIME_FILENAME )); // logs folder
2008-08-06 22:00:00 +02:00
}
else
{
Sys.app_name = HOST_NORMAL;
Sys.con_readonly = true;
// don't show console as default
2008-11-06 22:00:00 +01:00
if( Sys.developer < D_WARN )
Sys.con_showalways = false;
2010-07-24 22:00:00 +02:00
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "engine.log", com.timestamp( TIME_FILENAME )); // logs folder
2008-08-06 22:00:00 +02:00
}
2010-07-24 22:00:00 +02:00
2008-08-06 22:00:00 +02:00
Sys.linked_dll = &engine_dll; // pointer to engine.dll info
2010-09-10 22:00:00 +02:00
com.strcpy( Sys.caption, va( "Xash3D ver.%g", XASH_VERSION ));
2008-08-06 22:00:00 +02:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "bsplib" ))
2007-11-10 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
Sys.app_name = HOST_BSPLIB;
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to common.dll info
2010-09-10 22:00:00 +02:00
com.strcpy( Sys.log_path, "bsplib.log" ); // xash3d root directory
com.strcpy( Sys.caption, "Xash3D BSP Compiler");
2007-11-10 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "sprite" ))
2007-11-10 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
Sys.app_name = HOST_SPRITE;
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to common.dll info
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "%s/spritegen.log", sys_rootdir ); // same as .exe file
com.strcpy( Sys.caption, "Xash3D Sprite Compiler");
2007-11-10 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "studio" ))
2007-11-10 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
Sys.app_name = HOST_STUDIO;
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to common.dll info
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "%s/studiomdl.log", sys_rootdir ); // same as .exe file
com.strcpy( Sys.caption, "Xash3D Studio Models Compiler" );
2007-11-10 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "wadlib" ))
2007-11-27 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
Sys.app_name = HOST_WADLIB;
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to common.dll info
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "%s/wadlib.log", sys_rootdir ); // same as .exe file
com.strcpy( Sys.caption, "Xash3D Wad2\\Wad3 maker" );
2007-11-27 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "ripper" ))
2008-01-05 22:00:00 +01:00
{
2008-08-06 22:00:00 +02:00
Sys.app_name = HOST_RIPPER;
2008-01-05 22:00:00 +01:00
Sys.con_readonly = true;
2008-08-06 22:00:00 +02:00
Sys.log_active = true; // always create log
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to wdclib.dll info
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "%s/decompile.log", sys_rootdir ); // default
com.strcpy( Sys.caption, va("Quake Recource Extractor ver.%g", XASH_VERSION ));
2008-01-05 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
else if( !com.strcmp( Sys.progname, "ximage" ))
2008-01-05 22:00:00 +01:00
{
2009-09-04 22:00:00 +02:00
Sys.app_name = HOST_XIMAGE;
2008-01-05 22:00:00 +01:00
Sys.con_readonly = true;
2009-01-11 22:00:00 +01:00
Sys.linked_dll = &xtools_dll; // pointer to dpvenc.dll info
2010-09-10 22:00:00 +02:00
com.sprintf( Sys.log_path, "%s/image.log", sys_rootdir ); // logs folder
com.strcpy( Sys.caption, "Image Processing Tool" );
2007-11-11 22:00:00 +01:00
}
2010-07-29 22:00:00 +02:00
2008-07-30 22:00:00 +02:00
// share instance over all system
2009-09-10 22:00:00 +02:00
SI.instance = Sys.app_name;
2007-11-11 22:00:00 +01:00
}
/*
==================
Find needed library, setup and run it
==================
*/
void Sys_CreateInstance( void )
{
// export
2010-07-21 22:00:00 +02:00
launch_t CreateHost;
2008-07-24 22:00:00 +02:00
2009-10-02 22:00:00 +02:00
srand( time( NULL )); // init random generator
Sys_LoadLibrary( NULL, Sys.linked_dll ); // loading library if need
2007-11-11 22:00:00 +01:00
2007-11-25 22:00:00 +01:00
// pre initializations
2008-07-24 22:00:00 +02:00
switch( Sys.app_name )
2007-11-10 22:00:00 +01:00
{
2007-11-11 22:00:00 +01:00
case HOST_NORMAL:
case HOST_DEDICATED:
2009-09-04 22:00:00 +02:00
case HOST_XIMAGE:
2008-08-06 22:00:00 +02:00
case HOST_BSPLIB:
case HOST_SPRITE:
case HOST_STUDIO:
case HOST_WADLIB:
case HOST_RIPPER:
2007-11-11 22:00:00 +01:00
CreateHost = (void *)Sys.linked_dll->main;
2007-11-30 22:00:00 +01:00
Host = CreateHost( &com, NULL ); // second interface not allowed
2007-11-11 22:00:00 +01:00
Sys.Init = Host->Init;
Sys.Main = Host->Main;
Sys.Free = Host->Free;
2007-11-30 22:00:00 +01:00
Sys.CPrint = Host->CPrint;
2010-02-02 22:00:00 +01:00
Sys.CmdFwd = Host->CmdForward;
2010-02-18 22:00:00 +01:00
Sys.CmdAuto = Host->CmdComplete;
2007-11-11 22:00:00 +01:00
break;
2008-01-05 22:00:00 +01:00
case HOST_CREDITS:
2010-09-10 22:00:00 +02:00
Sys_Break( show_credits, com.timestamp( TIME_YEAR_ONLY ));
2007-11-11 22:00:00 +01:00
break;
case HOST_OFFLINE:
2008-08-06 22:00:00 +02:00
Sys_Break( "Host offline\n" );
2007-11-11 22:00:00 +01:00
break;
2007-11-10 22:00:00 +01:00
}
2007-11-11 22:00:00 +01:00
// init our host now!
2008-07-30 22:00:00 +02:00
Sys.Init( fs_argc, fs_argv );
2007-11-11 22:00:00 +01:00
2007-11-25 22:00:00 +01:00
// post initializations
2008-08-08 22:00:00 +02:00
switch( Sys.app_name )
2007-11-10 22:00:00 +01:00
{
2007-11-25 22:00:00 +01:00
case HOST_NORMAL:
Con_ShowConsole( false ); // hide console
2010-07-30 22:00:00 +02:00
Cbuf_AddText( "exec opengl.cfg\n" ); // openGL configuration
Cbuf_AddText( "exec valve.rc\n" ); // execute startup config and cmdline
2007-11-25 22:00:00 +01:00
case HOST_DEDICATED:
Cbuf_Execute();
// if stuffcmds wasn't run, then init.rc is probably missing, use default
2009-06-22 22:00:00 +02:00
if( !Sys.stuffcmdsrun ) Cbuf_ExecuteText( EXEC_NOW, "stuffcmds\n" );
2007-11-25 22:00:00 +01:00
break;
2009-09-04 22:00:00 +02:00
case HOST_XIMAGE:
2008-08-06 22:00:00 +02:00
case HOST_BSPLIB:
case HOST_SPRITE:
case HOST_STUDIO:
case HOST_WADLIB:
case HOST_RIPPER:
2007-11-27 22:00:00 +01:00
// always run stuffcmds for current instances
2007-11-25 22:00:00 +01:00
Cbuf_ExecuteText( EXEC_NOW, "stuffcmds\n" );
break;
2007-11-10 22:00:00 +01:00
}
2008-06-05 22:00:00 +02:00
2010-07-29 22:00:00 +02:00
Cmd_RemoveCommand( "setr" ); // remove potentially backdoor for change render settings
2008-06-05 22:00:00 +02:00
Sys.app_state = SYS_FRAME; // system is now active
2007-11-10 22:00:00 +01:00
}
/*
==================
Sys_ParseCommandLine
==================
*/
2008-08-04 22:00:00 +02:00
void Sys_ParseCommandLine( LPSTR lpCmdLine )
2007-11-10 22:00:00 +01:00
{
fs_argc = 1;
fs_argv[0] = "exe";
2008-08-04 22:00:00 +02:00
while( *lpCmdLine && (fs_argc < MAX_NUM_ARGVS))
2007-11-10 22:00:00 +01:00
{
2008-08-04 22:00:00 +02:00
while( *lpCmdLine && *lpCmdLine <= ' ' ) lpCmdLine++;
2007-11-10 22:00:00 +01:00
if (!*lpCmdLine) break;
if (*lpCmdLine == '\"')
{
// quoted string
lpCmdLine++;
fs_argv[fs_argc] = lpCmdLine;
fs_argc++;
2008-08-04 22:00:00 +02:00
while( *lpCmdLine && (*lpCmdLine != '\"')) lpCmdLine++;
2007-11-10 22:00:00 +01:00
}
else
{
// unquoted word
fs_argv[fs_argc] = lpCmdLine;
fs_argc++;
2008-08-04 22:00:00 +02:00
while( *lpCmdLine && *lpCmdLine > ' ') lpCmdLine++;
2007-11-10 22:00:00 +01:00
}
2008-08-04 22:00:00 +02:00
if( *lpCmdLine )
2007-11-10 22:00:00 +01:00
{
*lpCmdLine = 0;
lpCmdLine++;
}
}
}
2008-08-04 22:00:00 +02:00
void Sys_MergeCommandLine( LPSTR lpCmdLine )
2007-11-10 22:00:00 +01:00
{
2010-09-10 22:00:00 +02:00
const char *blank = "censored";
int i;
2008-08-04 22:00:00 +02:00
for( i = 0; i < fs_argc; i++ )
2008-07-31 22:00:00 +02:00
{
2008-08-04 22:00:00 +02:00
// we wan't return to first game
2010-09-10 22:00:00 +02:00
if( !com.stricmp( "-game", fs_argv[i] )) fs_argv[i] = (char *)blank;
2008-08-04 22:00:00 +02:00
// probably it's timewaster, because engine rejected second change
2010-09-10 22:00:00 +02:00
if( !com.stricmp( "+game", fs_argv[i] )) fs_argv[i] = (char *)blank;
2008-08-04 22:00:00 +02:00
// you sure what is map exists in new game?
2010-09-10 22:00:00 +02:00
if( !com.stricmp( "+map", fs_argv[i] )) fs_argv[i] = (char *)blank;
2008-08-04 22:00:00 +02:00
// just stupid action
2010-09-10 22:00:00 +02:00
if( !com.stricmp( "+load", fs_argv[i] )) fs_argv[i] = (char *)blank;
2008-08-04 22:00:00 +02:00
// changelevel beetwen games? wow it's great idea!
2010-09-10 22:00:00 +02:00
if( !com.stricmp( "+changelevel", fs_argv[i] )) fs_argv[i] = (char *)blank;
2010-01-31 22:00:00 +01:00
// second call
2010-09-10 22:00:00 +02:00
if( Sys.app_name == HOST_DEDICATED && !com.strnicmp( "+menu_", fs_argv[i], 6 ))
2010-01-31 22:00:00 +01:00
fs_argv[i] = (char *)blank;
2008-07-31 22:00:00 +02:00
}
2007-11-10 22:00:00 +01:00
}
/*
================
Sys_Print
print into window console
================
*/
2008-08-04 22:00:00 +02:00
void Sys_Print( const char *pMsg )
2007-11-10 22:00:00 +01:00
{
const char *msg;
2010-07-26 22:00:00 +02:00
char buffer[32768];
char logbuf[32768];
2007-11-10 22:00:00 +01:00
char *b = buffer;
char *c = logbuf;
int i = 0;
2008-08-04 22:00:00 +02:00
if( Sys.con_silentmode ) return;
2009-01-18 22:00:00 +01:00
if( Sys.CPrint && Sys.app_name == HOST_NORMAL )
Sys.CPrint( pMsg );
2007-11-10 22:00:00 +01:00
// if the message is REALLY long, use just the last portion of it
2010-09-10 22:00:00 +02:00
if ( com.strlen( pMsg ) > sizeof( buffer ) - 1 )
msg = pMsg + com.strlen( pMsg ) - sizeof( buffer ) + 1;
2007-11-10 22:00:00 +01:00
else msg = pMsg;
// copy into an intermediate buffer
while ( msg[i] && (( b - buffer ) < sizeof( buffer ) - 1 ))
{
if( msg[i] == '\n' && msg[i+1] == '\r' )
{
b[0] = '\r';
b[1] = c[0] = '\n';
b += 2, c++;
i++;
}
else if( msg[i] == '\r' )
{
b[0] = c[0] = '\r';
b[1] = '\n';
b += 2, c++;
}
else if( msg[i] == '\n' )
{
b[0] = '\r';
b[1] = c[0] = '\n';
b += 2, c++;
}
else if( msg[i] == '\35' || msg[i] == '\36' || msg[i] == '\37' )
{
i++; // skip console pseudo graph
}
else if(IsColorString( &msg[i])) i++; // skip color prefix
else
{
*b = *c = msg[i];
b++, c++;
}
i++;
}
*b = *c = 0; // cutoff garbage
2009-01-18 22:00:00 +01:00
// because we needs to kill any psedo graph symbols
// and color strings for other instances
if( Sys.CPrint && Sys.app_name != HOST_NORMAL )
Sys.CPrint( logbuf );
2007-11-10 22:00:00 +01:00
Sys_PrintLog( logbuf );
2008-08-04 22:00:00 +02:00
2010-09-09 22:00:00 +02:00
Sys.Con_Print( buffer );
2008-08-04 22:00:00 +02:00
Sys.printlevel = 0; // reset before next message
2007-11-10 22:00:00 +01:00
}
/*
================
Sys_Msg
formatted message
================
*/
void Sys_Msg( const char *pMsg, ... )
{
2008-07-31 22:00:00 +02:00
va_list argptr;
2010-07-26 22:00:00 +02:00
char text[MAX_SYSPATH];
2007-11-10 22:00:00 +01:00
2008-08-04 22:00:00 +02:00
va_start( argptr, pMsg );
2010-09-10 22:00:00 +02:00
com.vsprintf( text, pMsg, argptr );
2008-08-04 22:00:00 +02:00
va_end( argptr );
Sys.printlevel = 0;
2007-11-10 22:00:00 +01:00
Sys_Print( text );
}
void Sys_MsgDev( int level, const char *pMsg, ... )
{
va_list argptr;
2010-07-26 22:00:00 +02:00
char text[MAX_SYSPATH];
2007-11-30 22:00:00 +01:00
2008-08-04 22:00:00 +02:00
if( Sys.developer < level ) return;
Sys.printlevel = level;
2007-11-10 22:00:00 +01:00
2008-07-31 22:00:00 +02:00
va_start( argptr, pMsg );
2010-09-10 22:00:00 +02:00
com.vsprintf( text, pMsg, argptr );
2008-08-04 22:00:00 +02:00
va_end( argptr );
2007-11-30 22:00:00 +01:00
2008-01-03 22:00:00 +01:00
switch( level )
2007-11-30 22:00:00 +01:00
{
case D_WARN:
2010-09-09 22:00:00 +02:00
Sys_Print( va( "^3Warning:^7 %s", text ));
2007-11-30 22:00:00 +01:00
break;
case D_ERROR:
2010-09-09 22:00:00 +02:00
Sys_Print( va( "^1Error:^7 %s", text ));
2007-11-30 22:00:00 +01:00
break;
2010-09-09 22:00:00 +02:00
case D_INFO:
2007-11-30 22:00:00 +01:00
case D_NOTE:
2010-09-09 22:00:00 +02:00
case D_AICONSOLE:
2007-11-30 22:00:00 +01:00
Sys_Print( text );
break;
}
2007-11-10 22:00:00 +01:00
}
2010-07-23 22:00:00 +02:00
/*
================
Sys_DoubleTime
================
*/
2010-07-22 22:00:00 +02:00
double Sys_DoubleTime( void )
{
static LARGE_INTEGER g_PerformanceFrequency;
static LARGE_INTEGER g_ClockStart;
LARGE_INTEGER CurrentTime;
if( !g_PerformanceFrequency.QuadPart )
{
QueryPerformanceFrequency( &g_PerformanceFrequency );
QueryPerformanceCounter( &g_ClockStart );
}
QueryPerformanceCounter( &CurrentTime );
return (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) / (double)( g_PerformanceFrequency.QuadPart );
}
2007-11-10 22:00:00 +01:00
/*
================
Sys_GetClipboardData
create buffer, that contain clipboard
================
*/
char *Sys_GetClipboardData( void )
{
2009-09-10 22:00:00 +02:00
char *data = NULL;
char *cliptext;
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
if( OpenClipboard( NULL ) != 0 )
2007-11-10 22:00:00 +01:00
{
HANDLE hClipboardData;
if(( hClipboardData = GetClipboardData( CF_TEXT )) != 0 )
{
2009-09-10 22:00:00 +02:00
if(( cliptext = GlobalLock( hClipboardData )) != 0 )
2007-11-10 22:00:00 +01:00
{
data = Malloc( GlobalSize( hClipboardData ) + 1 );
2009-09-10 22:00:00 +02:00
com.strcpy( data, cliptext );
2007-11-10 22:00:00 +01:00
GlobalUnlock( hClipboardData );
}
}
CloseClipboard();
}
return data;
}
2008-07-12 22:00:00 +02:00
/*
================
Sys_GetCurrentUser
returns username for current profile
================
*/
char *Sys_GetCurrentUser( void )
{
static string s_userName;
dword size = sizeof( s_userName );
if( !GetUserName( s_userName, &size ))
2010-09-10 22:00:00 +02:00
com.strcpy( s_userName, "player" );
2008-07-12 22:00:00 +02:00
if( !s_userName[0] )
2010-09-10 22:00:00 +02:00
com.strcpy( s_userName, "player" );
2008-07-12 22:00:00 +02:00
return s_userName;
}
2007-11-10 22:00:00 +01:00
/*
================
Sys_Sleep
freeze application for some time
================
*/
2009-02-03 22:00:00 +01:00
void Sys_Sleep( int msec )
2007-11-10 22:00:00 +01:00
{
2009-02-03 22:00:00 +01:00
msec = bound( 1, msec, 1000 );
2007-11-10 22:00:00 +01:00
Sleep( msec );
}
void Sys_WaitForQuit( void )
{
2008-10-27 22:00:00 +01:00
MSG msg;
2007-11-10 22:00:00 +01:00
2008-10-27 22:00:00 +01:00
if( Sys.hooked_out )
2007-11-10 22:00:00 +01:00
{
2008-01-28 22:00:00 +01:00
// in-pipeline mode we don't want to wait for press any key
2010-02-18 22:00:00 +01:00
if( abs((int)GetStdHandle(STD_OUTPUT_HANDLE)) <= 100 )
2008-01-07 22:00:00 +01:00
{
2008-10-27 22:00:00 +01:00
Sys_Print( "press any key to quit\n" );
system( "@pause>nul\n" ); // wait for quit
2008-01-07 22:00:00 +01:00
}
2007-11-10 22:00:00 +01:00
}
else
{
Con_RegisterHotkeys();
2008-10-27 22:00:00 +01:00
Mem_Set( &msg, 0, sizeof( msg ));
2007-11-10 22:00:00 +01:00
// wait for the user to quit
2008-10-27 22:00:00 +01:00
while( msg.message != WM_QUIT )
2007-11-10 22:00:00 +01:00
{
2010-02-18 22:00:00 +01:00
if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2007-11-10 22:00:00 +01:00
{
2010-02-18 22:00:00 +01:00
TranslateMessage( &msg );
DispatchMessage( &msg );
2007-11-10 22:00:00 +01:00
}
else Sys_Sleep( 20 );
}
}
}
/*
================
Sys_Error
NOTE: we must prepare engine to shutdown
before call this
================
*/
2010-02-10 22:00:00 +01:00
void Sys_Error( const char *error, ... )
2007-11-10 22:00:00 +01:00
{
2010-02-10 22:00:00 +01:00
va_list argptr;
2010-07-26 22:00:00 +02:00
char text[MAX_SYSPATH];
2007-11-10 22:00:00 +01:00
2008-06-05 22:00:00 +02:00
if( Sys.app_state == SYS_ERROR )
return; // don't multiple executes
2008-08-04 22:00:00 +02:00
// make sure what console received last message
// stupid windows bug :(
if( Sys.app_state == SYS_RESTART )
Sys_Sleep( 200 );
2008-06-05 22:00:00 +02:00
Sys.error = true;
Sys.app_state = SYS_ERROR;
2008-08-04 22:00:00 +02:00
va_start( argptr, error );
2010-09-10 22:00:00 +02:00
com.vsprintf( text, error, argptr );
2008-08-04 22:00:00 +02:00
va_end( argptr );
2010-02-18 22:00:00 +01:00
2009-10-06 22:00:00 +02:00
if( Sys.app_name == HOST_NORMAL )
Sys.Free(); // kill video
2007-11-10 22:00:00 +01:00
2010-07-22 22:00:00 +02:00
if( Sys.developer > 0 )
{
Con_ShowConsole( true );
Con_DisableInput(); // disable input line for dedicated server
Sys_Print( text ); // print error message
Sys_WaitForQuit();
}
else
{
Con_ShowConsole( false );
MSGBOX( text );
}
2007-11-10 22:00:00 +01:00
Sys_Exit();
}
2010-02-10 22:00:00 +01:00
void Sys_Break( const char *error, ... )
2007-11-25 22:00:00 +01:00
{
va_list argptr;
2010-07-26 22:00:00 +02:00
char text[MAX_SYSPATH];
2007-11-25 22:00:00 +01:00
2008-08-04 22:00:00 +02:00
va_start( argptr, error );
2010-09-10 22:00:00 +02:00
com.vsprintf( text, error, argptr );
2010-02-16 22:00:00 +01:00
va_end( argptr );
2008-06-05 22:00:00 +02:00
Sys.error = true;
Sys.app_state = SYS_ERROR;
2009-10-06 22:00:00 +02:00
if( Sys.app_name == HOST_NORMAL )
Sys.Free(); // kill video
2009-09-28 22:00:00 +02:00
2010-02-18 22:00:00 +01:00
if( Sys.con_readonly && ( Sys.developer > 0 || Sys.app_name != HOST_NORMAL ))
2010-02-16 22:00:00 +01:00
{
Con_ShowConsole( true );
Sys_Print( text );
Sys_WaitForQuit();
}
else
{
2010-02-18 22:00:00 +01:00
Con_ShowConsole( false );
2010-02-16 22:00:00 +01:00
MSGBOX( text );
}
2007-11-25 22:00:00 +01:00
Sys_Exit();
}
2007-11-10 22:00:00 +01:00
2008-06-05 22:00:00 +02:00
void Sys_Abort( void )
{
// aborting by user, run normal shutdown procedure
Sys.app_state = SYS_ABORT;
Sys_Exit();
}
2010-02-10 22:00:00 +01:00
long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
{
// save config
if( Sys.app_state != SYS_CRASH )
{
// check to avoid recursive call
Sys.error = true;
Sys.app_state = SYS_CRASH;
2010-02-21 22:00:00 +01:00
if( Sys.app_name == HOST_NORMAL || Sys.app_name == HOST_DEDICATED )
Cmd_ExecuteString( "@crashed\n" ); // tell server about crash
2010-02-10 22:00:00 +01:00
Msg( "Sys_Crash: call %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
2010-03-28 22:00:00 +02:00
if( Sys.developer <= 0 )
{
// no reason to call debugger in release build - just exit
Sys_Exit();
return EXCEPTION_CONTINUE_EXECUTION;
}
2010-02-10 22:00:00 +01:00
// all other states keep unchanged to let debugger find bug
2010-03-28 22:00:00 +02:00
Con_DestroyConsole();
2010-02-10 22:00:00 +01:00
}
if( Sys.oldFilter )
return Sys.oldFilter( pInfo );
2010-03-25 22:00:00 +01:00
return EXCEPTION_CONTINUE_EXECUTION;
2010-02-10 22:00:00 +01:00
}
2007-11-10 22:00:00 +01:00
void Sys_Init( void )
{
MEMORYSTATUS lpBuffer;
char dev_level[4];
2010-02-10 22:00:00 +01:00
lpBuffer.dwLength = sizeof( MEMORYSTATUS );
2008-08-04 22:00:00 +02:00
GlobalMemoryStatus( &lpBuffer );
Sys.logfile = NULL;
2007-11-10 22:00:00 +01:00
2008-10-27 22:00:00 +01:00
// get current hInstance
Sys.hInstance = (HINSTANCE)GetModuleHandle( NULL );
2010-07-21 22:00:00 +02:00
Sys.developer = 0;
2007-11-10 22:00:00 +01:00
2007-11-11 22:00:00 +01:00
Sys_GetStdAPI();
Sys.Init = NullInit;
Sys.Main = NullFunc;
Sys.Free = NullFunc;
2008-08-04 22:00:00 +02:00
Sys.CPrint = NullPrint;
Sys.Con_Print = NullPrint;
2007-11-10 22:00:00 +01:00
2010-02-10 22:00:00 +01:00
Sys.oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
2008-10-27 22:00:00 +01:00
// some commands may turn engine into infinity loop,
2008-08-04 22:00:00 +02:00
// e.g. xash.exe +game xash -game xash
// so we clearing all cmd_args, but leave dbg states as well
if( Sys.app_state != SYS_RESTART )
Sys_ParseCommandLine( GetCommandLine());
else Sys_MergeCommandLine( GetCommandLine());
2007-11-10 22:00:00 +01:00
2008-08-04 22:00:00 +02:00
// parse and copy args into local array
2010-02-18 22:00:00 +01:00
if( FS_CheckParm( "-log" )) Sys.log_active = true;
if( FS_CheckParm( "-console" )) Sys.developer = 1;
2010-07-21 22:00:00 +02:00
if( FS_CheckParm( "-dev" ))
{
if( FS_GetParmFromCmdLine( "-dev", dev_level, sizeof( dev_level )))
{
if( com.is_digit( dev_level ))
2010-09-10 22:00:00 +02:00
Sys.developer = abs( com.atoi( dev_level ));
2010-07-21 22:00:00 +02:00
else Sys.developer++; // -dev == 1, -dev -console == 2
}
else Sys.developer++; // -dev == 1, -dev -console == 2
}
2010-07-17 22:00:00 +02:00
if( Sys.log_active && !Sys.developer ) Sys.log_active = false; // nothing to logging :)
2008-08-04 22:00:00 +02:00
2007-12-05 22:00:00 +01:00
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
2008-06-05 22:00:00 +02:00
if( Sys.hooked_out ) atexit( Sys_Abort );
2007-11-10 22:00:00 +01:00
2008-10-27 22:00:00 +01:00
// set default state
Sys.con_showalways = Sys.con_readonly = true;
Sys.con_showcredits = Sys.con_silentmode = Sys.stuffcmdsrun = false;
2007-11-10 22:00:00 +01:00
2008-10-27 22:00:00 +01:00
Sys_LookupInstance(); // init launcher
2010-07-22 22:00:00 +02:00
FS_UpdateEnvironmentVariables(); // set working directory
2007-11-10 22:00:00 +01:00
Con_CreateConsole();
2008-08-04 22:00:00 +02:00
2010-01-31 22:00:00 +01:00
// second pass (known state)
if( Sys.app_state == SYS_RESTART )
Sys_MergeCommandLine( GetCommandLine());
2008-08-04 22:00:00 +02:00
// first text message into console or log
2010-07-30 22:00:00 +02:00
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading launch.dll - ok\n" );
2008-08-04 22:00:00 +02:00
2008-10-27 22:00:00 +01:00
if( com.strlen( Sys.fmessage ) && !Sys.con_showcredits )
2008-08-04 22:00:00 +02:00
{
Sys_Print( Sys.fmessage );
Sys.fmessage[0] = '\0';
}
2007-11-10 22:00:00 +01:00
Memory_Init();
2008-10-27 22:00:00 +01:00
Sys_InitCPU();
2007-11-25 22:00:00 +01:00
Cmd_Init();
Cvar_Init();
2007-11-10 22:00:00 +01:00
FS_Init();
2008-08-06 22:00:00 +02:00
Image_Init();
2010-04-20 22:00:00 +02:00
Sound_Init();
2007-11-11 22:00:00 +01:00
Sys_CreateInstance();
2007-11-10 22:00:00 +01:00
}
2008-08-04 22:00:00 +02:00
void Sys_Shutdown( void )
{
// prepare host to close
Sys.Free();
Sys_FreeLibrary( Sys.linked_dll );
Sys.CPrint = NullPrint;
FS_Shutdown();
2008-08-06 22:00:00 +02:00
Image_Shutdown();
2010-04-20 22:00:00 +02:00
Sound_Shutdown();
2008-08-04 22:00:00 +02:00
Memory_Shutdown();
Con_DestroyConsole();
2010-02-10 22:00:00 +01:00
// restore filter
if( Sys.oldFilter )
{
SetUnhandledExceptionFilter( Sys.oldFilter );
}
2008-08-04 22:00:00 +02:00
}
2007-11-10 22:00:00 +01:00
/*
================
Sys_Exit
NOTE: we must prepare engine to shutdown
before call this
================
*/
2008-06-05 22:00:00 +02:00
void Sys_Exit( void )
2007-11-10 22:00:00 +01:00
{
2008-06-06 22:00:00 +02:00
if( Sys.shutdown_issued ) return;
Sys.shutdown_issued = true;
2008-06-05 22:00:00 +02:00
2008-08-04 22:00:00 +02:00
Sys_Shutdown();
2007-11-11 22:00:00 +01:00
exit( Sys.error );
2007-11-10 22:00:00 +01:00
}
//=======================================================================
// DLL'S MANAGER SYSTEM
//=======================================================================
2009-10-02 22:00:00 +02:00
bool Sys_LoadLibrary( const char *dll_name, dll_info_t *dll )
2007-11-10 22:00:00 +01:00
{
const dllfunc_t *func;
bool native_lib = false;
2008-06-06 22:00:00 +02:00
string errorstring;
2007-11-10 22:00:00 +01:00
// check errors
2009-09-10 22:00:00 +02:00
if( !dll ) return false; // invalid desc
if( dll->link ) return true; // already loaded
2007-11-10 22:00:00 +01:00
2009-10-02 22:00:00 +02:00
// check and replace names
if( dll_name && *dll_name ) dll->name = dll_name;
if( !dll->name || !*dll->name ) return false; // nothing to load
2009-09-10 22:00:00 +02:00
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s", dll->name );
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
if( dll->fcts )
2007-11-10 22:00:00 +01:00
{
// lookup export table
2009-09-10 22:00:00 +02:00
for( func = dll->fcts; func && func->name != NULL; func++ )
2007-11-10 22:00:00 +01:00
*func->func = NULL;
}
2009-09-10 22:00:00 +02:00
else if( dll->entry ) native_lib = true;
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
if( !dll->link ) dll->link = LoadLibrary ( va( "bin/%s", dll->name ));
if( !dll->link ) dll->link = LoadLibrary ( dll->name ); // environment pathes
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
// no DLL found
if( !dll->link )
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
com.sprintf( errorstring, "Sys_LoadLibrary: couldn't load %s\n", dll->name );
2007-11-10 22:00:00 +01:00
goto error;
}
2009-09-10 22:00:00 +02:00
if( native_lib )
2007-11-10 22:00:00 +01:00
{
2009-10-02 22:00:00 +02:00
if(( dll->main = Sys_GetProcAddress( dll, dll->entry )) == 0 )
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
com.sprintf( errorstring, "Sys_LoadLibrary: %s has no valid entry point\n", dll->name );
2007-11-10 22:00:00 +01:00
goto error;
}
}
else
{
// Get the function adresses
2009-09-10 22:00:00 +02:00
for( func = dll->fcts; func && func->name != NULL; func++ )
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
if (!( *func->func = Sys_GetProcAddress( dll, func->name )))
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
com.sprintf( errorstring, "Sys_LoadLibrary: %s missing or invalid function (%s)\n", dll->name, func->name );
2007-11-10 22:00:00 +01:00
goto error;
}
}
}
if( native_lib )
{
generic_api_t *check = NULL;
// NOTE: native dlls must support null import!
2009-09-10 22:00:00 +02:00
// e.g. see ..\engine\engine.c for details
2007-11-30 22:00:00 +01:00
check = (void *)dll->main( &com, NULL ); // first iface always stdlib_api_t
2007-11-10 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
if( !check )
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
com.sprintf( errorstring, "Sys_LoadLibrary: \"%s\" have no export\n", dll->name );
2007-11-10 22:00:00 +01:00
goto error;
}
2009-09-10 22:00:00 +02:00
if( check->api_size != dll->api_size )
2007-11-10 22:00:00 +01:00
{
2009-09-10 22:00:00 +02:00
com.sprintf( errorstring, "Sys_LoadLibrary: \"%s\" mismatch interface size (%i should be %i)\n", dll->name, check->api_size, dll->api_size );
2007-11-10 22:00:00 +01:00
goto error;
}
2009-09-10 22:00:00 +02:00
if( check->com_size != dll->com_size )
{
com.sprintf( errorstring, "Sys_LoadLibrary: \"%s\" mismatch stdlib api size (%i should be %i)\n", dll->name, check->com_size, dll->com_size);
goto error;
}
2007-11-10 22:00:00 +01:00
}
2009-09-10 22:00:00 +02:00
MsgDev( D_NOTE, " - ok\n" );
2007-11-10 22:00:00 +01:00
return true;
error:
2009-09-10 22:00:00 +02:00
MsgDev( D_NOTE, " - failed\n" );
Sys_FreeLibrary( dll ); // trying to free
if( dll->crash ) Sys_Error( errorstring );
2007-11-30 22:00:00 +01:00
else MsgDev( D_ERROR, errorstring );
2007-11-10 22:00:00 +01:00
return false;
}
2009-09-10 22:00:00 +02:00
void* Sys_GetProcAddress( dll_info_t *dll, const char* name )
2007-11-10 22:00:00 +01:00
{
2009-10-02 22:00:00 +02:00
if( !dll || !dll->link ) // invalid desc
2007-11-10 22:00:00 +01:00
return NULL;
2009-10-02 22:00:00 +02:00
return (void *)GetProcAddress( dll->link, name );
2007-11-10 22:00:00 +01:00
}
2008-08-04 22:00:00 +02:00
bool Sys_FreeLibrary( dll_info_t *dll )
2007-11-10 22:00:00 +01:00
{
2008-08-04 22:00:00 +02:00
// invalid desc or alredy freed
2009-10-02 22:00:00 +02:00
if( !dll || !dll->link )
2007-11-10 22:00:00 +01:00
return false;
2010-02-10 22:00:00 +01:00
if( Sys.app_state == SYS_CRASH )
{
// we need to hold down all modules, while MSVC can find error
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", dll->name );
return false;
}
else MsgDev( D_NOTE, "Sys_FreeLibrary: Unloading %s\n", dll->name );
2008-08-04 22:00:00 +02:00
FreeLibrary( dll->link );
2007-11-10 22:00:00 +01:00
dll->link = NULL;
return true;
}
2009-09-10 22:00:00 +02:00
/*
=================
Sys_ShellExecute
=================
*/
void Sys_ShellExecute( const char *path, const char *parms, bool exit )
{
ShellExecute( NULL, "open", path, parms, NULL, SW_SHOW );
if( exit ) Sys_Exit();
}
2007-11-10 22:00:00 +01:00
//=======================================================================
// MULTITHREAD SYSTEM
//=======================================================================
#define MAX_THREADS 64
int dispatch;
int workcount;
int oldf;
bool pacifier;
bool threaded;
void (*workfunction) (int);
int numthreads = -1;
CRITICAL_SECTION crit;
static int enter;
int Sys_GetNumThreads( void )
{
return numthreads;
}
void Sys_ThreadLock( void )
{
2008-06-06 22:00:00 +02:00
if( !threaded ) return;
EnterCriticalSection( &crit );
if( enter ) Sys_Error( "Recursive Sys_ThreadLock\n" );
enter = true;
2007-11-10 22:00:00 +01:00
}
void Sys_ThreadUnlock( void )
{
2008-06-06 22:00:00 +02:00
if( !threaded ) return;
if( !enter ) Sys_Error( "Sys_ThreadUnlock without lock\n" );
enter = false;
LeaveCriticalSection( &crit );
2007-11-10 22:00:00 +01:00
}
int Sys_GetThreadWork( void )
{
int r, f;
2008-06-06 22:00:00 +02:00
Sys_ThreadLock();
2007-11-10 22:00:00 +01:00
2008-06-06 22:00:00 +02:00
if( dispatch == workcount )
2007-11-10 22:00:00 +01:00
{
Sys_ThreadUnlock();
return -1;
}
f = 10 * dispatch / workcount;
2008-06-06 22:00:00 +02:00
if( f != oldf )
2007-11-10 22:00:00 +01:00
{
oldf = f;
2008-06-06 22:00:00 +02:00
if( pacifier ) Msg( "%i...", f );
2007-11-10 22:00:00 +01:00
}
r = dispatch;
dispatch++;
Sys_ThreadUnlock ();
return r;
}
2008-06-06 22:00:00 +02:00
void Sys_ThreadWorkerFunction( int threadnum )
2007-11-10 22:00:00 +01:00
{
int work;
2008-06-06 22:00:00 +02:00
while( 1 )
2007-11-10 22:00:00 +01:00
{
work = Sys_GetThreadWork();
2008-06-06 22:00:00 +02:00
if( work == -1 ) break;
workfunction( work );
2007-11-10 22:00:00 +01:00
}
}
2008-06-06 22:00:00 +02:00
void Sys_ThreadSetDefault( void )
2007-11-10 22:00:00 +01:00
{
2008-06-06 22:00:00 +02:00
if( numthreads == -1 ) // not set manually
2007-11-10 22:00:00 +01:00
{
// NOTE: we must init Plat_InitCPU() first
2009-09-10 22:00:00 +02:00
numthreads = SI.cpunum;
2008-06-06 22:00:00 +02:00
if( numthreads < 1 || numthreads > MAX_THREADS )
2007-11-10 22:00:00 +01:00
numthreads = 1;
}
}
2008-06-06 22:00:00 +02:00
void Sys_RunThreadsOnIndividual( int workcnt, bool showpacifier, void(*func)(int))
2007-11-10 22:00:00 +01:00
{
2008-06-06 22:00:00 +02:00
if (numthreads == -1) Sys_ThreadSetDefault();
2007-11-10 22:00:00 +01:00
workfunction = func;
Sys_RunThreadsOn (workcnt, showpacifier, Sys_ThreadWorkerFunction);
}
/*
=============
Sys_RunThreadsOn
=============
*/
2008-06-06 22:00:00 +02:00
void Sys_RunThreadsOn( int workcnt, bool showpacifier, void(*func)(int))
2007-11-10 22:00:00 +01:00
{
int i, threadid[MAX_THREADS];
HANDLE threadhandle[MAX_THREADS];
double start, end;
start = Sys_DoubleTime();
dispatch = 0;
workcount = workcnt;
oldf = -1;
pacifier = showpacifier;
threaded = true;
// run threads in parallel
2008-06-06 22:00:00 +02:00
InitializeCriticalSection(&crit);
2007-11-10 22:00:00 +01:00
if (numthreads == 1) func(0); // use same thread
else
{
for (i = 0; i < numthreads; i++)
{
threadhandle[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)func, (LPVOID)i, 0, &threadid[i]);
}
for (i = 0; i < numthreads; i++)
{
2008-06-06 22:00:00 +02:00
WaitForSingleObject(threadhandle[i], INFINITE);
2007-11-10 22:00:00 +01:00
}
}
2008-06-06 22:00:00 +02:00
DeleteCriticalSection(&crit);
2007-11-10 22:00:00 +01:00
threaded = false;
end = Sys_DoubleTime();
2008-06-06 22:00:00 +02:00
if( pacifier ) Msg(" Done [%.2f sec]\n", end - start);
2007-11-10 22:00:00 +01:00
}
2008-07-06 22:00:00 +02:00
/*
================
Sys_QueEvent
A time of 0 will get the current time
Ptr should either be null, or point to a block of data that can
be freed by the game later.
================
*/
2010-10-09 22:00:00 +02:00
void Sys_QueEvent( ev_type_t type, int value, int value2, int length, void *ptr )
2008-07-06 22:00:00 +02:00
{
sys_event_t *ev;
ev = &event_que[event_head & MASK_QUED_EVENTS];
if( event_head - event_tail >= MAX_QUED_EVENTS )
{
MsgDev( D_ERROR, "Sys_QueEvent: overflow\n");
// make sure what memory is allocated by engine
2010-06-17 22:00:00 +02:00
if( Mem_IsAllocated( ev->data )) Mem_Free( ev->data );
2008-07-06 22:00:00 +02:00
event_tail++;
}
event_head++;
ev->type = type;
ev->value[0] = value;
ev->value[1] = value2;
ev->length = length;
ev->data = ptr;
}
/*
================
Sys_GetEvent
================
*/
sys_event_t Sys_GetEvent( void )
{
MSG msg;
sys_event_t ev;
char *s;
2008-07-12 22:00:00 +02:00
2008-07-06 22:00:00 +02:00
// return if we have data
if( event_head > event_tail )
{
event_tail++;
2010-06-17 22:00:00 +02:00
return event_que[(event_tail - 1) & MASK_QUED_EVENTS];
2008-07-06 22:00:00 +02:00
}
// pump the message loop
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
2010-06-20 22:00:00 +02:00
if( !GetMessage( &msg, NULL, 0, 0 ))
2008-07-06 22:00:00 +02:00
{
Sys.error = true;
Sys_Exit();
}
TranslateMessage(&msg );
DispatchMessage( &msg );
}
// check for console commands
s = Sys_Input();
if( s )
{
char *b;
int len;
2010-06-20 22:00:00 +02:00
len = com.strlen( s ) + 1;
2008-07-06 22:00:00 +02:00
b = Malloc( len );
2010-06-17 22:00:00 +02:00
com.strncpy( b, s, len - 1 );
2010-10-09 22:00:00 +02:00
Sys_QueEvent( SE_CONSOLE, 0, 0, len, b );
2008-07-06 22:00:00 +02:00
}
2008-07-12 22:00:00 +02:00
2008-07-06 22:00:00 +02:00
// return if we have data
if( event_head > event_tail )
{
event_tail++;
return event_que[(event_tail - 1) & MASK_QUED_EVENTS];
}
// create an empty event to return
2008-10-27 22:00:00 +01:00
Mem_Set( &ev, 0, sizeof( ev ));
2008-07-06 22:00:00 +02:00
return ev;
}
2008-07-31 22:00:00 +02:00
bool Sys_GetModuleName( char *buffer, size_t length )
{
2008-10-27 22:00:00 +01:00
if( Sys.ModuleName[0] == '\0' )
2008-07-31 22:00:00 +02:00
return false;
2008-10-27 22:00:00 +01:00
com.strncpy( buffer, Sys.ModuleName, length + 1 );
2008-07-31 22:00:00 +02:00
return true;
}
2008-08-04 22:00:00 +02:00
/*
================
Sys_NewInstance
restarted engine with new instance
e.g. for change game or fallback to dedicated mode
================
*/
void Sys_NewInstance( const char *name, const char *fmsg )
{
// save parms
2010-07-29 22:00:00 +02:00
com.strncpy( Sys.ModuleName, name, sizeof( Sys.ModuleName ));
com.strncpy( Sys.fmessage, fmsg, sizeof( Sys.fmessage ));
2008-08-04 22:00:00 +02:00
Sys.app_state = SYS_RESTART; // set right state
Sys_Shutdown(); // shutdown current instance
// NOTE: we never return to old instance,
// because Sys_Exit call exit(0); and terminate program
Sys_Init();
Sys.Main();
Sys_Exit();
}
2007-11-10 22:00:00 +01:00
//=======================================================================
// REGISTRY COMMON TOOLS
//=======================================================================
bool REG_GetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuffer)
{
dword dwBufLen = 4096;
long lRet;
if(lRet = RegOpenKeyEx( hKey, SubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
return false;
else
{
lRet = RegQueryValueEx( hKey, Value, NULL, NULL, (byte *)pBuffer, &dwBufLen);
if(lRet != ERROR_SUCCESS) return false;
RegCloseKey( hKey );
}
return true;
}
bool REG_SetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuffer )
{
dword dwBufLen = 4096;
long lRet;
if(lRet = RegOpenKeyEx(hKey, SubKey, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
return false;
else
{
lRet = RegSetValueEx(hKey, Value, 0, REG_SZ, (byte *)pBuffer, dwBufLen );
if(lRet != ERROR_SUCCESS) return false;
RegCloseKey(hKey);
}
return true;
}