unvanquished filesystem
authorneumond <knifeslaughter@gmail.com>
Sun, 29 Jun 2014 15:29:26 +0000 (19:29 +0400)
committerThomas Debesse <dev@illwieckz.net>
Sun, 9 Apr 2017 12:52:00 +0000 (14:52 +0200)
include/qerplugin.h
libs/stream/textstream.h
libs/string/string.h
plugins/vfspk3/vfs.cpp
radiant/eclass.cpp
radiant/eclass_fgd.cpp
radiant/mainframe.cpp
radiant/mainframe.h
radiant/map.cpp
radiant/map.h
radiant/plugin.cpp

index 3c1db04..cb6c2ba 100644 (file)
@@ -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 );
index e8de139..7f8be89 100644 (file)
@@ -26,6 +26,7 @@
 /// \brief Text-output-formatting.
 
 #include "itextstream.h"
+#include "string/string.h"
 
 #include <cctype>
 #include <cstddef>
@@ -33,6 +34,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <algorithm>
+#include <string>
 
 #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<typename TextInputStreamType, int SIZE = 1024>
+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<typename TextOutputStreamType, int SIZE = 1024>
 class BufferedTextOutputStream : public TextOutputStream
index 826d4a9..c9ef2c4 100644 (file)
@@ -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<char> allocator;
index 893f002..9ec85fd 100644 (file)
@@ -84,6 +84,7 @@ struct archive_entry_t
 };
 
 #include <list>
+#include <map>
 
 typedef std::list<archive_entry_t> 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<CopiedString, PakLess> 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<CopiedString, pakfile_path_t> PakfilePathsKV;
+typedef std::map<CopiedString, pakfile_path_t> 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<TextInputStream> 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(){
 }
index db65063..ea9828e 100644 (file)
@@ -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();
 }
index 7b87791..ef1e6dc 100644 (file)
@@ -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();
 }
index 0e430f1..8989da3 100644 (file)
@@ -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
index 0b008a6..c273845 100644 (file)
@@ -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();
 
index fae78de..c5cc8a9 100644 (file)
@@ -38,6 +38,7 @@ MapModules& ReferenceAPI_getMapModules();
 #include "ifilesystem.h"
 #include "namespace.h"
 #include "moduleobserver.h"
+#include "moduleobservers.h"
 
 #include <set>
 
@@ -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 );
 
        {
index a359d46..8bfd511 100644 (file)
@@ -162,4 +162,7 @@ void Map_mergeClonedNames();
 
 const char* getMapsPath();
 
+void BindMapFileObservers();
+void UnBindMapFileObservers();
+
 #endif
index a43572a..8adf4d1 100644 (file)
@@ -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();