jedioutcast/CODE-mp/null/win_main.cpp
2013-04-04 16:05:53 -05:00

1490 lines
32 KiB
C++

// win_main.c
#include "../client/client.h"
#include "../qcommon/qcommon.h"
#include "../win32/win_local.h"
#include "../win32/resource.h"
#include <errno.h>
#include <float.h>
#include <fcntl.h>
#include <stdio.h>
#include <direct.h>
#include <io.h>
#include <conio.h>
#include "../qcommon/strip.h"
#define CD_BASEDIR "gamedata\\gamedata"
#define CD_EXE "jk2sp.exe"
#define CD_BASEDIR_LINUX "bin\\x86\\glibc-2.1"
#define CD_EXE_LINUX "jk2sp"
#define MEM_THRESHOLD 96*1024*1024
static char sys_cmdline[MAX_STRING_CHARS];
clientStatic_t cls;
static int sys_monkeySpank;
static int sys_checksum;
void *Sys_GetBotAIAPI (void *parms ) {
return NULL;
}
void Conbuf_AppendText( const char *pMsg )
{
char msg[4096];
strcpy(msg, pMsg);
printf(Q_CleanStr(msg));
printf("\n");
}
/*
==================
Sys_LowPhysicalMemory()
==================
*/
qboolean Sys_LowPhysicalMemory() {
MEMORYSTATUS stat;
GlobalMemoryStatus (&stat);
return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
}
/*
==================
Sys_FunctionCmp
==================
*/
int Sys_FunctionCmp(void *f1, void *f2) {
int i, j, l;
byte func_end[32] = {0xC3, 0x90, 0x90, 0x00};
byte *ptr, *ptr2;
byte *f1_ptr, *f2_ptr;
ptr = (byte *) f1;
if (*(byte *)ptr == 0xE9) {
//Com_Printf("f1 %p1 jmp %d\n", (int *) f1, *(int*)(ptr+1));
f1_ptr = (byte*)(((byte*)f1) + (*(int *)(ptr+1)) + 5);
}
else {
f1_ptr = ptr;
}
//Com_Printf("f1 ptr %p\n", f1_ptr);
ptr = (byte *) f2;
if (*(byte *)ptr == 0xE9) {
//Com_Printf("f2 %p jmp %d\n", (int *) f2, *(int*)(ptr+1));
f2_ptr = (byte*)(((byte*)f2) + (*(int *)(ptr+1)) + 5);
}
else {
f2_ptr = ptr;
}
//Com_Printf("f2 ptr %p\n", f2_ptr);
#ifdef _DEBUG
sprintf((char *)func_end, "%c%c%c%c%c%c%c", 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3);
#endif
for (i = 0; i < 1024; i++) {
for (j = 0; func_end[j]; j++) {
if (f1_ptr[i+j] != func_end[j])
break;
}
if (!func_end[j]) {
break;
}
}
#ifdef _DEBUG
l = i + 7;
#else
l = i + 2;
#endif
//Com_Printf("function length = %d\n", l);
for (i = 0; i < l; i++) {
// check for a potential function call
if (*((byte *) &f1_ptr[i]) == 0xE8) {
// get the function pointers in case this really is a function call
ptr = (byte *) (((byte *) &f1_ptr[i]) + (*(int *) &f1_ptr[i+1])) + 5;
ptr2 = (byte *) (((byte *) &f2_ptr[i]) + (*(int *) &f2_ptr[i+1])) + 5;
// if it was a function call and both f1 and f2 call the same function
if (ptr == ptr2) {
i += 4;
continue;
}
}
if (f1_ptr[i] != f2_ptr[i])
return qfalse;
}
return qtrue;
}
/*
==================
Sys_FunctionCheckSum
==================
*/
int Sys_FunctionCheckSum(void *f1) {
int i, j, l;
byte func_end[32] = {0xC3, 0x90, 0x90, 0x00};
byte *ptr;
byte *f1_ptr;
ptr = (byte *) f1;
if (*(byte *)ptr == 0xE9) {
//Com_Printf("f1 %p1 jmp %d\n", (int *) f1, *(int*)(ptr+1));
f1_ptr = (byte*)(((byte*)f1) + (*(int *)(ptr+1)) + 5);
}
else {
f1_ptr = ptr;
}
//Com_Printf("f1 ptr %p\n", f1_ptr);
#ifdef _DEBUG
sprintf((char *)func_end, "%c%c%c%c%c%c%c", 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3);
#endif
for (i = 0; i < 1024; i++) {
for (j = 0; func_end[j]; j++) {
if (f1_ptr[i+j] != func_end[j])
break;
}
if (!func_end[j]) {
break;
}
}
#ifdef _DEBUG
l = i + 7;
#else
l = i + 2;
#endif
//Com_Printf("function length = %d\n", l);
return Com_BlockChecksum( f1_ptr, l );
}
/*
==================
Sys_MonkeyShouldBeSpanked
==================
*/
int Sys_MonkeyShouldBeSpanked( void ) {
return sys_monkeySpank;
}
/*
==================
Sys_VerifyCodeChecksum
==================
*/
void Sys_VerifyCodeChecksum( void *codeBase ) {
}
/*
===============
PrintMatches
===============
*/
static char g_consoleField1[256];
static char g_consoleField2[256];
static void PrintMatches( const char *s ) {
if ( !Q_stricmpn( s, g_consoleField1, strlen( g_consoleField1 ) ) ) {
printf( " %s\n", s );
}
}
//qboolean stdin_active = qtrue;
char *Sys_ConsoleInput(void)
{
const char ClearLine[] = "\r \r";
static int len=0;
static bool bPendingExtended = false;
if (!kbhit()) return NULL;
if (len == 0) memset(g_consoleField1,0,sizeof(g_consoleField1));
g_consoleField1[len] = getch();
if (bPendingExtended)
{
switch (g_consoleField1[len])
{
case 'H': //up
strcpy(g_consoleField1, g_consoleField2);
printf(ClearLine);
printf("%s",g_consoleField1);
len = strlen(g_consoleField1);
break;
case 'K': //left
break;
case 'M': //right
break;
case 'P': //down
break;
}
g_consoleField1[len] = 0; //erase last key hit
bPendingExtended = false;
}
else
switch ((unsigned char) g_consoleField1[len])
{
case 0x00: //fkey is next
case 0xe0: //extended = arrow keys
g_consoleField1[len] = 0; //erase last key hit
bPendingExtended = true;
break;
case 8: // backspace
printf("%c %c",g_consoleField1[len],g_consoleField1[len]);
g_consoleField1[len] = 0;
if (len > 0) len--;
g_consoleField1[len] = 0;
break;
case 9: //Tab
if (len) {
g_consoleField1[len] = 0; //erase last key hit
printf( "\n");
// run through again, printing matches
Cmd_CommandCompletion( PrintMatches );
Cvar_CommandCompletion( PrintMatches );
printf( "\n%s", g_consoleField1);
}
break;
case 27: // esc
// clear the line
printf(ClearLine);
len = 0;
break;
case '\r': //enter
g_consoleField1[len] = 0; //erase last key hit
printf("\n");
if (len) {
len = 0;
strcpy(g_consoleField2, g_consoleField1);
return g_consoleField1;
}
break;
case 'v' - 'a' + 1: // ctrl-v is paste
g_consoleField1[len] = 0; //erase last key hit
char *cbd;
cbd = Sys_GetClipboardData();
if (cbd) {
strncpy (&g_consoleField1[len], cbd, sizeof(g_consoleField1) );
printf("%s",cbd);
len += strlen(cbd);
Z_Free( cbd );
if (len == sizeof(g_consoleField1))
{
len = 0;
return g_consoleField1;
}
}
break;
default:
printf("%c",g_consoleField1[len]);
len++;
if (len == sizeof(g_consoleField1))
{
len = 0;
return g_consoleField1;
}
break;
}
return NULL;
}
/*
==================
Sys_BeginProfiling
==================
*/
void Sys_BeginProfiling( void ) {
// this is just used on the mac build
}
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
{
}
/*
=============
Sys_Error
Show the early console as an error dialog
=============
*/
void QDECL Sys_Error( const char *error, ... ) {
va_list argptr;
char text[4096];
MSG msg;
va_start (argptr, error);
vsprintf (text, error, argptr);
va_end (argptr);
Conbuf_AppendText( text );
Conbuf_AppendText( "\n" );
// Sys_SetErrorText( text );
Sys_ShowConsole( 1, qtrue );
timeEndPeriod( 1 );
IN_Shutdown();
// wait for the user to quit
while ( 1 ) {
if (!GetMessage (&msg, NULL, 0, 0))
Com_Quit_f ();
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// Sys_DestroyConsole();
Com_ShutdownZoneMemory();
Com_ShutdownHunkMemory();
exit (1);
}
/*
==============
Sys_Quit
==============
*/
void Sys_Quit( void ) {
timeEndPeriod( 1 );
IN_Shutdown();
// Sys_DestroyConsole();
Com_ShutdownZoneMemory();
Com_ShutdownHunkMemory();
exit (0);
}
/*
==============
Sys_Print
==============
*/
void Sys_Print( const char *msg ) {
Conbuf_AppendText( msg );
}
/*
==============
Sys_Mkdir
==============
*/
void Sys_Mkdir( const char *path ) {
_mkdir (path);
}
/*
==============
Sys_Cwd
==============
*/
char *Sys_Cwd( void ) {
static char cwd[MAX_OSPATH];
_getcwd( cwd, sizeof( cwd ) - 1 );
cwd[MAX_OSPATH-1] = 0;
return cwd;
}
/*
==============
Sys_DefaultCDPath
==============
*/
char *Sys_DefaultCDPath( void ) {
return "";
}
/*
==============
Sys_DefaultBasePath
==============
*/
char *Sys_DefaultBasePath( void ) {
return Sys_Cwd();
}
/*
==============================================================
DIRECTORY SCANNING
==============================================================
*/
#define MAX_FOUND_FILES 0x1000
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **psList, int *numfiles ) {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
int findhandle;
struct _finddata_t findinfo;
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
return;
}
if (strlen(subdirs)) {
Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
}
else {
Com_sprintf( search, sizeof(search), "%s\\*", basedir );
}
findhandle = _findfirst (search, &findinfo);
if (findhandle == -1) {
return;
}
do {
if (findinfo.attrib & _A_SUBDIR) {
if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
if (strlen(subdirs)) {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
}
else {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, psList, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
break;
}
Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
if (!Com_FilterPath( filter, filename, qfalse ))
continue;
psList[ *numfiles ] = CopyString( filename );
(*numfiles)++;
} while ( _findnext (findhandle, &findinfo) != -1 );
_findclose (findhandle);
}
static qboolean strgtr(const char *s0, const char *s1) {
int l0, l1, i;
l0 = strlen(s0);
l1 = strlen(s1);
if (l1<l0) {
l0 = l1;
}
for(i=0;i<l0;i++) {
if (s1[i] > s0[i]) {
return qtrue;
}
if (s1[i] < s0[i]) {
return qfalse;
}
}
return qfalse;
}
char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
struct _finddata_t findinfo;
int findhandle;
int flag;
int i;
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = 0;
*numfiles = nfiles;
if (!nfiles)
return NULL;
listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ), TAG_FILESYS );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
if ( !extension) {
extension = "";
}
// passing a slash as extension will find directories
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
flag = 0;
} else {
flag = _A_SUBDIR;
}
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
// search
nfiles = 0;
findhandle = _findfirst (search, &findinfo);
if (findhandle == -1) {
*numfiles = 0;
return NULL;
}
do {
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
if ( nfiles == MAX_FOUND_FILES - 1 ) {
break;
}
list[ nfiles ] = CopyString( findinfo.name );
nfiles++;
}
} while ( _findnext (findhandle, &findinfo) != -1 );
list[ nfiles ] = 0;
_findclose (findhandle);
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ), TAG_FILESYS );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
do {
flag = 0;
for(i=1; i<nfiles; i++) {
if (strgtr(listCopy[i-1], listCopy[i])) {
char *temp = listCopy[i];
listCopy[i] = listCopy[i-1];
listCopy[i-1] = temp;
flag = 1;
}
}
} while(flag);
return listCopy;
}
void Sys_FreeFileList( char **psList ) {
int i;
if ( !psList ) {
return;
}
for ( i = 0 ; psList[i] ; i++ ) {
Z_Free( psList[i] );
}
Z_Free( psList );
}
//========================================================
/*
================
Sys_ScanForCD
Search all the drives to see if there is a valid CD to grab
the cddir from
================
*/
#ifdef FINAL_BUILD
static qboolean Sys_ScanForCD( void ) {
char drive[4];
FILE *f;
char test[MAX_OSPATH];
drive[0] = 'c';
drive[1] = ':';
drive[2] = '\\';
drive[3] = 0;
// scan the drives
for ( drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++ ) {
if ( GetDriveType (drive) == DRIVE_CDROM ) {
BOOL Result;
char VolumeName[MAX_PATH],FileSystemName[MAX_PATH];
DWORD VolumeSerialNumber,MaximumComponentLength,FileSystemFlags;
Result = GetVolumeInformation(drive,VolumeName,sizeof(VolumeName),&VolumeSerialNumber,
&MaximumComponentLength,&FileSystemFlags,FileSystemName,sizeof(FileSystemName));
if (Result && (strcmpi(VolumeName,"JEDIOUTCAST") == 0 ) )
{
sprintf (test, "%s%s\\%s",drive, CD_BASEDIR, CD_EXE);
f = fopen( test, "r" );
if ( f ) {
fclose (f);
return qtrue;
} else {
sprintf(test, "%s%s\\%s", drive, CD_BASEDIR, CD_EXE_LINUX);
f = fopen( test, "r" );
if ( f ) {
fclose (f);
return qtrue;
}
}
}
}
}
return qfalse;
}
#endif
/*
================
Sys_CheckCD
Return true if the proper CD is in the drive
================
*/
qboolean Sys_CheckCD( void ) {
#ifdef FINAL_BUILD
return Sys_ScanForCD();
#else
return qtrue;
#endif
}
/*
================
Sys_GetClipboardData
================
*/
char *Sys_GetClipboardData( void ) {
char *data = NULL;
char *cliptext;
if ( OpenClipboard( NULL ) != 0 ) {
HANDLE hClipboardData;
if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
if ( ( cliptext = (char *)GlobalLock( hClipboardData ) ) != 0 ) {
data = (char *)Z_Malloc( GlobalSize( hClipboardData ) + 1, TAG_CLIPBOARD);
Q_strncpyz( data, cliptext, GlobalSize( hClipboardData )+1 );
GlobalUnlock( hClipboardData );
strtok( data, "\n\r\b" );
}
}
CloseClipboard();
}
return data;
}
/*
========================================================================
LOAD/UNLOAD DLL
========================================================================
*/
/*
=================
Sys_UnloadDll
=================
*/
void Sys_UnloadDll( void *dllHandle ) {
if ( !dllHandle ) {
return;
}
if ( !FreeLibrary( (struct HINSTANCE__ *)dllHandle ) ) {
Com_Error (ERR_FATAL, "Sys_UnloadDll FreeLibrary failed");
}
}
/*
=================
Sys_LoadDll
Used to load a development dll instead of a virtual machine
=================
*/
extern char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
void * QDECL Sys_LoadDll( const char *name, int (QDECL **entryPoint)(int, ...),
int (QDECL *systemcalls)(int, ...) ) {
static int lastWarning = 0;
HINSTANCE libHandle;
void (QDECL *dllEntry)( int (QDECL *syscallptr)(int, ...) );
char *basepath;
char *cdpath;
char *gamedir;
char *fn;
#ifdef NDEBUG
int timestamp;
int ret;
#endif
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "%sx86.dll", name );
#ifdef NDEBUG
timestamp = Sys_Milliseconds();
if( ((timestamp - lastWarning) > (5 * 60000)) && !Cvar_VariableIntegerValue( "dedicated" )
&& !Cvar_VariableIntegerValue( "com_blindlyLoadDLLs" ) ) {
if (FS_FileExists(filename)) {
lastWarning = timestamp;
ret = MessageBoxEx( NULL, "You are about to load a .DLL executable that\n"
"has not been verified for use with Quake III Arena.\n"
"This type of file can compromise the security of\n"
"your computer.\n\n"
"Select 'OK' if you choose to load it anyway.",
"Security Warning", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) );
if( ret != IDOK ) {
return NULL;
}
}
}
#endif
// rjr disable for final release #ifndef NDEBUG
libHandle = LoadLibrary( filename );
if ( !libHandle ) {
//#endif
basepath = Cvar_VariableString( "fs_basepath" );
cdpath = Cvar_VariableString( "fs_cdpath" );
gamedir = Cvar_VariableString( "fs_game" );
fn = FS_BuildOSPath( basepath, gamedir, filename );
libHandle = LoadLibrary( fn );
if ( !libHandle ) {
if( cdpath[0] ) {
fn = FS_BuildOSPath( cdpath, gamedir, filename );
libHandle = LoadLibrary( fn );
}
if ( !libHandle ) {
return NULL;
}
}
//#ifndef NDEBUG
}
//#endif
dllEntry = ( void (QDECL *)( int (QDECL *)( int, ... ) ) )GetProcAddress( libHandle, "dllEntry" );
*entryPoint = (int (QDECL *)(int,...))GetProcAddress( libHandle, "vmMain" );
if ( !*entryPoint || !dllEntry ) {
FreeLibrary( libHandle );
return NULL;
}
dllEntry( systemcalls );
return libHandle;
}
/*
========================================================================
BACKGROUND FILE STREAMING
========================================================================
*/
#if 1
void Sys_InitStreamThread( void ) {
}
void Sys_ShutdownStreamThread( void ) {
}
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
}
void Sys_EndStreamedFile( fileHandle_t f ) {
}
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
return FS_Read( buffer, size * count, f );
}
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
FS_Seek( f, offset, origin );
}
#else
typedef struct {
fileHandle_t file;
byte *buffer;
qboolean eof;
qboolean active;
int bufferSize;
int streamPosition; // next byte to be returned by Sys_StreamRead
int threadPosition; // next byte to be read from file
} streamsIO_t;
typedef struct {
HANDLE threadHandle;
int threadId;
CRITICAL_SECTION crit;
streamsIO_t sIO[MAX_FILE_HANDLES];
} streamState_t;
streamState_t stream;
/*
===============
Sys_StreamThread
A thread will be sitting in this loop forever
================
*/
void Sys_StreamThread( void ) {
int buffer;
int count;
int readCount;
int bufferPoint;
int r, i;
while (1) {
Sleep( 10 );
// EnterCriticalSection (&stream.crit);
for (i=1;i<MAX_FILE_HANDLES;i++) {
// if there is any space left in the buffer, fill it up
if ( stream.sIO[i].active && !stream.sIO[i].eof ) {
count = stream.sIO[i].bufferSize - (stream.sIO[i].threadPosition - stream.sIO[i].streamPosition);
if ( !count ) {
continue;
}
bufferPoint = stream.sIO[i].threadPosition % stream.sIO[i].bufferSize;
buffer = stream.sIO[i].bufferSize - bufferPoint;
readCount = buffer < count ? buffer : count;
r = FS_Read( stream.sIO[i].buffer + bufferPoint, readCount, stream.sIO[i].file );
stream.sIO[i].threadPosition += r;
if ( r != readCount ) {
stream.sIO[i].eof = qtrue;
}
}
}
// LeaveCriticalSection (&stream.crit);
}
}
/*
===============
Sys_InitStreamThread
================
*/
void Sys_InitStreamThread( void ) {
int i;
InitializeCriticalSection ( &stream.crit );
// don't leave the critical section until there is a
// valid file to stream, which will cause the StreamThread
// to sleep without any overhead
// EnterCriticalSection( &stream.crit );
stream.threadHandle = CreateThread(
NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)Sys_StreamThread, // LPTHREAD_START_ROUTINE lpStartAddr,
0, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&stream.threadId);
for(i=0;i<MAX_FILE_HANDLES;i++) {
stream.sIO[i].active = qfalse;
}
}
/*
===============
Sys_ShutdownStreamThread
================
*/
void Sys_ShutdownStreamThread( void ) {
}
/*
===============
Sys_BeginStreamedFile
================
*/
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
if ( stream.sIO[f].file ) {
Sys_EndStreamedFile( stream.sIO[f].file );
}
stream.sIO[f].file = f;
stream.sIO[f].buffer = Z_Malloc( readAhead );
stream.sIO[f].bufferSize = readAhead;
stream.sIO[f].streamPosition = 0;
stream.sIO[f].threadPosition = 0;
stream.sIO[f].eof = qfalse;
stream.sIO[f].active = qtrue;
// let the thread start running
// LeaveCriticalSection( &stream.crit );
}
/*
===============
Sys_EndStreamedFile
================
*/
void Sys_EndStreamedFile( fileHandle_t f ) {
if ( f != stream.sIO[f].file ) {
Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file");
}
// don't leave critical section until another stream is started
EnterCriticalSection( &stream.crit );
stream.sIO[f].file = 0;
stream.sIO[f].active = qfalse;
Z_Free( stream.sIO[f].buffer );
LeaveCriticalSection( &stream.crit );
}
/*
===============
Sys_StreamedRead
================
*/
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
int available;
int remaining;
int sleepCount;
int copy;
int bufferCount;
int bufferPoint;
byte *dest;
if (stream.sIO[f].active == qfalse) {
Com_Error( ERR_FATAL, "Streamed read with non-streaming file" );
}
dest = (byte *)buffer;
remaining = size * count;
if ( remaining <= 0 ) {
Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
}
sleepCount = 0;
while ( remaining > 0 ) {
available = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition;
if ( !available ) {
if ( stream.sIO[f].eof ) {
break;
}
if ( sleepCount == 1 ) {
Com_DPrintf( "Sys_StreamedRead: waiting\n" );
}
if ( ++sleepCount > 100 ) {
Com_Error( ERR_FATAL, "Sys_StreamedRead: thread has died");
}
Sleep( 10 );
continue;
}
EnterCriticalSection( &stream.crit );
bufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize;
bufferCount = stream.sIO[f].bufferSize - bufferPoint;
copy = available < bufferCount ? available : bufferCount;
if ( copy > remaining ) {
copy = remaining;
}
memcpy( dest, stream.sIO[f].buffer + bufferPoint, copy );
stream.sIO[f].streamPosition += copy;
dest += copy;
remaining -= copy;
LeaveCriticalSection( &stream.crit );
}
return (count * size - remaining) / size;
}
/*
===============
Sys_StreamSeek
================
*/
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
// halt the thread
EnterCriticalSection( &stream.crit );
// clear to that point
FS_Seek( f, offset, origin );
stream.sIO[f].streamPosition = 0;
stream.sIO[f].threadPosition = 0;
stream.sIO[f].eof = qfalse;
// let the thread start running at the new position
LeaveCriticalSection( &stream.crit );
}
#endif
/*
========================================================================
EVENT LOOP
========================================================================
*/
#define MAX_QUED_EVENTS 256
#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
sysEvent_t eventQue[MAX_QUED_EVENTS];
static int eventHead=0;
static int eventTail=0;
byte sys_packetReceived[MAX_MSGLEN];
/*
================
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.
================
*/
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
sysEvent_t *ev;
ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
Com_Printf("Sys_QueEvent: overflow\n");
// we are discarding an event, but don't leak memory
if ( ev->evPtr ) {
Z_Free( ev->evPtr );
}
eventTail++;
}
eventHead++;
if ( time == 0 ) {
time = Sys_Milliseconds();
}
ev->evTime = time;
ev->evType = type;
ev->evValue = value;
ev->evValue2 = value2;
ev->evPtrLength = ptrLength;
ev->evPtr = ptr;
}
/*
================
Sys_GetEvent
================
*/
sysEvent_t Sys_GetEvent( void ) {
MSG msg;
sysEvent_t ev;
char *s;
msg_t netmsg;
netadr_t adr;
// return if we have data
if ( eventHead > eventTail ) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// pump the message loop
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
if ( !GetMessage (&msg, NULL, 0, 0) ) {
Com_Quit_f();
}
// save the msg time, because wndprocs don't have access to the timestamp
// g_wv.sysMsgTime = msg.time;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// check for console commands
s = Sys_ConsoleInput();
if ( s ) {
char *b;
int len;
len = strlen( s ) + 1;
b = (char *)Z_Malloc( len, TAG_EVENT );
Q_strncpyz( b, s, len );
Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
}
// check for network packets
MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
if ( Sys_GetPacket ( &adr, &netmsg ) ) {
netadr_t *buf;
int len;
// copy out to a seperate buffer for qeueing
// the readcount stepahead is for SOCKS support
len = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount;
buf = (netadr_t *)Z_Malloc( len, TAG_EVENT, qtrue );
*buf = adr;
memcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );
Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
}
// return if we have data
if ( eventHead > eventTail ) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// create an empty event to return
memset( &ev, 0, sizeof( ev ) );
ev.evTime = timeGetTime();
return ev;
}
//================================================================
/*
=================
Sys_In_Restart_f
Restart the input subsystem
=================
*/
void Sys_In_Restart_f( void ) {
IN_Shutdown();
IN_Init();
}
/*
=================
Sys_Net_Restart_f
Restart the network subsystem
=================
*/
void Sys_Net_Restart_f( void ) {
NET_Restart();
}
/*
================
Sys_Init
Called after the common systems (cvars, files, etc)
are initialized
================
*/
#define OSR2_BUILD_NUMBER 1111
#define WIN98_BUILD_NUMBER 1998
void Sys_Init( void ) {
int cpuid;
// make sure the timer is high precision, otherwise
// NT gets 18ms resolution
timeBeginPeriod( 1 );
Cmd_AddCommand ("in_restart", Sys_In_Restart_f);
Cmd_AddCommand ("net_restart", Sys_Net_Restart_f);
// g_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion );
// if (!GetVersionEx (&g_wv.osversion))
// Sys_Error ("Couldn't get OS info");
// if (g_wv.osversion.dwMajorVersion < 4)
// Sys_Error ("This game requires Windows version 4 or greater");
// if (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s)
// Sys_Error ("This game doesn't run on Win32s");
// if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT )
// {
// Cvar_Set( "arch", "winnt" );
// }
// else if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
// {
// if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER )
// {
// Cvar_Set( "arch", "win98" );
// }
// else if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
// {
// Cvar_Set( "arch", "win95 osr2.x" );
// }
// else
// {
// Cvar_Set( "arch", "win95" );
// }
// }
// else
// {
// Cvar_Set( "arch", "unknown Windows variant" );
// }
// save out a couple things in rom cvars for the renderer to access
// Cvar_Get( "win_hinstance", va("%i", (int)g_wv.hInstance), CVAR_ROM );
// Cvar_Get( "win_wndproc", va("%i", (int)MainWndProc), CVAR_ROM );
//
// figure out our CPU
//
Cvar_Get( "sys_cpustring", "detect", 0 );
if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring"), "detect" ) )
{
Com_Printf( "...detecting CPU, found " );
cpuid = Sys_GetProcessorId();
switch ( cpuid )
{
case CPUID_GENERIC:
Cvar_Set( "sys_cpustring", "generic" );
break;
case CPUID_INTEL_UNSUPPORTED:
Cvar_Set( "sys_cpustring", "x86 (pre-Pentium)" );
break;
case CPUID_INTEL_PENTIUM:
Cvar_Set( "sys_cpustring", "x86 (P5/PPro, non-MMX)" );
break;
case CPUID_INTEL_MMX:
Cvar_Set( "sys_cpustring", "x86 (P5/Pentium2, MMX)" );
break;
case CPUID_INTEL_KATMAI:
Cvar_Set( "sys_cpustring", "Intel Pentium III" );
break;
case CPUID_INTEL_WILLIAMETTE:
Cvar_Set( "sys_cpustring", "Intel Pentium IV" );
break;
case CPUID_AMD_3DNOW:
Cvar_Set( "sys_cpustring", "AMD w/ 3DNow!" );
break;
case CPUID_AXP:
Cvar_Set( "sys_cpustring", "Alpha AXP" );
break;
default:
Com_Error( ERR_FATAL, "Unknown cpu type %d\n", cpuid );
break;
}
}
else
{
Com_Printf( "...forcing CPU type to " );
if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "generic" ) )
{
cpuid = CPUID_GENERIC;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "x87" ) )
{
cpuid = CPUID_INTEL_PENTIUM;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "mmx" ) )
{
cpuid = CPUID_INTEL_MMX;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "3dnow" ) )
{
cpuid = CPUID_AMD_3DNOW;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIII" ) )
{
cpuid = CPUID_INTEL_KATMAI;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIV" ) )
{
cpuid = CPUID_INTEL_WILLIAMETTE;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "axp" ) )
{
cpuid = CPUID_AXP;
}
else
{
Com_Printf( "WARNING: unknown sys_cpustring '%s'\n", Cvar_VariableString( "sys_cpustring" ) );
cpuid = CPUID_GENERIC;
}
}
Cvar_SetValue( "sys_cpuid", cpuid );
Com_Printf( "%s\n", Cvar_VariableString( "sys_cpustring" ) );
Cvar_Set( "username", Sys_GetCurrentUser() );
IN_Init(); // FIXME: not in dedicated?
}
//=======================================================================
//int totalMsec, countMsec;
/*
==================
WinMain
==================
*/
//int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
int main(int argc, char **argv)
{
char cwd[MAX_OSPATH];
char *cmdline;
int i,len;
// int startTime, endTime;
// should never get a previous instance in Win32
// if ( hPrevInstance ) {
// return 0;
// }
// sys_checksum = Sys_CodeInMemoryChecksum( hInstance );
// Sys_VerifyCodeChecksum( hInstance );
// merge the command line, this is kinda silly
for (len = 1, i = 1; i < argc; i++)
len += strlen(argv[i]) + 1;
cmdline = (char *)malloc(len);
*cmdline = 0;
for (i = 1; i < argc; i++) {
if (i > 1)
strcat(cmdline, " ");
strcat(cmdline, argv[i]);
}
// g_wv.hInstance = hInstance;
// Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
// done before Com/Sys_Init since we need this for error output
// Sys_CreateConsole();
// no abort/retry/fail errors
SetErrorMode( SEM_FAILCRITICALERRORS );
// get the initial time base
Sys_Milliseconds();
#if 0
// if we find the CD, add a +set cddir xxx command line
Sys_ScanForCD();
#endif
Sys_InitStreamThread();
#if 0
CheckProcessTime();
#endif
Com_Init( cmdline );
#if 0
Cvar_Set( "com_othertasks", ( otherTasksRunning ? "1" : "0" ) );
Cvar_Set( "com_othertaskstime", va("%u", otherTaskTime) );
#else
Cvar_Set( "com_othertasks", "0" );
#endif
NET_Init();
_getcwd (cwd, sizeof(cwd));
Com_Printf("Working directory: %s\n", cwd);
// hide the early console since we've reached the point where we
// have a working graphics subsystems
if ( !com_dedicated->integer && !com_viewlog->integer ) {
Sys_ShowConsole( 0, qfalse );
}
#ifdef _DEBUG
if ( sys_monkeySpank ) {
Cvar_Set("cl_trn", "666");
}
#endif
// main game loop
while( 1 ) {
// if not running as a game client, sleep a bit
// if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {
Sleep( 5 );
// }
// set low precision every frame, because some system calls
// reset it arbitrarily
// _controlfp( _PC_24, _MCW_PC );
// startTime = Sys_Milliseconds();
// make sure mouse and joystick are only called once a frame
IN_Frame();
// run the game
Com_Frame();
// endTime = Sys_Milliseconds();
// totalMsec += endTime - startTime;
// countMsec++;
}
// never gets here
return 0;
}