source-engine/public/dmxloader/dmxelement.h

311 lines
11 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef DMXELEMENT_H
#define DMXELEMENT_H
#ifdef _WIN32
#pragma once
#endif
#include "datamodel/dmattributetypes.h"
#include "tier1/utlvector.h"
#include "tier1/utlrbtree.h"
#include "tier1/utlsymbol.h"
#include "tier1/mempool.h"
#include "tier1/UtlSortVector.h"
#include "dmxloader/dmxattribute.h"
//-----------------------------------------------------------------------------
// Sort functor class for attributes
//-----------------------------------------------------------------------------
class CDmxAttributeLess
{
public:
bool Less( const CDmxAttribute * pAttribute1, const CDmxAttribute *pAttribute2, void *pContext )
{
return pAttribute1->GetNameSymbol() < pAttribute2->GetNameSymbol();
}
};
//-----------------------------------------------------------------------------
// Used to unpack elements into a structure. Does not recurse
// Also does not work with arrays.
//-----------------------------------------------------------------------------
struct DmxElementUnpackStructure_t
{
const char *m_pAttributeName;
const char *m_pDefaultString;
DmAttributeType_t m_AttributeType;
int m_nOffset;
int m_nSize;
const void *m_pUserData; // If you want to associate some app-specific data with each field
};
#define DECLARE_DMXELEMENT_UNPACK() \
template <typename T> friend DmxElementUnpackStructure_t *DmxElementUnpackInit(T *);
#define BEGIN_DMXELEMENT_UNPACK( _structName ) \
template <typename T> DmxElementUnpackStructure_t *DmxElementUnpackInit(T *); \
template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ); \
namespace _structName##_UnpackInit \
{ \
static DmxElementUnpackStructure_t *s_pUnpack = DmxElementUnpackInit( (_structName *)NULL ); \
} \
\
template <> DmxElementUnpackStructure_t *DmxElementUnpackInit<_structName>( _structName * ) \
{ \
typedef _structName DestStructType_t; \
static DmxElementUnpackStructure_t unpack[] = \
{ \
#define DMXELEMENT_UNPACK_FLTX4( _attributeName, _defaultString, _varName ) \
{ _attributeName, _defaultString, CDmAttributeInfo<float>::AttributeType(), (int)offsetof( DestStructType_t, _varName ), sizeof( fltx4 ), NULL },
#define DMXELEMENT_UNPACK_FIELD( _attributeName, _defaultString, _type, _varName ) \
{ _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), (int)offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NULL },
#define DMXELEMENT_UNPACK_FIELD_STRING( _attributeName, _defaultString, _varName ) \
{ _attributeName, _defaultString, AT_STRING, offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), NULL },
#define DMXELEMENT_UNPACK_FIELD_USERDATA( _attributeName, _defaultString, _type, _varName, _userData ) \
{ _attributeName, _defaultString, CDmAttributeInfo<_type>::AttributeType(), (int)offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), _userData },
#define DMXELEMENT_UNPACK_FIELD_STRING_USERDATA( _attributeName, _defaultString, _varName, _userData ) \
{ _attributeName, _defaultString, AT_STRING, (int)offsetof( DestStructType_t, _varName ), sizeof( ((DestStructType_t *)0)->_varName), _userData },
#define END_DMXELEMENT_UNPACK( _structName, _varName ) \
{ NULL, NULL, AT_UNKNOWN, 0, 0, NULL } \
}; \
return unpack; \
} \
DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack;
#define END_DMXELEMENT_UNPACK_TEMPLATE( _structName, _varName ) \
{ NULL, NULL, AT_UNKNOWN, 0, 0, NULL } \
}; \
return unpack; \
} \
template<> DmxElementUnpackStructure_t *_varName = _structName##_UnpackInit::s_pUnpack;
//-----------------------------------------------------------------------------
// Element used to read dmx files from mod code. Similar to keyvalues.
//-----------------------------------------------------------------------------
class CDmxElement
{
DECLARE_DMX_ALLOCATOR( );
public:
bool HasAttribute( const char *pAttributeName ) const;
CDmxAttribute *GetAttribute( const char *pAttributeName );
const CDmxAttribute *GetAttribute( const char *pAttributeName ) const;
int AttributeCount() const;
CDmxAttribute *GetAttribute( int nIndex );
const CDmxAttribute *GetAttribute( int nIndex ) const;
CUtlSymbol GetType() const;
const char* GetTypeString() const;
const char* GetName() const;
const DmObjectId_t &GetId() const;
// Add+remove+rename can only occur during lock
// NOTE: AddAttribute will find or add; returning an existing attribute if
// one with the appropriate name exists
void LockForChanges( bool bLock );
CDmxAttribute *AddAttribute( const char *pAttributeName );
void RemoveAttribute( const char *pAttributeName );
void RemoveAttributeByPtr( CDmxAttribute *pAttribute );
void RemoveAllAttributes();
void RenameAttribute( const char *pAttributeName, const char *pNewName );
// Simple methods to read attributes
const char *GetValueString( const char *pAttributeName ) const;
template< class T > const T& GetValue( const char *pAttributeName ) const;
template< class T > const T& GetValue( const char *pAttributeName, const T& defaultValue ) const;
template< class T > const CUtlVector<T>& GetArray( const char *pAttributeName ) const;
template< class T > const CUtlVector<T>& GetArray( const char *pAttributeName, const CUtlVector<T>& defaultValue ) const;
// Set methods
CDmxAttribute* SetValue( const char *pAttributeName, const char *pString );
CDmxAttribute* SetValue( const char *pAttributeName, void *pBuffer, int nLen );
template< class T > CDmxAttribute* SetValue( const char *pAttributeName, const T& value );
// Method to unpack data into a structure
void UnpackIntoStructure( void *pData, size_t DataSizeInBytes, const DmxElementUnpackStructure_t *pUnpack ) const;
// Creates attributes based on the unpack structure
template <typename T>
void AddAttributesFromStructure( const T *pData, const DmxElementUnpackStructure_t *pUnpack )
{
AddAttributesFromStructure_Internal( pData, sizeof(T), pUnpack );
}
private:
void AddAttributesFromStructure_Internal( const void *pData, size_t byteCount, const DmxElementUnpackStructure_t *pUnpack );
typedef CUtlSortVector< CDmxAttribute*, CDmxAttributeLess > AttributeList_t;
CDmxElement( const char *pType );
~CDmxElement();
// Removes all elements recursively
void RemoveAllElementsRecursive();
// Adds elements to delete to the deletion list
void AddElementsToDelete( CUtlVector< CDmxElement * >& elementsToDelete );
// Sorts the vector when a change has occurred
void Resort( ) const;
// Finds an attribute by name
int FindAttribute( const char *pAttributeName ) const;
int FindAttribute( CUtlSymbol attributeName ) const;
// Sets the object id
void SetId( const DmObjectId_t &id );
// Are we locked?
bool IsLocked() const;
AttributeList_t m_Attributes;
DmObjectId_t m_Id; // We need this strictly because we support serialization
CUtlSymbol m_Type;
char m_nLockCount;
mutable bool m_bResortNeeded : 1;
bool m_bIsMarkedForDeletion : 1;
static CUtlSymbolTableMT s_TypeSymbols;
friend class CDmxSerializer;
friend class CDmxSerializerKeyValues2;
friend void CleanupDMX( CDmxElement* pElement );
friend CDmxElement* CreateDmxElement( const char *pType );
};
//-----------------------------------------------------------------------------
// inline methods
//-----------------------------------------------------------------------------
// Are we locked?
inline bool CDmxElement::IsLocked() const
{
return m_nLockCount > 0;
}
inline const char *CDmxElement::GetValueString( const char *pAttributeName ) const
{
const CDmxAttribute* pAttribute = GetAttribute( pAttributeName );
if ( pAttribute )
return pAttribute->GetValueString();
return "";
}
template< class T >
inline const T& CDmxElement::GetValue( const char *pAttributeName ) const
{
const CDmxAttribute* pAttribute = GetAttribute( pAttributeName );
if ( pAttribute )
return pAttribute->GetValue<T>();
static T defaultValue;
CDmAttributeInfo<T>::SetDefaultValue( defaultValue );
return defaultValue;
}
template< class T >
inline const T& CDmxElement::GetValue( const char *pAttributeName, const T& defaultValue ) const
{
const CDmxAttribute* pAttribute = GetAttribute( pAttributeName );
if ( pAttribute )
return pAttribute->GetValue<T>();
return defaultValue;
}
template< class T >
inline const CUtlVector<T>& CDmxElement::GetArray( const char *pAttributeName ) const
{
const CDmxAttribute* pAttribute = GetAttribute( pAttributeName );
if ( pAttribute )
return pAttribute->GetArray<T>();
static CUtlVector<T> defaultValue;
return defaultValue;
}
template< class T >
inline const CUtlVector<T>& CDmxElement::GetArray( const char *pAttributeName, const CUtlVector<T>& defaultValue ) const
{
const CDmxAttribute* pAttribute = GetAttribute( pAttributeName );
if ( pAttribute )
return pAttribute->GetArray<T>();
return defaultValue;
}
//-----------------------------------------------------------------------------
// Creates a dmx element
//-----------------------------------------------------------------------------
CDmxElement* CreateDmxElement( const char *pType );
//-----------------------------------------------------------------------------
// Helper class to lock elements for changes
//-----------------------------------------------------------------------------
class CDmxElementModifyScope
{
public:
CDmxElementModifyScope( CDmxElement *pElement ) : m_pElement( pElement )
{
m_pElement->LockForChanges( true );
}
~CDmxElementModifyScope()
{
Release();
}
void Release()
{
if ( m_pElement )
{
m_pElement->LockForChanges( false );
m_pElement = NULL;
}
}
private:
CDmxElement *m_pElement;
};
//-----------------------------------------------------------------------------
// Set methods
//-----------------------------------------------------------------------------
inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, const char *pString )
{
CDmxElementModifyScope modify( this );
CDmxAttribute *pAttribute = AddAttribute( pAttributeName );
pAttribute->SetValue( pString );
return pAttribute;
}
inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, void *pBuffer, int nLen )
{
CDmxElementModifyScope modify( this );
CDmxAttribute *pAttribute = AddAttribute( pAttributeName );
pAttribute->SetValue( pBuffer, nLen );
return pAttribute;
}
template< class T >
inline CDmxAttribute* CDmxElement::SetValue( const char *pAttributeName, const T& value )
{
CDmxElementModifyScope modify( this );
CDmxAttribute *pAttribute = AddAttribute( pAttributeName );
pAttribute->SetValue( value );
return pAttribute;
}
#endif // DMXELEMENT_H