2013-08-29 11:45:22 +09:00
/*
Copyright ( c ) 2013 yvt
2014-04-06 20:10:13 +11:00
2013-08-29 11:45:22 +09:00
This file is part of OpenSpades .
2014-04-06 20:10:13 +11:00
2013-08-29 11:45:22 +09:00
OpenSpades 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 .
2014-04-06 20:10:13 +11:00
2013-08-29 11:45:22 +09:00
OpenSpades 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 .
2014-04-06 20:10:13 +11:00
2013-08-29 11:45:22 +09:00
You should have received a copy of the GNU General Public License
along with OpenSpades . If not , see < http : //www.gnu.org/licenses/>.
2014-04-06 20:10:13 +11:00
2013-08-29 11:45:22 +09:00
*/
2013-08-18 16:18:06 +09:00
2013-08-29 00:21:27 +02:00
# include <OpenSpades.h>
2016-07-16 00:14:59 +09:00
# include <zlib.h>
2013-11-22 22:50:14 +09:00
# include <Imports/SDL.h>
# include "Main.h"
# include "MainScreen.h"
2013-09-13 23:07:49 +02:00
# include <Core/FileManager.h>
# include <Core/DirectoryFileSystem.h>
# include <Core/Debug.h>
# include <Core/Settings.h>
# include <Core/ConcurrentDispatch.h>
2013-11-27 00:46:12 +09:00
# include <Core/Thread.h>
2013-09-13 23:07:49 +02:00
# include <Core/ZipFileSystem.h>
2013-10-09 23:18:13 +02:00
# include <Core/ServerAddress.h>
2013-11-22 22:50:14 +09:00
# include "Runner.h"
2013-11-28 17:39:00 +01:00
# include <Client/GameMap.h>
2013-11-22 22:50:14 +09:00
# include <Client/Client.h>
2013-12-25 14:21:21 +09:00
# include <Core/CpuID.h>
2014-02-07 00:09:26 +09:00
# include <Gui/StartupScreen.h>
2014-02-14 16:24:10 +09:00
# include <Core/Strings.h>
2013-08-18 16:18:06 +09:00
2013-09-13 23:07:49 +02:00
# include <Core/VoxelModel.h>
# include <Draw/GLOptimizedVoxelModel.h>
2013-08-18 16:18:06 +09:00
2013-09-14 02:05:05 +02:00
# include <ScriptBindings/ScriptManager.h>
2013-09-12 02:10:44 +09:00
2013-09-13 23:07:36 +02:00
# include <algorithm> //std::sort
2014-03-31 20:37:23 +09:00
# include <memory>
# include <Core/MemoryStream.h>
# include <Core/Bitmap.h>
2014-04-07 19:58:10 +11:00
# ifdef __APPLE__
# elif __unix
# include <sys/types.h>
# include <sys/stat.h>
# endif
2016-07-15 19:35:09 +09:00
# if _MSC_VER >= 1900 // Visual Studio 2015 or higher
2016-02-17 21:47:55 +02:00
extern " C " { FILE __iob_func [ 3 ] = { * stdin , * stdout , * stderr } ; }
2016-03-01 16:35:36 +02:00
# endif
2016-02-17 21:47:55 +02:00
2014-03-31 20:37:23 +09:00
static const unsigned char splashImage [ ] = {
# include "SplashImage.inc"
} ;
2016-07-15 19:35:09 +09:00
# ifdef __APPLE__
# elif __unix
2014-05-06 00:22:01 +11:00
static const unsigned char Icon [ ] = {
# include "Icon.inc"
} ;
2016-07-15 19:35:09 +09:00
# endif
2014-05-06 00:22:01 +11:00
2014-05-03 17:33:51 +09:00
SPADES_SETTING ( cl_showStartupWindow , " 1 " ) ;
2013-11-27 00:48:58 +09:00
2013-08-18 16:18:06 +09:00
# ifdef WIN32
# include <windows.h>
# include <shlobj.h>
2013-10-09 23:18:13 +02:00
# define strncasecmp(x,y,z) _strnicmp(x,y,z)
# define strcasecmp(x,y) _stricmp(x,y)
2013-11-01 22:08:03 +01:00
2014-01-01 20:43:46 +09:00
SPADES_SETTING ( core_win32BeginPeriod , " 1 " ) ;
class ThreadQuantumSetter {
public :
ThreadQuantumSetter ( ) {
if ( core_win32BeginPeriod ) {
timeBeginPeriod ( 1 ) ;
SPLog ( " Thread quantum was modified to 1ms by timeBeginPeriod " ) ;
SPLog ( " (to disable this behavior, set core_win32BeginPeriod to 0) " ) ;
} else {
SPLog ( " Thread quantum is not modified " ) ;
SPLog ( " (to enable this behavior, set core_win32BeginPeriod to 1) " ) ;
}
}
~ ThreadQuantumSetter ( ) {
if ( core_win32BeginPeriod ) {
timeEndPeriod ( 1 ) ;
SPLog ( " Thread quantum was restored " ) ;
}
}
} ;
2013-11-01 22:08:03 +01:00
//lm: without doing it this way, we will get a low-res icon or an ugly resampled icon in our window.
//we cannot use the fltk function on the console window, because it's not an Fl_Window...
void setIcon ( HWND hWnd )
{
HINSTANCE hInstance = GetModuleHandle ( NULL ) ;
HICON hIcon = ( HICON ) LoadImageA ( hInstance , " AppIcon " , IMAGE_ICON , GetSystemMetrics ( SM_CXICON ) , GetSystemMetrics ( SM_CYICON ) , 0 ) ;
if ( hIcon ) {
SendMessage ( hWnd , WM_SETICON , ICON_BIG , ( LPARAM ) hIcon ) ;
}
hIcon = ( HICON ) LoadImageA ( hInstance , " AppIcon " , IMAGE_ICON , GetSystemMetrics ( SM_CXSMICON ) , GetSystemMetrics ( SM_CYSMICON ) , 0 ) ;
if ( hIcon ) {
SendMessage ( hWnd , WM_SETICON , ICON_SMALL , ( LPARAM ) hIcon ) ;
}
}
2013-12-24 00:31:51 +01:00
# include <DbgHelp.h>
LONG WINAPI UnhandledExceptionProc ( LPEXCEPTION_POINTERS lpEx )
{
typedef BOOL ( WINAPI * PDUMPFN ) ( HANDLE hProcess , DWORD ProcessId , HANDLE hFile , MINIDUMP_TYPE DumpType , PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam , PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam , PMINIDUMP_CALLBACK_INFORMATION CallbackParam ) ;
HMODULE hLib = LoadLibrary ( " DbgHelp.dll " ) ;
PDUMPFN pMiniDumpWriteDump = ( PDUMPFN ) GetProcAddress ( hLib , " MiniDumpWriteDump " ) ;
static char buf [ MAX_PATH + 120 ] = { 0 } ; //this is our display buffer.
if ( pMiniDumpWriteDump ) {
static char fullBuf [ MAX_PATH + 120 ] = { 0 } ;
if ( SUCCEEDED ( SHGetFolderPath ( NULL , CSIDL_DESKTOPDIRECTORY , NULL , 0 , buf ) ) ) { //max length = MAX_PATH (temp abuse this buffer space)
strcat_s ( buf , " \\ " ) ; // ensure we end with a slash.
} else {
buf [ 0 ] = 0 ; //empty it, the file will now end up in the working directory :(
}
sprintf ( fullBuf , " %sOpenSpadesCrash%d.dmp " , buf , GetTickCount ( ) ) ; //some sort of randomization.
2014-04-06 20:10:13 +11:00
HANDLE hFile = CreateFile ( fullBuf , GENERIC_READ | GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-12-24 00:31:51 +01:00
if ( hFile ! = INVALID_HANDLE_VALUE ) {
MINIDUMP_EXCEPTION_INFORMATION mdei = { 0 } ;
mdei . ThreadId = GetCurrentThreadId ( ) ;
mdei . ExceptionPointers = lpEx ;
mdei . ClientPointers = TRUE ;
MINIDUMP_TYPE mdt = MiniDumpNormal ;
BOOL rv = pMiniDumpWriteDump ( GetCurrentProcess ( ) , GetCurrentProcessId ( ) , hFile , mdt , ( lpEx ! = 0 ) ? & mdei : 0 , 0 , 0 ) ;
CloseHandle ( hFile ) ;
sprintf_s ( buf , " Something went horribly wrong, please send the file \n %s \n for analysis. " , fullBuf ) ;
} else {
sprintf_s ( buf , " Something went horribly wrong, \n i even failed to store information about the problem... (0x%08x) " , lpEx ? lpEx - > ExceptionRecord - > ExceptionCode : 0xffffffff ) ;
}
} else {
sprintf_s ( buf , " Something went horribly wrong, \n i even failed to retrieve information about the problem... (0x%08x) " , lpEx ? lpEx - > ExceptionRecord - > ExceptionCode : 0xffffffff ) ;
}
MessageBoxA ( NULL , buf , " Oops, we crashed... " , MB_OK | MB_ICONERROR ) ;
ExitProcess ( - 1 ) ;
//return EXCEPTION_EXECUTE_HANDLER;
}
2014-01-01 20:43:46 +09:00
# else
class ThreadQuantumSetter {
2014-04-06 20:10:13 +11:00
2014-01-01 20:43:46 +09:00
} ;
2013-08-18 16:18:06 +09:00
# endif
2013-10-09 23:18:13 +02:00
SPADES_SETTING ( cg_lastQuickConnectHost , " " ) ;
SPADES_SETTING ( cg_protocolVersion , " " ) ;
2013-12-08 23:49:39 +09:00
SPADES_SETTING ( cg_playerName , " " ) ;
2013-10-09 23:18:13 +02:00
int cg_autoConnect = 0 ;
2014-05-08 16:40:44 +03:00
bool cg_printVersion = false ;
bool cg_printHelp = false ;
void printHelp ( char * binaryName )
{
2014-09-14 00:11:19 +11:00
printf ( " usage: %s [server_address] [v=protocol_version] [-h|--help] [-v|--version] \n " , binaryName ) ;
2014-05-08 16:40:44 +03:00
}
2013-10-09 23:18:13 +02:00
int argsHandler ( int argc , char * * argv , int & i )
{
if ( char * a = argv [ i ] ) {
if ( ! strncasecmp ( a , " aos:// " , 6 ) ) {
cg_lastQuickConnectHost = a ;
cg_autoConnect = 1 ;
return + + i ;
}
//lm: we attempt to detect protocol version, allowing with or without a prefix 'v='
//we set proto, but without url we will not auto-connect
if ( a [ 0 ] = = ' v ' & & a [ 1 ] = = ' = ' ) { a + = 2 ; }
if ( ! strcasecmp ( a , " 75 " ) | | ! strcasecmp ( a , " 075 " ) | | ! strcasecmp ( a , " 0.75 " ) ) {
cg_protocolVersion = 3 ;
return + + i ;
}
if ( ! strcasecmp ( a , " 76 " ) | | ! strcasecmp ( a , " 076 " ) | | ! strcasecmp ( a , " 0.76 " ) ) {
cg_protocolVersion = 4 ;
return + + i ;
}
2014-05-08 16:40:44 +03:00
if ( ! strcasecmp ( a , " --version " ) | | ! strcasecmp ( a , " -v " ) ) {
cg_printVersion = true ;
return + + i ;
}
if ( ! strcasecmp ( a , " --help " ) | | ! strcasecmp ( a , " -h " ) ) {
cg_printHelp = true ;
return + + i ;
}
}
2013-10-09 23:18:13 +02:00
return 0 ;
}
2013-11-22 22:50:14 +09:00
namespace spades {
void StartClient ( const spades : : ServerAddress & addr , const std : : string & playerName ) {
class ConcreteRunner : public spades : : gui : : Runner {
spades : : ServerAddress addr ;
std : : string playerName ;
protected :
virtual spades : : gui : : View * CreateView ( spades : : client : : IRenderer * renderer , spades : : client : : IAudioDevice * audio ) {
return new spades : : client : : Client ( renderer , audio , addr , playerName ) ;
}
public :
ConcreteRunner ( const spades : : ServerAddress & addr ,
const std : : string & playerName ) :
addr ( addr ) , playerName ( playerName ) { }
} ;
ConcreteRunner runner ( addr , playerName ) ;
runner . RunProtected ( ) ;
}
void StartMainScreen ( ) {
class ConcreteRunner : public spades : : gui : : Runner {
protected :
virtual spades : : gui : : View * CreateView ( spades : : client : : IRenderer * renderer , spades : : client : : IAudioDevice * audio ) {
return new spades : : gui : : MainScreen ( renderer , audio ) ;
}
public :
} ;
ConcreteRunner runner ;
runner . RunProtected ( ) ;
}
}
2013-11-28 17:39:00 +01:00
2014-03-31 20:37:23 +09:00
/** Thrown when user wants to exit the program while its initialization. */
class ExitRequestException : public std : : exception {
public :
ExitRequestException ( ) throw ( ) { }
} ;
class SplashWindow {
SDL_Window * window ;
SDL_Surface * surface ;
spades : : Handle < spades : : Bitmap > bmp ;
bool startupScreenRequested ;
public :
SplashWindow ( ) :
window ( nullptr ) ,
surface ( nullptr ) ,
startupScreenRequested ( false ) {
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
spades : : MemoryStream stream ( reinterpret_cast < const char * > ( splashImage ) , sizeof ( splashImage ) ) ;
bmp . Set ( spades : : Bitmap : : Load ( & stream ) , false ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
SDL_InitSubSystem ( SDL_INIT_VIDEO | SDL_INIT_TIMER ) ;
window = SDL_CreateWindow ( " OpenSpades Splash Window " , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,
bmp - > GetWidth ( ) , bmp - > GetHeight ( ) , SDL_WINDOW_BORDERLESS ) ;
if ( window = = nullptr ) {
SPLog ( " Creation of splash window failed. " ) ;
return ;
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
surface = SDL_GetWindowSurface ( window ) ;
if ( surface = = nullptr ) {
SPLog ( " Creation of splash window surface failed. " ) ;
SDL_DestroyWindow ( window ) ;
return ;
}
2014-04-06 20:10:13 +11:00
2014-04-24 11:42:57 +11:00
# ifdef __APPLE__
# elif __unix
SDL_Surface * icon = nullptr ;
SDL_RWops * icon_rw = nullptr ;
2014-05-06 00:22:01 +11:00
icon_rw = SDL_RWFromConstMem ( Icon , sizeof ( Icon ) ) ;
2014-04-24 11:42:57 +11:00
if ( icon_rw ! = nullptr ) {
icon = IMG_LoadPNG_RW ( icon_rw ) ;
SDL_FreeRW ( icon_rw ) ;
}
if ( icon = = nullptr ) {
std : : string msg = SDL_GetError ( ) ;
SPLog ( " Failed to load icon: %s " , msg . c_str ( ) ) ;
} else {
SDL_SetWindowIcon ( window , icon ) ;
SDL_FreeSurface ( icon ) ;
}
# endif
2014-03-31 20:37:23 +09:00
// put splash image
auto * s = SDL_CreateRGBSurfaceFrom ( bmp - > GetPixels ( ) , bmp - > GetWidth ( ) , bmp - > GetHeight ( ) ,
32 , bmp - > GetWidth ( ) * 4 ,
0xff , 0xff00 , 0xff0000 , 0 ) ;
SDL_BlitSurface ( s , nullptr , surface , nullptr ) ;
SDL_FreeSurface ( s ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
SDL_UpdateWindowSurface ( window ) ;
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
SDL_Window * GetWindow ( ) {
return window ;
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
void PumpEvents ( ) {
SDL_PumpEvents ( ) ;
SDL_Event e ;
while ( SDL_PollEvent ( & e ) ) {
switch ( e . type ) {
case SDL_KEYDOWN :
switch ( e . key . keysym . sym ) {
case SDLK_ESCAPE : throw ExitRequestException ( ) ;
case SDLK_SPACE :
startupScreenRequested = true ;
break ;
}
break ;
case SDL_QUIT :
throw ExitRequestException ( ) ;
}
}
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
bool IsStartupScreenRequested ( ) {
return startupScreenRequested ;
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
~ SplashWindow ( ) {
if ( window ) SDL_DestroyWindow ( window ) ;
}
} ;
2016-07-16 00:14:59 +09:00
static uLong computeCrc32ForStream ( spades : : IStream * s )
{
uLong crc = crc32 ( 0L , Z_NULL , 0 ) ;
char buf [ 16384 ] ;
size_t sz ;
while ( ( sz = s - > Read ( buf , 16384 ) ) ! = 0 ) {
crc = crc32 ( crc , reinterpret_cast < const Bytef * > ( buf ) ,
static_cast < uInt > ( sz ) ) ;
}
return crc ;
}
2014-03-31 20:37:23 +09:00
2014-04-04 16:46:01 +09:00
# ifdef WIN32
static std : : string Utf8FromWString ( const wchar_t * ws ) {
auto * s = ( char * ) SDL_iconv_string ( " UTF-8 " , " UCS-2-INTERNAL " , ( char * ) ( ws ) , wcslen ( ws ) * 2 + 2 ) ;
if ( ! s ) return " " ;
std : : string ss ( s ) ;
SDL_free ( s ) ;
return ss ;
}
# endif
2013-08-18 16:18:06 +09:00
int main ( int argc , char * * argv )
{
2013-12-24 00:31:51 +01:00
# ifdef WIN32
SetUnhandledExceptionFilter ( UnhandledExceptionProc ) ;
# endif
2014-04-06 20:10:13 +11:00
2014-05-08 16:40:44 +03:00
for ( int i = 1 ; i < argc ; ) {
int ret = argsHandler ( argc , argv , i ) ;
if ( ! ret ) {
// ignore unknown arg
i + + ;
}
}
if ( cg_printVersion ) {
printf ( " %s \n " , PACKAGE_STRING ) ;
return 0 ;
}
if ( cg_printHelp ) {
printHelp ( argv [ 0 ] ) ;
return 0 ;
}
2014-03-31 20:37:23 +09:00
std : : unique_ptr < SplashWindow > splashWindow ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
try {
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// start recording backtrace
2013-09-12 02:10:44 +09:00
spades : : reflection : : Backtrace : : StartBacktrace ( ) ;
SPADES_MARK_FUNCTION ( ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// show splash window
// NOTE: splash window uses image loader, which assumes backtrace is already initialized.
splashWindow . reset ( new SplashWindow ( ) ) ;
auto showSplashWindowTime = SDL_GetTicks ( ) ;
auto pumpEvents = [ & splashWindow ] { splashWindow - > PumpEvents ( ) ; } ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// initialize threads
2013-11-27 00:46:12 +09:00
spades : : Thread : : InitThreadSystem ( ) ;
2013-09-12 02:10:44 +09:00
spades : : DispatchQueue : : GetThreadQueue ( ) - > MarkSDLVideoThread ( ) ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
SPLog ( " Package: " PACKAGE_STRING ) ;
2014-03-31 20:37:23 +09:00
// setup user-specific default resource directories
2013-09-12 02:10:44 +09:00
# ifdef WIN32
2014-04-04 16:46:01 +09:00
static wchar_t buf [ 4096 ] ;
GetModuleFileNameW ( NULL , buf , 4096 ) ;
std : : wstring appdir = buf ;
appdir = appdir . substr ( 0 , appdir . find_last_of ( L ' \\ ' ) + 1 ) ;
2014-04-06 20:10:13 +11:00
2014-04-04 16:46:01 +09:00
if ( SUCCEEDED ( SHGetFolderPathW ( NULL , CSIDL_APPDATA , NULL , 0 , buf ) ) ) {
std : : wstring datadir = buf ;
datadir + = L " \\ OpenSpades \\ Resources " ;
spades : : FileManager : : AddFileSystem ( new spades : : DirectoryFileSystem ( Utf8FromWString ( datadir . c_str ( ) ) , true ) ) ;
2013-11-01 22:08:03 +01:00
}
2013-12-05 08:58:24 +09:00
2014-04-06 21:56:07 +09:00
spades : : FileManager : : AddFileSystem ( new spades : : DirectoryFileSystem ( Utf8FromWString ( ( appdir + L " Resources " ) . c_str ( ) ) , false ) ) ;
2014-04-08 09:55:52 +09:00
2013-11-01 22:08:03 +01:00
//fltk has a console window on windows (can disable while building, maybe use a builtin console for a later release?)
HWND hCon = GetConsoleWindow ( ) ;
if ( NULL ! = hCon ) {
setIcon ( hCon ) ;
2013-09-12 02:10:44 +09:00
}
2013-11-01 22:08:03 +01:00
2013-08-18 16:18:06 +09:00
# elif defined(__APPLE__)
2013-09-12 02:10:44 +09:00
std : : string home = getenv ( " HOME " ) ;
spades : : FileManager : : AddFileSystem
( new spades : : DirectoryFileSystem ( " ./Resources " , false ) ) ;
2014-04-06 20:10:13 +11:00
2014-04-01 15:52:40 +09:00
// OS X application is made of Bundle, which contains its own Resources directory.
{
char * baseDir = SDL_GetBasePath ( ) ;
if ( baseDir ) {
spades : : FileManager : : AddFileSystem
( new spades : : DirectoryFileSystem ( baseDir , false ) ) ;
SDL_free ( baseDir ) ;
}
}
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
spades : : FileManager : : AddFileSystem
( new spades : : DirectoryFileSystem ( home + " /Library/Application Support/OpenSpades/Resources " , true ) ) ;
2013-08-18 16:18:06 +09:00
# else
2013-09-12 02:10:44 +09:00
std : : string home = getenv ( " HOME " ) ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
spades : : FileManager : : AddFileSystem
( new spades : : DirectoryFileSystem ( " ./Resources " , false ) ) ;
2014-04-06 20:10:13 +11:00
2014-05-09 02:59:35 +11:00
spades : : FileManager : : AddFileSystem ( new spades : : DirectoryFileSystem ( CMAKE_INSTALL_PREFIX " / " OPENSPADES_INSTALL_RESOURCES , false ) ) ;
2014-04-06 20:10:13 +11:00
2014-04-07 19:58:10 +11:00
std : : string xdg_data_home = home + " /.local/share " ;
if ( getenv ( " XDG_DATA_HOME " ) = = NULL ) {
SPLog ( " XDG_DATA_HOME not defined. Assuming that XDG_DATA_HOME is ~/.local/share " ) ;
}
else {
2014-04-06 20:10:13 +11:00
std : : string xdg_data_home = getenv ( " XDG_DATA_HOME " ) ;
SPLog ( " XDG_DATA_HOME is %s " , xdg_data_home . c_str ( ) ) ;
2014-04-07 19:58:10 +11:00
}
2014-04-06 20:10:13 +11:00
2014-04-07 19:58:10 +11:00
struct stat info ;
if ( stat ( ( xdg_data_home + " /openspades " ) . c_str ( ) , & info ) ! = 0 ) {
if ( stat ( ( home + " /.openspades " ) . c_str ( ) , & info ) ! = 0 ) { }
else if ( info . st_mode & S_IFDIR ) {
SPLog ( " Openspades directory in XDG_DATA_HOME not found, though old directory exists. Trying to resolve compatibility problem. " ) ;
if ( rename ( ( home + " /.openspades " ) . c_str ( ) , ( xdg_data_home + " /openspades " ) . c_str ( ) ) ! = 0 ) {
SPLog ( " Failed to move old directory to new. " ) ;
} else {
SPLog ( " Successfully moved old directory. " ) ;
if ( mkdir ( ( home + " /.openspades " ) . c_str ( ) , S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) = = 0 ) {
SDL_RWops * io = SDL_RWFromFile ( ( home + " /.openspades/CONTENT_MOVED_TO_NEW_DIR " ) . c_str ( ) , " wb " ) ;
if ( io ! = NULL ) {
const char * text = ( " Content of this directory moved to " + xdg_data_home + " /openspades " ) . c_str ( ) ;
io - > write ( io , text , strlen ( text ) , 1 ) ;
io - > close ( io ) ;
}
}
}
}
2014-04-06 20:10:13 +11:00
}
2013-09-12 02:10:44 +09:00
spades : : FileManager : : AddFileSystem
2014-04-07 19:58:10 +11:00
( new spades : : DirectoryFileSystem ( xdg_data_home + " /openspades/Resources " , true ) ) ;
2013-08-18 16:18:06 +09:00
# endif
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// start log output to SystemMessages.log
2013-09-12 02:10:44 +09:00
try {
spades : : StartLog ( ) ;
} catch ( const std : : exception & ex ) {
2014-03-15 21:57:31 +09:00
SDL_InitSubSystem ( SDL_INIT_VIDEO ) ;
auto msg = spades : : Format ( " Failed to start recording log because of the following error: \n {0} \n \n "
" OpenSpades will continue to run, but any critical events are not logged. " , ex . what ( ) ) ;
if ( SDL_ShowSimpleMessageBox ( SDL_MESSAGEBOX_WARNING ,
" OpenSpades Log System Failure " ,
2014-03-31 20:37:23 +09:00
msg . c_str ( ) , splashWindow - > GetWindow ( ) ) ) {
2014-03-15 21:57:31 +09:00
// showing dialog failed.
}
2013-09-12 02:10:44 +09:00
}
SPLog ( " Log Started. " ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// load preferences.
2014-03-31 19:20:28 +09:00
spades : : Settings : : GetInstance ( ) - > Load ( ) ;
2014-03-31 20:37:23 +09:00
pumpEvents ( ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// dump CPU info (for debugging?)
2013-12-25 14:21:21 +09:00
{
spades : : CpuID cpuid ;
SPLog ( " ---- CPU Information ---- " ) ;
SPLog ( " Vendor ID: %s " , cpuid . GetVendorId ( ) . c_str ( ) ) ;
SPLog ( " Brand ID: %s " , cpuid . GetBrand ( ) . c_str ( ) ) ;
SPLog ( " Supports MMX: %s " , cpuid . Supports ( spades : : CpuFeature : : MMX ) ? " YES " : " NO " ) ;
SPLog ( " Supports SSE: %s " , cpuid . Supports ( spades : : CpuFeature : : SSE ) ? " YES " : " NO " ) ;
SPLog ( " Supports SSE2: %s " , cpuid . Supports ( spades : : CpuFeature : : SSE2 ) ? " YES " : " NO " ) ;
SPLog ( " Supports SSE3: %s " , cpuid . Supports ( spades : : CpuFeature : : SSE3 ) ? " YES " : " NO " ) ;
SPLog ( " Supports SSSE3: %s " , cpuid . Supports ( spades : : CpuFeature : : SSSE3 ) ? " YES " : " NO " ) ;
SPLog ( " Supports FMA: %s " , cpuid . Supports ( spades : : CpuFeature : : FMA ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX2: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX2 ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX512F: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX512F ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX512CD: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX512CD ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX512ER: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX512ER ) ? " YES " : " NO " ) ;
SPLog ( " Supports AVX512PF: %s " , cpuid . Supports ( spades : : CpuFeature : : AVX512PF ) ? " YES " : " NO " ) ;
SPLog ( " Simultaneous Multithreading: %s " , cpuid . Supports ( spades : : CpuFeature : : SimultaneousMT ) ? " YES " : " NO " ) ;
SPLog ( " Misc: " ) ;
SPLog ( " %s " , cpuid . GetMiscInfo ( ) . c_str ( ) ) ;
SPLog ( " ------------------------- " ) ;
}
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// register resource directory specified by Makefile (or something)
2014-05-09 02:59:35 +11:00
# if defined(RESDIR_DEFINED)
2013-11-01 22:08:03 +01:00
spades : : FileManager : : AddFileSystem ( new spades : : DirectoryFileSystem ( RESDIR , false ) ) ;
2013-08-18 18:49:41 +09:00
# endif
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// search current file system for .pak files
2013-09-12 02:10:44 +09:00
{
std : : vector < spades : : IFileSystem * > fss ;
2014-03-16 00:53:28 +09:00
std : : vector < spades : : IFileSystem * > fssImportant ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
std : : vector < std : : string > files = spades : : FileManager : : EnumFiles ( " " ) ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
struct Comparator {
static int GetPakId ( const std : : string & str ) {
if ( str . size ( ) > = 4 & & str [ 0 ] = = ' p ' & &
str [ 1 ] = = ' a ' & & str [ 2 ] = = ' k ' & &
( str [ 3 ] > = ' 0 ' & & str [ 3 ] < = ' 9 ' ) ) {
return atoi ( str . c_str ( ) + 3 ) ;
} else {
return 32767 ;
}
2013-09-11 19:46:08 +09:00
}
2013-09-12 02:10:44 +09:00
static bool Compare ( const std : : string & a ,
const std : : string & b ) {
int pa = GetPakId ( a ) ;
int pb = GetPakId ( b ) ;
if ( pa = = pb ) {
return a < b ;
} else {
return pa < pb ;
}
2013-09-11 19:46:08 +09:00
}
2013-09-12 02:10:44 +09:00
} ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
std : : sort ( files . begin ( ) , files . end ( ) , Comparator : : Compare ) ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
for ( size_t i = 0 ; i < files . size ( ) ; i + + ) {
std : : string name = files [ i ] ;
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
// check extension
2016-07-27 16:43:46 +09:00
if ( name . size ( ) < 4 | |
( name . rfind ( " .pak " ) ! = name . size ( ) - 4 & &
name . rfind ( " .zip " ) ! = name . size ( ) - 4 ) ) {
2016-07-27 16:33:17 +09:00
SPLog ( " Ignored loose file: %s " , name . c_str ( ) ) ;
2013-09-12 02:10:44 +09:00
continue ;
}
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
if ( spades : : FileManager : : FileExists ( name . c_str ( ) ) ) {
spades : : IStream * stream = spades : : FileManager : : OpenForReading ( name . c_str ( ) ) ;
2016-07-16 00:14:59 +09:00
uLong crc = computeCrc32ForStream ( stream ) ;
stream - > SetPosition ( 0 ) ;
2013-09-12 02:10:44 +09:00
spades : : ZipFileSystem * fs = new spades : : ZipFileSystem ( stream ) ;
2014-03-16 00:53:28 +09:00
if ( name [ 0 ] = = ' _ ' & & false ) { // last resort for #198
2016-07-16 00:14:59 +09:00
SPLog ( " Pak registered: %s: %08lx (marked as 'important') " , name . c_str ( ) ,
static_cast < unsigned long > ( crc ) ) ;
2014-03-16 00:53:28 +09:00
fssImportant . push_back ( fs ) ;
} else {
2016-07-16 00:14:59 +09:00
SPLog ( " Pak registered: %s: %08lx " , name . c_str ( ) ,
static_cast < unsigned long > ( crc ) ) ;
2014-03-16 00:53:28 +09:00
fss . push_back ( fs ) ;
}
2013-09-12 02:10:44 +09:00
}
}
2013-11-03 15:01:13 +09:00
for ( size_t i = fss . size ( ) ; i > 0 ; i - - ) {
2014-03-16 00:53:28 +09:00
spades : : FileManager : : AppendFileSystem ( fss [ i - 1 ] ) ;
}
for ( size_t i = 0 ; i < fssImportant . size ( ) ; i + + ) {
spades : : FileManager : : PrependFileSystem ( fssImportant [ i ] ) ;
2013-08-18 16:18:06 +09:00
}
}
2014-03-31 20:37:23 +09:00
pumpEvents ( ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// initialize localization system
2014-02-14 16:20:42 +09:00
SPLog ( " Initializing localization system " ) ;
spades : : LoadCurrentLocale ( ) ;
_Tr ( " Main " , " Localization System Loaded " ) ;
2014-03-31 20:37:23 +09:00
pumpEvents ( ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 21:15:56 +09:00
// parse args
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// initialize AngelScript
2013-09-12 02:10:44 +09:00
SPLog ( " Initializing script engine " ) ;
spades : : ScriptManager : : GetInstance ( ) ;
2014-03-31 20:37:23 +09:00
pumpEvents ( ) ;
2014-04-06 20:10:13 +11:00
2014-01-01 20:43:46 +09:00
ThreadQuantumSetter quantumSetter ;
2014-02-24 19:02:13 +09:00
( void ) quantumSetter ; // suppress "unused variable" warning
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
SDL_InitSubSystem ( SDL_INIT_VIDEO ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// we want to show splash window at least for some time...
pumpEvents ( ) ;
auto ticks = SDL_GetTicks ( ) ;
if ( ticks < showSplashWindowTime + 1500 ) {
SDL_Delay ( showSplashWindowTime + 1500 - ticks ) ;
}
pumpEvents ( ) ;
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
// everything is now ready!
2013-10-09 23:18:13 +02:00
if ( ! cg_autoConnect ) {
2013-12-08 23:49:39 +09:00
if ( ! ( ( int ) cl_showStartupWindow ! = 0 | |
2014-03-31 20:37:23 +09:00
splashWindow - > IsStartupScreenRequested ( ) ) ) {
splashWindow . reset ( ) ;
2014-04-06 20:10:13 +11:00
2013-11-22 22:50:14 +09:00
SPLog ( " Starting main screen " ) ;
spades : : StartMainScreen ( ) ;
} else {
2014-03-31 20:37:23 +09:00
splashWindow . reset ( ) ;
2014-04-06 20:10:13 +11:00
2014-02-07 00:09:26 +09:00
SPLog ( " Starting startup window " ) ;
: : spades : : gui : : StartupScreen : : Run ( ) ;
2013-11-22 22:50:14 +09:00
}
2013-10-09 23:18:13 +02:00
} else {
2014-03-31 20:37:23 +09:00
splashWindow . reset ( ) ;
2014-04-06 20:10:13 +11:00
2013-10-09 23:18:13 +02:00
spades : : ServerAddress host ( cg_lastQuickConnectHost . CString ( ) , ( int ) cg_protocolVersion = = 3 ? spades : : ProtocolVersion : : v075 : spades : : ProtocolVersion : : v076 ) ;
2013-12-08 23:49:39 +09:00
spades : : StartClient ( host , cg_playerName ) ;
2013-10-09 23:18:13 +02:00
}
2014-04-06 20:10:13 +11:00
2013-09-12 02:10:44 +09:00
spades : : Settings : : GetInstance ( ) - > Flush ( ) ;
2013-10-10 20:16:29 +02:00
2014-03-31 20:37:23 +09:00
} catch ( const ExitRequestException & ) {
// user changed his mind.
2013-09-12 02:10:44 +09:00
} catch ( const std : : exception & ex ) {
2014-04-06 20:10:13 +11:00
2014-03-31 20:37:23 +09:00
try {
splashWindow . reset ( nullptr ) ;
} catch ( . . . ) {
}
2014-04-06 20:10:13 +11:00
2014-02-24 19:02:13 +09:00
std : : string msg = ex . what ( ) ;
msg = _Tr ( " Main " , " A serious error caused OpenSpades to stop working: \n \n {0} \n \n See SystemMessages.log for more details. " , msg ) ;
2014-04-06 20:10:13 +11:00
2014-02-24 19:02:13 +09:00
SPLog ( " [!] Terminating due to the fatal error: %s " , ex . what ( ) ) ;
2014-04-06 20:10:13 +11:00
2014-02-24 19:02:13 +09:00
SDL_InitSubSystem ( SDL_INIT_VIDEO ) ;
if ( SDL_ShowSimpleMessageBox ( SDL_MESSAGEBOX_ERROR , _Tr ( " Main " , " OpenSpades Fatal Error " ) . c_str ( ) , msg . c_str ( ) , nullptr ) ) {
// showing dialog failed.
// TODO: do appropriate action
2013-08-18 16:18:06 +09:00
}
2014-04-06 20:10:13 +11:00
2013-08-18 16:18:06 +09:00
}
2014-04-06 20:10:13 +11:00
2013-08-18 16:18:06 +09:00
return 0 ;
}