mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-10 10:59:39 +08:00
203 lines
6.0 KiB
C++
203 lines
6.0 KiB
C++
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
|
//
|
|
// Definition of a class to pre-process mission files and perform
|
|
// rule substitution.
|
|
//
|
|
//===============================================================================
|
|
|
|
#include "KeyValues.h"
|
|
#include "tilegen_core.h"
|
|
#include "tilegen_enum.h"
|
|
#include "tilegen_rule.h"
|
|
#include "tilegen_mission_preprocessor.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Public Implementation
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
CTilegenMissionPreprocessor::~CTilegenMissionPreprocessor()
|
|
{
|
|
m_Rules.PurgeAndDeleteElements();
|
|
}
|
|
|
|
const CTilegenRule *CTilegenMissionPreprocessor::FindRule( const char *pRuleName ) const
|
|
{
|
|
for ( int i = 0; i < m_Rules.Count(); ++ i )
|
|
{
|
|
if ( Q_stricmp( m_Rules[i]->GetName(), pRuleName ) == 0 )
|
|
{
|
|
return m_Rules[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const CTilegenEnum *CTilegenMissionPreprocessor::FindEnum( const char *pEnumName ) const
|
|
{
|
|
for ( int i = 0; i < m_Enums.Count(); ++ i )
|
|
{
|
|
if ( Q_stricmp( m_Enums[i]->GetName(), pEnumName ) == 0 )
|
|
{
|
|
return m_Enums[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool CTilegenMissionPreprocessor::ParseAndStripRules( KeyValues *pRulesKV )
|
|
{
|
|
for ( KeyValues *pSubKey = pRulesKV->GetFirstSubKey(); pSubKey != NULL; ) // sub-key gets advanced in the loop
|
|
{
|
|
if ( Q_stricmp( pSubKey->GetName(), "rule" ) == 0 )
|
|
{
|
|
KeyValues *pKeyValuesToRemove = pSubKey;
|
|
pSubKey = pSubKey->GetNextKey();
|
|
pRulesKV->RemoveSubKey( pKeyValuesToRemove );
|
|
|
|
CTilegenRule *pNewRule = new CTilegenRule();
|
|
if ( !pNewRule->LoadFromKeyValues( pKeyValuesToRemove ) )
|
|
{
|
|
delete pNewRule;
|
|
return false;
|
|
}
|
|
m_Rules.AddToTail( pNewRule );
|
|
}
|
|
else if ( Q_stricmp( pSubKey->GetName(), "enum" ) == 0 )
|
|
{
|
|
KeyValues *pKeyValuesToRemove = pSubKey;
|
|
pSubKey = pSubKey->GetNextKey();
|
|
pRulesKV->RemoveSubKey( pKeyValuesToRemove );
|
|
|
|
CTilegenEnum *pNewEnum = new CTilegenEnum();
|
|
if ( !pNewEnum->LoadFromKeyValues( pKeyValuesToRemove ) )
|
|
{
|
|
delete pNewEnum;
|
|
return false;
|
|
}
|
|
m_Enums.AddToTail( pNewEnum );
|
|
}
|
|
else
|
|
{
|
|
pSubKey = pSubKey->GetNextKey();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CTilegenMissionPreprocessor::SubstituteRules( KeyValues *pKeyValues )
|
|
{
|
|
m_nUniqueIndex = 0;
|
|
for ( KeyValues *pSubKey = pKeyValues->GetFirstSubKey(); pSubKey != NULL; )
|
|
{
|
|
KeyValues *pNextSubKey = pSubKey->GetNextKey();
|
|
|
|
// Rules should have been stripped out.
|
|
Assert( Q_stricmp( pSubKey->GetName(), "rule" ) != 0 );
|
|
|
|
if ( !SubstituteRules_Recursive( pKeyValues, pSubKey ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// pSubKey may have been deleted during the call and is no longer valid
|
|
pSubKey = pNextSubKey;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Private Implementation
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// During macro substitution, there are some meta-variables (starting with
|
|
// a '%' sign, e.g. %UniqueName) which are substituted for values
|
|
// using special logic in this function.
|
|
//-----------------------------------------------------------------------------
|
|
void CTilegenMissionPreprocessor::EvaluateMetaVariables( KeyValues *pKeyValues )
|
|
{
|
|
const char *pString = pKeyValues->GetString();
|
|
const char *pFind = "%Unique";
|
|
|
|
if ( Q_stristr( pString, pFind ) != NULL )
|
|
{
|
|
char uniqueNumber[15];
|
|
Q_snprintf( uniqueNumber, 15, "%02d", m_nUniqueIndex );
|
|
char outputString[MAX_TILEGEN_IDENTIFIER_LENGTH];
|
|
Q_StrSubst( pString, pFind, uniqueNumber, outputString, MAX_TILEGEN_IDENTIFIER_LENGTH );
|
|
pKeyValues->SetString( NULL, outputString );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Recursively looks for rule_instance blocks, finds the corresponding rule,
|
|
// performs the substitution recursively, and deletes the old rule_instance
|
|
// block.
|
|
//-----------------------------------------------------------------------------
|
|
bool CTilegenMissionPreprocessor::SubstituteRules_Recursive( KeyValues *pParent, KeyValues *pKeyValues )
|
|
{
|
|
if ( Q_stricmp( pKeyValues->GetName(), "rule_instance" ) == 0 )
|
|
{
|
|
if ( pKeyValues->GetBool( "disabled", false ) )
|
|
{
|
|
// The rule_instance has been disabled from the UI, ignore it and generate nothing in its place.
|
|
pParent->RemoveSubKey( pKeyValues );
|
|
pKeyValues->deleteThis();
|
|
}
|
|
else
|
|
{
|
|
const char *pRuleName = pKeyValues->GetString( "name", "" );
|
|
if ( pRuleName[0] == '\0' )
|
|
{
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Rule instance must have a valid 'name' key.\n" );
|
|
return false;
|
|
}
|
|
const CTilegenRule *pRule = FindRule( pRuleName );
|
|
if ( pRule == NULL )
|
|
{
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Rule %s not found in rule list.\n", pRuleName );
|
|
return false;
|
|
}
|
|
|
|
// Each instantiated rule needs a unique index to generate unique names.
|
|
++ m_nUniqueIndex;
|
|
|
|
KeyValues *pInstantiatedKV = pRule->InstantiateRule( pKeyValues, this );
|
|
|
|
if ( pInstantiatedKV == NULL )
|
|
{
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Error instantiating rule %s.\n", pRuleName );
|
|
return false;
|
|
}
|
|
|
|
pParent->SwapSubKey( pKeyValues, pInstantiatedKV );
|
|
|
|
// Recursively apply rules as needed.
|
|
if ( !SubstituteRules_Recursive( pParent, pInstantiatedKV ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pParent->ElideSubKey( pInstantiatedKV );
|
|
|
|
// Delete the rule_instance
|
|
pKeyValues->deleteThis();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
for ( KeyValues *pSubKey = pKeyValues->GetFirstSubKey(); pSubKey != NULL; )
|
|
{
|
|
KeyValues *pNextSubKey = pSubKey->GetNextKey();
|
|
if ( !SubstituteRules_Recursive( pKeyValues, pSubKey ) )
|
|
{
|
|
return false;
|
|
}
|
|
// pSubKey may have been deleted during the call and is no longer valid
|
|
pSubKey = pNextSubKey;
|
|
}
|
|
}
|
|
return true;
|
|
}
|