Files
FC1/Editor/Objects/ObjectLayerManager.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

512 lines
14 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: objectlayermanager.cpp
// Version: v1.00
// Created: 9/5/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "ObjectLayerManager.h"
#include "ObjectLoader.h"
#include "ObjectManager.h"
#include "GameEngine.h"
#include "ErrorReport.h"
#include "Settings.h"
#define LAYER_FILE_EXTENSION ".lyr"
//////////////////////////////////////////////////////////////////////////
CObjectLayerManager::CObjectLayerManager( CObjectManager *pObjectManager )
{
m_pObjectManager = pObjectManager;
m_layersPath = "Layers\\";
// Create main root level.
m_pMainLayer = new CObjectLayer( this );
m_layersMap[m_pMainLayer->GetGUID()] = m_pMainLayer;
m_pMainLayer->SetRemovable(false);
m_pMainLayer->SetExternal(false);
m_pMainLayer->SetName( "Main" );
m_pMainLayer->Expand(true);
m_pCurrentLayer = m_pMainLayer;
m_bOverwriteDuplicates = false;
}
void CObjectLayerManager::GetLayers( std::vector<CObjectLayer*> &layers ) const
{
layers.clear();
layers.reserve( m_layersMap.size() );
for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
{
layers.push_back( it->second );
}
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ClearLayers()
{
// Erase all removable layers.
LayersMap::iterator it,itnext;
for (LayersMap::iterator it = m_layersMap.begin(); it != m_layersMap.end(); it = itnext)
{
CObjectLayer *pLayer = it->second;
itnext = it;
itnext++;
if (pLayer->IsRemovable())
{
NotifyListeners( ON_LAYER_REMOVE,pLayer );
m_layersMap.erase( it );
}
}
m_pCurrentLayer = 0;
if (!m_layersMap.empty())
{
SetCurrentLayer( m_layersMap.begin()->second );
}
NotifyListeners( ON_LAYER_UPDATEALL,NULL );
}
//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::CreateLayer()
{
CObjectLayer *pLayer = new CObjectLayer( this );
m_layersMap[pLayer->GetGUID()] = pLayer;
//m_pMainLayer->AddChild( pLayer );
NotifyListeners( ON_LAYER_ADD,pLayer );
// pLayer->SetExternal(true);
return pLayer;
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::AddLayer( CObjectLayer *pLayer )
{
assert(pLayer);
if (!m_bOverwriteDuplicates)
{
CObjectLayer *pPrevLayer = FindLayerByName( pLayer->GetName() );
if (pPrevLayer)
{
CErrorRecord err;
err.error.Format( _T("Duplicate Layer Name <%s>"),(const char*)pLayer->GetName() );
err.severity = CErrorRecord::ESEVERITY_ERROR;
GetIEditor()->GetErrorReport()->ReportError(err);
return;
}
if (m_layersMap.find(pLayer->GetGUID()) != m_layersMap.end())
{
pPrevLayer = FindLayer(pLayer->GetGUID());
CErrorRecord err;
err.error.Format( _T("Duplicate Layer GUID,Layer <%s> collides with layer <%s>"),
(const char*)pPrevLayer->GetName(),(const char*)pLayer->GetName() );
err.severity = CErrorRecord::ESEVERITY_ERROR;
GetIEditor()->GetErrorReport()->ReportError(err);
return;
}
}
m_layersMap[pLayer->GetGUID()] = pLayer;
NotifyListeners( ON_LAYER_ADD,pLayer );
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::DeleteLayer( CObjectLayer *pLayer )
{
assert( pLayer );
// cannot remove non removable layer.
if (!pLayer->IsRemovable())
return;
// First delete all child layers.
for (int i = 0; i < pLayer->GetChildCount(); i++)
{
DeleteLayer( pLayer->GetChild(i) );
}
// prevent reference counted layer to be released before this function ends.
TSmartPtr<CObjectLayer> pLayerHolder = pLayer;
if (pLayer->GetParent())
pLayer->GetParent()->RemoveChild( pLayer );
// Delete all objects for this layer.
std::vector<CBaseObjectPtr> objects;
m_pObjectManager->GetAllObjects( objects );
for (int k = 0; k < objects.size(); k++)
{
if (objects[k]->GetLayer() == pLayer)
m_pObjectManager->DeleteObject(objects[k]);
}
if (m_pCurrentLayer == pLayer)
m_pCurrentLayer = pLayer->GetParent();
m_layersMap.erase( pLayer->GetGUID() );
if (!m_pCurrentLayer)
m_pCurrentLayer = m_pMainLayer;
NotifyListeners( ON_LAYER_REMOVE,pLayer );
NotifyListeners( ON_LAYER_SELECT,m_pCurrentLayer );
}
//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::FindLayer( REFGUID guid ) const
{
CObjectLayer *pLayer = stl::find_in_map( m_layersMap,guid,(CObjectLayer*)0 );
return pLayer;
}
//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::FindLayerByName( const CString &layerName ) const
{
for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
{
if (stricmp(it->second->GetName(),layerName) == 0)
return it->second;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::NotifyLayerChange( CObjectLayer *pLayer )
{
assert(pLayer);
// check if this layers is already registered in manager.
if (m_layersMap.find(pLayer->GetGUID()) != m_layersMap.end())
{
// Notify listeners of this change.
NotifyListeners( ON_LAYER_MODIFY,pLayer );
}
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::AddUpdateListener( const LayersUpdateCallback &cb )
{
m_listeners.Add( cb );
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::RemoveUpdateListener( const LayersUpdateCallback &cb )
{
m_listeners.Remove(cb);
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::NotifyListeners( EUpdateType type,CObjectLayer *pLayer )
{
m_listeners.Call( type,pLayer );
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::Serialize( CObjectArchive &ar,bool bIgnoreExternalLayers )
{
XmlNodeRef xmlNode = ar.node;
if (ar.bLoading)
{
ClearLayers();
// Loading from archive.
XmlNodeRef layers = xmlNode->findChild( "ObjectLayers" );
if (layers)
{
for (int i = 0; i < layers->getChildCount(); i++)
{
XmlNodeRef layerNode = layers->getChild(i);
TSmartPtr<CObjectLayer> pLayer = new CObjectLayer( this );
pLayer->Serialize( layerNode,true );
if (pLayer->IsExternal())
{
if (!bIgnoreExternalLayers)
LoadExternalLayer( pLayer->GetName(),ar );
}
else
{
// Check if this layer is alyeady loaded.
if (!FindLayer( pLayer->GetGUID() ))
AddLayer( pLayer );
}
}
GUID currentLayerGUID;
if (layers->getAttr( "CurrentGUID",currentLayerGUID ))
{
CObjectLayer *pLayer = FindLayer( currentLayerGUID );
if (pLayer)
SetCurrentLayer( pLayer );
}
}
ResolveLayerLinks();
}
else
{
// Saving to archive.
XmlNodeRef layersNode = xmlNode->newChild( "ObjectLayers" );
//! Store currently selected layer.
if (m_pCurrentLayer)
{
layersNode->setAttr( "Current",m_pCurrentLayer->GetName() );
layersNode->setAttr( "CurrentGUID",m_pCurrentLayer->GetGUID() );
}
for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
{
CObjectLayer *pLayer = it->second;
if (!pLayer->IsRemovable())
continue;
XmlNodeRef layerNode = layersNode->newChild("Layer");
pLayer->Serialize( layerNode,false );
if (pLayer->IsExternal() && !bIgnoreExternalLayers)
{
// Save external level additionally to file.
SaveExternalLayer( pLayer,ar );
}
}
}
ar.node = xmlNode;
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SaveExternalLayer( CObjectLayer *pLayer,CObjectArchive &ar )
{
// Form file name from layer name.
CString path = Path::AddBackslash( GetIEditor()->GetGameEngine()->GetLevelPath() ) + m_layersPath;
CString file = path + pLayer->GetName() + LAYER_FILE_EXTENSION;
CFileUtil::CreateDirectory( path );
// Make a backup of file.
if (gSettings.bBackupOnSave)
CFileUtil::BackupFile( file );
// Serialize this layer.
XmlNodeRef rootFileNode = new CXmlNode( "ObjectLayer" );
XmlNodeRef layerNode = rootFileNode->newChild( "Layer" );
ar.node = layerNode;
ExportLayer( pLayer,ar,false ); // Also save all childs but not external layers.
// Save xml file to disk.
rootFileNode->saveToFile( file );
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::LoadExternalLayer( const CString &layerName,CObjectArchive &archive )
{
// Form file name from layer name.
CString file = Path::AddBackslash( GetIEditor()->GetGameEngine()->GetLevelPath() );
file += m_layersPath + layerName + LAYER_FILE_EXTENSION;
XmlParser parser;
XmlNodeRef root = parser.parse( file );
if (!root)
{
CErrorRecord err;
err.error.Format( _T("Failed to import external object layer <%s> from File %s"),(const char*)layerName,(const char*)file );
err.file = file;
err.severity = CErrorRecord::ESEVERITY_ERROR;
archive.ReportError(err);
return;
}
XmlNodeRef layerDesc = root->findChild("Layer");
if (layerDesc)
{
XmlNodeRef prevRoot = archive.node;
archive.node = layerDesc;
m_bOverwriteDuplicates = true;
ImportLayer( archive,false );
m_bOverwriteDuplicates = false;
archive.node = prevRoot;
}
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ExportLayer( CObjectLayer *pLayer,CObjectArchive &ar,bool bExportExternalChilds )
{
pLayer->Serialize( ar.node,false );
XmlNodeRef orgNode = ar.node;
XmlNodeRef layerObjects = ar.node->newChild("LayerObjects");
ar.node = layerObjects;
std::vector<CBaseObject*> objects;
GetIEditor()->GetObjectManager()->GetObjects( objects,pLayer );
// Save all objects to XML.
for (int i = 0; i < objects.size(); i++)
{
ar.SaveObject( objects[i] );
}
if (pLayer->GetChildCount() > 0)
{
XmlNodeRef childLayers = orgNode->newChild("ChildLayers");
// Export layer childs.
for (int i = 0; i < pLayer->GetChildCount(); i++)
{
CObjectLayer *pChildLayer = pLayer->GetChild(i);
if (pChildLayer->IsExternal() && !bExportExternalChilds)
continue;
XmlNodeRef childLayer = childLayers->newChild("Layer");
ar.node = childLayer;
ExportLayer( pChildLayer,ar,bExportExternalChilds );
}
}
ar.node = orgNode;
}
//////////////////////////////////////////////////////////////////////////
CObjectLayer* CObjectLayerManager::ImportLayer( CObjectArchive &ar,bool bResolveObjects )
{
XmlNodeRef layerNode = ar.node;
if (stricmp(layerNode->getTag(),"Layer") != 0)
{
CErrorRecord err;
err.error.Format( _T("Not a valid Layer XML Node %s, Must be \"Layer\""),(const char*)layerNode->getTag() );
err.severity = CErrorRecord::ESEVERITY_WARNING;
ar.ReportError(err);
//Warning( "Not a valid Layer XML Node" );
// Bad layer,Import fails.
return 0;
}
TSmartPtr<CObjectLayer> pLayer = new CObjectLayer( this );
pLayer->Serialize( layerNode,true );
CString layerName = pLayer->GetName();
bool bRemoveLayer = false;
CObjectLayer *pPrevLayer = FindLayer( pLayer->GetGUID() );
if (pPrevLayer)
{
if (m_bOverwriteDuplicates)
{
pLayer = pPrevLayer;
pLayer->Serialize( layerNode,true ); // Serialize it again.
}
else
{
// Duplicate layer imported.
CString layerName = pPrevLayer->GetName();
bRemoveLayer = true;
CString str;
str.Format( _T("Replace Layer %s?\r\nAll object of replaced layer will be deleted."),(const char*)layerName );
if (AfxGetMainWnd()->MessageBox( str,_T("Confirm Replace Layer"),MB_YESNO|MB_ICONQUESTION) == IDNO)
{
return 0;
}
DeleteLayer(pPrevLayer);
}
}
if (pLayer)
{
AddLayer( pLayer );
}
XmlNodeRef layerObjects = layerNode->findChild("LayerObjects");
if (layerObjects)
{
int numObjects = layerObjects->getChildCount();
if (bResolveObjects)
m_pObjectManager->StartObjectsLoading( numObjects );
//ar.node = layerObjects;
//m_pObjectManager->LoadObjects( ar,false );
ar.LoadObjects( layerObjects );
if (bResolveObjects)
m_pObjectManager->EndObjectsLoading();
}
XmlNodeRef childLayers = layerNode->findChild("ChildLayers");
if (childLayers)
{
// Import child layers.
for (int i = 0; i < childLayers->getChildCount(); i++)
{
XmlNodeRef childLayer = childLayers->getChild(i);
ar.node = childLayer;
CObjectLayer *pChildLayer = ImportLayer( ar,false );
if (pChildLayer)
{
// Import child layers.
pLayer->AddChild( pChildLayer );
}
}
ar.node = layerNode;
}
if (bResolveObjects)
{
ResolveLayerLinks();
ar.ResolveObjects();
}
return pLayer;
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::SetCurrentLayer( CObjectLayer* pCurrLayer )
{
assert( pCurrLayer );
if (pCurrLayer == m_pCurrentLayer)
return;
m_pCurrentLayer = pCurrLayer;
NotifyListeners( ON_LAYER_SELECT,m_pCurrentLayer );
}
//////////////////////////////////////////////////////////////////////////
void CObjectLayerManager::ResolveLayerLinks()
{
for (LayersMap::const_iterator it = m_layersMap.begin(); it != m_layersMap.end(); ++it)
{
CObjectLayer *pLayer = it->second;
if (!pLayer->IsRemovable())
continue;
// Try to connect to parent layer.
CObjectLayer *pNewParent = FindLayer( pLayer->m_parentGUID );
/*
if (pNewParent == NULL && pLayer->GetParent() == m_pMainLayer)
{
// If parent is already main layer, skip.
continue;
}
*/
if (pLayer->GetParent() != NULL && pLayer->GetParent() != pNewParent)
{
// Deatch from old parent layer.
pLayer->GetParent()->RemoveChild( pLayer );
}
if (pNewParent)
{
// Attach to new parent layer.
pNewParent->AddChild( pLayer );
}
/*
if (pLayer->GetParent() == NULL)
{
// all removable layers without parent must be attached to main layer.
m_pMainLayer->AddChild( pLayer );
}
*/
}
NotifyListeners( ON_LAYER_UPDATEALL,0 );
}