mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-10 02:58:48 +08:00
303 lines
14 KiB
C++
303 lines
14 KiB
C++
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
|
//
|
|
// Boilerplate template code to generically instantiate tilegen
|
|
// classes by name and parse them from KeyValues files.
|
|
//
|
|
//===============================================================================
|
|
|
|
#ifndef TILEGEN_CLASS_FACTORIES_H
|
|
#define TILEGEN_CLASS_FACTORIES_H
|
|
|
|
#if defined( COMPILER_MSVC )
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "utlvector.h"
|
|
#include "KeyValues.h"
|
|
#include "tilegen_class_interfaces.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function must be called at least once before any tilegen
|
|
// expression, action, or range classes are parsed.
|
|
// Subsequent calls are ignored.
|
|
//-----------------------------------------------------------------------------
|
|
void RegisterAllTilegenClasses();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The most generic, abstract base form of a tilegen class factory.
|
|
// Each derived template instantiation is capable of instantiating a single
|
|
// kind of tilegen class derived from TTilegenInterface.
|
|
//
|
|
// TTilegenInterface - the type of interface this class factory returns,
|
|
// e.g. ITilegenExpression< int >, ITilegenRange< const CExit * >,
|
|
// ITilegenAction
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TTilegenInterface >
|
|
class ITilegenClassFactory
|
|
{
|
|
public:
|
|
//-----------------------------------------------------------------------------
|
|
// Creates an instance of the tilegen class this factory is templated on.
|
|
//-----------------------------------------------------------------------------
|
|
virtual TTilegenInterface * CreateInstance() = 0;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Gets the friendly string name of the tilegen class this factory produces.
|
|
//-----------------------------------------------------------------------------
|
|
virtual const char *GetName() = 0;
|
|
|
|
static TTilegenInterface *ReadLiteralValue( KeyValues *pKeyValues )
|
|
{
|
|
// Only some tilegen classes can be loaded this way.
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Tilegen class does not support literal values.\n" );
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
// Annoying workaround due to template specialization rules.
|
|
// I want these implemented in a .cpp elsewhere but if I simply do a template prototype and define the function elsewhere,
|
|
// it won't specialize. So I need a fully implemented template specialization to call these functions.
|
|
ITilegenExpression< int > *ReadLiteralIntValue( KeyValues *pKeyValues );
|
|
ITilegenExpression< bool > *ReadLiteralBoolValue( KeyValues *pKeyValues );
|
|
ITilegenExpression< float > *ReadLiteralFloatValue( KeyValues *pKeyValues );
|
|
ITilegenExpression< const char * > *ReadLiteralStringValue( KeyValues *pKeyValues );
|
|
|
|
// Class factory specializations to handle parsing literal values...
|
|
|
|
ITilegenExpression< int > *ITilegenClassFactory< ITilegenExpression< int > >::ReadLiteralValue( KeyValues *pKeyValues )
|
|
{
|
|
return ReadLiteralIntValue( pKeyValues );
|
|
}
|
|
|
|
ITilegenExpression< bool > *ITilegenClassFactory< ITilegenExpression< bool > >::ReadLiteralValue( KeyValues *pKeyValues )
|
|
{
|
|
return ReadLiteralBoolValue( pKeyValues );
|
|
}
|
|
|
|
ITilegenExpression< float > *ITilegenClassFactory< ITilegenExpression< float > >::ReadLiteralValue( KeyValues *pKeyValues )
|
|
{
|
|
return ReadLiteralFloatValue( pKeyValues );
|
|
}
|
|
|
|
ITilegenExpression< char const * > *ITilegenClassFactory< ITilegenExpression< char const * > >::ReadLiteralValue( KeyValues *pKeyValues )
|
|
{
|
|
return ReadLiteralStringValue( pKeyValues );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Implementation of a generic tilegen class factory which
|
|
// can be specialized to implement either expression, action, and range class
|
|
// factories.
|
|
//
|
|
// TTilegenInterface - the type of interface this class factory produces,
|
|
// e.g. ITilegenExpression< int >, ITilegenRange< const CExit * >,
|
|
// ITilegenAction
|
|
// TTilegenClass - the specific class (which must derive from
|
|
// TTilegenInterface) that this factory actually produduces,
|
|
// e.g. CTilegenExpression_Add, CTilegenRange_NewOpenExits,
|
|
// CTilegenAction_SwitchState
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TTilegenInterface, typename TTilegenClass >
|
|
class CTilegenClassFactory : public ITilegenClassFactory< TTilegenInterface >
|
|
{
|
|
public:
|
|
virtual TTilegenInterface * CreateInstance() { return new TTilegenClass(); }
|
|
virtual const char *GetName();
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Class factory type to produce tilegen expressions.
|
|
//
|
|
// TExpressionValue - the type the expression class returns, e.g. bool, int
|
|
// TExpressionClass - the specific type of the expression, e.g.
|
|
// CTilegenExpression_Add
|
|
//
|
|
// TExpressionClass must derive from ITilegenExpression< TExpressionValue >
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TExpressionValue, typename TExpressionClass >
|
|
class CTilegenExpressionClassFactory : public CTilegenClassFactory< ITilegenExpression< TExpressionValue >, TExpressionClass >
|
|
{
|
|
public:
|
|
// Must be implemented for each specialization of CTilegenExpressionClassFactory
|
|
// (see macro IMPLEMENT_TILEGEN_EXPRESSION in tilegen_class_factories.cpp).
|
|
virtual const char *GetName();
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Class factory type to produce tilegen actions.
|
|
//
|
|
// TActionClass - the specific type of the action, e.g.
|
|
// CTilegenAction_SwitchState
|
|
//
|
|
// TActionClass must derive from ITilegenAction
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TActionClass >
|
|
class CTilegenActionClassFactory : public CTilegenClassFactory< ITilegenAction, TActionClass >
|
|
{
|
|
public:
|
|
// Must be implemented for each specialization of CTilegenActionClassFactory
|
|
// (see macro IMPLEMENT_TILEGEN_ACTION in tilegen_class_factories.cpp).
|
|
virtual const char *GetName();
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Class factory type to produce tilegen ranges.
|
|
//
|
|
// TElementValue - the type of each element in the range, e.g. const CExit *
|
|
// TRangeClass - the specific type of the range, e.g.
|
|
// CTilegenRange_NewOpenExits, CTilegenRange_ClosedExits
|
|
//
|
|
// TRangeClass must derive from ITilegenRange< TElementValue >
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TElementValue, typename TRangeClass >
|
|
class CTilegenRangeClassFactory : public CTilegenClassFactory< ITilegenRange< TElementValue >, TRangeClass >
|
|
{
|
|
public:
|
|
// Must be implemented for each specialization of CTilegenRangeClassFactory
|
|
// (see macro IMPLEMENT_TILEGEN_RANGE in tilegen_class_factories.cpp).
|
|
virtual const char *GetName();
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A class registry which is capable of instantiating any class
|
|
// which has a class factory instance registered with it.
|
|
// A list of class factories is tracked and searched by string when
|
|
// an instance of a particular type is requested.
|
|
//
|
|
// TTilegenInterface - base interface class which is returned when a
|
|
// new instance is created.
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TTilegenInterface >
|
|
class CTilegenClassRegistry
|
|
{
|
|
typedef ITilegenClassFactory< TTilegenInterface > TTilegenClassFactoryInterface;
|
|
public:
|
|
// @TODO: do we need cleanup the CUtlVector for each instance of this class?
|
|
// If so, we're better off making implicit linked lists, since
|
|
// each factory class is statically allocated..
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Registers a new factory instance which can produce a specific type of
|
|
// tilegen class.
|
|
//-----------------------------------------------------------------------------
|
|
static void AddFactory( TTilegenClassFactoryInterface *pFactory )
|
|
{
|
|
m_FactoryList.AddToTail( pFactory );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates an instance of the class specified by pClassName
|
|
//-----------------------------------------------------------------------------
|
|
static TTilegenInterface *CreateInstance( const char *pClassName )
|
|
{
|
|
for ( int i = 0; i < m_FactoryList.Count(); ++ i )
|
|
{
|
|
if ( Q_stricmp( m_FactoryList[i]->GetName(), pClassName ) == 0 )
|
|
{
|
|
return m_FactoryList[i]->CreateInstance();
|
|
}
|
|
}
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Class %s not found in %s. Check the class name spelling and the context in which it is used.\n", pClassName, m_pFactoryName );
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
static CUtlVector< TTilegenClassFactoryInterface * > m_FactoryList;
|
|
static const char *m_pFactoryName;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Parses KeyValues data and instantiates the appropriate class
|
|
//
|
|
// bCreateEmptyInstance is used in the rare case where the caller needs
|
|
// the object created but not actually loaded from KeyValues.
|
|
// (One example of this is CTilegenExpression_MapReduce, which uses binary
|
|
// operators to fold/reduce values together but does not need any state
|
|
// in the operators to function.
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TTilegenInterface >
|
|
static TTilegenInterface *CreateFromKeyValues( KeyValues *pKeyValues, bool bCreateEmptyInstance = false )
|
|
{
|
|
if ( pKeyValues->GetFirstSubKey() == NULL )
|
|
{
|
|
// Code to handle literal/inline values
|
|
return ITilegenClassFactory< TTilegenInterface >::ReadLiteralValue( pKeyValues );
|
|
}
|
|
|
|
const char *pClassName = pKeyValues->GetString( "class", NULL );
|
|
if ( pClassName == NULL )
|
|
{
|
|
Log_Warning( LOG_TilegenLayoutSystem, "No class name specified for class instantiation in key values.\n" );
|
|
return NULL;
|
|
}
|
|
|
|
TTilegenInterface *pNewClass = CTilegenClassRegistry< TTilegenInterface >::CreateInstance( pClassName );
|
|
if ( pNewClass != NULL && !bCreateEmptyInstance && !pNewClass->LoadFromKeyValues( pKeyValues ) )
|
|
{
|
|
delete pNewClass;
|
|
pNewClass = NULL;
|
|
}
|
|
return pNewClass;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the appropriate tilegen class from the specified sub-key
|
|
// of KeyValues data.
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TTilegenClass >
|
|
bool CreateFromKeyValuesBlock( KeyValues *pParentKV, const char *pKeyName, const char *pParentClassName, TTilegenClass **ppClass, bool bOptional = false, bool bCreateEmptyInstance = false )
|
|
{
|
|
KeyValues *pSubKey = pParentKV->FindKey( pKeyName );
|
|
*ppClass = NULL;
|
|
if ( pSubKey == NULL )
|
|
{
|
|
if ( bOptional )
|
|
{
|
|
return true;
|
|
}
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Could not load sub-key '%s' for parent class '%s'.\n", pKeyName, pParentClassName );
|
|
return false;
|
|
}
|
|
|
|
*ppClass = CreateFromKeyValues< TTilegenClass >( pSubKey, bCreateEmptyInstance );
|
|
if ( *ppClass == NULL )
|
|
{
|
|
Log_Warning( LOG_TilegenLayoutSystem, "Could not create class for sub-key '%s' for parent class '%s'.\n", pKeyName, pParentClassName );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the appropriate tilegen expression class from the specified sub-key
|
|
// of KeyValues data.
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TExpressionValue >
|
|
bool CreateExpressionFromKeyValuesBlock( KeyValues *pParentKV, const char *pKeyName, const char *pParentClassName, ITilegenExpression< TExpressionValue > **ppClass, bool bOptional = false, bool bCreateEmptyInstance = false )
|
|
{
|
|
return CreateFromKeyValuesBlock< ITilegenExpression< TExpressionValue > >( pParentKV, pKeyName, pParentClassName, ppClass, bOptional, bCreateEmptyInstance );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the appropriate tilegen action and boolean expression class
|
|
// (if present) from the specified KeyValues data.
|
|
//-----------------------------------------------------------------------------
|
|
bool CreateActionAndCondition( KeyValues *pKeyValues, ITilegenAction **ppAction, ITilegenExpression< bool > **ppCondition );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the appropriate tilegen action and boolean expression class
|
|
// (if present) from the specified sub-key of KeyValues data.
|
|
//-----------------------------------------------------------------------------
|
|
bool CreateActionAndConditionFromKeyValuesBlock( KeyValues *pParentKV, const char *pKeyName, const char *pParentClassName, ITilegenAction **ppAction, ITilegenExpression< bool > **ppCondition );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates the appropriate tilegen range class from the specified sub-key
|
|
// of KeyValues data.
|
|
//-----------------------------------------------------------------------------
|
|
template< typename TElementValue >
|
|
bool CreateRangeFromKeyValuesBlock( KeyValues *pParentKV, const char *pKeyName, const char *pParentClassName, ITilegenRange< TElementValue > **ppClass )
|
|
{
|
|
return CreateFromKeyValuesBlock< ITilegenRange< TElementValue > >( pParentKV, pKeyName, pParentClassName, ppClass );
|
|
}
|
|
|
|
#endif // TILEGEN_CLASS_FACTORIES_H
|