/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant 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 2 of the License, or (at your option) any later version. GtkRadiant 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 GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* The following source code is licensed by Id Software and subject to the terms of its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT, please contact Id Software immediately at info@idsoftware.com. */ // // Linux stuff // // Leonardo Zide (leo@lokigames.com) // #include "qe3.h" #include "debugging/debugging.h" #include "ifilesystem.h" #include #include #include "stream/textfilestream.h" #include "commandlib.h" #include "stream/stringstream.h" #include "os/path.h" #include "scenelib.h" #include "gtkutil/messagebox.h" #include "error.h" #include "map.h" #include "build.h" #include "points.h" #include "camwindow.h" #include "mainframe.h" #include "preferences.h" #include "watchbsp.h" #include "autosave.h" QEGlobals_t g_qeglobals; #if defined( POSIX ) #include // chmod #endif #define RADIANT_MONITOR_ADDRESS "127.0.0.1:39000" void QE_InitVFS(){ // VFS initialization ----------------------- // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files) // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too const char* gamename = gamename_get(); const char* basegame = basegame_get(); const char* userRoot = g_qeglobals.m_userEnginePath.c_str(); const char* globalRoot = EnginePath_get(); std::vector paths; const auto paths_push = [&paths]( const char* newPath ){ // collects unique paths if( !string_empty( newPath ) && std::none_of( paths.cbegin(), paths.cend(), [newPath]( const CopiedString& path ){ return path_equal( path.c_str(), newPath ); } ) ) paths.emplace_back( newPath ); }; for( const auto& path : ExtraResourcePaths_get() ) paths_push( path.c_str() ); StringOutputStream str( 256 ); // ~/./ paths_push( str( userRoot, gamename, '/' ) ); // userGamePath // / paths_push( str( globalRoot, gamename, '/' ) ); // globalGamePath // ~/./ paths_push( str( userRoot, basegame, '/' ) ); // userBasePath // / paths_push( str( globalRoot, basegame, '/' ) ); // globalBasePath for( const auto& path : paths ) GlobalFileSystem().initDirectory( path.c_str() ); } SimpleCounter g_brushCount; SimpleCounter g_patchCount; SimpleCounter g_entityCount; void QE_brushCountChange(){ std::size_t counts[3] = { g_brushCount.get(), g_patchCount.get(), g_entityCount.get() }; if( GlobalSelectionSystem().countSelected() != 0 ) GlobalSelectionSystem().countSelectedStuff( counts[0], counts[1], counts[2] ); for ( int i = 0; i < 3; ++i ){ char buffer[32]; buffer[0] = '\0'; if( counts[i] != 0 ) sprintf( buffer, "%zu", counts[i] ); g_pParentWnd->SetStatusText( c_status_brushcount + i, buffer ); } } IdleDraw g_idle_scene_counts_update = IdleDraw( FreeCaller() ); void QE_brushCountChanged(){ g_idle_scene_counts_update.queueDraw(); } bool ConfirmModified( const char* title ){ if ( !Map_Modified( g_map ) ) { return true; } EMessageBoxReturn result = qt_MessageBox( MainFrame_getWindow(), "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, EMessageBoxType::Question, eIDYES | eIDNO | eIDCANCEL ); if ( result == eIDCANCEL ) { return false; } if ( result == eIDYES ) { if ( Map_Unnamed( g_map ) ) { return Map_SaveAs(); } else { return Map_Save(); } } return true; // eIDNO } void bsp_init(){ StringOutputStream stream( 256 ); build_set_variable( "RadiantPath", AppPath_get() ); build_set_variable( "ExecutableType", RADIANT_EXECUTABLE ); build_set_variable( "EnginePath", EnginePath_get() ); build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() ); for( const auto& path : ExtraResourcePaths_get() ) if( !path.empty() ) stream << " -fs_pakpath " << makeQuoted( path ); build_set_variable( "ExtraResourcePaths", stream ); build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? RADIANT_MONITOR_ADDRESS : "" ); build_set_variable( "GameName", gamename_get() ); const char* mapname = Map_Name( g_map ); build_set_variable( "BspFile", stream( PathExtensionless( mapname ), ".bsp" ) ); if( g_region_active ){ build_set_variable( "MapFile", stream( PathExtensionless( mapname ), ".reg" ) ); } else{ build_set_variable( "MapFile", mapname ); } build_set_variable( "MapName", stream( PathFilename( mapname ) ) ); } void bsp_shutdown(){ build_clear_variables(); } class BatchCommandListener { TextOutputStream& m_file; std::size_t m_commandCount; const char* m_outputRedirect; public: BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){ } void execute( const char* command ){ m_file << command; if( m_outputRedirect ){ m_file << ( m_commandCount == 0? " > " : " >> " ); m_file << makeQuoted( m_outputRedirect ); } m_file << '\n'; ++m_commandCount; } }; void RunBSP( size_t buildIdx ){ if( !g_region_active ) SaveMap(); if ( Map_Unnamed( g_map ) ) { globalErrorStream() << "build cancelled: the map is unnamed\n"; return; } if ( !g_region_active && g_SnapShots_Enabled && Map_Modified( g_map ) ) Map_Snapshot(); if ( g_region_active ) { const char* mapname = Map_Name( g_map ); Map_SaveRegion( StringStream( PathExtensionless( mapname ), ".reg" ) ); } Pointfile_Delete(); bsp_init(); const std::vector commands = build_construct_commands( buildIdx ); const bool monitor = std::any_of( commands.cbegin(), commands.cend(), []( const CopiedString& command ){ return strstr( command.c_str(), RADIANT_MONITOR_ADDRESS ) != 0; } ); if ( g_WatchBSP_Enabled && monitor ) { // grab the file name for engine running const char* fullname = Map_Name( g_map ); const auto bspname = StringStream<64>( PathFilename( fullname ) ); BuildMonitor_Run( commands, bspname ); } else { const auto junkpath = StringStream( SettingsPath_get(), "junk.txt" ); #if defined( POSIX ) const auto batpath = StringStream( SettingsPath_get(), "qe3bsp.sh" ); #elif defined( WIN32 ) const auto batpath = StringStream( SettingsPath_get(), "qe3bsp.bat" ); #else #error "unsupported platform" #endif bool written = false; { TextFileOutputStream batchFile( batpath ); if ( !batchFile.failed() ) { #if defined ( POSIX ) batchFile << "#!/bin/sh \n\n"; #endif BatchCommandListener listener( batchFile, g_WatchBSP0_DumpLog? junkpath : 0 ); for( const auto& command : commands ) listener.execute( command.c_str() ); written = true; } } if ( written ) { #if defined ( POSIX ) chmod( batpath, 0744 ); #endif globalOutputStream() << "Writing the compile script to '" << batpath << "'\n"; if( g_WatchBSP0_DumpLog ) globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n"; Q_Exec( batpath, NULL, NULL, true, false ); } } bsp_shutdown(); } // ============================================================================= // Sys_ functions void Sys_SetTitle( const char *text, bool modified ){ auto title = StringStream( text ); if ( modified ) { title << " *"; } MainFrame_getWindow()->setWindowTitle( title.c_str() ); }