*/
#include "referencecache.h"
+#include "globaldefs.h"
#include "debugging/debugging.h"
#include "iselection.h"
#include "iundo.h"
#include "imap.h"
+
MapModules& ReferenceAPI_getMapModules();
+
#include "imodel.h"
+
ModelModules& ReferenceAPI_getModelModules();
+
#include "ifilesystem.h"
#include "iarchive.h"
#include "ifiletypes.h"
#include "map.h"
#include "filetypes.h"
+extern bool g_writeMapComments;
bool References_Saved();
if ( !file.failed() ) {
globalOutputStream() << "success\n";
ScopeDisableScreenUpdates disableScreenUpdates( path_get_filename_start( filename ), "Saving Map" );
- format.writeGraph( root, traverse, file );
+ format.writeGraph( root, traverse, file, g_writeMapComments );
return true;
}
StringOutputStream backup( 256 );
backup << StringRange( path, path_get_extension( path ) ) << "bak";
- return ( !file_exists( backup.c_str() ) || file_remove( backup.c_str() ) ) // remove backup
- && file_move( path, backup.c_str() ); // rename current to backup
+ return file_move( path, backup.c_str() ); // rename current to backup
}
globalErrorStream() << "map path is not writeable: " << makeQuoted( path ) << "\n";
fullpath << path << name;
if ( path_is_absolute( fullpath.c_str() ) ) {
- if ( !file_exists( fullpath.c_str() ) || file_saveBackup( fullpath.c_str() ) ) {
+ /* We don't want a backup + rename operation if the .map file is
+ * a symlink. Otherwise we'll break the user's careful symlink setup.
+ * Just overwrite the original file. Assume the user has versioning. */
+ bool make_backup;
+ struct stat st;
+ if ( lstat(fullpath.c_str(), &st) == 0 ) {
+ make_backup = true; // file exists
+ if ( (st.st_mode & S_IFMT) == S_IFLNK ) {
+ make_backup = false; // .. but it is a symlink
+ }
+ } else {
+ make_backup = false; // nothing to move
+ }
+
+ if ( !make_backup || file_saveBackup( fullpath.c_str() ) ) {
return MapResource_saveFile( format, root, Map_Traverse, fullpath.c_str() );
}
inline hash_t path_hash( const char* path, hash_t previous = 0 ){
-#if defined( WIN32 )
+#if GDEF_OS_WINDOWS
return string_hash_nocase( path, previous );
#else // UNIX
return string_hash( path, previous );
struct PathHash
{
typedef hash_t hash_type;
+
hash_type operator()( const CopiedString& path ) const {
return path_hash( path.c_str() );
}
struct ModelKeyHash
{
typedef hash_t hash_type;
+
hash_type operator()( const ModelKey& key ) const {
return hash_combine( path_hash( key.first.c_str() ), path_hash( key.second.c_str() ) );
}
realise();
}
}
+
~ModelResource(){
if ( realised() ) {
unrealise();
}
ASSERT_MESSAGE( !realised(), "ModelResource::~ModelResource: resource reference still realised: " << makeQuoted( m_name.c_str() ) );
}
+
// NOT COPYABLE
ModelResource( const ModelResource& );
+
// NOT ASSIGNABLE
ModelResource& operator=( const ModelResource& );
void setModel( const NodeSmartReference& model ){
m_model = model;
}
+
void clearModel(){
m_model = g_nullModel;
}
return m_model != g_nullModel;
}
+
bool save(){
if ( !mapSaved() ) {
const char* moduleName = findModuleName( GetFileTypeRegistry(), MapFormat::Name(), m_type.c_str() );
}
return false;
}
+
void flush(){
if ( realised() ) {
ModelCache_flush( m_path.c_str(), m_name.c_str() );
}
}
+
scene::Node* getNode(){
//if(m_model != g_nullModel)
{
}
//return 0;
}
+
void setNode( scene::Node* node ){
ModelCache::iterator i = ModelCache_find( m_path.c_str(), m_name.c_str() );
if ( i != g_modelCache.end() ) {
connectMap();
}
+
void attach( ModuleObserver& observer ){
if ( realised() ) {
observer.realise();
}
m_observers.attach( observer );
}
+
void detach( ModuleObserver& observer ){
if ( realised() ) {
observer.unrealise();
}
m_observers.detach( observer );
}
+
bool realised(){
return m_unrealised == 0;
}
+
void realise(){
ASSERT_MESSAGE( m_unrealised != 0, "ModelResource::realise: already realised" );
if ( --m_unrealised == 0 ) {
m_observers.realise();
}
}
+
void unrealise(){
if ( ++m_unrealised == 1 ) {
m_observers.unrealise();
clearModel();
}
}
+
bool isMap() const {
return Node_getMapFile( m_model ) != 0;
}
+
void connectMap(){
MapFile* map = Node_getMapFile( m_model );
if ( map != 0 ) {
- map->setChangedCallback( FreeCaller<MapChanged>() );
+ map->setChangedCallback( makeCallbackF(MapChanged) );
}
}
+
std::time_t modified() const {
StringOutputStream fullpath( 256 );
fullpath << m_path.c_str() << m_name.c_str();
return file_modified( fullpath.c_str() );
}
+
void mapSave(){
m_modified = modified();
MapFile* map = Node_getMapFile( m_model );
map->save();
}
}
+
bool mapSaved() const {
MapFile* map = Node_getMapFile( m_model );
if ( map != 0 ) {
}
return true;
}
+
bool isModified() const {
return ( ( !string_empty( m_path.c_str() ) // had or has an absolute path
&& m_modified != modified() ) // AND disk timestamp changed
|| !path_equal( rootPath( m_originalName.c_str() ), m_path.c_str() ) ); // OR absolute vfs-root changed
}
+
void refresh(){
if ( isModified() ) {
flush();
Iterators m_iterators;
public:
typedef Iterators::iterator iterator;
+
ModelReferencesSnapshot( ModelReferences& references ) : m_references( references ){
for ( ModelReferences::iterator i = m_references.begin(); i != m_references.end(); ++i )
{
m_iterators.push_back( i );
}
}
+
~ModelReferencesSnapshot(){
for ( Iterators::iterator i = m_iterators.begin(); i != m_iterators.end(); ++i )
{
m_references.release( *i );
}
}
+
iterator begin(){
return m_iterators.begin();
}
+
iterator end(){
return m_iterators.end();
}
iterator begin(){
return m_references.begin();
}
+
iterator end(){
return m_references.end();
}
//globalOutputStream() << "capture: \"" << path << "\"\n";
return m_references.capture( CopiedString( path ) ).get();
}
+
void release( const char* path ){
m_references.release( CopiedString( path ) );
//globalOutputStream() << "release: \"" << path << "\"\n";
bool realised() const {
return m_unrealised == 0;
}
+
void realise(){
ASSERT_MESSAGE( m_unrealised != 0, "HashtableReferenceCache::realise: already realised" );
if ( --m_unrealised == 0 ) {
}
}
}
+
void unrealise(){
if ( ++m_unrealised == 1 ) {
g_realised = false;
ModelCache_clear();
}
}
+
void refresh(){
ModelReferencesSnapshot snapshot( m_references );
for ( ModelReferencesSnapshot::iterator i = snapshot.begin(); i != snapshot.end(); ++i )
m_map_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "maptypes" ) )
{
}
+
ModelModules& getModelModules(){
return m_model_modules.get();
}
+
MapModules& getMapModules(){
return m_map_modules.get();
}
ReferenceCache* m_reference;
public:
typedef ReferenceCache Type;
+
STRING_CONSTANT( Name, "*" );
ReferenceAPI(){
m_reference = &GetReferenceCache();
}
+
~ReferenceAPI(){
GlobalFileSystem().detach( g_referenceCache );
g_nullModel = g_nullNode;
}
+
ReferenceCache* getTable(){
return m_reference;
}
ModelModules& ReferenceAPI_getModelModules(){
return StaticReferenceModule::instance().getDependencies().getModelModules();
}
+
MapModules& ReferenceAPI_getMapModules(){
return StaticReferenceModule::instance().getDependencies().getMapModules( );
}