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/engine/host.c

659 lines
14 KiB
C
Raw Normal View History

2007-06-21 22:00:00 +02:00
//=======================================================================
// Copyright XashXT Group 2007 <20>
// host.c - dedicated and shared host
//=======================================================================
#include <setjmp.h>
#include "engine.h"
2007-11-17 22:00:00 +01:00
#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ))
2007-11-24 22:00:00 +01:00
physic_exp_t *pe;
2007-11-17 22:00:00 +01:00
render_exp_t *re;
2007-09-03 22:00:00 +02:00
host_parm_t host; // host parms
2007-11-18 22:00:00 +01:00
stdlib_api_t std, newstd;
2007-06-21 22:00:00 +02:00
byte *zonepool;
2007-09-11 22:00:00 +02:00
char *buildstring = __TIME__ " " __DATE__;
2007-09-02 22:00:00 +02:00
2007-11-18 22:00:00 +01:00
//void Key_Init (void);
2007-06-21 22:00:00 +02:00
2007-11-08 22:00:00 +01:00
dll_info_t physic_dll = { "physic.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(physic_exp_t) };
2007-11-17 22:00:00 +01:00
dll_info_t render_dll = { "render.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(render_exp_t) };
2007-06-21 22:00:00 +02:00
cvar_t *timescale;
cvar_t *fixedtime;
2007-11-14 22:00:00 +01:00
cvar_t *dedicated;
cvar_t *host_serverstate;
cvar_t *host_frametime;
2007-11-18 22:00:00 +01:00
cvar_t *r_fullscreen;
2007-11-17 22:00:00 +01:00
cvar_t *vid_gamma;
cvar_t *r_xpos; // X coordinate of window position
cvar_t *r_ypos; // Y coordinate of window position
/*
=======
Host_MapKey
Map from windows to engine keynums
=======
*/
static int Host_MapKey( int key )
{
int result, modified;
bool is_extended = false;
modified = ( key >> 16 ) & 255;
if( modified > 127 ) return 0;
if ( key & ( 1 << 24 ))
is_extended = true;
result = scan_to_key[modified];
if( !is_extended )
{
switch ( result )
{
case K_HOME: return K_KP_HOME;
case K_UPARROW: return K_KP_UPARROW;
case K_PGUP: return K_KP_PGUP;
case K_LEFTARROW: return K_KP_LEFTARROW;
case K_RIGHTARROW: return K_KP_RIGHTARROW;
case K_END: return K_KP_END;
case K_DOWNARROW: return K_KP_DOWNARROW;
case K_PGDN: return K_KP_PGDN;
case K_INS: return K_KP_INS;
case K_DEL: return K_KP_DEL;
default: return result;
}
}
else
{
switch ( result )
{
case K_PAUSE: return K_KP_NUMLOCK;
case 0x0D: return K_KP_ENTER;
case 0x2F: return K_KP_SLASH;
case 0xAF: return K_KP_PLUS;
}
return result;
}
}
2007-06-21 22:00:00 +02:00
2007-11-18 22:00:00 +01:00
void Host_InitCommon( uint funcname, int argc, char **argv )
2007-06-21 22:00:00 +02:00
{
2007-11-18 22:00:00 +01:00
newstd = std;
2007-10-22 22:00:00 +02:00
2007-11-10 22:00:00 +01:00
// overload some funcs
2007-11-18 22:00:00 +01:00
newstd.print = Host_Print;
newstd.printf = Host_Printf;
newstd.dprintf = Host_DPrintf;
newstd.wprintf = Host_DWarnf;
newstd.Com_AddCommand = Cmd_AddCommand;
newstd.Com_DelCommand = Cmd_RemoveCommand;
newstd.Com_Argc = Cmd_Argc;
newstd.Com_Argv = Cmd_Argv;
newstd.Com_AddText = Cbuf_AddText;
newstd.Com_GetCvar = _Cvar_Get;
newstd.Com_CvarSetValue = Cvar_SetValue;
newstd.Com_CvarSetString = Cvar_Set;
newstd.error = Host_Error;
2007-09-13 22:00:00 +02:00
// TODO: init basedir here
2007-11-10 22:00:00 +01:00
FS_LoadGameInfo("gameinfo.txt");
2007-06-21 22:00:00 +02:00
zonepool = Mem_AllocPool("Zone Engine");
}
2007-09-13 22:00:00 +02:00
void Host_FreeCommon( void )
2007-06-21 22:00:00 +02:00
{
2007-11-11 22:00:00 +01:00
Mem_FreePool( &zonepool );
2007-06-21 22:00:00 +02:00
}
2007-10-22 22:00:00 +02:00
void Host_InitPhysic( void )
{
static physic_imp_t pi;
2007-11-17 22:00:00 +01:00
launch_t CreatePhysic;
2007-10-22 22:00:00 +02:00
2007-10-27 22:00:00 +02:00
// phys callback
2007-11-11 22:00:00 +01:00
pi.api_size = sizeof(physic_imp_t);
2007-10-27 22:00:00 +02:00
pi.Transform = SV_Transform;
2007-10-22 22:00:00 +02:00
Sys_LoadLibrary( &physic_dll );
2007-11-17 22:00:00 +01:00
CreatePhysic = (void *)physic_dll.main;
2007-11-24 22:00:00 +01:00
pe = CreatePhysic( &newstd, &pi );
2007-10-22 22:00:00 +02:00
2007-11-24 22:00:00 +01:00
pe->Init();
2007-10-22 22:00:00 +02:00
}
void Host_FreePhysic( void )
{
if(physic_dll.link)
{
2007-11-24 22:00:00 +01:00
pe->Shutdown();
memset( &pe, 0, sizeof(pe));
2007-10-22 22:00:00 +02:00
}
Sys_FreeLibrary( &physic_dll );
}
2007-11-17 22:00:00 +01:00
void Host_InitRender( void )
{
static render_imp_t ri;
launch_t CreateRender;
ri.api_size = sizeof(render_imp_t);
// studio callbacks
ri.StudioEvent = CL_StudioEvent;
2007-11-24 22:00:00 +01:00
ri.ShowCollision = pe->ShowCollision;
2007-11-17 22:00:00 +01:00
Sys_LoadLibrary( &render_dll );
CreateRender = (void *)render_dll.main;
2007-11-18 22:00:00 +01:00
re = CreateRender( &newstd, &ri );
2007-11-17 22:00:00 +01:00
if(!re->Init(GetModuleHandle(NULL), Host_WndProc ))
Sys_Error("VID_InitRender: can't init render.dll\nUpdate your opengl drivers\n");
CL_Snd_Restart_f();
}
void Host_FreeRender( void )
{
if(render_dll.link)
{
re->Shutdown();
memset( &re, 0, sizeof(re));
}
Sys_FreeLibrary( &render_dll );
}
2007-09-10 22:00:00 +02:00
/*
================
Host_AbortCurrentFrame
aborts the current host frame and goes on with the next one
================
*/
void Host_AbortCurrentFrame( void )
{
longjmp(host.abortframe, 1);
}
2007-11-14 22:00:00 +01:00
/*
==================
Host_GetServerState
==================
*/
int Host_ServerState( void )
{
return host_serverstate->integer;
}
/*
==================
Host_SetServerState
==================
*/
void Host_SetServerState( int state )
{
Cvar_SetValue("host_serverstate", state );
}
2007-06-21 22:00:00 +02:00
/*
=================
2007-11-17 22:00:00 +01:00
Host_VidRestart_f
Restart the video subsystem
2007-06-21 22:00:00 +02:00
=================
*/
2007-11-17 22:00:00 +01:00
void Host_VidRestart_f( void )
2007-06-21 22:00:00 +02:00
{
2007-11-17 22:00:00 +01:00
cl.force_refdef = true; // can't use a paused refdef
S_StopAllSounds(); // don't let them loop during the restart
cl.refresh_prepped = false;
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Host_FreeRender(); // release render.dll
Host_InitRender(); // load it again
}
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
/*
============
VID_Init
============
*/
void VID_Init( void )
{
2007-11-18 22:00:00 +01:00
scr_width = Cvar_Get("width", "640", 0 );
scr_height = Cvar_Get("height", "480", 0 );
2007-11-17 22:00:00 +01:00
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
Cmd_AddCommand ("vid_restart", Host_VidRestart_f, "restarts video system" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Host_InitRender();
}
2007-06-21 22:00:00 +02:00
/*
=================
Host_Frame
=================
*/
2007-11-17 22:00:00 +01:00
void Host_Frame( double time )
2007-06-21 22:00:00 +02:00
{
2007-09-10 22:00:00 +02:00
char *s;
2007-06-21 22:00:00 +02:00
2007-11-18 22:00:00 +01:00
if(setjmp(host.abortframe)) return;
2007-06-21 22:00:00 +02:00
2007-09-11 22:00:00 +02:00
rand(); // keep the random time dependent
2007-11-14 22:00:00 +01:00
Sys_SendKeyEvents(); // get new key events
2007-10-29 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
do
{
s = Sys_ConsoleInput ();
2007-09-11 22:00:00 +02:00
if(s) Cbuf_AddText (va("%s\n",s));
2007-11-14 22:00:00 +01:00
} while( s );
2007-11-11 22:00:00 +01:00
Cbuf_Execute();
2007-09-06 22:00:00 +02:00
2007-10-29 22:00:00 +01:00
// if at a full screen console, don't update unless needed
2007-11-18 22:00:00 +01:00
if( host.state != HOST_FRAME || host.type == HOST_DEDICATED )
2007-10-29 22:00:00 +01:00
{
2007-11-18 22:00:00 +01:00
Sys_Sleep( 20 );
2007-10-29 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
SV_Frame (time);
CL_Frame (time);
2007-09-07 22:00:00 +02:00
host.framecount++;
2007-06-21 22:00:00 +02:00
}
/*
2007-11-17 22:00:00 +01:00
====================
2007-11-18 22:00:00 +01:00
Host_WndProc
2007-11-17 22:00:00 +01:00
main window procedure
====================
2007-06-21 22:00:00 +02:00
*/
2007-11-17 22:00:00 +01:00
long _stdcall Host_WndProc( HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam)
2007-06-21 22:00:00 +02:00
{
2007-11-18 22:00:00 +01:00
int temp = 0;
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
switch (uMsg)
2007-06-21 22:00:00 +02:00
{
2007-11-17 22:00:00 +01:00
case WM_MOUSEWHEEL:
2007-11-18 22:00:00 +01:00
if((short)HIWORD(wParam) > 0)
2007-11-17 22:00:00 +01:00
{
2007-11-18 22:00:00 +01:00
Key_Event( K_MWHEELUP, true, host.sv_timer );
Key_Event( K_MWHEELUP, false, host.sv_timer );
}
else
{
Key_Event( K_MWHEELDOWN, true, host.sv_timer );
Key_Event( K_MWHEELDOWN, false, host.sv_timer );
2007-11-17 22:00:00 +01:00
}
break;
case WM_CREATE:
host.hWnd = hWnd;
2007-11-18 22:00:00 +01:00
r_xpos = Cvar_Get("r_xpos", "3", CVAR_ARCHIVE );
r_ypos = Cvar_Get("r_ypos", "22", CVAR_ARCHIVE );
r_fullscreen = Cvar_Get("fullscreen", "0", CVAR_ARCHIVE | CVAR_LATCH );
2007-11-17 22:00:00 +01:00
break;
case WM_DESTROY:
host.hWnd = NULL;
break;
case WM_CLOSE:
Cbuf_ExecuteText( EXEC_APPEND, "quit" );
break;
case WM_ACTIVATE:
2007-11-18 22:00:00 +01:00
if(LOWORD(wParam) != WA_INACTIVE && HIWORD(wParam)) host.state = HOST_SLEEP;
else if(LOWORD(wParam) == WA_INACTIVE) host.state = HOST_NOFOCUS;
else host.state = HOST_FRAME;
Key_ClearStates(); // FIXME!!!
2007-11-17 22:00:00 +01:00
SNDDMA_Activate();
2007-11-18 22:00:00 +01:00
if( host.state == HOST_FRAME )
{
M_Activate();
SetForegroundWindow( hWnd );
ShowWindow( hWnd, SW_RESTORE );
}
else if( r_fullscreen->integer )
{
ShowWindow( hWnd, SW_MINIMIZE );
}
2007-11-17 22:00:00 +01:00
break;
case WM_MOVE:
if (!r_fullscreen->integer )
{
RECT r;
int xPos, yPos, style;
xPos = (short) LOWORD(lParam); // horizontal position
yPos = (short) HIWORD(lParam); // vertical position
r.left = r.top = 0;
r.right = r.bottom = 1;
style = GetWindowLong( hWnd, GWL_STYLE );
AdjustWindowRect( &r, style, FALSE );
Cvar_SetValue( "r_xpos", xPos + r.left);
Cvar_SetValue( "r_ypos", yPos + r.top);
r_xpos->modified = false;
r_ypos->modified = false;
2007-11-18 22:00:00 +01:00
M_Activate();
2007-11-17 22:00:00 +01:00
}
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MOUSEMOVE:
if(wParam & MK_LBUTTON) temp |= 1;
if(wParam & MK_RBUTTON) temp |= 2;
if(wParam & MK_MBUTTON) temp |= 4;
2007-11-18 22:00:00 +01:00
M_Event( temp );
2007-11-17 22:00:00 +01:00
break;
case WM_SYSCOMMAND:
if( wParam == SC_SCREENSAVE ) return 0;
break;
case WM_SYSKEYDOWN:
2007-11-18 22:00:00 +01:00
if( wParam == 13 && r_fullscreen)
2007-11-17 22:00:00 +01:00
{
2007-11-18 22:00:00 +01:00
Cvar_SetValue( "fullscreen", !r_fullscreen->value );
2007-11-17 22:00:00 +01:00
return 0;
}
// intentional fallthrough
case WM_KEYDOWN:
Key_Event( Host_MapKey( lParam ), true, host.sv_timer);
break;
case WM_SYSKEYUP:
case WM_KEYUP:
Key_Event( Host_MapKey( lParam ), false, host.sv_timer);
break;
case WM_CHAR:
CL_CharEvent( wParam );
break;
2007-06-21 22:00:00 +02:00
}
2007-11-17 22:00:00 +01:00
return DefWindowProc( hWnd, uMsg, wParam, lParam );
2007-06-21 22:00:00 +02:00
}
2007-11-14 22:00:00 +01:00
/*
================
Host_Print
Handles cursor positioning, line wrapping, etc
All console printing must go through this in order to be logged to disk
If no console is visible, the text will appear at the top of the game window
================
*/
void Host_Print( const char *txt )
{
if(host.rd.target)
{
if((strlen (txt) + strlen(host.rd.buffer)) > (host.rd.buffersize - 1))
{
if(host.rd.flush)
{
host.rd.flush(host.rd.target, host.rd.buffer);
*host.rd.buffer = 0;
}
}
strcat (host.rd.buffer, txt);
return;
}
Con_Print( txt ); // echo to client console
Sys_Print( txt ); // echo to system console
// sys print also stored messages into system log
}
/*
=============
Host_Printf
Both client and server can use this, and it will output
to the apropriate place.
=============
*/
void Host_Printf( const char *fmt, ... )
{
va_list argptr;
char msg[MAX_INPUTLINE];
va_start( argptr, fmt );
vsprintf( msg, fmt, argptr );
va_end( argptr );
Host_Print( msg );
}
/*
================
Host_DPrintf
A Msg that only shows up in developer mode
================
*/
void Host_DPrintf( int level, const char *fmt, ... )
{
va_list argptr;
char msg[MAX_INPUTLINE];
// don't confuse non-developers with techie stuff...
if(host.developer < level) return;
va_start( argptr, fmt );
vsprintf( msg, fmt, argptr );
va_end( argptr );
switch(level)
{
case D_INFO:
Host_Print( msg );
break;
case D_WARN:
Host_Print(va("^3Warning:^7 %s", msg));
break;
case D_ERROR:
Host_Print(va("^1Error:^7 %s", msg));
break;
case D_LOAD:
Host_Print(va("^2Loading: ^7%s", msg));
break;
case D_NOTE:
Host_Print( msg );
break;
case D_MEMORY:
Host_Print(va("^6Mem: ^7%s", msg));
break;
}
}
/*
================
Host_DWarnf
A Warning that only shows up in debug mode
================
*/
void Host_DWarnf( const char *fmt, ... )
{
va_list argptr;
char msg[MAX_INPUTLINE];
// don't confuse non-developers with techie stuff...
if (!host.debug) return;
va_start( argptr, fmt );
vsprintf( msg, fmt, argptr );
va_end( argptr );
Host_Print(va("^3Warning:^7 %s", msg));
}
2007-09-10 22:00:00 +02:00
/*
=================
Host_Error
=================
*/
void Host_Error( const char *error, ... )
{
static char hosterror1[MAX_INPUTLINE];
static char hosterror2[MAX_INPUTLINE];
static bool recursive = false;
va_list argptr;
va_start( argptr, error );
vsprintf( hosterror1, error, argptr );
va_end( argptr );
2007-11-21 22:00:00 +01:00
if( host.framecount < 3 || host.state == HOST_SHUTDOWN )
2007-09-10 22:00:00 +02:00
Sys_Error ("%s", hosterror1 );
2007-11-14 22:00:00 +01:00
else Host_Printf("Host_Error: %s", hosterror1);
2007-09-10 22:00:00 +02:00
if(recursive)
{
2007-11-21 22:00:00 +01:00
Msg("Host_RecursiveError: %s", hosterror2 );
Sys_Error ("%s", hosterror1 );
return; // don't multiple executes
2007-09-10 22:00:00 +02:00
}
2007-11-21 22:00:00 +01:00
2007-09-10 22:00:00 +02:00
recursive = true;
2007-11-21 22:00:00 +01:00
sprintf( host.finalmsg, "Server crashed: %s\n", hosterror1 );
std.strncpy( host.finalmsg, "Server shutdown\n", MAX_STRING );
2007-09-10 22:00:00 +02:00
2007-11-21 22:00:00 +01:00
SV_Shutdown( false );
2007-09-10 22:00:00 +02:00
CL_Drop(); // drop clients
recursive = false;
Host_AbortCurrentFrame();
2007-09-22 22:00:00 +02:00
host.state = HOST_ERROR;
2007-09-10 22:00:00 +02:00
}
void Host_Error_f( void )
{
2007-11-17 22:00:00 +01:00
if( Cmd_Argc() == 1 ) Sys_Error( "break\n" );
else Sys_Error( "%s\n", Cmd_Argv( 1 ));
}
/*
=================
Host_Crash_f
=================
*/
static void Host_Crash_f (void)
{
*(int *)0 = 0xffffffff;
}
/*
=================
Host_Init
=================
*/
void Host_Init (uint funcname, int argc, char **argv)
{
char *s;
host.state = HOST_INIT; // initialzation started
host.type = funcname;
srand(time(NULL)); // init random generator
Host_InitCommon( funcname, argc, argv ); // loading common.dll
Cmd_Init( argc, argv );
Cvar_Init();
Key_Init();
PRVM_Init();
// get default configuration
#if 1
Cbuf_AddText("exec keys.rc\n");
Cbuf_AddText("exec vars.rc\n");
#else
Cbuf_AddText("exec default.cfg\n");
Cbuf_AddText("exec config.cfg\n");
#endif
Cbuf_Execute();
// init commands and vars
if(host.developer)
{
Cmd_AddCommand ("error", Host_Error_f, "just throw a fatal error to test shutdown procedures" );
Cmd_AddCommand ("crash", Host_Crash_f, "a way to force a bus error for development reasons");
}
host_frametime = Cvar_Get ("host_frametime", "0.01", 0);
host_serverstate = Cvar_Get ("host_serverstate", "0", 0);
timescale = Cvar_Get ("timescale", "1", 0);
fixedtime = Cvar_Get ("fixedtime", "0", 0);
if(host.type == HOST_DEDICATED) dedicated = Cvar_Get ("dedicated", "1", CVAR_INIT);
else dedicated = Cvar_Get ("dedicated", "0", CVAR_INIT);
s = va("^1Xash %g ^3%s", XASH_VERSION, buildstring );
Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_INIT);
if(dedicated->value) Cmd_AddCommand ("quit", Sys_Quit, "quit the game" );
NET_Init();
Netchan_Init();
Host_InitPhysic();
SV_Init();
CL_Init();
Cbuf_AddText("exec init.rc\n");
Cbuf_Execute();
// if stuffcmds wasn't run, then init.rc is probably missing, use default
if(!host.stuffcmdsrun) Cbuf_ExecuteText( EXEC_NOW, "stuffcmds\n" );
Sys_DoubleTime(); // initialize timer
}
/*
=================
Host_Main
=================
*/
void Host_Main( void )
{
static double time, oldtime, newtime;
oldtime = host.realtime;
// main window message loop
2007-11-21 22:00:00 +01:00
while( host.type != HOST_OFFLINE )
2007-11-17 22:00:00 +01:00
{
oldtime = newtime;
newtime = Sys_DoubleTime();
time = newtime - oldtime;
2007-11-21 22:00:00 +01:00
// engine frame
Host_Frame( time );
2007-11-17 22:00:00 +01:00
}
2007-11-21 22:00:00 +01:00
// prepare host to normal shutdown
2007-11-17 22:00:00 +01:00
host.state = HOST_SHUTDOWN;
2007-11-21 22:00:00 +01:00
std.strncpy( host.finalmsg, "Server shutdown\n", MAX_STRING );
2007-11-17 22:00:00 +01:00
}
/*
=================
Host_Shutdown
=================
*/
void Host_Free( void )
{
2007-11-21 22:00:00 +01:00
SV_Shutdown( false );
2007-11-17 22:00:00 +01:00
CL_Shutdown();
Host_FreeRender();
NET_Shutdown();
Host_FreePhysic();
Host_FreeCommon();
2007-06-21 22:00:00 +02:00
}