You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1860 lines
51 KiB
1860 lines
51 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// Defines the entry point for the application. |
|
// |
|
//===========================================================================// |
|
|
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
#include <windows.h> |
|
#include "shlwapi.h" // registry stuff |
|
#include <direct.h> |
|
#elif defined ( LINUX ) || defined( OSX ) |
|
#define O_EXLOCK 0 |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
#include <locale.h> |
|
#elif defined ( _X360 ) |
|
#else |
|
#error |
|
#endif |
|
#include "appframework/ilaunchermgr.h" |
|
#include <stdio.h> |
|
#include "tier0/icommandline.h" |
|
#include "engine_launcher_api.h" |
|
#include "tier0/vcrmode.h" |
|
#include "ifilesystem.h" |
|
#include "tier1/interface.h" |
|
#include "tier0/dbg.h" |
|
#include "iregistry.h" |
|
#include "appframework/IAppSystem.h" |
|
#include "appframework/AppFramework.h" |
|
#include <vgui/VGUI.h> |
|
#include <vgui/ISurface.h> |
|
#include "tier0/platform.h" |
|
#include "tier0/memalloc.h" |
|
#include "filesystem.h" |
|
#include "tier1/utlrbtree.h" |
|
#include "materialsystem/imaterialsystem.h" |
|
#include "istudiorender.h" |
|
#include "vgui/IVGui.h" |
|
#include "IHammer.h" |
|
#include "datacache/idatacache.h" |
|
#include "datacache/imdlcache.h" |
|
#include "vphysics_interface.h" |
|
#include "filesystem_init.h" |
|
#include "vstdlib/iprocessutils.h" |
|
#include "video/ivideoservices.h" |
|
#include "tier1/tier1.h" |
|
#include "tier2/tier2.h" |
|
#include "tier3/tier3.h" |
|
#include "p4lib/ip4.h" |
|
#include "inputsystem/iinputsystem.h" |
|
#include "filesystem/IQueuedLoader.h" |
|
#include "reslistgenerator.h" |
|
#include "tier1/fmtstr.h" |
|
#include "sourcevr/isourcevirtualreality.h" |
|
|
|
#define VERSION_SAFE_STEAM_API_INTERFACES |
|
#include "steam/steam_api.h" |
|
|
|
#if defined( _X360 ) |
|
#include "xbox/xbox_win32stubs.h" |
|
#include "xbox/xbox_console.h" |
|
#include "xbox/xbox_launch.h" |
|
#endif |
|
|
|
#if defined( USE_SDL ) |
|
#include "SDL.h" |
|
|
|
#if !defined( _WIN32 ) |
|
#define MB_OK 0x00000001 |
|
#define MB_SYSTEMMODAL 0x00000002 |
|
#define MB_ICONERROR 0x00000004 |
|
int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType ); |
|
#endif // _WIN32 |
|
|
|
#endif // USE_SDL |
|
|
|
#if defined( POSIX ) |
|
#define RELAUNCH_FILE "/tmp/hl2_relaunch" |
|
#endif |
|
|
|
#if defined ( ANDROID ) |
|
#include <android/log.h> |
|
#include "jni.h" |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define DEFAULT_HL2_GAMEDIR "hl2" |
|
|
|
#if defined( USE_SDL ) |
|
extern void* CreateSDLMgr(); |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Modules... |
|
//----------------------------------------------------------------------------- |
|
static IEngineAPI *g_pEngineAPI; |
|
static IHammer *g_pHammer; |
|
|
|
bool g_bTextMode = false; |
|
|
|
static char g_szBasedir[MAX_PATH]; |
|
static char g_szGamedir[MAX_PATH]; |
|
|
|
// copied from sys.h |
|
struct FileAssociationInfo |
|
{ |
|
char const *extension; |
|
char const *command_to_issue; |
|
}; |
|
|
|
static FileAssociationInfo g_FileAssociations[] = |
|
{ |
|
{ ".dem", "playdemo" }, |
|
{ ".sav", "load" }, |
|
{ ".bsp", "map" }, |
|
}; |
|
|
|
#ifdef _WIN32 |
|
#pragma warning(disable:4073) |
|
#pragma init_seg(lib) |
|
#endif |
|
|
|
class CLeakDump |
|
{ |
|
public: |
|
CLeakDump() |
|
: m_bCheckLeaks( false ) |
|
{ |
|
} |
|
|
|
~CLeakDump() |
|
{ |
|
if ( m_bCheckLeaks ) |
|
{ |
|
MemAlloc_DumpStats(); |
|
} |
|
} |
|
|
|
bool m_bCheckLeaks; |
|
} g_LeakDump; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Spew function! |
|
//----------------------------------------------------------------------------- |
|
SpewRetval_t LauncherDefaultSpewFunc( SpewType_t spewType, char const *pMsg ) |
|
{ |
|
#ifndef _CERT |
|
#ifdef WIN32 |
|
OutputDebugStringA( pMsg ); |
|
#else |
|
fprintf( stderr, "%s", pMsg ); |
|
#endif |
|
|
|
switch( spewType ) |
|
{ |
|
case SPEW_MESSAGE: |
|
case SPEW_LOG: |
|
return SPEW_CONTINUE; |
|
|
|
case SPEW_WARNING: |
|
if ( !stricmp( GetSpewOutputGroup(), "init" ) ) |
|
{ |
|
#if defined( WIN32 ) || defined( USE_SDL ) |
|
::MessageBox( NULL, pMsg, "Warning!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR ); |
|
#endif |
|
} |
|
return SPEW_CONTINUE; |
|
|
|
case SPEW_ASSERT: |
|
if ( !ShouldUseNewAssertDialog() ) |
|
{ |
|
#if defined( WIN32 ) || defined( USE_SDL ) |
|
::MessageBox( NULL, pMsg, "Assert!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR ); |
|
#endif |
|
} |
|
return SPEW_DEBUGGER; |
|
|
|
case SPEW_ERROR: |
|
default: |
|
#if defined( WIN32 ) || defined( USE_SDL ) |
|
::MessageBox( NULL, pMsg, "Error!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR ); |
|
#endif |
|
_exit( 1 ); |
|
} |
|
#else |
|
if ( spewType != SPEW_ERROR) |
|
return SPEW_CONTINUE; |
|
_exit( 1 ); |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Implementation of VCRHelpers. |
|
//----------------------------------------------------------------------------- |
|
class CVCRHelpers : public IVCRHelpers |
|
{ |
|
public: |
|
virtual void ErrorMessage( const char *pMsg ) |
|
{ |
|
#if defined( WIN32 ) || defined( LINUX ) |
|
NOVCR( ::MessageBox( NULL, pMsg, "VCR Error", MB_OK ) ); |
|
#endif |
|
} |
|
|
|
virtual void* GetMainWindow() |
|
{ |
|
return NULL; |
|
} |
|
}; |
|
|
|
static CVCRHelpers g_VCRHelpers; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the game directory |
|
// Output : char |
|
//----------------------------------------------------------------------------- |
|
char *GetGameDirectory( void ) |
|
{ |
|
return g_szGamedir; |
|
} |
|
|
|
void SetGameDirectory( const char *game ) |
|
{ |
|
Q_strncpy( g_szGamedir, game, sizeof(g_szGamedir) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets the executable name |
|
//----------------------------------------------------------------------------- |
|
bool GetExecutableName( char *out, int outSize ) |
|
{ |
|
#ifdef WIN32 |
|
if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, outSize ) ) |
|
{ |
|
return false; |
|
} |
|
return true; |
|
#else |
|
return false; |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the base directory |
|
// Output : char |
|
//----------------------------------------------------------------------------- |
|
char *GetBaseDirectory( void ) |
|
{ |
|
return g_szBasedir; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determine the directory where this .exe is running from |
|
//----------------------------------------------------------------------------- |
|
void UTIL_ComputeBaseDir() |
|
{ |
|
g_szBasedir[0] = 0; |
|
|
|
if ( IsX360() ) |
|
{ |
|
char const *pBaseDir = CommandLine()->ParmValue( "-basedir" ); |
|
if ( pBaseDir ) |
|
{ |
|
strcpy( g_szBasedir, pBaseDir ); |
|
} |
|
} |
|
|
|
if ( !g_szBasedir[0] && GetExecutableName( g_szBasedir, sizeof( g_szBasedir ) ) ) |
|
{ |
|
char *pBuffer = strrchr( g_szBasedir, '\\' ); |
|
if ( *pBuffer ) |
|
{ |
|
*(pBuffer+1) = '\0'; |
|
} |
|
|
|
int j = strlen( g_szBasedir ); |
|
if (j > 0) |
|
{ |
|
if ( ( g_szBasedir[j-1] == '\\' ) || |
|
( g_szBasedir[j-1] == '/' ) ) |
|
{ |
|
g_szBasedir[j-1] = 0; |
|
} |
|
} |
|
} |
|
|
|
if ( IsPC() ) |
|
{ |
|
char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" ); |
|
if ( pOverrideDir ) |
|
{ |
|
strcpy( g_szBasedir, pOverrideDir ); |
|
} |
|
} |
|
|
|
#ifdef WIN32 |
|
Q_strlower( g_szBasedir ); |
|
#endif |
|
Q_FixSlashes( g_szBasedir ); |
|
} |
|
|
|
#ifdef WIN32 |
|
BOOL WINAPI MyHandlerRoutine( DWORD dwCtrlType ) |
|
{ |
|
#if !defined( _X360 ) |
|
TerminateProcess( GetCurrentProcess(), 2 ); |
|
#endif |
|
return TRUE; |
|
} |
|
#endif |
|
|
|
void InitTextMode() |
|
{ |
|
#ifdef WIN32 |
|
#if !defined( _X360 ) |
|
AllocConsole(); |
|
|
|
SetConsoleCtrlHandler( MyHandlerRoutine, TRUE ); |
|
|
|
freopen( "CONIN$", "rb", stdin ); // reopen stdin handle as console window input |
|
freopen( "CONOUT$", "wb", stdout ); // reopen stout handle as console window output |
|
freopen( "CONOUT$", "wb", stderr ); // reopen stderr handle as console window output |
|
#else |
|
XBX_Error( "%s %s: Not Supported", __FILE__, __LINE__ ); |
|
#endif |
|
#endif |
|
} |
|
|
|
void SortResList( char const *pchFileName, char const *pchSearchPath ); |
|
|
|
#define ALL_RESLIST_FILE "all.lst" |
|
#define ENGINE_RESLIST_FILE "engine.lst" |
|
|
|
// create file to dump out to |
|
class CLogAllFiles |
|
{ |
|
public: |
|
CLogAllFiles(); |
|
void Init(); |
|
void Shutdown(); |
|
void LogFile( const char *fullPathFileName, const char *options ); |
|
|
|
private: |
|
static void LogAllFilesFunc( const char *fullPathFileName, const char *options ); |
|
void LogToAllReslist( char const *line ); |
|
|
|
bool m_bActive; |
|
char m_szCurrentDir[_MAX_PATH]; |
|
|
|
// persistent across restarts |
|
CUtlRBTree< CUtlString, int > m_Logged; |
|
CUtlString m_sResListDir; |
|
CUtlString m_sFullGamePath; |
|
}; |
|
|
|
static CLogAllFiles g_LogFiles; |
|
|
|
static bool AllLogLessFunc( CUtlString const &pLHS, CUtlString const &pRHS ) |
|
{ |
|
return CaselessStringLessThan( pLHS.Get(), pRHS.Get() ); |
|
} |
|
|
|
CLogAllFiles::CLogAllFiles() : |
|
m_bActive( false ), |
|
m_Logged( 0, 0, AllLogLessFunc ) |
|
{ |
|
MEM_ALLOC_CREDIT(); |
|
m_sResListDir = "reslists"; |
|
} |
|
|
|
void CLogAllFiles::Init() |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
return; |
|
} |
|
|
|
// Can't do this in edit mode |
|
if ( CommandLine()->CheckParm( "-edit" ) ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !CommandLine()->CheckParm( "-makereslists" ) ) |
|
{ |
|
return; |
|
} |
|
|
|
m_bActive = true; |
|
|
|
char const *pszDir = NULL; |
|
if ( CommandLine()->CheckParm( "-reslistdir", &pszDir ) && pszDir ) |
|
{ |
|
char szDir[ MAX_PATH ]; |
|
Q_strncpy( szDir, pszDir, sizeof( szDir ) ); |
|
Q_StripTrailingSlash( szDir ); |
|
#ifdef WIN32 |
|
Q_strlower( szDir ); |
|
#endif |
|
Q_FixSlashes( szDir ); |
|
if ( Q_strlen( szDir ) > 0 ) |
|
{ |
|
m_sResListDir = szDir; |
|
} |
|
} |
|
|
|
// game directory has not been established yet, must derive ourselves |
|
char path[MAX_PATH]; |
|
Q_snprintf( path, sizeof(path), "%s/%s", GetBaseDirectory(), CommandLine()->ParmValue( "-game", "hl2" ) ); |
|
Q_FixSlashes( path ); |
|
#ifdef WIN32 |
|
Q_strlower( path ); |
|
#endif |
|
m_sFullGamePath = path; |
|
|
|
// create file to dump out to |
|
char szDir[ MAX_PATH ]; |
|
V_snprintf( szDir, sizeof( szDir ), "%s\\%s", m_sFullGamePath.String(), m_sResListDir.String() ); |
|
g_pFullFileSystem->CreateDirHierarchy( szDir, "GAME" ); |
|
|
|
g_pFullFileSystem->AddLoggingFunc( &LogAllFilesFunc ); |
|
|
|
if ( !CommandLine()->FindParm( "-startmap" ) && !CommandLine()->FindParm( "-startstage" ) ) |
|
{ |
|
m_Logged.RemoveAll(); |
|
g_pFullFileSystem->RemoveFile( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "GAME" ); |
|
} |
|
|
|
#ifdef WIN32 |
|
::GetCurrentDirectory( sizeof(m_szCurrentDir), m_szCurrentDir ); |
|
Q_strncat( m_szCurrentDir, "\\", sizeof(m_szCurrentDir), 1 ); |
|
_strlwr( m_szCurrentDir ); |
|
#else |
|
getcwd( m_szCurrentDir, sizeof(m_szCurrentDir) ); |
|
Q_strncat( m_szCurrentDir, "/", sizeof(m_szCurrentDir), 1 ); |
|
#endif |
|
} |
|
|
|
void CLogAllFiles::Shutdown() |
|
{ |
|
if ( !m_bActive ) |
|
return; |
|
|
|
m_bActive = false; |
|
|
|
if ( CommandLine()->CheckParm( "-makereslists" ) ) |
|
{ |
|
g_pFullFileSystem->RemoveLoggingFunc( &LogAllFilesFunc ); |
|
} |
|
|
|
// Now load and sort all.lst |
|
SortResList( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "GAME" ); |
|
// Now load and sort engine.lst |
|
SortResList( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ENGINE_RESLIST_FILE ), "GAME" ); |
|
|
|
m_Logged.Purge(); |
|
} |
|
|
|
void CLogAllFiles::LogToAllReslist( char const *line ) |
|
{ |
|
// Open for append, write data, close. |
|
FileHandle_t fh = g_pFullFileSystem->Open( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "at", "GAME" ); |
|
if ( fh != FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
g_pFullFileSystem->Write("\"", 1, fh); |
|
g_pFullFileSystem->Write( line, Q_strlen(line), fh ); |
|
g_pFullFileSystem->Write("\"\n", 2, fh); |
|
g_pFullFileSystem->Close( fh ); |
|
} |
|
} |
|
|
|
void CLogAllFiles::LogFile(const char *fullPathFileName, const char *options) |
|
{ |
|
if ( !m_bActive ) |
|
{ |
|
Assert( 0 ); |
|
return; |
|
} |
|
|
|
// write out to log file |
|
Assert( fullPathFileName[1] == ':' ); |
|
|
|
int idx = m_Logged.Find( fullPathFileName ); |
|
if ( idx != m_Logged.InvalidIndex() ) |
|
{ |
|
return; |
|
} |
|
|
|
m_Logged.Insert( fullPathFileName ); |
|
|
|
// make it relative to our root directory |
|
const char *relative = Q_stristr( fullPathFileName, GetBaseDirectory() ); |
|
if ( relative ) |
|
{ |
|
relative += ( Q_strlen( GetBaseDirectory() ) + 1 ); |
|
|
|
char rel[ MAX_PATH ]; |
|
Q_strncpy( rel, relative, sizeof( rel ) ); |
|
#ifdef WIN32 |
|
Q_strlower( rel ); |
|
#endif |
|
Q_FixSlashes( rel ); |
|
|
|
LogToAllReslist( rel ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: callback function from filesystem |
|
//----------------------------------------------------------------------------- |
|
void CLogAllFiles::LogAllFilesFunc(const char *fullPathFileName, const char *options) |
|
{ |
|
g_LogFiles.LogFile( fullPathFileName, options ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: This is a bit of a hack because it appears |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
static bool IsWin98OrOlder() |
|
{ |
|
bool retval = false; |
|
|
|
#if defined( WIN32 ) && !defined( _X360 ) |
|
OSVERSIONINFOEX osvi; |
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); |
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
|
|
|
BOOL bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi); |
|
if( !bOsVersionInfoEx ) |
|
{ |
|
// If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. |
|
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); |
|
if ( !GetVersionEx ( (OSVERSIONINFO *) &osvi) ) |
|
{ |
|
Error( "IsWin98OrOlder: Unable to get OS version information" ); |
|
} |
|
} |
|
|
|
switch (osvi.dwPlatformId) |
|
{ |
|
case VER_PLATFORM_WIN32_NT: |
|
// NT, XP, Win2K, etc. all OK for SSE |
|
break; |
|
case VER_PLATFORM_WIN32_WINDOWS: |
|
// Win95, 98, Me can't do SSE |
|
retval = true; |
|
break; |
|
case VER_PLATFORM_WIN32s: |
|
// Can't really run this way I don't think... |
|
retval = true; |
|
break; |
|
default: |
|
break; |
|
} |
|
#endif |
|
|
|
return retval; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Figure out if Steam is running, then load the GameOverlayRenderer.dll |
|
//----------------------------------------------------------------------------- |
|
void TryToLoadSteamOverlayDLL() |
|
{ |
|
#if defined( WIN32 ) && !defined( _X360 ) |
|
// First, check if the module is already loaded, perhaps because we were run from Steam directly |
|
HMODULE hMod = GetModuleHandle( "GameOverlayRenderer" DLL_EXT_STRING ); |
|
if ( hMod ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( 0 == GetEnvironmentVariableA( "SteamGameId", NULL, 0 ) ) |
|
{ |
|
// Initializing the Steam client API has the side effect of setting up the AppId |
|
// which is immediately queried in GameOverlayRenderer.dll's DllMain entry point |
|
if( SteamAPI_InitSafe() ) |
|
{ |
|
const char *pchSteamInstallPath = SteamAPI_GetSteamInstallPath(); |
|
if ( pchSteamInstallPath ) |
|
{ |
|
char rgchSteamPath[MAX_PATH]; |
|
V_ComposeFileName( pchSteamInstallPath, "GameOverlayRenderer" DLL_EXT_STRING, rgchSteamPath, Q_ARRAYSIZE(rgchSteamPath) ); |
|
// This could fail, but we can't fix it if it does so just ignore failures |
|
LoadLibrary( rgchSteamPath ); |
|
|
|
} |
|
|
|
SteamAPI_Shutdown(); |
|
} |
|
} |
|
|
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Inner loop: initialize, shutdown main systems, load steam to |
|
//----------------------------------------------------------------------------- |
|
class CSourceAppSystemGroup : public CSteamAppSystemGroup |
|
{ |
|
public: |
|
// Methods of IApplication |
|
virtual bool Create(); |
|
virtual bool PreInit(); |
|
virtual int Main(); |
|
virtual void PostShutdown(); |
|
virtual void Destroy(); |
|
|
|
private: |
|
const char *DetermineDefaultMod(); |
|
const char *DetermineDefaultGame(); |
|
|
|
bool m_bEditMode; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// The dirty disk error report function |
|
//----------------------------------------------------------------------------- |
|
void ReportDirtyDiskNoMaterialSystem() |
|
{ |
|
#ifdef _X360 |
|
for ( int i = 0; i < 4; ++i ) |
|
{ |
|
if ( XUserGetSigninState( i ) != eXUserSigninState_NotSignedIn ) |
|
{ |
|
XShowDirtyDiscErrorUI( i ); |
|
return; |
|
} |
|
} |
|
XShowDirtyDiscErrorUI( 0 ); |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Instantiate all main libraries |
|
//----------------------------------------------------------------------------- |
|
bool CSourceAppSystemGroup::Create() |
|
{ |
|
IFileSystem *pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); |
|
pFileSystem->InstallDirtyDiskReportFunc( ReportDirtyDiskNoMaterialSystem ); |
|
|
|
#ifdef WIN32 |
|
CoInitialize( NULL ); |
|
#endif |
|
|
|
// Are we running in edit mode? |
|
m_bEditMode = CommandLine()->CheckParm( "-edit" ); |
|
|
|
double st = Plat_FloatTime(); |
|
|
|
AppSystemInfo_t appSystems[] = |
|
{ |
|
{ "engine" DLL_EXT_STRING, CVAR_QUERY_INTERFACE_VERSION }, // NOTE: This one must be first!! |
|
{ "inputsystem" DLL_EXT_STRING, INPUTSYSTEM_INTERFACE_VERSION }, |
|
{ "materialsystem" DLL_EXT_STRING, MATERIAL_SYSTEM_INTERFACE_VERSION }, |
|
{ "datacache" DLL_EXT_STRING, DATACACHE_INTERFACE_VERSION }, |
|
{ "datacache" DLL_EXT_STRING, MDLCACHE_INTERFACE_VERSION }, |
|
{ "datacache" DLL_EXT_STRING, STUDIO_DATA_CACHE_INTERFACE_VERSION }, |
|
{ "studiorender" DLL_EXT_STRING, STUDIO_RENDER_INTERFACE_VERSION }, |
|
{ "vphysics" DLL_EXT_STRING, VPHYSICS_INTERFACE_VERSION }, |
|
{ "video_services" DLL_EXT_STRING, VIDEO_SERVICES_INTERFACE_VERSION }, |
|
|
|
// NOTE: This has to occur before vgui2.dll so it replaces vgui2's surface implementation |
|
{ "vguimatsurface" DLL_EXT_STRING, VGUI_SURFACE_INTERFACE_VERSION }, |
|
{ "vgui2" DLL_EXT_STRING, VGUI_IVGUI_INTERFACE_VERSION }, |
|
{ "engine" DLL_EXT_STRING, VENGINE_LAUNCHER_API_VERSION }, |
|
|
|
{ "", "" } // Required to terminate the list |
|
}; |
|
|
|
#if defined( USE_SDL ) |
|
AddSystem( (IAppSystem *)CreateSDLMgr(), SDLMGR_INTERFACE_VERSION ); |
|
#endif |
|
|
|
if ( !AddSystems( appSystems ) ) |
|
return false; |
|
|
|
// This will be NULL for games that don't support VR. That's ok. Just don't load the DLL |
|
AppModule_t sourceVRModule = LoadModule( "sourcevr" DLL_EXT_STRING ); |
|
if( sourceVRModule != APP_MODULE_INVALID ) |
|
{ |
|
AddSystem( sourceVRModule, SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION ); |
|
} |
|
|
|
// pull in our filesystem dll to pull the queued loader from it, we need to do it this way due to the |
|
// steam/stdio split for our steam filesystem |
|
char pFileSystemDLL[MAX_PATH]; |
|
bool bSteam; |
|
if ( FileSystem_GetFileSystemDLLName( pFileSystemDLL, MAX_PATH, bSteam ) != FS_OK ) |
|
return false; |
|
|
|
AppModule_t fileSystemModule = LoadModule( pFileSystemDLL ); |
|
AddSystem( fileSystemModule, QUEUEDLOADER_INTERFACE_VERSION ); |
|
|
|
// Hook in datamodel and p4 control if we're running with -tools |
|
if ( IsPC() && ( ( CommandLine()->FindParm( "-tools" ) && !CommandLine()->FindParm( "-nop4" ) ) || CommandLine()->FindParm( "-p4" ) ) ) |
|
{ |
|
#ifdef STAGING_ONLY |
|
AppModule_t p4libModule = LoadModule( "p4lib" DLL_EXT_STRING ); |
|
IP4 *p4 = (IP4*)AddSystem( p4libModule, P4_INTERFACE_VERSION ); |
|
|
|
// If we are running with -steam then that means the tools are being used by an SDK user. Don't exit in this case! |
|
if ( !p4 && !CommandLine()->FindParm( "-steam" ) ) |
|
{ |
|
return false; |
|
} |
|
#endif // STAGING_ONLY |
|
|
|
AppModule_t vstdlibModule = LoadModule( "vstdlib" DLL_EXT_STRING ); |
|
IProcessUtils *processUtils = ( IProcessUtils* )AddSystem( vstdlibModule, PROCESS_UTILS_INTERFACE_VERSION ); |
|
if ( !processUtils ) |
|
return false; |
|
} |
|
|
|
// Connect to iterfaces loaded in AddSystems that we need locally |
|
IMaterialSystem *pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); |
|
if ( !pMaterialSystem ) |
|
return false; |
|
|
|
g_pEngineAPI = (IEngineAPI*)FindSystem( VENGINE_LAUNCHER_API_VERSION ); |
|
|
|
// Load the hammer DLL if we're in editor mode |
|
#if defined( _WIN32 ) && defined( STAGING_ONLY ) |
|
if ( m_bEditMode ) |
|
{ |
|
AppModule_t hammerModule = LoadModule( "hammer_dll" DLL_EXT_STRING ); |
|
g_pHammer = (IHammer*)AddSystem( hammerModule, INTERFACEVERSION_HAMMER ); |
|
if ( !g_pHammer ) |
|
{ |
|
return false; |
|
} |
|
} |
|
#endif // defined( _WIN32 ) && defined( STAGING_ONLY ) |
|
|
|
// Load up the appropriate shader DLL |
|
// This has to be done before connection. |
|
char const* pDLLName = "shaderapidx9" DLL_EXT_STRING; |
|
if ( CommandLine()->FindParm( "-noshaderapi" ) ) |
|
{ |
|
pDLLName = "shaderapiempty" DLL_EXT_STRING; |
|
} |
|
|
|
pMaterialSystem->SetShaderAPI( pDLLName ); |
|
|
|
double elapsed = Plat_FloatTime() - st; |
|
COM_TimestampedLog( "LoadAppSystems: Took %.4f secs to load libraries and get factories.", (float)elapsed ); |
|
|
|
return true; |
|
} |
|
|
|
bool CSourceAppSystemGroup::PreInit() |
|
{ |
|
CreateInterfaceFn factory = GetFactory(); |
|
ConnectTier1Libraries( &factory, 1 ); |
|
ConVar_Register( ); |
|
ConnectTier2Libraries( &factory, 1 ); |
|
ConnectTier3Libraries( &factory, 1 ); |
|
|
|
if ( !g_pFullFileSystem || !g_pMaterialSystem ) |
|
return false; |
|
|
|
CFSSteamSetupInfo steamInfo; |
|
steamInfo.m_bToolsMode = false; |
|
steamInfo.m_bSetSteamDLLPath = false; |
|
steamInfo.m_bSteam = g_pFullFileSystem->IsSteam(); |
|
steamInfo.m_bOnlyUseDirectoryName = true; |
|
steamInfo.m_pDirectoryName = DetermineDefaultMod(); |
|
if ( !steamInfo.m_pDirectoryName ) |
|
{ |
|
steamInfo.m_pDirectoryName = DetermineDefaultGame(); |
|
if ( !steamInfo.m_pDirectoryName ) |
|
{ |
|
Error( "FileSystem_LoadFileSystemModule: no -defaultgamedir or -game specified." ); |
|
} |
|
} |
|
if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) |
|
return false; |
|
|
|
CFSMountContentInfo fsInfo; |
|
fsInfo.m_pFileSystem = g_pFullFileSystem; |
|
fsInfo.m_bToolsMode = m_bEditMode; |
|
fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; |
|
if ( FileSystem_MountContent( fsInfo ) != FS_OK ) |
|
return false; |
|
|
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
fsInfo.m_pFileSystem->AddSearchPath( "platform", "PLATFORM" ); |
|
} |
|
else |
|
{ |
|
// 360 needs absolute paths |
|
FileSystem_AddSearchPath_Platform( g_pFullFileSystem, steamInfo.m_GameInfoPath ); |
|
} |
|
|
|
if ( IsPC() ) |
|
{ |
|
// This will get called multiple times due to being here, but only the first one will do anything |
|
reslistgenerator->Init( GetBaseDirectory(), CommandLine()->ParmValue( "-game", "hl2" ) ); |
|
|
|
// This will also get called each time, but will actually fix up the command line as needed |
|
reslistgenerator->SetupCommandLine(); |
|
} |
|
|
|
// FIXME: Logfiles is mod-specific, needs to move into the engine. |
|
g_LogFiles.Init(); |
|
|
|
// Required to run through the editor |
|
if ( m_bEditMode ) |
|
{ |
|
g_pMaterialSystem->EnableEditorMaterials(); |
|
} |
|
|
|
StartupInfo_t info; |
|
info.m_pInstance = GetAppInstance(); |
|
info.m_pBaseDirectory = GetBaseDirectory(); |
|
info.m_pInitialMod = DetermineDefaultMod(); |
|
info.m_pInitialGame = DetermineDefaultGame(); |
|
info.m_pParentAppSystemGroup = this; |
|
info.m_bTextMode = g_bTextMode; |
|
|
|
g_pEngineAPI->SetStartupInfo( info ); |
|
|
|
return true; |
|
} |
|
|
|
int CSourceAppSystemGroup::Main() |
|
{ |
|
return g_pEngineAPI->Run(); |
|
} |
|
|
|
void CSourceAppSystemGroup::PostShutdown() |
|
{ |
|
// FIXME: Logfiles is mod-specific, needs to move into the engine. |
|
g_LogFiles.Shutdown(); |
|
|
|
reslistgenerator->Shutdown(); |
|
|
|
DisconnectTier3Libraries(); |
|
DisconnectTier2Libraries(); |
|
ConVar_Unregister( ); |
|
DisconnectTier1Libraries(); |
|
} |
|
|
|
void CSourceAppSystemGroup::Destroy() |
|
{ |
|
g_pEngineAPI = NULL; |
|
g_pMaterialSystem = NULL; |
|
g_pHammer = NULL; |
|
|
|
#ifdef WIN32 |
|
CoUninitialize(); |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Determines the initial mod to use at load time. |
|
// We eventually (hopefully) will be able to switch mods at runtime |
|
// because the engine/hammer integration really wants this feature. |
|
//----------------------------------------------------------------------------- |
|
const char *CSourceAppSystemGroup::DetermineDefaultMod() |
|
{ |
|
if ( !m_bEditMode ) |
|
{ |
|
return CommandLine()->ParmValue( "-game", DEFAULT_HL2_GAMEDIR ); |
|
} |
|
return g_pHammer->GetDefaultMod(); |
|
} |
|
|
|
const char *CSourceAppSystemGroup::DetermineDefaultGame() |
|
{ |
|
if ( !m_bEditMode ) |
|
{ |
|
return CommandLine()->ParmValue( "-defaultgamedir", DEFAULT_HL2_GAMEDIR ); |
|
} |
|
return g_pHammer->GetDefaultGame(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// MessageBox for SDL/OSX |
|
//----------------------------------------------------------------------------- |
|
#if defined( USE_SDL ) && !defined( _WIN32 ) |
|
|
|
int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType ) |
|
{ |
|
SDL_ShowSimpleMessageBox( 0, header, message, GetAssertDialogParent() ); |
|
return 0; |
|
} |
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Allow only one windowed source app to run at a time |
|
//----------------------------------------------------------------------------- |
|
#ifdef WIN32 |
|
HANDLE g_hMutex = NULL; |
|
#elif defined(POSIX) |
|
int g_lockfd = -1; |
|
char g_lockFilename[MAX_PATH]; |
|
#endif |
|
bool GrabSourceMutex() |
|
{ |
|
#ifdef WIN32 |
|
if ( IsPC() ) |
|
{ |
|
// don't allow more than one instance to run |
|
g_hMutex = ::CreateMutex(NULL, FALSE, TEXT("hl2_singleton_mutex")); |
|
|
|
unsigned int waitResult = ::WaitForSingleObject(g_hMutex, 0); |
|
|
|
// Here, we have the mutex |
|
if (waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED) |
|
return true; |
|
|
|
// couldn't get the mutex, we must be running another instance |
|
::CloseHandle(g_hMutex); |
|
|
|
return false; |
|
} |
|
#elif defined(POSIX) |
|
|
|
// Under OSX use flock in /tmp/source_engine_<game>.lock, create the file if it doesn't exist |
|
const char *pchGameParam = CommandLine()->ParmValue( "-game", DEFAULT_HL2_GAMEDIR ); |
|
CRC32_t gameCRC; |
|
CRC32_Init(&gameCRC); |
|
CRC32_ProcessBuffer( &gameCRC, (void *)pchGameParam, Q_strlen( pchGameParam ) ); |
|
CRC32_Final( &gameCRC ); |
|
|
|
#ifdef ANDROID |
|
return true; |
|
#elif defined (LINUX) |
|
/* |
|
* Linux |
|
*/ |
|
|
|
// Check TMPDIR environment variable for temp directory. |
|
char *tmpdir = getenv( "TMPDIR" ); |
|
|
|
// If it's NULL, or it doesn't exist, or it isn't a directory, fallback to /tmp. |
|
struct stat buf; |
|
if( !tmpdir || stat( tmpdir, &buf ) || !S_ISDIR ( buf.st_mode ) ) |
|
tmpdir = "/tmp"; |
|
|
|
V_snprintf( g_lockFilename, sizeof(g_lockFilename), "%s/source_engine_%u.lock", tmpdir, gameCRC ); |
|
|
|
g_lockfd = open( g_lockFilename, O_WRONLY | O_CREAT, 0666 ); |
|
if ( g_lockfd == -1 ) |
|
{ |
|
printf( "open(%s) failed\n", g_lockFilename ); |
|
return false; |
|
} |
|
|
|
struct flock fl; |
|
fl.l_type = F_WRLCK; |
|
fl.l_whence = SEEK_SET; |
|
fl.l_start = 0; |
|
fl.l_len = 1; |
|
|
|
if ( fcntl ( g_lockfd, F_SETLK, &fl ) == -1 ) |
|
{ |
|
printf( "fcntl(%d) for %s failed\n", g_lockfd, g_lockFilename ); |
|
return false; |
|
} |
|
|
|
return true; |
|
#else |
|
/* |
|
* OSX |
|
*/ |
|
V_snprintf( g_lockFilename, sizeof(g_lockFilename), "/tmp/source_engine_%u.lock", gameCRC ); |
|
|
|
g_lockfd = open( g_lockFilename, O_CREAT | O_WRONLY | O_EXLOCK | O_NONBLOCK | O_TRUNC, 0777 ); |
|
if (g_lockfd >= 0) |
|
{ |
|
// make sure we give full perms to the file, we only one instance per machine |
|
fchmod( g_lockfd, 0777 ); |
|
|
|
// we leave the file open, under unix rules when we die we'll automatically close and remove the locks |
|
return true; |
|
} |
|
|
|
// We were unable to open the file, it should be because we are unable to retain a lock |
|
if ( errno != EWOULDBLOCK) |
|
{ |
|
fprintf( stderr, "unexpected error %d trying to exclusively lock %s\n", errno, g_lockFilename ); |
|
} |
|
|
|
return false; |
|
#endif // OSX |
|
|
|
#endif // POSIX |
|
return true; |
|
} |
|
|
|
void ReleaseSourceMutex() |
|
{ |
|
#ifdef WIN32 |
|
if ( IsPC() && g_hMutex ) |
|
{ |
|
::ReleaseMutex( g_hMutex ); |
|
::CloseHandle( g_hMutex ); |
|
g_hMutex = NULL; |
|
} |
|
#elif defined(POSIX) |
|
if ( g_lockfd != -1 ) |
|
{ |
|
close( g_lockfd ); |
|
g_lockfd = -1; |
|
unlink( g_lockFilename ); |
|
} |
|
#endif |
|
} |
|
|
|
// Remove all but the last -game parameter. |
|
// This is for mods based off something other than Half-Life 2 (like HL2MP mods). |
|
// The Steam UI does 'steam -applaunch 320 -game c:\steam\steamapps\sourcemods\modname', but applaunch inserts |
|
// its own -game parameter, which would supercede the one we really want if we didn't intercede here. |
|
void RemoveSpuriousGameParameters() |
|
{ |
|
// Find the last -game parameter. |
|
int nGameArgs = 0; |
|
char lastGameArg[MAX_PATH]; |
|
for ( int i=0; i < CommandLine()->ParmCount()-1; i++ ) |
|
{ |
|
if ( Q_stricmp( CommandLine()->GetParm( i ), "-game" ) == 0 ) |
|
{ |
|
Q_snprintf( lastGameArg, sizeof( lastGameArg ), "\"%s\"", CommandLine()->GetParm( i+1 ) ); |
|
++nGameArgs; |
|
++i; |
|
} |
|
} |
|
|
|
// We only care if > 1 was specified. |
|
if ( nGameArgs > 1 ) |
|
{ |
|
CommandLine()->RemoveParm( "-game" ); |
|
CommandLine()->AppendParm( "-game", lastGameArg ); |
|
} |
|
} |
|
|
|
/* |
|
============ |
|
va |
|
|
|
does a varargs printf into a temp buffer, so I don't need to have |
|
varargs versions of all text functions. |
|
============ |
|
*/ |
|
static char *va( char *format, ... ) |
|
{ |
|
va_list argptr; |
|
static char string[8][512]; |
|
static int curstring = 0; |
|
|
|
curstring = ( curstring + 1 ) % 8; |
|
|
|
va_start (argptr, format); |
|
Q_vsnprintf( string[curstring], sizeof( string[curstring] ), format, argptr ); |
|
va_end (argptr); |
|
|
|
return string[curstring]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *param - |
|
// Output : static char const |
|
//----------------------------------------------------------------------------- |
|
static char const *Cmd_TranslateFileAssociation(char const *param ) |
|
{ |
|
static char sz[ 512 ]; |
|
char *retval = NULL; |
|
|
|
char temp[ 512 ]; |
|
Q_strncpy( temp, param, sizeof( temp ) ); |
|
Q_FixSlashes( temp ); |
|
#ifdef WIN32 |
|
Q_strlower( temp ); |
|
#endif |
|
const char *extension = V_GetFileExtension(temp); |
|
// must have an extension to map |
|
if (!extension) |
|
return retval; |
|
extension--; // back up so we have the . in the extension |
|
|
|
int c = ARRAYSIZE( g_FileAssociations ); |
|
for ( int i = 0; i < c; i++ ) |
|
{ |
|
FileAssociationInfo& info = g_FileAssociations[ i ]; |
|
|
|
if ( ! Q_strcmp( extension, info.extension ) && |
|
! CommandLine()->FindParm(va( "+%s", info.command_to_issue ) ) ) |
|
{ |
|
// Translate if haven't already got one of these commands |
|
Q_strncpy( sz, temp, sizeof( sz ) ); |
|
Q_FileBase( sz, temp, sizeof( sz ) ); |
|
|
|
Q_snprintf( sz, sizeof( sz ), "%s %s", info.command_to_issue, temp ); |
|
retval = sz; |
|
break; |
|
} |
|
} |
|
|
|
// return null if no translation, otherwise return commands |
|
return retval; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Converts all the convar args into a convar command |
|
// Input : none |
|
// Output : const char * series of convars |
|
//----------------------------------------------------------------------------- |
|
static const char *BuildCommand() |
|
{ |
|
static CUtlBuffer build( 0, 0, CUtlBuffer::TEXT_BUFFER ); |
|
build.Clear(); |
|
|
|
// arg[0] is the executable name |
|
for ( int i=1; i < CommandLine()->ParmCount(); i++ ) |
|
{ |
|
const char *szParm = CommandLine()->GetParm(i); |
|
if (!szParm) continue; |
|
|
|
if (szParm[0] == '-') |
|
{ |
|
// skip -XXX options and eat their args |
|
const char *szValue = CommandLine()->ParmValue(szParm); |
|
if ( szValue ) i++; |
|
continue; |
|
} |
|
if (szParm[0] == '+') |
|
{ |
|
// convert +XXX options and stuff them into the build buffer |
|
const char *szValue = CommandLine()->ParmValue(szParm); |
|
if (szValue) |
|
{ |
|
build.PutString(va("%s %s;", szParm+1, szValue)); |
|
i++; |
|
} |
|
else |
|
{ |
|
build.PutString(szParm+1); |
|
build.PutChar(';'); |
|
} |
|
} |
|
else |
|
{ |
|
// singleton values, convert to command |
|
char const *translated = Cmd_TranslateFileAssociation( CommandLine()->GetParm( i ) ); |
|
if (translated) |
|
{ |
|
build.PutString(translated); |
|
build.PutChar(';'); |
|
} |
|
} |
|
} |
|
|
|
build.PutChar( '\0' ); |
|
|
|
return (const char *)build.Base(); |
|
} |
|
|
|
#ifdef ANDROID |
|
char dataDir[512]; |
|
|
|
const char *LauncherArgv[512]; |
|
char javaArgv[2048]; |
|
char gameName[512]; |
|
char startArgs[256][128]; |
|
char language[1024] = "english"; |
|
int iLastArgs = 0; |
|
static int scr_width,scr_height; |
|
|
|
bool bClient_loaded = false; |
|
bool bShowTouch = true; |
|
void *libclient; |
|
|
|
static struct jnimethods_s |
|
{ |
|
jclass actcls; |
|
JavaVM *vm; |
|
JNIEnv *env; |
|
jmethodID enableTextInput; |
|
} jni; |
|
|
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setMainPackFilePath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setMainPackFilePath" ); |
|
return setenv( "VALVE_PAK0_PATH", env->GetStringUTFChars(str, NULL), 1 ); |
|
} |
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setPatchPackFilePath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setPatchPackFilePath" ); |
|
return setenv( "VALVE_PAK1_PATH", env->GetStringUTFChars(str, NULL), 1 ); |
|
} |
|
DLL_EXPORT void Java_com_valvesoftware_ValveActivity2_setCacheDirectoryPath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setCacheDirectoryPath" ); |
|
//return setenv( "VALVE_CACHE_PATH", env->GetStringUTFChars(str, NULL), 1 ); |
|
} |
|
DLL_EXPORT void Java_com_valvesoftware_ValveActivity2_gpgsStart() |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_gpgsStart" ); |
|
} |
|
DLL_EXPORT void Java_com_valvesoftware_ValveActivity2_nativeOnActivityResult() |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_nativeOnActivityResult" ); |
|
} |
|
|
|
DLL_EXPORT void Java_com_valvesoftware_ValveActivity2_setNativeLibPath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setNativeLibPath" ); |
|
// snprintf(dataDir, sizeof dataDir, env->GetStringUTFChars(str, NULL)); |
|
} |
|
DLL_EXPORT void Java_com_valvesoftware_ValveActivity2_setLanguage(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
snprintf(language, sizeof language, "%s", env->GetStringUTFChars(str, NULL)); |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setLanguage" ); |
|
} |
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setDocumentDirectoryPath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setDocumentDirectoryPath" ); |
|
setenv( "HOME", env->GetStringUTFChars(str, NULL), 1); |
|
return setenv( "VALVE_CACHE_PATH", env->GetStringUTFChars(str, NULL), 1 ); |
|
} |
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setDropMip(int a1, int a2, signed int a3) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setDropMip" ); |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_saveGame() |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_saveGame" ); |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setDataDirectoryPath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity_setDataDirectoryPath" ); |
|
snprintf(dataDir, sizeof dataDir, env->GetStringUTFChars(str, NULL)); |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setExtrasPackFilePath(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity2_setExtrasPackFilePath" ); |
|
return setenv( "VALVE_PAK2_PATH", env->GetStringUTFChars(str, NULL), 1 ); |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setenv(JNIEnv *jenv, jclass *jclass, jstring env, jstring value, jint over) |
|
{ |
|
__android_log_print( ANDROID_LOG_DEBUG, "SourceSDK2013", "Java_com_valvesoftware_ValveActivity2_setenv %s=%s", jenv->GetStringUTFChars(env, NULL),jenv->GetStringUTFChars(value, NULL) ); |
|
return setenv( jenv->GetStringUTFChars(env, NULL), jenv->GetStringUTFChars(value, NULL), over ); |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setGame(JNIEnv *jenv, jclass *jclass, jstring game) |
|
{ |
|
snprintf(gameName, sizeof dataDir, "-game %s", jenv->GetStringUTFChars(game, NULL)); |
|
return setenv( "VALVE_MOD", jenv->GetStringUTFChars(game, NULL), 1); |
|
} |
|
|
|
typedef void (*t_TouchEvent)(int finger, int x, int y, int act); |
|
t_TouchEvent TouchEvent; |
|
|
|
DLL_EXPORT void clientLoaded( void ) |
|
{ |
|
bClient_loaded = true; |
|
libclient = dlopen("libclient.so",0); |
|
TouchEvent = (t_TouchEvent)dlsym(libclient, "TouchEvent"); |
|
((void (*)(bool, int, int))dlsym(libclient, "showTouch"))(bShowTouch, scr_width, scr_height); |
|
} |
|
|
|
DLL_EXPORT void showKeyboard( int show ) |
|
{ |
|
jni.env->CallStaticVoidMethod( jni.actcls, jni.enableTextInput, show ); |
|
} |
|
|
|
DLL_EXPORT void JNICALL Java_com_valvesoftware_ValveActivity2_showTouch(JNIEnv *env, jobject obj, jboolean show_touch, jint width, jint height) |
|
{ |
|
scr_width = width; |
|
scr_height = height; |
|
bShowTouch = show_touch; |
|
} |
|
|
|
DLL_EXPORT void JNICALL Java_com_valvesoftware_ValveActivity2_TouchEvent(JNIEnv *env, jobject obj, jint fingerid, jint x, jint y, jint action) |
|
{ |
|
if( !bClient_loaded ) |
|
return; |
|
|
|
TouchEvent( fingerid, x, y, action ); |
|
} |
|
|
|
DLL_EXPORT const char* getSystemLanguage() |
|
{ |
|
return language; |
|
} |
|
|
|
typedef void (*t_SDL_Android_Init)(JNIEnv* env, jclass cls); |
|
t_SDL_Android_Init SDL_Android_Init; |
|
|
|
//typedef void *(*t_SDL_StartTextInput)(); |
|
//t_SDL_StartTextInput SDL_StartTextInput; |
|
|
|
typedef void (*t_egl_init)(); |
|
t_egl_init egl_init; |
|
|
|
bool bUseGL; |
|
|
|
void SetRenderer() |
|
{ |
|
if ( bUseGL ) |
|
{ |
|
//setenv("USE_BIG_GL", "1", 1); |
|
} |
|
else |
|
{ |
|
setenv("REGAL_LOG", "0", 1); |
|
setenv("REGAL_LOG_ERROR", "0", 1); |
|
setenv("REGAL_LOG_WARNING", "0", 1); |
|
setenv("REGAL_LOG_INFO", "0", 1); |
|
setenv("REGAL_LOG_HTTP", "0", 1); |
|
setenv("REGAL_LOG_JSON", "0", 1); |
|
setenv("REGAL_LOG_CALLBACK", "0", 1); |
|
setenv("REGAL_LOG_ONCE", "0", 1); |
|
setenv("REGAL_LOG_POINTERS", "0", 1); |
|
setenv("REGAL_LOG_THREAD", "0", 1); |
|
setenv("REGAL_LOG_PROCESS", "0", 1); |
|
setenv("REGAL_LOG_ALL", "0", 1); |
|
setenv("REGAL_DEBUG", "0", 1); |
|
setenv("REGAL_ERROR", "0", 1); |
|
setenv("REGAL_LOG_FILE", "/dev/null", 1); |
|
setenv("REGAL_EMU_SO", "0", 1); |
|
setenv("REGAL_THREAD_LOCKING", "0", 1); |
|
setenv("REGAL_FORCE_ES2_PROFILE", "1", 1); |
|
setenv("REGAL_SYS_GLX", "0", 1); |
|
setenv("REGAL_SYS_ES2", "1", 1); |
|
setenv("REGAL_SYS_EGL", "1", 1); |
|
setenv("REGAL_SYS_GL", "0", 1); |
|
setenv("REGAL_GL_VERSION", "2.1", 1); |
|
setenv("REGAL_GL_EXTENSIONS", "GL_EXT_framebuffer_object GL_EXT_framebuffer_blit GL_OES_mapbuffer GL_EXT_texture_sRGB_decode GL_EXT_texture_compression_s3tc GL_EXT_texture_compression_dxt1", 1); |
|
} |
|
} |
|
|
|
void SetArg( const char *arg ) |
|
{ |
|
char *pch; |
|
char str[1024]; |
|
strncpy( str, arg, sizeof str ); |
|
pch = strtok (str," "); |
|
while (pch != NULL) |
|
{ |
|
strncpy( startArgs[iLastArgs], pch, sizeof startArgs[0] ); |
|
LauncherArgv[iLastArgs] = startArgs[iLastArgs]; |
|
iLastArgs++; |
|
pch = strtok (NULL, " "); |
|
} |
|
} |
|
|
|
DLL_EXPORT int Java_com_valvesoftware_ValveActivity2_setArgs(JNIEnv *env, jclass *clazz, jstring str) |
|
{ |
|
snprintf( javaArgv, sizeof javaArgv, env->GetStringUTFChars(str, NULL) ); |
|
} |
|
|
|
void SetStartArgs() |
|
{ |
|
char lang[2048]; |
|
snprintf(lang, sizeof lang, "-language %s +cc_lang %s", language, language); |
|
|
|
SetArg(dataDir); |
|
SetArg(lang); |
|
SetArg(gameName); |
|
SetArg(javaArgv); |
|
SetArg("-window " |
|
"-nosteam " |
|
"-nouserclip " |
|
"+sv_unlockedchapters 99 " |
|
"+mat_queue_mode 2 " |
|
"-ignoredxsupportcfg " |
|
"-regal " |
|
"+gl_rt_forcergba 1 " |
|
"+mat_antialias 1 " |
|
"-mat_antialias 1 " |
|
"+r_flashlightdepthtexture 1 " |
|
"+gl_dropmips 1 " |
|
"-insecure"); |
|
|
|
if( bUseGL ) |
|
SetArg("-userclip " |
|
"-gl_disablesamplerobjects " |
|
// "-egl " |
|
"+gl_enabletexsubimage 1 " |
|
"+gl_blitmode 1 " |
|
"+gl_supportMapBuffer 0 " |
|
"-gl_separatedepthstencil 0 " |
|
"-gl_nodepthtexture 0 " |
|
"+r_flashlight_version2 0 " |
|
"+gl_emurgba16 0 " |
|
"+gl_emunooverwrite 0"); |
|
else |
|
SetArg("-nouserclip " |
|
"-gl_disablesamplerobjects " |
|
"+gl_enabletexsubimage 0 " |
|
"+mat_reducefillrate 1 " |
|
"+gl_blitmode 1 " |
|
"+gl_supportMapBuffer 1 " |
|
"-gl_separatedepthstencil 0 "// default is 1 |
|
"-gl_nodepthtexture 1 " |
|
"+r_flashlight_version2 1 " |
|
"+gl_emurgba16 1 " |
|
"+gl_emunooverwrite 1"); |
|
} |
|
|
|
DLL_EXPORT int LauncherMain( int argc, char **argv ); |
|
|
|
DLL_EXPORT int LauncherMainAndroid( int argc, char **argv ) |
|
{ |
|
//void *sdlHandle = dlopen("libSDL2.so", 0); |
|
|
|
//SDL_Android_Init = (t_SDL_Android_Init)dlsym(sdlHandle, "SDL_Android_Init"); |
|
//SDL_Android_Init(env, cls); |
|
|
|
//SDL_StartTextInput = (t_SDL_StartTextInput)dlsym(sdlHandle, "SDL_StartTextInput"); |
|
//SDL_StartTextInput(); |
|
|
|
// unused? |
|
chdir(dataDir); |
|
getcwd(dataDir, sizeof dataDir); |
|
setenv( "VALVE_GAME_PATH", dataDir, 1 ); |
|
snprintf(dataDir, sizeof dataDir, "%s/hl2_linux", dataDir); |
|
|
|
bUseGL = false; |
|
|
|
SetRenderer(); |
|
SetStartArgs(); |
|
|
|
//#ifdef GL4ES |
|
void *glHandle = dlopen("libGL4ES.so", 0); |
|
egl_init = (t_egl_init)dlsym(glHandle, "egl_init"); |
|
if( egl_init ) |
|
egl_init(); |
|
//#endif |
|
|
|
//jni.env = env; |
|
//jni.actcls = env->FindClass("org/libsdl/app/SDLActivity"); |
|
//jni.enableTextInput = env->GetStaticMethodID(jni.actcls, "showKeyboard", "(I)V"); |
|
|
|
return LauncherMain(iLastArgs, LauncherArgv); |
|
} |
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: The real entry point for the application |
|
// Input : hInstance - |
|
// hPrevInstance - |
|
// lpCmdLine - |
|
// nCmdShow - |
|
// Output : int APIENTRY |
|
//----------------------------------------------------------------------------- |
|
#ifdef WIN32 |
|
extern "C" __declspec(DLL_EXPORT) int LauncherMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) |
|
#else |
|
DLL_EXPORT int LauncherMain( int argc, char **argv ) |
|
#endif |
|
{ |
|
#ifdef LINUX |
|
// Temporary fix to stop us from crashing in printf/sscanf functions that don't expect |
|
// localization to mess with your "." and "," float seperators. Mac OSX also sets LANG |
|
// to en_US.UTF-8 before starting up (in info.plist I believe). |
|
// We need to double check that localization for libcef is handled correctly |
|
// when we slam things to en_US.UTF-8. |
|
// Also check if C.UTF-8 exists and use it? This file: /usr/lib/locale/C.UTF-8. |
|
// It looks like it's only installed on Debian distros right now though. |
|
const char en_US[] = "en_US.UTF-8"; |
|
|
|
setenv( "LC_ALL", en_US, 1 ); |
|
setlocale( LC_ALL, en_US ); |
|
|
|
const char *CurrentLocale = setlocale( LC_ALL, NULL ); |
|
if ( Q_stricmp( CurrentLocale, en_US ) ) |
|
{ |
|
Warning( "WARNING: setlocale('%s') failed, using locale:'%s'. International characters may not work.\n", en_US, CurrentLocale ); |
|
} |
|
#endif // LINUX |
|
|
|
#ifdef WIN32 |
|
SetAppInstance( hInstance ); |
|
#elif defined( POSIX ) |
|
// Store off command line for argument searching |
|
Plat_SetCommandLine( BuildCmdLine( argc, argv, false ) ); |
|
|
|
if( CommandLine()->CheckParm( "-sleepatstartup" ) ) |
|
{ |
|
// When launching from Steam, it can be difficult to get a debugger attached when you're |
|
// crashing quickly at startup. So add a -sleepatstartup command line and sleep for 5 |
|
// seconds which should allow time to attach a debugger. |
|
sleep( 5 ); |
|
} |
|
#endif |
|
|
|
// Hook the debug output stuff. |
|
SpewOutputFunc( LauncherDefaultSpewFunc ); |
|
|
|
if ( 0 && IsWin98OrOlder() ) |
|
{ |
|
Error( "This build does not currently run under Windows 98/Me." ); |
|
return -1; |
|
} |
|
|
|
// Quickly check the hardware key, essentially a warning shot. |
|
if ( !Plat_VerifyHardwareKeyPrompt() ) |
|
{ |
|
return -1; |
|
} |
|
|
|
const char *filename; |
|
#ifdef WIN32 |
|
CommandLine()->CreateCmdLine( IsPC() ? VCRHook_GetCommandLine() : lpCmdLine ); |
|
#else |
|
CommandLine()->CreateCmdLine( argc, argv ); |
|
#endif |
|
|
|
// No -dxlevel or +mat_hdr_level allowed on POSIX |
|
#ifdef POSIX |
|
CommandLine()->RemoveParm( "-dxlevel" ); |
|
CommandLine()->RemoveParm( "+mat_hdr_level" ); |
|
CommandLine()->RemoveParm( "+mat_dxlevel" ); |
|
#endif |
|
|
|
// If we're using -default command line parameters, get rid of DX8 settings. |
|
if ( CommandLine()->CheckParm( "-default" ) ) |
|
{ |
|
CommandLine()->RemoveParm( "-dxlevel" ); |
|
CommandLine()->RemoveParm( "-maxdxlevel" ); |
|
CommandLine()->RemoveParm( "+mat_dxlevel" ); |
|
} |
|
|
|
// Figure out the directory the executable is running from |
|
UTIL_ComputeBaseDir(); |
|
|
|
#if defined( _X360 ) |
|
bool bSpewDllInfo = CommandLine()->CheckParm( "-dllinfo" ); |
|
bool bWaitForConsole = CommandLine()->CheckParm( "-vxconsole" ); |
|
XboxConsoleInit(); |
|
XBX_InitConsoleMonitor( bWaitForConsole || bSpewDllInfo ); |
|
#endif |
|
|
|
|
|
#if defined( _X360 ) |
|
if ( bWaitForConsole ) |
|
COM_TimestampedLog( "LauncherMain: Application Start - %s", CommandLine()->GetCmdLine() ); |
|
if ( bSpewDllInfo ) |
|
{ |
|
XBX_DumpDllInfo( GetBaseDirectory() ); |
|
Error( "Stopped!\n" ); |
|
} |
|
|
|
int storageID = XboxLaunch()->GetStorageID(); |
|
if ( storageID != XBX_INVALID_STORAGE_ID && storageID != XBX_STORAGE_DECLINED ) |
|
{ |
|
// Validate the storage device |
|
XDEVICE_DATA deviceData; |
|
DWORD ret = XContentGetDeviceData( storageID, &deviceData ); |
|
if ( ret != ERROR_SUCCESS ) |
|
{ |
|
// Device was removed |
|
storageID = XBX_INVALID_STORAGE_ID; |
|
XBX_QueueEvent( XEV_LISTENER_NOTIFICATION, WM_SYS_STORAGEDEVICESCHANGED, 0, 0 ); |
|
} |
|
} |
|
XBX_SetStorageDeviceId( storageID ); |
|
|
|
int userID = XboxLaunch()->GetUserID(); |
|
if ( !IsRetail() && userID == XBX_INVALID_USER_ID ) |
|
{ |
|
// didn't come from appchooser, try find a valid user id for dev purposes |
|
XUSER_SIGNIN_INFO info; |
|
for ( int i = 0; i < 4; ++i ) |
|
{ |
|
if ( ERROR_NO_SUCH_USER != XUserGetSigninInfo( i, 0, &info ) ) |
|
{ |
|
userID = i; |
|
break; |
|
} |
|
} |
|
} |
|
XBX_SetPrimaryUserId( userID ); |
|
#endif // defined( _X360 ) |
|
|
|
#ifdef POSIX |
|
{ |
|
struct stat st; |
|
if ( stat( RELAUNCH_FILE, &st ) == 0 ) |
|
{ |
|
unlink( RELAUNCH_FILE ); |
|
} |
|
} |
|
#endif |
|
|
|
// This call is to emulate steam's injection of the GameOverlay DLL into our process if we |
|
// are running from the command line directly, this allows the same experience the user gets |
|
// to be present when running from perforce, the call has no effect on X360 |
|
TryToLoadSteamOverlayDLL(); |
|
|
|
// Start VCR mode? |
|
if ( CommandLine()->CheckParm( "-vcrrecord", &filename ) ) |
|
{ |
|
if ( !VCRStart( filename, true, &g_VCRHelpers ) ) |
|
{ |
|
Error( "-vcrrecord: can't open '%s' for writing.\n", filename ); |
|
return -1; |
|
} |
|
} |
|
else if ( CommandLine()->CheckParm( "-vcrplayback", &filename ) ) |
|
{ |
|
if ( !VCRStart( filename, false, &g_VCRHelpers ) ) |
|
{ |
|
Error( "-vcrplayback: can't open '%s' for reading.\n", filename ); |
|
return -1; |
|
} |
|
} |
|
|
|
// See the function for why we do this. |
|
RemoveSpuriousGameParameters(); |
|
|
|
#ifdef WIN32 |
|
if ( IsPC() ) |
|
{ |
|
// initialize winsock |
|
WSAData wsaData; |
|
int nError = ::WSAStartup( MAKEWORD(2,0), &wsaData ); |
|
if ( nError ) |
|
{ |
|
Msg( "Warning! Failed to start Winsock via WSAStartup = 0x%x.\n", nError); |
|
} |
|
} |
|
#endif |
|
|
|
// Run in text mode? (No graphics or sound). |
|
if ( CommandLine()->CheckParm( "-textmode" ) ) |
|
{ |
|
g_bTextMode = true; |
|
InitTextMode(); |
|
} |
|
#ifdef WIN32 |
|
else |
|
{ |
|
int retval = -1; |
|
// Can only run one windowed source app at a time |
|
if ( !GrabSourceMutex() ) |
|
{ |
|
// Allow the user to explicitly say they want to be able to run multiple instances of the source mutex. |
|
// Useful for side-by-side comparisons of different renderers. |
|
bool multiRun = CommandLine()->CheckParm( "-multirun" ) != NULL; |
|
|
|
// We're going to hijack the existing session and load a new savegame into it. This will mainly occur when users click on links in Bugzilla that will automatically copy saves and load them |
|
// directly from the web browser. The -hijack command prevents the launcher from objecting that there is already an instance of the game. |
|
if (CommandLine()->CheckParm( "-hijack" )) |
|
{ |
|
HWND hwndEngine = FindWindow( "Valve001", NULL ); |
|
|
|
// Can't find the engine |
|
if ( hwndEngine == NULL ) |
|
{ |
|
::MessageBox( NULL, "The modified entity keyvalues could not be sent to the Source Engine because the engine does not appear to be running.", "Source Engine Not Running", MB_OK | MB_ICONEXCLAMATION ); |
|
} |
|
else |
|
{ |
|
const char *szCommand = BuildCommand(); |
|
|
|
// |
|
// Fill out the data structure to send to the engine. |
|
// |
|
COPYDATASTRUCT copyData; |
|
copyData.cbData = strlen( szCommand ) + 1; |
|
copyData.dwData = 0; |
|
copyData.lpData = ( void * )szCommand; |
|
|
|
if ( !::SendMessage( hwndEngine, WM_COPYDATA, 0, (LPARAM)©Data ) ) |
|
{ |
|
::MessageBox( NULL, "The Source Engine was found running, but did not accept the request to load a savegame. It may be an old version of the engine that does not support this functionality.", "Source Engine Declined Request", MB_OK | MB_ICONEXCLAMATION ); |
|
} |
|
else |
|
{ |
|
retval = 0; |
|
} |
|
|
|
free((void *)szCommand); |
|
} |
|
} |
|
else |
|
{ |
|
if (!multiRun) { |
|
::MessageBox(NULL, "Only one instance of the game can be running at one time.", "Source - Warning", MB_ICONINFORMATION | MB_OK); |
|
} |
|
} |
|
|
|
if (!multiRun) { |
|
return retval; |
|
} |
|
} |
|
} |
|
#elif defined( POSIX ) |
|
else |
|
{ |
|
if ( !GrabSourceMutex() ) |
|
{ |
|
::MessageBox(NULL, "Only one instance of the game can be running at one time.", "Source - Warning", 0 ); |
|
return -1; |
|
} |
|
} |
|
#endif |
|
|
|
#ifdef WIN32 |
|
// Make low priority? |
|
if ( CommandLine()->CheckParm( "-low" ) ) |
|
{ |
|
SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS ); |
|
} |
|
else if ( CommandLine()->CheckParm( "-high" ) ) |
|
{ |
|
SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ); |
|
} |
|
#endif |
|
|
|
// If game is not run from Steam then add -insecure in order to avoid client timeout message |
|
if ( NULL == CommandLine()->CheckParm( "-steam" ) ) |
|
{ |
|
CommandLine()->AppendParm( "-insecure", NULL ); |
|
} |
|
|
|
// Figure out the directory the executable is running from |
|
// and make that be the current working directory |
|
_chdir( GetBaseDirectory() ); |
|
|
|
g_LeakDump.m_bCheckLeaks = CommandLine()->CheckParm( "-leakcheck" ) ? true : false; |
|
|
|
bool bRestart = true; |
|
while ( bRestart ) |
|
{ |
|
bRestart = false; |
|
|
|
CSourceAppSystemGroup sourceSystems; |
|
CSteamApplication steamApplication( &sourceSystems ); |
|
int nRetval = steamApplication.Run(); |
|
if ( steamApplication.GetErrorStage() == CSourceAppSystemGroup::INITIALIZATION ) |
|
{ |
|
bRestart = (nRetval == INIT_RESTART); |
|
} |
|
else if ( nRetval == RUN_RESTART ) |
|
{ |
|
bRestart = true; |
|
} |
|
|
|
bool bReslistCycle = false; |
|
if ( !bRestart ) |
|
{ |
|
bReslistCycle = reslistgenerator->ShouldContinue(); |
|
bRestart = bReslistCycle; |
|
} |
|
|
|
if ( !bReslistCycle ) |
|
{ |
|
// Remove any overrides in case settings changed |
|
CommandLine()->RemoveParm( "-w" ); |
|
CommandLine()->RemoveParm( "-h" ); |
|
CommandLine()->RemoveParm( "-width" ); |
|
CommandLine()->RemoveParm( "-height" ); |
|
CommandLine()->RemoveParm( "-sw" ); |
|
CommandLine()->RemoveParm( "-startwindowed" ); |
|
CommandLine()->RemoveParm( "-windowed" ); |
|
CommandLine()->RemoveParm( "-window" ); |
|
CommandLine()->RemoveParm( "-full" ); |
|
CommandLine()->RemoveParm( "-fullscreen" ); |
|
CommandLine()->RemoveParm( "-dxlevel" ); |
|
CommandLine()->RemoveParm( "-autoconfig" ); |
|
CommandLine()->RemoveParm( "+mat_hdr_level" ); |
|
} |
|
} |
|
|
|
#ifdef WIN32 |
|
if ( IsPC() ) |
|
{ |
|
// shutdown winsock |
|
int nError = ::WSACleanup(); |
|
if ( nError ) |
|
{ |
|
Msg( "Warning! Failed to complete WSACleanup = 0x%x.\n", nError ); |
|
} |
|
} |
|
#endif |
|
|
|
// Allow other source apps to run |
|
ReleaseSourceMutex(); |
|
|
|
#if defined( WIN32 ) && !defined( _X360 ) |
|
|
|
// Now that the mutex has been released, check HKEY_CURRENT_USER\Software\Valve\Source\Relaunch URL. If there is a URL here, exec it. |
|
// This supports the capability of immediately re-launching the the game via Steam in a different audio language |
|
HKEY hKey; |
|
if ( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Source", NULL, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS ) |
|
{ |
|
char szValue[MAX_PATH]; |
|
DWORD dwValueLen = MAX_PATH; |
|
|
|
if ( RegQueryValueEx( hKey, "Relaunch URL", NULL, NULL, (unsigned char*)szValue, &dwValueLen ) == ERROR_SUCCESS ) |
|
{ |
|
ShellExecute (0, "open", szValue, 0, 0, SW_SHOW); |
|
RegDeleteValue( hKey, "Relaunch URL" ); |
|
} |
|
|
|
RegCloseKey(hKey); |
|
} |
|
|
|
#elif defined( OSX ) || defined( LINUX ) |
|
struct stat st; |
|
if ( stat( RELAUNCH_FILE, &st ) == 0 ) |
|
{ |
|
FILE *fp = fopen( RELAUNCH_FILE, "r" ); |
|
if ( fp ) |
|
{ |
|
char szCmd[256]; |
|
int nChars = fread( szCmd, 1, sizeof(szCmd), fp ); |
|
if ( nChars > 0 ) |
|
{ |
|
if ( nChars > (sizeof(szCmd)-1) ) |
|
{ |
|
nChars = (sizeof(szCmd)-1); |
|
} |
|
szCmd[nChars] = 0; |
|
char szOpenLine[ MAX_PATH ]; |
|
#if defined( LINUX ) |
|
Q_snprintf( szOpenLine, sizeof(szOpenLine), "xdg-open \"%s\"", szCmd ); |
|
#else |
|
Q_snprintf( szOpenLine, sizeof(szOpenLine), "open \"%s\"", szCmd ); |
|
#endif |
|
system( szOpenLine ); |
|
} |
|
fclose( fp ); |
|
unlink( RELAUNCH_FILE ); |
|
} |
|
} |
|
#elif defined( _X360 ) |
|
#else |
|
#error |
|
#endif |
|
|
|
return 0; |
|
}
|
|
|