|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "foundrydoc.h"
#include "tier1/KeyValues.h"
#include "tier1/utlbuffer.h"
#include "datamodel/dmelement.h"
#include "toolutils/enginetools_int.h"
#include "filesystem.h"
#include "foundrytool.h"
#include "toolframework/ienginetool.h"
#include "dmevmfentity.h"
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CFoundryDoc::CFoundryDoc( IFoundryDocCallback *pCallback ) : m_pCallback( pCallback ) { m_hRoot = NULL; m_pBSPFileName[0] = 0; m_pVMFFileName[0] = 0; m_bDirty = false; g_pDataModel->InstallNotificationCallback( this ); }
CFoundryDoc::~CFoundryDoc() { g_pDataModel->RemoveNotificationCallback( this ); }
//-----------------------------------------------------------------------------
// Inherited from INotifyUI
//-----------------------------------------------------------------------------
void CFoundryDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) { OnDataChanged( pReason, nNotifySource, nNotifyFlags ); }
//-----------------------------------------------------------------------------
// Gets the file name
//-----------------------------------------------------------------------------
const char *CFoundryDoc::GetBSPFileName() { return m_pBSPFileName; }
const char *CFoundryDoc::GetVMFFileName() { return m_pVMFFileName; }
void CFoundryDoc::SetVMFFileName( const char *pFileName ) { Q_strncpy( m_pVMFFileName, pFileName, sizeof( m_pVMFFileName ) ); Q_FixSlashes( m_pVMFFileName ); SetDirty( true ); }
//-----------------------------------------------------------------------------
// Dirty bits
//-----------------------------------------------------------------------------
void CFoundryDoc::SetDirty( bool bDirty ) { m_bDirty = bDirty; }
bool CFoundryDoc::IsDirty() const { return m_bDirty; }
//-----------------------------------------------------------------------------
// Saves/loads from file
//-----------------------------------------------------------------------------
bool CFoundryDoc::LoadFromFile( const char *pFileName ) { Assert( !m_hRoot.Get() );
// This is not undoable
CAppDisableUndoScopeGuard guard( "CFoundryDoc::LoadFromFile", 0 ); SetDirty( false );
if ( !pFileName[0] ) return false;
// Store the BSP file name
Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) );
// Construct VMF file name from the BSP
const char *pGame = Q_stristr( pFileName, "\\game\\" ); if ( !pGame ) return false;
// Compute the map name
char mapname[ 256 ]; const char *pMaps = Q_stristr( pFileName, "\\maps\\" ); if ( !pMaps ) return false;
Q_strncpy( mapname, pMaps + 6, sizeof( mapname ) );
int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1; Q_strncpy( m_pVMFFileName, pFileName, nLen ); Q_strncat( m_pVMFFileName, "\\content\\", sizeof(m_pVMFFileName) ); Q_strncat( m_pVMFFileName, pGame + 6, sizeof(m_pVMFFileName) ); Q_SetExtension( m_pVMFFileName, ".vmf", sizeof(m_pVMFFileName) );
CDmElement *pVMF = NULL; if ( g_pDataModel->RestoreFromFile( m_pVMFFileName, NULL, "vmf", &pVMF ) == DMFILEID_INVALID ) { m_pBSPFileName[0] = 0; m_pVMFFileName[0] = 0; return false; }
m_hRoot = pVMF;
guard.Release(); SetDirty( false );
char cmd[ 256 ]; Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", mapname ); enginetools->Command( cmd ); enginetools->Execute( );
return true; }
void CFoundryDoc::SaveToFile( ) { if ( m_hRoot.Get() && m_pVMFFileName && m_pVMFFileName[0] ) { g_pDataModel->SaveToFile( m_pVMFFileName, NULL, "keyvalues", "vmf", m_hRoot ); }
SetDirty( false ); }
//-----------------------------------------------------------------------------
// Returns the root object
//-----------------------------------------------------------------------------
CDmElement *CFoundryDoc::GetRootObject() { return m_hRoot; }
//-----------------------------------------------------------------------------
// Returns the entity list
//-----------------------------------------------------------------------------
CDmAttribute *CFoundryDoc::GetEntityList() { return m_hRoot ? m_hRoot->GetAttribute( "entities", AT_ELEMENT_ARRAY ) : NULL; }
//-----------------------------------------------------------------------------
// Deletes an entity
//-----------------------------------------------------------------------------
void CFoundryDoc::DeleteEntity( CDmeVMFEntity *pEntity ) { CDmrElementArray<> entities( GetEntityList() ); if ( !entities.IsValid() ) return;
int nCount = entities.Count(); for ( int i = 0; i < nCount; ++i ) { if ( pEntity == CastElement< CDmeVMFEntity >( entities[i] ) ) { entities.FastRemove( i ); return; } } }
//-----------------------------------------------------------------------------
// Called when data changes
//-----------------------------------------------------------------------------
void CFoundryDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) { SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false ); m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags ); }
//-----------------------------------------------------------------------------
// List of all entity classnames to copy over from the original block
//-----------------------------------------------------------------------------
static const char *s_pUseOriginalClasses[] = { "worldspawn", "func_occluder", NULL };
//-----------------------------------------------------------------------------
// Always copy the worldspawn and other entities that had data built into them by VBSP out
//-----------------------------------------------------------------------------
void CFoundryDoc::AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ) { while ( *pActualEntityData ) { pActualEntityData = strchr( pActualEntityData, '{' ); if ( !pActualEntityData ) break;
const char *pBlockStart = pActualEntityData;
pActualEntityData = strstr( pActualEntityData, "\"classname\"" ); if ( !pActualEntityData ) break;
// Skip "classname"
pActualEntityData += 11;
pActualEntityData = strchr( pActualEntityData, '\"' ); if ( !pActualEntityData ) break;
// Skip "
++pActualEntityData;
char pClassName[512]; int j = 0; while (*pActualEntityData != 0 && *pActualEntityData != '\"' ) { pClassName[j++] = *pActualEntityData++; } pClassName[j] = 0;
pActualEntityData = strchr( pActualEntityData, '}' ); if ( !pActualEntityData ) break; // Skip }
++pActualEntityData;
for ( int i = 0; s_pUseOriginalClasses[i]; ++i ) { if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) ) { // Found one we need to keep, add it to the buffer
int nBytes = (int)( (size_t)pActualEntityData - (size_t)pBlockStart ); entityBuf.Put( pBlockStart, nBytes ); entityBuf.PutChar( '\n' ); break; } } } }
//-----------------------------------------------------------------------------
// Copy in other entities from the editable VMF
//-----------------------------------------------------------------------------
void CFoundryDoc::AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ) { const CDmrElementArray<CDmElement> entityArray( m_hRoot, "entities" ); if ( !entityArray.IsValid() ) return;
int nCount = entityArray.Count(); for ( int iEntity = 0; iEntity < nCount; ++iEntity ) { CDmElement *pEntity = entityArray[iEntity]; const char *pClassName = pEntity->GetValueString( "classname" ); if ( !pClassName || !pClassName[0] ) continue;
// Don't spawn those classes we grab from the actual compiled map
bool bDontUse = false; for ( int i = 0; s_pUseOriginalClasses[i]; ++i ) { if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) ) { bDontUse = true; break; } }
if ( bDontUse ) continue;
entityBuf.PutString( "{\n" ); entityBuf.Printf( "\"id\" \"%d\"\n", atol( pEntity->GetName() ) );
for( CDmAttribute *pAttribute = pEntity->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) { if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) ) continue;
if ( IsArrayType( pAttribute->GetType() ) ) continue;
if ( !Q_stricmp( pAttribute->GetName(), "editorType" ) || !Q_stricmp( pAttribute->GetName(), "editor" ) ) continue;
entityBuf.Printf( "\"%s\" ", pAttribute->GetName() );
// FIXME: Set up standard delimiters
entityBuf.PutChar( '\"' ); pAttribute->Serialize( entityBuf ); entityBuf.PutString( "\"\n" ); }
entityBuf.PutString( "}\n" ); } }
//-----------------------------------------------------------------------------
// Create a text block the engine can parse containing the entity data to spawn
//-----------------------------------------------------------------------------
const char* CFoundryDoc::GenerateEntityData( const char *pActualEntityData ) { if ( !m_hRoot.Get() ) return pActualEntityData;
// Contains the text block the engine can parse containing the entity data to spawn
static CUtlBuffer entityBuf( 2048, 2048, CUtlBuffer::TEXT_BUFFER ); entityBuf.Clear();
// Always copy the worldspawn and other entities that had data built into them by VBSP out
AddOriginalEntities( entityBuf, pActualEntityData );
// Copy in other entities from the editable VMF
AddVMFEntities( entityBuf, pActualEntityData );
return (const char*)entityBuf.Base(); }
|