This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

333 lines
14 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef DMXELEMENT_H
#define DMXELEMENT_H
#ifdef _WIN32
#pragma once
#endif
#include "datamodel/dmattributetypes.h"
#include "dmxloader/dmxattribute.h"
#include "tier1/UtlSortVector.h"
#include "tier1/mempool.h"
#include "tier1/utlrbtree.h"
#include "tier1/utlsymbol.h"
#include "tier1/utlvector.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(), \
offsetof(DestStructType_t, _varName), \
sizeof(fltx4), \
NULL},
#define DMXELEMENT_UNPACK_FIELD(_attributeName, _defaultString, _type, \
_varName) \
{_attributeName, \
_defaultString, \
CDmAttributeInfo<_type>::AttributeType(), \
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(), \
offsetof(DestStructType_t, _varName), \
sizeof(((DestStructType_t *)0)->_varName), \
_userData},
#define DMXELEMENT_UNPACK_FIELD_STRING_USERDATA( \
_attributeName, _defaultString, _varName, _userData) \
{_attributeName, \
_defaultString, \
AT_STRING, \
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