summaryrefslogtreecommitdiff
path: root/tools/foundry/foundrydoc.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tools/foundry/foundrydoc.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'tools/foundry/foundrydoc.cpp')
-rw-r--r--tools/foundry/foundrydoc.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/tools/foundry/foundrydoc.cpp b/tools/foundry/foundrydoc.cpp
new file mode 100644
index 0000000..9d3b5d1
--- /dev/null
+++ b/tools/foundry/foundrydoc.cpp
@@ -0,0 +1,345 @@
+//========= 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();
+}
+