From bbe9ab19c2012a84d1e0080e2e1bb8f8a402f13c Mon Sep 17 00:00:00 2001 From: neumond Date: Sun, 29 Jun 2014 19:29:26 +0400 Subject: [PATCH] unvanquished filesystem --- include/qerplugin.h | 10 +- libs/stream/textstream.h | 44 ++++++ libs/string/string.h | 8 + plugins/vfspk3/vfs.cpp | 325 ++++++++++++++++++++++++++++++++++----- radiant/eclass.cpp | 12 +- radiant/eclass_fgd.cpp | 9 +- radiant/mainframe.cpp | 32 ++-- radiant/mainframe.h | 3 +- radiant/map.cpp | 31 ++++ radiant/map.h | 3 + radiant/plugin.cpp | 16 +- 11 files changed, 418 insertions(+), 75 deletions(-) diff --git a/include/qerplugin.h b/include/qerplugin.h index 3c1db046..cb6c2ba5 100644 --- a/include/qerplugin.h +++ b/include/qerplugin.h @@ -124,6 +124,7 @@ struct _QERFuncTable_1 const char* ( *getSettingsPath )( ); const char* ( *getMapsPath )( ); + const char* ( *getGameFile )( ); const char* ( *getGameName )( ); const char* ( *getGameMode )( ); @@ -134,15 +135,6 @@ struct _QERFuncTable_1 const char* ( *getGameDescriptionKeyValue )(const char* key); const char* ( *getRequiredGameDescriptionKeyValue )(const char* key); - void ( *attachGameToolsPathObserver )( ModuleObserver& observer ); - void ( *detachGameToolsPathObserver )( ModuleObserver& observer ); - void ( *attachEnginePathObserver )( ModuleObserver& observer ); - void ( *detachEnginePathObserver )( ModuleObserver& observer ); - void ( *attachGameNameObserver )( ModuleObserver& observer ); - void ( *detachGameNameObserver )( ModuleObserver& observer ); - void ( *attachGameModeObserver )( ModuleObserver& observer ); - void ( *detachGameModeObserver )( ModuleObserver& observer ); - SignalHandlerId ( *XYWindowDestroyed_connect )( const SignalHandler& handler ); void ( *XYWindowDestroyed_disconnect )( SignalHandlerId id ); MouseEventHandlerId ( *XYWindowMouseDown_connect )( const MouseEventHandler& handler ); diff --git a/libs/stream/textstream.h b/libs/stream/textstream.h index e8de1391..7f8be898 100644 --- a/libs/stream/textstream.h +++ b/libs/stream/textstream.h @@ -26,6 +26,7 @@ /// \brief Text-output-formatting. #include "itextstream.h" +#include "string/string.h" #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include "generic/arrayrange.h" @@ -396,6 +398,48 @@ std::size_t write( const char* buffer, std::size_t length ){ } }; + +/// \brief A wrapper for a TextInputStream used for reading one text line at a time. +template +class TextLinesInputStream +{ +TextInputStreamType& m_inputStream; +char m_buffer[SIZE + 1]; +char* m_cur; +char* m_end; + +int fillBuffer(){ + m_end = m_buffer + m_inputStream.read( m_buffer, SIZE ); + m_cur = m_buffer; + m_buffer[SIZE] = '\0'; + *m_end = '\0'; + return m_end - m_cur; +} +public: + +TextLinesInputStream( TextInputStreamType& inputStream ) : m_inputStream( inputStream ), m_cur( m_buffer ), m_end( m_buffer ){ + m_buffer[0] = '\0'; +} + +CopiedString readLine(){ + std::string s; + char* m_fin; + + while ( (m_fin = strchr( m_cur, '\n' )) == 0 ) + { + s.append( m_cur, m_end - m_cur ); + if ( fillBuffer() <= 0 ) break; + } + if ( m_fin != 0 ) { + s.append( m_cur, m_fin - m_cur + 1 ); + m_cur = m_fin + 1; + } + + return CopiedString( s.c_str() ); +} +}; + + /// \brief A wrapper for a TextOutputStream, optimised for writing a few characters at a time. template class BufferedTextOutputStream : public TextOutputStream diff --git a/libs/string/string.h b/libs/string/string.h index 826d4a93..c9ef2c4d 100644 --- a/libs/string/string.h +++ b/libs/string/string.h @@ -194,6 +194,14 @@ inline char* string_new( std::size_t length ){ return string_new( length, allocator ); } +/// \brief Allocates a new buffer large enough to hold two concatenated strings and fills it with strings. +inline char* string_new_concat( const char* a, const char* b ){ + char* str = string_new( string_length( a ) + string_length( b ) ); + strcpy( str, a ); + strcat( str, b ); + return str; +} + /// \brief Deallocates the \p buffer large enough to hold \p length characters. inline void string_release( char* string, std::size_t length ){ DefaultAllocator allocator; diff --git a/plugins/vfspk3/vfs.cpp b/plugins/vfspk3/vfs.cpp index 893f002b..9ec85fd8 100644 --- a/plugins/vfspk3/vfs.cpp +++ b/plugins/vfspk3/vfs.cpp @@ -84,6 +84,7 @@ struct archive_entry_t }; #include +#include typedef std::list archives_t; @@ -132,7 +133,7 @@ const _QERArchiveTable* GetArchiveTable( ArchiveModules& archiveModules, const c tmp << LowerCase( ext ); return archiveModules.findModule( tmp.c_str() ); } -static void InitPakFile( ArchiveModules& archiveModules, const char *filename ){ +static Archive* InitPakFile( ArchiveModules& archiveModules, const char *filename ){ const _QERArchiveTable* table = GetArchiveTable( archiveModules, path_get_extension( filename ) ); if ( table != 0 ) { @@ -143,7 +144,11 @@ static void InitPakFile( ArchiveModules& archiveModules, const char *filename ){ entry.is_pakfile = true; g_archives.push_back( entry ); globalOutputStream() << " pak file: " << filename << "\n"; + + return entry.archive; } + + return 0; } inline void pathlist_prepend_unique( GSList*& pathlist, char* path ){ @@ -276,6 +281,219 @@ bool operator()( const CopiedString& self, const CopiedString& other ) const { typedef std::set Archives; +Archive* AddPk3Dir( const char* fullpath ){ + if ( g_numDirs == VFS_MAXDIRS ) return 0; + + strncpy( g_strDirs[g_numDirs], fullpath, PATH_MAX ); + g_strDirs[g_numDirs][PATH_MAX] = '\0'; + g_numDirs++; + + { + archive_entry_t entry; + entry.name = fullpath; + entry.archive = OpenArchive( fullpath ); + entry.is_pakfile = false; + g_archives.push_back( entry ); + + return entry.archive; + } +} + +// for unvanquished + +bool IsUnvanquished(){ + return strncmp( GlobalRadiant().getGameFile(), "unvanquished", 12 ) == 0; +} + +struct pakfile_path_t +{ + CopiedString fullpath; // full pak dir or pk3dir name + bool is_pakfile; // defines is it .pk3dir or .pk3 file +}; + +typedef std::pair PakfilePathsKV; +typedef std::map PakfilePaths; // key must have no extension, only name + +static PakfilePaths g_pakfile_paths; + +void AddUnvPak( const char* name, const char* fullpath, bool is_pakfile ){ + pakfile_path_t pakfile_path; + pakfile_path.fullpath = fullpath; + pakfile_path.is_pakfile = is_pakfile; + g_pakfile_paths.insert( PakfilePathsKV( name, pakfile_path ) ); +} + +// Comparaison function for version numbers +// Implementation is based on dpkg's version comparison code (verrevcmp() and order()) +// http://anonscm.debian.org/gitweb/?p=dpkg/dpkg.git;a=blob;f=lib/dpkg/version.c;hb=74946af470550a3295e00cf57eca1747215b9311 +static int char_weight(char c){ + if (std::isdigit(c)) + return 0; + else if (std::isalpha(c)) + return c; + else if (c == '~') + return -1; + else if (c) + return c + 256; + else + return 0; +} + +static int VersionCmp(const char* a, const char* b){ + while (*a || *b) { + int firstDiff = 0; + + while ((*a && !std::isdigit(*a)) || (*b && !std::isdigit(*b))) { + int ac = char_weight(*a); + int bc = char_weight(*b); + + if (ac != bc) + return ac - bc; + + a++; + b++; + } + + while (*a == '0') + a++; + while (*b == '0') + b++; + + while (std::isdigit(*a) && std::isdigit(*b)) { + if (firstDiff == 0) + firstDiff = *a - *b; + a++; + b++; + } + + if (std::isdigit(*a)) + return 1; + if (std::isdigit(*b)) + return -1; + if (firstDiff) + return firstDiff; + } + + return false; +} + +// takes name without ext, returns without ext +static const char* GetLatestVersionOfUnvPak( const char* name ){ + const char* maxversion = 0; + const char* result = 0; + const char* pakname; + const char* pakversion; + int namelen = string_length( name ); + + for ( PakfilePaths::iterator i = g_pakfile_paths.begin(); i != g_pakfile_paths.end(); ++i ) + { + pakname = i->first.c_str(); + if ( strncmp( pakname, name, namelen ) != 0 || pakname[namelen] != '_' ) continue; + pakversion = pakname + (namelen + 1); + if ( maxversion == 0 || VersionCmp( pakversion, maxversion ) > 0 ){ + maxversion = pakversion; + result = pakname; + } + } + return result; +} + +// release string after using +static char* GetCurrentMapPakName(){ + char* mapdir; + char* mapname; + int mapnamelen; + char* result = 0; + + mapname = string_clone( GlobalRadiant().getMapName() ); + mapnamelen = string_length( mapname ); + + mapdir = strrchr( mapname, '/' ); + if ( mapdir ) { + mapdir -= 12; + if ( strncmp( mapdir, ".pk3dir/maps/", 13 ) == 0 ) { + *mapdir = '\0'; + mapdir = strrchr( mapname, '/' ); + if ( mapdir ) mapdir++; + else mapdir = mapname; + result = string_clone( mapdir ); + } + } + + string_release( mapname, mapnamelen ); + return result; + +} + +// prevent loading duplicates or circular references +static Archives g_loaded_unv_paks; + +// actual pak adding on initialise, deferred from InitDirectory +// Unvanquished filesystem doesn't need load all paks it finds +static void LoadPakWithDeps( const char* pakname ){ + const char* und = strrchr( pakname, '_' ); + if ( !und ) pakname = GetLatestVersionOfUnvPak( pakname ); + if ( !pakname || g_loaded_unv_paks.find( pakname ) != g_loaded_unv_paks.end() ) return; + + PakfilePaths::iterator i = g_pakfile_paths.find( pakname ); + if ( i == g_pakfile_paths.end() ) return; + + Archive* arc; + if ( i->second.is_pakfile ){ + arc = InitPakFile( FileSystemQ3API_getArchiveModules(), i->second.fullpath.c_str() ); + } else { + arc = AddPk3Dir( i->second.fullpath.c_str() ); + } + g_loaded_unv_paks.insert( pakname ); + + ArchiveTextFile* depsFile = arc->openTextFile( "DEPS" ); + if ( !depsFile ) return; + + { + TextLinesInputStream istream = depsFile->getInputStream(); + + CopiedString line; + const char* c; + const char* p_name; + const char* p_name_end; + const char* p_version; + const char* p_version_end; + while ( line = istream.readLine(), string_length( line.c_str() ) ) { + c = line.c_str(); + while ( std::isspace( *c ) && *c != '\0' ) ++c; + p_name = c; + while ( !std::isspace( *c ) && *c != '\0' ) ++c; + p_name_end = c; + while ( std::isspace( *c ) && *c != '\0' ) ++c; + p_version = c; + while ( !std::isspace( *c ) && *c != '\0' ) ++c; + p_version_end = c; + + if ( p_name_end - p_name == 0 ) continue; + if ( p_version_end - p_version == 0 ) { + const char* p_pakname; + CopiedString name_final = CopiedString( StringRange( p_name, p_name_end ) ); + p_pakname = GetLatestVersionOfUnvPak( name_final.c_str() ); + if ( !p_pakname ) continue; + LoadPakWithDeps( p_pakname ); + } else { + int len = ( p_name_end - p_name ) + ( p_version_end - p_version ) + 1; + char* p_pakname = string_new( len ); + strncpy( p_pakname, p_name, p_name_end - p_name ); + p_pakname[ p_name_end - p_name ] = '\0'; + strcat( p_pakname, "_" ); + strncat( p_pakname, p_version, p_version_end - p_version ); + LoadPakWithDeps( p_pakname ); + string_release( p_pakname, len ); + } + } + } + + depsFile->release(); +} + +// end for unvanquished + // ============================================================================= // Global functions @@ -337,15 +555,19 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){ } if ( g_bUsePak ) { + GDir* dir = g_dir_open( path, 0, 0 ); if ( dir != 0 ) { globalOutputStream() << "vfs directory: " << path << "\n"; + bool unv; + unv = IsUnvanquished(); + const char* ignore_prefix = ""; const char* override_prefix = ""; - { + if ( !unv ) { // See if we are in "sp" or "mp" mapping mode const char* gamemode = gamemode_get(); @@ -381,23 +603,19 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){ } const char *ext = strrchr( name, '.' ); + char tmppath[PATH_MAX]; if ( ext && !string_compare_nocase_upper( ext, ".pk3dir" ) ) { - if ( g_numDirs == VFS_MAXDIRS ) { - continue; - } - snprintf( g_strDirs[g_numDirs], PATH_MAX, "%s%s/", path, name ); - g_strDirs[g_numDirs][PATH_MAX] = '\0'; - FixDOSName( g_strDirs[g_numDirs] ); - AddSlash( g_strDirs[g_numDirs] ); - g_numDirs++; - - { - archive_entry_t entry; - entry.name = g_strDirs[g_numDirs - 1]; - entry.archive = OpenArchive( g_strDirs[g_numDirs - 1] ); - entry.is_pakfile = false; - g_archives.push_back( entry ); + + snprintf( tmppath, PATH_MAX, "%s%s/", path, name ); + tmppath[PATH_MAX] = '\0'; + FixDOSName( tmppath ); + AddSlash( tmppath ); + + if ( unv ) { + AddUnvPak( CopiedString( StringRange( name, ext ) ).c_str(), tmppath, false ); + } else { + AddPk3Dir( tmppath ); } } @@ -410,7 +628,11 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){ continue; } if ( !string_empty( override_prefix ) && strncmp( name, override_prefix, strlen( override_prefix ) ) == 0 ) { - archivesOverride.insert( name ); + if ( unv ) { + archives.insert( name ); + } else { + archivesOverride.insert( name ); + } continue; } @@ -420,19 +642,29 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){ g_dir_close( dir ); // add the entries to the vfs - for ( Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i ) - { - char filename[PATH_MAX]; - strcpy( filename, path ); - strcat( filename, ( *i ).c_str() ); - InitPakFile( archiveModules, filename ); - } - for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i ) - { - char filename[PATH_MAX]; - strcpy( filename, path ); - strcat( filename, ( *i ).c_str() ); - InitPakFile( archiveModules, filename ); + char* fullpath; + if ( unv ) { + for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i ) { + const char* name = i->c_str(); + const char* ext = strrchr( name, '.' ); + CopiedString name_final = CopiedString( StringRange( name, ext ) ); + fullpath = string_new_concat( path, name ); + AddUnvPak( name_final.c_str(), fullpath, true ); + string_release( fullpath, string_length( fullpath ) ); + } + } else { + for ( Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i ) + { + fullpath = string_new_concat( path, i->c_str() ); + InitPakFile( archiveModules, fullpath ); + string_release( fullpath, string_length( fullpath ) ); + } + for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i ) + { + fullpath = string_new_concat( path, i->c_str() ); + InitPakFile( archiveModules, fullpath ); + string_release( fullpath, string_length( fullpath ) ); + } } } else @@ -454,6 +686,9 @@ void Shutdown(){ g_numDirs = 0; g_numForbiddenDirs = 0; + + g_pakfile_paths.clear(); + g_loaded_unv_paks.clear(); } #define VFS_SEARCH_PAK 0x1 @@ -587,6 +822,25 @@ void initDirectory( const char *path ){ InitDirectory( path, FileSystemQ3API_getArchiveModules() ); } void initialise(){ + if ( IsUnvanquished() ) { + const char* pakname; + g_loaded_unv_paks.clear(); + + pakname = GetLatestVersionOfUnvPak( "tex-common" ); + if ( pakname ) LoadPakWithDeps( pakname ); + + pakname = GetLatestVersionOfUnvPak( "radiant" ); + if ( pakname ) LoadPakWithDeps( pakname ); + + pakname = GetCurrentMapPakName(); + if ( pakname && !string_empty( pakname ) ) { + LoadPakWithDeps( pakname ); + } + + g_pakfile_paths.clear(); + g_loaded_unv_paks.clear(); + } + globalOutputStream() << "filesystem initialised\n"; g_observers.realise(); } @@ -692,14 +946,15 @@ void forEachArchive( const ArchiveNameCallback& callback, bool pakonly, bool rev } }; + Quake3FileSystem g_Quake3FileSystem; -void FileSystem_Init(){ +VirtualFileSystem& GetFileSystem(){ + return g_Quake3FileSystem; } -void FileSystem_Shutdown(){ +void FileSystem_Init(){ } -VirtualFileSystem& GetFileSystem(){ - return g_Quake3FileSystem; +void FileSystem_Shutdown(){ } diff --git a/radiant/eclass.cpp b/radiant/eclass.cpp index db65063a..ea9828e5 100644 --- a/radiant/eclass.cpp +++ b/radiant/eclass.cpp @@ -336,14 +336,14 @@ EclassManagerAPI(){ m_eclassmanager.realise = &EntityClass_realise; m_eclassmanager.unrealise = &EntityClass_unrealise; - GlobalRadiant().attachGameToolsPathObserver( g_EntityClassQuake3 ); - GlobalRadiant().attachGameModeObserver( g_EntityClassQuake3 ); - GlobalRadiant().attachGameNameObserver( g_EntityClassQuake3 ); + Radiant_attachGameToolsPathObserver( g_EntityClassQuake3 ); + Radiant_attachGameModeObserver( g_EntityClassQuake3 ); + Radiant_attachGameNameObserver( g_EntityClassQuake3 ); } ~EclassManagerAPI(){ - GlobalRadiant().detachGameNameObserver( g_EntityClassQuake3 ); - GlobalRadiant().detachGameModeObserver( g_EntityClassQuake3 ); - GlobalRadiant().detachGameToolsPathObserver( g_EntityClassQuake3 ); + Radiant_detachGameNameObserver( g_EntityClassQuake3 ); + Radiant_detachGameModeObserver( g_EntityClassQuake3 ); + Radiant_detachGameToolsPathObserver( g_EntityClassQuake3 ); EntityClassQuake3_destroy(); } diff --git a/radiant/eclass_fgd.cpp b/radiant/eclass_fgd.cpp index 7b877915..ef1e6dce 100644 --- a/radiant/eclass_fgd.cpp +++ b/radiant/eclass_fgd.cpp @@ -28,6 +28,7 @@ #include "ifilesystem.h" #include "iscriplib.h" #include "qerplugin.h" +#include "mainframe.h" #include "string/string.h" #include "eclasslib.h" @@ -699,12 +700,12 @@ EntityClassFGDAPI(){ m_eclassmanager.realise = &EntityClassFGD_realise; m_eclassmanager.unrealise = &EntityClassFGD_unrealise; - GlobalRadiant().attachGameToolsPathObserver( g_EntityClassFGD ); - GlobalRadiant().attachGameNameObserver( g_EntityClassFGD ); + Radiant_attachGameToolsPathObserver( g_EntityClassFGD ); + Radiant_attachGameNameObserver( g_EntityClassFGD ); } ~EntityClassFGDAPI(){ - GlobalRadiant().detachGameNameObserver( g_EntityClassFGD ); - GlobalRadiant().detachGameToolsPathObserver( g_EntityClassFGD ); + Radiant_detachGameNameObserver( g_EntityClassFGD ); + Radiant_detachGameToolsPathObserver( g_EntityClassFGD ); EntityClassFGD_destroy(); } diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 0e430f11..8989da30 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -146,22 +146,33 @@ glwindow_globals_t g_glwindow_globals; // VFS + +bool g_vfsInitialized = false; + +void VFS_Init(){ + if ( g_vfsInitialized ) return; + QE_InitVFS(); + GlobalFileSystem().initialise(); + g_vfsInitialized = true; +} +void VFS_Shutdown(){ + if ( !g_vfsInitialized ) return; + GlobalFileSystem().shutdown(); + g_vfsInitialized = false; +} +void VFS_Restart(){ + VFS_Shutdown(); + VFS_Init(); +} + class VFSModuleObserver : public ModuleObserver { -std::size_t m_unrealised; public: -VFSModuleObserver() : m_unrealised( 1 ){ -} void realise(){ - if ( --m_unrealised == 0 ) { - QE_InitVFS(); - GlobalFileSystem().initialise(); - } + VFS_Init(); } void unrealise(){ - if ( ++m_unrealised == 1 ) { - GlobalFileSystem().shutdown(); - } + VFS_Shutdown(); } }; @@ -513,6 +524,7 @@ void gamemode_set( const char* gamemode ){ } } + #include "os/dir.h" class CLoadModule diff --git a/radiant/mainframe.h b/radiant/mainframe.h index 0b008a6b..c2738450 100644 --- a/radiant/mainframe.h +++ b/radiant/mainframe.h @@ -245,8 +245,7 @@ void gamemode_set( const char* gamemode ); void Radiant_attachGameModeObserver( ModuleObserver& observer ); void Radiant_detachGameModeObserver( ModuleObserver& observer ); - - +void VFS_Restart(); void VFS_Construct(); void VFS_Destroy(); diff --git a/radiant/map.cpp b/radiant/map.cpp index fae78de3..c5cc8a90 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -38,6 +38,7 @@ MapModules& ReferenceAPI_getMapModules(); #include "ifilesystem.h" #include "namespace.h" #include "moduleobserver.h" +#include "moduleobservers.h" #include @@ -404,6 +405,31 @@ float g_MinWorldCoord = -64 * 1024; void AddRegionBrushes( void ); void RemoveRegionBrushes( void ); +/* Map open/close observers */ + +ModuleObservers g_mapPathObservers; + +class UnvanquishedMapFileObserver : public ModuleObserver +{ +void realise() { + if ( strncmp( GlobalRadiant().getGameFile(), "unvanquished", 12 ) == 0 ) { + // Restart VFS to apply new pak filtering based on mapname + VFS_Restart(); + } +} +void unrealise() { } +}; + +UnvanquishedMapFileObserver g_unvanquishedMapFileObserver; + +void BindMapFileObservers(){ + g_mapPathObservers.attach( g_unvanquishedMapFileObserver ); +} + +void UnBindMapFileObservers(){ + g_mapPathObservers.detach( g_unvanquishedMapFileObserver ); +} + /* ================ @@ -422,6 +448,7 @@ void Map_Free(){ g_currentMap = 0; Brush_unlatchPreferences(); + g_mapPathObservers.unrealise(); } class EntityFindByClassname : public scene::Graph::Walker @@ -946,6 +973,7 @@ void Map_LoadFile( const char *filename ){ } Brush_toggleFormat( i ); g_map.m_name = filename; + g_mapPathObservers.realise(); Map_UpdateTitle( g_map ); g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); if ( format ) { @@ -1177,10 +1205,12 @@ void Map_RenameAbsolute( const char* absolute ){ g_map.m_resource->detach( g_map ); GlobalReferenceCache().release( g_map.m_name.c_str() ); + g_mapPathObservers.unrealise(); g_map.m_resource = resource; g_map.m_name = absolute; + g_mapPathObservers.realise(); Map_UpdateTitle( g_map ); g_map.m_resource->attach( g_map ); @@ -1218,6 +1248,7 @@ void Map_New(){ //globalOutputStream() << "Map_New\n"; g_map.m_name = "unnamed.map"; + g_mapPathObservers.realise(); Map_UpdateTitle( g_map ); { diff --git a/radiant/map.h b/radiant/map.h index a359d461..8bfd5114 100644 --- a/radiant/map.h +++ b/radiant/map.h @@ -162,4 +162,7 @@ void Map_mergeClonedNames(); const char* getMapsPath(); +void BindMapFileObservers(); +void UnBindMapFileObservers(); + #endif diff --git a/radiant/plugin.cpp b/radiant/plugin.cpp index a43572aa..8adf4d12 100644 --- a/radiant/plugin.cpp +++ b/radiant/plugin.cpp @@ -113,6 +113,10 @@ const char* TextureBrowser_getSelectedShader(){ return TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ); } +const char* getGameFile(){ + return g_GamesDialog.m_sGameFile.c_str(); +} + class RadiantCoreAPI { _QERFuncTable_1 m_radiantcore; @@ -128,6 +132,7 @@ RadiantCoreAPI(){ m_radiantcore.getSettingsPath = &SettingsPath_get; m_radiantcore.getMapsPath = &getMapsPath; + m_radiantcore.getGameFile = &getGameFile; m_radiantcore.getGameName = &gamename_get; m_radiantcore.getGameMode = &gamemode_get; @@ -138,15 +143,6 @@ RadiantCoreAPI(){ m_radiantcore.getGameDescriptionKeyValue = &GameDescription_getKeyValue; m_radiantcore.getRequiredGameDescriptionKeyValue = &GameDescription_getRequiredKeyValue; - m_radiantcore.attachGameToolsPathObserver = Radiant_attachGameToolsPathObserver; - m_radiantcore.detachGameToolsPathObserver = Radiant_detachGameToolsPathObserver; - m_radiantcore.attachEnginePathObserver = Radiant_attachEnginePathObserver; - m_radiantcore.detachEnginePathObserver = Radiant_detachEnginePathObserver; - m_radiantcore.attachGameNameObserver = Radiant_attachGameNameObserver; - m_radiantcore.detachGameNameObserver = Radiant_detachGameNameObserver; - m_radiantcore.attachGameModeObserver = Radiant_attachGameModeObserver; - m_radiantcore.detachGameModeObserver = Radiant_detachGameModeObserver; - m_radiantcore.XYWindowDestroyed_connect = XYWindowDestroyed_connect; m_radiantcore.XYWindowDestroyed_disconnect = XYWindowDestroyed_disconnect; m_radiantcore.XYWindowMouseDown_connect = XYWindowMouseDown_connect; @@ -254,10 +250,12 @@ Radiant(){ MapRoot_construct(); EnginePath_verify(); + BindMapFileObservers(); EnginePath_Realise(); } ~Radiant(){ EnginePath_Unrealise(); + UnBindMapFileObservers(); MapRoot_destroy(); NullModel_destroy(); -- 2.39.2