amxmodx/hlsdk/dedicated/engine.cpp
2006-08-27 02:22:59 +00:00

362 lines
6.2 KiB
C++

//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#define snprintf _snprintf
#else
#include <memory.h>
#include <string.h>
#include <stdlib.h> // exit()
#endif
#include "dedicated.h"
#include "dll_state.h"
#include "enginecallback.h"
#include "sys_ded.h"
int iWait = 0;
int fDeferedPause = 0;
int gDLLState;
int gDLLStateInfo;
long ghMod = 0;
static engine_api_t nullapi;
engine_api_t engineapi = nullapi;
extern SleepType Sys_Sleep; // setup by sys_ded.cpp
typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api );
#ifdef _WIN32
// This is a big chunk of uninitialized memory that we reserve for loading blobs into.
char g_rgchBlob[0x03800000];
#endif // _WIN32
/*
==============
Eng_LoadFunctions
Load engine->front end interface, if possible
==============
*/
int Eng_LoadFunctions( long hMod )
{
engine_api_func pfnEngineAPI;
pfnEngineAPI = ( engine_api_func )Sys_GetProcAddress( hMod, "Sys_EngineAPI" );
if ( !pfnEngineAPI )
return 0;
if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) )
return 0;
// All is okay
return 1;
}
/*
==============
Eng_LoadStubs
Force NULL interface
==============
*/
void Eng_LoadStubs( void )
{
// No callbacks in dedicated server since engine should always be loaded.
memset( &engineapi, 0, sizeof( engineapi ) );
engineapi.version = ENGINE_LAUNCHER_API_VERSION;
engineapi.rendertype = RENDERTYPE_UNDEFINED;
engineapi.size = sizeof( engine_api_t );
}
/*
==============
Eng_Unload
Free engine .dll and reset interfaces
==============
*/
void Eng_Unload(void)
{
if ( ghMod )
{
Sys_FreeLibrary(ghMod);
ghMod = 0;
}
Eng_LoadStubs();
gDLLState = 0;
gDLLStateInfo = 0;
}
/*
==============
Eng_KillEngine
Load failure on engine
==============
*/
void Eng_KillEngine( long *phMod )
{
Sys_FreeLibrary( ghMod );
ghMod = *phMod = 0;
Eng_LoadStubs();
}
/*
==============
Eng_Load
Try to load the engine with specified command line, etc. etc. and the specified .dll
==============
*/
int Eng_Load( const char *cmdline, struct exefuncs_s *pef, int memory, void *pmembase, const char *psz, int iSubMode )
{
char szLastDLL[ 100 ];
long hMod = (long)NULL;
#if defined( _DEBUG )
char *p;
if ( psz && !stricmp( psz, "swds.dll" ) && CheckParm( "-force", &p ) && p )
{
psz = p;
}
#endif
// Are we loading a different engine?
if ( psz && ghMod && !strcmp( psz, szLastDLL ) )
{
return 1;
}
if ( ghMod )
{
Eng_KillEngine( &hMod );
}
if ( !psz )
{
hMod = 0;
Eng_LoadStubs();
}
else if ( !ghMod )
{
hMod = Sys_LoadLibrary( (char *)psz );
if ( !hMod )
{
return 0;
}
// Load function table from engine
if ( !Eng_LoadFunctions( hMod ) )
{
Sys_FreeLibrary( hMod );
Eng_LoadStubs();
return 0;
}
// Activate engine
Eng_SetState( DLL_ACTIVE );
}
Eng_SetSubState( iSubMode );
snprintf( szLastDLL, sizeof( szLastDLL ), "%s", psz );
ghMod = hMod;
if ( ghMod )
{
static char *szEmpty = "";
char *p = (char *)cmdline;
if ( !p )
{
p = szEmpty;
}
if ( !engineapi.Game_Init( p, (unsigned char *)pmembase, memory, pef, NULL, 1) )
{
Sys_FreeLibrary(ghMod);
ghMod = hMod = 0;
return 0;
}
if ( engineapi.SetStartupMode )
{
engineapi.SetStartupMode( 1 );
}
if ( engineapi.Host_Frame )
{
Eng_Frame( 1, 0.05 );
}
if ( engineapi.SetStartupMode )
{
engineapi.SetStartupMode( 0 );
}
}
return 1;
}
/*
==============
Eng_Frame
Run a frame in the engine, if it's loaded.
==============
*/
int Eng_Frame( int fForce, double time )
{
if ( ( gDLLState != DLL_ACTIVE ) && !fForce )
return 0;
if ( gDLLState )
{
gDLLStateInfo = DLL_NORMAL;
int iState = engineapi.Host_Frame ( (float)time, gDLLState, &gDLLStateInfo );
// Special Signal
if ( gDLLStateInfo != DLL_NORMAL )
{
switch (gDLLStateInfo)
{
case DLL_QUIT:
Eng_Unload();
#ifdef _WIN32
PostQuitMessage(0);
#else
exit( 0 );
#endif
break;
case DLL_RESTART:
Eng_Unload();
#ifdef _WIN32
PostQuitMessage(1);
#else
exit( 1 );
#endif
break;
default:
break;
}
}
// Are we in our transistion counter?
if (iWait)
{
iWait--;
// Defer all pauses until we're ready to bring up the launcher
if (iState == DLL_PAUSED)
{
fDeferedPause = 1;
Eng_SetState(DLL_ACTIVE);
iState = DLL_ACTIVE;
}
// Are we done waiting, if so, did someone request a pause?
if (!iWait && fDeferedPause)
{
//force a pause
iState = DLL_PAUSED;
gDLLState = DLL_ACTIVE;
fDeferedPause = 0;
}
}
// Are we now in a transistion?
if (iState == DLL_TRANS)
{
iState = DLL_ACTIVE;
iWait = 5; // Let's wait N frames before we'll allow a pause
Eng_SetState(DLL_ACTIVE);
}
// Has the state changed?
if (iState != gDLLState)
{
Eng_SetState(iState);
}
}
if ( gDLLState == DLL_CLOSE || gDLLState == DLL_RESTART)
{
static int bQuitting = 0;
if ( !bQuitting )
{
bQuitting = 1;
engineapi.Cbuf_AddText( "killserver\n" );
Eng_Frame( 1, 0.05 );
Sys_Sleep( 100 );
Eng_Frame( 1, 0.05 );
Sys_Sleep( 100 );
return gDLLState;
}
Eng_Unload();
#ifdef _WIN32
PostQuitMessage(0);
#else
if ( gDLLState == DLL_RESTART )
{
exit( 1 );
}
else
{
exit( 0 );
}
#endif
}
return gDLLState;
}
/*
==============
Eng_SetSubState
==============
*/
void Eng_SetSubState(int iSubState)
{
if ( !engineapi.GameSetSubState )
return;
if ( iSubState != ENG_NORMAL )
{
engineapi.GameSetSubState( iSubState );
}
}
/*
==============
Eng_SetState
==============
*/
void Eng_SetState(int iState)
{
gDLLState = iState;
if (engineapi.GameSetState)
{
engineapi.GameSetState( iState );
}
}