You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
12 KiB
301 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Attributable entities contain one of these, which handles game specific handling: |
|
// - Save / Restore |
|
// - Networking |
|
// - Attribute providers |
|
// - Application of attribute effects |
|
// |
|
//============================================================================= |
|
|
|
#ifndef ATTRIBUTE_MANAGER_H |
|
#define ATTRIBUTE_MANAGER_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "econ_item_view.h" |
|
#include "ihasattributes.h" |
|
#include "tf_gcmessages.h" |
|
|
|
// Provider types |
|
enum attributeprovidertypes_t |
|
{ |
|
PROVIDER_GENERIC, |
|
PROVIDER_WEAPON, |
|
}; |
|
|
|
float CollateAttributeValues( const CEconItemAttributeDefinition *pAttrDef1, const float flAttribValue1, const CEconItemAttributeDefinition *pAttrDef2, const float flAttribValue2 ); |
|
|
|
// Retrieve the IHasAttributes pointer from a Base Entity. This function checks for NULL entities |
|
// and asserts the return value is == to dynamic_cast< IHasAttributes * >( pEntity ). |
|
inline IHasAttributes *GetAttribInterface( CBaseEntity *pEntity ) |
|
{ |
|
IHasAttributes *pAttribInterface = pEntity ? pEntity->GetHasAttributesInterfacePtr() : NULL; |
|
// If this assert hits it most likely means that m_pAttribInterface has not been set |
|
// in the leaf class constructor for this object. See CTFPlayer::CTFPlayer() for an |
|
// example. |
|
Assert( pAttribInterface == dynamic_cast< IHasAttributes *>( pEntity ) ); |
|
return pAttribInterface; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Macros for hooking the application of attributes |
|
#define CALL_ATTRIB_HOOK( vartype, retval, hookName, who, itemlist ) \ |
|
retval = CAttributeManager::AttribHookValue<vartype>( retval, #hookName, static_cast<const CBaseEntity*>( who ), itemlist, true ); |
|
|
|
#define CALL_ATTRIB_HOOK_INT( retval, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, this, NULL ) |
|
#define CALL_ATTRIB_HOOK_FLOAT( retval, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, this, NULL ) |
|
#define CALL_ATTRIB_HOOK_STRING( retval, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, this, NULL ) |
|
#define CALL_ATTRIB_HOOK_INT_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, other, NULL ) |
|
#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, other, NULL ) |
|
#define CALL_ATTRIB_HOOK_STRING_ON_OTHER( other, retval, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, other, NULL ) |
|
#define CALL_ATTRIB_HOOK_INT_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( int, retval, hookName, other, items_array ) |
|
#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( float, retval, hookName, other, items_array ) |
|
#define CALL_ATTRIB_HOOK_STRING_ON_OTHER_WITH_ITEMS( other, retval, items_array, hookName ) CALL_ATTRIB_HOOK( CAttribute_String, retval, hookName, other, items_array ) |
|
|
|
template< class T > T AttributeConvertFromFloat( float flValue ); |
|
template<> float AttributeConvertFromFloat<float>( float flValue ); |
|
template<> int AttributeConvertFromFloat<int>( float flValue ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Base Attribute manager. |
|
// This class knows how to apply attribute effects that have been |
|
// provided to its owner by other entities, but doesn't contain attributes itself. |
|
//----------------------------------------------------------------------------- |
|
class CAttributeManager |
|
{ |
|
DECLARE_CLASS_NOBASE( CAttributeManager ); |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_EMBEDDED_NETWORKVAR(); |
|
|
|
CAttributeManager(); |
|
virtual ~CAttributeManager() {} |
|
|
|
// Call this inside your entity's Spawn() |
|
virtual void InitializeAttributes( CBaseEntity *pEntity ); |
|
|
|
CBaseEntity *GetOuter( void ) const { return m_hOuter.Get(); } |
|
|
|
//-------------------------------------------------------- |
|
// Attribute providers. |
|
// Other entities that are providing attributes to this entity (i.e. weapons being carried by a player) |
|
void ProvideTo( CBaseEntity *pProvider ); |
|
void StopProvidingTo( CBaseEntity *pProvider ); |
|
|
|
protected: |
|
// Not to be called directly. Use ProvideTo() or StopProvidingTo() above. |
|
void AddProvider( CBaseEntity *pProvider ); |
|
void RemoveProvider( CBaseEntity *pProvider ); |
|
|
|
public: |
|
// Return true if this entity is providing attributes to the specified entity |
|
bool IsProvidingTo( CBaseEntity *pEntity ) const; |
|
|
|
// Return true if this entity is being provided attributes by the specified entity |
|
bool IsBeingProvidedToBy( CBaseEntity *pEntity ) const; |
|
|
|
// Provider types are used to prevent specified providers supplying to certain initiators |
|
void SetProviderType( attributeprovidertypes_t tType ) { m_ProviderType = tType; } |
|
attributeprovidertypes_t GetProviderType( void ) const { return m_ProviderType; } |
|
|
|
//-------------------------------------------------------- |
|
// Attribute hook. Use the CALL_ATTRIB_HOOK macros above. |
|
template <class T> static T AttribHookValue( T TValue, const char *pszAttribHook, const CBaseEntity *pEntity, CUtlVector<CBaseEntity*> *pItemList = NULL, bool bIsGlobalConstString = false ) |
|
{ |
|
VPROF_BUDGET( "CAttributeManager::AttribHookValue", VPROF_BUDGETGROUP_ATTRIBUTES ); |
|
|
|
// Do we have a hook? |
|
if ( pszAttribHook == NULL || pszAttribHook[0] == '\0' ) |
|
return TValue; |
|
|
|
// Verify that we have an entity, at least as "this" |
|
if ( pEntity == NULL ) |
|
return TValue; |
|
|
|
IHasAttributes *pAttribInterface = GetAttribInterface( (CBaseEntity*) pEntity ); |
|
AssertMsg( pAttribInterface, "If you hit this, you've probably got a hook incorrectly setup, because the entity it's hooking on doesn't know about attributes." ); |
|
if ( pAttribInterface == NULL ) |
|
return TValue; |
|
|
|
// Hook base attribute. |
|
T Scratch; |
|
AttribHookValueInternal( Scratch, TValue, pszAttribHook, pEntity, pAttribInterface, pItemList, bIsGlobalConstString ); |
|
|
|
return Scratch; |
|
} |
|
|
|
private: |
|
template <class T> static void TypedAttribHookValueInternal( T& out, T TValue, string_t iszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList ) |
|
{ |
|
float flValue = pAttribInterface->GetAttributeManager()->ApplyAttributeFloatWrapper( static_cast<float>( TValue ), const_cast<CBaseEntity *>( pEntity ), iszAttribHook, pItemList ); |
|
|
|
out = AttributeConvertFromFloat<T>( flValue ); |
|
} |
|
|
|
static void TypedAttribHookValueInternal( CAttribute_String& out, const CAttribute_String& TValue, string_t iszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList ) |
|
{ |
|
string_t iszIn = AllocPooledString( TValue.value().c_str() ); |
|
string_t iszOut = pAttribInterface->GetAttributeManager()->ApplyAttributeStringWrapper( iszIn, const_cast<CBaseEntity *>( pEntity ), iszAttribHook, pItemList ); |
|
const char* pszOut = STRING( iszOut ); |
|
// STRING() returns different value for server and client |
|
// server will return "" for NULL_STRING |
|
// client will return NULL for NULL_STRING |
|
if ( pszOut ) |
|
{ |
|
out.set_value( pszOut ); |
|
} |
|
else |
|
{ |
|
out.set_value( "" ); |
|
} |
|
} |
|
|
|
template <class T> static void AttribHookValueInternal( T& out, T TValue, const char *pszAttribHook, const CBaseEntity *pEntity, IHasAttributes *pAttribInterface, CUtlVector<CBaseEntity*> *pItemList, bool bIsGlobalConstString ) |
|
{ |
|
Assert( pszAttribHook ); |
|
Assert( pszAttribHook[0] ); |
|
Assert( pEntity ); |
|
Assert( pAttribInterface ); |
|
Assert( GetAttribInterface( (CBaseEntity*) pEntity ) == pAttribInterface ); |
|
Assert( pAttribInterface->GetAttributeManager() ); |
|
|
|
string_t iszAttribHook = bIsGlobalConstString ? AllocPooledString_StaticConstantStringPointer( pszAttribHook ) : AllocPooledString( pszAttribHook ); |
|
return TypedAttribHookValueInternal( out, TValue, iszAttribHook, pEntity, pAttribInterface, pItemList ); |
|
} |
|
int m_nCurrentTick; |
|
int m_nCalls; |
|
|
|
public: |
|
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ); |
|
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ); |
|
|
|
//-------------------------------------------------------- |
|
// Networking |
|
#ifdef CLIENT_DLL |
|
virtual void OnPreDataChanged( DataUpdateType_t updateType ); |
|
virtual void OnDataChanged( DataUpdateType_t updateType ); |
|
#endif |
|
|
|
//-------------------------------------------------------- |
|
// memory handling |
|
void *operator new( size_t stAllocateBlock ); |
|
void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); |
|
|
|
protected: |
|
CUtlVector<EHANDLE> m_Providers; // entities that we receive attribute data *from* |
|
CUtlVector<EHANDLE> m_Receivers; // entities that we provide attribute data *to* |
|
CNetworkVarForDerived( int, m_iReapplyProvisionParity ); |
|
CNetworkVarForDerived( EHANDLE, m_hOuter ); |
|
bool m_bPreventLoopback; |
|
CNetworkVarForDerived( attributeprovidertypes_t, m_ProviderType ); |
|
int m_iCacheVersion; // maps to gamerules counter for global cache flushing |
|
|
|
public: |
|
virtual void OnAttributeValuesChanged() |
|
{ |
|
ClearCache(); |
|
} |
|
|
|
private: |
|
void ClearCache(); |
|
int GetGlobalCacheVersion() const; |
|
|
|
virtual float ApplyAttributeFloatWrapper( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList = NULL ); |
|
virtual string_t ApplyAttributeStringWrapper( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList = NULL ); |
|
|
|
// Cached attribute results |
|
// We cache off requests for data, and wipe the cache whenever our providers change. |
|
union cached_attribute_types |
|
{ |
|
float fl; |
|
string_t isz; |
|
}; |
|
|
|
struct cached_attribute_t |
|
{ |
|
string_t iAttribHook; |
|
cached_attribute_types in; |
|
cached_attribute_types out; |
|
}; |
|
CUtlVector<cached_attribute_t> m_CachedResults; |
|
|
|
#ifdef CLIENT_DLL |
|
public: |
|
// Data received from the server |
|
int m_iOldReapplyProvisionParity; |
|
#endif |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: This is an attribute manager that also knows how to contain attributes. |
|
//----------------------------------------------------------------------------- |
|
class CAttributeContainer : public CAttributeManager |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CAttributeContainer, CAttributeManager ); |
|
DECLARE_EMBEDDED_NETWORKVAR(); |
|
|
|
virtual void InitializeAttributes( CBaseEntity *pEntity ); |
|
|
|
//-------------------------------------------------------- |
|
// Attribute hook. Use the CALL_ATTRIB_HOOK macros above. |
|
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE; |
|
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE; |
|
|
|
CEconItemView *GetItem( void ) { return &m_Item; } |
|
const CEconItemView *GetItem( void ) const { return &m_Item; } |
|
void SetItem( const CEconItemView *pItem ) { m_Item.CopyFrom( *pItem ); } |
|
|
|
virtual void OnAttributeValuesChanged() |
|
{ |
|
BaseClass::OnAttributeValuesChanged(); |
|
|
|
m_Item.OnAttributeValuesChanged(); |
|
} |
|
|
|
private: |
|
CNetworkVarEmbedded( CEconItemView, m_Item ); |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: An attribute manager that uses a player's shared attributes. |
|
//----------------------------------------------------------------------------- |
|
|
|
#ifndef DOTA_DLL |
|
class CAttributeContainerPlayer : public CAttributeManager |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CAttributeContainerPlayer, CAttributeManager ); |
|
DECLARE_EMBEDDED_NETWORKVAR(); |
|
|
|
virtual float ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE; |
|
virtual string_t ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook = NULL_STRING, CUtlVector<CBaseEntity*> *pItemList = NULL ) OVERRIDE; |
|
|
|
CBasePlayer* GetPlayer( void ) { return m_hPlayer; } |
|
void SetPlayer( CBasePlayer *pPlayer ) { m_hPlayer = pPlayer; } |
|
|
|
virtual void OnAttributeValuesChanged() |
|
{ |
|
BaseClass::OnAttributeValuesChanged(); |
|
|
|
m_hPlayer->NetworkStateChanged(); |
|
} |
|
|
|
private: |
|
CNetworkHandle( CBasePlayer, m_hPlayer ); |
|
}; |
|
#endif |
|
|
|
#ifdef CLIENT_DLL |
|
EXTERN_RECV_TABLE( DT_AttributeManager ); |
|
EXTERN_RECV_TABLE( DT_AttributeContainer ); |
|
#else |
|
EXTERN_SEND_TABLE( DT_AttributeManager ); |
|
EXTERN_SEND_TABLE( DT_AttributeContainer ); |
|
#endif |
|
|
|
#endif // ATTRIBUTE_MANAGER_H
|
|
|