mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-02 08:51:57 +00:00
a203345897
D3BFG gets the username from Steam, in the GPL release it just uses the hostname. Now it's possible to set a custom name with the ui_name CVAR (like in classic doom3). If ui_name is empty ("") the hostname is used. The window losing focus in MP resulted in the console being spammed with "changing com_pause not allowed in Multi Player" (or similar) messages. Added CVAR_NOCHEAT flag to com_pause to get rid of that.
1931 lines
46 KiB
C++
1931 lines
46 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
Copyright (C) 2012 Robert Beckebans
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Common_local.h"
|
|
|
|
#include "ConsoleHistory.h"
|
|
#include "../renderer/AutoRenderBink.h"
|
|
|
|
#include "../sound/sound.h"
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
#include "../../doomclassic/doom/doomlib.h"
|
|
#include "../../doomclassic/doom/d_event.h"
|
|
#include "../../doomclassic/doom/d_main.h"
|
|
#endif
|
|
// RB end
|
|
|
|
|
|
#include "../sys/sys_savegame.h"
|
|
|
|
#if defined( _DEBUG )
|
|
#define BUILD_DEBUG "-debug"
|
|
#else
|
|
#define BUILD_DEBUG ""
|
|
#endif
|
|
|
|
struct version_s
|
|
{
|
|
version_s()
|
|
{
|
|
sprintf( string, "%s.%d%s %s %s %s", ENGINE_VERSION, BUILD_NUMBER, BUILD_DEBUG, BUILD_STRING, __DATE__, __TIME__ );
|
|
}
|
|
char string[256];
|
|
} version;
|
|
|
|
idCVar com_version( "si_version", version.string, CVAR_SYSTEM | CVAR_ROM | CVAR_SERVERINFO, "engine version" );
|
|
idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "force generic platform independent SIMD" );
|
|
|
|
#ifdef ID_RETAIL
|
|
idCVar com_allowConsole( "com_allowConsole", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "allow toggling console with the tilde key" );
|
|
#else
|
|
idCVar com_allowConsole( "com_allowConsole", "1", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "allow toggling console with the tilde key" );
|
|
#endif
|
|
|
|
idCVar com_developer( "developer", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "developer mode" );
|
|
idCVar com_speeds( "com_speeds", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show engine timings" );
|
|
// DG: support "com_showFPS 2" for fps-only view like in classic doom3 => make it CVAR_INTEGER
|
|
idCVar com_showFPS( "com_showFPS", "0", CVAR_INTEGER | CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "show frames rendered per second. 0: off 1: default bfg values, 2: only show FPS (classic view)" );
|
|
// DG end
|
|
idCVar com_showMemoryUsage( "com_showMemoryUsage", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show total and per frame memory usage" );
|
|
idCVar com_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "update the load size after loading a map" );
|
|
|
|
idCVar com_productionMode( "com_productionMode", "0", CVAR_SYSTEM | CVAR_BOOL, "0 - no special behavior, 1 - building a production build, 2 - running a production build" );
|
|
|
|
idCVar com_japaneseCensorship( "com_japaneseCensorship", "0", CVAR_NOCHEAT, "Enable Japanese censorship" );
|
|
|
|
idCVar preload_CommonAssets( "preload_CommonAssets", "1", CVAR_SYSTEM | CVAR_BOOL, "preload common assets" );
|
|
|
|
idCVar net_inviteOnly( "net_inviteOnly", "1", CVAR_BOOL | CVAR_ARCHIVE, "whether or not the private server you create allows friends to join or invite only" );
|
|
|
|
// DG: add cvar for pause
|
|
idCVar com_pause( "com_pause", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "set to 1 to pause game, to 0 to unpause again" );
|
|
// DG end
|
|
|
|
extern idCVar g_demoMode;
|
|
|
|
idCVar com_engineHz( "com_engineHz", "60", CVAR_FLOAT | CVAR_ARCHIVE, "Frames per second the engine runs at", 10.0f, 1024.0f );
|
|
float com_engineHz_latched = 60.0f; // Latched version of cvar, updated between map loads
|
|
int64 com_engineHz_numerator = 100LL * 1000LL;
|
|
int64 com_engineHz_denominator = 100LL * 60LL;
|
|
|
|
// RB begin
|
|
#if defined(_WIN32)
|
|
HWND com_hwndMsg = NULL;
|
|
#endif
|
|
// RB end
|
|
|
|
#ifdef __DOOM_DLL__
|
|
idGame* game = NULL;
|
|
idGameEdit* gameEdit = NULL;
|
|
#endif
|
|
|
|
idCommonLocal commonLocal;
|
|
idCommon* common = &commonLocal;
|
|
|
|
|
|
idCVar com_skipIntroVideos( "com_skipIntroVideos", "0", CVAR_BOOL , "skips intro videos" );
|
|
|
|
// For doom classic
|
|
struct Globals;
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::idCommonLocal
|
|
==================
|
|
*/
|
|
idCommonLocal::idCommonLocal() :
|
|
readSnapshotIndex( 0 ),
|
|
writeSnapshotIndex( 0 ),
|
|
optimalPCTBuffer( 0.5f ),
|
|
optimalTimeBuffered( 0.0f ),
|
|
optimalTimeBufferedWindow( 0.0f ),
|
|
lastPacifierSessionTime( 0 ),
|
|
lastPacifierGuiTime( 0 ),
|
|
lastPacifierDialogState( false ),
|
|
showShellRequested( false )
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
,
|
|
currentGame( DOOM3_BFG ),
|
|
idealCurrentGame( DOOM3_BFG ),
|
|
doomClassicMaterial( NULL )
|
|
#endif
|
|
// RB end
|
|
{
|
|
|
|
snapCurrent.localTime = -1;
|
|
snapPrevious.localTime = -1;
|
|
snapCurrent.serverTime = -1;
|
|
snapPrevious.serverTime = -1;
|
|
snapTimeBuffered = 0.0f;
|
|
effectiveSnapRate = 0.0f;
|
|
totalBufferedTime = 0;
|
|
totalRecvTime = 0;
|
|
|
|
com_fullyInitialized = false;
|
|
com_refreshOnPrint = false;
|
|
com_errorEntered = ERP_NONE;
|
|
com_shuttingDown = false;
|
|
com_isJapaneseSKU = false;
|
|
|
|
logFile = NULL;
|
|
|
|
strcpy( errorMessage, "" );
|
|
|
|
rd_buffer = NULL;
|
|
rd_buffersize = 0;
|
|
rd_flush = NULL;
|
|
|
|
gameDLL = 0;
|
|
|
|
loadGUI = NULL;
|
|
nextLoadTip = 0;
|
|
isHellMap = false;
|
|
wipeForced = false;
|
|
defaultLoadscreen = false;
|
|
|
|
menuSoundWorld = NULL;
|
|
|
|
insideUpdateScreen = false;
|
|
insideExecuteMapChange = false;
|
|
|
|
mapSpawnData.savegameFile = NULL;
|
|
|
|
currentMapName.Clear();
|
|
aviDemoShortName.Clear();
|
|
|
|
renderWorld = NULL;
|
|
soundWorld = NULL;
|
|
menuSoundWorld = NULL;
|
|
readDemo = NULL;
|
|
writeDemo = NULL;
|
|
|
|
gameFrame = 0;
|
|
gameTimeResidual = 0;
|
|
syncNextGameFrame = true;
|
|
mapSpawned = false;
|
|
aviCaptureMode = false;
|
|
timeDemo = TD_NO;
|
|
|
|
nextSnapshotSendTime = 0;
|
|
nextUsercmdSendTime = 0;
|
|
|
|
clientPrediction = 0;
|
|
|
|
saveFile = NULL;
|
|
stringsFile = NULL;
|
|
|
|
ClearWipe();
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::Quit
|
|
==================
|
|
*/
|
|
void idCommonLocal::Quit()
|
|
{
|
|
|
|
// don't try to shutdown if we are in a recursive error
|
|
if( !com_errorEntered )
|
|
{
|
|
Shutdown();
|
|
}
|
|
Sys_Quit();
|
|
}
|
|
|
|
|
|
/*
|
|
============================================================================
|
|
|
|
COMMAND LINE FUNCTIONS
|
|
|
|
+ characters separate the commandLine string into multiple console
|
|
command lines.
|
|
|
|
All of these are valid:
|
|
|
|
doom +set test blah +map test
|
|
doom set test blah+map test
|
|
doom set test blah + map test
|
|
|
|
============================================================================
|
|
*/
|
|
|
|
#define MAX_CONSOLE_LINES 32
|
|
int com_numConsoleLines;
|
|
idCmdArgs com_consoleLines[MAX_CONSOLE_LINES];
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::ParseCommandLine
|
|
==================
|
|
*/
|
|
void idCommonLocal::ParseCommandLine( int argc, const char* const* argv )
|
|
{
|
|
int i, current_count;
|
|
|
|
com_numConsoleLines = 0;
|
|
current_count = 0;
|
|
// API says no program path
|
|
for( i = 0; i < argc; i++ )
|
|
{
|
|
if( idStr::Icmp( argv[ i ], "+connect_lobby" ) == 0 )
|
|
{
|
|
// Handle Steam bootable invites.
|
|
|
|
// RB begin
|
|
#if defined(_WIN32)
|
|
session->HandleBootableInvite( _atoi64( argv[ i + 1 ] ) );
|
|
#else
|
|
session->HandleBootableInvite( atol( argv[ i + 1 ] ) );
|
|
#endif
|
|
// RB end
|
|
}
|
|
else if( argv[ i ][ 0 ] == '+' )
|
|
{
|
|
com_numConsoleLines++;
|
|
com_consoleLines[ com_numConsoleLines - 1 ].AppendArg( argv[ i ] + 1 );
|
|
}
|
|
else
|
|
{
|
|
if( !com_numConsoleLines )
|
|
{
|
|
com_numConsoleLines++;
|
|
}
|
|
com_consoleLines[ com_numConsoleLines - 1 ].AppendArg( argv[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::SafeMode
|
|
|
|
Check for "safe" on the command line, which will
|
|
skip loading of config file (DoomConfig.cfg)
|
|
==================
|
|
*/
|
|
bool idCommonLocal::SafeMode()
|
|
{
|
|
int i;
|
|
|
|
for( i = 0 ; i < com_numConsoleLines ; i++ )
|
|
{
|
|
if( !idStr::Icmp( com_consoleLines[ i ].Argv( 0 ), "safe" )
|
|
|| !idStr::Icmp( com_consoleLines[ i ].Argv( 0 ), "cvar_restart" ) )
|
|
{
|
|
com_consoleLines[ i ].Clear();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::StartupVariable
|
|
|
|
Searches for command line parameters that are set commands.
|
|
If match is not NULL, only that cvar will be looked for.
|
|
That is necessary because cddir and basedir need to be set
|
|
before the filesystem is started, but all other sets should
|
|
be after execing the config and default.
|
|
==================
|
|
*/
|
|
void idCommonLocal::StartupVariable( const char* match )
|
|
{
|
|
int i = 0;
|
|
while( i < com_numConsoleLines )
|
|
{
|
|
if( strcmp( com_consoleLines[ i ].Argv( 0 ), "set" ) != 0 )
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
const char* s = com_consoleLines[ i ].Argv( 1 );
|
|
|
|
if( !match || !idStr::Icmp( s, match ) )
|
|
{
|
|
cvarSystem->SetCVarString( s, com_consoleLines[ i ].Argv( 2 ) );
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::AddStartupCommands
|
|
|
|
Adds command line parameters as script statements
|
|
Commands are separated by + signs
|
|
|
|
Returns true if any late commands were added, which
|
|
will keep the demoloop from immediately starting
|
|
==================
|
|
*/
|
|
void idCommonLocal::AddStartupCommands()
|
|
{
|
|
// quote every token, so args with semicolons can work
|
|
for( int i = 0; i < com_numConsoleLines; i++ )
|
|
{
|
|
if( !com_consoleLines[i].Argc() )
|
|
{
|
|
continue;
|
|
}
|
|
// directly as tokenized so nothing gets screwed
|
|
cmdSystem->BufferCommandArgs( CMD_EXEC_APPEND, com_consoleLines[i] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::WriteConfigToFile
|
|
==================
|
|
*/
|
|
void idCommonLocal::WriteConfigToFile( const char* filename )
|
|
{
|
|
idFile* f = fileSystem->OpenFileWrite( filename );
|
|
if( !f )
|
|
{
|
|
Printf( "Couldn't write %s.\n", filename );
|
|
return;
|
|
}
|
|
|
|
idKeyInput::WriteBindings( f );
|
|
cvarSystem->WriteFlaggedVariables( CVAR_ARCHIVE, "set", f );
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::WriteConfiguration
|
|
|
|
Writes key bindings and archived cvars to config file if modified
|
|
===============
|
|
*/
|
|
void idCommonLocal::WriteConfiguration()
|
|
{
|
|
// if we are quiting without fully initializing, make sure
|
|
// we don't write out anything
|
|
if( !com_fullyInitialized )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !( cvarSystem->GetModifiedFlags() & CVAR_ARCHIVE ) )
|
|
{
|
|
return;
|
|
}
|
|
cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
|
|
|
|
// save to the profile
|
|
idLocalUser* user = session->GetSignInManager().GetMasterLocalUser();
|
|
if( user != NULL )
|
|
{
|
|
user->SaveProfileSettings();
|
|
}
|
|
|
|
#ifdef CONFIG_FILE
|
|
// disable printing out the "Writing to:" message
|
|
bool developer = com_developer.GetBool();
|
|
com_developer.SetBool( false );
|
|
|
|
WriteConfigToFile( CONFIG_FILE );
|
|
|
|
// restore the developer cvar
|
|
com_developer.SetBool( developer );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============
|
|
KeysFromBinding()
|
|
Returns the key bound to the command
|
|
===============
|
|
*/
|
|
const char* idCommonLocal::KeysFromBinding( const char* bind )
|
|
{
|
|
return idKeyInput::KeysFromBinding( bind );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
BindingFromKey()
|
|
Returns the binding bound to key
|
|
===============
|
|
*/
|
|
const char* idCommonLocal::BindingFromKey( const char* key )
|
|
{
|
|
return idKeyInput::BindingFromKey( key );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
ButtonState()
|
|
Returns the state of the button
|
|
===============
|
|
*/
|
|
int idCommonLocal::ButtonState( int key )
|
|
{
|
|
return usercmdGen->ButtonState( key );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
ButtonState()
|
|
Returns the state of the key
|
|
===============
|
|
*/
|
|
int idCommonLocal::KeyState( int key )
|
|
{
|
|
return usercmdGen->KeyState( key );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idCmdSystemLocal::PrintMemInfo_f
|
|
|
|
This prints out memory debugging data
|
|
============
|
|
*/
|
|
CONSOLE_COMMAND( printMemInfo, "prints memory debugging data", NULL )
|
|
{
|
|
MemInfo_t mi;
|
|
memset( &mi, 0, sizeof( mi ) );
|
|
mi.filebase = commonLocal.GetCurrentMapName();
|
|
|
|
renderSystem->PrintMemInfo( &mi ); // textures and models
|
|
soundSystem->PrintMemInfo( &mi ); // sounds
|
|
|
|
common->Printf( " Used image memory: %s bytes\n", idStr::FormatNumber( mi.imageAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.imageAssetsTotal;
|
|
|
|
common->Printf( " Used model memory: %s bytes\n", idStr::FormatNumber( mi.modelAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.modelAssetsTotal;
|
|
|
|
common->Printf( " Used sound memory: %s bytes\n", idStr::FormatNumber( mi.soundAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.soundAssetsTotal;
|
|
|
|
common->Printf( " Used asset memory: %s bytes\n", idStr::FormatNumber( mi.assetTotals ).c_str() );
|
|
|
|
// write overview file
|
|
idFile* f;
|
|
|
|
f = fileSystem->OpenFileAppend( "maps/printmeminfo.txt" );
|
|
if( !f )
|
|
{
|
|
return;
|
|
}
|
|
|
|
f->Printf( "total(%s ) image(%s ) model(%s ) sound(%s ): %s\n", idStr::FormatNumber( mi.assetTotals ).c_str(), idStr::FormatNumber( mi.imageAssetsTotal ).c_str(),
|
|
idStr::FormatNumber( mi.modelAssetsTotal ).c_str(), idStr::FormatNumber( mi.soundAssetsTotal ).c_str(), mi.filebase.c_str() );
|
|
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Com_Error_f
|
|
|
|
Just throw a fatal error to test error shutdown procedures.
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( error, "causes an error", NULL )
|
|
{
|
|
if( !com_developer.GetBool() )
|
|
{
|
|
commonLocal.Printf( "error may only be used in developer mode\n" );
|
|
return;
|
|
}
|
|
|
|
if( args.Argc() > 1 )
|
|
{
|
|
commonLocal.FatalError( "Testing fatal error" );
|
|
}
|
|
else
|
|
{
|
|
commonLocal.Error( "Testing drop error" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Com_Freeze_f
|
|
|
|
Just freeze in place for a given number of seconds to test error recovery.
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( freeze, "freezes the game for a number of seconds", NULL )
|
|
{
|
|
float s;
|
|
int start, now;
|
|
|
|
if( args.Argc() != 2 )
|
|
{
|
|
commonLocal.Printf( "freeze <seconds>\n" );
|
|
return;
|
|
}
|
|
|
|
if( !com_developer.GetBool() )
|
|
{
|
|
commonLocal.Printf( "freeze may only be used in developer mode\n" );
|
|
return;
|
|
}
|
|
|
|
s = atof( args.Argv( 1 ) );
|
|
|
|
start = eventLoop->Milliseconds();
|
|
|
|
while( 1 )
|
|
{
|
|
now = eventLoop->Milliseconds();
|
|
if( ( now - start ) * 0.001f > s )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Com_Crash_f
|
|
|
|
A way to force a bus error for development reasons
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( crash, "causes a crash", NULL )
|
|
{
|
|
if( !com_developer.GetBool() )
|
|
{
|
|
commonLocal.Printf( "crash may only be used in developer mode\n" );
|
|
return;
|
|
}
|
|
#ifdef __GNUC__
|
|
__builtin_trap();
|
|
#else
|
|
* ( int* ) 0 = 0x12345678;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Com_Quit_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND_SHIP( quit, "quits the game", NULL )
|
|
{
|
|
commonLocal.Quit();
|
|
}
|
|
CONSOLE_COMMAND_SHIP( exit, "exits the game", NULL )
|
|
{
|
|
commonLocal.Quit();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Com_WriteConfig_f
|
|
|
|
Write the config file to a specific name
|
|
===============
|
|
*/
|
|
CONSOLE_COMMAND( writeConfig, "writes a config file", NULL )
|
|
{
|
|
idStr filename;
|
|
|
|
if( args.Argc() != 2 )
|
|
{
|
|
commonLocal.Printf( "Usage: writeconfig <filename>\n" );
|
|
return;
|
|
}
|
|
|
|
filename = args.Argv( 1 );
|
|
filename.DefaultFileExtension( ".cfg" );
|
|
commonLocal.Printf( "Writing %s.\n", filename.c_str() );
|
|
commonLocal.WriteConfigToFile( filename );
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::CheckStartupStorageRequirements
|
|
========================
|
|
*/
|
|
void idCommonLocal::CheckStartupStorageRequirements()
|
|
{
|
|
// RB: disabled savegame and profile storage checks, because it fails sometimes without any clear reason
|
|
#if 0
|
|
int64 availableSpace = 0;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Savegame and Profile required storage
|
|
// ------------------------------------------------------------------------
|
|
{
|
|
// Make sure the save path exists in case it was deleted.
|
|
// If the path cannot be created we can safely assume there is no
|
|
// free space because in that case nothing can be saved anyway.
|
|
const char* savepath = cvarSystem->GetCVarString( "fs_savepath" );
|
|
idStr directory = savepath;
|
|
//idStr directory = fs_savepath.GetString();
|
|
directory += "\\"; // so it doesn't think the last part is a file and ignores in the directory creation
|
|
fileSystem->CreateOSPath( directory );
|
|
|
|
// Get the free space on the save path.
|
|
availableSpace = Sys_GetDriveFreeSpaceInBytes( savepath );
|
|
|
|
// If free space fails then get space on drive as a fall back
|
|
// (the directory will be created later anyway)
|
|
if( availableSpace <= 1 )
|
|
{
|
|
idStr savePath( savepath );
|
|
if( savePath.Length() >= 3 )
|
|
{
|
|
if( savePath[ 1 ] == ':' && savePath[ 2 ] == '\\' &&
|
|
( ( savePath[ 0 ] >= 'A' && savePath[ 0 ] <= 'Z' ) ||
|
|
( savePath[ 0 ] >= 'a' && savePath[ 0 ] <= 'z' ) ) )
|
|
{
|
|
savePath = savePath.Left( 3 );
|
|
availableSpace = Sys_GetDriveFreeSpaceInBytes( savePath );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int MIN_SAVE_STORAGE_PROFILE = 1024 * 1024;
|
|
const int MIN_SAVE_STORAGE_SAVEGAME = MIN_SAVEGAME_SIZE_BYTES;
|
|
|
|
uint64 requiredSizeBytes = MIN_SAVE_STORAGE_SAVEGAME + MIN_SAVE_STORAGE_PROFILE;
|
|
|
|
idLib::Printf( "requiredSizeBytes: %lld\n", requiredSizeBytes );
|
|
|
|
if( ( int64 )( requiredSizeBytes - availableSpace ) > 0 )
|
|
{
|
|
class idSWFScriptFunction_Continue : public idSWFScriptFunction_RefCounted
|
|
{
|
|
public:
|
|
virtual ~idSWFScriptFunction_Continue() {}
|
|
idSWFScriptVar Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
|
|
{
|
|
common->Dialog().ClearDialog( GDM_INSUFFICENT_STORAGE_SPACE );
|
|
common->Quit();
|
|
return idSWFScriptVar();
|
|
}
|
|
};
|
|
|
|
idStaticList< idSWFScriptFunction*, 4 > callbacks;
|
|
idStaticList< idStrId, 4 > optionText;
|
|
callbacks.Append( new( TAG_SWF ) idSWFScriptFunction_Continue() );
|
|
optionText.Append( idStrId( "#STR_SWF_ACCEPT" ) );
|
|
|
|
// build custom space required string
|
|
// #str_dlg_space_required ~= "There is insufficient storage available. Please free %s and try again."
|
|
idStr format = idStrId( "#str_dlg_startup_insufficient_storage" ).GetLocalizedString();
|
|
idStr size;
|
|
if( requiredSizeBytes > ( 1024 * 1024 ) )
|
|
{
|
|
size = va( "%.1f MB", ( float )requiredSizeBytes / ( 1024.0f * 1024.0f ) + 0.1f ); // +0.1 to avoid truncation
|
|
}
|
|
else
|
|
{
|
|
size = va( "%.1f KB", ( float )requiredSizeBytes / 1024.0f + 0.1f );
|
|
}
|
|
idStr msg = va( format.c_str(), size.c_str() );
|
|
|
|
common->Dialog().AddDynamicDialog( GDM_INSUFFICENT_STORAGE_SPACE, callbacks, optionText, true, msg );
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
session->GetAchievementSystem().Start();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::JapaneseCensorship
|
|
===============
|
|
*/
|
|
bool idCommonLocal::JapaneseCensorship() const
|
|
{
|
|
return com_japaneseCensorship.GetBool() || com_isJapaneseSKU;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::FilterLangList
|
|
===============
|
|
*/
|
|
void idCommonLocal::FilterLangList( idStrList* list, idStr lang )
|
|
{
|
|
|
|
idStr temp;
|
|
for( int i = 0; i < list->Num(); i++ )
|
|
{
|
|
temp = ( *list )[i];
|
|
temp = temp.Right( temp.Length() - strlen( "strings/" ) );
|
|
temp = temp.Left( lang.Length() );
|
|
if( idStr::Icmp( temp, lang ) != 0 )
|
|
{
|
|
list->RemoveIndex( i );
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::InitLanguageDict
|
|
===============
|
|
*/
|
|
extern idCVar sys_lang;
|
|
void idCommonLocal::InitLanguageDict()
|
|
{
|
|
idStr fileName;
|
|
|
|
//D3XP: Instead of just loading a single lang file for each language
|
|
//we are going to load all files that begin with the language name
|
|
//similar to the way pak files work. So you can place english001.lang
|
|
//to add new strings to the english language dictionary
|
|
idFileList* langFiles;
|
|
langFiles = fileSystem->ListFilesTree( "strings", ".lang", true );
|
|
|
|
idStrList langList = langFiles->GetList();
|
|
|
|
// Loop through the list and filter
|
|
idStrList currentLangList = langList;
|
|
FilterLangList( ¤tLangList, sys_lang.GetString() );
|
|
|
|
if( currentLangList.Num() == 0 )
|
|
{
|
|
// reset to english and try to load again
|
|
sys_lang.SetString( ID_LANG_ENGLISH );
|
|
currentLangList = langList;
|
|
FilterLangList( ¤tLangList, sys_lang.GetString() );
|
|
}
|
|
|
|
idLocalization::ClearDictionary();
|
|
for( int i = 0; i < currentLangList.Num(); i++ )
|
|
{
|
|
//common->Printf("%s\n", currentLangList[i].c_str());
|
|
const byte* buffer = NULL;
|
|
int len = fileSystem->ReadFile( currentLangList[i], ( void** )&buffer );
|
|
if( len <= 0 )
|
|
{
|
|
assert( false && "couldn't read the language dict file" );
|
|
break;
|
|
}
|
|
idLocalization::LoadDictionary( buffer, len, currentLangList[i] );
|
|
fileSystem->FreeFile( ( void* )buffer );
|
|
}
|
|
|
|
fileSystem->FreeFileList( langFiles );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
ReloadLanguage_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( reloadLanguage, "reload language dict", NULL )
|
|
{
|
|
commonLocal.InitLanguageDict();
|
|
}
|
|
|
|
#include "../renderer/Image.h"
|
|
|
|
/*
|
|
=================
|
|
Com_StartBuild_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( startBuild, "prepares to make a build", NULL )
|
|
{
|
|
globalImages->StartBuild();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Com_FinishBuild_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( finishBuild, "finishes the build process", NULL )
|
|
{
|
|
if( game )
|
|
{
|
|
game->CacheDictionaryMedia( NULL );
|
|
}
|
|
globalImages->FinishBuild( ( args.Argc() > 1 ) );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::RenderSplash
|
|
=================
|
|
*/
|
|
void idCommonLocal::RenderSplash()
|
|
{
|
|
const float sysWidth = renderSystem->GetWidth() * renderSystem->GetPixelAspect();
|
|
const float sysHeight = renderSystem->GetHeight();
|
|
const float sysAspect = sysWidth / sysHeight;
|
|
const float splashAspect = 16.0f / 9.0f;
|
|
const float adjustment = sysAspect / splashAspect;
|
|
const float barHeight = ( adjustment >= 1.0f ) ? 0.0f : ( 1.0f - adjustment ) * ( float )SCREEN_HEIGHT * 0.25f;
|
|
const float barWidth = ( adjustment <= 1.0f ) ? 0.0f : ( adjustment - 1.0f ) * ( float )SCREEN_WIDTH * 0.25f;
|
|
if( barHeight > 0.0f )
|
|
{
|
|
renderSystem->SetColor( colorBlack );
|
|
renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial );
|
|
renderSystem->DrawStretchPic( 0, SCREEN_HEIGHT - barHeight, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial );
|
|
}
|
|
if( barWidth > 0.0f )
|
|
{
|
|
renderSystem->SetColor( colorBlack );
|
|
renderSystem->DrawStretchPic( 0, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial );
|
|
renderSystem->DrawStretchPic( SCREEN_WIDTH - barWidth, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial );
|
|
}
|
|
renderSystem->SetColor4( 1, 1, 1, 1 );
|
|
renderSystem->DrawStretchPic( barWidth, barHeight, SCREEN_WIDTH - barWidth * 2.0f, SCREEN_HEIGHT - barHeight * 2.0f, 0, 0, 1, 1, splashScreen );
|
|
|
|
const emptyCommand_t* cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
|
|
renderSystem->RenderCommandBuffers( cmd );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::RenderBink
|
|
=================
|
|
*/
|
|
void idCommonLocal::RenderBink( const char* path )
|
|
{
|
|
const float sysWidth = renderSystem->GetWidth() * renderSystem->GetPixelAspect();
|
|
const float sysHeight = renderSystem->GetHeight();
|
|
const float sysAspect = sysWidth / sysHeight;
|
|
const float movieAspect = ( 16.0f / 9.0f );
|
|
const float imageWidth = SCREEN_WIDTH * movieAspect / sysAspect;
|
|
const float chop = 0.5f * ( SCREEN_WIDTH - imageWidth );
|
|
|
|
idStr materialText;
|
|
materialText.Format( "{ translucent { videoMap %s } }", path );
|
|
|
|
idMaterial* material = const_cast<idMaterial*>( declManager->FindMaterial( "splashbink" ) );
|
|
material->Parse( materialText.c_str(), materialText.Length(), false );
|
|
material->ResetCinematicTime( Sys_Milliseconds() );
|
|
|
|
while( Sys_Milliseconds() <= material->GetCinematicStartTime() + material->CinematicLength() )
|
|
{
|
|
renderSystem->DrawStretchPic( chop, 0, imageWidth, SCREEN_HEIGHT, 0, 0, 1, 1, material );
|
|
const emptyCommand_t* cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
|
|
renderSystem->RenderCommandBuffers( cmd );
|
|
Sys_GenerateEvents();
|
|
Sys_Sleep( 10 );
|
|
}
|
|
|
|
material->MakeDefault();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::InitSIMD
|
|
=================
|
|
*/
|
|
void idCommonLocal::InitSIMD()
|
|
{
|
|
idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() );
|
|
com_forceGenericSIMD.ClearModified();
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::LoadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::LoadGameDLL()
|
|
{
|
|
#ifdef __DOOM_DLL__
|
|
char dllPath[ MAX_OSPATH ];
|
|
|
|
gameImport_t gameImport;
|
|
gameExport_t gameExport;
|
|
GetGameAPI_t GetGameAPI;
|
|
|
|
fileSystem->FindDLL( "game", dllPath, true );
|
|
|
|
if( !dllPath[ 0 ] )
|
|
{
|
|
common->FatalError( "couldn't find game dynamic library" );
|
|
return;
|
|
}
|
|
common->DPrintf( "Loading game DLL: '%s'\n", dllPath );
|
|
gameDLL = sys->DLL_Load( dllPath );
|
|
if( !gameDLL )
|
|
{
|
|
common->FatalError( "couldn't load game dynamic library" );
|
|
return;
|
|
}
|
|
|
|
const char* functionName = "GetGameAPI";
|
|
GetGameAPI = ( GetGameAPI_t ) Sys_DLL_GetProcAddress( gameDLL, functionName );
|
|
if( !GetGameAPI )
|
|
{
|
|
Sys_DLL_Unload( gameDLL );
|
|
gameDLL = NULL;
|
|
common->FatalError( "couldn't find game DLL API" );
|
|
return;
|
|
}
|
|
|
|
gameImport.version = GAME_API_VERSION;
|
|
gameImport.sys = ::sys;
|
|
gameImport.common = ::common;
|
|
gameImport.cmdSystem = ::cmdSystem;
|
|
gameImport.cvarSystem = ::cvarSystem;
|
|
gameImport.fileSystem = ::fileSystem;
|
|
gameImport.renderSystem = ::renderSystem;
|
|
gameImport.soundSystem = ::soundSystem;
|
|
gameImport.renderModelManager = ::renderModelManager;
|
|
gameImport.uiManager = ::uiManager;
|
|
gameImport.declManager = ::declManager;
|
|
gameImport.AASFileManager = ::AASFileManager;
|
|
gameImport.collisionModelManager = ::collisionModelManager;
|
|
|
|
gameExport = *GetGameAPI( &gameImport );
|
|
|
|
if( gameExport.version != GAME_API_VERSION )
|
|
{
|
|
Sys_DLL_Unload( gameDLL );
|
|
gameDLL = NULL;
|
|
common->FatalError( "wrong game DLL API version" );
|
|
return;
|
|
}
|
|
|
|
game = gameExport.game;
|
|
gameEdit = gameExport.gameEdit;
|
|
|
|
#endif
|
|
|
|
// initialize the game object
|
|
if( game != NULL )
|
|
{
|
|
game->Init();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::UnloadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::CleanupShell()
|
|
{
|
|
if( game != NULL )
|
|
{
|
|
game->Shell_Cleanup();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::UnloadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::UnloadGameDLL()
|
|
{
|
|
|
|
// shut down the game object
|
|
if( game != NULL )
|
|
{
|
|
game->Shutdown();
|
|
}
|
|
|
|
#ifdef __DOOM_DLL__
|
|
|
|
if( gameDLL )
|
|
{
|
|
Sys_DLL_Unload( gameDLL );
|
|
gameDLL = NULL;
|
|
}
|
|
game = NULL;
|
|
gameEdit = NULL;
|
|
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::IsInitialized
|
|
=================
|
|
*/
|
|
bool idCommonLocal::IsInitialized() const
|
|
{
|
|
return com_fullyInitialized;
|
|
}
|
|
|
|
|
|
//======================================================================================
|
|
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::Init
|
|
=================
|
|
*/
|
|
void idCommonLocal::Init( int argc, const char* const* argv, const char* cmdline )
|
|
{
|
|
try
|
|
{
|
|
// set interface pointers used by idLib
|
|
idLib::sys = sys;
|
|
idLib::common = common;
|
|
idLib::cvarSystem = cvarSystem;
|
|
idLib::fileSystem = fileSystem;
|
|
|
|
// initialize idLib
|
|
idLib::Init();
|
|
|
|
// clear warning buffer
|
|
ClearWarnings( GAME_NAME " initialization" );
|
|
|
|
idLib::Printf( va( "Command line: %s\n", cmdline ) );
|
|
//::MessageBox( NULL, cmdline, "blah", MB_OK );
|
|
// parse command line options
|
|
idCmdArgs args;
|
|
if( cmdline )
|
|
{
|
|
// tokenize if the OS doesn't do it for us
|
|
args.TokenizeString( cmdline, true );
|
|
argv = args.GetArgs( &argc );
|
|
}
|
|
ParseCommandLine( argc, argv );
|
|
|
|
// init console command system
|
|
cmdSystem->Init();
|
|
|
|
// init CVar system
|
|
cvarSystem->Init();
|
|
|
|
// register all static CVars
|
|
idCVar::RegisterStaticVars();
|
|
|
|
idLib::Printf( "QA Timing INIT: %06dms\n", Sys_Milliseconds() );
|
|
|
|
// print engine version
|
|
Printf( "%s\n", version.string );
|
|
|
|
// initialize key input/binding, done early so bind command exists
|
|
idKeyInput::Init();
|
|
|
|
// init the console so we can take prints
|
|
console->Init();
|
|
|
|
// get architecture info
|
|
Sys_Init();
|
|
|
|
// initialize networking
|
|
Sys_InitNetworking();
|
|
|
|
// override cvars from command line
|
|
StartupVariable( NULL );
|
|
|
|
consoleUsed = com_allowConsole.GetBool();
|
|
|
|
if( Sys_AlreadyRunning() )
|
|
{
|
|
Sys_Quit();
|
|
}
|
|
|
|
// initialize processor specific SIMD implementation
|
|
InitSIMD();
|
|
|
|
// initialize the file system
|
|
fileSystem->Init();
|
|
|
|
const char* defaultLang = Sys_DefaultLanguage();
|
|
com_isJapaneseSKU = ( idStr::Icmp( defaultLang, ID_LANG_JAPANESE ) == 0 );
|
|
|
|
// Allow the system to set a default lanugage
|
|
Sys_SetLanguageFromSystem();
|
|
|
|
// Pre-allocate our 20 MB save buffer here on time, instead of on-demand for each save....
|
|
|
|
saveFile.SetNameAndType( SAVEGAME_CHECKPOINT_FILENAME, SAVEGAMEFILE_BINARY );
|
|
saveFile.PreAllocate( MIN_SAVEGAME_SIZE_BYTES );
|
|
|
|
stringsFile.SetNameAndType( SAVEGAME_STRINGS_FILENAME, SAVEGAMEFILE_BINARY );
|
|
stringsFile.PreAllocate( MAX_SAVEGAME_STRING_TABLE_SIZE );
|
|
|
|
fileSystem->BeginLevelLoad( "_startup", saveFile.GetDataPtr(), saveFile.GetAllocated() );
|
|
|
|
// initialize the declaration manager
|
|
declManager->Init();
|
|
|
|
// init journalling, etc
|
|
eventLoop->Init();
|
|
|
|
// init the parallel job manager
|
|
parallelJobManager->Init();
|
|
|
|
// exec the startup scripts
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
|
|
|
|
#ifdef CONFIG_FILE
|
|
// skip the config file if "safe" is on the command line
|
|
if( !SafeMode() && !g_demoMode.GetBool() )
|
|
{
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec " CONFIG_FILE "\n" );
|
|
}
|
|
#endif
|
|
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec autoexec.cfg\n" );
|
|
|
|
// run cfg execution
|
|
cmdSystem->ExecuteCommandBuffer();
|
|
|
|
// re-override anything from the config files with command line args
|
|
StartupVariable( NULL );
|
|
|
|
// if any archived cvars are modified after this, we will trigger a writing of the config file
|
|
cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
|
|
|
|
// init OpenGL, which will open a window and connect sound and input hardware
|
|
renderSystem->InitOpenGL();
|
|
|
|
// Support up to 2 digits after the decimal point
|
|
com_engineHz_denominator = 100LL * com_engineHz.GetFloat();
|
|
com_engineHz_latched = com_engineHz.GetFloat();
|
|
|
|
// start the sound system, but don't do any hardware operations yet
|
|
soundSystem->Init();
|
|
|
|
// initialize the renderSystem data structures
|
|
renderSystem->Init();
|
|
|
|
whiteMaterial = declManager->FindMaterial( "_white" );
|
|
|
|
if( idStr::Icmp( sys_lang.GetString(), ID_LANG_FRENCH ) == 0 )
|
|
{
|
|
// If the user specified french, we show french no matter what SKU
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_french" );
|
|
}
|
|
else if( idStr::Icmp( defaultLang, ID_LANG_FRENCH ) == 0 )
|
|
{
|
|
// If the lead sku is french (ie: europe), display figs
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_figs" );
|
|
}
|
|
else
|
|
{
|
|
// Otherwise show it in english
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_english" );
|
|
}
|
|
|
|
const int legalMinTime = 4000;
|
|
const bool showVideo = ( !com_skipIntroVideos.GetBool() && fileSystem->UsingResourceFiles() );
|
|
if( showVideo )
|
|
{
|
|
RenderBink( "video\\loadvideo.bik" );
|
|
RenderSplash();
|
|
RenderSplash();
|
|
}
|
|
else
|
|
{
|
|
idLib::Printf( "Skipping Intro Videos!\n" );
|
|
// display the legal splash screen
|
|
// No clue why we have to render this twice to show up...
|
|
RenderSplash();
|
|
RenderSplash();
|
|
}
|
|
|
|
|
|
int legalStartTime = Sys_Milliseconds();
|
|
declManager->Init2();
|
|
|
|
// initialize string database so we can use it for loading messages
|
|
InitLanguageDict();
|
|
|
|
// spawn the game thread, even if we are going to run without SMP
|
|
// one meg stack, because it can parse decls from gui surfaces (unfortunately)
|
|
// use a lower priority so job threads can run on the same core
|
|
gameThread.StartWorkerThread( "Game/Draw", CORE_1B, THREAD_BELOW_NORMAL, 0x100000 );
|
|
// boost this thread's priority, so it will prevent job threads from running while
|
|
// the render back end still has work to do
|
|
|
|
// init the user command input code
|
|
usercmdGen->Init();
|
|
|
|
Sys_SetRumble( 0, 0, 0 );
|
|
|
|
// initialize the user interfaces
|
|
uiManager->Init();
|
|
|
|
// startup the script debugger
|
|
// DebuggerServerInit();
|
|
|
|
// load the game dll
|
|
LoadGameDLL();
|
|
|
|
// On the PC touch them all so they get included in the resource build
|
|
if( !fileSystem->UsingResourceFiles() )
|
|
{
|
|
declManager->FindMaterial( "guis/assets/splash/legal_english" );
|
|
declManager->FindMaterial( "guis/assets/splash/legal_french" );
|
|
declManager->FindMaterial( "guis/assets/splash/legal_figs" );
|
|
// register the japanese font so it gets included
|
|
renderSystem->RegisterFont( "DFPHeiseiGothicW7" );
|
|
// Make sure all videos get touched because you can bring videos from one map to another, they need to be included in all maps
|
|
for( int i = 0; i < declManager->GetNumDecls( DECL_VIDEO ); i++ )
|
|
{
|
|
declManager->DeclByIndex( DECL_VIDEO, i );
|
|
}
|
|
}
|
|
|
|
fileSystem->UnloadResourceContainer( "_ordered" );
|
|
|
|
// the same idRenderWorld will be used for all games
|
|
// and demos, insuring that level specific models
|
|
// will be freed
|
|
renderWorld = renderSystem->AllocRenderWorld();
|
|
soundWorld = soundSystem->AllocSoundWorld( renderWorld );
|
|
|
|
menuSoundWorld = soundSystem->AllocSoundWorld( NULL );
|
|
menuSoundWorld->PlaceListener( vec3_origin, mat3_identity, 0 );
|
|
|
|
// init the session
|
|
session->Initialize();
|
|
session->InitializeSoundRelatedSystems();
|
|
|
|
InitializeMPMapsModes();
|
|
|
|
// leaderboards need to be initialized after InitializeMPMapsModes, which populates the MP Map list.
|
|
if( game != NULL )
|
|
{
|
|
game->Leaderboards_Init();
|
|
}
|
|
|
|
CreateMainMenu();
|
|
|
|
commonDialog.Init();
|
|
|
|
// load the console history file
|
|
consoleHistory.LoadHistoryFile();
|
|
|
|
AddStartupCommands();
|
|
|
|
StartMenu( true );
|
|
|
|
while( Sys_Milliseconds() - legalStartTime < legalMinTime )
|
|
{
|
|
RenderSplash();
|
|
Sys_GenerateEvents();
|
|
Sys_Sleep( 10 );
|
|
};
|
|
|
|
// print all warnings queued during initialization
|
|
PrintWarnings();
|
|
|
|
// remove any prints from the notify lines
|
|
console->ClearNotifyLines();
|
|
|
|
CheckStartupStorageRequirements();
|
|
|
|
|
|
if( preload_CommonAssets.GetBool() && fileSystem->UsingResourceFiles() )
|
|
{
|
|
idPreloadManifest manifest;
|
|
manifest.LoadManifest( "_common.preload" );
|
|
globalImages->Preload( manifest, false );
|
|
soundSystem->Preload( manifest );
|
|
}
|
|
|
|
fileSystem->EndLevelLoad();
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
// Initialize support for Doom classic.
|
|
doomClassicMaterial = declManager->FindMaterial( "_doomClassic" );
|
|
idImage* image = globalImages->GetImage( "_doomClassic" );
|
|
if( image != NULL )
|
|
{
|
|
idImageOpts opts;
|
|
opts.format = FMT_RGBA8;
|
|
opts.colorFormat = CFM_DEFAULT;
|
|
opts.width = DOOMCLASSIC_RENDERWIDTH;
|
|
opts.height = DOOMCLASSIC_RENDERHEIGHT;
|
|
opts.numLevels = 1;
|
|
image->AllocImage( opts, TF_LINEAR, TR_REPEAT );
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
com_fullyInitialized = true;
|
|
|
|
|
|
// No longer need the splash screen
|
|
if( splashScreen != NULL )
|
|
{
|
|
for( int i = 0; i < splashScreen->GetNumStages(); i++ )
|
|
{
|
|
idImage* image = splashScreen->GetStage( i )->texture.image;
|
|
if( image != NULL )
|
|
{
|
|
image->PurgeImage();
|
|
}
|
|
}
|
|
}
|
|
|
|
Printf( "--- Common Initialization Complete ---\n" );
|
|
|
|
idLib::Printf( "QA Timing IIS: %06dms\n", Sys_Milliseconds() );
|
|
}
|
|
catch( idException& )
|
|
{
|
|
Sys_Error( "Error during initialization" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::Shutdown
|
|
=================
|
|
*/
|
|
void idCommonLocal::Shutdown()
|
|
{
|
|
|
|
if( com_shuttingDown )
|
|
{
|
|
return;
|
|
}
|
|
com_shuttingDown = true;
|
|
|
|
|
|
// Kill any pending saves...
|
|
printf( "session->GetSaveGameManager().CancelToTerminate();\n" );
|
|
session->GetSaveGameManager().CancelToTerminate();
|
|
|
|
// kill sound first
|
|
printf( "soundSystem->StopAllSounds();\n" );
|
|
soundSystem->StopAllSounds();
|
|
|
|
// shutdown the script debugger
|
|
// DebuggerServerShutdown();
|
|
|
|
if( aviCaptureMode )
|
|
{
|
|
printf( "EndAVICapture();\n" );
|
|
EndAVICapture();
|
|
}
|
|
|
|
printf( "Stop();\n" );
|
|
Stop();
|
|
|
|
printf( "CleanupShell();\n" );
|
|
CleanupShell();
|
|
|
|
printf( "delete loadGUI;\n" );
|
|
delete loadGUI;
|
|
loadGUI = NULL;
|
|
|
|
printf( "delete renderWorld;\n" );
|
|
delete renderWorld;
|
|
renderWorld = NULL;
|
|
|
|
printf( "delete soundWorld;\n" );
|
|
delete soundWorld;
|
|
soundWorld = NULL;
|
|
|
|
printf( "delete menuSoundWorld;\n" );
|
|
delete menuSoundWorld;
|
|
menuSoundWorld = NULL;
|
|
|
|
// shut down the session
|
|
printf( "session->ShutdownSoundRelatedSystems();\n" );
|
|
session->ShutdownSoundRelatedSystems();
|
|
printf( "session->Shutdown();\n" );
|
|
session->Shutdown();
|
|
|
|
// shutdown, deallocate leaderboard definitions.
|
|
if( game != NULL )
|
|
{
|
|
printf( "game->Leaderboards_Shutdown();\n" );
|
|
game->Leaderboards_Shutdown();
|
|
}
|
|
|
|
// shut down the user interfaces
|
|
printf( "uiManager->Shutdown();\n" );
|
|
uiManager->Shutdown();
|
|
|
|
// shut down the sound system
|
|
printf( "soundSystem->Shutdown();\n" );
|
|
soundSystem->Shutdown();
|
|
|
|
// shut down the user command input code
|
|
printf( "usercmdGen->Shutdown();\n" );
|
|
usercmdGen->Shutdown();
|
|
|
|
// shut down the event loop
|
|
printf( "eventLoop->Shutdown();\n" );
|
|
eventLoop->Shutdown();
|
|
|
|
// shutdown the decl manager
|
|
printf( "declManager->Shutdown();\n" );
|
|
declManager->Shutdown();
|
|
|
|
// shut down the renderSystem
|
|
printf( "renderSystem->Shutdown();\n" );
|
|
renderSystem->Shutdown();
|
|
|
|
printf( "commonDialog.Shutdown();\n" );
|
|
commonDialog.Shutdown();
|
|
|
|
// unload the game dll
|
|
printf( "UnloadGameDLL();\n" );
|
|
UnloadGameDLL();
|
|
|
|
printf( "saveFile.Clear( true );\n" );
|
|
saveFile.Clear( true );
|
|
printf( "stringsFile.Clear( true );\n" );
|
|
stringsFile.Clear( true );
|
|
|
|
// only shut down the log file after all output is done
|
|
printf( "CloseLogFile();\n" );
|
|
CloseLogFile();
|
|
|
|
// shut down the file system
|
|
printf( "fileSystem->Shutdown( false );\n" );
|
|
fileSystem->Shutdown( false );
|
|
|
|
// shut down non-portable system services
|
|
printf( "Sys_Shutdown();\n" );
|
|
Sys_Shutdown();
|
|
|
|
// shut down the console
|
|
printf( "console->Shutdown();\n" );
|
|
console->Shutdown();
|
|
|
|
// shut down the key system
|
|
printf( "idKeyInput::Shutdown();\n" );
|
|
idKeyInput::Shutdown();
|
|
|
|
// shut down the cvar system
|
|
printf( "cvarSystem->Shutdown();\n" );
|
|
cvarSystem->Shutdown();
|
|
|
|
// shut down the console command system
|
|
printf( "cmdSystem->Shutdown();\n" );
|
|
cmdSystem->Shutdown();
|
|
|
|
// free any buffered warning messages
|
|
printf( "ClearWarnings( GAME_NAME \" shutdown\" );\n" );
|
|
ClearWarnings( GAME_NAME " shutdown" );
|
|
printf( "warningCaption.Clear();\n" );
|
|
warningCaption.Clear();
|
|
printf( "errorList.Clear();\n" );
|
|
errorList.Clear();
|
|
|
|
// shutdown idLib
|
|
printf( "idLib::ShutDown();\n" );
|
|
idLib::ShutDown();
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::CreateMainMenu
|
|
========================
|
|
*/
|
|
void idCommonLocal::CreateMainMenu()
|
|
{
|
|
if( game != NULL )
|
|
{
|
|
// note which media we are going to need to load
|
|
declManager->BeginLevelLoad();
|
|
renderSystem->BeginLevelLoad();
|
|
soundSystem->BeginLevelLoad();
|
|
uiManager->BeginLevelLoad();
|
|
|
|
// create main inside an "empty" game level load - so assets get
|
|
// purged automagically when we transition to a "real" map
|
|
game->Shell_CreateMenu( false );
|
|
game->Shell_Show( true );
|
|
game->Shell_SyncWithSession();
|
|
|
|
// load
|
|
renderSystem->EndLevelLoad();
|
|
soundSystem->EndLevelLoad();
|
|
declManager->EndLevelLoad();
|
|
uiManager->EndLevelLoad( "" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::Stop
|
|
|
|
called on errors and game exits
|
|
===============
|
|
*/
|
|
void idCommonLocal::Stop( bool resetSession )
|
|
{
|
|
ClearWipe();
|
|
|
|
// clear mapSpawned and demo playing flags
|
|
UnloadMap();
|
|
|
|
soundSystem->StopAllSounds();
|
|
|
|
insideUpdateScreen = false;
|
|
insideExecuteMapChange = false;
|
|
|
|
// drop all guis
|
|
ExitMenu();
|
|
|
|
if( resetSession )
|
|
{
|
|
session->QuitMatchToTitle();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::BusyWait
|
|
===============
|
|
*/
|
|
void idCommonLocal::BusyWait()
|
|
{
|
|
Sys_GenerateEvents();
|
|
|
|
const bool captureToImage = false;
|
|
UpdateScreen( captureToImage );
|
|
|
|
session->UpdateSignInManager();
|
|
session->Pump();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::WaitForSessionState
|
|
===============
|
|
*/
|
|
bool idCommonLocal::WaitForSessionState( idSession::sessionState_t desiredState )
|
|
{
|
|
if( session->GetState() == desiredState )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
while( true )
|
|
{
|
|
BusyWait();
|
|
|
|
idSession::sessionState_t sessionState = session->GetState();
|
|
if( sessionState == desiredState )
|
|
{
|
|
return true;
|
|
}
|
|
if( sessionState != idSession::LOADING &&
|
|
sessionState != idSession::SEARCHING &&
|
|
sessionState != idSession::CONNECTING &&
|
|
sessionState != idSession::BUSY &&
|
|
sessionState != desiredState )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Sys_Sleep( 10 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::LeaveGame
|
|
========================
|
|
*/
|
|
void idCommonLocal::LeaveGame()
|
|
{
|
|
|
|
const bool captureToImage = false;
|
|
UpdateScreen( captureToImage );
|
|
|
|
ResetNetworkingState();
|
|
|
|
|
|
Stop( false );
|
|
|
|
CreateMainMenu();
|
|
|
|
StartMenu();
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::ProcessEvent
|
|
===============
|
|
*/
|
|
bool idCommonLocal::ProcessEvent( const sysEvent_t* event )
|
|
{
|
|
// hitting escape anywhere brings up the menu
|
|
if( game && game->IsInGame() )
|
|
{
|
|
if( event->evType == SE_KEY && event->evValue2 == 1 && ( event->evValue == K_ESCAPE || event->evValue == K_JOY9 ) )
|
|
{
|
|
if( !game->Shell_IsActive() )
|
|
{
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
console->Close();
|
|
|
|
StartMenu();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
console->Close();
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
game->Shell_ClosePause();
|
|
}
|
|
}
|
|
}
|
|
|
|
// let the pull-down console take it if desired
|
|
if( console->ProcessEvent( event, false ) )
|
|
{
|
|
return true;
|
|
}
|
|
if( session->ProcessInputEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if( Dialog().IsDialogActive() )
|
|
{
|
|
Dialog().HandleDialogEvent( event );
|
|
return true;
|
|
}
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
|
|
// Let Doom classic run events.
|
|
if( IsPlayingDoomClassic() )
|
|
{
|
|
// Translate the event to Doom classic format.
|
|
event_t classicEvent;
|
|
if( event->evType == SE_KEY )
|
|
{
|
|
|
|
if( event->evValue2 == 1 )
|
|
{
|
|
classicEvent.type = ev_keydown;
|
|
}
|
|
else if( event->evValue2 == 0 )
|
|
{
|
|
classicEvent.type = ev_keyup;
|
|
}
|
|
|
|
DoomLib::SetPlayer( 0 );
|
|
|
|
extern Globals* g;
|
|
if( g != NULL )
|
|
{
|
|
classicEvent.data1 = DoomLib::RemapControl( event->GetKey() );
|
|
|
|
D_PostEvent( &classicEvent );
|
|
}
|
|
DoomLib::SetPlayer( -1 );
|
|
}
|
|
|
|
// Let the classics eat all events.
|
|
return true;
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// if we aren't in a game, force the console to take it
|
|
if( !mapSpawned )
|
|
{
|
|
console->ProcessEvent( event, true );
|
|
return true;
|
|
}
|
|
|
|
// in game, exec bindings for all key downs
|
|
if( event->evType == SE_KEY && event->evValue2 == 1 )
|
|
{
|
|
idKeyInput::ExecKeyBinding( event->evValue );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::ResetPlayerInput
|
|
========================
|
|
*/
|
|
void idCommonLocal::ResetPlayerInput( int playerIndex )
|
|
{
|
|
userCmdMgr.ResetPlayer( playerIndex );
|
|
}
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::SwitchToGame
|
|
========================
|
|
*/
|
|
void idCommonLocal::SwitchToGame( currentGame_t newGame )
|
|
{
|
|
idealCurrentGame = newGame;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::PerformGameSwitch
|
|
========================
|
|
*/
|
|
void idCommonLocal::PerformGameSwitch()
|
|
{
|
|
// If the session state is past the menu, we should be in Doom 3.
|
|
// This will happen if, for example, we accept an invite while playing
|
|
// Doom or Doom 2.
|
|
if( session->GetState() > idSession::IDLE )
|
|
{
|
|
idealCurrentGame = DOOM3_BFG;
|
|
}
|
|
|
|
if( currentGame == idealCurrentGame )
|
|
{
|
|
return;
|
|
}
|
|
|
|
const int DOOM_CLASSIC_HZ = 35;
|
|
|
|
if( idealCurrentGame == DOOM_CLASSIC || idealCurrentGame == DOOM2_CLASSIC )
|
|
{
|
|
// Pause Doom 3 sound.
|
|
if( menuSoundWorld != NULL )
|
|
{
|
|
menuSoundWorld->Pause();
|
|
}
|
|
|
|
DoomLib::skipToNew = false;
|
|
DoomLib::skipToLoad = false;
|
|
|
|
// Reset match parameters for the classics.
|
|
DoomLib::matchParms = idMatchParameters();
|
|
|
|
// The classics use the usercmd manager too, clear it.
|
|
userCmdMgr.SetDefaults();
|
|
|
|
// Classics need a local user too.
|
|
session->UpdateSignInManager();
|
|
session->GetSignInManager().RegisterLocalUser( 0 );
|
|
|
|
com_engineHz_denominator = 100LL * DOOM_CLASSIC_HZ;
|
|
com_engineHz_latched = DOOM_CLASSIC_HZ;
|
|
|
|
DoomLib::SetCurrentExpansion( idealCurrentGame );
|
|
|
|
}
|
|
else if( idealCurrentGame == DOOM3_BFG )
|
|
{
|
|
DoomLib::Interface.Shutdown();
|
|
com_engineHz_denominator = 100LL * com_engineHz.GetFloat();
|
|
com_engineHz_latched = com_engineHz.GetFloat();
|
|
|
|
// Don't MoveToPressStart if we have an invite, we need to go
|
|
// directly to the lobby.
|
|
if( session->GetState() <= idSession::IDLE )
|
|
{
|
|
session->MoveToPressStart();
|
|
}
|
|
|
|
// Unpause Doom 3 sound.
|
|
if( menuSoundWorld != NULL )
|
|
{
|
|
menuSoundWorld->UnPause();
|
|
}
|
|
}
|
|
|
|
currentGame = idealCurrentGame;
|
|
}
|
|
|
|
#endif // #if defined(USE_DOOMCLASSIC)
|
|
// RB end
|
|
|
|
/*
|
|
==================
|
|
Common_WritePrecache_f
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( writePrecache, "writes precache commands", NULL )
|
|
{
|
|
if( args.Argc() != 2 )
|
|
{
|
|
common->Printf( "USAGE: writePrecache <execFile>\n" );
|
|
return;
|
|
}
|
|
idStr str = args.Argv( 1 );
|
|
str.DefaultFileExtension( ".cfg" );
|
|
idFile* f = fileSystem->OpenFileWrite( str );
|
|
declManager->WritePrecacheCommands( f );
|
|
renderModelManager->WritePrecacheCommands( f );
|
|
uiManager->WritePrecacheCommands( f );
|
|
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
================
|
|
Common_Disconnect_f
|
|
================
|
|
*/
|
|
CONSOLE_COMMAND_SHIP( disconnect, "disconnects from a game", NULL )
|
|
{
|
|
session->QuitMatch();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Common_Hitch_f
|
|
===============
|
|
*/
|
|
CONSOLE_COMMAND( hitch, "hitches the game", NULL )
|
|
{
|
|
if( args.Argc() == 2 )
|
|
{
|
|
Sys_Sleep( atoi( args.Argv( 1 ) ) );
|
|
}
|
|
else
|
|
{
|
|
Sys_Sleep( 100 );
|
|
}
|
|
}
|
|
|
|
CONSOLE_COMMAND( showStringMemory, "shows memory used by strings", NULL )
|
|
{
|
|
idStr::ShowMemoryUsage_f( args );
|
|
}
|
|
CONSOLE_COMMAND( showDictMemory, "shows memory used by dictionaries", NULL )
|
|
{
|
|
idDict::ShowMemoryUsage_f( args );
|
|
}
|
|
CONSOLE_COMMAND( listDictKeys, "lists all keys used by dictionaries", NULL )
|
|
{
|
|
idDict::ListKeys_f( args );
|
|
}
|
|
CONSOLE_COMMAND( listDictValues, "lists all values used by dictionaries", NULL )
|
|
{
|
|
idDict::ListValues_f( args );
|
|
}
|
|
CONSOLE_COMMAND( testSIMD, "test SIMD code", NULL )
|
|
{
|
|
idSIMD::Test_f( args );
|
|
}
|