This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+881
View File
@@ -0,0 +1,881 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "attribute_manager.h"
#include "gamestringpool.h"
#include "saverestore.h"
#include "saverestore_utlvector.h"
#include "fmtstr.h"
#include "KeyValues.h"
#include "econ_item_system.h"
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
#include "tf_gamerules.h" // attribute cache flushing; can be generalized if/when Dota needs similar functionality
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
#define PROVIDER_PARITY_BITS 6
#define PROVIDER_PARITY_MASK ((1<<PROVIDER_PARITY_BITS)-1)
//==================================================================================================================
// ATTRIBUTE MANAGER SAVE/LOAD & NETWORKING
//===================================================================================================================
BEGIN_DATADESC_NO_BASE( CAttributeManager )
DEFINE_UTLVECTOR( m_Providers, FIELD_EHANDLE ),
DEFINE_UTLVECTOR( m_Receivers, FIELD_EHANDLE ),
DEFINE_FIELD( m_iReapplyProvisionParity, FIELD_INTEGER ),
DEFINE_FIELD( m_hOuter, FIELD_EHANDLE ),
// DEFINE_FIELD( m_bPreventLoopback, FIELD_BOOLEAN ), // Don't need to save
DEFINE_FIELD( m_ProviderType, FIELD_INTEGER ),
END_DATADESC()
BEGIN_DATADESC( CAttributeContainer )
DEFINE_EMBEDDED( m_Item ),
END_DATADESC()
#ifndef DOTA_DLL
BEGIN_DATADESC( CAttributeContainerPlayer )
END_DATADESC()
#endif
#ifndef CLIENT_DLL
EXTERN_SEND_TABLE( DT_ScriptCreatedItem );
#else
EXTERN_RECV_TABLE( DT_ScriptCreatedItem );
#endif
BEGIN_NETWORK_TABLE_NOBASE( CAttributeManager, DT_AttributeManager )
#ifndef CLIENT_DLL
SendPropEHandle( SENDINFO(m_hOuter) ),
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
#else
RecvPropEHandle( RECVINFO(m_hOuter) ),
RecvPropInt( RECVINFO(m_ProviderType) ),
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
#endif
END_NETWORK_TABLE()
BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainer, DT_AttributeContainer )
#ifndef CLIENT_DLL
SendPropEHandle( SENDINFO(m_hOuter) ),
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
SendPropDataTable(SENDINFO_DT(m_Item), &REFERENCE_SEND_TABLE(DT_ScriptCreatedItem)),
#else
RecvPropEHandle( RECVINFO(m_hOuter) ),
RecvPropInt( RECVINFO(m_ProviderType) ),
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
RecvPropDataTable(RECVINFO_DT(m_Item), 0, &REFERENCE_RECV_TABLE(DT_ScriptCreatedItem)),
#endif
END_NETWORK_TABLE()
#ifndef DOTA_DLL
BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainerPlayer, DT_AttributeContainerPlayer )
#ifndef CLIENT_DLL
SendPropEHandle( SENDINFO(m_hOuter) ),
SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
SendPropEHandle( SENDINFO(m_hPlayer) ),
#else
RecvPropEHandle( RECVINFO(m_hOuter) ),
RecvPropInt( RECVINFO(m_ProviderType) ),
RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
RecvPropEHandle( RECVINFO( m_hPlayer ) ),
#endif
END_NETWORK_TABLE()
#endif
template< class T > T AttributeConvertFromFloat( float flValue )
{
return static_cast<T>( flValue );
}
template<> float AttributeConvertFromFloat<float>( float flValue )
{
return flValue;
}
template<> int AttributeConvertFromFloat<int>( float flValue )
{
return RoundFloatToInt( flValue );
}
//-----------------------------------------------------------------------------
// All fields in the object are all initialized to 0.
//-----------------------------------------------------------------------------
void *CAttributeManager::operator new( size_t stAllocateBlock )
{
// call into engine to get memory
Assert( stAllocateBlock != 0 );
void *pMem = malloc( stAllocateBlock );
memset( pMem, 0, stAllocateBlock );
return pMem;
};
void *CAttributeManager::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
{
// call into engine to get memory
Assert( stAllocateBlock != 0 );
void *pMem = malloc( stAllocateBlock );
memset( pMem, 0, stAllocateBlock );
return pMem;
}
CAttributeManager::CAttributeManager()
{
m_nCalls = 0;
m_nCurrentTick = 0;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::OnPreDataChanged( DataUpdateType_t updateType )
{
m_iOldReapplyProvisionParity = m_iReapplyProvisionParity;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::OnDataChanged( DataUpdateType_t updateType )
{
if ( m_iReapplyProvisionParity != m_iOldReapplyProvisionParity )
{
// We've changed who we're providing to in some way. Reapply it.
IHasAttributes *pAttribInterface = GetAttribInterface( GetOuter() );
if ( pAttribInterface )
{
pAttribInterface->ReapplyProvision();
}
ClearCache();
m_iOldReapplyProvisionParity = m_iReapplyProvisionParity.Get();
}
}
#endif // CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Call this inside your entity's Spawn()
//-----------------------------------------------------------------------------
void CAttributeManager::InitializeAttributes( CBaseEntity *pEntity )
{
Assert( GetAttribInterface( pEntity ) );
m_hOuter = pEntity;
m_bPreventLoopback = false;
}
//=====================================================================================================
// ATTRIBUTE PROVIDERS
//=====================================================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::ProvideTo( CBaseEntity *pProvider )
{
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pProvider );
if ( pOwnerAttribInterface )
{
pOwnerAttribInterface->GetAttributeManager()->AddProvider( m_hOuter.Get() );
#ifndef CLIENT_DLL
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
NetworkStateChanged();
#endif
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::StopProvidingTo( CBaseEntity *pProvider )
{
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pProvider );
if ( pOwnerAttribInterface )
{
pOwnerAttribInterface->GetAttributeManager()->RemoveProvider( m_hOuter.Get() );
#ifndef CLIENT_DLL
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
NetworkStateChanged();
#endif
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::AddProvider( CBaseEntity *pProvider )
{
// Make sure he's not already in our list, and prevent circular provision
Assert( !IsBeingProvidedToBy(pProvider) );
Assert( !IsProvidingTo(pProvider) );
// Ensure he's allowed to provide
IHasAttributes *pProviderAttrInterface = GetAttribInterface( pProvider );
Assert( pProviderAttrInterface );
m_Providers.AddToTail( pProvider );
pProviderAttrInterface->GetAttributeManager()->m_Receivers.AddToTail( GetOuter() );
ClearCache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::RemoveProvider( CBaseEntity *pProvider )
{
Assert( pProvider );
IHasAttributes *pProviderAttrInterface = GetAttribInterface( pProvider );
Assert( pProviderAttrInterface );
if ( !IsBeingProvidedToBy( pProvider ) )
return;
Assert( pProviderAttrInterface->GetAttributeManager()->IsProvidingTo( GetOuter() ) );
Assert( pProviderAttrInterface->GetAttributeManager()->m_Receivers.Find( GetOuter() ) != pProviderAttrInterface->GetAttributeManager()->m_Receivers.InvalidIndex() );
m_Providers.FindAndFastRemove( pProvider );
pProviderAttrInterface->GetAttributeManager()->m_Receivers.FindAndFastRemove( GetOuter() );
ClearCache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAttributeManager::ClearCache( void )
{
if ( m_bPreventLoopback )
return;
m_CachedResults.Purge();
m_bPreventLoopback = true;
// Tell all providers relying on me that they need to wipe their cache too
FOR_EACH_VEC( m_Receivers, i )
{
IHasAttributes *pAttribInterface = GetAttribInterface( m_Receivers[i].Get() );
if ( pAttribInterface )
{
pAttribInterface->GetAttributeManager()->ClearCache();
}
}
// Tell our owner that he needs to clear his too, in case he has attributes affecting him
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
if ( pMyAttribInterface )
{
pMyAttribInterface->GetAttributeManager()->ClearCache();
}
m_bPreventLoopback = false;
#ifndef CLIENT_DLL
// Force out client to clear their cache as well
m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
NetworkStateChanged();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CAttributeManager::GetGlobalCacheVersion() const
{
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
return TFGameRules() ? TFGameRules()->GetGlobalAttributeCacheVersion() : 0;
#else
return 0;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this entity is providing attributes to the specified entity
//-----------------------------------------------------------------------------
bool CAttributeManager::IsProvidingTo( CBaseEntity *pEntity ) const
{
IHasAttributes *pAttribInterface = GetAttribInterface( pEntity );
if ( pAttribInterface )
{
if ( pAttribInterface->GetAttributeManager()->IsBeingProvidedToBy( GetOuter() ) )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this entity is being provided attributes by the specified entity
//-----------------------------------------------------------------------------
bool CAttributeManager::IsBeingProvidedToBy( CBaseEntity *pEntity ) const
{
return ( m_Providers.Find( pEntity ) != m_Providers.InvalidIndex() );
}
//=====================================================================================================
// ATTRIBUTE HOOKS
//=====================================================================================================
//-----------------------------------------------------------------------------
// Purpose: Wrapper that checks to see if we've already got the result in our cache
//-----------------------------------------------------------------------------
float CAttributeManager::ApplyAttributeFloatWrapper( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
{
VPROF_BUDGET( "CAttributeManager::ApplyAttributeFloatWrapper", VPROF_BUDGETGROUP_ATTRIBUTES );
#ifdef DEBUG
AssertMsg1( m_nCalls != 5000, "%d calls for attributes in a single tick. This is slow and bad.", m_nCalls );
if( m_nCurrentTick != gpGlobals->tickcount )
{
m_nCalls = 0;
m_nCurrentTick = gpGlobals->tickcount;
}
++m_nCalls;
#endif
// Have we requested a global attribute cache flush?
const int iGlobalCacheVersion = GetGlobalCacheVersion();
if ( m_iCacheVersion != iGlobalCacheVersion )
{
ClearCache();
m_iCacheVersion = iGlobalCacheVersion;
}
// We can't cache off item references so if we asked for them we need to execute the whole slow path.
if ( !pItemList )
{
int iCount = m_CachedResults.Count();
for ( int i = iCount-1; i >= 0; i-- )
{
if ( m_CachedResults[i].iAttribHook == iszAttribHook )
{
if ( m_CachedResults[i].in.fl == flValue )
return m_CachedResults[i].out.fl;
// We've got a cached result for a different flIn value. Remove the cached result to
// prevent stacking up entries for different requests (i.e. crit chance)
m_CachedResults.Remove(i);
break;
}
}
}
// Wasn't in cache, or we need item references. Do the work.
float flResult = ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
// Add it to our cache if we didn't ask for item references. We could add the result value here
// even if we did but we'd need to walk the cache to search for an old entry to overwrite first.
if ( !pItemList )
{
int iIndex = m_CachedResults.AddToTail();
m_CachedResults[iIndex].in.fl = flValue;
m_CachedResults[iIndex].out.fl = flResult;
m_CachedResults[iIndex].iAttribHook = iszAttribHook;
}
return flResult;
}
//-----------------------------------------------------------------------------
// Purpose: Wrapper that checks to see if we've already got the result in our cache
//-----------------------------------------------------------------------------
string_t CAttributeManager::ApplyAttributeStringWrapper( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
{
// Have we requested a global attribute cache flush?
const int iGlobalCacheVersion = GetGlobalCacheVersion();
if ( m_iCacheVersion != iGlobalCacheVersion )
{
ClearCache();
m_iCacheVersion = iGlobalCacheVersion;
}
// We can't cache off item references so if we asked for them we need to execute the whole slow path.
if ( !pItemList )
{
int iCount = m_CachedResults.Count();
for ( int i = iCount-1; i >= 0; i-- )
{
if ( m_CachedResults[i].iAttribHook == iszAttribHook )
{
if ( m_CachedResults[i].in.isz == iszValue )
{
return m_CachedResults[i].out.isz;
}
// We've got a cached result for a different flIn value. Remove the cached result to
// prevent stacking up entries for different requests (i.e. crit chance)
m_CachedResults.Remove(i);
break;
}
}
}
// Wasn't in cache, or we need item references. Do the work.
string_t iszOut = ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
// Add it to our cache if we didn't ask for item references. We could add the result value here
// even if we did but we'd need to walk the cache to search for an old entry to overwrite first.
if ( !pItemList )
{
int iIndex = m_CachedResults.AddToTail();
m_CachedResults[iIndex].in.isz = iszValue;
m_CachedResults[iIndex].out.isz = iszOut;
m_CachedResults[iIndex].iAttribHook = iszAttribHook;
}
return iszOut;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CAttributeManager::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
{
VPROF_BUDGET( "CAttributeManager::ApplyAttributeFloat", VPROF_BUDGETGROUP_ATTRIBUTES );
if ( m_bPreventLoopback || !GetOuter() )
return flValue;
// We need to prevent loopback between two items both providing to the same entity.
m_bPreventLoopback = true;
IHasAttributes *pInitiatorAttribInterface = GetAttribInterface( pInitiator );
// See if we have any providers. If we do, tell them to apply.
FOR_EACH_VEC( m_Providers, iHook )
{
CBaseEntity *pProvider = m_Providers[iHook].Get();
if ( !pProvider )
continue;
if ( pProvider == pInitiator )
continue;
IHasAttributes *pAttribInterface = GetAttribInterface( pProvider );
Assert( pAttribInterface );
// Don't allow weapons to provide to other weapons being carried by the same person
if ( pInitiatorAttribInterface &&
pAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON &&
pInitiatorAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
{
continue;
}
flValue = pAttribInterface->GetAttributeManager()->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
}
// Then see if our owner has any attributes he wants to apply as well.
// i.e. An aura is providing attributes to this weapon's carrier.
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
Assert( pMyAttribInterface );
if ( pMyAttribInterface && pMyAttribInterface->GetAttributeOwner() )
{
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pMyAttribInterface->GetAttributeOwner() );
if ( pOwnerAttribInterface )
{
flValue = pOwnerAttribInterface->GetAttributeManager()->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
}
}
m_bPreventLoopback = false;
return flValue;
}
string_t CAttributeManager::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
{
VPROF_BUDGET( "CAttributeManager::ApplyAttributeString", VPROF_BUDGETGROUP_ATTRIBUTES );
if ( m_bPreventLoopback || !GetOuter() )
return iszValue;
// We need to prevent loopback between two items both providing to the same entity.
m_bPreventLoopback = true;
IHasAttributes *pInitiatorAttribInterface = GetAttribInterface( pInitiator );
// See if we have any providers. If we do, tell them to apply.
FOR_EACH_VEC( m_Providers, iHook )
{
CBaseEntity *pProvider = m_Providers[iHook].Get();
if ( !pProvider )
continue;
if ( pProvider == pInitiator )
continue;
IHasAttributes *pAttribInterface = GetAttribInterface( pProvider );
Assert( pAttribInterface );
// Don't allow weapons to provide to other weapons being carried by the same person
if ( pInitiatorAttribInterface &&
pAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON &&
pInitiatorAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
{
continue;
}
iszValue = pAttribInterface->GetAttributeManager()->ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
}
// Then see if our owner has any attributes he wants to apply as well.
// i.e. An aura is providing attributes to this weapon's carrier.
IHasAttributes *pMyAttribInterface = GetAttribInterface( m_hOuter.Get().Get() );
Assert( pMyAttribInterface );
if ( pMyAttribInterface->GetAttributeOwner() )
{
IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pMyAttribInterface->GetAttributeOwner() );
if ( pOwnerAttribInterface )
{
iszValue = pOwnerAttribInterface->GetAttributeManager()->ApplyAttributeString( iszValue, pInitiator, iszAttribHook, pItemList );
}
}
m_bPreventLoopback = false;
return iszValue;
}
//=====================================================================================================
// ATTRIBUTE CONTAINER
//=====================================================================================================
//-----------------------------------------------------------------------------
// Purpose: Call this inside your entity's Spawn()
//-----------------------------------------------------------------------------
void CAttributeContainer::InitializeAttributes( CBaseEntity *pEntity )
{
BaseClass::InitializeAttributes( pEntity );
#ifndef CLIENT_DLL
/*
if ( !m_Item.IsValid() )
{
Warning("Item '%s' not setup correctly. Attempting to create attributes on an unitialized item.\n", m_hOuter.Get()->GetDebugName() );
}
*/
#endif
m_Item.GetAttributeList()->SetManager( this );
OnAttributeValuesChanged();
}
static void ApplyAttribute( const CEconItemAttributeDefinition *pAttributeDef, float& flValue, const float flValueModifier )
{
Assert( pAttributeDef );
Assert( pAttributeDef->GetAttributeType() );
AssertMsg1( pAttributeDef->GetAttributeType()->BSupportsGameplayModificationAndNetworking(), "Attempt to hook the value of attribute '%s' which doesn't support hooking! Pull the value of the attribute directly using FindAttribute()!", pAttributeDef->GetDefinitionName() );
const int iAttrDescFormat = pAttributeDef->GetDescriptionFormat();
switch ( iAttrDescFormat )
{
case ATTDESCFORM_VALUE_IS_PERCENTAGE:
case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
{
flValue *= flValueModifier;
}
break;
case ATTDESCFORM_VALUE_IS_ADDITIVE:
case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
case ATTDESCFORM_VALUE_IS_PARTICLE_INDEX:
{
flValue += flValueModifier;
}
break;
case ATTDESCFORM_VALUE_IS_KILLSTREAK_IDLEEFFECT_INDEX:
case ATTDESCFORM_VALUE_IS_KILLSTREAKEFFECT_INDEX:
case ATTDESCFORM_VALUE_IS_FROM_LOOKUP_TABLE:
{
flValue = flValueModifier;
}
break;
case ATTDESCFORM_VALUE_IS_OR:
{
int iTmp = flValue;
iTmp |= (int)flValueModifier;
flValue = iTmp;
}
break;
case ATTDESCFORM_VALUE_IS_DATE:
Assert( !"Attempt to apply date attribute in ApplyAttribute()." ); // No-one should be hooking date descriptions
break;
default:
// Unknown value format.
AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: Given two attributes, return a collated value.
//-----------------------------------------------------------------------------
float CollateAttributeValues( const CEconItemAttributeDefinition *pAttrDef1, const float flAttribValue1, const CEconItemAttributeDefinition *pAttrDef2, const float flAttribValue2 )
{
Assert( pAttrDef1 );
Assert( pAttrDef2 );
AssertMsg2( !Q_stricmp( pAttrDef1->GetAttributeClass(), pAttrDef2->GetAttributeClass() ), "We can only collate attributes of matching definitions: mismatch between '%s' / '%s'!", pAttrDef1->GetAttributeClass(), pAttrDef2->GetAttributeClass() );
AssertMsg2( pAttrDef1->GetDescriptionFormat() == pAttrDef2->GetDescriptionFormat(), "We can only collate attributes of matching description format: mismatch between '%u' / '%u'!", pAttrDef1->GetDescriptionFormat(), pAttrDef2->GetDescriptionFormat() );
const int iAttrDescFormat = pAttrDef1->GetDescriptionFormat();
float flValue = 0;
switch ( iAttrDescFormat )
{
case ATTDESCFORM_VALUE_IS_PERCENTAGE:
case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
{
flValue = 1.0;
}
break;
case ATTDESCFORM_VALUE_IS_ADDITIVE:
case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
case ATTDESCFORM_VALUE_IS_FROM_LOOKUP_TABLE:
case ATTDESCFORM_VALUE_IS_OR:
{
flValue = 0;
}
break;
case ATTDESCFORM_VALUE_IS_DATE:
Assert( !"Attempt to apply date attribute in CollateAttributeValues()." ); // No-one should be hooking date descriptions
break;
default:
// Unknown value format.
AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
break;
}
ApplyAttribute( pAttrDef1, flValue, flAttribValue1 );
ApplyAttribute( pAttrDef2, flValue, flAttribValue2 );
return flValue;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemAttributeIterator_ApplyAttributeFloat : public CEconItemSpecificAttributeIterator
{
public:
CEconItemAttributeIterator_ApplyAttributeFloat( CBaseEntity *pOuter, float flInitialValue, string_t iszAttribHook, CUtlVector<CBaseEntity *> *pItemList )
: m_pOuter( pOuter )
, m_flValue( flInitialValue )
, m_iszAttribHook( iszAttribHook )
, m_pItemList( pItemList )
{
Assert( pOuter );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
{
COMPILE_TIME_ASSERT( sizeof( value ) == sizeof( float ) );
Assert( pAttrDef );
if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
return true;
if ( m_pItemList && !m_pItemList->HasElement( m_pOuter ) )
{
m_pItemList->AddToTail( m_pOuter );
}
ApplyAttribute( pAttrDef, m_flValue, *reinterpret_cast<float *>( &value ) );
// We assume that each attribute can only be in the attribute list for a single item once, but we're
// iterating over attribute *classes* here, not unique attribute types, so we carry on looking.
return true;
}
float GetResultValue() const
{
return m_flValue;
}
private:
CBaseEntity *m_pOuter;
float m_flValue;
string_t m_iszAttribHook;
CUtlVector<CBaseEntity *> *m_pItemList;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CAttributeContainer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
{
if ( m_bPreventLoopback || !GetOuter() )
return flValue;
// We need to prevent loopback between two items both providing to the same entity.
m_bPreventLoopback = true;
// ...
CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
m_Item.IterateAttributes( &it );
m_bPreventLoopback = false;
return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
}
#ifndef DOTA_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CAttributeContainerPlayer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
{
if ( m_bPreventLoopback || !GetOuter() )
return flValue;
m_bPreventLoopback = true;
CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
CBasePlayer *pPlayer = GetPlayer();
if ( pPlayer )
{
pPlayer->m_AttributeList.IterateAttributes( &it );
}
m_bPreventLoopback = false;
return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemAttributeIterator_ApplyAttributeString : public CEconItemSpecificAttributeIterator
{
public:
CEconItemAttributeIterator_ApplyAttributeString( CBaseEntity *pOuter, string_t iszInitialValue, string_t iszAttribHook, CUtlVector<CBaseEntity *> *pItemList )
: m_pOuter( pOuter )
, m_iszValue( iszInitialValue )
, m_iszAttribHook( iszAttribHook )
, m_pItemList( pItemList )
, m_bFoundString( false )
{
Assert( pOuter );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
{
COMPILE_TIME_ASSERT( sizeof( value ) == sizeof( float ) );
// Do we want to process attribute of this type?
Assert( pAttrDef );
Assert( pAttrDef->GetCachedClass() != m_iszAttribHook );
//AssertMsg( 0, "OnIterateAttributeValue of type CAttribute_String, we shouldn't get here." );
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value )
{
Assert( pAttrDef );
if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
return true;
if ( FoundString() )
return true;
m_iszValue = AllocPooledString( value.value().c_str() );
m_bFoundString = true;
return true;
}
string_t GetResultValue()
{
return m_iszValue;
}
private:
bool FoundString()
{
// Implement something for the case where there's more than one of the same attribute
AssertMsg( !m_bFoundString, "Already found a string attribute with %s class, return the first attribute found.", STRING( m_iszAttribHook ) );
return m_bFoundString;
}
CBaseEntity *m_pOuter;
string_t m_iszValue;
string_t m_iszAttribHook;
CUtlVector<CBaseEntity *> *m_pItemList;
bool m_bFoundString;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
string_t CAttributeContainer::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
{
if ( m_bPreventLoopback || !GetOuter() )
return iszValue;
// We need to prevent loopback between two items both providing to the same entity.
m_bPreventLoopback = true;
// ...
CEconItemAttributeIterator_ApplyAttributeString it( GetOuter(), iszValue, iszAttribHook, pItemList );
m_Item.IterateAttributes( &it );
m_bPreventLoopback = false;
return BaseClass::ApplyAttributeString( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
}
string_t CAttributeContainerPlayer::ApplyAttributeString( string_t iszValue, CBaseEntity *pInitiator, string_t iszAttribHook /*= NULL_STRING*/, CUtlVector<CBaseEntity*> *pItemList /*= NULL*/ )
{
if ( m_bPreventLoopback || !GetOuter() )
return iszValue;
m_bPreventLoopback = true;
CEconItemAttributeIterator_ApplyAttributeString it( GetOuter(), iszValue, iszAttribHook, pItemList );
CBasePlayer *pPlayer = GetPlayer();
if ( pPlayer )
{
pPlayer->m_AttributeList.IterateAttributes( &it );
}
m_bPreventLoopback = false;
return BaseClass::ApplyAttributeString( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
}
+301
View File
@@ -0,0 +1,301 @@
//========= 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
+126
View File
@@ -0,0 +1,126 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Code for the CEconClaimCode object
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "econ_item_tools.h"
#include "econ_claimcode.h"
using namespace GCSDK;
#ifdef GC
IMPLEMENT_CLASS_MEMPOOL( CEconClaimCode, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool CEconClaimCode::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess )
{
CSchAssignedClaimCode schCode;
WriteToRecord( &schCode );
return CSchemaSharedObjectHelper::BYieldingAddInsertToTransaction( sqlAccess, &schCode );
}
void CEconClaimCode::WriteToRecord( CSchAssignedClaimCode *pClaimCode )
{
pClaimCode->m_unAccountID = Obj().account_id();
pClaimCode->m_unCodeType = Obj().code_type();
pClaimCode->m_rtime32TimeAcquired = Obj().time_acquired();
WRITE_VAR_CHAR_FIELD( *pClaimCode, VarCharCode, Obj().code().c_str() );
}
void CEconClaimCode::ReadFromRecord( const CSchAssignedClaimCode & code )
{
const char *pchCode = READ_VAR_CHAR_FIELD( code, m_VarCharCode );
Obj().set_code_type( code.m_unCodeType );
Obj().set_time_acquired( code.m_rtime32TimeAcquired );
Obj().set_code( pchCode );
}
bool BBuildRedemptionURL( CEconClaimCode *pClaimCode, CUtlString &redemptionURL )
{
const CEconItemDefinition *pItemDef = GEconManager()->GetItemSchema()->GetItemDefinition( pClaimCode->Obj().code_type() );
if ( pItemDef )
{
const char *pOriginalURL = pItemDef->GetDefinitionString( "redeem_url" );
const char *code = pClaimCode->Obj().code().c_str();
char url[1024];
if ( Q_StrSubst( pOriginalURL, "CLAIMCODE", code, url, sizeof( url ) ) )
{
redemptionURL = url;
return true;
}
}
return false;
}
// -----------------------------------------------------------------------------
// Purpose: Gets a summary of what's going on with the GC
// -----------------------------------------------------------------------------
class CJobWG_GetPromoCodes : public CGCGameBaseWGJob
{
public:
CJobWG_GetPromoCodes( CGCGameBase *pGC ) : CGCGameBaseWGJob( pGC ) {}
virtual bool BYieldingRunJobFromRequest( KeyValues *pkvRequest, KeyValues *pkvResponse );
private:
};
bool CJobWG_GetPromoCodes::BYieldingRunJobFromRequest( KeyValues *pkvRequest, KeyValues *pkvResponse )
{
CSteamID actorID( pkvRequest->GetUint64( "token/steamid" ) );
KeyValues *pkvPromoCodes = pkvResponse->FindKey( "promo_codes", true );
CSharedObjectCache *pSOCache = m_pGCGameBase->YieldingFindOrLoadSOCache( actorID );
if ( pSOCache == NULL )
return true;
CSharedObjectTypeCache *pTypeCache = pSOCache->FindBaseTypeCache( k_EEconTypeClaimCode );
if ( pTypeCache == NULL )
return true;
for ( uint32 i = 0; i < pTypeCache->GetCount(); ++i )
{
CEconClaimCode *pClaimCode = (CEconClaimCode*)pTypeCache->GetObject( i );
const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( pClaimCode->Obj().code_type() );
if ( pItemDef == NULL )
continue;
const CEconTool_ClaimCode *pEconClaimCodeTool = pItemDef->GetTypedEconTool<CEconTool_ClaimCode>();
if ( pEconClaimCodeTool == NULL )
continue;
const char *pClaimCodeName = pEconClaimCodeTool->GetClaimType();
if ( pClaimCodeName == NULL )
continue;
CUtlString claimURL;
if ( BBuildRedemptionURL( pClaimCode, claimURL ) == false )
{
SetErrorMessage( pkvResponse, CFmtStr( "Unable to construct redemption url for: %s", pClaimCodeName ), k_EResultFail );
continue;
}
const char *code = pClaimCode->Obj().code().c_str();
// finally populate the key values
KeyValues *pkvPromoCode = pkvPromoCodes->CreateNewKey();
pkvPromoCode->SetString( "code_name", pClaimCodeName );
pkvPromoCode->SetInt( "timestamp", pClaimCode->Obj().time_acquired() );
pkvPromoCode->SetString( "code", code );
pkvPromoCode->SetString( "redeem_url", claimURL.Get() );
}
return true;
}
DECLARE_GCWG_JOB( CGCEcon, CJobWG_GetPromoCodes, "GetPromoCodes", k_EGCWebApiPriv_Session )
END_DECLARE_GCWG_JOB( CJobWG_GetPromoCodes);
#endif
+40
View File
@@ -0,0 +1,40 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CEconClaimCode object
//
// $NoKeywords: $
//=============================================================================//
#ifndef ECON_CLAIMCODE_H
#define ECON_CLAIMCODE_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/protobufsharedobject.h"
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks for TF
//---------------------------------------------------------------------------------
class CEconClaimCode : public GCSDK::CProtoBufSharedObject< CSOEconClaimCode, k_EEconTypeClaimCode >
{
#ifdef GC
DECLARE_CLASS_MEMPOOL( CEconClaimCode );
#endif
public:
#ifdef GC
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
void WriteToRecord( CSchAssignedClaimCode *pClaimCode );
void ReadFromRecord( const CSchAssignedClaimCode & mapContribution );
#endif
};
#ifdef GC
bool BBuildRedemptionURL( CEconClaimCode *pClaimCode, CUtlString &redemptionURL );
#endif
#endif // ECON_CLAIMCODE_H
+64
View File
@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Code for the CTFMapContribution object
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "econ_contribution.h"
using namespace GCSDK;
#ifdef GC
IMPLEMENT_CLASS_MEMPOOL( CTFMapContribution, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool CTFMapContribution::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess )
{
CSchMapContribution schMapContribution;
WriteToRecord( &schMapContribution );
return CSchemaSharedObjectHelper::BYieldingAddInsertToTransaction( sqlAccess, &schMapContribution );
}
bool CTFMapContribution::BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields )
{
CSchMapContribution schMapContribution;
WriteToRecord( &schMapContribution );
CColumnSet csDatabaseDirty( schMapContribution.GetPSchema()->GetRecordInfo() );
csDatabaseDirty.MakeEmpty();
if ( fields.HasElement( CSOTFMapContribution::kContributionLevelFieldNumber ) )
{
csDatabaseDirty.BAddColumn( CSchMapContribution::k_iField_unContributionLevel );
}
return CSchemaSharedObjectHelper::BYieldingAddWriteToTransaction( sqlAccess, &schMapContribution, csDatabaseDirty );
}
bool CTFMapContribution::BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess )
{
CSchMapContribution schMapContribution;
WriteToRecord( &schMapContribution );
return CSchemaSharedObjectHelper::BYieldingAddRemoveToTransaction( sqlAccess, &schMapContribution );
}
void CTFMapContribution::WriteToRecord( CSchMapContribution *pMapContribution ) const
{
pMapContribution->m_unAccountID = Obj().account_id();
pMapContribution->m_unDefIndex = Obj().def_index();
pMapContribution->m_unContributionLevel = Obj().contribution_level();
}
void CTFMapContribution::ReadFromRecord( const CSchMapContribution & mapContribution )
{
Obj().set_account_id( mapContribution.m_unAccountID );
Obj().set_def_index( mapContribution.m_unDefIndex );
Obj().set_contribution_level( mapContribution.m_unContributionLevel );
}
#endif
+45
View File
@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CTFMapContribution object
//
// $NoKeywords: $
//=============================================================================//
#ifndef TFMAPCONTRIBUTION_H
#define TFMAPCONTRIBUTION_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/protobufsharedobject.h"
#include "tf_gcmessages.h"
namespace GCSDK
{
class CSQLAccess;
};
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks for TF
//---------------------------------------------------------------------------------
class CTFMapContribution : public GCSDK::CProtoBufSharedObject< CSOTFMapContribution, k_EEconTypeMapContribution >
{
#ifdef GC
DECLARE_CLASS_MEMPOOL( CTFMapContribution );
#endif
public:
CTFMapContribution() {}
#ifdef GC
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields );
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess );
void WriteToRecord( CSchMapContribution *pMapContribution ) const;
void ReadFromRecord( const CSchMapContribution & mapContribution );
#endif
};
#endif // TFMAPCONTRIBUTION_H
+250
View File
@@ -0,0 +1,250 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Functions related to dynamic recipes
//
//=============================================================================
#include "cbase.h"
#include "econ_dynamic_recipe.h"
#ifndef GC_DLL
#include "quest_objective_manager.h"
#endif
// This pattern was chosen to not be:
// - a valid string acceptable for user-input (ie., custom name)
// - a sensical float bit pattern
// - a common int bit pattern
// - meaningful Unicode data
const char *g_pszAttrEncodeSeparator = "|\x01\x02\x01\x03|\x01\x02\x01\x03|";
CRecipeComponentMatchingIterator::CRecipeComponentMatchingIterator( const IEconItemInterface *pSourceItem,
const IEconItemInterface *pTargetItem )
: m_pSourceItem( pSourceItem )
, m_pTargetItem( pTargetItem )
, m_bIgnoreCompleted( true )
, m_nInputsTotal( 0 )
, m_nInputsFulfilled( 0 )
, m_nOutputsTotal( 0 )
{}
bool CRecipeComponentMatchingIterator::OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value )
{
// Don't count ourselves as a match!
if ( m_pSourceItem && m_pTargetItem && m_pSourceItem->GetID() == m_pTargetItem->GetID() )
return true;
// If this isn't a match and the item isn't NULL, we skip. We consider NULL to mean
// that we want to tally ALL attributes of this type
if ( !DefinedItemAttribMatch( value, m_pTargetItem ) && m_pTargetItem != NULL )
return true;
// Dont let non-craftable items through
if ( m_pTargetItem && !m_pTargetItem->IsUsableInCrafting() )
return true;
// Is this an output?
if ( value.component_flags() & DYNAMIC_RECIPE_FLAG_IS_OUTPUT )
{
m_vecMatchingOutputs.AddToTail( pAttrDef );
m_nOutputsTotal += value.num_required();
}
else
{
m_vecMatchingInputs.AddToTail( pAttrDef );
m_nInputsTotal += value.num_required();
m_nInputsFulfilled += value.num_fulfilled();
}
return true;
}
bool DefinedItemAttribMatch( const CAttribute_DynamicRecipeComponent& attribValue, const IEconItemInterface* pItem )
{
if ( !pItem )
return false;
// If our fulfilled count is what our item count is, then we're done. We dont want any more matches.
if ( attribValue.num_fulfilled() == attribValue.num_required() )
return false;
// If the item_def flag is set, and the item's item_def doesnt match then not a match
if ( ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET ) &&
( attribValue.def_index() != (uint32)pItem->GetItemDefIndex() ) )
return false;
// If the quality flag is set, and the item's quality doesn't match, then not a match
if ( ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET ) &&
( attribValue.item_quality() != (uint32)pItem->GetQuality() ) )
return false;
// check if we have ALL required attributes
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ALL )
{
CUtlVector<CEconItem::attribute_t> vecAttribs;
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
{
AssertMsg2( 0, "%s: Unable to decode dynamic recipe attributes on item %llu", __FUNCTION__, pItem->GetID() );
return false;
}
FOR_EACH_VEC( vecAttribs, i )
{
const CEconItemAttributeDefinition *pAttr = GetItemSchema()->GetAttributeDefinition( vecAttribs[i].m_unDefinitionIndex );
Assert( pAttr );
uint32 itemAttributeValue;
if ( !pAttr || !pItem->FindAttribute( pAttr, &itemAttributeValue ) || itemAttributeValue != vecAttribs[i].m_value.asUint32 )
{
return false;
}
}
}
// check if we have ANY required attributes
else if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ANY )
{
CUtlVector<CEconItem::attribute_t> vecAttribs;
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
{
AssertMsg2( 0, "%s: Unable to decode dynamic recipe attributes on item %llu", __FUNCTION__, pItem->GetID() );
return false;
}
bool bHasAnyMatchingAttributes = false;
FOR_EACH_VEC( vecAttribs, i )
{
const CEconItemAttributeDefinition *pAttr = GetItemSchema()->GetAttributeDefinition( vecAttribs[i].m_unDefinitionIndex );
Assert( pAttr );
uint32 itemAttributeValue;
if ( pAttr && pItem->FindAttribute( pAttr, &itemAttributeValue ) && itemAttributeValue == vecAttribs[i].m_value.asUint32 )
{
bHasAnyMatchingAttributes = true;
break;
}
}
if ( !bHasAnyMatchingAttributes )
{
return false;
}
}
return true;
}
bool DecodeAttributeStringIntoAttributes( const CAttribute_DynamicRecipeComponent& attribValue, CUtlVector<CEconItem::attribute_t>& vecAttribs )
{
CUtlStringList vecAttributeStrings; // Automatically free'd
V_SplitString( attribValue.attributes_string().c_str(), g_pszAttrEncodeSeparator, vecAttributeStrings );
if( vecAttributeStrings.Count() % 2 != 0 )
{
AssertMsg1( 0, "%s: Uneven count of encoded attribute strings!", __FUNCTION__ );
return false;
}
for( int j = 0; j< vecAttributeStrings.Count(); j+=2 )
{
// Get the attribute definition that's stored in the string, and its type
attrib_definition_index_t index = Q_atoi( vecAttributeStrings[j] );
const CEconItemAttributeDefinition *pAttrDef = GEconItemSchema().GetAttributeDefinition( index );
if ( !pAttrDef )
{
#ifdef GC
EmitError( SPEW_GC, __FUNCTION__ ": Unable to find attribute definition '%s' (index %d)!\n", vecAttributeStrings[j], j );
#endif
return false;
}
CEconItem::attribute_t& attrib = vecAttribs[vecAttribs.AddToTail()];
attrib.m_unDefinitionIndex = pAttrDef->GetDefinitionIndex();
// Now have the attribute read in the value stored in the string
const ISchemaAttributeType* pAttrType = pAttrDef->GetAttributeType();
pAttrType->InitializeNewEconAttributeValue( &attrib.m_value );
// Don't fail us now!
const char* pszAttribValue = vecAttributeStrings[j+1];
if ( !pAttrType->BConvertStringToEconAttributeValue( pAttrDef, pszAttribValue, &attrib.m_value ) )
{
#ifdef GC
EmitError( SPEW_GC, __FUNCTION__ ": Unable to parse attribute value '%s' for attribute '%s'!\n", pszAttribValue, pAttrDef->GetDefinitionName() );
#endif
return false;
}
}
return true;
}
bool DecodeItemFromEncodedAttributeString( const CAttribute_DynamicRecipeComponent& attribValue, CEconItem* pItem )
{
// If the item_def flag is set, set that item def
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET )
{
pItem->SetDefinitionIndex( attribValue.def_index() );
}
else
{
// If the flag is not set, then we want the item name to be generic. In english, we want to just call it "item".
CAttribute_String attrStr;
attrStr.set_value( "#TF_ItemName_Item" );
static CSchemaAttributeDefHandle pAttrDef_ItemNameTextOverride( "item name text override" );
pItem->SetDynamicAttributeValue( pAttrDef_ItemNameTextOverride, attrStr );
}
// If the quality flag is set, take the quality
if ( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET )
{
pItem->SetQuality( attribValue.item_quality() );
// If there's no item def set and the quality specified is "unique", we want to be explicit
// and have the item description actually say "unique item" so there's no confusion as to what
// item quality we want as an input.
if ( !( attribValue.component_flags() & DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET )
&& pItem->GetQuality() == AE_UNIQUE )
{
CAttribute_String attrStr;
attrStr.set_value( "#unique" );
static CSchemaAttributeDefHandle pAttrDef_QualityTextOverride( "quality text override" );
pItem->SetDynamicAttributeValue( pAttrDef_QualityTextOverride, attrStr );
}
}
else
{
// If no quality was specified, we want to explicity say that we'll accept ANY quality.
pItem->SetQuality( AE_UNIQUE );
CAttribute_String attrStr;
attrStr.set_value( "#TF_QualityText_Any" );
static CSchemaAttributeDefHandle pAttrDef_QualityTextOverride( "quality text override" );
pItem->SetDynamicAttributeValue( pAttrDef_QualityTextOverride, attrStr );
}
pItem->SetFlags( 0 );
// Get all the attributes encoded into the attribute
CUtlVector<CEconItem::attribute_t> vecAttribs;
if( !DecodeAttributeStringIntoAttributes( attribValue, vecAttribs ) )
{
AssertMsg1( 0, " %s : Unable to decode dynamic recipe attributes", __FUNCTION__ );
return false;
}
// Apply the attributes to the item
FOR_EACH_VEC( vecAttribs, j )
{
// We don't expect to get here with any missing attributes.
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( vecAttribs[j].m_unDefinitionIndex );
Assert( pAttrDef );
const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
pAttrType->LoadEconAttributeValue( pItem, pAttrDef, vecAttribs[j].m_value );
// Free up our attribute memory now that we're done with it.
pAttrType->UnloadEconAttributeValue( &vecAttribs[j].m_value );
}
return true;
}
+76
View File
@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Functions related to dynamic recipes
//
//=============================================================================
#ifndef ECON_DYNAMIC_RECIPE
#define ECON_DYNAMIC_RECIPE
#ifdef _WIN32
#pragma once
#endif
#include "tf_gcmessages.h"
#include "game_item_schema.h"
#include "econ_item.h"
extern const char *g_pszAttrEncodeSeparator;
//-----------------------------------------------------------------------------
// Purpose: Stores off all CAttribute_DynamicRecipeComponent attributes
// that consider m_pTargetItem to be a match. If NULL is passed in for pTargetItem
// then we consider all attributes to be a match
//-----------------------------------------------------------------------------
class CRecipeComponentMatchingIterator : public CEconItemSpecificAttributeIterator
{
public:
CRecipeComponentMatchingIterator( const IEconItemInterface *pSourceItem,
const IEconItemInterface *pTargetItem );
void SetSourceItem( const IEconItemInterface *m_pSourceItem );
void SetTargetItem( const IEconItemInterface *pTargetItem );
void SetIgnoreCompleted( bool bIgnoreCompleted ) { m_bIgnoreCompleted = bIgnoreCompleted; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef,
const CAttribute_DynamicRecipeComponent& value ) OVERRIDE;
const CUtlVector< const CEconItemAttributeDefinition* >& GetMatchingComponentInputs() const { return m_vecMatchingInputs; }
const CUtlVector< const CEconItemAttributeDefinition* >& GetMatchingComponentOutputs() const { return m_vecMatchingOutputs; }
int GetTotalInputs() const { return m_nInputsTotal; }
int GetInputsFulfilled() const { return m_nInputsFulfilled; }
int GetTotalOutputs() const { return m_nOutputsTotal; }
private:
const IEconItemInterface *m_pSourceItem;
const IEconItemInterface *m_pTargetItem;
bool m_bIgnoreCompleted;
CUtlVector< const CEconItemAttributeDefinition* > m_vecMatchingInputs;
CUtlVector< const CEconItemAttributeDefinition* > m_vecMatchingOutputs;
int m_nInputsTotal;
int m_nInputsFulfilled;
int m_nOutputsTotal;
};
//-----------------------------------------------------------------------------
// Purpose: Given a CAttribute_DynamicRecipeComponent and a IEconItemInterface,
// returns whether the item pass the criteria of the attribute
//-----------------------------------------------------------------------------
bool DefinedItemAttribMatch( const CAttribute_DynamicRecipeComponent& attribValue, const IEconItemInterface* pItem );
//-----------------------------------------------------------------------------
// Purpose: Decodes the encoded attributes in attribValue and applies those attributes to pItem
// Returns true on success, false if anything fails
//-----------------------------------------------------------------------------
bool DecodeAttributeStringIntoAttributes( const CAttribute_DynamicRecipeComponent& attribValue, CUtlVector<CEconItem::attribute_t>& vecAttribs);
//-----------------------------------------------------------------------------
// Purpose: Decodes the encoded attributes in attribValue forms pItem into the
// item that it describes
//-----------------------------------------------------------------------------
bool DecodeItemFromEncodedAttributeString( const CAttribute_DynamicRecipeComponent& attribValue, CEconItem* pItem );
#endif //ECON_DYNAMIC_RECIPE
File diff suppressed because it is too large Load Diff
+229
View File
@@ -0,0 +1,229 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ECON_ENTITY_H
#define ECON_ENTITY_H
#ifdef _WIN32
#pragma once
#endif
#include "ihasattributes.h"
#include "ihasowner.h"
#include "attribute_manager.h"
#include "econ_item_view.h"
#if defined( CLIENT_DLL )
#define CEconEntity C_EconEntity
#define CBaseAttributableItem C_BaseAttributableItem
// Additional attachments.
struct AttachedModelData_t
{
const model_t *m_pModel;
int m_iModelDisplayFlags;
};
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconEntity : public CBaseAnimating, public IHasAttributes
{
DECLARE_CLASS( CEconEntity, CBaseAnimating );
public:
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
CEconEntity();
~CEconEntity();
void InitializeAttributes( void );
void DebugDescribe( void );
Activity TranslateViewmodelHandActivity( Activity actBase );
virtual void UpdateOnRemove( void );
virtual CStudioHdr * OnNewModel();
#if !defined( CLIENT_DLL )
virtual void GiveTo( CBaseEntity *pOther ) {}
void OnOwnerClassChange( void );
void UpdateModelToClass( void );
void PlayAnimForPlaybackEvent( wearableanimplayback_t iPlayback );
virtual int CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer );
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
void MarkAttachedEntityAsValidated() { m_bValidatedAttachedEntity = true; }
#endif // TF_DLL || TF_CLIENT_DLL
#else
enum ParticleSystemState_t
{
PARTICLE_SYSTEM_STATE_NOT_VISIBLE,
PARTICLE_SYSTEM_STATE_VISIBLE,
PARTICLE_SYSTEM_STATE_VISIBLE_VM
};
virtual void Release();
virtual void SetDormant( bool bDormant );
virtual void OnPreDataChanged( DataUpdateType_t type );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual bool ShouldShowToolTip( void ) { return true; }
virtual bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup );
virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo );
virtual IMaterial *GetEconWeaponMaterialOverride( int iTeam ) OVERRIDE;
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
bool InternalFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
// Custom flex controllers
virtual bool UsesFlexDelayedWeights( void );
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
float m_flFlexDelayTime;
float * m_flFlexDelayedWeight;
int m_cFlexDelayedWeight;
// Custom particle attachments
bool HasCustomParticleSystems( void ) const;
void UpdateParticleSystems( void );
virtual bool ShouldDrawParticleSystems( void );
void SetParticleSystemsVisible( ParticleSystemState_t bVisible );
void UpdateSingleParticleSystem( bool bVisible, const attachedparticlesystem_t *pSystem );
virtual void UpdateAttachmentModels( void );
virtual bool AttachmentModelsShouldBeVisible( void ) { return true; }
void GetEconParticleSystems( CUtlVector<const attachedparticlesystem_t *> *out_pvecParticleSystems ) const;
// Model swaping
bool ShouldDraw( void );
bool ShouldHideForVisionFilterFlags( void );
virtual bool IsTransparent( void ) OVERRIDE;
// Viewmodel overriding
virtual bool ViewModel_IsTransparent( void );
virtual bool ViewModel_IsUsingFBTexture( void );
virtual bool IsOverridingViewmodel( void );
virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags );
// Attachments
bool WantsToOverrideViewmodelAttachments( void ) { return (m_hViewmodelAttachment != NULL); }
virtual int LookupAttachment( const char *pAttachmentName );
virtual bool GetAttachment( const char *szName, Vector &absOrigin ) { return BaseClass::GetAttachment(szName,absOrigin); }
virtual bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ) { return BaseClass::GetAttachment(szName,absOrigin,absAngles); }
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
virtual bool GetAttachment( int number, Vector &origin );
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
C_BaseAnimating *GetViewmodelAttachment( void ) { return m_hViewmodelAttachment.Get(); }
virtual void ViewModelAttachmentBlending( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) {}
void SetWaitingToLoad( bool bWaiting );
virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry );
virtual void SetMaterialOverride( int team, const char *pszMaterial );
virtual void SetMaterialOverride( int team, CMaterialReference &ref );
// Deal with recording
virtual void GetToolRecordingState( KeyValues *msg );
#endif
public:
// IHasAttributes
CAttributeManager *GetAttributeManager( void ) { return &m_AttributeManager; }
CAttributeContainer *GetAttributeContainer( void ) { return &m_AttributeManager; }
const CAttributeContainer *GetAttributeContainer( void ) const { return &m_AttributeManager; }
CBaseEntity *GetAttributeOwner( void ) { return GetOwnerEntity(); }
CAttributeList *GetAttributeList( void ) { return m_AttributeManager.GetItem()->GetAttributeList(); }
virtual void ReapplyProvision( void );
virtual bool UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState );
protected:
virtual Activity TranslateViewmodelHandActivityInternal( Activity actBase ) { return actBase; }
protected:
CNetworkVarEmbedded( CAttributeContainer, m_AttributeManager );
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
CNetworkVar( bool, m_bValidatedAttachedEntity );
#endif // TF_DLL || TF_CLIENT_DLL
#ifdef CLIENT_DLL
bool m_bClientside;
ParticleSystemState_t m_nParticleSystemsCreated;
CMaterialReference m_MaterialOverrides[TEAM_VISUAL_SECTIONS];
CHandle<C_BaseAnimating> m_hViewmodelAttachment;
int m_iOldTeam;
bool m_bAttachmentDirty;
int m_nUnloadedModelIndex;
int m_iNumOwnerValidationRetries;
#endif
bool m_bHasParticleSystems;
EHANDLE m_hOldProvidee;
#ifdef GAME_DLL
int m_iOldOwnerClass; // Used to detect class changes on items that have per-class models
#endif
protected:
#ifdef CLIENT_DLL
public:
CUtlVector<AttachedModelData_t> m_vecAttachedModels;
#endif // CLIENT_DLL
};
#define ITEM_PICKUP_BOX_BLOAT 24
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CBaseAttributableItem : public CEconEntity
{
DECLARE_CLASS( CBaseAttributableItem, CEconEntity );
public:
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
CBaseAttributableItem();
};
#if defined( CLIENT_DLL )
#ifndef DOTA_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_ViewmodelAttachmentModel : public C_BaseAnimating, public IHasOwner
{
DECLARE_CLASS( C_ViewmodelAttachmentModel, C_BaseAnimating );
public:
void SetOuter( CEconEntity *pOuter );
CHandle<CEconEntity> GetOuter( void ) { return m_hOuter; }
bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup );
int InternalDrawModel( int flags );
bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo );
virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
virtual CBaseEntity *GetOwnerViaInterface( void ) { return GetOuter()->GetAttributeOwner(); }
virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld );
virtual int GetSkin( void );
private:
CHandle<CEconEntity> m_hOuter;
bool m_bAlwaysFlip;
};
#endif // !defined( DOTA_DLL )
#endif // defined( CLIENT_DLL )
#endif // ECON_ENTITY_H
+180
View File
@@ -0,0 +1,180 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "econ_entity_creation.h"
#include "utldict.h"
#include "filesystem.h"
#include "gamestringpool.h"
#include "KeyValues.h"
#include "attribute_manager.h"
#include "vgui/ILocalize.h"
#include "tier3/tier3.h"
#include "util_shared.h"
#ifdef TF_CLIENT_DLL
#include "c_tf_player.h"
#endif // TF_CLIENT_DLL
//==================================================================================
// GENERATION SYSTEM
//==================================================================================
CItemGeneration g_ItemGenerationSystem;
CItemGeneration *ItemGeneration( void )
{
return &g_ItemGenerationSystem;
}
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CItemGeneration::CItemGeneration( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Generate a random item matching the specified criteria
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::GenerateRandomItem( CItemSelectionCriteria *pCriteria, const Vector &vecOrigin, const QAngle &vecAngles )
{
entityquality_t iQuality;
int iChosenItem = ItemSystem()->GenerateRandomItem( pCriteria, &iQuality );
if ( iChosenItem == INVALID_ITEM_DEF_INDEX )
return NULL;
return SpawnItem( iChosenItem, vecOrigin, vecAngles, pCriteria->GetItemLevel(), iQuality, NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Generate a random item matching the specified definition index
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::GenerateItemFromDefIndex( int iDefIndex, const Vector &vecOrigin, const QAngle &vecAngles )
{
return SpawnItem( iDefIndex, vecOrigin, vecAngles, 1, AE_UNIQUE, NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Generate an item from the specified item data
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::GenerateItemFromScriptData( const CEconItemView *pData, const Vector &vecOrigin, const QAngle &vecAngles, const char *pszOverrideClassName )
{
return SpawnItem( pData, vecOrigin, vecAngles, pszOverrideClassName );
}
//-----------------------------------------------------------------------------
// Purpose: Generate the base item for a class's loadout slot
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::GenerateBaseItem( struct baseitemcriteria_t *pCriteria )
{
int iChosenItem = ItemSystem()->GenerateBaseItem( pCriteria );
if ( iChosenItem == INVALID_ITEM_DEF_INDEX )
return NULL;
return SpawnItem( iChosenItem, vec3_origin, vec3_angle, 1, AE_NORMAL, NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Create a new instance of the chosen item
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::SpawnItem( int iChosenItem, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, int iItemLevel, entityquality_t entityQuality, const char *pszOverrideClassName )
{
CEconItemDefinition *pData = ItemSystem()->GetStaticDataForItemByDefIndex( iChosenItem );
if ( !pData )
return NULL;
if ( !pszOverrideClassName )
{
pszOverrideClassName = pData->GetItemClass();
}
if ( !pszOverrideClassName )
return NULL;
CBaseEntity *pItem = CreateEntityByName( pszOverrideClassName );
if ( !pItem )
return NULL;
// Set the item level & quality
IHasAttributes *pItemInterface = GetAttribInterface( pItem );
Assert( pItemInterface );
if ( pItemInterface )
{
// Setup the script item. Don't generate attributes here, because it'll be done during entity spawn.
CEconItemView *pScriptItem = pItemInterface->GetAttributeContainer()->GetItem();
pScriptItem->Init( iChosenItem, entityQuality, iItemLevel, false );
}
return PostSpawnItem( pItem, pItemInterface, vecAbsOrigin, vecAbsAngles );
}
//-----------------------------------------------------------------------------
// Purpose: Create a base entity for the specified item data
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::SpawnItem( const CEconItemView *pData, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, const char *pszOverrideClassName )
{
if ( !pData->GetStaticData() )
return NULL;
if ( !pszOverrideClassName )
{
pszOverrideClassName = pData->GetStaticData()->GetItemClass();
}
if ( !pszOverrideClassName )
return NULL;
CBaseEntity *pItem = CreateEntityByName( pszOverrideClassName );
if ( !pItem )
return NULL;
// Set the item level & quality
IHasAttributes *pItemInterface = GetAttribInterface( pItem );
Assert( pItemInterface );
if ( pItemInterface )
{
pItemInterface->GetAttributeContainer()->SetItem( pData );
}
return PostSpawnItem( pItem, pItemInterface, vecAbsOrigin, vecAbsAngles );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseEntity *CItemGeneration::PostSpawnItem( CBaseEntity *pItem, IHasAttributes *pItemInterface, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles )
{
#ifdef CLIENT_DLL
const char *pszPlayerModel = NULL;
if ( pItemInterface )
{
CEconItemView *pScriptItem = pItemInterface->GetAttributeContainer()->GetItem();
int iClass = 0;
int iTeam = 0;
#ifdef TF_CLIENT_DLL
C_TFPlayer *pTFPlayer = ToTFPlayer( GetPlayerByAccountID( pScriptItem->GetAccountID() ) );
if ( pTFPlayer )
{
iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
iTeam = pTFPlayer->GetTeamNumber();
}
#endif // TF_CLIENT_DLL
pszPlayerModel = pScriptItem->GetPlayerDisplayModel( iClass, iTeam );
}
// If we create a clientside item, we need to force it to initialize attributes
if ( pItem->InitializeAsClientEntity( pszPlayerModel, RENDER_GROUP_OPAQUE_ENTITY ) == false )
return NULL;
#endif // CLIENT_DLL
pItem->SetAbsOrigin( vecAbsOrigin );
pItem->SetAbsAngles( vecAbsAngles );
pItem->Spawn();
pItem->Activate();
return pItem;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ITEM_CREATION_H
#define ITEM_CREATION_H
#ifdef _WIN32
#pragma once
#endif
#include "igamesystem.h"
#include "econ_item_system.h"
#include "econ_entity.h"
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
#include "tf_shareddefs.h"
#endif
//-----------------------------------------------------------------------------
// Purpose: Game system that handles initializing the item system, and generating items as full game entities
//-----------------------------------------------------------------------------
class CItemGeneration : public CAutoGameSystem
{
public:
CItemGeneration( void );
// Generate a random item matching the specified criteria
CBaseEntity *GenerateRandomItem( CItemSelectionCriteria *pCriteria, const Vector &vecOrigin, const QAngle &vecAngles );
// Generate a random item matching the specified definition index
CBaseEntity *GenerateItemFromDefIndex( int iDefIndex, const Vector &vecOrigin, const QAngle &vecAngles );
// Generate an item from the specified item data
CBaseEntity *GenerateItemFromScriptData( const CEconItemView *pData, const Vector &vecOrigin, const QAngle &vecAngles, const char *pszOverrideClassName );
// Generate the base item for a class's loadout slot
CBaseEntity *GenerateBaseItem( struct baseitemcriteria_t *pCriteria );
private:
// Create a new instance of the chosen item
CBaseEntity *SpawnItem( int iChosenItem, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, int iItemLevel, entityquality_t entityQuality, const char *pszOverrideClassName );
CBaseEntity *SpawnItem( const CEconItemView *pData, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles, const char *pszOverrideClassName );
CBaseEntity *PostSpawnItem( CBaseEntity *pItem, IHasAttributes *pItemInterface, const Vector &vecAbsOrigin, const QAngle &vecAbsAngles );
};
extern CItemGeneration *ItemGeneration( void );
#endif // ITEM_CREATION_H
+19
View File
@@ -0,0 +1,19 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "econ_experiment.h"
using namespace GCSDK;
#ifdef GC_DLL
IMPLEMENT_CLASS_MEMPOOL( CEconExperiment, 10 * 10000, UTLMEMORYPOOL_GROW_SLOW );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
+27
View File
@@ -0,0 +1,27 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CEconExperiment
//
// $NoKeywords: $
//=============================================================================//
#ifndef TFEXPERIMENT_H
#define TFEXPERIMENT_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/schemasharedobject.h"
//---------------------------------------------------------------------------------
// Purpose:
//---------------------------------------------------------------------------------
class CEconExperiment : public GCSDK::CSchemaSharedObject< CSchExperiment, k_EEconTypeExperiment >
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconExperiment );
#endif
};
#endif // TFEXPERIMENT_H
+17
View File
@@ -0,0 +1,17 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Code for the CEconGameAccount object
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
using namespace GCSDK;
#ifdef GC_DLL
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccount, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
+57
View File
@@ -0,0 +1,57 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CEconGameAccount object
//
// $NoKeywords: $
//=============================================================================//
#ifndef ECON_GAME_ACCOUNT_H
#define ECON_GAME_ACCOUNT_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/schemasharedobject.h"
#include "rtime.h"
enum
{
kGameAccountFlags_ConvertedUniques = 1 << 0,
kGameAccountFlags_MadeFirstPurchase = 1 << 1,
kGameAccountFlags_ConvertItemFlagsToOrigin = 1 << 2,
kGameAccountFlags_ConvertPackageItemGrants = 1 << 3,
kGameAccountFlags_RemoveCafeOrSchoolItems = 1 << 4,
kGameAccountFlags_CleanupItemNames = 1 << 5,
kGameAccountFlags_NeedToChooseMostHelpfulFriend = 1 << 6,
kGameAccountFlags_DONT_USE_THIS_BUI_LIES = 1 << 7, // some accounts might have this set! it used to be the "needs to thank a friend" bit
kGameAccountFlags_OwnedGameServersDisabled = 1 << 8,
kGameAccountFlags_UpdatedEquippedSlots = 1 << 9,
kGameAccountFlags_MadeFirstWebPurchase = 1 << 10,
kGameAccountFlags_UpdatedPresetOriginalItemIDs = 1 << 11,
kGameAccountFlags_GC_UpgradedToPremium = 1 << 12, // we did something (used an item, whatever) on the GC that means the GC has decided we're premium regardless of what Steam says
// Deprecated
// kGameAccountFlags_InitializedSkillRating = 1 << 13,
// kGameAccountFlags_InitializedSkillRating6v6 = 1 << 14,
// kGameAccountFlags_InitializedSkillRating9v9 = 1 << 15,
kGameAccountFlags_InitializedKickBucket = 1 << 16,
};
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks
//---------------------------------------------------------------------------------
class CEconGameAccount : public GCSDK::CSchemaSharedObject< CSchGameAccount, k_EEconTypeGameAccount >
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconGameAccount );
#endif
public:
CEconGameAccount() {}
CEconGameAccount( uint32 unAccountID )
{
Obj().m_unAccountID = unAccountID;
Obj().m_rtime32FirstPlayed = CRTime::RTime32TimeCur();
}
};
#endif //ECON_GAME_ACCOUNT_H
@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Code for the CEconGameAccountClient object
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
using namespace GCSDK;
#ifdef GC
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccountClient, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@@ -0,0 +1,29 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CEconGameAccountClient object
//
// $NoKeywords: $
//=============================================================================//
#ifndef ECON_GAME_ACCOUNT_CLIENT_H
#define ECON_GAME_ACCOUNT_CLIENT_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/protobufsharedobject.h"
#include "base_gcmessages.pb.h"
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks
//---------------------------------------------------------------------------------
class CEconGameAccountClient : public GCSDK::CProtoBufSharedObject< CSOEconGameAccountClient, k_EEconTypeGameAccountClient >
{
#ifdef GC
DECLARE_CLASS_MEMPOOL( CEconGameAccountClient );
public:
virtual bool BIsDatabaseBacked() const { return false; }
#endif
};
#endif //ECON_GAME_ACCOUNT_CLIENT_H
@@ -0,0 +1,40 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Code for the CEconGameAccount object
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "econ_game_account_server.h"
using namespace GCSDK;
#ifdef GC_DLL
//---------------------------------------------------------------------------------
// Purpose:
//---------------------------------------------------------------------------------
IMPLEMENT_CLASS_MEMPOOL( CEconGameServerAccount, 100, UTLMEMORYPOOL_GROW_SLOW );
void GameServerAccount_GenerateIdentityToken( char* pIdentityToken, uint32 unMaxChars )
{
static const char s_ValidChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./+!$%^-_+?<>()&~:";
const int nLastValidIndex = ARRAYSIZE(s_ValidChars) - 2; // last = size - 1, minus another one for null terminator
// create a randomized token
for ( uint32 i = 0; i < unMaxChars - 1; ++i )
{
pIdentityToken[i] = s_ValidChars[ RandomInt( 0, nLastValidIndex ) ];
}
pIdentityToken[unMaxChars - 1] = 0;
}
//---------------------------------------------------------------------------------
// Purpose: Selective account-level data for game servers
//---------------------------------------------------------------------------------
IMPLEMENT_CLASS_MEMPOOL( CEconGameAccountForGameServers, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
+110
View File
@@ -0,0 +1,110 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CEconGameServerAccount object
//
// $NoKeywords: $
//=============================================================================//
#ifndef ECON_GAME_SERVER_ACCOUNT_H
#define ECON_GAME_SERVER_ACCOUNT_H
#ifdef _WIN32
#pragma once
#endif
enum eGameServerOrigin
{
kGSAOrigin_Player = 0,
kGSAOrigin_Support = 1,
kGSAOrigin_AutoRegister = 2, // for valve-owned servers
};
enum eGameServerScoreStanding
{
kGSStanding_Good,
kGSStanding_Bad,
};
enum eGameServerScoreStandingTrend
{
kGSStandingTrend_Up,
kGSStandingTrend_SteadyUp,
kGSStandingTrend_Steady,
kGSStandingTrend_SteadyDown,
kGSStandingTrend_Down,
};
#ifdef GC
#include "gcsdk/schemasharedobject.h"
//---------------------------------------------------------------------------------
// Purpose:
//---------------------------------------------------------------------------------
class CEconGameServerAccount : public GCSDK::CSchemaSharedObject< CSchGameServerAccount, k_EEconTypeGameServerAccount >
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconGameServerAccount );
#endif
public:
CEconGameServerAccount() {}
CEconGameServerAccount( uint32 unAccountID )
{
Obj().m_unAccountID = unAccountID;
}
};
void GameServerAccount_GenerateIdentityToken( char* pIdentityToken, uint32 unMaxChars );
#endif // GC
inline const char *GameServerAccount_GetStandingString( eGameServerScoreStanding standing )
{
const char *pStanding = "Good";
switch ( standing )
{
case kGSStanding_Good:
pStanding = "Good";
break;
case kGSStanding_Bad:
pStanding = "Bad";
break;
} // switch
return pStanding;
}
inline const char *GameServerAccount_GetStandingTrendString( eGameServerScoreStandingTrend trend )
{
const char *pStandingTrend = "Steady";
switch ( trend )
{
case kGSStandingTrend_Up:
pStandingTrend = "Upward Fast";
break;
case kGSStandingTrend_SteadyUp:
pStandingTrend = "Slightly Upward";
break;
case kGSStandingTrend_Steady:
pStandingTrend = "Steady";
break;
case kGSStandingTrend_SteadyDown:
pStandingTrend = "Slightly Downward";
break;
case kGSStandingTrend_Down:
pStandingTrend = "Downward Fast";
break;
} // switch
return pStandingTrend;
}
//---------------------------------------------------------------------------------
// Purpose: Selective account-level data for game servers
//---------------------------------------------------------------------------------
class CEconGameAccountForGameServers : public GCSDK::CProtoBufSharedObject < CSOEconGameAccountForGameServers, k_EEconTypeGameAccountForGameServers >
{
#ifdef GC
DECLARE_CLASS_MEMPOOL( CEconGameAccountForGameServers );
public:
virtual bool BIsDatabaseBacked() const { return false; }
#endif
};
#endif //ECON_GAME_SERVER_ACCOUNT_H
+345
View File
@@ -0,0 +1,345 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file defines all of our over-the-wire net protocols for the
// Game Coordinator for the item system. Note that we never use types
// with undefined length (like int). Always use an explicit type
// (like int32).
//
//=============================================================================
#ifndef ITEM_GCMESSAGES_H
#define ITEM_GCMESSAGES_H
#ifdef _WIN32
#pragma once
#endif
#include "econ_gcmessages.pb.h"
#pragma pack( push, 1 )
// generic zero-length message struct
struct MsgGCEmpty_t
{
};
// k_EMsgGCSetItemPosition
struct MsgGCSetItemPosition_t
{
uint64 m_unItemID;
uint32 m_unNewPosition;
};
// k_EMsgGCCraft
struct MsgGCCraft_t
{
int16 m_nRecipeDefIndex;
uint16 m_nItemCount;
// list of m_nItemCount uint64 item IDs
};
// k_EMsgGCDelete
struct MsgGCDelete_t
{
uint64 m_unItemID;
};
// k_EMsgGCCraftResponse
struct MsgGCStandardResponse_t
{
int16 m_nResponseIndex;
uint32 m_eResponse;
};
// k_EMsgGCVerifyCacheSubscription
struct MsgGCVerifyCacheSubscription_t
{
uint64 m_ulSteamID;
};
// k_EMsgGCNameItem
struct MsgGCNameItem_t
{
uint64 m_unToolItemID; // the Nametag item
uint64 m_unSubjectItemID; // the item to be renamed
bool m_bDescription;
// Varchar: Item name
};
// k_EMsgGCNameBaseItem
struct MsgGCNameBaseItem_t
{
uint64 m_unToolItemID; // the Nametag item
uint32 m_unBaseItemDefinitionID; // the base item definition to be renamed
bool m_bDescription;
// Varchar: Item name
};
// k_EMsgGCUnlockCrate
struct MsgGCUnlockCrate_t
{
uint64 m_unToolItemID; // the crate key
uint64 m_unSubjectItemID; // the crate to be decoded
};
// k_EMsgGCPaintItem
struct MsgGCPaintItem_t
{
uint64 m_unToolItemID; // the Paint Can item
uint64 m_unSubjectItemID; // the item to be painted
};
// k_EMsgGCGiftWrapItem
struct MsgGCGiftWrapItem_t
{
uint64 m_unToolItemID; // the Gift Wrap item
uint64 m_unSubjectItemID; // the item to be wrapped
};
// k_EMsgGCDeliverGift
struct MsgGCDeliverGift_t
{
uint64 m_unGiftID;
uint64 m_ulGiverSteamID;
uint64 m_ulTargetSteamID;
};
// k_EMsgGCUnwrapGiftRequest
struct MsgGCUnwrapGiftRequest_t
{
uint64 m_unItemID;
};
// k_EMsgGCMOTDRequest
struct MsgGCMOTDRequest_t
{
RTime32 m_nLastMOTDRequest; // Time at which the client last asked for MOTDs. GC will send back all MOTDs posted since.
int16 m_eLanguage;
};
// k_EMsgGCMOTDRequestResponse
struct MsgGCMOTDRequestResponse_t
{
int16 m_nEntries;
};
// k_EMsgGCCustomizeItemTexture
struct MsgGCCustomizeItemTexture_t
{
uint64 m_unToolItemID; // the tool
uint64 m_unSubjectItemID; // the item wants the texture
uint64 m_unImageUGCHandle; // cloud ID of image file (UGCHandle_t)
};
// k_EMsgGCSetItemStyle
struct MsgGCSetItemStyle_t
{
uint64 m_unItemID;
uint8 m_iStyle;
};
// k_EMsgGCItemPreviewCheckStatus
struct MsgGCCheckItemPreviewStatus_t
{
uint32 m_unItemDefIndex;
};
// k_EMsgGCItemPreviewCheckStatusResponse
struct MsgGCItemPreviewCheckStatusResponse_t
{
uint32 m_unItemDefIndex;
uint32 m_eResponse;
RTime32 m_timePreviewTime;
};
// k_EMsgGCItemPreviewRequest
struct MsgGCItemPreviewRequest_t
{
uint32 m_unItemDefIndex;
};
// k_EMsgGCItemPreviewRequestResponse
struct MsgGCItemPreviewRequestResponse_t
{
uint32 m_unItemDefIndex;
uint32 m_eResponse;
};
// k_EMsgGCItemPreviewExpire
struct MsgGCItemPreviewExpire_t
{
};
// k_EMsgGCItemPreviewExpireNotification
struct MsgGCItemPreviewExpireNotification_t
{
uint32 m_unItemDefIndex;
};
//-----------------------------------------------------------------------------
// k_EMsgGCUseItemResponse
enum EGCMsgUseItemResponse
{
k_EGCMsgUseItemResponse_ItemUsed = 0,
k_EGCMsgUseItemResponse_GiftNoOtherPlayers = 1,
k_EGCMsgUseItemResponse_ServerError = 2,
k_EGCMsgUseItemResponse_MiniGameAlreadyStarted = 3,
k_EGCMsgUseItemResponse_ItemUsed_ItemsGranted = 4,
k_EGCMsgUseItemResponse_CannotBeUsedByAccount = 5,
k_EGCMsgUseItemResponse_ForceSizeInt = 0x7FFFFFFF
};
// k_EMsgGCUseItemResponse
struct MsgGCUseItemResponse_t
{
uint32 m_eResponse;
};
// k_EMsgGCSpawnItem
struct MsgGCSpawnItem_t
{
uint64 m_ulInitiatorSteamID;
uint32 m_unItemDefinitionID;
// other data dynamically added:
// string of initiator name
};
// k_EMsgGCRespawnPostLoadoutChange
struct MsgGCRespawnPostLoadoutChange_t
{
uint64 m_ulInitiatorSteamID;
};
// k_EMsgGCRemoveItemName
struct MsgGCRemoveItemName_t
{
uint64 m_unItemID;
bool m_bDescription;
};
//-----------------------------------------------------------------------------
// Trading
// k_EMsgGCTrading_InitiateTradeRequest
struct MsgGCTrading_InitiateTradeRequest_t
{
uint32 m_unTradeRequestID;
uint64 m_ulOtherSteamID;
// @note player A's name as string when sent to party B
};
enum EGCMsgInitiateTradeResponse
{
k_EGCMsgInitiateTradeResponse_Accepted = 0,
k_EGCMsgInitiateTradeResponse_Declined = 1,
k_EGCMsgInitiateTradeResponse_VAC_Banned_Initiator = 2,
k_EGCMsgInitiateTradeResponse_VAC_Banned_Target = 3,
k_EGCMsgInitiateTradeResponse_Target_Already_Trading = 4,
k_EGCMsgInitiateTradeResponse_Disabled = 5,
k_EGCMsgInitiateTradeResponse_NotLoggedIn = 6,
k_EGCMsgInitiateTradeResponse_Cancel = 7,
k_EGCMsgInitiateTradeResponse_TooSoon = 8,
k_EGCMsgInitiateTradeResponse_TooSoonPenalty = 9,
k_EGCMsgInitiateTradeResponse_Trade_Banned_Initiator = 10,
k_EGCMsgInitiateTradeResponse_Trade_Banned_Target = 11,
k_EGCMsgInitiateTradeResponse_Free_Account_Initiator_DEPRECATED = 12, // free accounts can initiate trades now
k_EGCMsgInitiateTradeResponse_Shared_Account_Initiator= 13,
k_EGCMsgInitiateTradeResponse_Service_Unavailable = 14,
k_EGCMsgInitiateTradeResponse_Target_Blocked = 15,
k_EGCMsgInitiateTradeResponse_NeedVerifiedEmail = 16,
k_EGCMsgInitiateTradeResponse_NeedSteamGuard = 17,
k_EGCMsgInitiateTradeResponse_SteamGuardDuration = 18,
k_EGCMsgInitiateTradeResponse_TheyCannotTrade = 19,
k_EGCMsgInitiateTradeResponse_Recent_Password_Reset = 20,
k_EGCMsgInitiateTradeResponse_Using_New_Device = 21,
k_EGCMsgInitiateTradeResponse_Sent_Invalid_Cookie = 22,
k_EGCMsgInitiateTradeResponse_Count,
k_EGCMsgInitiateTradeResponse_ForceSizeInt = 0x7FFFFFFF
};
// k_EMsgGCTrading_InitiateTradeResponse
struct MsgGCTrading_InitiateTradeResponse_t
{
uint32 m_eResponse;
uint32 m_unTradeRequestID;
};
// k_EMsgGCTrading_StartSession
struct MsgGCTrading_StartSession_t
{
uint32 m_unSessionVersion;
uint64 m_ulSteamIDPartyA;
uint64 m_ulSteamIDPartyB;
// @note strings from player names will be added to the message
};
// k_EMsgGCTrading_CancelSession
struct MsgGCTrading_CancelSession_t
{
};
// k_EMsgGCUsedClaimCodeItem
struct MsgGCUsedClaimCodeItem_t
{
// string of URL
};
//-----------------------------------------------------------------------------
// ServerBrowser messages
enum EGCMsgServerBrowser
{
k_EGCMsgServerBrowser_FromServerBrowser = 0,
k_EGCMsgServerBrowser_FromAutoAskDialog = 1,
};
// k_EMsgGCServerBrowser_FavoriteServer
// k_EMsgGCServerBrowser_BlacklistServer
struct MsgGCServerBrowser_Server_t
{
uint32 m_unIP;
int m_usPort;
uint8 m_ubSource; // 0=serverbrowser, 1=auto-ask dialog
};
//-----------------------------------------------------------------------------
// Public facing loot lists.
// k_EMsgGC_RevolvingLootList
struct MsgGC_RevolvingLootList_t
{
uint8 m_usListID; // Id of this list.
// Var Data:
// Serialized Lootlist KV
};
// k_EMsgGCLookupAccount
struct MsgGCLookupAccount_t
{
uint16 m_uiFindType;
// Var Data
// string containing Persona / URL / etc
};
// k_EMsgGCLookupAccountName
struct MsgGCLookupAccountName_t
{
uint32 m_unAccountID;
};
// k_EMsgGCLookupAccountNameResponse
struct MsgGCLookupAccountNameResponse_t
{
uint32 m_unAccountID;
// string containing persona name
};
#pragma pack( pop )
#endif
+644
View File
@@ -0,0 +1,644 @@
//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
//
// Purpose: The file defines our Google Protocol Buffers which are used in over
// the wire messages between servers as well as between the TF GC and TF gameservers
// and clients.
//
//=============================================================================
// We care more about speed than code size
option optimize_for = SPEED;
// We don't use the service generation functionality
option cc_generic_services = false;
//
// STYLE NOTES:
//
// Use CamelCase CMsgMyMessageName style names for messages.
//
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
// but plays nice with the Google formatted code generation.
//
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
// your message and wants to remove or rename fields.
//
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
// than 2^56 as it will safe space on the wire in those cases.
//
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
// 2^28. It will save space in those cases, otherwise use int32 which will safe space for smaller values.
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
// time.
//
import "steammessages.proto";
enum EGCItemMsg
{
k_EMsgGCBase = 1000;
k_EMsgGCSetSingleItemPosition = 1001; // uses old-school struct for a single item. Prefer k_EMsgGCSetItemPositions
k_EMsgGCCraft = 1002;
k_EMsgGCCraftResponse = 1003;
k_EMsgGCDelete = 1004;
k_EMsgGCVerifyCacheSubscription = 1005; // sent by gameservers who don't have a cache they expect
k_EMsgGCNameItem = 1006;
k_EMsgGCUnlockCrate = 1007; // used by decoder rings to unlock supply crates
k_EMsgGCUnlockCrateResponse = 1008;
k_EMsgGCPaintItem = 1009; // used by paint cans to paint items
k_EMsgGCPaintItemResponse = 1010;
k_EMsgGCGoldenWrenchBroadcast = 1011; // sent to all users when a Golden Wrench is crafted or deleted
k_EMsgGCMOTDRequest = 1012; // client is asking for a set of MOTDs
k_EMsgGCMOTDRequestResponse = 1013;
// k_EMsgGCAddItemToSocket_DEPRECATED = 1014;
// k_EMsgGCAddItemToSocketResponse_DEPRECATED = 1015;
// k_EMsgGCAddSocketToBaseItem_DEPRECATED = 1016;
// k_EMsgGCAddSocketToItem_DEPRECATED = 1017;
// k_EMsgGCAddSocketToItemResponse_DEPRECATED = 1018;
k_EMsgGCNameBaseItem = 1019;
k_EMsgGCNameBaseItemResponse = 1020;
k_EMsgGCRemoveSocketItem_DEPRECATED = 1021;
k_EMsgGCRemoveSocketItemResponse_DEPRECATED = 1022;
k_EMsgGCCustomizeItemTexture = 1023;
k_EMsgGCCustomizeItemTextureResponse = 1024;
k_EMsgGCUseItemRequest = 1025; // client/game server => GC
k_EMsgGCUseItemResponse = 1026; // GC => client/game server
// k_EMsgGCSpawnItem_DEPRECATED = 1028; // GC => game server
k_EMsgGCRespawnPostLoadoutChange = 1029; // client => GC => game server
k_EMsgGCRemoveItemName = 1030; // client => GC
k_EMsgGCRemoveItemPaint = 1031; // client => GC
k_EMsgGCGiftWrapItem = 1032; // client => GC (the player requests an item to be gift wrapped)
k_EMsgGCGiftWrapItemResponse = 1033; // GC => client (confirmation that an item was gift wrapped)
k_EMsgGCDeliverGift = 1034;
k_EMsgGCDeliverGiftResponseReceiver = 1036;
k_EMsgGCUnwrapGiftRequest = 1037;
k_EMsgGCUnwrapGiftResponse = 1038;
k_EMsgGCSetItemStyle = 1039;
k_EMsgGCUsedClaimCodeItem = 1040;
k_EMsgGCSortItems = 1041;
k_EMsgGC_RevolvingLootList_DEPRECATED= 1042; // GC => client; revolving loot list
k_EMsgGCLookupAccount = 1043; // client is requesting a lookup of an account
k_EMsgGCLookupAccountResponse = 1044;
k_EMsgGCLookupAccountName = 1045; // old-school struct for single account. client is requesting a lookup of an account name
k_EMsgGCLookupAccountNameResponse = 1046;
//k_EMsgGCStartupCheck = 1047; // GC => client
//k_EMsgGCStartupCheckResponse = 1048; // client => GC
k_EMsgGCUpdateItemSchema = 1049; // GC => client
k_EMsgGCRequestInventoryRefresh = 1050; // client => GC
k_EMsgGCRemoveCustomTexture = 1051; // client => GC
k_EMsgGCRemoveCustomTextureResponse = 1052; // GC => client
k_EMsgGCRemoveMakersMark = 1053; // client => GC
k_EMsgGCRemoveMakersMarkResponse = 1054; // GC => client
k_EMsgGCRemoveUniqueCraftIndex = 1055; // client => GC
k_EMsgGCRemoveUniqueCraftIndexResponse = 1056; // GC => client
k_EMsgGCSaxxyBroadcast = 1057; // sent to all users when a Saxxy is deleted
k_EMsgGCBackpackSortFinished = 1058; // GC => client
k_EMsgGCAdjustItemEquippedState = 1059; // GC => client
// k_EMsgGCRequestItemSchemaData_DEPRECATED = 1060; // client => GC Should only be used in dev universe
k_EMsgGCCollectItem = 1061;
k_EMsgGCItemAcknowledged = 1062; // sent to a dedicated server when a client acknowledges an item
// item presets
k_EMsgGCPresets_SelectPresetForClass = 1063; // client => GC
k_EMsgGCPresets_SetItemPosition = 1064; // client => GC
// Abuse reporting
k_EMsgGC_ReportAbuse = 1065; // client => GC
k_EMsgGC_ReportAbuseResponse = 1066; // GC => client
// more item presets
k_EMsgGCPresets_SelectPresetForClassReply = 1067; // GC => client
// item naming broadcast
k_EMsgGCNameItemNotification = 1068; // GC => client
// !FIXME! DOTAMERGE
// these messages are particular to DOTA, or
// conflict with corresponding TF messages
//
// k_EMsgGCGiftedItems = 1027; // GC => game server
// k_EMsgGCDeliverGiftResponseGiver = 1035;
//
// k_EMsgGCApplyConsumableEffects = 1069;
//
// k_EMsgGCConsumableExhausted = 1070;
// k_EMsgGCApplyStrangePart = 1073; // GC => client
// k_EMsgGCShowItemsPickedUp = 1071;
//
// // generic broadcast
// k_EMsgGCClientDisplayNotification = 1072; // GC => client
//
//// OBSOLETE k_EMsgGC_IncrementKillCountAttribute = 1074; // client => GC
// k_EMsgGC_IncrementKillCountResponse = 1075; // GC => client
// k_EMsgGCApplyPennantUpgrade = 1076; // GC => client
//
// k_EMsgGCSetItemPositions = 1077; // client => GC; protobuf batched item position update
//
// k_EMsgGCUnlockItemStyle = 1080;
// k_EMsgGCUnlockItemStyleResponse = 1081;
//
// k_EMsgGCFulfillDynamicRecipeComponent = 1082;
// k_EMsgGCFulfillDynamicRecipeComponentResponse = 1083;
// k_EMsgGCApplyEggEssence = 1078;
// k_EMsgGCNameEggEssenceResponse = 1079;
//
// k_EMsgGCClientRequestMarketData = 1084;
// k_EMsgGCClientRequestMarketDataResponse = 1085;
// k_EMsgGCExtractGems = 1086;
// k_EMsgGCAddSocket = 1087; // client -> GC
// k_EMsgGCAddItemToSocket = 1088; // client -> GC
// k_EMsgGCAddItemToSocketResponse = 1089; // GC -> client
// k_EMsgGCAddSocketResponse = 1090; // GC -> client
//
// k_EMsgGCResetStrangeGemCount = 1091; // client -> GC
// << DOTA
// TF >>
// generic broadcast
k_EMsgGCClientDisplayNotification = 1069; // GC => client
k_EMsgGCApplyStrangePart = 1070; // GC => client
k_EMsgGC_IncrementKillCountAttribute = 1071; // client => GC
k_EMsgGC_IncrementKillCountResponse = 1072; // GC => client
k_EMsgGCRemoveStrangePart = 1073; // GC => client
k_EMsgGCResetStrangeScores = 1074; // client => GC
k_EMsgGCGiftedItems = 1075; // GC => game server
k_EMsgGCApplyUpgradeCard = 1077; // client => GC
k_EMsgGCRemoveUpgradeCard = 1078; // client => GC
k_EMsgGCApplyStrangeRestriction = 1079; // client => GC
k_EMsgGCClientRequestMarketData = 1080; // client => GC
k_EMsgGCClientRequestMarketDataResponse = 1081; // GC => client
k_EMsgGCApplyXifier = 1082; // client => GC
k_EMsgGCApplyXifierResponse = 1083; // GC => Client
k_EMsgGC_TrackUniquePlayerPairEvent = 1084; // client => GC
k_EMsgGCFulfillDynamicRecipeComponent = 1085; // client => GC
k_EMsgGCFulfillDynamicRecipeComponentResponse = 1086; // GC => client
k_EMsgGCSetItemEffectVerticalOffset = 1087; // client => GC
k_EMsgGCSetHatEffectUseHeadOrigin = 1088; // client => GC
k_EMsgGCItemEaterRecharger = 1089; // client => GC
k_EMsgGCItemEaterRechargerResponse = 1090; // GC => Client
k_EMsgGCApplyBaseItemXifier = 1091; // client => GC
k_EMsgGCApplyClassTransmogrifier = 1092; // client => GC
k_EMsgGCApplyHalloweenSpellbookPage = 1093; // client => GC
k_EMsgGCRemoveKillStreak = 1094; // client => GC
k_EMsgGCRemoveKillStreakResponse = 1095; // GC => client
k_EMsgGCTFSpecificItemBroadcast = 1096; // GC => client (broadcast)
k_EMsgGC_IncrementKillCountAttribute_Multiple = 1097; // client (game server) => GC
k_EMsgGCDeliverGiftResponseGiver = 1098;
k_EMsgGCSetItemPositions = 1100; // client => GC; protobuf batched item position update
// << TF
k_EMsgGCLookupMultipleAccountNames = 1101;
k_EMsgGCLookupMultipleAccountNamesResponse = 1102;
// trading!
k_EMsgGCTradingBase = 1500;
k_EMsgGCTrading_InitiateTradeRequest = 1501; // client A -> GC and then GC -> client B
k_EMsgGCTrading_InitiateTradeResponse = 1502; // client B -> GC or GC -> client A
k_EMsgGCTrading_StartSession = 1503; // GC -> client A & B
// k_EMsgGCTrading_SetItem = 1504; // client -> GC
// k_EMsgGCTrading_RemoveItem = 1505; // client -> GC
// k_EMsgGCTrading_UpdateTradeInfo = 1506; // GC -> client A & B in response to SetItem or RemoveItem message
// k_EMsgGCTrading_SetReadiness = 1507; // client -> GC
// k_EMsgGCTrading_ReadinessResponse = 1508; // GC -> client A & B
k_EMsgGCTrading_SessionClosed = 1509; // GC -> client A & B
k_EMsgGCTrading_CancelSession = 1510; // client -> GC
// k_EMsgGCTrading_TradeChatMsg = 1511; // client -> GC and then GC -> other client
// k_EMsgGCTrading_ConfirmOffer = 1512; // client -> GC
// k_EMsgGCTrading_TradeTypingChatMsg = 1513; // client -> GC and then GC -> other client
k_EMsgGCTrading_InitiateTradeRequestResponse = 1514; // GC -> client
// serverbrowser messages
k_EMsgGCServerBrowser_FavoriteServer = 1601;
k_EMsgGCServerBrowser_BlacklistServer = 1602;
// rentals & previews
k_EMsgGCServerRentalsBase = 1700;
k_EMsgGCItemPreviewCheckStatus = 1701;
k_EMsgGCItemPreviewStatusResponse = 1702;
k_EMsgGCItemPreviewRequest = 1703;
k_EMsgGCItemPreviewRequestResponse = 1704;
k_EMsgGCItemPreviewExpire = 1705;
k_EMsgGCItemPreviewExpireNotification = 1706;
// !FIXME! DOTAMERGE
// This message is 1707 in DOTA, but it came from TF, where it was 1707 at one time, then switched to 1708
// when the message format changed.
// k_EMsgGCItemPreviewItemBoughtNotification = 1707;
k_EMsgGCItemPreviewItemBoughtNotification = 1708;
// Development only messages
k_EMsgGCDev_NewItemRequest = 2001;
k_EMsgGCDev_NewItemRequestResponse = 2002;
k_EMsgGCDev_DebugRollLootRequest = 2003;
// Microtransaction messages
k_EMsgGCStoreGetUserData = 2500; // Gets the current price sheet from the GC
k_EMsgGCStoreGetUserDataResponse = 2501; // Response
k_EMsgGCStorePurchaseInit_DEPRECATED = 2502; // Initiate a purchase (old pre-protobuff format -- deprecated!)
k_EMsgGCStorePurchaseInitResponse_DEPRECATED = 2503; // Response
// !FIXME! DOTAMERGE
// These messages have different values in TF and DOTA.
// k_EMsgGCStorePurchaseFinalize = 2504; // Finalize a purchase
// k_EMsgGCStorePurchaseFinalizeResponse = 2505; // Response
// k_EMsgGCStorePurchaseCancel = 2506; // Cancel a purchase
// k_EMsgGCStorePurchaseCancelResponse = 2507; // Response
k_EMsgGCStorePurchaseFinalize = 2512; // Finalize a purchase
k_EMsgGCStorePurchaseFinalizeResponse = 2513; // Response
k_EMsgGCStorePurchaseCancel = 2514; // Cancel a purchase
k_EMsgGCStorePurchaseCancelResponse = 2515; // Response
k_EMsgGCStorePurchaseQueryTxn = 2508; // Query the status of a transaction
k_EMsgGCStorePurchaseQueryTxnResponse = 2509; // Response
k_EMsgGCStorePurchaseInit = 2510; // Initiate a purchase
k_EMsgGCStorePurchaseInitResponse = 2511; // Response
// !FIXME! DOTAMERGE
// Conflict with TF messages
// k_EMsgGCBannedWordListRequest = 2512; // Request a list of new banned words
// k_EMsgGCBannedWordListResponse = 2513; // response to a request, or a push of a new banned word update to clients
// k_EMsgGCToGCBannedWordListBroadcast = 2514; // sent from GC to GC so the main GC can broadcast a banned word change to clients
// k_EMsgGCToGCBannedWordListUpdated = 2515; // sent from GC to other GCs so that they can be kept in sync with banned word list updates
k_EMsgGCToGCDirtySDOCache = 2516; // when an SDO cache needs to be dirtied on another GC
k_EMsgGCToGCDirtyMultipleSDOCache = 2517; // when a list of SDO caches needs to be dirtied on another GC
k_EMsgGCToGCUpdateSQLKeyValue = 2518; // when a key value changes and needs to be updated on other GCs
// k_EMsgGCToGCIsTrustedServer = 2519; // Is the specified server trusted?
// k_EMsgGCToGCIsTrustedServerResponse = 2520; // response to whether or not this is a trusted server
k_EMsgGCToGCBroadcastConsoleCommand = 2521; // run a console command remotely on another GC from a GC
k_EMsgGCServerVersionUpdated = 2522; // Sent when the active version of a server changes so servers can restart
k_EMsgGCApplyAutograph = 2523; //
k_EMsgGCToGCWebAPIAccountChanged = 2524;
k_EMsgGCRequestAnnouncements = 2525; //
k_EMsgGCRequestAnnouncementsResponse = 2526; //
k_EMsgGCRequestPassportItemGrant = 2527;
k_EMsgGCClientVersionUpdated = 2528; // Sent when the client doesn't match the appropriate version
k_EMsgGCItemPurgatory_FinalizePurchase = 2531; // Sent for Korean government requirement - move a purchased item from the "maybe box" (referred to as item purgatory in code) to the backpack
k_EMsgGCItemPurgatory_FinalizePurchaseResponse = 2532;
k_EMsgGCItemPurgatory_RefundPurchase = 2533;
k_EMsgGCItemPurgatory_RefundPurchaseResponse = 2534;
k_EMsgGCToGCPlayerStrangeCountAdjustments = 2535;
k_EMsgGCRequestStoreSalesData = 2536; // get which items are currently on sale
k_EMsgGCRequestStoreSalesDataResponse = 2537;
k_EMsgGCRequestStoreSalesDataUpToDateResponse = 2538;
k_EMsgGCToGCPingRequest = 2539;
k_EMsgGCToGCPingResponse = 2540;
k_EMsgGCToGCGetUserSessionServer = 2541; // GC->GC, see what the steam ID is of the server that this user is on
k_EMsgGCToGCGetUserSessionServerResponse = 2542; // --response
k_EMsgGCToGCGetUserServerMembers = 2543; // GC->GC, what members are on the server and spectating
k_EMsgGCToGCGetUserServerMembersResponse = 2544; // --response
k_EMsgGCToGCGrantSelfMadeItemToAccount = 2555; // GC->GC, via SQL message queue, grant one specific self-made item to this contributor account ID
k_EMsgGCToGCThankedByNewUser = 2556; // GC->GC, via SQL message queue, this account was thanked by a new user account, so grant a thanked item or level up the current item
k_EMsgGCShuffleCrateContents = 2557; // game client->GC, shuffle the contents of the line item loot list for this crate
k_EMsgGCQuestObjective_Progress = 2558; // client/game -> GC, report progress in a quest objective
k_EMsgGCQuestCompleted = 2559; // GC -> client, report completion of a quest
k_EMsgGCApplyDuckToken = 2560; // client => GC
k_EMsgGCQuestComplete_Request = 2561; // client -> GC
k_EMsgGCQuestObjective_PointsChange = 2562; // server -> GC
k_EMsgGCQuestObjective_RequestLoanerItems = 2564; // client -> GC
k_EMsgGCQuestObjective_RequestLoanerResponse = 2565; // GC -> client
k_EMsgGCApplyStrangeCountTransfer = 2566; // client => GC
k_EMsgGCCraftCollectionUpgrade = 2567; // client => GC
k_EMsgGCCraftHalloweenOffering = 2568; // client => GC
k_EMsgGCQuestDiscard_Request = 2569; // client => GC
k_EMsgGCRemoveGiftedBy = 2570; // client => GC
k_EMsgGCRemoveGiftedByResponse = 2571; // GC => client
k_EMsgGCRemoveFestivizer = 2572; // client => GC
k_EMsgGCRemoveFestivizerResponse = 2573; // GC => client
k_EMsgGCCraftCommonStatClock = 2574; // client => GC
// Game specific messages start at 5000 and GCGameBase messages start at 3000
// So all these must be < 3000
};
enum EGCMsgResponse
{
k_EGCMsgResponseOK = 0; // Request succeeded
k_EGCMsgResponseDenied = 1; // Request denied
k_EGCMsgResponseServerError = 2; // Request failed due to a temporary server error
k_EGCMsgResponseTimeout = 3; // Request timed out
k_EGCMsgResponseInvalid = 4; // Request was corrupt
k_EGCMsgResponseNoMatch = 5; // No item definition matched the request
k_EGCMsgResponseUnknownError = 6; // Request failed with an unknown error
k_EGCMsgResponseNotLoggedOn = 7; // Client not logged on to steam
k_EGCMsgFailedToCreate = 8; // Failed to create whatever object the GC was asked to create
// k_EGCMsgResponseForceSizeInt = 0x7FFFFFFF
};
enum EUnlockStyle
{
k_UnlockStyle_Succeeded = 0;
k_UnlockStyle_Failed_PreReq = 1;
k_UnlockStyle_Failed_CantAfford = 2;
k_UnlockStyle_Failed_CantCommit = 3;
k_UnlockStyle_Failed_CantLockCache = 4;
k_UnlockStyle_Failed_CantAffordAttrib = 5;
k_UnlockStyle_Failed_CantAffordGem = 6;
};
enum EItemPurgatoryResponse_Finalize
{
k_ItemPurgatoryResponse_Finalize_Succeeded = 0;
k_ItemPurgatoryResponse_Finalize_Failed_Incomplete = 1; // Some but not all finalized
k_ItemPurgatoryResponse_Finalize_Failed_ItemsNotInPurgatory = 2; // Item ID's sent up were not in purgatory
k_ItemPurgatoryResponse_Finalize_Failed_CouldNotFindItems = 3; // One or more items do not belong to the given steam ID or were deleted, etc.
k_ItemPurgatoryResponse_Finalize_Failed_NoSOCache = 4; // Couldn't load the user's SO cache
k_ItemPurgatoryResponse_Finalize_BackpackFull = 5; // Backpack was full. We may have finalized some items.
};
enum EItemPurgatoryResponse_Refund
{
k_ItemPurgatoryResponse_Refund_Succeeded = 0;
k_ItemPurgatoryResponse_Refund_Failed_ItemNotInPurgatory = 1; // Item ID's sent up were not in purgatory
k_ItemPurgatoryResponse_Refund_Failed_CouldNotFindItem = 2; // One or more items do not belong to the given steam ID or were deleted, etc.
k_ItemPurgatoryResponse_Refund_Failed_NoSOCache = 3; // Couldn't load the user's SO cache
k_ItemPurgatoryResponse_Refund_Failed_NoDetail = 4; // Generic error to avoid giving the client too much detail
k_ItemPurgatoryResponse_Refund_Failed_NexonWebAPI = 5; // The Nexon WebAPI failed
};
//
// k_EMsgGCApplyAutograph
//
message CMsgApplyAutograph
{
optional uint64 autograph_item_id = 1; // which autograph?
optional uint64 item_item_id = 2; // which item is getting this autograph
};
// k_EMsgGCToGCPlayerStrangeCountAdjustments
// Used in the GC SQL Msg queue and in match signout
message CMsgEconPlayerStrangeCountAdjustment
{
message CStrangeCountAdjustment
{
optional uint32 event_type = 1;
optional uint64 item_id = 2;
optional uint32 adjustment = 3;
};
optional uint32 account_id = 1;
repeated CStrangeCountAdjustment strange_count_adjustments = 2;
};
//
// k_EMsgGCItemPurgatory_FinalizePurchase
//
message CMsgRequestItemPurgatory_FinalizePurchase
{
repeated uint64 item_ids = 1;
};
//
// k_EMsgGCItemPurgatory_FinalizePurchaseResponse
//
message CMsgRequestItemPurgatory_FinalizePurchaseResponse
{
optional uint32 result = 1;
};
//
// k_EMsgGCItemPurgatory_RefundPurchase
//
message CMsgRequestItemPurgatory_RefundPurchase
{
optional uint64 item_id = 1;
};
//
// k_EMsgGCItemPurgatory_RefundPurchaseResponse
//
message CMsgRequestItemPurgatory_RefundPurchaseResponse
{
optional uint32 result = 1;
};
message CMsgCraftingResponse
{
repeated uint64 item_ids = 1;
};
// k_EMsgGCRequestStoreSalesData
message CMsgGCRequestStoreSalesData
{
optional uint32 version = 1; // the last received version (used to identify when sales data may have changed)
optional uint32 currency = 2; // which currency we want the sales values for
};
// k_EMsgGCRequestStoreSalesDataResponse
message CMsgGCRequestStoreSalesDataResponse
{
message Price
{
optional uint32 item_def = 1;
optional uint32 price = 2;
};
repeated Price sale_price = 1; // the list of items on sale and their sale price for the requested currency
optional uint32 version = 2; // the version of this data, future sale requests should provide this value so redundant requests can be ignored
optional uint32 expiration_time = 3; // the time after which this sale is likely to expire. It could expire sooner than this if the GC restarts
};
// k_EMsgGCRequestStoreSalesDataUpToDateResponse
message CMsgGCRequestStoreSalesDataUpToDateResponse
{
optional uint32 version = 1; // the last received version (used to identify when sales data may have changed)
optional uint32 expiration_time = 2; // the time after which this sale is likely to expire. It could expire sooner than this if the GC restarts
};
// k_EMsgGCToGCPingRequest
message CMsgGCToGCPingRequest
{
};
// k_EMsgGCToGCPingResponse
message CMsgGCToGCPingResponse
{
};
// k_EMsgGCToGCGetUserSessionServer
message CMsgGCToGCGetUserSessionServer
{
optional uint32 account_id = 1; // the user to lookup the server information for
};
// k_EMsgGCToGCGetUserSessionServerResponse
message CMsgGCToGCGetUserSessionServerResponse
{
optional fixed64 server_steam_id = 1; // zero if this user is not online or not on a server
};
// k_EMsgGCToGCGetUserServerMembers
message CMsgGCToGCGetUserServerMembers
{
optional uint32 account_id = 1; // the account ID to look up the server and spectators from
optional uint32 max_spectators = 2; // do you want spectators? If so what is the limit of how many will be returned (otherwise specify zero)
};
// k_EMsgGCToGCGetUserServerMembersResponse
message CMsgGCToGCGetUserServerMembersResponse
{
repeated uint32 member_account_id = 1; // the list of other server members or spectators
};
// k_EMsgGCLookupMultipleAccountNames
message CMsgLookupMultipleAccountNames
{
repeated uint32 accountids = 1 [ packed=true ];
};
// k_EMsgGCLookupMultipleAccountNamesResponse
message CMsgLookupMultipleAccountNamesResponse
{
message Account
{
optional uint32 accountid = 1;
optional string persona = 2;
}
repeated Account accounts = 1;
};
// k_EMsgGCToGCGrantSelfMadeItemToAccount
message CMsgGCToGCGrantSelfMadeItemToAccount
{
optional uint32 item_def_index = 1;
optional uint32 accountid = 2;
}
// k_EMsgGCToGCThankedByNewUser
message CMsgGCToGCThankedByNewUser
{
optional uint32 new_user_accountid = 1; // guy who did the thanking
optional uint32 thanked_user_accountid = 2; // guy who was thanked
}
// k_EMsgGCShuffleCrateContents
message CMsgGCShuffleCrateContents
{
optional uint64 crate_item_id = 1;
optional string user_code_string = 2;
}
// k_EMsgGCQuestObjective_Progress
message CMsgGCQuestObjective_Progress
{
optional uint64 quest_item_id = 1;
optional uint32 quest_attrib_index = 2;
optional uint32 delta = 3;
optional fixed64 owner_steamid = 4;
}
// CMsgGCQuestObjective_PointsChange
message CMsgGCQuestObjective_PointsChange
{
optional uint64 quest_item_id = 1;
optional uint32 standard_points = 2;
optional uint32 bonus_points = 3;
optional fixed64 owner_steamid = 4;
optional bool update_base_points = 5 [default = false];
}
// k_EMsgGCQuestComplete_Request
message CMsgGCQuestComplete_Request
{
optional uint64 quest_item_id = 1;
}
// k_EMsgGCQuestCompleted
message CMsgGCQuestCompleted
{
}
// k_EMsgGCQuestObjective_RequestLoanerItems
message CMsgGCQuestObjective_RequestLoanerItems
{
optional uint64 quest_item_id = 1;
}
// k_EMsgGCQuestObjective_RequestLoanerResponse
message CMsgGCQuestObjective_RequestLoanerResponse
{
}
// k_EMsgGCCraftCollectionUpgrader
message CMsgCraftCollectionUpgrade
{
repeated uint64 item_id = 1; // list of item ids
};
// k_EMsgGCCraftHalloweenOffering
message CMsgCraftHalloweenOffering
{
optional uint64 tool_id = 1; // tool that is invoking this call
repeated uint64 item_id = 2; // list of item ids
};
// k_EMsgGCCraftCommonStatClock
message CMsgCraftCommonStatClock
{
optional uint64 tool_id = 1; // tool that is invoking this call
repeated uint64 item_id = 2; // list of item ids
};
// k_EMsgGCQuestDiscard_Request
message CMsgGCQuestDiscard_Request
{
optional uint64 quest_item_id = 1;
}
// Do not remove this comment due to a bug on the Mac OS X protobuf compiler - lol
+415
View File
@@ -0,0 +1,415 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "cbase.h"
#include "rtime.h"
#include "econ_holidays.h"
//-----------------------------------------------------------------------------
// Purpose: Interface that answers the simple question "on the passed-in time,
// would this holiday be active?". Any caching of calculations is left
// up to subclasses.
//-----------------------------------------------------------------------------
class IIsHolidayActive
{
public:
IIsHolidayActive( const char *pszHolidayName ) : m_pszHolidayName( pszHolidayName ) { }
virtual ~IIsHolidayActive ( ) { }
virtual bool IsActive( const CRTime& timeCurrent ) = 0;
const char *GetHolidayName() const { return m_pszHolidayName; }
private:
const char *m_pszHolidayName;
};
//-----------------------------------------------------------------------------
// Purpose: Always-disabled. Dummy event needed to map to slot zero for "disabled
// holiday".
//-----------------------------------------------------------------------------
class CNoHoliday : public IIsHolidayActive
{
public:
CNoHoliday() : IIsHolidayActive( "none" ) { }
virtual bool IsActive( const CRTime& timeCurrent )
{
return false;
}
};
//-----------------------------------------------------------------------------
// Purpose: A holiday that lasts exactly one and only one day.
//-----------------------------------------------------------------------------
class CSingleDayHoliday : public IIsHolidayActive
{
public:
CSingleDayHoliday( const char *pszName, int iMonth, int iDay )
: IIsHolidayActive( pszName )
, m_iMonth( iMonth )
, m_iDay( iDay )
{
//
}
virtual bool IsActive( const CRTime& timeCurrent )
{
return m_iMonth == timeCurrent.GetMonth()
&& m_iDay == timeCurrent.GetDayOfMonth();
}
private:
int m_iMonth;
int m_iDay;
};
//-----------------------------------------------------------------------------
// Purpose: We want "week long" holidays to encompass at least two weekends,
// so that players get plenty of time interacting with the holiday
// features.
//-----------------------------------------------------------------------------
class CWeeksBasedHoliday : public IIsHolidayActive
{
public:
CWeeksBasedHoliday( const char *pszName, int iMonth, int iDay, int iExtraWeeks )
: IIsHolidayActive( pszName )
, m_iMonth( iMonth )
, m_iDay( iDay )
, m_iExtraWeeks( iExtraWeeks )
, m_iCachedCalculatedYear( 0 )
{
// We'll calculate the interval the first time we call IsActive().
}
void RecalculateTimeActiveInterval( int iYear )
{
// Get the date of the holiday.
tm holiday_tm = { };
holiday_tm.tm_mday = m_iDay;
holiday_tm.tm_mon = m_iMonth - 1;
holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
mktime( &holiday_tm );
// The event starts on the first Friday at least four days prior to the holiday.
tm start_time_tm( holiday_tm );
start_time_tm.tm_mday -= 4; // Move back four days.
mktime( &start_time_tm );
int days_offset = start_time_tm.tm_wday - kFriday; // Find the nearest prior Friday.
if ( days_offset < 0 )
days_offset += 7;
start_time_tm.tm_mday -= days_offset;
time_t start_time = mktime( &start_time_tm );
// The event ends on the first Monday after the holiday, maybe plus some additional fudge
// time.
tm end_time_tm( holiday_tm );
days_offset = 7 - (end_time_tm.tm_wday - kMonday);
if ( days_offset >= 7 )
days_offset -= 7;
end_time_tm.tm_mday += days_offset + 7 * m_iExtraWeeks;
time_t end_time = mktime( &end_time_tm );
#ifdef GC_DLL
char rgchDateStartBuf[ 128 ];
BGetLocalFormattedDate( start_time, rgchDateStartBuf, sizeof( rgchDateStartBuf) );
char rgchDateEndBuf[ 128 ];
BGetLocalFormattedDate( end_time, rgchDateEndBuf, sizeof( rgchDateEndBuf ) );
EmitInfo( GCSDK::SPEW_GC, 4, LOG_ALWAYS, "Holiday - '%s' event starts on '%s' and ends on '%s'.\n", GetHolidayName(), rgchDateStartBuf, rgchDateEndBuf );
#endif // GC_DLL
m_timeStart = start_time;
m_timeEnd = end_time;
// We're done and our interval data is cached.
m_iCachedCalculatedYear = iYear;
}
virtual bool IsActive( const CRTime& timeCurrent )
{
const int iCurrentYear = timeCurrent.GetYear();
if ( m_iCachedCalculatedYear != iCurrentYear )
RecalculateTimeActiveInterval( iCurrentYear );
return timeCurrent.GetRTime32() > m_timeStart
&& timeCurrent.GetRTime32() < m_timeEnd;
}
private:
static const int kMonday = 1;
static const int kFriday = 5;
int m_iMonth;
int m_iDay;
int m_iExtraWeeks;
// Filled out from RecalculateTimeActiveInterval().
int m_iCachedCalculatedYear;
RTime32 m_timeStart;
RTime32 m_timeEnd;
};
//-----------------------------------------------------------------------------
// Purpose: A holiday that repeats on a certain time interval, like "every N days"
// or "once every two months" or, uh, "any time there's a full moon".
//-----------------------------------------------------------------------------
class CCyclicalHoliday : public IIsHolidayActive
{
public:
CCyclicalHoliday( const char *pszName, int iMonth, int iDay, int iYear, float fCycleLengthInDays, float fBonusTimeInDays )
: IIsHolidayActive( pszName )
, m_fCycleLengthInDays( fCycleLengthInDays )
, m_fBonusTimeInDays( fBonusTimeInDays )
{
// When is our initial interval?
tm holiday_tm = { };
holiday_tm.tm_mday = iDay;
holiday_tm.tm_mon = iMonth - 1;
holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
m_timeInitial = mktime( &holiday_tm );
}
virtual bool IsActive( const CRTime& timeCurrent )
{
// Days-to-seconds conversion.
const int iSecondsPerDay = 24 * 60 * 60;
// Convert our cycle/buffer times to seconds.
const int iCycleLengthInSeconds = (int)(m_fCycleLengthInDays * iSecondsPerDay);
const int iBufferTimeInSeconds = (int)(m_fBonusTimeInDays * iSecondsPerDay);
// How long has it been since we started this cycle?
int iSecondsIntoCycle = (timeCurrent.GetRTime32() - m_timeInitial) % iCycleLengthInSeconds;
// If we're within the buffer period right after the start of a cycle, we're active.
if ( iSecondsIntoCycle < iBufferTimeInSeconds )
return true;
// If we're within the buffer period towards the end of a cycle, we're active.
if ( iSecondsIntoCycle > iCycleLengthInSeconds - iBufferTimeInSeconds )
return true;
// Alas, normal mode for us.
return false;
}
private:
time_t m_timeInitial ;
float m_fCycleLengthInDays;
float m_fBonusTimeInDays;
};
//-----------------------------------------------------------------------------
// Purpose: A pseudo-holiday that is active when either of its child holidays
// is active. Works through pointers but does not manage memory.
//-----------------------------------------------------------------------------
class COrHoliday : public IIsHolidayActive
{
public:
COrHoliday( const char *pszName, IIsHolidayActive *pA, IIsHolidayActive *pB )
: IIsHolidayActive( pszName )
, m_pA( pA )
, m_pB( pB )
{
Assert( pA );
Assert( pB );
Assert( pA != pB );
}
virtual bool IsActive( const CRTime& timeCurrent )
{
return m_pA->IsActive( timeCurrent )
|| m_pB->IsActive( timeCurrent );
}
private:
IIsHolidayActive *m_pA;
IIsHolidayActive *m_pB;
};
//-----------------------------------------------------------------------------
// Purpose: Holiday that is defined by a start and end date
//-----------------------------------------------------------------------------
class CDateBasedHoliday : public IIsHolidayActive
{
public:
CDateBasedHoliday( const char *pszName, const char *pszStartTime, const char *pszEndTime )
: IIsHolidayActive( pszName )
{
m_rtStartTime = CRTime::RTime32FromString( pszStartTime );
m_rtEndTime = CRTime::RTime32FromString( pszEndTime );
}
virtual bool IsActive( const CRTime& timeCurrent )
{
return ( ( timeCurrent >= m_rtStartTime ) && ( timeCurrent <= m_rtEndTime ) );
}
RTime32 GetEndRTime() const
{
return m_rtEndTime.GetRTime32();
}
private:
CRTime m_rtStartTime;
CRTime m_rtEndTime;
};
//-----------------------------------------------------------------------------
// Purpose: Holiday that is defined by a start and end date with no year specified
//-----------------------------------------------------------------------------
class CDateBasedHolidayNoSpecificYear : public IIsHolidayActive
{
public:
CDateBasedHolidayNoSpecificYear( const char *pszName, const char *pszStartTime, const char *pszEndTime )
: IIsHolidayActive( pszName )
, m_pszStartTime( pszStartTime )
, m_pszEndTime( pszEndTime )
, m_iCachedYear( -1 )
{
}
virtual bool IsActive( const CRTime& timeCurrent )
{
const int iYear = timeCurrent.GetYear();
if ( iYear != m_iCachedYear )
{
char m_szStartTime[k_RTimeRenderBufferSize];
char m_szEndTime[k_RTimeRenderBufferSize];
V_sprintf_safe( m_szStartTime, "%d-%s", iYear, m_pszStartTime );
V_sprintf_safe( m_szEndTime, "%d-%s", iYear, m_pszEndTime );
m_iCachedYear = iYear;
m_rtCachedStartTime = CRTime::RTime32FromString( m_szStartTime );
m_rtCachedEndTime = CRTime::RTime32FromString( m_szEndTime );
}
return ( ( timeCurrent >= m_rtCachedStartTime ) && ( timeCurrent <= m_rtCachedEndTime ) );
}
private:
const char *m_pszStartTime;
const char *m_pszEndTime;
int m_iCachedYear;
CRTime m_rtCachedStartTime;
CRTime m_rtCachedEndTime;
};
//-----------------------------------------------------------------------------
// Purpose: Actual holiday implementation objects.
//-----------------------------------------------------------------------------
static CNoHoliday g_Holiday_NoHoliday;
static CDateBasedHolidayNoSpecificYear g_Holiday_TF2Birthday ( "birthday", "08-23", "08-25" );
static CDateBasedHoliday g_Holiday_Halloween ( "halloween", "2016-10-19", "2016-11-18" );
static CDateBasedHoliday g_Holiday_Christmas ( "christmas", "2016-11-28", "2017-01-12" );
static CDateBasedHolidayNoSpecificYear g_Holiday_ValentinesDay ( "valentines", "02-13", "02-15" );
static CDateBasedHoliday g_Holiday_MeetThePyro ( "meet_the_pyro", "2012-06-26", "2012-07-05" );
/* starting date cycle length in days bonus time in days on both sides */
static CCyclicalHoliday g_Holiday_FullMoon ( "fullmoon", 5, 21, 2016, 29.53f, 1.0f );
// note: the cycle length is 29.5 instead of 29.53 so that the time calculations always start at noon based on the way CCyclicalHoliday works
static COrHoliday g_Holiday_HalloweenOrFullMoon ( "halloween_or_fullmoon", &g_Holiday_Halloween, &g_Holiday_FullMoon );
static COrHoliday g_Holiday_HalloweenOrFullMoonOrValentines ( "halloween_or_fullmoon_or_valentines", &g_Holiday_HalloweenOrFullMoon, &g_Holiday_ValentinesDay );
static CDateBasedHolidayNoSpecificYear g_Holiday_AprilFools ( "april_fools", "03-31", "04-02" );
static CDateBasedHoliday g_Holiday_EndOfTheLine ( "eotl_launch", "2014-12-03", "2015-01-05" );
static CDateBasedHoliday g_Holiday_CommunityUpdate ( "community_update", "2015-09-01", "2015-11-05" );
// ORDER NEEDS TO MATCH enum EHoliday
static IIsHolidayActive *s_HolidayChecks[] =
{
&g_Holiday_NoHoliday, // kHoliday_None
&g_Holiday_TF2Birthday, // kHoliday_TFBirthday
&g_Holiday_Halloween, // kHoliday_Halloween
&g_Holiday_Christmas, // kHoliday_Christmas
&g_Holiday_CommunityUpdate, // kHoliday_CommunityUpdate
&g_Holiday_EndOfTheLine, // kHoliday_EOTL
&g_Holiday_ValentinesDay, // kHoliday_Valentines
&g_Holiday_MeetThePyro, // kHoliday_MeetThePyro
&g_Holiday_FullMoon, // kHoliday_FullMoon
&g_Holiday_HalloweenOrFullMoon, // kHoliday_HalloweenOrFullMoon
&g_Holiday_HalloweenOrFullMoonOrValentines, // kHoliday_HalloweenOrFullMoonOrValentines
&g_Holiday_AprilFools, // kHoliday_AprilFools
};
COMPILE_TIME_ASSERT( ARRAYSIZE( s_HolidayChecks ) == kHolidayCount );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool EconHolidays_IsHolidayActive( int iHolidayIndex, const CRTime& timeCurrent )
{
if ( iHolidayIndex < 0 || iHolidayIndex >= kHolidayCount )
return false;
Assert( s_HolidayChecks[iHolidayIndex] );
if ( !s_HolidayChecks[iHolidayIndex] )
return false;
return s_HolidayChecks[iHolidayIndex]->IsActive( timeCurrent );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int EconHolidays_GetHolidayForString( const char* pszHolidayName )
{
for ( int iHoliday = 0; iHoliday < kHolidayCount; ++iHoliday )
{
Assert( s_HolidayChecks[iHoliday] );
if ( s_HolidayChecks[iHoliday] &&
0 == Q_stricmp( pszHolidayName, s_HolidayChecks[iHoliday]->GetHolidayName() ) )
{
return iHoliday;
}
}
return kHoliday_None;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *EconHolidays_GetActiveHolidayString()
{
CRTime timeNow;
timeNow.SetToCurrentTime();
timeNow.SetToGMT( true );
for ( int iHoliday = 0; iHoliday < kHolidayCount; iHoliday++ )
{
if ( EconHolidays_IsHolidayActive( iHoliday, timeNow ) )
{
Assert( s_HolidayChecks[iHoliday] );
return s_HolidayChecks[iHoliday]->GetHolidayName();
}
}
// No holidays currently active.
return NULL;
}
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
RTime32 EconHolidays_TerribleHack_GetHalloweenEndData()
{
return g_Holiday_Halloween.GetEndRTime();
}
#endif // defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
+18
View File
@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#ifndef ECON_HOLIDAYS_H
#define ECON_HOLIDAYS_H
#ifdef _WIN32
#pragma once
#endif
bool EconHolidays_IsHolidayActive( int iHolidayIndex, const class CRTime& timeCurrent );
int EconHolidays_GetHolidayForString( const char* pszHolidayName );
const char *EconHolidays_GetActiveHolidayString();
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
RTime32 EconHolidays_TerribleHack_GetHalloweenEndData();
#endif // defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
#endif // ECON_HOLIDAYS_H
File diff suppressed because it is too large Load Diff
+864
View File
@@ -0,0 +1,864 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CEconItem, a shared object for econ items
//
//=============================================================================
#ifndef ECONITEM_H
#define ECONITEM_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/gcclientsdk.h"
#include "base_gcmessages.pb.h"
#include "econ_item_constants.h"
#include "econ_item_interface.h"
#include "econ_item_schema.h"
#include <typeinfo> // needed for typeid()
#define ENABLE_TYPED_ATTRIBUTE_PARANOIA 1
#ifdef GC_DLL
class CSchItem;
class CEconSharedObjectCache;
#endif
namespace GCSDK
{
class CColumnSet;
#ifdef GC_DLL
class CWebAPIValues;
#endif
};
class CEconItem;
class CSOEconItem;
class CEconItemCustomData;
class CEconSessionItemAudit;
//-----------------------------------------------------------------------------
// Stats tracking for the attributes attached to CEconItem instances.
//-----------------------------------------------------------------------------
struct schema_attribute_stat_bucket_t
{
const schema_attribute_stat_bucket_t *m_pNext;
const char *m_pszDesc;
uint64 m_unLiveInlineCount;
uint64 m_unLifetimeInlineCount;
uint64 m_unLiveHeapCount;
uint64 m_unLifetimeHeapCount;
void OnAllocateInlineInstance() { m_unLiveInlineCount++; m_unLifetimeInlineCount++; }
void OnFreeInlineInstance() { Assert( m_unLiveInlineCount > 0 ); m_unLiveInlineCount--; }
void OnAllocateHeapInstance() { m_unLiveHeapCount++; m_unLifetimeHeapCount++; }
void OnFreeHeapInstance() { Assert( m_unLiveHeapCount ); m_unLiveHeapCount--; }
};
class CSchemaAttributeStats
{
public:
template < typename TAttribStatsStorageClass, typename TAttribInMemoryType >
static void RegisterAttributeType()
{
TAttribStatsStorageClass::s_InstanceStats.m_pszDesc = typeid( TAttribInMemoryType ).name();
TAttribStatsStorageClass::s_InstanceStats.m_pNext = m_pHead;
m_pHead = &TAttribStatsStorageClass::s_InstanceStats;
}
static const schema_attribute_stat_bucket_t *GetFirstStatBucket()
{
return m_pHead;
}
private:
static const schema_attribute_stat_bucket_t *m_pHead;
};
//-----------------------------------------------------------------------------
// Base class interface for attributes of a certain in-memory type.
//-----------------------------------------------------------------------------
unsigned int Internal_GetAttributeTypeUniqueIdentifierNextValue();
template < typename T >
unsigned int GetAttributeTypeUniqueIdentifier()
{
static unsigned int s_unUniqueCounter = Internal_GetAttributeTypeUniqueIdentifierNextValue();
return s_unUniqueCounter;
}
//-----------------------------------------------------------------------------
// Base class interface for attributes of a certain in-memory type.
//-----------------------------------------------------------------------------
template < typename TAttribInMemoryType >
class ISchemaAttributeTypeBase : public ISchemaAttributeType
{
friend class CSchemaAttributeStats;
public:
ISchemaAttributeTypeBase()
{
CSchemaAttributeStats::RegisterAttributeType< ISchemaAttributeTypeBase<TAttribInMemoryType>, TAttribInMemoryType >();
// The implementation of the attributes-in-memory system is such that it may or may not behave according to
// expectations. Rather than have to stare at all the details to answer questions about where memory is allocated
// or managed, or when it will be freed, for all our current use cases it makes more sense to just disable raw
// pointer types from being an attribute-in-memory type and instead steer people towards this message explaining
// why.
COMPILE_TIME_ASSERT( !IsPointerType<TAttribInMemoryType>::kValue );
}
#ifdef GC_DLL
// By default, without a specific type we don't support any sort of custom value generation, so all we can do
// to load an attribute is to copy the value out from the generic format (union) and turn it into whatever our
// type is, and then add that type to the item as an attribute.
//
// Unlike most of the functions in this class, this is not meant to be a catch-all default implementation but
// is instead a base implementation. Subclasses are intended to override to add or change functionality.
virtual void LoadOrGenerateEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const OVERRIDE
{
Assert( pTargetItem );
Assert( pAttrDef );
AssertMsg( !staticAttrib.m_pKVCustomData, "Default implementation of LoadOrGenerateEconAttributeValue() doesn't support custom value generation!" );
AssertMsg( pGameAccount || !staticAttrib.m_pKVCustomData, "Cannot run custom logic with no game account object! Passing in NULL for pGameAccount is only supported when we know we won't be running custom value generation code!" );
LoadEconAttributeValue( pTargetItem, pAttrDef, staticAttrib.m_value );
}
// By default, we dont generate any custom value
virtual void GenerateEconAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount, attribute_data_union_t* out_pValue ) const OVERRIDE
{
Assert( pAttrDef );
Assert( pGameAccount );
Assert( out_pValue );
}
#endif // GC_DLL
virtual void LoadEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value ) const OVERRIDE;
// Returns a unique identifier per run based on the type of <TAttribInMemoryType>.
virtual unsigned int GetTypeUniqueIdentifier() const OVERRIDE
{
return GetAttributeTypeUniqueIdentifier<TAttribInMemoryType>();
}
// Takes the value specified in [typedValue] and stores it in the most appropriate way
// somewhere attached to [out_pValue]. This may hit the heap. The storage itself is
// intended to be opaque but can be reversed by calling GetTypedValueContentsFromEconAttributeValue().
void ConvertTypedValueToEconAttributeValue( const TAttribInMemoryType& typedValue, attribute_data_union_t *out_pValue ) const
{
// If our type is smaller than an int, we don't know how to copy the memory into our flat structure. We could write
// this code but we have no use case for it now so this is set up to fail so if someone does come up with a use case
// they know where to fix.
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
// Do we fit in the bottom 32-bits?
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
{
*reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asUint32 ) = typedValue;
}
// What about in the full 64-bits (if we're running a 64-bit build)?
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
{
*reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asBlobPointer ) = typedValue;
}
// We're too big for our flat structure. We need to allocate space somewhere outside our attribute instance and point
// to that.
else
{
Assert( out_pValue->asBlobPointer );
*reinterpret_cast<TAttribInMemoryType *>( out_pValue->asBlobPointer ) = typedValue;
}
}
// Guaranteed to return a valid reference (or assert/crash if calling code is behaving inappropriately and calling
// this before an attribute value is allocated/set).
const TAttribInMemoryType& GetTypedValueContentsFromEconAttributeValue( const attribute_data_union_t& value ) const
{
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
// Do we fit in the bottom 32-bits?
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
return *reinterpret_cast<const TAttribInMemoryType *>( &value.asUint32 );
// What about in the full 64-bits (if we're running a 64-bit build)?
if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
return *reinterpret_cast<const TAttribInMemoryType *>( &value.asBlobPointer );
// We don't expect to get to a "read value" call without having written a value, which would
// have allocated this memory.
Assert( value.asBlobPointer );
return *reinterpret_cast<const TAttribInMemoryType *>( value.asBlobPointer );
}
void ConvertEconAttributeValueToTypedValue( const attribute_data_union_t& value, TAttribInMemoryType *out_pTypedValue ) const
{
Assert( out_pTypedValue );
*out_pTypedValue = GetTypedValueContentsFromEconAttributeValue( value );
}
void InitializeNewEconAttributeValue( attribute_data_union_t *out_pValue ) const OVERRIDE
{
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
{
new( &out_pValue->asUint32 ) TAttribInMemoryType;
s_InstanceStats.OnAllocateInlineInstance();
}
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
{
new( &out_pValue->asBlobPointer ) TAttribInMemoryType;
s_InstanceStats.OnAllocateInlineInstance();
}
else
{
out_pValue->asBlobPointer = reinterpret_cast<byte *>( new TAttribInMemoryType );
s_InstanceStats.OnAllocateHeapInstance();
}
}
virtual void UnloadEconAttributeValue( attribute_data_union_t *out_pValue ) const OVERRIDE
{
COMPILE_TIME_ASSERT( sizeof( TAttribInMemoryType ) >= sizeof( uint32 ) );
// For smaller types, anything that fits inside the bits of a void pointer, we store the contents
// inline and only have to worry about calling the correct destructor. We check against the small-/
// size/medium-size values separately to not worry about which bits we're storing the uint32 in.
if ( sizeof( TAttribInMemoryType ) <= sizeof( uint32 ) )
{
(reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asUint32 ))->~TAttribInMemoryType();
s_InstanceStats.OnFreeInlineInstance();
}
else if ( sizeof( TAttribInMemoryType ) <= sizeof( void * ) )
{
(reinterpret_cast<TAttribInMemoryType *>( &out_pValue->asBlobPointer ))->~TAttribInMemoryType();
s_InstanceStats.OnFreeInlineInstance();
}
// For larger types, we have the memory stored on the heap somewhere. We don't have to manually
// destruct, but we do have to manually free.
else
{
Assert( out_pValue->asBlobPointer );
delete reinterpret_cast<TAttribInMemoryType *>( out_pValue->asBlobPointer );
s_InstanceStats.OnFreeHeapInstance();
}
}
virtual bool OnIterateAttributeValue( IEconItemAttributeIterator *pIterator, const CEconItemAttributeDefinition *pAttrDef, const attribute_data_union_t& value ) const OVERRIDE
{
Assert( pIterator );
Assert( pAttrDef );
// Call the appropriate virtual function on our iterator based on whatever type we represent.
return pIterator->OnIterateAttributeValue( pAttrDef, GetTypedValueContentsFromEconAttributeValue( value ) );
}
virtual void LoadByteStreamToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const std::string& sBytes ) const OVERRIDE;
virtual void ConvertEconAttributeValueToByteStream( const attribute_data_union_t& value, ::std::string *out_psBytes ) const;
virtual void ConvertTypedValueToByteStream( const TAttribInMemoryType& typedValue, ::std::string *out_psBytes ) const = 0;
virtual void ConvertByteStreamToTypedValue( const ::std::string& sBytes, TAttribInMemoryType *out_pTypedValue ) const = 0;
private:
static schema_attribute_stat_bucket_t s_InstanceStats;
};
// This function exists only to back-convert code that relies on the old untyped
// attribute system, doing things like shoving floating-point bits into a uint32
// value in the database.
//
// There is no reason to use this function moving forward! If you're writing new
// code and calling this function seems like the only way to get the effect you
// want, it probably just means that there is no attribute type for what you're
// trying to do yet.
template < typename T > uint32 WrapDeprecatedUntypedEconItemAttribute( T tValue ) { COMPILE_TIME_ASSERT( sizeof( T ) == sizeof( uint32 ) ); return *reinterpret_cast<uint32 *>( &tValue ); }
template < typename TAttribInMemoryType >
schema_attribute_stat_bucket_t ISchemaAttributeTypeBase<TAttribInMemoryType>::s_InstanceStats;
class CEconItem : public GCSDK::CSharedObject, public CMaterialOverrideContainer< IEconItemInterface >
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconItem );
#endif
public:
typedef GCSDK::CSharedObject BaseClass;
struct attribute_t
{
attrib_definition_index_t m_unDefinitionIndex; // stored as ints here for memory efficiency on the GC
attribute_data_union_t m_value;
private:
void operator=( const attribute_t& rhs );
};
struct EquippedInstance_t
{
EquippedInstance_t() : m_unEquippedClass( 0 ), m_unEquippedSlot( INVALID_EQUIPPED_SLOT ) {}
EquippedInstance_t( equipped_class_t unClass, equipped_slot_t unSlot ) : m_unEquippedClass( unClass ), m_unEquippedSlot( unSlot ) {}
equipped_class_t m_unEquippedClass;
equipped_slot_t m_unEquippedSlot;
};
#ifdef GC_DLL
class CAuditEntry
{
public:
CAuditEntry( EItemAction eAction, uint32 unData ) : m_eAction( eAction ), m_unData( unData ) { }
bool BAddAuditEntryToTransaction( CSQLAccess& sqlAccess, const CEconItem *pItem ) const;
private:
EItemAction m_eAction;
uint32 m_unData;
};
// Set only the top 16 bits for field ID types! These will be or'd into the index of
// the field itself and then pulled apart later.
enum
{
kUpdateFieldIDType_FieldID = 0x00000000, // this must stay as 0 for legacy code
kUpdateFieldIDType_AttributeID = 0x00010000,
};
#endif // GC_DLL
const static int k_nTypeID = k_EEconTypeItem;
virtual int GetTypeID() const { return k_nTypeID; }
CEconItem();
CEconItem( const CEconItem& rhs );
virtual ~CEconItem();
CEconItem &operator=( const CEconItem& rhs );
//called to determine if this item is tradable or not. This will return the time after which it can be traded. If 0 it can be traded. This is
//needed since the base implementation of this is protected
RTime32 GetTradableAfterDateTime() const { return IEconItemInterface::GetTradableAfterDateTime(); }
//called to set a tradable after date/time value onto this item (this avoids a lot of potential inefficiencies around this process)
void SetTradableAfterDateTime( RTime32 rtTime );
// IEconItemInterface interface.
const GameItemDefinition_t *GetItemDefinition() const;
public:
virtual void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const OVERRIDE;
virtual itemid_t GetID() const { return GetItemID(); }
// Accessors/Settors
itemid_t GetItemID() const { return m_ulID; }
void SetItemID( uint64 ulID );
itemid_t GetOriginalID() const;
void SetOriginalID( uint64 ulOriginalID );
uint32 GetAccountID() const { return m_unAccountID; }
void SetAccountID( uint32 unAccountID ) { m_unAccountID = unAccountID; }
uint32 GetDefinitionIndex() const { return m_unDefIndex; }
void SetDefinitionIndex( uint32 unDefinitionIndex ) { m_unDefIndex = unDefinitionIndex; }
uint32 GetItemLevel() const { return m_unLevel; }
void SetItemLevel( uint32 unItemLevel ) { m_unLevel = unItemLevel; }
int32 GetQuality() const { return m_nQuality; }
void SetQuality( int32 nQuality ) { m_nQuality = nQuality; }
uint32 GetInventoryToken() const { return m_unInventory; }
void SetInventoryToken( uint32 unToken ) { m_unInventory = unToken; }
int GetQuantity() const;
void SetQuantity( uint16 unQuantity );
uint8 GetFlags() const { return m_unFlags; }
void SetFlags( uint8 unFlags ) { m_unFlags = unFlags; }
void SetFlag( uint8 unFlag ) { m_unFlags |= unFlag; }
void ClearFlag( uint8 unFlag ) { m_unFlags &= ~unFlag; }
bool CheckFlags( uint8 unFlags ) const { return ( m_unFlags & unFlags ) != 0; }
eEconItemOrigin GetOrigin() const { return (eEconItemOrigin)m_unOrigin; }
void SetOrigin( eEconItemOrigin unOrigin ) { m_unOrigin = unOrigin; Assert( m_unOrigin == unOrigin ); }
bool IsForeign() const { return m_unOrigin == kEconItemOrigin_Foreign; }
style_index_t GetStyle() const;
void SetStyle( uint8 unStyle ) { m_unStyle = unStyle; DirtyIconURL(); }
const char *GetIconURLSmall() const;
const char *GetIconURLLarge() const;
const char *GetCustomName() const;
void SetCustomName( const char *pName );
const char *GetCustomDesc() const;
void SetCustomDesc( const char *pDesc );
bool IsEquipped() const;
bool IsEquippedForClass( equipped_class_t unClass ) const;
equipped_slot_t GetEquippedPositionForClass( equipped_class_t unClass ) const;
void Equip( equipped_class_t unClass, equipped_slot_t unSlot );
void Unequip();
void UnequipFromClass( equipped_class_t unClass );
// This should really only used for the WebAPIs, debugging, etc. Data manipulation during gameplay should use
// the above functions.
int GetEquippedInstanceCount() const;
const EquippedInstance_t &GetEquippedInstance( int iIdx ) const;
virtual bool GetInUse() const;
void SetInUse( bool bInUse );
bool IsTradable() const;
bool IsMarketable() const;
bool IsCommodity() const;
void AdoptMoreRestrictedTradabilityFromItem( const CEconItem *pOther, uint32 nTradabilityFlagsToAccept = 0xFFFFFFFF );
void AdoptMoreRestrictedTradability( uint32 nTradabilityFlags, RTime32 nUntradableTime );
bool IsUsableInCrafting() const;
#ifdef GC_DLL
RTime32 GetAssetInfoExpirationCacheExpirationTime() const;
#endif // GC_DLL
// --------------------------------------------------------------------------------------------
// Typed attributes. These are methods for accessing and setting values of attributes with
// some semblance of type information and type safety.
// --------------------------------------------------------------------------------------------
// Assign the value of the attribute [pAttrDef] to [value]. Passing in a type for [value] that
// doesn't match the storage type specified by the attribute definition will fail asserts a bunch
// of asserts all the way down the stack and may or may not crash -- it would be nice to make this
// fail asserts at compile time.
//
// This function has undefined results (besides asserting) if called to add a dynamic version of
// an attrib that's already specified statically.
template < typename T >
void SetDynamicAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const T& value )
{
Assert( pAttrDef );
const ISchemaAttributeTypeBase<T> *pAttrType = GetTypedAttributeType<T>( pAttrDef );
#ifdef GC_DLL
// The GC is expected to always have internally-consistent information and so be able to access the
// type information of any attribute if we started up successfully.
Assert( pAttrType );
#else
// Game clients and servers may be running code that doesn't have all of the types for the new attributes
// for a GC that just propped. Because we're not authoritative over items here, about the best we can do
// here is abort entirely. This means that the client may not display certain attributes at all, or even
// have them in the attribute list in memory, but we don't understand those attributes anyway.
if ( !pAttrType )
return;
#endif
// Fail right off the bat if we're trying to write a dynamic attribute value for an item that already
// has this as a static value.
AssertMsg4( !::FindAttribute( GetItemDefinition(), pAttrDef ),
"Item id %llu (%s) attempting to set dynamic attribute value for '%s' (%d) when static attribute exists!",
GetItemID(), GetItemDefinition()->GetDefinitionName(), pAttrDef->GetDefinitionName(), pAttrDef->GetDefinitionIndex() );
// Alright, we have a data type match so we can safely store data. Some types may need to initialize
// their data to a current state if it's the first time we're writing to this value (as opposed to
// updating an existing value).
attribute_t *pEconAttrib = FindDynamicAttributeInternal( pAttrDef );
if ( !pEconAttrib )
{
pEconAttrib = &(AddDynamicAttributeInternal());
pEconAttrib->m_unDefinitionIndex = pAttrDef->GetDefinitionIndex();
pAttrType->InitializeNewEconAttributeValue( &pEconAttrib->m_value );
}
pAttrType->ConvertTypedValueToEconAttributeValue( value, &pEconAttrib->m_value );
#if ENABLE_TYPED_ATTRIBUTE_PARANOIA
// Paranoia!: make sure that our read/write functions are mirrored correctly, and that if we attempt
// to read back a value we get something identical to what we just wrote. We do this via converting
// to strings and then comparing those because there may or not be equality comparisons for our type
// T that make sense (ie., protobufs).
{
T readValue;
DbgVerify( FindAttribute( pAttrDef, &readValue ) );
std::string sBytes, sReadBytes;
pAttrType->ConvertTypedValueToByteStream( value, &sBytes );
pAttrType->ConvertTypedValueToByteStream( readValue, &sReadBytes );
AssertMsg1( sBytes == sReadBytes, "SetDynamicAttributeValue(): read/write mismatch for attribute '%s'.", pAttrDef->GetDefinitionName() );
}
#endif // ENABLE_TYPED_ATTRIBUTE_PARANOIA
}
// Called to set a time stamp dynamic attribute on this item. But it will first check the current value assigned to this item, and will
// only set it if this new time extends beyond the current one
void SetDynamicMaxTimeAttributeValue( const CEconItemAttributeDefinition *pAttrDef, RTime32 rtTime );
// Remove an instance of an attribute from this item. This will also free any dynamic memory associated
// with that instance if any was allocated.
void RemoveDynamicAttribute( const CEconItemAttributeDefinition *pAttrDef );
// Copy all attributes and values in a type-safe way from [source] to ourself. Attributes that we have
// that don't exist on [source] will maintain their current values. All other attributes will get their
// values set to whatever [source] specifies.
void CopyAttributesFrom( const CEconItem& source );
bool BHasDynamicAttributes() const { return GetDynamicAttributeCountInternal() > 0; }
private:
const char* FindIconURL( bool bLarge ) const;
void Init();
template < typename T >
static const ISchemaAttributeTypeBase<T> *GetTypedAttributeType( const CEconItemAttributeDefinition *pAttrDef )
{
// Make sure the type of data we're passing in matches the type of data we're claiming that we can
// store in the attribute definition.
const ISchemaAttributeType *pIAttr = pAttrDef->GetAttributeType();
Assert( pIAttr );
Assert( pIAttr->GetTypeUniqueIdentifier() == GetAttributeTypeUniqueIdentifier<T>() );
#if ENABLE_TYPED_ATTRIBUTE_PARANOIA
return dynamic_cast<const ISchemaAttributeTypeBase<T> *>( pIAttr );
#else
return static_cast<const ISchemaAttributeTypeBase<T> *>( pIAttr );
#endif
}
public:
void Compact();
#ifdef GC
bool BDeserializeFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors );
#endif // GC
#ifdef GC_DLL
void ExportToAPI( GCSDK::CWebAPIValues *pValues ) const;
bool BImportFromAPI( GCSDK::CWebAPIValues *pValues );
#endif // GC_DLL
// these are overridden to handle attributes
#ifdef GC_DLL
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess & sqlAccess );
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess & sqlAccess, const CUtlVector< int > &fields );
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess & sqlAccess );
void SerializeToSchemaItem( CSchItem &item ) const;
void DeserializeFromSchemaItem( const CSchItem &item );
void SetInteriorItem( CEconItem* pInteriorItem );
#endif // GC_DLL
virtual bool BParseFromMessage( const CUtlBuffer &buffer ) OVERRIDE;
virtual bool BParseFromMessage( const std::string &buffer ) OVERRIDE;
virtual bool BUpdateFromNetwork( const CSharedObject & objUpdate ) OVERRIDE;
#ifdef GC
virtual bool BAddToMessage( CUtlBuffer & bufOutput ) const OVERRIDE;
virtual bool BAddToMessage( std::string *pBuffer ) const OVERRIDE; // short cut to remove an extra copy
virtual bool BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const OVERRIDE;
virtual bool BAddDestroyToMessage( std::string *pBuffer ) const OVERRIDE;
bool BYieldingSerializeFromDatabase( itemid_t ulItemID );
#endif
virtual bool BIsKeyLess( const CSharedObject & soRHS ) const ;
virtual void Copy( const CSharedObject & soRHS );
virtual void Dump() const;
virtual CUtlString GetDebugString() const OVERRIDE;
void SerializeToProtoBufItem( CSOEconItem &msgItem ) const;
void DeserializeFromProtoBufItem( const CSOEconItem &msgItem );
#ifdef GC_DLL
CEconItem* YieldingGetInteriorItem();
const CEconItem* YieldingGetInteriorItem() const { return const_cast<CEconItem *>(this)->YieldingGetInteriorItem(); }
void SetEquippedThisGameServerSession( bool bEquipped ) { m_bEquippedThisGameServerSession = bEquipped; }
bool EquippedThisGameServerSession() const { return m_bEquippedThisGameServerSession; }
#endif
// Non-yielding -- will return current interior item if it exists and is already loaded
// but will make no attempt to load.
CEconItem* GetInteriorItem();
const CEconItem* GetInteriorItem() const { return const_cast<CEconItem *>(this)->GetInteriorItem(); }
const CEconItemCustomData* GetCustomData() const { return m_pCustomData; }
void OnTraded( uint32 unTradabilityDelaySeconds );
void OnReceivedFromMarket( bool bFromRollback );
protected:
// Call this when the appearance of this item changes (ex. paintkit, style, festive). This will
// cause the icon to be lazily re-evaluated (ie. so that changing the style will change the icon)
void DirtyIconURL() { m_pszLargeIcon = NULL; m_pszSmallIcon = NULL; }
// CSharedObject
// adapted from CSchemaSharedObject
void GetDirtyColumnSet( const CUtlVector< int > &fields, GCSDK::CColumnSet &cs ) const;
void EnsureCustomDataExists();
bool BYieldingLoadInteriorItem();
void OnTransferredOwnership();
// Internal attribute interface.
friend class CWebAPIStringExporterAttributeIterator;
friend class CAttributeToStringIterator;
attribute_t& AddDynamicAttributeInternal(); // add another chunk of data to our internal storage to store a new attribute -- initialization is the responsibility of the caller
attribute_t *FindDynamicAttributeInternal( const CEconItemAttributeDefinition *pAttrDef ); // search for an instance of a dynamic attribute with this definition -- ignores static properties, etc. and will return NULL if not found
int GetDynamicAttributeCountInternal() const; // how many attributes are there attached to this instance?
attribute_t& GetMutableDynamicAttributeInternal( int iAttrIndexIntoArray ); // get a writable version of our attribute memory base chunk (added by AddDynamicAttributeInternal) for this index (same "array" as GetDynamicAttributeCountInternal)
const attribute_t& GetDynamicAttributeInternal( int iAttrIndexIntoArray ) const // read-only version of our attribute memory base chunk for this index (same "array" as GetDynamicAttributeCountInternal)
{
return const_cast<CEconItem *>( this )->GetMutableDynamicAttributeInternal( iAttrIndexIntoArray );
}
const EquippedInstance_t *FindEquippedInstanceForClass( equipped_class_t nClass ) const;
void InternalVerifyEquipInstanceIntegrity() const;
struct dirty_bits_t
{
// other
uint8 m_bInUse : 1;
uint8 m_bHasEquipSingleton : 1;
uint8 m_bHasAttribSingleton: 1;
};
mutable const char* m_pszSmallIcon;
mutable const char* m_pszLargeIcon;
public:
// data that is most commonly changed
uint64 m_ulID; // Item ID
uint32 m_unAccountID; // Item Owner
uint32 m_unInventory; // App managed int representing inventory placement
item_definition_index_t m_unDefIndex; // Item definition index
uint8 m_unLevel; // Item Level
uint8 m_nQuality; // Item quality (rarity)
uint8 m_unFlags; // Flags
uint8 m_unOrigin; // Origin (eEconItemOrigin)
style_index_t m_unStyle; // Style
dirty_bits_t m_dirtyBits; // dirty bits
// Fields that we often have zero or one of, but not often more
EquippedInstance_t m_EquipInstanceSingleton; // Where the item is equipped. Valid only if m_bHasEquipSingleton and there is no custom data
attribute_t m_CustomAttribSingleton; // Custom attribute. Valid only if m_bHasAttribSingleton and there is no custom data
// optional data (custom name, additional attributes, etc.)
CEconItemCustomData *m_pCustomData;
#ifdef GC_DLL
private:
bool m_bEquippedThisGameServerSession;
#endif // GC_DLL
};
//-----------------------------------------------------------------------------
// Purpose: Storage for data that is not commonly changed in CEconItem, primarily
// as a memory savings mechanism.
//-----------------------------------------------------------------------------
class CEconItemCustomData
{
public:
CEconItemCustomData()
: m_pInteriorItem( NULL )
, m_ulOriginalID( INVALID_ITEM_ID )
, m_unQuantity( 1 )
, m_vecAttributes( /* grow size: */ 1, /* init size: */ 0 )
, m_vecEquipped( /* grow size: */ 1, /* init size: */ 0 )
{}
~CEconItemCustomData();
CUtlVector< CEconItem::attribute_t > m_vecAttributes;
CEconItem* m_pInteriorItem;
uint64 m_ulOriginalID; // Original Item ID
uint16 m_unQuantity; // Consumable stack count (ammo, money, etc)
CUtlVector<CEconItem::EquippedInstance_t> m_vecEquipped;
static void FreeAttributeMemory( CEconItem::attribute_t *pAttrib );
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconItemCustomData );
#endif
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < typename TAttribInMemoryType >
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::LoadByteStreamToEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const std::string& sBytes ) const
{
Assert( pTargetItem );
Assert( pAttrDef );
TAttribInMemoryType typedValue;
ConvertByteStreamToTypedValue( sBytes, &typedValue );
pTargetItem->SetDynamicAttributeValue( pAttrDef, typedValue );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < typename TAttribInMemoryType >
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::ConvertEconAttributeValueToByteStream( const attribute_data_union_t& value, ::std::string *out_psBytes ) const
{
ConvertTypedValueToByteStream( GetTypedValueContentsFromEconAttributeValue( value ), out_psBytes );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < typename TAttribInMemoryType >
/*virtual*/ void ISchemaAttributeTypeBase<TAttribInMemoryType>::LoadEconAttributeValue( CEconItem *pTargetItem, const CEconItemAttributeDefinition *pAttrDef, const union attribute_data_union_t& value ) const
{
pTargetItem->SetDynamicAttributeValue( pAttrDef, GetTypedValueContentsFromEconAttributeValue( value ) );
}
#ifdef GC_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
struct CEconItemEquipInstanceHelpers
{
static void AssignItemToSlot( CEconSharedObjectCache *pSOCache, CEconItem *pItem, equipped_class_t unClass, equipped_slot_t unSlot, CEconUserSession *pOptionalSession = NULL );
};
#endif // GC_DLL
void YieldingAddAuditRecord( GCSDK::CSQLAccess *sqlAccess, CEconItem *pItem, uint32 unOwnerID, EItemAction eAction, uint32 unData );
void YieldingAddAuditRecord( GCSDK::CSQLAccess *sqlAccess, uint64 ulItemID, uint32 unOwnerID, EItemAction eAction, uint32 unData );
bool YieldingAddItemToDatabase( CEconItem *pItem, const CSteamID & steamID, EItemAction eAction, uint32 unData );
//-----------------------------------------------------------------------------
// Purpose: wrap the idea of "get a loot list from this item"; some loot lists
// are static definitions and some are temporary heap-allocated objects
// and this means you don't care which you're dealing with until we
// come up with a better interface
//-----------------------------------------------------------------------------
class CCrateLootListWrapper
{
public:
CCrateLootListWrapper( const IEconItemInterface *pEconItem )
: m_pLootList( NULL )
, m_unAuditDetailData( 0 )
, m_bIsDynamicallyAllocatedLootList( false )
{
Assert( pEconItem );
if ( !BAttemptCrateSeriesInitialization( pEconItem )
&& !BAttemptLootListStringInitialization( pEconItem )
&& !BAttemptLineItemInitialization( pEconItem ) )
{
// We don't actually have anything to do here. We'll return NULL when someone asks for our
// loot list and we're done.
}
}
~CCrateLootListWrapper()
{
if ( m_bIsDynamicallyAllocatedLootList )
{
delete m_pLootList;
}
}
const IEconLootList *GetEconLootList() const
{
return m_pLootList;
}
uint32 GetAuditDetailData() const
{
return m_unAuditDetailData;
}
private:
CCrateLootListWrapper( const CCrateLootListWrapper& ); // intentionally unimplemented
void operator=( const CCrateLootListWrapper& ); // intentionally unimplemented
private:
// Look for an attribute that specifies a crate series.
MUST_CHECK_RETURN bool BAttemptCrateSeriesInitialization( const IEconItemInterface *pEconItem );
// Look for an attribute that specifies a loot list by string name.
MUST_CHECK_RETURN bool BAttemptLootListStringInitialization( const IEconItemInterface *pEconItem );
// Look for a line-item-per-attribute list.
MUST_CHECK_RETURN bool BAttemptLineItemInitialization( const IEconItemInterface *pEconItem );
private:
const IEconLootList *m_pLootList;
uint32 m_unAuditDetailData;
bool m_bIsDynamicallyAllocatedLootList;
};
//-----------------------------------------------------------------------------
// Purpose: Maintains a handle to an CEconItem. If the item gets deleted, this
// handle will return NULL when dereferenced
//-----------------------------------------------------------------------------
class CEconItemHandle : GCSDK::ISharedObjectListener
{
public:
CEconItemHandle()
: m_pItem( NULL )
, m_iItemID( INVALID_ITEM_ID )
{}
CEconItemHandle( CEconItem* pItem )
: m_pItem( pItem )
{
SetItem( pItem );
}
virtual ~CEconItemHandle();
void SetItem( CEconItem* pItem );
operator CEconItem *( void ) const
{
return m_pItem;
}
CEconItem* operator->( void ) const
{
return m_pItem;
}
CEconItem* operator=( CEconItem* pRhs )
{
SetItem( pRhs );
return m_pItem;
}
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE{}
private:
void UnsubscribeFromSOEvents();
CEconItem* m_pItem; // The item
itemid_t m_iItemID; // The stored itemID
CSteamID m_OwnerSteamID; // Steam ID of the item owner. Used for registering/unregistering from SOCache
};
#endif // ECONITEM_H
+970
View File
@@ -0,0 +1,970 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds constants for the econ item system
//
//=============================================================================
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *g_szQualityStrings[] =
{
"Normal",
"rarity1", // Genuine
"rarity2", // Customized
"vintage", // Vintage has to stay at 3 for backwards compatibility
"rarity3", // Well-Designed
"rarity4", // Unusual
"Unique",
"community",
"developer",
"selfmade",
"customized",
"strange",
"completed",
"haunted",
"collectors",
"paintkitWeapon",
"default", // AE_RARITY_DEFAULT,
"common", // AE_RARITY_COMMON,
"uncommon", // AE_RARITY_UNCOMMON,
"rare", // AE_RARITY_RARE,
"mythical", // AE_RARITY_MYTHICAL,
"legendary", // AE_RARITY_LEGENDARY,
"ancient", // AE_RARITY_ANCIENT,
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityStrings ) == AE_MAX_TYPES );
const char *EconQuality_GetQualityString( EEconItemQuality eQuality )
{
// This is a runtime check and not an assert because we could theoretically bounce the GC with new
// qualities while the client is running.
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
return g_szQualityStrings[ eQuality ];
return NULL;
}
EEconItemQuality EconQuality_GetQualityFromString( const char* pszQuality )
{
// Convert to lowercase
CUtlString strLoweredInput( pszQuality );
strLoweredInput.ToLower();
// Guaranteed with the compile time assert above that AE_MAX_TYPES is
// the size of the string qualities
for( int i = 0; i < AE_MAX_TYPES; ++i )
{
// Convert to lowercase
CUtlString strLoweredQuality( g_szQualityStrings[i] );
strLoweredQuality.ToLower();
if( !Q_stricmp( strLoweredInput.Get(), strLoweredQuality.Get() ) )
return EEconItemQuality(i);
}
return AE_UNDEFINED;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *g_szQualityColorStrings[] =
{
"QualityColorNormal",
"QualityColorrarity1",
"QualityColorrarity2",
"QualityColorVintage",
"QualityColorrarity3",
"QualityColorrarity4", // AE_UNUSUAL
"QualityColorUnique",
"QualityColorCommunity",
"QualityColorDeveloper",
"QualityColorSelfMade",
"QualityColorSelfMadeCustomized",
"QualityColorStrange",
"QualityColorCompleted",
"QualityColorHaunted", // AE_HAUNTED
"QualityColorCollectors", // AE_COLLECTORS
"QualityColorPaintkitWeapon", // AE_PAINTKITWEAPON
"ItemRarityDefault" , // AE_RARITY_DEFAULT,
"ItemRarityCommon" , // AE_RARITY_COMMON,
"ItemRarityUncommon" , // AE_RARITY_UNCOMMON,
"ItemRarityRare" , // AE_RARITY_RARE,
"ItemRarityMythical" , // AE_RARITY_MYTHICAL,
"ItemRarityLegendary" , // AE_RARITY_LEGENDARY,
"ItemRarityAncient" , // AE_RARITY_ANCIENT,
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityColorStrings ) == AE_MAX_TYPES );
const char *EconQuality_GetColorString( EEconItemQuality eQuality )
{
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
return g_szQualityColorStrings[ eQuality ];
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *g_szQualityLocalizationStrings[] =
{
"#Normal",
"#rarity1", // Genuine
"#rarity2",
"#vintage",
"#rarity3", // Artisan
"#rarity4", // Unusual
"#unique",
"#community",
"#developer",
"#selfmade",
"#customized",
"#strange",
"#completed",
"#haunted",
"#collectors",
"#paintkitWeapon",
"#Rarity_Default",
"#Rarity_Common",
"#Rarity_Uncommon",
"#Rarity_Rare",
"#Rarity_Mythical",
"#Rarity_Legendary",
"#Rarity_Ancient"
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityLocalizationStrings ) == AE_MAX_TYPES );
const char *EconQuality_GetLocalizationString( EEconItemQuality eQuality )
{
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
return g_szQualityLocalizationStrings[ eQuality ];
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Sort order for rarities
// Small Numbers sort to front
//-----------------------------------------------------------------------------
int g_nRarityScores[] =
{
15, // AE_NORMAL,
10, // AE_RARITY1, // Geniune
102, // AE_RARITY2, // Customized (unused)
11, // AE_VINTAGE,
101, // AE_RARITY3, // Artisan (unused)
0, // AE_UNUSUAL,
14, // AE_UNIQUE,
-1, // AE_COMMUNITY,
-3, // AE_DEVELOPER,
-2, // AE_SELFMADE,
100, // AE_CUSTOMIZED, // Unused
9, // AE_STRANGE,
103, // AE_COMPLETED, // Unused
13, // AE_HAUNTED
12, // AE_COLLECTORS
8, // AE_PAINTKITWEAPON
7, // AE_RARITY_DEFAULT,
6, // AE_RARITY_COMMON,
5, // AE_RARITY_UNCOMMON,
4, // AE_RARITY_RARE,
3, // AE_RARITY_MYTHICAL,
2, // AE_RARITY_LEGENDARY,
1, // AE_RARITY_ANCIENT,
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_nRarityScores ) == AE_MAX_TYPES );
//-----------------------------------------------------------------------------
int EconQuality_GetRarityScore( EEconItemQuality eQuality )
{
if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
return g_nRarityScores[ eQuality ];
return 0;
}
//-----------------------------------------------------------------------------
const char *g_pchWearAmountStrings[] =
{
"#TFUI_InvTooltip_None",
"#TFUI_InvTooltip_FactoryNew",
"#TFUI_InvTooltip_MinimalWear",
"#TFUI_InvTooltip_FieldTested",
"#TFUI_InvTooltip_WellWorn",
"#TFUI_InvTooltip_BattleScared"
};
//-----------------------------------------------------------------------------
int EconWear_ToIntCategory( float flWear )
{
if ( flWear <= 0.2f )
{
return 1;
}
else if ( flWear <= 0.4f )
{
return 2;
}
else if ( flWear <= 0.6f )
{
return 3;
}
else if ( flWear <= 0.8f )
{
return 4;
}
else if ( flWear <= 1.0f )
{
return 5;
}
return 3; // default wear
}
// -------------------------------------------------------------------------
// Shim to return a value for buckets. For strange we bucket all of them in to 1 non-instance data group
int EconStrange_ToStrangeBucket( float value )
{
return 0;
}
float EconStrange_FromStrangeBucket( int value )
{
return 0;
}
//-----------------------------------------------------------------------------
const char *GetWearLocalizationString( float flWear )
{
int nIndex = EconWear_ToIntCategory( flWear );
return g_pchWearAmountStrings[ nIndex ];
}
//-----------------------------------------------------------------------------
bool EconWear_IsValidValue( int nWear )
{
return nWear > 0 && nWear <= 5;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CSchemaColorDefHandle g_AttribColorDefs[] =
{
CSchemaColorDefHandle( "desc_level" ), // ATTRIB_COL_LEVEL
CSchemaColorDefHandle( "desc_attrib_neutral" ), // ATTRIB_COL_NEUTRAL
CSchemaColorDefHandle( "desc_attrib_positive" ), // ATTRIB_COL_POSITIVE
CSchemaColorDefHandle( "desc_attrib_negative" ), // ATTRIB_COL_NEGATIVE
CSchemaColorDefHandle( "desc_itemset_name" ), // ATTRIB_COL_ITEMSET_NAME
CSchemaColorDefHandle( "desc_itemset_equipped" ), // ATTRIB_COL_ITEMSET_EQUIPPED
CSchemaColorDefHandle( "desc_itemset_missing" ), // ATTRIB_COL_ITEMSET_MISSING
CSchemaColorDefHandle( "desc_bundle" ), // ATTRIB_COL_BUNDLE_ITEM
CSchemaColorDefHandle( "desc_limited_use" ), // ATTRIB_COL_LIMITED_USE
CSchemaColorDefHandle( "desc_flags" ), // ATTRIB_COL_component_flags
CSchemaColorDefHandle( "desc_limited_quantity" ), // ATTRIB_COL_LIMITED_QUANTITY
CSchemaColorDefHandle( "desc_default" ), // ATTRIB_COL_RARITY_DEFAULT
CSchemaColorDefHandle( "desc_common" ), // ATTRIB_COL_RARITY_COMMON
CSchemaColorDefHandle( "desc_uncommon" ), // ATTRIB_COL_RARITY_UNCOMMON
CSchemaColorDefHandle( "desc_rare" ), // ATTRIB_COL_RARITY_RARE
CSchemaColorDefHandle( "desc_mythical" ), // ATTRIB_COL_RARITY_MYTHICAL
CSchemaColorDefHandle( "desc_legendary" ), // ATTRIB_COL_RARITY_LEGENDARY
CSchemaColorDefHandle( "desc_ancient" ), // ATTRIB_COL_RARITY_ANCIENT
CSchemaColorDefHandle( "desc_immortal" ), // ATTRIB_COL_RARITY_IMMORTAL
CSchemaColorDefHandle( "desc_arcana" ), // ATTRIB_COL_RARITY_ARCANA
CSchemaColorDefHandle( "desc_strange" ), // ATTRIB_COL_STRANGE
CSchemaColorDefHandle( "desc_unusual" ), // ATTRIB_COL_UNUSUAL
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_AttribColorDefs ) == NUM_ATTRIB_COLORS );
attrib_colors_t GetAttribColorIndexForName( const char* pszName )
{
for ( int i = 0; i < NUM_ATTRIB_COLORS; ++i )
{
if ( !Q_strcmp( g_AttribColorDefs[i].GetName(), pszName ) )
return (attrib_colors_t)i;
}
return (attrib_colors_t)0;
}
const char *GetColorNameForAttribColor( attrib_colors_t unAttribColor )
{
Assert( unAttribColor >= 0 );
Assert( unAttribColor < NUM_ATTRIB_COLORS );
return g_AttribColorDefs[unAttribColor]
? g_AttribColorDefs[unAttribColor]->GetColorName()
: "ItemAttribNeutral";
}
const char *GetHexColorForAttribColor( attrib_colors_t unAttribColor )
{
Assert( unAttribColor >= 0 );
Assert( unAttribColor < NUM_ATTRIB_COLORS );
return g_AttribColorDefs[unAttribColor]
? g_AttribColorDefs[unAttribColor]->GetHexColor()
: "#ebe2ca";
}
entityquality_t GetItemQualityFromString( const char *sQuality )
{
for ( int i = 0; i < AE_MAX_TYPES; i++ )
{
if ( !Q_strnicmp( sQuality, g_szQualityStrings[i], 16 ) )
return (entityquality_t)i;
}
return AE_NORMAL;
}
const char *g_szRecipeCategoryStrings[] =
{
"crafting", // RECIPE_CATEGORY_CRAFTINGITEMS = 0,
"commonitem", // RECIPE_CATEGORY_COMMONITEMS,
"rareitem", // RECIPE_CATEGORY_RAREITEMS,
"special", // RECIPE_CATEGORY_SPECIAL,
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_szRecipeCategoryStrings ) == NUM_RECIPE_CATEGORIES );
//-----------------------------------------------------------------------------
// Item acquisition.
//-----------------------------------------------------------------------------
// Strings shown to the local player in the pickup dialog
const char *g_pszItemPickupMethodStrings[] =
{
"#NewItemMethod_Dropped", // UNACK_ITEM_DROPPED = 1,
"#NewItemMethod_Crafted", // UNACK_ITEM_CRAFTED,
"#NewItemMethod_Traded", // UNACK_ITEM_TRADED,
"#NewItemMethod_Purchased", // UNACK_ITEM_PURCHASED,
"#NewItemMethod_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
"#NewItemMethod_Gifted", // UNACK_ITEM_GIFTED,
"#NewItemMethod_Support", // UNACK_ITEM_SUPPORT,
"#NewItemMethod_Promotion", // UNACK_ITEM_PROMOTION,
"#NewItemMethod_Earned", // UNACK_ITEM_EARNED,
"#NewItemMethod_Refunded", // UNACK_ITEM_REFUNDED,
"#NewItemMethod_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED,
"#NewItemMethod_Foreign", // UNACK_ITEM_FOREIGN,
"#NewItemMethod_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
"#NewItemMethod_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
"#NewItemMethod_PreviewItemPurchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
"#NewItemMethod_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
"#NewItemMethod_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
"#NewItemMethod_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
"#NewItemMethod_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
"#NewItemMethod_CommunityMarketPurchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
"#NewItemMethod_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
"#NewItemMethod_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
"#NewItemMethod_QuestLoaner", // UNACK_ITEM_QUEST_LOANER
"#NewItemMethod_TradeUp", // UNACK_ITEM_TRADE_UP
"#NewItemMethod_QuestMerasmissionOutput", //UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
"#NewItemMethod_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
#ifdef ENABLE_STORE_RENTAL_BACKEND
"#NewItemMethod_RentalPurchase", // UNACK_ITEM_RENTAL_PURCHASE
#endif
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStrings ) == (UNACK_NUM_METHODS - 1) ); // -1 because UNACK_ITEM_DROPPED is index 1, not 0
const char *g_pszItemPickupMethodStringsUnloc[] =
{
"dropped", // UNACK_ITEM_DROPPED = 1,
"crafted", // UNACK_ITEM_CRAFTED,
"traded", // UNACK_ITEM_TRADED,
"purchased", // UNACK_ITEM_PURCHASED,
"found_in_crate", // UNACK_ITEM_FOUND_IN_CRATE,
"gifted", // UNACK_ITEM_GIFTED,
"support", // UNACK_ITEM_SUPPORT,
"promotion", // UNACK_ITEM_PROMOTION,
"earned", // UNACK_ITEM_EARNED,
"refunded", // UNACK_ITEM_REFUNDED,
"gift_wrapped", // UNACK_ITEM_GIFT_WRAPPED
"foreign", // UNACK_ITEM_FOREIGN
"collection_reward",// UNACK_ITEM_COLLECTION_REWARD
"preview_item", // UNACK_ITEM_PREVIEW_ITEM
"preview_item_purchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
"periodic_score_reward", // UNACK_ITEM_PERIODIC_SCORE_REWARD
"mvm_badge_completion_reward", // UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
"mvm_squad_surplus_reward", // UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
"holiday_gift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
"market_purchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
"recipe_output", // UNACK_ITEM_RECIPE_OUTPUT
"hidden_quest", // UNACK_ITEM_HIDDEN_QUEST_ITEM
"quest_output", // UNACK_ITEM_QUEST_OUTPUT
"trade_up", // UNACK_ITEM_TRADE_UP
"quest_output", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
"viral_competitive_beta_pass", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
#ifdef ENABLE_STORE_RENTAL_BACKEND
"rental_purchase", // UNACK_ITEM_RENTAL_PURCHASE
#endif
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStringsUnloc ) == (UNACK_NUM_METHODS - 1) );
// Strings shown to other players in the chat dialog
const char *g_pszItemFoundMethodStrings[] =
{
"#Item_Found", // UNACK_ITEM_DROPPED = 1,
"#Item_Crafted", // UNACK_ITEM_CRAFTED,
"#Item_Traded", // UNACK_ITEM_TRADED,
NULL, // UNACK_ITEM_PURCHASED,
"#Item_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
"#Item_Gifted", // UNACK_ITEM_GIFTED,
NULL, // UNACK_ITEM_SUPPORT,
NULL, // UNACK_ITEM_PROMOTION
"#Item_Earned", // UNACK_ITEM_EARNED
"#Item_Refunded", // UNACK_ITEM_REFUNDED
"#Item_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED
"#Item_Foreign", // UNACK_ITEM_FOREIGN
"#Item_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
"#Item_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
"#Item_PreviewItemPurchased",// UNACK_ITEM_PREVIEW_ITEM_PURCHASED
"#Item_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
"#Item_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
"#Item_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
"#Item_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
NULL, // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
"#Item_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
"#Item_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
NULL, // UNACK_ITEM_QUEST_LOANER
"#Item_TradeUp", // UNACK_ITEM_TRADE_UP
"#Item_QuestMerasmissionOutput", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
"#Item_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
#ifdef ENABLE_STORE_RENTAL_BACKEND
NULL, // UNACK_ITEM_RENTAL_PURCHASE
#endif
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemFoundMethodStrings ) == (UNACK_NUM_METHODS - 1) );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
struct strange_attr_set_t
{
strange_attr_set_t( const char *pScoreAttrName, const char *pTypeAttrName, const char *pRestrictionAttrName, const char *pRestrictionValueAttrName, bool bIsUserCustomizable )
: m_attrScore( pScoreAttrName )
, m_attrType( pTypeAttrName )
, m_attrRestriction( pRestrictionAttrName )
, m_attrRestrictionValue( pRestrictionValueAttrName )
, m_bIsUserCustomizable( bIsUserCustomizable )
{
//
}
CSchemaAttributeDefHandle m_attrScore;
CSchemaAttributeDefHandle m_attrType;
CSchemaAttributeDefHandle m_attrRestriction;
CSchemaAttributeDefHandle m_attrRestrictionValue;
bool m_bIsUserCustomizable;
};
strange_attr_set_t g_KillEaterAttr[] =
{
strange_attr_set_t( "kill eater", "kill eater score type", "strange restriction type 1", "strange restriction value 1", false ),
strange_attr_set_t( "kill eater 2", "kill eater score type 2", "strange restriction type 2", "strange restriction value 2", false ),
strange_attr_set_t( "kill eater 3", "kill eater score type 3", "strange restriction type 3", "strange restriction value 3", false ),
// assumption: all of the user-customizable attributes will follow all of the schema-specified attributes
strange_attr_set_t( "kill eater user 1", "kill eater user score type 1", "strange restriction user type 1", "strange restriction user value 1", true ),
strange_attr_set_t( "kill eater user 2", "kill eater user score type 2", "strange restriction user type 2", "strange restriction user value 2", true ),
strange_attr_set_t( "kill eater user 3", "kill eater user score type 3", "strange restriction user type 3", "strange restriction user value 3", true ),
};
int GetKillEaterAttrCount()
{
#ifdef DBGFLAG_ASSERT
// Verify our commented assumption that all of the non-user-customizable attributes will be followed by
// all of the user-customizable attributes.
bool bInUserCustomizableBlock = false;
for ( int i = 0; i < ARRAYSIZE( g_KillEaterAttr ); i++ )
{
if ( bInUserCustomizableBlock )
{
AssertMsg( g_KillEaterAttr[i].m_bIsUserCustomizable, "Ordering assumption for g_KillEaterAttr violated! User-customizable attributes should all be at the end of the list!" );
}
bInUserCustomizableBlock |= g_KillEaterAttr[i].m_bIsUserCustomizable;
}
#endif
return ARRAYSIZE( g_KillEaterAttr );
}
int GetKillEaterAttrCount_UserCustomizable()
{
int iCount = 0;
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
if ( GetKillEaterAttr_IsUserCustomizable( i ) )
{
iCount++;
}
}
return iCount;
}
const CEconItemAttributeDefinition *GetKillEaterAttr_Score( int i )
{
Assert( i >= 0 );
Assert( i < GetKillEaterAttrCount() );
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrScore;
AssertMsg1( pAttrRes, "Missing Killeater attr score %s", g_KillEaterAttr[ i ].m_attrScore.GetName() );
return pAttrRes;
}
const CEconItemAttributeDefinition *GetKillEaterAttr_Type( int i )
{
Assert( i >= 0 );
Assert( i < GetKillEaterAttrCount() );
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrType;
AssertMsg1( pAttrRes, "Missing Killeater attr type %s", g_KillEaterAttr[ i ].m_attrType.GetName() );
return pAttrRes;
}
const CEconItemAttributeDefinition *GetKillEaterAttr_Restriction( int i )
{
Assert( i >= 0 );
Assert( i < GetKillEaterAttrCount() );
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestriction;
AssertMsg1( pAttrRes, "Missing Killeater attr restriction %s", g_KillEaterAttr[ i ].m_attrRestriction.GetName() );
return pAttrRes;
}
const CEconItemAttributeDefinition *GetKillEaterAttr_RestrictionValue( int i )
{
Assert( i >= 0 );
Assert( i < GetKillEaterAttrCount() );
const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestrictionValue;
AssertMsg1( pAttrRes, "Missing Killeater attr restriction value %s", g_KillEaterAttr[ i ].m_attrRestrictionValue.GetName() );
return pAttrRes;
}
bool GetKillEaterAttr_IsUserCustomizable( int i )
{
Assert( i >= 0 );
Assert( i < GetKillEaterAttrCount() );
return g_KillEaterAttr[i].m_bIsUserCustomizable;
}
bool GetKilleaterValueByEvent( const IEconItemInterface* pItem, const kill_eater_event_t& EEventType, uint32& value )
{
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
const CEconItemAttributeDefinition *pAttribKillEater = GetKillEaterAttr_Score( i );
const CEconItemAttributeDefinition *pAttribKillEaterScoreType = GetKillEaterAttr_Type( i );
Assert( pAttribKillEater && pAttribKillEaterScoreType );
if ( !pAttribKillEater || !pAttribKillEaterScoreType )
return false;
// make sure this item even has a kill count attribute we're looking for
uint32 unKillEaterAttrValue;
if ( !pItem->FindAttribute( pAttribKillEater, &unKillEaterAttrValue ) )
continue;
uint32 unKillEaterScoreTypeAttrValue = kKillEaterEvent_PlayerKill;
float fKillEaterScoreTypeAttrValue;
if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttribKillEaterScoreType, &fKillEaterScoreTypeAttrValue ) )
{
unKillEaterScoreTypeAttrValue = (uint32)fKillEaterScoreTypeAttrValue;
}
// this isn't the attribute we're trying to find
if ( EEventType != (kill_eater_event_t)unKillEaterScoreTypeAttrValue )
continue;
value = unKillEaterAttrValue;
return true;
}
return false;
}
// Does this thing have kill eater
bool BIsItemStrange( const IEconItemInterface *pItem )
{
// Go over the attributes of the item, if it has any strange attributes the item is strange and don't apply
uint32 unKillEaterAttr;
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
if ( pItem->FindAttribute( GetKillEaterAttr_Score( i ), &unKillEaterAttr ) )
{
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Get a localization token that describes why an item is not usable
// in the trade-up crafting. Returns NULL if no reason. Can pass in
// another item to compare against, which causes extra consistency checks
//-----------------------------------------------------------------------------
const char* GetCollectionCraftingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
{
if ( !pTestItem )
{
return "#TF_CollectionCrafting_NoItem";
}
// Needs to have a collection
const CEconItemCollectionDefinition* pTestCollection = pTestItem->GetItemDefinition()->GetItemCollectionDefinition();
if ( !pTestCollection )
{
return "#TF_CollectionCrafting_NoCollection";
}
// Make sure this item is a part of the collection it claims to be in
{
item_definition_index_t nThisDefIndex = pTestItem->GetItemDefIndex();
bool bFound = false;
for( int i=0; i < pTestCollection->m_iItemDefs.Count() && !bFound; ++i )
{
bFound |= pTestCollection->m_iItemDefs[i] == nThisDefIndex;
}
if ( !bFound )
{
return "#TF_CollectionCrafting_NoCollection";
}
}
// Needs rarity
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
if( nRarity == k_unItemRarity_Any )
{
return "#TF_CollectionCrafting_NoRarity";
}
// Can't use items with rarity at the "top" of a collection (what would they craft into?)
if ( nRarity == pTestCollection->GetMaxRarity() )
{
return "#TF_CollectionCrafting_MaxRarity";
}
// No self mades or community items
uint32 eQuality = pTestItem->GetQuality();
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
{
return "#TF_CollectionCrafting_NoUnusual";
}
// This is how we test for unusuals. Don't let unusuals be crafted
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
{
return "#TF_CollectionCrafting_NoUnusual";
}
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
{
return "#TF_CollectionCrafting_NoUnusual";
}
// Not allowed to be crafted?
if ( !pTestItem->IsUsableInCrafting() )
{
return "#TF_CollectionCrafting_NotCraftable";
}
// If another item was passed in, we have a few consistency checks to make
if ( pSourceItem )
{
// Need to have the same rarity
if ( nRarity != pSourceItem->GetItemDefinition()->GetRarity() )
{
return "#TF_CollectionCrafting_MismatchRarity";
}
// Need to have the same strangeness
if ( BIsItemStrange( pSourceItem ) != BIsItemStrange( pTestItem ) )
{
return "#TF_CollectionCrafting_MismatchStrange";
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Get a localization token that describes why an item is not usable
// in the Halloween Offering. Returns NULL if no reason. Can pass in
// another item to compare against, which causes extra consistency checks
//-----------------------------------------------------------------------------
const char* GetHalloweenOfferingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
{
// Must either be a Cosmetic
// Taunt
// Allowable Tool (Strange part, Paint, name tag, killstreak). Not crates, keys
// Marketable Weapon ie Strange, Genuine, Vintage, paintkit
// Cannot be Unusual
if ( !pTestItem )
{
return "#TF_CollectionCrafting_NoItem";
}
// No self mades or community items
uint32 eQuality = pTestItem->GetQuality();
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
{
return "#TF_CollectionCrafting_NoUnusual";
}
// This is how we test for unusuals. Don't let unusuals be crafted
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
{
return "#TF_CollectionCrafting_NoUnusual";
}
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
{
return "#TF_CollectionCrafting_NoUnusual";
}
// Invalid Items
static CSchemaAttributeDefHandle pAttrDef_CannotTransmute( "cannot_transmute" );
if ( pTestItem->FindAttribute( pAttrDef_CannotTransmute ) )
{
return "#TF_HalloweenOffering_Invalid";
}
static CSchemaAttributeDefHandle pAttrDef_CannotDelete( "cannot delete" );
if ( pTestItem->FindAttribute( pAttrDef_CannotDelete ) )
{
return "#TF_HalloweenOffering_Invalid";
}
const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
if ( pItemDef == NULL )
{
return "#TF_CollectionCrafting_NoItem";
}
if ( pTestItem->IsTemporaryItem() )
{
return "#TF_CollectionCrafting_NoItem";
}
// If you are a taunt or a cosmetic you are allowed
if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT )
{
// do not 'medal' equip region items
if ( pTestItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "medal" ) )
{
return "#TF_HalloweenOffering_Invalid";
}
return NULL;
}
// Do not allow Crates
if ( ( pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE ) != 0 )
{
return "#TF_HalloweenOffering_Invalid";
}
// Cause of weird legacy items lets be explicit about what we allow
if ( pItemDef->IsTool() )
{
// ignore everything that is not a paint can tool
const IEconTool *pEconTool = pItemDef->GetEconTool();
if ( !pEconTool )
return "#TF_HalloweenOffering_Invalid";
const char *pToolType = pEconTool->GetTypeName();
if ( !V_strcmp( pToolType, "paint_can" ) )
return NULL;
else if ( !V_strcmp( pToolType, "strange_part" ) )
return NULL;
else if ( !V_strcmp( pToolType, "name" ) )
return NULL;
else if ( !V_strcmp( pToolType, "desc" ) )
return NULL;
else if ( !V_strcmp( pToolType, "killstreakifier" ) )
return NULL;
else if ( !V_strcmp( pToolType, "strangifier" ) )
return NULL;
// Not a tool we are allowing
return "#TF_HalloweenOffering_Invalid";
}
// Otherwise you must be a weapon or we won't allow
if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PRIMARY
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_SECONDARY
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MELEE
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_BUILDING
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA
|| pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA2
) {
// Must be strange, genuine, vintage, haunted or paintkit (ie a marketable weapon)
eQuality = pTestItem->GetQuality();
if ( eQuality == AE_RARITY1
|| eQuality == AE_VINTAGE
|| eQuality == AE_HAUNTED
|| eQuality == AE_COLLECTORS
|| eQuality == AE_PAINTKITWEAPON
) {
return NULL;
}
// Weapons with rarity are allowed
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
if ( nRarity != k_unItemRarity_Any )
{
return NULL;
}
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
// See if we've got any strange attributes.
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
{
return NULL;
}
}
}
return "#TF_HalloweenOffering_Invalid";
}
const char* GetCraftCommonStatClockInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem )
{
if ( !pTestItem )
{
return "#TF_CollectionCrafting_NoItem";
}
// Not allowed to be crafted?
if ( !pTestItem->IsUsableInCrafting() )
{
return "#TF_CollectionCrafting_NotCraftable";
}
// No self mades or community items
uint32 eQuality = pTestItem->GetQuality();
if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
return "#TF_CollectionCrafting_NoUnusual";
// This is how we test for unusuals. Don't let unusuals be crafted
static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
return "#TF_CollectionCrafting_NoUnusual";
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
return "#TF_CollectionCrafting_NoUnusual";
const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
if ( pItemDef == NULL )
return "#TF_CollectionCrafting_NoItem";
if ( pTestItem->IsTemporaryItem() )
return "#TF_CollectionCrafting_NoItem";
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
// See if we've got any strange attributes.
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
{
return NULL;
}
}
// Needs Rarity
uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
if ( nRarity != k_unItemRarity_Any && nRarity > 1 ) // do not allow default nor common rarity
{
return NULL;
}
return "#TF_MannCoTrade_ItemInvalid";
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
enum { kMaxCardUpgradesPerItem = 2 };
int GetMaxCardUpgradesPerItem()
{
return kMaxCardUpgradesPerItem;
}
const CEconItemAttributeDefinition *GetCardUpgradeForIndex( const IEconItemInterface *pItem, int i )
{
Assert( pItem );
Assert( i >= 0 );
Assert( i < kMaxCardUpgradesPerItem );
class CGetNthUserGeneratedAttributeIterator : public IEconItemUntypedAttributeIterator
{
public:
CGetNthUserGeneratedAttributeIterator( int iTargetIndex )
: m_iCount( iTargetIndex )
, m_pAttrDef( NULL )
{
}
virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) OVERRIDE
{
if ( pAttrDef->GetUserGenerationType() != 0 && m_iCount-- == 0 )
{
m_pAttrDef = pAttrDef;
return false;
}
return true;
}
const CEconItemAttributeDefinition *GetAttrDef() const { return m_pAttrDef; }
private:
int m_iCount;
const CEconItemAttributeDefinition *m_pAttrDef;
};
CGetNthUserGeneratedAttributeIterator findNthAttrIterator( i );
pItem->IterateAttributes( &findNthAttrIterator );
return findNthAttrIterator.GetAttrDef();
}
+965
View File
@@ -0,0 +1,965 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ACTUAL_ECON_ITEM_CONSTANTS_H // ECON_ITEM_CONSTANTS_H is used by src/common/econ_item_view.h
#define ACTUAL_ECON_ITEM_CONSTANTS_H
#ifdef _WIN32
#pragma once
#endif
//=============================================================================
// To avoid #include dependency chains, this file should
// contain only constants that do not depend on other
// header files.
// This file is #included in cbase.h to allow schema compiles
// to use these constants to ensure correlation between
// code data structures and database entries
//=============================================================================
typedef uint32 item_price_t; // this is the type that is used to hold currency values for transactions! don't change this without changing the relevant code/databases/etc.
typedef uint8 item_transaction_quantity_t;
class CLocalizationProvider;
enum { kLocalizedPriceSizeInChararacters = 64 };
//-----------------------------------------------------------------------------
// Econ Item testing
//-----------------------------------------------------------------------------
enum testitem_itemtypes_t
{
TI_TYPE_UNKNOWN = -1,
TI_TYPE_WEAPON = 0,
TI_TYPE_HEADGEAR,
TI_TYPE_MISC1,
TI_TYPE_MISC2,
TI_TYPE_COUNT,
};
#define TESTITEM_DEFINITIONS_BEGIN_AT 40000
//-----------------------------------------------------------------------------
// Type IDs for economy classes. These are part of the client-GC protocol and
// should not change if it can be helped
//-----------------------------------------------------------------------------
enum EEconTypeID
{
k_EEconTypeItem =1,
k_EEconTypePlayerInfo =2,
k_EEconTypeClaimCode =3,
k_EEconTypeRecipe =5,
k_EEconTypeGameAccountClient =7,
k_EEconTypeGameAccount =8,
k_EEconTypeDuelSummary =19,
k_EEconTypeExperiment =20,
k_EEconTypeMapContribution =28,
k_EEconTypeGameServerAccount =29,
k_EEconTypeCoachRating =30,
// k_EEconTypeEquipInstance =31, // DEPRECATED
k_EEconTypeSelectedItemPreset =35,
k_EEconTypeItemPresetInstance =36,
k_EEconTypeGameAccountForGameServers =37,
k_EEConTypeWarData =38,
k_EEConTypeLadderData =39,
k_EEConTypeMatchResultPlayerInfo =40,
k_EEconTypeXPSource =41,
k_EEconTypeNotification =42,
};
//-----------------------------------------------------------------------------
// Actions for the ItemAudit table
//-----------------------------------------------------------------------------
// WARNING!!! Values stored in DB. Do not renumber!
enum EItemAction
{
k_EItemActionInvalid = -1,
k_EItemActionGSCreate = 0,
k_EItemActionUnpurchase = 1,
k_EItemActionDelete = 2,
k_EItemActionAwardAchievement = 3,
k_EItemActionBanned = 4,
k_EItemActionQuantityChanged = 5,
k_EItemActionRestored = 6,
k_EItemActionAwardTime = 7,
k_EItemActionManualCreate = 8,
k_EItemActionDrop = 9,
k_EItemActionPickUp = 10,
k_EItemActionCraftDestroy = 11,
k_EItemActionCraftCreate = 12,
k_EItemActionLimitExceeded = 13,
k_EItemActionPurchase = 14,
k_EItemActionNameChanged_Add = 15,
k_EItemActionUnlockCrate_Add = 16,
k_EItemActionPaintItem_Add = 17,
k_EItemActionAutoGrantItem = 18,
k_EItemActionCrossGameAchievement = 19,
k_EItemActionAddItemToSocket_Add = 20,
k_EItemActionAddSocketToItem_Add = 21,
k_EItemActionRemoveSocketItem_Add = 22,
k_EItemActionCustomizeItemTexture_Add = 23,
k_EItemActionItemTraded_Add = 24,
k_EItemActionUseItem = 25,
k_EItemActionAwardGift_Receiver = 26,
k_EItemActionNameChanged_Remove = 27,
k_EItemActionUnlockCrate_Remove = 28,
k_EItemActionPaintItem_Remove = 29,
k_EItemActionAddItemToSocket_Remove = 30,
k_EItemActionAddSocketToItem_Remove = 31,
k_EItemActionRemoveSocketItem_Remove = 32,
k_EItemActionCustomizeItemTexture_Remove = 33,
k_EItemActionItemTraded_Remove = 34,
k_EItemActionUnpackItemBundle = 35,
k_EItemActionCreateItemFromBundle = 36,
k_EItemActionAwardStorePromotionItem = 37,
k_EItemActionConvertItem = 38,
k_EItemActionEarnedItem = 39,
k_EItemActionAwardGift_Giver = 40,
k_EItemActionRefundedItem = 41,
k_EItemActionAwardThirdPartyPromo = 42,
k_EItemActionRemoveItemName_Remove = 43,
k_EItemActionRemoveItemName_Add = 44,
k_EItemActionRemoveItemPaint_Remove = 45,
k_EItemActionRemoveItemPaint_Add = 46,
k_EItemActionHalloweenDrop = 47,
k_EItemActionSteamWorkshopContributor = 48,
k_EItemActionManualOwnershipChange = 49, // when we have bad bugs that corrupt item data and have to fix up rows in the DB by hand
k_EItemActionSupportDelete = 50,
k_EItemActionSupportCreatedByUndo = 51,
k_EItemActionSupportDeletedByUndo = 52,
k_EItemActionSupportQuantityChangedByUndo = 53,
k_EItemActionSupportRename_Add = 54,
k_EItemActionSupportRename_Remove = 55,
k_EItemActionSupportDescribe_Add = 56,
k_EItemActionSupportDescribe_Remove = 57,
k_EItemActionStrangePartApply_Add = 58,
k_EItemActionStrangePartApply_Remove = 59,
k_EItemActionStrangeScoreReset_Add = 60,
k_EItemActionStrangeScoreReset_Remove = 61,
k_EItemActionStrangePartRemove_Add = 62,
k_EItemActionStrangePartRemove_Remove = 63,
k_EItemActionSupportStrangify_Add = 64,
k_EItemActionSupportStrangify_Remove = 65,
k_EItemActionUpgradeCardApply_Add = 66,
k_EItemActionUpgradeCardApply_Remove = 67,
k_EItemActionUpgradeCardRemove_Add = 68,
k_EItemActionUpgradeCardRemove_Remove = 69,
k_EItemActionStrangeRestrictionApply_Add = 70,
k_EItemActionStrangeRestrictionApply_Remove = 71,
k_EItemActionTransmogrify_Add = 72,
k_EItemActionTransmogrify_Remove = 73,
k_EItemActionHalloweenSpellPageAdd_Add = 74,
k_EItemActionHalloweenSpellPageAdd_Remove = 75,
k_EItemActionDev_ClientLootListRoll = 90,
k_EItemActionGiftWrap_Add = 100,
k_EItemActionGiftWrap_Remove = 101,
k_EItemActionGiftDelivery_Add = 102,
k_EItemActionGiftDelivery_Remove = 103,
k_EItemActionGiftUnwrap_Add = 104,
k_EItemActionGiftUnwrap_Remove = 105,
k_EItemActionPackageItem = 106,
k_EItemActionPackageItem_Revoked = 107,
k_EItemActionHandleMapToken = 108,
k_EItemActionCafeOrSchoolItem_Remove = 109,
k_EItemActionVACBanned_Remove = 110,
k_EItemActionUpgradeThirdPartyPromo = 111,
k_EItemActionExpired = 112,
k_EItemActionTradeRollback_Add = 113,
k_EItemActionTradeRollback_Remove = 114,
k_EItemActionCDKeyGrant = 115,
k_EItemActionCDKeyRevoke = 116,
k_EItemActionWeddingRing_Add = 117,
k_EItemActionWeddingRing_Remove = 118,
k_EItemActionWeddingRing_AddPartner = 119,
k_EItemActionEconSetUnowned = 120,
k_EItemActionEconSetOwned = 121,
k_EItemActionStrangifyItem_Add = 122,
k_EItemActionStrangifyItem_Remove = 123,
k_EItemActionConsumeItem_Consume_ToolRemove = 124,
k_EItemActionConsumeItem_Consume_ToolAdd = 125,
k_EItemActionConsumeItem_Consume_InputRemove = 126,
k_EItemActionConsumeItem_Complete_OutputAdd = 127,
k_EItemActionConsumeItem_Complete_ToolRemove = 128,
k_EItemActionItemEaterRecharge_Add = 129,
k_EItemActionItemEaterRecharge_Remove = 130,
k_EItemActionRemoveItemCraftIndex_Remove = 150,
k_EItemActionRemoveItemCraftIndex_Add = 151,
k_EItemActionRemoveItemMakersMark_Remove = 152, // early versions of this will be in the database as 150
k_EItemActionRemoveItemMakersMark_Add = 153, // early versions of this will be in the database as 151 because I am a terrible person
k_EItemActionCollectItem_CollectedItem = 154,
k_EItemActionCollectItem_UpdateCollection = 155,
k_EItemActionCollectItem_RemoveCollection = 156,
k_EItemActionCollectItem_RedeemCollectionReward = 157,
k_EItemActionPreviewItem_BeginPreviewPeriod = 158,
k_EItemActionPreviewItem_EndPreviewPeriodExpired = 159,
k_EItemActionPreviewItem_EndPreviewPeriodItemBought = 160,
k_EItemActionPeriodicScoreReward_Add = 170,
k_EItemActionPeriodicScoreReward_Remove = 171,
k_EItemActionMvM_ChallengeCompleted_RemoveTicket = 180, // we completed a challenge and consumed this ticket as the cost
k_EItemActionMvM_ChallengeCompleted_GrantBadge = 181, // we completed a challenge and granted the player a badge because they didn't have one
k_EItemActionMvM_ChallengeCompleted_UpdateBadgeStamps_Remove = 182, // we completed a challenge and we're crossing an entry off our badge checklist (this may also reset the badge back down to empty if this was the last line item)
k_EItemActionMvM_ChallengeCompleted_UpdateBadgeStamps_Add = 183, // (other half of the above)
k_EItemActionMvM_ChallengeCompleted_GrantMissionCompletionLoot = 184, // we completed a mission in MvM
k_EItemActionMvM_RemoveSquadSurplusVoucher = 185,
k_EItemActionMvM_AwardSquadSurplus_Receiver = 186,
k_EItemActionMvM_AwardSquadSurplus_Giver = 187,
k_EItemActionMvM_ChallengeCompleted_GrantTourCompletionLoot = 188, // we completed a full tour in MvM
k_EItemActionMvM_AwardHelpANoobBonus_Helper = 189,
k_EItemActionHalloween_UpdateMerasmusLootLevel_Add = 200, // set the level of the merasmus loot
k_EItemActionHalloween_UpdateMerasmusLootLevel_Remove = 201,
k_EItemActionRemoveItemKillStreak_Remove = 202,
k_EItemActionRemoveItemKillStreak_Add = 203,
k_EItemActionSupportAddOrModifyAttribute_Remove = 204,
k_EItemActionSupportAddOrModifyAttribute_Add = 205,
k_EItemActionSpyVsEngyWar_JoinedWar = 206,
k_EItemAction_UpdateDuckBadgeLevel_Add = 207,
k_EItemAction_UpdateDuckBadgeLevel_Remove = 208,
k_EItemAction_QuestDrop = 209,
k_EItemAction_OperationPass_Add = 210,
k_EItemActionMarket_Add = 211,
k_EItemActionMarket_Remove = 212,
k_EItemAction_QuestComplete_Reward = 213,
k_EItemAction_QuestComplete_Remove = 214,
k_EItemAction_QuestLoaner_Add = 215,
k_EItemActionStrangeCountTransfer_Add = 216,
k_EItemActionStrangeCountTransfer_Remove = 217,
k_EItemActionCraftCollectionUpgrade_Add = 218,
k_EItemActionCraftCollectionUpgrade_Remove = 219,
k_EItemActionCraftHalloweenOffering_Add = 220,
k_EItemActionCraftHalloweenOffering_Remove = 221,
k_EItemActionRemoveItemGiftedBy_Remove = 222,
k_EItemActionRemoveItemGiftedBy_Add = 223,
k_EItemActionAddParticleVerticalAttr_Remove = 224,
k_EItemActionAddParticleVerticalAttr_Add = 225,
k_EItemActionAddParticleUseHeadOriginAttr_Remove = 226,
k_EItemActionAddParticleUseHeadOriginAttr_Add = 227,
k_EItemActionRemoveItemDynamicAttr_Add = 228,
k_EItemActionRemoveItemDynamicAttr_Remove = 229,
k_EItemActionCraftStatClockTradeUp_Add = 230,
k_EItemActionCraftStatClockTradeUp_Remove = 231,
k_EItemActionViralCompetitiveBetaPass_Drop = 232,
k_EItemActionSupportDeleteAttribute_Remove = 233,
k_EItemActionSupportDeleteAttribute_Add = 234,
// Let's be consistent with the underscores please.
// k_EItemActionYourNewAction, not k_EItemAction_YourNewAction
// Yes, it matters. See PchLocalizedNameFromEItemAction for why.
};
extern const char *PchNameFromEItemAction( EItemAction eAction );
extern const char *PchNameFromEItemActionUnsafe( EItemAction eAction );
extern bool BIsActionCreative( EItemAction );
extern bool BIsActionDestructive( EItemAction );
enum EItemActionMissingBehavior { kEItemAction_FriendlyNameLookup_ReturnNULLIfMissing, kEItemAction_FriendlyNameLookup_ReturnDummyStringIfMissing };
extern const char *PchFriendlyNameFromEItemAction( EItemAction eAction, EItemActionMissingBehavior eMissingBehavior );
extern const char *PchLocalizedNameFromEItemAction( EItemAction eAction, CLocalizationProvider &localizationProvider );
//-----------------------------------------------------------------------------
// Purpose: Used to pass audit actions to asset servers for SetUnowned and
// SetOwned methods.
//-----------------------------------------------------------------------------
enum EEconOwnershipAction
{
k_EEconOwnershipAction_Invalid = 0,
k_EEconOwnershipAction_TradeBase = 100,
k_EEconOwnershipAction_TradeCommit = 101, // precommit and docommit step of a trade. Reference is trade ID
k_EEconOwnershipAction_TradeRollback = 102, // cancelcommit and rollbackcommit step of a trade. Reference is trade ID
};
// old
enum eEconItemFlags_Deprecated
{
kDeprecated_EconItemFlag_AchievementGrantedItem = 1 << 0,
kDeprecated_EconItemFlag_CannotTrade = 1 << 1,
kDeprecated_EconItemFlag_Purchased = 1 << 2,
kDeprecated_EconItemFlag_CannotBeUsedInCrafting = 1 << 3,
kDeprecated_EconItemFlag_Promotion = 1 << 4,
};
//-----------------------------------------------------------------------------
// Periodic score events
//-----------------------------------------------------------------------------
enum eEconPeriodicScoreEvents
{
kPeriodicScoreEvent_GiftsDistributed = 0,
kPeriodicScoreEvent_DuelsWon = 1,
kPeriodicScoreEvent_MapStampsPurchased = 2,
};
//-----------------------------------------------------------------------------
// Flags for CEconItem
//-----------------------------------------------------------------------------
// WARNING!!! Values stored in DB. DO NOT CHANGE EXISTING VALUES. Add values to the end.
enum eEconItemFlags
{
kEconItemFlag_CannotTrade = 1 << 0,
kEconItemFlag_CannotBeUsedInCrafting = 1 << 1,
kEconItemFlag_CanBeTradedByFreeAccounts = 1 << 2,
kEconItemFlag_NonEconomy = 1 << 3, // used for items that are meant to not interact in the economy -- these can't be traded, gift-wrapped, crafted, etc.
kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012 = 1 << 4, // cosmetic items coming from the store are now usable in crafting; this flag is set on all items purchased from the store after this change was made
#ifdef CLIENT_DLL
#ifdef TF_CLIENT_DLL
kEconItemFlagClient_ForceBlueTeam = 1 << 5,
#endif // TF_CLIENT_DLL
kEconItemFlagClient_StoreItem = 1 << 6,
kEconItemFlagClient_Preview = 1 << 7, // only set on the client; means "this item is being previewed"
#endif // CLIENT_DLL
// combination of the above flags used in code
kEconItemFlags_CheckFlags_AllGCFlags = kEconItemFlag_CannotTrade | kEconItemFlag_CannotBeUsedInCrafting | kEconItemFlag_CanBeTradedByFreeAccounts | kEconItemFlag_NonEconomy | kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012,
};
//-----------------------------------------------------------------------------
// Origin for an item for CEconItem
//-----------------------------------------------------------------------------
// WARNING!!! Values stored in DB. DO NOT CHANGE EXISTING VALUES. Add values to the end.
enum eEconItemOrigin
{
kEconItemOrigin_Invalid = -1, // should never be stored in the DB! used to indicate "invalid" for in-memory objects only
kEconItemOrigin_Drop = 0,
kEconItemOrigin_Achievement,
kEconItemOrigin_Purchased,
kEconItemOrigin_Traded,
kEconItemOrigin_Crafted,
kEconItemOrigin_StorePromotion,
kEconItemOrigin_Gifted,
kEconItemOrigin_SupportGranted,
kEconItemOrigin_FoundInCrate,
kEconItemOrigin_Earned,
kEconItemOrigin_ThirdPartyPromotion,
kEconItemOrigin_GiftWrapped,
kEconItemOrigin_HalloweenDrop,
kEconItemOrigin_PackageItem,
kEconItemOrigin_Foreign,
kEconItemOrigin_CDKey,
kEconItemOrigin_CollectionReward,
kEconItemOrigin_PreviewItem,
kEconItemOrigin_SteamWorkshopContribution,
kEconItemOrigin_PeriodicScoreReward,
kEconItemOrigin_MvMMissionCompletionReward, // includes loot from both "mission completed" and "tour completed" events
kEconItemOrigin_MvMSquadSurplusReward,
kEconItemOrigin_RecipeOutput,
kEconItemOrigin_QuestDrop,
kEconItemOrigin_QuestLoanerItem,
kEconItemOrigin_TradeUp,
kEconItemOrigin_ViralCompetitiveBetaPassSpread,
kEconItemOrigin_Max,
};
extern const char *PchNameFromeEconItemOrigin( eEconItemOrigin eOrigin );
// The Steam backend representation of a unique item index
typedef uint64 itemid_t;
typedef uint16 item_definition_index_t;
typedef uint16 attrib_definition_index_t;
typedef uint32 attrib_value_t;
typedef uint32 operation_definition_index_t;
typedef uint8 war_definition_index_t;
typedef uint8 war_side_t;
// Misc typedefs for clarity.
typedef uint32 equip_region_mask_t;
typedef uint8 style_index_t;
const uint64 INVALID_ITEM_ID = (itemid_t)-1;
const item_definition_index_t INVALID_ITEM_DEF_INDEX = ((item_definition_index_t)-1);
const attrib_definition_index_t INVALID_ATTRIB_DEF_INDEX= ((attrib_definition_index_t)-1);
const war_definition_index_t INVALID_WAR_DEF_INDEX = ((war_definition_index_t)-1);
const war_side_t INVALID_WAR_SIDE = ((war_side_t)-1);
// Hard code the pyro/heavy stuff. Must be in sync with the schema.
const war_definition_index_t PYRO_VS_HEAVY_WAR_DEF_INDEX= ((war_definition_index_t)0);
const war_side_t PYRO_VS_HEAVY_WAR_SIDE_HEAVY = ((war_side_t)0);
const war_side_t PYRO_VS_HEAVY_WAR_SIDE_PYRO = ((war_side_t)1);
//-----------------------------------------------------------------------------
// Standard/default backpack size
#define DEFAULT_NUM_BACKPACK_SLOTS 300
#define DEFAULT_NUM_BACKPACK_SLOTS_FREE_TRIAL_ACCOUNT 50
#define MAX_NUM_BACKPACK_SLOTS 2000
// Current item level range
#define MIN_ITEM_LEVEL 0
#define MAX_ITEM_LEVEL 100
// Maximum number of attributes allowed on a single item
#define MAX_ATTRIBUTES_PER_ITEM 15
// The maximum length of a single attribute's description
// divide by locchar_t, so we can ensure 192 bytes, whether that's 128 wchars on client or 256 utf-8 bytes on gc
#define MAX_ATTRIBUTE_DESCRIPTION_LENGTH ( 256 / sizeof( locchar_t ) )
// The maximum length of an item's name
#define MAX_ITEM_NAME_LENGTH 128
#define MAX_ITEM_DESC_LENGTH 256
// The maximum length of an item description. (Extra +1 line is for the base item type line)
#define MAX_ITEM_DESCRIPTION_LENGTH ((MAX_ATTRIBUTES_PER_ITEM+1) * MAX_ATTRIBUTE_DESCRIPTION_LENGTH)
// For custom user-naming of econ items.
#define MAX_ITEM_CUSTOM_NAME_LENGTH 40
#define MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_NAME_LENGTH) + 1) // Ensures we can store MAX_ITEM_CUSTOM_NAME_LENGTH
// characters worth of obscure unicode characters in UTF8
#define MAX_ITEM_CUSTOM_DESC_LENGTH 80
#define MAX_ITEM_CUSTOM_DESC_DATABASE_SIZE ((4 * MAX_ITEM_CUSTOM_DESC_LENGTH) + 1)
#define MAX_KILLCAM_MESSAGE_LENGTH 40
#define MAX_KILLCAM_MESSAGE_DATABASE_SIZE ((4 * MAX_KILLCAM_MESSAGE_LENGTH) + 1)
// max length in the DB for claim codes
#define MAX_CLAIM_CODE_LENGTH 128
// The item definition index reserved for the preview item
#define PREVIEW_ITEM_DEFINITION_INDEX (item_definition_index_t)-1
// The number of items to work on in a job before checking if a yield is necessary
#define MAX_ITEMS_BEFORE_YIELD 50
// TF team-color paints (moved from econ_item_view.h)
#define RGB_INT_RED 12073019
#define RGB_INT_BLUE 5801378
// Custom textures
const int k_nCustomImageSize = 128;
const int k_nMaxCustomImageFileSize = k_nCustomImageSize*k_nCustomImageSize*4 + 4*1024; // Is this about right?
//-----------------------------------------------------------------------------
// Purpose: Quality types of items
//-----------------------------------------------------------------------------
typedef int32 entityquality_t;
enum EEconItemQuality
{
AE_UNDEFINED = -1,
AE_NORMAL = 0,
AE_RARITY1 = 1, // Genuine
AE_RARITY2 = 2, // Customized (unused)
AE_VINTAGE = 3, // Vintage has to stay at 3 for backwards compatibility
AE_RARITY3, // Artisan
AE_UNUSUAL, // Unusual
AE_UNIQUE,
AE_COMMUNITY,
AE_DEVELOPER,
AE_SELFMADE,
AE_CUSTOMIZED, // (unused)
AE_STRANGE,
AE_COMPLETED,
AE_HAUNTED,
AE_COLLECTORS,
AE_PAINTKITWEAPON,
AE_RARITY_DEFAULT,
AE_RARITY_COMMON,
AE_RARITY_UNCOMMON,
AE_RARITY_RARE,
AE_RARITY_MYTHICAL,
AE_RARITY_LEGENDARY,
AE_RARITY_ANCIENT,
AE_MAX_TYPES,
AE_DEPRECATED_UNIQUE = 3,
};
//-----------------------------------------------------------------------------
// Purpose: colors used in the display of attributes
//-----------------------------------------------------------------------------
enum attrib_colors_t
{
ATTRIB_COL_LEVEL = 0,
ATTRIB_COL_NEUTRAL,
ATTRIB_COL_POSITIVE,
ATTRIB_COL_NEGATIVE,
ATTRIB_COL_ITEMSET_NAME,
ATTRIB_COL_ITEMSET_EQUIPPED,
ATTRIB_COL_ITEMSET_MISSING,
ATTRIB_COL_BUNDLE_ITEM,
ATTRIB_COL_LIMITED_USE,
ATTRIB_COL_component_flags,
ATTRIB_COL_LIMITED_QUANTITY,
ATTRIB_COL_RARITY_DEFAULT,
ATTRIB_COL_RARITY_COMMON,
ATTRIB_COL_RARITY_UNCOMMON,
ATTRIB_COL_RARITY_RARE,
ATTRIB_COL_RARITY_MYTHICAL,
ATTRIB_COL_RARITY_LEGENDARY,
ATTRIB_COL_RARITY_ANCIENT,
ATTRIB_COL_RARITY_IMMORTAL,
ATTRIB_COL_RARITY_ARCANA,
ATTRIB_COL_STRANGE,
ATTRIB_COL_UNUSUAL,
NUM_ATTRIB_COLORS,
};
#define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
const char *EconQuality_GetQualityString( EEconItemQuality eQuality );
const char *EconQuality_GetColorString( EEconItemQuality eQuality );
const char *EconQuality_GetLocalizationString( EEconItemQuality eQuality );
EEconItemQuality EconQuality_GetQualityFromString( const char* pszQuality );
// Sort order for rarities
int EconQuality_GetRarityScore( EEconItemQuality eQuality );
extern attrib_colors_t GetAttribColorIndexForName( const char* pszName );
extern const char *GetColorNameForAttribColor( attrib_colors_t unAttribColor );
extern const char *GetHexColorForAttribColor( attrib_colors_t unAttribColor );
// Utility function that'll get you an item quality from a string
entityquality_t GetItemQualityFromString( const char *sQuality );
enum recipecategories_t
{
RECIPE_CATEGORY_CRAFTINGITEMS = 0,
RECIPE_CATEGORY_COMMONITEMS,
RECIPE_CATEGORY_RAREITEMS,
RECIPE_CATEGORY_SPECIAL,
NUM_RECIPE_CATEGORIES
};
extern const char *g_szRecipeCategoryStrings[NUM_RECIPE_CATEGORIES];
//-----------------------------------------------------------------------------
// Kill eater support.
// Strange counters and strange parts
//-----------------------------------------------------------------------------
#if defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
enum kill_eater_event_t
{
kKillEaterEvent_PlayerKill = 0, // default; items with no event type specified use this
kKillEaterEvent_UberActivated,
kKillEaterEvent_PlayerKillAssist,
kKillEaterEvent_PlayerKillsBySentry, // your sentry you built with this item killed someone
kKillEaterEvent_PeeVictims, // this game is great
kKillEaterEvent_BackstabAbsorbed, // you're a sniper and you got a spy to stab your Razorback
kKillEaterEvent_HeadsTaken, // this also tracks kills but with different flavor text
kKillEaterEvent_Humiliations, // fish kills!
kKillEaterEvent_GiftsGiven, // number of gifts given
kKillEaterEvent_DeathsFeigned, // number of deaths successfully feigned with the Dead Ringer
kKillEaterEvent_ScoutKill, // (part)
kKillEaterEvent_SniperKill, // (part)
kKillEaterEvent_SoldierKill, // (part)
kKillEaterEvent_DemomanKill, // (part)
kKillEaterEvent_HeavyKill, // (part)
kKillEaterEvent_PyroKill, // (part)
kKillEaterEvent_SpyKill, // (part)
kKillEaterEvent_EngineerKill, // (part)
kKillEaterEvent_MedicKill, // (part)
kKillEaterEvent_BuildingDestroyed, // (part)
kKillEaterEvent_ProjectileReflect, // (part)
kKillEaterEvent_HeadshotKill, // (part)
kKillEaterEvent_AirborneEnemyKill, // (part) (enemy is in the air when they die)
kKillEaterEvent_GibKill, // (part)
kKillEaterEvent_BuildingSapped, // a sapper was doing damage to this building while it was destroyed
kKillEaterEvent_PlayerTickle, // we used our comedy holiday gloves to force someone else to laugh
kKillEaterEvent_PlayerKillByBootStomp, // we killed a player by transferring our falling damage onto them
kKillEaterEvent_PlayerKillDuringFullMoon, // (part) we killed a player during the full moon holiday event (GC-updated)
kKillEaterEvent_PlayerKillStartDomination, // (part) we killed a player and this kill was enough to start our domination of them
kKillEaterEvent_PlayerKillAlreadyDominated, // (part) we killed a player with this weapon that we were already dominating
kKillEaterEvent_PlayerKillRevenge, // (part) we killed a player with this weapon when that player was dominating us
kKillEaterEvent_PlayerKillPosthumous, // (part) we killed a player after we were already dead (afterburn, stray rocket, etc.)
kKillEaterEvent_BurningAllyExtinguished, // (part) we used urine/milk/flamethrower/whatever to put out the fire on an ally that was burning
kKillEaterEvent_PlayerKillCritical, // (part) we killed a player with a shot that was a critical
kKillEaterEvent_PlayerKillWhileExplosiveJumping, // (part) we killed a player while we were rocket/sticky-jumping
kKillEaterEvent_PlayerKillFriend, // (part) we killed a player who is a Steam friend (GC-updated)
kKillEaterEvent_SapperDestroyed, // (part) we destroyed a sapper that was on a friendly building
kKillEaterEvent_InvisibleSpiesKilled, // (part) we killed an invisible spy
kKillEaterEvent_MedicsWithFullUberKilled, // (part) we killed a fully ubered medic
kKillEaterEvent_RobotsDestroyed, // (part) we killed a robot in MvM
kKillEaterEvent_MinibossRobotsDestroyed, // (part) we killed a miniboss robot in MvM
kKillEaterEvent_RobotsDestroyedAfterPenetration, // (part) we killed a robot with a shot that had already penetrated another robot
kKillEaterEvent_RobotHeadshotKills, // (part) like kKillEaterEvent_HeadshotKill, but only for robots
kKillEaterEvent_RobotsSlowed, // (part) we hit some robots with Jarate and now they're slow
kKillEaterEvent_KillWhileLowHealth, // (part) we killed someone while we had <10% max health
kKillEaterEvent_HalloweenKill, // (part) we killed someone during the Halloween holiday
kKillEaterEvent_HalloweenKillRobot, // (part) we killed a robot in MvM during the Halloween holiday
kKillEaterEvent_DefenderKill, // (part) we killed someone carrying the intel, pushing the cart, or capping a point
kKillEaterEvent_UnderwaterKill, // (part) we killed someone who was completely submerged
kKillEaterEvent_KillWhileUbercharged, // (part) we killed someone while we were invulnerable
kKillEaterEvent_FoodEaten, // We ate our food
kKillEaterEvent_BannersDeployed, // We deployed a banner buff
kKillEaterEvent_NEGATIVE_SniperShotsMissed, // (part) we shot our sniper rifle and didnt hit anything
kKillEaterEvent_NEGATIVE_UbersDropped, // (part) we died with a full ubercharge
kKillEaterEvent_NEGATIVE_DeathsWhileCarryingBuilding, // (part) we died while carrying a building
kKillEaterEvent_NEGATIVE_DeathsFromCratering, // (part) we died from cratering
kKillEaterEvent_NEGATIVE_DeathsFromEnvironment, // (part) we died from environmental damage
kKillEaterEvent_NEGATIVE_Deaths, // (part) we died :(
kKillEaterEvent_TimeCloaked, // Time we are cloaked
kKillEaterEvent_HealingProvided, // Health Provided to Allies
kKillEaterEvent_TeleportsProvided, // Teleports Provided to Allies
kKillEaterEvent_TanksDestroyed, // (part) we dealt the killing blow to a tank in MvM
kKillEaterEvent_LongDistanceKill, // (part) we dealt the killing blow (while alive) from far away
kKillEaterEvent_UniqueEvent__KilledAccountWithItem, // (part) (unique event) how many individual accounts have we killed?
// kKillEaterEvent_UniqueEvent__PlayedWithAccountIDWhileWearingItem, // (part) (unique event) how many individual accounts have we played a round with?
kKillEaterEvent_PointsScored, // How many score points we've accumulated
kKillEaterEvent_DoubleDonks, // Double-Donks scored with the loose cannon
kKillEaterEvent_TeammatesWhipped, // Whipped Teammates with the Disciplinary Action
kKillEaterEvent_VictoryTimeKill, // Kills while in Victory / Bonus Time
kKillEaterEvent_RobotScoutKill, // (part)
kKillEaterEvent_RobotSniperKill, // (part) Not yet shipped
kKillEaterEvent_RobotSoldierKill, // (part) Not yet shipped
kKillEaterEvent_RobotDemomanKill, // (part) Not yet shipped
kKillEaterEvent_RobotHeavyKill, // (part) Not yet shipped
kKillEaterEvent_RobotPyroKill, // (part) Not yet shipped
kKillEaterEvent_RobotSpyKill, // (part)
kKillEaterEvent_RobotEngineerKill, // (part) Not yet shipped
kKillEaterEvent_RobotMedicKill, // (part) Not yet shipped
kKillEaterEvent_TauntKill, // Taunt Kills
kKillEaterEvent_PlayersWearingUnusualKill, // (part) we killed someone wearing an unusual hat (!)
kKillEaterEvent_BurningEnemyKill, // (part) we killed someone who was on fire up until they died
kKillEaterEvent_KillstreaksEnded, // (part) we killed someone who was on a killstreak
kKillEaterEvent_KillcamTaunts, // (cosmetic part) we appeared wearing this item in the killcam taunting
kKillEaterEvent_DamageDealt, // (part) we have dealt this much damage to people
kKillEaterEvent_FiresSurvived, // (cosmetic part) we were lit on fire wearing this item and then the fire went out and we were still alive
kKillEaterEvent_AllyHealingDone, // (part) we have healed this much (directly, so doesn't count Mad Milk, etc. because we lose the item pointer at some point); also ignores self heal (ie., Concheror buff, MvM upgrades)
kKillEaterEvent_PointBlankKills, // (part) we killed someone while standing right next to them
kKillEaterEvent_PlayerKillsByManualControlOfSentry, // Kills from wrangled a sentry
kKillEaterEvent_CosmeticKills, // (cosmetic part) kills
kKillEaterEvent_FullHealthKills, // (part) Kills while at fullhealth
kKillEaterEvent_TauntingPlayerKills, // (part) Taunting Player Kills
kKillEaterEvent_Halloween_OverworldKills,
kKillEaterEvent_Halloween_UnderworldKills,
kKillEaterEvent_Halloween_MinigamesWon,
kKillEaterEvent_NonCritKills, // part kills that are not crit or mini crit
kKillEaterEvent_PlayersHit, // part
kKillEaterEvent_CosmeticAssists, // Cosmetic part
kKillEaterEvent_CosmeticOperationContractsCompleted, // Operation Stat Tracker
kKillEaterEvent_CosmeticOperationKills, // Operation Stat Tracker
kKillEaterEvent_CosmeticOperationContractsPoints,
kKillEaterEvent_CosmeticOperationBonusPoints,
kKillEaterEvent_TauntsPerformed, // Strange Taunts
kKillEaterEvent_InvasionKills, // Kills During Invasion Event. Locked after Operation
kKillEaterEvent_InvasionKillsOnMap01,
kKillEaterEvent_InvasionKillsOnMap02,
kKillEaterEvent_InvasionKillsOnMap03,
kKillEaterEvent_InvasionKillsOnMap04,
kKillEaterEvent_HalloweenSouls, // Halloween
kKillEaterEvent_HalloweenContractsCompleted,
kKillEaterEvent_HalloweenOfferings,
kKillEaterEvent_PowerupBottlesUsed,
// NEW ENTRIES MUST BE ADDED AT THE BOTTOM
};
#else
// projects that actually want to implement kill-eater functionality will want to put their list somewhere around here,
// but unfortunately the base code relies on this specific definition being entry 0
static const uint32 kKillEaterEvent_PlayerKill = 0;
#endif // defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
enum strange_event_restriction_t
{
kStrangeEventRestriction_None = 0, // default -- unassigned, all events pass
kStrangeEventRestriction_VictimSteamAccount, // the victim must have a specific Steam ID
#if defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
kStrangeEventRestriction_Map, // must be playing on a certain map when the event takes place
kStrangeEventRestriction_Competitive, // must be playing in a competitive game
#endif // defined( TF_DLL ) || defined( TF_GC_DLL ) || defined( TF_CLIENT_DLL )
kStrangeEventRestrictionCount
};
// Ugh -- these are shared between the GC and the client. Maybe #define is slightly better than
// magic string literals?
#define KILL_EATER_RANK_LEVEL_BLOCK_NAME "KillEaterRank"
#ifdef TF_DLL
class CTFWeaponBase *GetKilleaterWeaponFromDamageInfo( const class CTakeDamageInfo *pInfo );
// A specific CEconEntity caused a kill eater event to happen. For example, a weapon might cause a
// player kill event so we want to update the stats for that specific weapon.
void EconEntity_OnOwnerKillEaterEvent( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconItemInterface_OnOwnerKillEaterEvent( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconEntity_OnOwnerKillEaterEventNoPartner( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconItemInterface_OnOwnerKillEaterEventNoPartner( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void HatAndMiscEconEntities_OnOwnerKillEaterEvent( class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void HatAndMiscEconEntities_OnOwnerKillEaterEventNoParter( class CTFPlayer *pOwner, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconEntity_NonEquippedItemKillTracking_NoPartner( class CTFPlayer *pOwner, item_definition_index_t iDefIndex, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconEntity_NonEquippedItemKillTracking_NoPartnerBatched( class CTFPlayer *pOwner, item_definition_index_t iDefIndex, kill_eater_event_t eEventType, int nIncrementValue = 1 );
// Batching system for frequent events (ie., damage dealing). The game server will flush all batches
// at specific time intervals and send up one composite message to avoid flooding the GC. Batched
// messages will only work correctly for types that support increment values. Because the game client
// and game server don't know which event types support increment values we can't do any checking
// before we send the message.
void EconEntity_OnOwnerKillEaterEvent_Batched( class CEconEntity *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void EconItemInterface_OnOwnerKillEaterEvent_Batched( class IEconItemInterface *pEconEntity, class CTFPlayer *pOwner, class CTFPlayer *pVictim, kill_eater_event_t eEventType, int nIncrementValue = 1 );
void KillEaterEvents_FlushBatches();
#endif // TF_DLL
int GetKillEaterAttrCount();
int GetKillEaterAttrCount_UserCustomizable();
const class CEconItemAttributeDefinition *GetKillEaterAttr_Score( int i );
const class CEconItemAttributeDefinition *GetKillEaterAttr_Type( int i );
const class CEconItemAttributeDefinition *GetKillEaterAttr_Restriction( int i );
const class CEconItemAttributeDefinition *GetKillEaterAttr_RestrictionValue( int i );
bool GetKillEaterAttr_IsUserCustomizable( int i );
bool GetKilleaterValueByEvent( const class IEconItemInterface* pItem, const kill_eater_event_t& EEventType, uint32& value );
bool BIsItemStrange( const class IEconItemInterface *pItem );
const int COLLECTION_CRAFTING_ITEM_COUNT = 10;
const char* GetCollectionCraftingInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
const int HALLOWEEN_OFFERING_ITEM_COUNT = 3;
const char* GetHalloweenOfferingInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
const int CRAFT_COMMON_STATCLOCK_ITEM_COUNT = 5;
const char* GetCraftCommonStatClockInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem );
int GetMaxCardUpgradesPerItem();
const class CEconItemAttributeDefinition *GetCardUpgradeForIndex( const class IEconItemInterface *pItem, int i );
#define GUARANTEED_OUTPUT (1<<0)
#define GUARANTEED_INPUT (1<<1)
#define DYNAMIC_RECIPE_FLAG_IS_OUTPUT (1<<0)
#define DYNAMIC_RECIPE_FLAG_IS_UNTRADABLE (1<<1)
#define DYNAMIC_RECIPE_FLAG_PARAM_ITEM_DEF_SET (1<<2)
#define DYNAMIC_RECIPE_FLAG_PARAM_QUALITY_SET (1<<3)
#define DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ALL (1<<4)
#define DYNAMIC_RECIPE_FLAG_PARAM_ATTRIBUTE_SET_ANY (1<<5)
#define k_ObjectiveTrackerFlag_OwnerClient (1<<0)
#define k_ObjectiveTrackerFlag_Servers (1<<1)
#define k_ObjectiveTrackerFlag_AllClients (1<<2)
#define k_ObjectiveTrackerFlag_ClientAndServer ( k_ObjectiveTrackerFlag_OwnerClient | k_ObjectiveTrackerFlag_Servers )
const float k_MaxElapsedQuestReportTime = 10.f;
//===============================================================================================================
// POSITION HANDLING
//===============================================================================================================
// TF Inventory Position cracking
// REALLY OLD FORMAT (??):
// We store a bag index in the highbits of the inventory position.
// The lowbit stores the position of the item within the bag.
//
// LESS OLD FORMAT (up through July, 2011):
// If Bit 31 is 0:
// Bits 1-16 are the backpack position.
// Bits 17-26 are a bool for whether the item is equipped in the matching class.
// Otherwise, if Bit 31 is 1:
// Item hasn't been acknowledged by the player yet.
// Bits 1-16 are the method by the player found the item (see unacknowledged_item_inventory_positions_t)
// Bit 32 is 1, to note the new format.
//
// CURRENT FORMAT:
// If Bit 31 is 0:
// Bits 1-16 are the backpack position.
// Otherwise, if Bit 31 is 1:
// Item hasn't been acknowledged by the player yet.
// Bits 1-16 are the method by the player found the item (see unacknowledged_item_inventory_positions_t)
// Equipped state is stored elsewhere.
// This is the only format that should exist on clients.
// Note (1/15/2013) For backwards compatibility, if the value is 0 item is considered unacknowledged too
enum unacknowledged_item_inventory_positions_t
{
UNACK_ITEM_UNKNOWN = 0,
UNACK_ITEM_DROPPED = 1,
UNACK_ITEM_CRAFTED,
UNACK_ITEM_TRADED,
UNACK_ITEM_PURCHASED,
UNACK_ITEM_FOUND_IN_CRATE,
UNACK_ITEM_GIFTED,
UNACK_ITEM_SUPPORT,
UNACK_ITEM_PROMOTION,
UNACK_ITEM_EARNED,
UNACK_ITEM_REFUNDED,
UNACK_ITEM_GIFT_WRAPPED,
UNACK_ITEM_FOREIGN,
UNACK_ITEM_COLLECTION_REWARD,
UNACK_ITEM_PREVIEW_ITEM,
UNACK_ITEM_PREVIEW_ITEM_PURCHASED,
UNACK_ITEM_PERIODIC_SCORE_REWARD,
UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD,
UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD,
UNACK_ITEM_FOUND_HOLIDAY_GIFT,
UNACK_ITEM_COMMUNITY_MARKET_PURCHASE,
UNACK_ITEM_RECIPE_OUTPUT,
UNACK_ITEM_HIDDEN_QUEST_ITEM,
UNACK_ITEM_QUEST_OUTPUT,
UNACK_ITEM_QUEST_LOANER,
UNACK_ITEM_TRADE_UP,
UNACK_ITEM_QUEST_MERASMISSION_OUTPUT,
UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD,
#ifdef ENABLE_STORE_RENTAL_BACKEND
UNACK_ITEM_RENTAL_PURCHASE,
#endif
UNACK_NUM_METHODS,
};
extern const char *g_pszItemPickupMethodStrings[UNACK_NUM_METHODS - 1]; // -1 because UNACK_ITEM_DROPPED is index 1, not 0
extern const char *g_pszItemPickupMethodStringsUnloc[UNACK_NUM_METHODS - 1];
extern const char *g_pszItemFoundMethodStrings[UNACK_NUM_METHODS - 1];
enum
{
kGCItemSort_NoSort = 0, // this won't do anything, but can be used as a safe "header" value
kGCItemSort_SortByName = 1,
kGCItemSort_SortByDefIndex = 2,
kGCItemSort_SortByRarity = 3,
kGCItemSort_SortByType = 4,
kGCItemSort_SortByDate = 5,
kGCItemSort_GameSpecificBase = 100,
};
// FIXME: these should be moved... somewhere; where?
enum
{
kTFGCItemSort_SortByClass = kGCItemSort_GameSpecificBase + 1,
kTFGCItemSort_SortBySlot = kGCItemSort_GameSpecificBase + 2,
};
enum
{
kBackendPosition_Unacked = 1 << 30,
kBackendPosition_NewFormat = 1 << 31,
kBackendPositionMask_Position = 0x0000ffff,
kBackendPositionMask_FormatFlags = (kBackendPosition_Unacked | kBackendPosition_NewFormat),
};
inline void SetBackpackPosition( uint32 *pPosition, uint32 iPackPosition )
{
(*pPosition) = iPackPosition;
// Remove the unack'd flag
(*pPosition) &= ~kBackendPosition_Unacked;
}
inline bool IsNewPositionFormat( uint32 iBackendPosition )
{
return ( iBackendPosition & kBackendPosition_NewFormat ) != 0;
}
inline bool IsUnacknowledged( uint32 iBackendPosition )
{
// For backwards compatibility, we consider position 0 as unacknowledged too
return (iBackendPosition == 0 || (iBackendPosition & kBackendPosition_Unacked) != 0);
}
inline int ExtractBackpackPositionFromBackend( uint32 iBackendPosition )
{
if ( IsUnacknowledged( iBackendPosition) )
return 0;
return iBackendPosition & kBackendPositionMask_Position;
}
inline unacknowledged_item_inventory_positions_t GetUnacknowledgedReason( uint32 iBackendPosition )
{
return (unacknowledged_item_inventory_positions_t)( iBackendPosition &= ~kBackendPositionMask_FormatFlags );
}
inline uint32 GetUnacknowledgedPositionFor( unacknowledged_item_inventory_positions_t iMethod )
{
return (iMethod | kBackendPosition_Unacked | kBackendPosition_NewFormat);
}
//-----------------------------------------------------------------------------
// Item Preview event IDs for logging.
//-----------------------------------------------------------------------------
enum EEconItemPreviewEventIDs
{
k_EEconItemPreview_Start =1,
k_EEconItemPreview_Expired =2,
k_EEconItemPreview_ItemPurchased =3,
};
//-----------------------------------------------------------------------------
// List of holidays. These are sorted by priority. Needs to match static IIsHolidayActive *s_HolidayChecks
//-----------------------------------------------------------------------------
enum EHoliday
{
kHoliday_None = 0, // must stay at zero for backwards compatibility
kHoliday_TFBirthday,
kHoliday_Halloween,
kHoliday_Christmas,
kHoliday_CommunityUpdate,
kHoliday_EOTL,
kHoliday_Valentines,
kHoliday_MeetThePyro,
kHoliday_FullMoon,
kHoliday_HalloweenOrFullMoon,
kHoliday_HalloweenOrFullMoonOrValentines,
kHoliday_AprilFools,
kHolidayCount,
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
enum ECartItemType
{
kCartItem_Purchase, // a normal lifetime purchase (needs to stay as entry 0!)
kCartItem_TryOutUpgrade, // an upgrade from "try-it-out"
kCartItem_Rental_1Day,
kCartItem_Rental_3Day,
kCartItem_Rental_7Day,
};
inline bool IsRentalCartItemType( ECartItemType eCartType )
{
return eCartType == kCartItem_Rental_1Day
|| eCartType == kCartItem_Rental_3Day
|| eCartType == kCartItem_Rental_7Day;
}
const uint8 k_unItemRarity_Any = 0xFF;
const uint8 k_unItemQuality_Any = 0xFF;
typedef int econ_tag_handle_t;
enum EItemUntradability
{
k_Untradability_Temporary = 1<<1,
k_Untradability_Permanent = 1<<2,
};
#define INVALID_ECON_TAG_HANDLE ((econ_tag_handle_t)-1)
#endif // ACTUAL_ECON_ITEM_CONSTANTS_H
File diff suppressed because it is too large Load Diff
+536
View File
@@ -0,0 +1,536 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#ifndef ECONITEMDESCRIPTION_H
#define ECONITEMDESCRIPTION_H
#ifdef _WIN32
#pragma once
#endif
#include "localization_provider.h" // needed for locchar_t type
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
#define PROJECT_TF
#endif
#define TF_ANTI_IDLEBOT_VERIFICATION defined( PROJECT_TF )
#if TF_ANTI_IDLEBOT_VERIFICATION
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA ,
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( arg ) arg
#else
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
#define TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( arg )
#endif
#if TF_ANTI_IDLEBOT_VERIFICATION
#include "checksum_md5.h"
#include "tf_gcmessages.pb.h"
#include "tf_gcmessages.h"
#ifdef CLIENT_DLL
#include "gc_clientsystem.h"
#endif // CLIENT_DLL
#endif // TF_ANTI_IDLEBOT_VERIFICATION
#ifdef GC_DLL
#include "gcsdk/gclogger.h"
using namespace GCSDK;
#endif
class IEconItemInterface;
namespace GCSDK
{
class CSharedObjectTypeCache;
}
//-----------------------------------------------------------------------------
// Purpose: Generate a description block for an IEconItemInterface. What the
// client does with the description is anyone's guess, but this will
// generate a block of UTF16 lines of text with meta/color data that
// can be used for whatever.
//-----------------------------------------------------------------------------
enum EDescriptionLineMetaFlags
{
kDescLineFlag_Name = 0x001, // the item name (can be renamed by user)
kDescLineFlag_Type = 0x002, // the item type (ie., "Level 5 Rocket Launcher")
kDescLineFlag_Desc = 0x004, // base item description (description from the item definition, level, etc.)
kDescLineFlag_Attribute = 0x008, // some sort of gameplay-affecting attribute
kDescLineFlag_Misc = 0x010, // not an attribute, not name/level
kDescLineFlag_Empty = 0x020, // line with no content that needs to be displayed; meant for spacing
kDescLineFlag_Set = 0x040, // this line is associated with item sets somehow
kDescLineFlag_LimitedUse= 0x080, // this is a limited use item
kDescLineFlag_SetName = 0x100, // this line is the title for an item set
kDescLineFlag_Collection = 0x200, // this line is associated with item collections
kDescLineFlag_CollectionCurrentItem = 0x400, // this line is the current item being describe
kDescLineFlag_CollectionName = 0x800, // this line is the collection name
kDescLineFlagSet_DisplayInAttributeBlock = ~(kDescLineFlag_Name | kDescLineFlag_Type),
};
struct econ_item_description_line_t
{
attrib_colors_t eColor; // desired color type for this line -- will likely be looked up either in VGUI or in the schema
uint32 unMetaType; // type information for this line -- "item name"? "item level"?; etc.; can be game-specific
CUtlConstStringBase<locchar_t> sText; // actual text for this, post-localization
item_definition_index_t unDefIndex; // item def index for description lines which represent names of other items (used by bundles)
bool bIsItemForSale; // if this line is an item (eg in the case where a bundle description lists its contained items) - is the given item for sale?
};
class IEconItemDescription
{
public:
// This may yield on the GC and should never yield on the client.
static void YieldingFillOutEconItemDescription( IEconItemDescription *out_pDescription, CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
public:
IEconItemDescription() { }
virtual ~IEconItemDescription() { }
uint32 GetLineCount() const { return m_vecDescLines.Count(); }
const econ_item_description_line_t& GetLine( int i ) const { return m_vecDescLines[i]; }
// Finds and returns the first line with *all* of the passed in search flags. Will return NULL if a line
// will all of the flags cannot be found.
const econ_item_description_line_t *GetFirstLineWithMetaType( uint32 unMetaTypeSearchFlags ) const;
private:
// When generating an item description, this is guaranteed to be called once and only once before GenerateDescription()
// is called. Any data that may yield but will be needed somewhere deep inside GenerateDescription() should be determined
// and cached off here.
virtual void YieldingCacheDescriptionData( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem ) { }
// Take the properties off our pEconItem, and anything that we calculated in YieldingCacheDescriptionData() above and
// fill out all of our description lines.
virtual void GenerateDescriptionLines( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem ) = 0;
protected:
CUtlVector<econ_item_description_line_t> m_vecDescLines;
};
// This will be defined as either 1 or 0 depending on which project we're in. We test its value explicitly
// rather than just checking defined() because otherwise failing to include this header file will silently
// result in it appearing to be undefined.
#define BUILD_ITEM_NAME_AND_DESC (defined( CLIENT_DLL ) || defined( GC_DLL ))
#if BUILD_ITEM_NAME_AND_DESC
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class IAccountPersonaLocalizer
{
public:
virtual const locchar_t *FindAccountPersonaName( uint32 unAccountID ) const = 0;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemDescription : public IEconItemDescription, public IAccountPersonaLocalizer
{
public:
// Instances should be filled out via YieldingFillOutEconItemDescription().
CEconItemDescription()
#if TF_ANTI_IDLEBOT_VERIFICATION
: m_pHashContext( NULL )
, m_bIsVerbose( false )
#ifdef GC_DLL
, m_bTextModeEnabled( false )
#else // if defined( CLIENT_DLL )
, m_bUnknownPlayer( false )
#endif // GC_DLL
#endif // TF_ANTI_IDLEBOT_VERIFICATION
{
//
}
// External helper interface, also used internally. This should only be used to add lines
// that are not a part of the properties of the item, but are instead a part of the environment
// around the item (ie., "this item cannot be equipped in this slot because another item is
// equipped that has conflicting regions").
//
// The final argument is an optional target array to use for the description lines instead of
// our internal storage. We can use this to queue up and then batch-submit/-discard lines. Passing
// in NULL means "use the internal array".
virtual void AddDescLine( const locchar_t *pString, attrib_colors_t eColor, uint32 unMetaType, CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL, item_definition_index_t unDefIndex = INVALID_ITEM_DEF_INDEX, bool bIsItemForSale = true );
virtual void AddEmptyDescLine( CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL );
virtual void LocalizedAddDescLine( const CLocalizationProvider *pLocalizationProvider, const char *pLocalizationToken, attrib_colors_t eColor, uint32 unMetaType, CUtlVector<econ_item_description_line_t> *out_pOptionalDescLineDest = NULL, item_definition_index_t unDefIndex = INVALID_ITEM_DEF_INDEX, bool bIsItemForSale = true );
// A helper class to iterate all attributes that we expect to appear on an item description. This
// is useable from outside CEconItemDescription. Attributes can be accessed in iteration order or
// manually sorted to be grouped by positive/negative status, etc.
class CVisibleAttributeDisplayer : public IEconItemAttributeIterator
{
public:
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) OVERRIDE
{
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) OVERRIDE
{
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) OVERRIDE
{
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) OVERRIDE
{
// Don't show these
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) OVERRIDE
{
// Don't show these
return true;
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) OVERRIDE
{
// Don't show these
return true;
}
void SortAttributes();
void Finalize( const IEconItemInterface *pEconItem, CEconItemDescription *pEconItemDescription, const CLocalizationProvider *pLocalizationProvider );
private:
struct attrib_iterator_value_t
{
const CEconItemAttributeDefinition *m_pAttrDef;
attrib_value_t m_value;
};
CUtlVector<attrib_iterator_value_t> m_vecAttributes;
};
class CRecipeNameAttributeDisplayer : public CVisibleAttributeDisplayer
{
public:
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE;
};
#if TF_ANTI_IDLEBOT_VERIFICATION
void SetHashContext( MD5Context_t *pHashContext )
{
AssertMsg( pHashContext == NULL || m_pHashContext == NULL, "Only one hash context allowed per item description!" );
m_pHashContext = pHashContext;
}
void SetVerbose( bool bIsVerbose )
{
m_bIsVerbose = bIsVerbose;
}
#ifdef GC_DLL
void SetHashGCTextModeEnabled( bool bTextModeEnabled )
{
m_bTextModeEnabled = bTextModeEnabled;
}
#endif // GC_DLL
#endif // TF_ANTI_IDLEBOT_VERIFICATION
#ifdef GC_DLL
bool HasUnknownPlayer( ) const
{
return false;
}
#else // if defined( CLIENT_DLL )
bool HasUnknownPlayer( ) const
{
return m_bUnknownPlayer;
}
#endif
private:
// IEconItemDescription interface.
virtual void YieldingCacheDescriptionData( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void GenerateDescriptionLines( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
private:
// Internal.
virtual void AddAttributeDescription( const CLocalizationProvider *pLocalizationProvider, const CEconItemAttributeDefinition *pAttribDef, attrib_value_t value, attrib_colors_t eOverrideDisplayColor = NUM_ATTRIB_COLORS );
virtual void Generate_ItemName( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_ItemLevelDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
#if defined( STAGING_ONLY ) && defined( CLIENT_DLL )
virtual void Generate_DebugInformation( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
#endif // defined( DEBUG ) && defined( CLIENT_DLL )
virtual void Generate_CraftTag( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_StyleDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_HolidayRestriction( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_QualityDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_ItemRarityDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_WearAmountDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_ItemDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_Bundle( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_GiftedBy( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
#ifdef PROJECT_TF
virtual void Generate_DuelingMedal( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_MapContributor( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_FriendlyHat( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_SaxxyAwardDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_MvmChallenges( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_SquadSurplusClaimedBy( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_DynamicRecipe( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_Leaderboard( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
#endif // PROJECT_TF
virtual void Generate_XifierToolTargetItem( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_Painted( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_Uses( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_LootListDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_EventDetail( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_ItemSetDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_CollectionDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_ExpirationDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_MarketInformation( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_FlagsAttributes( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_DropPeriodDesc( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_VisibleAttributes( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
virtual void Generate_DirectX8Warning( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem );
// Helpers for the above.
virtual void Generate_ItemLevelDesc_Default( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, const locchar_t *locTypename );
virtual bool BGenerate_ItemLevelDesc_StrangeNameAndStats( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, const locchar_t *locTypename ); // returns true if generated a level/desc based on strange stats or false if nothing was generated
const locchar_t *GetLocalizedStringForStrangeRestrictionAttr( const CLocalizationProvider *pLocalizationProvider, const IEconItemInterface *pEconItem, int iAttrIndex ) const;
// Internal data.
void YieldingFillOutAccountPersonaName( const CLocalizationProvider *pLocalizationProvider, uint32 unAccountID );
const locchar_t *FindAccountPersonaName( uint32 unAccountID ) const;
void YieldingFillOutAccountTypeCache( uint32 unAccountID, int nClassID );
GCSDK::CSharedObjectTypeCache *FindAccountTypeCache( uint32 unAccountID, int nClassID ) const;
// Defined in source file -- not meant for external access.
template < typename T >
const T *FindAccountTypeCacheSingleton( uint32 unAccountID, int nClassID ) const;
// Precache data.
struct steam_account_persona_name_t
{
uint32 unAccountID;
CUtlConstStringBase<locchar_t> loc_sPersonaName;
};
CUtlVector<steam_account_persona_name_t> vecPersonaNames;
struct steam_account_type_cache_t
{
uint32 unAccountID;
int nClassID;
GCSDK::CSharedObjectTypeCache *pTypeCache;
};
CUtlVector<steam_account_type_cache_t> vecTypeCaches;
#if TF_ANTI_IDLEBOT_VERIFICATION
MD5Context_t *m_pHashContext;
bool m_bIsVerbose;
#ifdef GC_DLL
bool m_bTextModeEnabled;
#else // if defined( CLIENT_DLL )
bool m_bUnknownPlayer;
#endif // GC_DLL
#endif // TF_ANTI_IDLEBOT_VERIFICATION
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconAttributeDescription
{
private:
// Internal constructor.
void InternalConstruct
(
const CLocalizationProvider *pLocalizationProvider,
const CEconItemAttributeDefinition *pAttribDef,
attrib_value_t value,
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *pHashContext ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
IAccountPersonaLocalizer *pOptionalAccountPersonaLocalizer
);
public:
// Outward-facing constructor. Pass in whatever you want for "value" and we'll
// use the raw bits for their value interpreted however the attribute says.
template < typename T >
CEconAttributeDescription
(
const CLocalizationProvider *pLocalizationProvider,
const CEconItemAttributeDefinition *pAttribDef,
T value,
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *pHashContext = NULL ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA
IAccountPersonaLocalizer *pOptionalAccountPersonaLocalizer = NULL
)
{
COMPILE_TIME_ASSERT( sizeof( T ) == sizeof( attrib_value_t ) );
InternalConstruct( pLocalizationProvider, pAttribDef, *(attrib_value_t *)&value, TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( pHashContext ) TF_ANTI_IDLEBOT_VERIFICATION_ONLY_COMMA pOptionalAccountPersonaLocalizer );
}
const CUtlConstStringBase<locchar_t>& GetDescription() const { return m_loc_sValue; }
const CUtlConstStringBase<locchar_t>& GetShortDescription() const { return m_loc_sShortValue; }
attrib_colors_t GetDefaultColor() const { return m_eDefaultColor; }
private:
CUtlConstStringBase<locchar_t> m_loc_sValue;
CUtlConstStringBase<locchar_t> m_loc_sShortValue;
attrib_colors_t m_eDefaultColor;
};
//-----------------------------------------------------------------------------
// Purpose: control how item name is generated
//-----------------------------------------------------------------------------
enum EGenerateLocalizedFullItemNameFlag_t
{
k_EGenerateLocalizedFullItemName_Default = 0,
k_EGenerateLocalizedFullItemName_WithPaintWear = ( 1 << 0 ),
k_EGenerateLocalizedFullItemName_WithoutCustomName = ( 1 << 1 ),
k_EGenerateLocalizedFullItemName_WithoutQuality = ( 1 << 2 ),
k_EGenerateLocalizedFullItemName_WithPaintkitNoItem = ( 1 << 3 ),
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemLocalizedFullNameGenerator
{
public:
CEconItemLocalizedFullNameGenerator( const CLocalizationProvider *pLocalizationProvider, const CEconItemDefinition *pItemDef, bool bUseingHashContext = true, entityquality_t eQuality = AE_UNIQUE );
const locchar_t *GetFullName() const { return m_loc_LocalizedItemName; }
private:
locchar_t m_loc_LocalizedItemName[ MAX_ITEM_NAME_LENGTH ];
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemLocalizedMarketNameGenerator
{
public:
CEconItemLocalizedMarketNameGenerator( const CLocalizationProvider *pLocalizationProvider, CEconItem *pItem, bool bUseingHashContext = true );
const locchar_t *GetFullName() const { return m_loc_LocalizedItemName; }
private:
locchar_t m_loc_LocalizedItemName[ MAX_ITEM_NAME_LENGTH ];
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSteamAccountIDAttributeCollector : public CEconItemSpecificAttributeIterator
{
public:
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE
{
if ( pAttrDef->GetDescriptionFormat() == ATTDESCFORM_VALUE_IS_ACCOUNT_ID )
{
m_vecSteamAccountIDs.AddToTail( value );
}
return true;
}
// Data access.
const CUtlVector<uint32>& GetAccountIDs()
{
return m_vecSteamAccountIDs;
}
private:
CUtlVector<uint32> m_vecSteamAccountIDs;
};
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
#if TF_ANTI_IDLEBOT_VERIFICATION
#include "checksum_md5.h"
enum
{
kTFDescriptionHash_TextmodeArbitraryKey = 0x19a04480,
kTFDescriptionHash_ValidArbitraryKey = 0xa0939180,
kTFDescriptionHash_MultiRunArbitraryKey = 0x5790a31d,
kTFDescriptionHash_ChallengeXorShenanigans = 0x1870f0d2,
};
// Global function/variable names show up in Mac binaries so we give them names that will stand out less
// here and then #define them back so the code is readable.
#define TF_Description_HashDataMungeContents CompressFragments
inline void TFDescription_HashDataMungeContents( MD5Context_t *out_pContext, const void *pContents, size_t unContentLength, bool bIsVerbose, const char* pszInfo )
{
Assert( out_pContext );
Assert( pContents );
MD5Update( out_pContext, static_cast<const uint8 *>( pContents ), unContentLength );
// if Verbose, report the contents to the GC
if ( bIsVerbose )
{
MD5Context_t md5ContextEx = *out_pContext;
MD5Value_t md5ResultEx;
MD5Final( &md5ResultEx.bits[0], &md5ContextEx );
#ifdef GC_DLL
EmitInfo( SPEW_GC, SPEW_ALWAYS, LOG_ALWAYS, "Verbose Verification GC : [ %s ] - [ %s ] \n", MD5_Print( md5ResultEx.bits, MD5_DIGEST_LENGTH ), pszInfo );
#else
// Client reports this to the GC
GCSDK::CProtoBufMsg<CGCMsgTFSyncEx> msgResponse( k_EMsgGC_ClientVerificationVerboseResponse );
msgResponse.Body().set_version_checksum( pszInfo ); // before
msgResponse.Body().set_version_checksum_ex( &md5ResultEx.bits[0], MD5_DIGEST_LENGTH ); // after
GCClientSystem()->BSendMessage( msgResponse );
#endif
//delete [] pArr;
}
}
// Okay, this one is actually just a helper macro.
#define TFDescription_HashDataMunge( context, field, bIsVerbose, pszInfo ) \
{ \
TFDescription_HashDataMungeContents( context, (void *)&field, sizeof( field ), bIsVerbose, pszInfo ); \
}
#endif // TF_ANTI_IDLEBOT_VERIFICATION
#endif // BUILD_ITEM_NAME_AND_DESC
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
struct CLocalizedRTime32
{
RTime32 m_unTime;
bool m_bForceGMTOnClient; // display this time in GMT on the client? by default, clients show local time; the GC will ignore this flag and always display GMT
const CLocalizationProvider *m_pLocalizationProvider;
TF_ANTI_IDLEBOT_VERIFICATION_ONLY_ARG( MD5Context_t *m_pHashContext; )
};
template < >
class CLocalizedStringArg<CLocalizedRTime32>
{
public:
enum { kIsValid = true };
CLocalizedStringArg( const CLocalizedRTime32& cTimeIn );
const locchar_t *GetLocArg() const { return m_Str.Get(); }
private:
CUtlConstStringBase<locchar_t> m_Str;
};
#endif // ECONITEMDESCRIPTION_H
+331
View File
@@ -0,0 +1,331 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: EconItemFactory: Manages rolling for items requested by the game server
//
//=============================================================================
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#include "econ/econ_assetapi_context.h"
using namespace GCSDK;
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CEconItemFactory::CEconItemFactory( )
: m_ulNextObjID( 0 )
, m_bIsInitialized( false )
{
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the item factory and schema. Return false if init failed
//-----------------------------------------------------------------------------
bool CEconItemFactory::BYieldingInit()
{
CUtlVector< CUtlString > vecErrors;
bool bRet = m_schema.BInit( "scripts/items/unencrypted/items_master.txt", "GAME", &vecErrors );
FOR_EACH_VEC( vecErrors, nError )
{
EmitError( SPEW_GC, "%s\n", vecErrors[nError].Get() );
}
static const char *pchMaxIDQuery = "SELECT MAX( ID ) FROM "
"( select max(ID) AS ID FROM Item UNION SELECT MAX(ID) AS ID FROM ForeignItem ) as tbl";
CSQLAccess sqlAccess;
if( !sqlAccess.BYieldingExecuteSingleResult<uint64, uint64>( NULL, pchMaxIDQuery, k_EGCSQLType_int64, &m_ulNextObjID, NULL ) )
{
EmitError( SPEW_GC, "Failed to read max item ID" );
return false;
}
m_ulNextObjID++; // our next ID is one past the current max ID
m_bIsInitialized = bRet;
return bRet;
}
static const CEconItemQualityDefinition *GetQualityDefinitionForItemCreation( const CItemSelectionCriteria *pOptionalCriteria, const CEconItemDefinition *pItemDef )
{
Assert( pItemDef );
// Do we have a quality specified? If so, is it a valid quality? If not, we fall back to the
// quality specified by the item definition, the schema, etc.
uint8 unQuality = k_unItemQuality_Any;
// Quality specified in generation request via criteria?
if ( pOptionalCriteria && pOptionalCriteria->BQualitySet() )
{
unQuality = pOptionalCriteria->GetQuality();
}
// If not: quality specified in item definition?
if ( unQuality == k_unItemQuality_Any )
{
unQuality = pItemDef->GetQuality();
}
// Final fallback: default quality in schema.
if ( unQuality == k_unItemQuality_Any )
{
unQuality = GetItemSchema()->GetDefaultQuality();
}
AssertMsg( unQuality != k_unItemQuality_Any, "Unable to locate valid quality!" );
return GetItemSchema()->GetQualityDefinition( unQuality );
}
//-----------------------------------------------------------------------------
// Purpose: Creates an item matching the incoming item selection criteria
// Input: pItem - Pointer to the item to fill in
// criteria - The criteria that the generated item must match
// Output: True if a matching item could be generated, false otherwise
//-----------------------------------------------------------------------------
CEconItem *CEconItemFactory::CreateRandomItem( const CEconGameAccount *pGameAccount, const CItemSelectionCriteria &criteria )
{
// Find a matching item definition.
const CEconItemDefinition *pItemDef = RollItemDefinition( criteria );
if ( NULL == pItemDef )
{
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with no matching definition\n" );
return NULL;
}
const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( &criteria, pItemDef );
if ( NULL == pQualityDef )
{
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with unknown quality\n" );
return NULL;
}
// At this point we have everything that can fail will already have failed, so we can safely
// create an item and just move properties over to it.
CEconItem *pItem = new CEconItem();
pItem->SetItemID( GetNextID() );
pItem->SetDefinitionIndex( pItemDef->GetDefinitionIndex() );
pItem->SetItemLevel( criteria.BItemLevelSet() ? criteria.GetItemLevel() : pItemDef->RollItemLevel() );
pItem->SetQuality( pQualityDef->GetDBValue() );
pItem->SetInventoryToken( criteria.GetInitialInventory() );
pItem->SetQuantity( criteria.BInitialQuantitySet() ? criteria.GetInitialQuantity() : pItemDef->GetDefaultDropQuantity() );
// don't set account ID
// Add any custom attributes we need
if( !BAddGCGeneratedAttributesToItem( pGameAccount, pItem ) )
{
delete pItem;
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Failed to generate attributes\n" );
return NULL;
}
return pItem;
}
//-----------------------------------------------------------------------------
// Purpose: Creates an item based on a specific item definition index
// Input: pItem - Pointer to the item to fill in
// unDefinitionIndex - The definition index of the item to create
// Output: True if a matching item could be generated, false otherwise
//-----------------------------------------------------------------------------
CEconItem *CEconItemFactory::CreateSpecificItem( const CEconGameAccount *pGameAccount, item_definition_index_t unDefinitionIndex )
{
// Find the matching index
const CEconItemDefinition *pItemDef = m_schema.GetItemDefinition( unDefinitionIndex );
if ( NULL == pItemDef )
{
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with no matching definition (def index %u)\n", unDefinitionIndex );
return NULL;
}
const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( NULL, pItemDef );
if ( NULL == pQualityDef )
{
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with unknown quality\n" );
return NULL;
}
CEconItem *pItem = new CEconItem();
if ( pGameAccount != NULL )
pItem->SetItemID( GetNextID() );
pItem->SetDefinitionIndex( unDefinitionIndex );
pItem->SetItemLevel( pItemDef->RollItemLevel() );
pItem->SetQuality( pQualityDef->GetDBValue() );
// don't set inventory token
pItem->SetQuantity( MAX( 1, pItemDef->GetDefaultDropQuantity() ) );
// Startup test code calls this with a null pGameAccount.
if ( pGameAccount != NULL )
{
pItem->SetAccountID( pGameAccount->Obj().m_unAccountID );
// Add any custom attributes we need
if( !BAddGCGeneratedAttributesToItem( pGameAccount, pItem ) )
{
delete pItem;
EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Failed to generate attributes\n" );
return NULL;
}
}
return pItem;
}
//-----------------------------------------------------------------------------
// Purpose: Randomly chooses an item definition that matches the criteria
// Input: sCriteria - The criteria that the generated item must match
// Output: The chosen item definition, or NULL if no item could be selected
//-----------------------------------------------------------------------------
const CEconItemDefinition *CEconItemFactory::RollItemDefinition( const CItemSelectionCriteria &criteria ) const
{
// Determine which item templates match the criteria
CUtlVector<item_definition_index_t> vecMatches;
const CEconItemSchema::ItemDefinitionMap_t &mapDefs = m_schema.GetItemDefinitionMap();
FOR_EACH_MAP_FAST( mapDefs, i )
{
if ( criteria.BEvaluate( mapDefs[i] ) )
{
vecMatches.AddToTail( mapDefs.Key( i ) );
}
}
if ( 0 == vecMatches.Count() )
return NULL;
// Choose a random match
int iIndex = RandomInt( 0, vecMatches.Count() - 1 );
return m_schema.GetItemDefinition( vecMatches[iIndex] );
}
//-----------------------------------------------------------------------------
// Purpose: Generates attributes that the item definition insists it always has, but must be generated by the GC
// Input:
//-----------------------------------------------------------------------------
bool CEconItemFactory::BAddGCGeneratedAttributesToItem( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const
{
const CEconItemDefinition *pDef = m_schema.GetItemDefinition( pItem->GetDefinitionIndex() );
if ( !pDef )
return false;
const CUtlVector<static_attrib_t> &vecStaticAttribs = pDef->GetStaticAttributes();
// Only generate attributes that force the GC to generate them (so they vary per item created)
FOR_EACH_VEC( vecStaticAttribs, i )
{
if ( vecStaticAttribs[i].bForceGCToGenerate )
{
ApplyStaticAttributeToItem( pItem, vecStaticAttribs[i], pGameAccount );
}
}
const IEconTool* pTool = pDef->GetEconTool();
if( pTool )
{
if( !pTool->BGenerateDynamicAttributes( pItem, pGameAccount ) )
return false;
}
if ( !pDef->BApplyPropertyGenerators( pItem ) )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemFactory::ApplyStaticAttributeToItem( CEconItem *pItem, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const
{
static CSchemaAttributeDefHandle pAttr_ElevateQuality( "elevate quality" );
static CSchemaAttributeDefHandle pAttr_ElevateToUnusual( "elevate to unusual if applicable" );
static CSchemaAttributeDefHandle pAttr_Particle( "attach particle effect" );
static CSchemaAttributeDefHandle pAttr_HatUnusual( "hat only unusual effect" );
static CSchemaAttributeDefHandle pAttrDef_TauntUnusual( "taunt only unusual effect" );
static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( staticAttrib.iDefIndex );
Assert( pAttrDef );
// Special-case the elevate-quality attribute.
if ( pAttrDef == pAttr_ElevateQuality )
{
//AssertMsg( CEconItem::GetTypedAttributeType<CSchemaAttributeType_Default>( pAttrDef ), "Elevate quality attribute doesn't have the right type!" );
int iQuality = (int)staticAttrib.m_value.asFloat;
// Do not change the quality of an item to Strange if it is not basic
if ( iQuality == AE_STRANGE )
{
if ( pItem->GetQuality() == AE_UNIQUE || pItem->GetQuality() == AE_PAINTKITWEAPON || pItem->GetQuality() == AE_NORMAL )
{
pItem->SetQuality( iQuality );
}
// If the quality is strange, strangify this item
StrangifyItemInPlace( pItem );
}
else
{
pItem->SetQuality( iQuality );
}
return;
}
// Special-case to elevate-quality only if item has particles. This 'attr' needs to be added LAST in a lootlist
// Or rather after particles may have been granted
else if ( pAttrDef == pAttr_ElevateToUnusual )
{
// Scan all attributes.
if ( pItem->FindAttribute( pAttr_Particle ) || pItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
{
pItem->SetQuality( AE_UNUSUAL );
}
return;
}
else if ( pAttrDef == pAttr_HatUnusual )
{
// Ensure the target item is a hat, if it is not bail, if it is setup a particle effect attr (Whole head items are considered 'hats' for purposes of unusuals )
if ( !(pItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "hat" ) )
&& !(pItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "whole_head" ) )
) {
// does not match, bail
return;
}
// create a new static attrib
static_attrib_t unusualAttr( staticAttrib );
// load the normal attach effect instead
pAttr_Particle->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttr_Particle, unusualAttr, pGameAccount );
return;
}
else if ( pAttrDef == pAttrDef_TauntUnusual )
{
// Ensure the target item is a taunt, if it is not bail
if ( pItem->GetItemDefinition()->GetLoadoutSlot( 0 ) != LOADOUT_POSITION_TAUNT )
{
// does not match, bail
CFmtStr fmtStr( "Attempted to put an unusual taunt effect onto item %s, but it's not a taunt! Check which lootlists it appears in and remove it from any that are trying to unusualize it!", pItem->GetItemDefinition()->GetItemDefinitionName() );
EmitError( SPEW_GC, "%s\n", fmtStr.Get() );
return;
}
// create a new static attrib
static_attrib_t unusualAttr( staticAttrib );
// load the normal attach effect instead
pAttrDef_TauntUnusualAttr->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttrDef_TauntUnusualAttr, unusualAttr, pGameAccount );
return;
}
// Custom attribute initialization code?
pAttrDef->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttrDef, staticAttrib, pGameAccount );
}
+75
View File
@@ -0,0 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: EconItemFactory: Manages rolling for items requested by the game server
//
//=============================================================================
#ifndef ECONITEMFACTORY_H
#define ECONITEMFACTORY_H
#ifdef _WIN32
#pragma once
#endif
class CEconItem;
class CEconGameAccount;
namespace GCSDK
{
class CGCSharedObjectCache;
}
#include "game_item_schema.h"
//-----------------------------------------------------------------------------
// CEconItemFactory
// Factory responsible for rolling random items
//-----------------------------------------------------------------------------
class CEconItemFactory
{
public:
CEconItemFactory( );
// Gets a pointer to the underlying item schema the factory is using
GameItemSchema_t &GetSchema() { return m_schema; }
// Create a random item based on the incoming item selection criteria
CEconItem *CreateRandomItem( const CEconGameAccount *pGameAccount, const CItemSelectionCriteria &criteria );
// Create an item from a specific definition index
CEconItem *CreateSpecificItem( const CEconGameAccount *pGameAccount, item_definition_index_t unDefinitionIndex );
CEconItem *CreateSpecificItem( GCSDK::CGCSharedObjectCache *pUserSOCache, item_definition_index_t unDefinitionIndex )
{
return CreateSpecificItem( pUserSOCache->GetSingleton<CEconGameAccount>(), unDefinitionIndex );
}
uint64 GetNextID() { Assert( m_bIsInitialized ); return m_ulNextObjID++; }
bool BYieldingInit();
bool BIsInitialized() { return m_bIsInitialized; }
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName )
{
VALIDATE_SCOPE();
ValidateObj( m_schema );
}
#endif // DBGFLAG_VALIDATE
void ApplyStaticAttributeToItem( CEconItem *pItem, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount ) const;
const CEconItemDefinition *RollItemDefinition( const CItemSelectionCriteria &criteria ) const;
private:
bool BAddGCGeneratedAttributesToItem( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const;
private:
// The schema this factory uses to create items
GameItemSchema_t m_schema;
// the next item ID to give out
itemid_t m_ulNextObjID;
bool m_bIsInitialized;
};
#endif //ECONITEMFACTORY_H
+412
View File
@@ -0,0 +1,412 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "cbase.h"
#include "econ_item_interface.h"
#include "econ_item_tools.h" // needed for CEconTool_WrappedGift definition for IsMarketable()
#include "rtime.h"
#ifdef STAGING_ONLY
ConVar tf_paint_kit_force_wear( "tf_paint_kit_force_wear", "0", FCVAR_REPLICATED, "Set to force the wear level of paink kit weapons and ignore the GC dynamic attribute value." );
#endif
// --------------------------------------------------------------------------
bool IEconItemInterface::GetCustomPaintKitWear( float &flWear ) const
{
#ifdef STAGING_ONLY
// don't assert in staging if this ConVar is set
if ( tf_paint_kit_force_wear.GetInt() > 0 )
{
flWear = tf_paint_kit_force_wear.GetFloat();
return true;
}
#endif // STAGING_ONLY
static CSchemaAttributeDefHandle pAttrDef_PaintKitWear( "set_item_texture_wear" );
float flPaintKitWear = 0;
if ( pAttrDef_PaintKitWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_PaintKitWear, &flPaintKitWear ) )
{
flWear = flPaintKitWear;
return true;
}
static CSchemaAttributeDefHandle pAttrDef_DefaultWear( "texture_wear_default" );
if ( pAttrDef_DefaultWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_DefaultWear, &flPaintKitWear ) )
{
flWear = flPaintKitWear;
return true;
}
// If you have no wear, you also should not have a paint kit
AssertMsg( !GetCustomPainkKitDefinition(), "No Wear Found on Item [%llu - %s] that has a Paintkit!", GetID(), GetItemDefinition()->GetDefinitionName() );
return false;
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
bool IEconItemInterface::IsTemporaryItem() const
{
// store preview items are also temporary
if ( GetOrigin() == kEconItemOrigin_PreviewItem )
return true;
RTime32 rtTime = GetExpirationDate();
if ( rtTime > 0 )
return true;
return false;
}
// --------------------------------------------------------------------------
RTime32 IEconItemInterface::GetExpirationDate() const
{
COMPILE_TIME_ASSERT( sizeof( float ) == sizeof( RTime32 ) );
// dynamic attributes, if present, will override any static expiration timer
static CSchemaAttributeDefHandle pAttrib_ExpirationDate( "expiration date" );
attrib_value_t unAttribExpirationTimeBits;
COMPILE_TIME_ASSERT( sizeof( unAttribExpirationTimeBits ) == sizeof( RTime32 ) );
if ( pAttrib_ExpirationDate && FindAttribute( pAttrib_ExpirationDate, &unAttribExpirationTimeBits ) )
return *(RTime32 *)&unAttribExpirationTimeBits;
// do we have a static timer set in the schema for all instances to expire?
return GetItemDefinition()
? GetItemDefinition()->GetExpirationDate()
: RTime32( 0 );
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
RTime32 IEconItemInterface::GetTradableAfterDateTime() const
{
static CSchemaAttributeDefHandle pAttrib_TradableAfter( "tradable after date" );
Assert( pAttrib_TradableAfter );
if ( !pAttrib_TradableAfter )
return 0;
RTime32 rtTimestamp;
if ( !FindAttribute( pAttrib_TradableAfter, &rtTimestamp ) )
return 0;
return rtTimestamp;
}
// --------------------------------------------------------------------------
// Purpose: Return true if this item can never be traded
// --------------------------------------------------------------------------
bool IEconItemInterface::IsPermanentlyUntradable() const
{
if ( GetItemDefinition() == NULL )
return true;
// tagged to not be a part of the economy?
if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
return true;
// check attributes
static CSchemaAttributeDefHandle pAttrib_AlwaysTradable( "always tradable" );
static CSchemaAttributeDefHandle pAttrib_CannotTrade( "cannot trade" );
static CSchemaAttributeDefHandle pAttrib_NonEconomy( "non economy" );
Assert( pAttrib_AlwaysTradable != NULL );
Assert( pAttrib_CannotTrade != NULL );
if ( pAttrib_AlwaysTradable == NULL || pAttrib_CannotTrade == NULL || pAttrib_NonEconomy == NULL )
return true;
// Order matters, check for nonecon first. Always tradable overrides cannot trade.
if ( FindAttribute( pAttrib_NonEconomy ) )
return true;
if ( FindAttribute( pAttrib_AlwaysTradable ) ) // *sigh*
return false;
if ( FindAttribute( pAttrib_CannotTrade ) )
return true;
// items gained in this way are not tradable
switch ( GetOrigin() )
{
case kEconItemOrigin_Invalid:
case kEconItemOrigin_Achievement:
case kEconItemOrigin_Foreign:
case kEconItemOrigin_PreviewItem:
case kEconItemOrigin_SteamWorkshopContribution:
return true;
}
// temporary items (items that will expire for any reason) cannot be traded
if ( IsTemporaryItem() )
return true;
// certain quality levels are not tradable
if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
return true;
// explicitly marked cannot trade?
if ( ( kEconItemFlag_CannotTrade & GetFlags() ) != 0 )
return true;
return false;
}
// --------------------------------------------------------------------------
// Purpose: Return true if this item is a commodity on the Market (can place buy orders)
// --------------------------------------------------------------------------
bool IEconItemInterface::IsCommodity() const
{
if ( GetItemDefinition() == NULL )
return false;
static CSchemaAttributeDefHandle pAttrib_IsCommodity( "is commodity" );
if ( FindAttribute( pAttrib_IsCommodity ) )
return true;
return false;
}
// --------------------------------------------------------------------------
// Purpose: Return true if temporarily untradable
// --------------------------------------------------------------------------
bool IEconItemInterface::IsTemporarilyUntradable() const
{
// Temporary untradability does NOT take "always tradable" into account
if ( GetTradableAfterDateTime() >= CRTime::RTime32TimeCur() )
return true;
return false;
}
// --------------------------------------------------------------------------
// Purpose: Return true if this item is untradable
// --------------------------------------------------------------------------
bool IEconItemInterface::IsTradable() const
{
// Items that are expired are never listable, regardless of other rules.
//RTime32 timeExpirationDate = GetExpirationDate();
//if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
// return false;
return GetUntradabilityFlags() == 0;
}
// --------------------------------------------------------------------------
// Purpose: Return untradability flags
// --------------------------------------------------------------------------
int IEconItemInterface::GetUntradabilityFlags() const
{
int nFlags = 0;
if ( IsTemporarilyUntradable() )
{
nFlags |= k_Untradability_Temporary;
}
if ( IsPermanentlyUntradable() )
{
nFlags |= k_Untradability_Permanent;
}
return nFlags;
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
bool IEconItemInterface::IsUsableInCrafting() const
{
if ( GetItemDefinition() == NULL )
return false;
// tagged to not be a part of the economy?
if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
return false;
// always craftable?
static CSchemaAttributeDefHandle pAttrib_AlwaysUsableInCraft( "always tradable" );
Assert( pAttrib_AlwaysUsableInCraft );
if ( FindAttribute( pAttrib_AlwaysUsableInCraft ) )
return true;
// never craftable?
static CSchemaAttributeDefHandle pAttrib_NeverCraftable( "never craftable" );
Assert( pAttrib_NeverCraftable );
if ( FindAttribute( pAttrib_NeverCraftable ) )
return false;
// temporary items (items that will expire for any reason) cannot be turned into
// permanent items
if ( IsTemporaryItem() )
return false;
// explicitly marked not usable in crafting?
if ( ( kEconItemFlag_CannotBeUsedInCrafting & GetFlags() ) != 0 )
return false;
// items gained in this way are not craftable
switch ( GetOrigin() )
{
case kEconItemOrigin_Invalid:
case kEconItemOrigin_Foreign:
case kEconItemOrigin_StorePromotion:
case kEconItemOrigin_SteamWorkshopContribution:
return false;
// purchased items can be used in crafting if explicitly tagged, but not by default
case kEconItemOrigin_Purchased:
// deny items the GC didn't flag at purchase time
if ( (GetFlags() & kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012) == 0 )
return false;
// deny items that can never be used
if ( (GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED) == 0 )
return false;
break;
}
// certain quality levels are not craftable
if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
return false;
return true;
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
bool IEconItemInterface::IsMarketable() const
{
const CEconItemDefinition *pItemDef = GetItemDefinition();
if ( pItemDef == NULL )
return false;
// Untradeable items can never be marketed, regardless of other rules.
// Temporarily untradable items can be marketed, only permanent untradable items cannot be marketed
if ( IsPermanentlyUntradable() )
return false;
// Items that are expired are never listable, regardless of other rules.
RTime32 timeExpirationDate = GetExpirationDate();
if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
return false;
// Initially, only TF2 supports listing items in the Marketplace.
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
{
// User-created wrapped gifts are untradeable for the moment. This would provide a backdoor
// for users to sell anything they wanted, which is interesting but not what we want in
// the initial launch.
if ( pItemDef->GetTypedEconTool<CEconTool_WrappedGift>() )
return false;
// All other tools are listable. This includes keys, paints, backpack expanders, strange
// parts, Halloween spells, wedding rings, etc. It does not includes gifts (see above),
// noisemakers, or crates (see below).
if ( pItemDef->IsTool() )
return true;
// All crates are listable. Anything with the "decodable" flag is considered a crate.
if ( (pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE) != 0 )
return true;
// Genuine-quality items come from time-limited purchase promos and are listable. Vintage
// items are from one-time transitions and are all finite quality. Haunted quality items are
// TF-Halloween-event specific. Some of the older haunted items didn't generate revenue, but
// the content is all old and there seems to be little harm in letting it be listed. The
// haunted items from 2013 all come from crates, which means they all generated revenue.
// Collectors items are created from a finite set of recipes.
// Paintkit Weapons are from cases or operations
if ( GetQuality() == AE_RARITY1 || GetQuality() == AE_VINTAGE || GetQuality() == AE_HAUNTED
|| GetQuality() == AE_COLLECTORS || GetQuality() == AE_PAINTKITWEAPON )
return true;
// All festive items are from time-limited holiday crates and are listable. This code seems
// safe. (...) (This code is in fact so safe that if we just do a substring match we'll also
// allow "A Rather Festive Tree".)
if ( !V_strncmp( pItemDef->GetDefinitionName(), "Festive", 7 ) )
return true;
// All botkiller items come from MvM rewards and are listable. This does a substring search
// to find all varieties (gold, silver, rust, etc.), etc.
if ( V_strstr( pItemDef->GetDefinitionName(), " Botkiller " ) )
return true;
// Mvm V2 Robit Parts
if ( V_strstr( pItemDef->GetDefinitionName(), "Robits " ) )
return true;
// MvM Killstreak Weapons
static CSchemaAttributeDefHandle pAttr_killstreak( "killstreak tier" );
if ( FindAttribute( pAttr_killstreak ) )
return true;
// Australium Items
static CSchemaAttributeDefHandle pAttrDef_IsAustralium( "is australium item" );
if ( FindAttribute( pAttrDef_IsAustralium ) )
return true;
// Glitch GateHat Replacement Item
static CSchemaItemDefHandle pItemDef_GlitchedCircuit( "Glitched Circuit Board" );
if ( pItemDef == pItemDef_GlitchedCircuit )
return true;
// Anything that says it wants to be marketable.
static CSchemaAttributeDefHandle pAttrDef_IsMarketable( "is marketable" );
if ( FindAttribute( pAttrDef_IsMarketable ) )
return true;
// Anything that is of limited quantity (ie limited promos)
static CSchemaAttributeDefHandle pAttrDef_IsLimited( "limited quantity item" );
if ( FindAttribute( pAttrDef_IsLimited ) )
return true;
// Allow the Giving items (not a wrapped_gift but a gift, ie Secret Saxton, Pile O Gifts, Pallet of Keys)
const CEconTool_Gift *pEconToolGift = pItemDef->GetTypedEconTool<CEconTool_Gift>();
if ( pEconToolGift )
return true;
// Unusual Cosmetics and Taunts
if ( GetQuality() == AE_UNUSUAL && ( GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT ) )
return true;
// Strange items. Dont just check for strange quality, actually check for a strange attribute.
// See if we've got any strange attributes.
for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
{
if ( FindAttribute( GetKillEaterAttr_Score( i ) ) )
{
return true;
}
}
}
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
// By default, items aren't listable.
return false;
}
// --------------------------------------------------------------------------
const char *IEconItemInterface::GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue ) const
{
const GameItemDefinition_t *pDef = GetItemDefinition();
if ( pDef )
return pDef->GetDefinitionString( pszKeyName, pszDefaultValue );
return pszDefaultValue;
}
// --------------------------------------------------------------------------
KeyValues *IEconItemInterface::GetDefinitionKey( const char *pszKeyName ) const
{
const GameItemDefinition_t *pDef = GetItemDefinition();
if ( pDef )
return pDef->GetDefinitionKey( pszKeyName );
return NULL;
}
+546
View File
@@ -0,0 +1,546 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CEconItem, a shared object for econ items
//
//=============================================================================
#ifndef ECONITEMINTERFACE_H
#define ECONITEMINTERFACE_H
#ifdef _WIN32
#pragma once
#endif
#include "game_item_schema.h" // needed for GameItemDefinition_t
class CAttribute_String;
class CAttribute_DynamicRecipeComponent;
class CAttribute_ItemSlotCriteria;
class CAttribute_WorldItemPlacement;
class IMaterial;
//-----------------------------------------------------------------------------
// Purpose: Template helper classes for dealing with types.
//-----------------------------------------------------------------------------
// StripConstIfPresent<T> will take an input type T and "return" via ResultType:
//
// - T: T
// - const T: T
//
// This is used to prevent having to have different specializations for "T" versus
// "const T" when checking for equivalent template type arguments, etc.
template < typename T >
struct StripConstIfPresent { typedef T ResultType; };
template < typename T > struct StripConstIfPresent<const T> { typedef T ResultType; };
// AreTypesIdentical<T, U> takes two input types and "returns" via kValue whether the
// types are exactly equal. This is intended for checking type equivalence at compile-time
// in ways that template specializations for functions/classes may not be ideal for.
//
// We use it in the attribute code to guarantee that we're only doing The Old, Scary Path
// when dealing with attributes of The Old, Scary Type.
template < typename T, typename U >
struct AreTypesIdentical { enum { kValue = false }; };
template < typename T > struct AreTypesIdentical<T, T> { enum { kValue = true }; };
// IsPointerType<T> takes one input and "returns" via kValue whether the type is a pointer
// type in any way, const, volatile, whatever.
template < typename T >
struct IsPointerType { enum { kValue = false }; };
template < typename T > struct IsPointerType<T *> { enum { kValue = true }; };
// IsValidAttributeValueTypeImpl<T> is a hand-made specialization for what types we want
// to consider valid attribute data types. This is used as a sanity check to make sure we
// don't pass in completely arbitrary types to things like FindAttribute(). (Doing so
// would cause an assert at runtime, but it seems like getting compile-time asserts is
// advantageous, and probably worth paying the small cost of adding to this list whenever
// a new attribute type is added.)
template < typename T>
struct IsValidAttributeValueTypeImpl { enum { kValue = false }; };
template < > struct IsValidAttributeValueTypeImpl<attrib_value_t> { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl<float> { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl<uint64> { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl<CAttribute_String> { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl<CAttribute_DynamicRecipeComponent> { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl < CAttribute_ItemSlotCriteria > { enum { kValue = true }; };
template < > struct IsValidAttributeValueTypeImpl < CAttribute_WorldItemPlacement > { enum { kValue = true }; };
template < typename T >
struct IsValidAttributeValueType : public IsValidAttributeValueTypeImpl< typename StripConstIfPresent<T>::ResultType > { };
//-----------------------------------------------------------------------------
// Purpose: Interface for callback functions per-attribute-data-type. When adding
// a new attribute data type that can't be converted to any existing type,
// you'll need to add a new virtual function here or the code will fail
// to compile.
//-----------------------------------------------------------------------------
class IEconItemAttributeIterator
{
public:
virtual ~IEconItemAttributeIterator ( ) { }
// Returns whether to continue iteration after this element.
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) = 0;
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) = 0;
};
//-----------------------------------------------------------------------------
// Purpose: Iterator where each callback is default implemented, but the value
// is ignored. Derive from this iterator when you only care about certain
// attribute types.
//
//-----------------------------------------------------------------------------
class CEconItemSpecificAttributeIterator : public IEconItemAttributeIterator
{
// By default, always return true
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& value ) { return true; }
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& value ) { return true; }
};
//-----------------------------------------------------------------------------
// Purpose: Interface for a single callback function per-attribute, regardless of
// what type of data it stores and what the value is. This can be used
// to count attributes, display generic information about definitions, etc.
// but can't be used to pull data.
//
// To implement a subclass, override the OnIterateAttributeValueUntyped()
// method.
//-----------------------------------------------------------------------------
class IEconItemUntypedAttributeIterator : public IEconItemAttributeIterator
{
public:
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64& ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent& ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria& ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement& ) OVERRIDE
{
return OnIterateAttributeValueUntyped( pAttrDef );
}
private:
virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) = 0;
};
//-----------------------------------------------------------------------------
// Purpose: Simple class to answer the question "does this attribute exist" without
// regards to what value it might have. Intended to be used by FindAttribute()
// but made global because why not.
//-----------------------------------------------------------------------------
class CAttributeIterator_HasAttribute : public IEconItemUntypedAttributeIterator
{
public:
CAttributeIterator_HasAttribute( const CEconItemAttributeDefinition *pAttrDef )
: m_pAttrDef( pAttrDef )
, m_bFound( false )
{
Assert( m_pAttrDef );
}
bool WasFound() const
{
return m_bFound;
}
private:
bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) OVERRIDE
{
// We don't assert because we might be reusing the same iterator between calls.
// Assert( !m_bFound );
if ( m_pAttrDef == pAttrDef )
{
m_bFound = true;
}
return !m_bFound;
}
private:
const CEconItemAttributeDefinition *m_pAttrDef;
bool m_bFound;
};
//-----------------------------------------------------------------------------
// Purpose: Helper class to answer the question "does this attribute exist? and if
// so what is its value?". There are some template shenanigans that happen
// to make things as safe as possible, and to catch errors as early as
// possible.
//
// TActualTypeInMemory: the in-memory type of the data we're going to try
// to read out (ie., "attrib_value_t", "CAttribute_String",
// etc.
//
// TTreatAsThisType: if TActualTypeInMemory is "attrib_value_t", then we're
// dealing with the old attribute system and so maybe we
// want to treat these bits as a float, or a bitmask, or
// who knows! Specifying this type for non-attrib_value_t
// in-memory types is invalid and will fail to compile.
//
// This class isn't intended to be used directly but instead called from
// either FindAttribute() or FindAttribute_UnsafeBitwiseCast(). It's
// global because C++ doesn't support template member functions on a
// template class inside a standalone template function. Weird.
//-----------------------------------------------------------------------------
template < typename TActualTypeInMemory, typename TTreatAsThisType = TActualTypeInMemory >
class CAttributeIterator_GetTypedAttributeValue : public IEconItemAttributeIterator
{
public:
CAttributeIterator_GetTypedAttributeValue( const CEconItemAttributeDefinition *pAttrDef, TTreatAsThisType *outpValue )
: m_pAttrDef( pAttrDef )
, m_outpValue( outpValue )
, m_bFound( false )
{
// If this fails, it means that the type TActualTypeInMemory isn't something the attribute
// system is prepared to recognize as a valid attribute storage type. The list of valid types
// are IsValidAttributeValueTypeImpl<> specializations.
//
// If you added a new type and didn't make a specialization for it, this will fail. If you
// *didn't* add a new type, it probably means you're passing a pointer of an incorrect type
// in to FindAttribute().
COMPILE_TIME_ASSERT( IsValidAttributeValueType<TActualTypeInMemory>::kValue );
// The only reason we allow callers to specify a different TTreatAsThisType (versus having
// it always match TActualTypeInMemory) is to deal with the old attribute system, which sometimes
// had attributes have int/float types and sometimes had attribute data values that were 32
// arbitrary bits. We test here to make sure that we're only using the "treat these bits as
// a different type" behavior code when dealing with attributes using the old storage system
// (attrib_value_t) or when we're trying to get the pointer to buffer contents for a string.
COMPILE_TIME_ASSERT( ((AreTypesIdentical<TActualTypeInMemory, attrib_value_t>::kValue && AreTypesIdentical<TTreatAsThisType, float>::kValue) ||
(AreTypesIdentical<TActualTypeInMemory, CAttribute_String>::kValue && AreTypesIdentical<TTreatAsThisType, const char *>::kValue) ||
AreTypesIdentical<TActualTypeInMemory, TTreatAsThisType>::kValue) );
Assert( m_pAttrDef );
Assert( outpValue );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const uint64 & value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String & value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_DynamicRecipeComponent & value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_ItemSlotCriteria & value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_WorldItemPlacement & value ) OVERRIDE
{
return OnIterateAttributeValueTyped( pAttrDef, value );
}
bool WasFound() const
{
return m_bFound;
}
private:
// Generic template function for handling any attribute value of any type besides the one that we're looking
// for. For example, if we say "we're looking for attribute 'damage multiplier' and give me back a float", then
// all other attribute value types (strings, structures, etc.) will go through this code, which does nothing
// except look for caller errors.
//
// If you call FindAttribute() and specify the wrong type for an attribute (ie., using the above example, looking
// for "damage multiplier" but feeding in a string), it will get found in this function, which will assert and
// tell you you've got the wrong type. (FindAttribute() in that case will return false because it's impossible
// for us to safely copy the value out.)
template < typename TAnyOtherType >
bool OnIterateAttributeValueTyped( const CEconItemAttributeDefinition *pAttrDef, const TAnyOtherType& value )
{
COMPILE_TIME_ASSERT( IsValidAttributeValueType<TAnyOtherType>::kValue );
// We don't assert because we might be reusing the same iterator between calls.
// Assert( !m_bFound );
AssertMsg( m_pAttrDef != pAttrDef, "Incorrect type found for attribute during iteration." );
return true;
}
// Overload for attributes of the data type we're looking for. ie., if we say "we're looking for attribute
// 'damage multiplier' and give me back a float", this will be the <float> specialization. We assume that
// we're only going to find at most one attribute per definition and stop looking after we've found the first.
//
// Note that this is just a normal member function, but is *not* a template member function, which would compile
// under VC but otherwise be illegal.
bool OnIterateAttributeValueTyped( const CEconItemAttributeDefinition *pAttrDef, const TActualTypeInMemory& value )
{
// We don't assert because we might be reusing the same iterator between calls.
// Assert( !m_bFound );
if ( m_pAttrDef == pAttrDef )
{
m_bFound = true;
CopyAttributeValueToOutput( &value, reinterpret_cast<TTreatAsThisType *>( m_outpValue ) );
}
return !m_bFound;
}
private:
static void CopyAttributeValueToOutput( const TActualTypeInMemory *pValue, TTreatAsThisType *out_pValue )
{
// Even if we are using the old attribute type system, we need to guarantee that the type
// in memory (ie., uint32) and the type we're considering it as (ie., float) are the same size
// because we're going to be doing bitwise casts.
COMPILE_TIME_ASSERT( sizeof( TActualTypeInMemory ) == sizeof( TTreatAsThisType ) );
Assert( pValue );
Assert( out_pValue );
*out_pValue = *reinterpret_cast<const TTreatAsThisType *>( pValue );
}
private:
const CEconItemAttributeDefinition *m_pAttrDef;
TTreatAsThisType *m_outpValue;
bool m_bFound;
};
//-----------------------------------------------------------------------------
// Purpose: Custom code path to support getting the char * result from an
// attribute of type CAttribute_String.
//
// We can't specify the implementation here because we may or may not
// have the definition of CAttribute_String in scope. We also can't
// declare the template specialization here and define it later because
// that would violate the standard, so instead we have the template
// function call a declared-but-not-defined non-template function that
// we can define later.
//-----------------------------------------------------------------------------
void CopyStringAttributeValueToCharPointerOutput( const CAttribute_String *pValue, const char **out_pValue );
template < >
inline void CAttributeIterator_GetTypedAttributeValue<CAttribute_String, const char *>::CopyAttributeValueToOutput( const CAttribute_String *pValue, const char **out_pValue )
{
CopyStringAttributeValueToCharPointerOutput( pValue, out_pValue );
}
//-----------------------------------------------------------------------------
// Purpose: Look for the existence/nonexistence of an attribute with the
// definition [pAttrDef]. Can be called on anything with an IterateAttributes()
// member functions (IEconItemInterface, CEconItemDefinition).
//-----------------------------------------------------------------------------
template < typename TAttributeContainerType >
bool FindAttribute( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef )
{
#ifdef CLIENT_DLL
VPROF_BUDGET( "IEconItemInterface::FindAttribute", VPROF_BUDGETGROUP_FINDATTRIBUTE );
#endif
if ( !pAttrDef )
return false;
CAttributeIterator_HasAttribute it( pAttrDef );
pSomethingThatHasAnIterateAttributesFunction->IterateAttributes( &it );
return it.WasFound();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < typename TActualTypeInMemory, typename TTreatAsThisType, typename TAttributeContainerType >
bool FindAttribute_UnsafeBitwiseCast( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef, TTreatAsThisType *out_pValue )
{
#ifdef CLIENT_DLL
VPROF_BUDGET( "IEconItemInterface::FindAttribute_UnsafeBitwiseCast", VPROF_BUDGETGROUP_FINDATTRIBUTEUNSAFE );
#endif
if ( !pAttrDef )
return false;
CAttributeIterator_GetTypedAttributeValue<TActualTypeInMemory, TTreatAsThisType> it( pAttrDef, out_pValue );
pSomethingThatHasAnIterateAttributesFunction->IterateAttributes( &it );
return it.WasFound();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
template < typename TAttributeContainerType, typename T >
bool FindAttribute( const TAttributeContainerType *pSomethingThatHasAnIterateAttributesFunction, const CEconItemAttributeDefinition *pAttrDef, T *out_pValue )
{
return FindAttribute_UnsafeBitwiseCast<T, T, TAttributeContainerType>( pSomethingThatHasAnIterateAttributesFunction, pAttrDef, out_pValue );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class IEconItemInterface
{
public:
virtual ~IEconItemInterface() { }
// Is an attribute present? We neither know nor care anything about the attribute
// value stored.
bool FindAttribute( const CEconItemAttributeDefinition *pAttrDef ) const
{
return ::FindAttribute( this, pAttrDef );
}
// If an attribute is present, it will copy the value into out_pValue and return true.
// If the attribute is not present, it will return false and not touch the value in
// out_pValue. If a T is passed in that is not a type the attribute system understands,
// this function will fail to compile.
template < typename T >
bool FindAttribute( const CEconItemAttributeDefinition *pAttrDef, T *out_pValue ) const
{
return ::FindAttribute( this, pAttrDef, out_pValue );
}
// Helpers to look for specific attribute values
virtual CEconItemPaintKitDefinition *GetCustomPainkKitDefinition( void ) const { return GetItemDefinition() ? GetItemDefinition()->GetCustomPainkKitDefinition() : NULL; }
virtual bool GetCustomPaintKitWear( float &flWear ) const;
// IEconItemInterface common implementation.
virtual bool IsTradable() const;
virtual int GetUntradabilityFlags() const;
virtual bool IsCommodity() const;
virtual bool IsUsableInCrafting() const;
virtual bool IsMarketable() const; // can this item be listed on the Marketplace?
bool IsTemporaryItem() const; // returns whether this item is a temporary instance of an item that is not by nature temporary (ie., a preview item, an item with an attribute expiration timer)
RTime32 GetExpirationDate() const; // will return RTime32( 0 ) if this item will not expire, otherwise the time that it will auto-delete itself; this looks at both static and dynamic ways of expiring timers
// IEconItemInterface interface.
virtual const GameItemDefinition_t *GetItemDefinition() const = 0;
virtual itemid_t GetID() const = 0; // intentionally not called GetItemID to avoid stomping non-virtual GetItemID() on CEconItem
virtual uint32 GetAccountID() const = 0;
virtual int32 GetQuality() const = 0;
virtual style_index_t GetStyle() const = 0;
virtual uint8 GetFlags() const = 0;
virtual eEconItemOrigin GetOrigin() const = 0;
virtual int GetQuantity() const = 0;
virtual uint32 GetItemLevel() const = 0;
virtual bool GetInUse() const = 0; // is this item in use somewhere in the backend? (ie., cross-game trading)
virtual const char *GetCustomName() const = 0; // get a user-generated name, if present, otherwise NULL; return value is UTF8
virtual const char *GetCustomDesc() const = 0; // get a user-generated flavor text, if present, otherwise NULL; return value is UTF8
// IEconItemInterface attribute iteration interface. This is not meant to be used for
// attribute lookup! This is meant for anything that requires iterating over the full
// attribute list.
virtual void IterateAttributes( IEconItemAttributeIterator *pIterator ) const = 0;
// Fetch values from the definition
const char *GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue = "" ) const;
KeyValues *GetDefinitionKey( const char *pszKeyName ) const;
RTime32 GetTradableAfterDateTime() const;
virtual item_definition_index_t GetItemDefIndex() const { return GetItemDefinition() ? GetItemDefinition()->GetDefinitionIndex() : INVALID_ITEM_DEF_INDEX; }
virtual IMaterial* GetMaterialOverride( int iTeam ) = 0;
protected:
bool IsPermanentlyUntradable() const;
bool IsTemporarilyUntradable() const;
};
//-----------------------------------------------------------------------------
// Purpose: Classes that want default behavior for GetMaterialOverride, which
// currently derive from IEconItemInterface can instead derive from
// CMaterialOverrideContainer< IEconItemInterface > and have the details
// of material overrides hidden from them.
//-----------------------------------------------------------------------------
template <typename TBaseClass>
class CMaterialOverrideContainer : public TBaseClass
{
public:
virtual IMaterial* GetMaterialOverride( int iTeam ) OVERRIDE
{
#ifdef CLIENT_DLL
Assert( iTeam >= 0 && iTeam < ARRAYSIZE( m_materialOverrides ) );
if ( m_materialOverrides[ iTeam ].IsValid() )
return m_materialOverrides[ iTeam ];
if ( !this->GetItemDefinition() )
return NULL;
const char* pName = this->GetItemDefinition()->GetMaterialOverride( iTeam );
if ( pName == NULL )
return NULL;
m_materialOverrides[ iTeam ].Init( pName, TEXTURE_GROUP_CLIENT_EFFECTS );
return m_materialOverrides[ iTeam ];
#else
return NULL;
#endif
}
protected:
void ResetMaterialOverrides()
{
#ifdef CLIENT_DLL
for ( int i = 0; i < TF_TEAM_COUNT; ++i )
m_materialOverrides[ i ].Shutdown();
#endif
}
private:
#ifdef CLIENT_DLL
CMaterialReference m_materialOverrides[ TF_TEAM_COUNT ];
#endif
};
#endif // ECONITEMINTERFACE_H
File diff suppressed because it is too large Load Diff
+472
View File
@@ -0,0 +1,472 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Container that allows client & server access to data in player inventories & loadouts
//
//=============================================================================
#ifndef ITEM_INVENTORY_H
#define ITEM_INVENTORY_H
#ifdef _WIN32
#pragma once
#endif
#include "igamesystem.h"
#include "econ_entity.h"
#include "gamestringpool.h"
#include "econ_item_view.h"
#include "UtlSortVector.h"
#include "econ_gcmessages.h"
#include "gc_clientsystem.h"
#if !defined(NO_STEAM)
#include "steam/steam_api.h"
#include "gcsdk/gcclientsdk.h"
#endif // NO_STEAM
class CPlayerInventory;
class CEconItem;
struct baseitemcriteria_t;
class CEconItemViewHandle;
#ifdef CLIENT_DLL
class ITexture;
#endif
// Inventory Less function.
// Used to sort the inventory items into their positions.
class CInventoryListLess
{
public:
bool Less( const CEconItemView &src1, const CEconItemView &src2, void *pCtx );
};
// A class that wants notifications when an inventory is updated
class IInventoryUpdateListener : public GCSDK::ISharedObjectListener
{
public:
virtual void InventoryUpdated( CPlayerInventory *pInventory ) = 0;
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
};
//-----------------------------------------------------------------------------
// Purpose: A single player's inventory.
// On the client, the inventory manager contains an instance of this for the local player.
// On the server, each player contains an instance of this.
//-----------------------------------------------------------------------------
class CPlayerInventory : public GCSDK::ISharedObjectListener
{
DECLARE_CLASS_NOBASE( CPlayerInventory );
public:
CPlayerInventory();
virtual ~CPlayerInventory();
void Clear();
// Returns true if this inventory has been filled out by Steam.
bool RetrievedInventoryFromSteam( void ) { return m_bGotItemsFromSteam; }
bool IsWaitingForSteam( void ) { return (m_iPendingRequests > 0); }
// Inventory access
CSteamID &GetOwner( void ) { return m_OwnerID; }
int GetItemCount( void ) const { return m_aInventoryItems.Count(); }
virtual bool CanPurchaseItems( int iItemCount ) const { return GetMaxItemCount() - GetItemCount() >= iItemCount; }
virtual int GetMaxItemCount( void ) const { return DEFAULT_NUM_BACKPACK_SLOTS; }
CEconItemView *GetItem( int i ) { return &m_aInventoryItems[i]; }
virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) { AssertMsg( 0, "Implement me!" ); return NULL; }
// Get the item object cache data for the specified item
CEconItem *GetSOCDataForItem( itemid_t iItemID );
GCSDK::CGCClientSharedObjectCache *GetSOC( void ) { return m_pSOCache; }
// tells the GC systems to forget about this listener
void RemoveListener( GCSDK::ISharedObjectListener *pListener );
// Finds the item in our inventory that matches the specified global index
CEconItemView *GetInventoryItemByItemID( itemid_t iIndex, int *pIndex = NULL );
// Finds the item in our inventory that matches the specified global original id
CEconItemView *GetInventoryItemByOriginalID( itemid_t iOriginalID, int *pIndex = NULL );
// Finds the item in our inventory in the specified position
CEconItemView *GetItemByPosition( int iPosition, int *pIndex = NULL );
// Finds the first item in our backpack with match itemdef
CEconItemView *FindFirstItembyItemDef( item_definition_index_t iItemDef );
// Used to reject items on the backend for inclusion into this inventory.
// Mostly used for division of bags into different in-game inventories.
virtual bool ItemShouldBeIncluded( int iItemPosition ) { return true; }
// Debugging
virtual void DumpInventoryToConsole( bool bRoot );
// Extracts the position that should be used to sort items in the inventory from the backend position.
// Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
virtual int ExtractInventorySortPosition( uint32 iBackendPosition ) { return iBackendPosition; }
// Recipe access
int GetRecipeCount( void ) const;
const CEconCraftingRecipeDefinition *GetRecipeDef( int iIndex );
const CEconCraftingRecipeDefinition *GetRecipeDefByDefIndex( uint16 iDefIndex );
// Item previews
virtual int GetPreviewItemDef( void ) const { return 0; };
// Access helpers
virtual void SOClear();
virtual void NotifyHasNewItems() {}
void AddItemHandle( CEconItemViewHandle* pHandle );
void RemoveItemHandle( CEconItemViewHandle* pHandle );
#ifdef CLIENT_DLL
virtual ITexture *GetWeaponSkinBaseLowRes( itemid_t nItemId, int iTeam ) const { return NULL; }
#endif
protected:
// Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
// use the SteamRequestX functions in CInventoryManager.
void RequestInventory( CSteamID pSteamID );
void AddListener( GCSDK::ISharedObjectListener *pListener );
virtual bool AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems );
virtual void RemoveItem( itemid_t iItemID );
bool FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem );
void SendInventoryUpdateEvent();
virtual void OnHasNewItems() {}
virtual void OnItemChangedPosition( CEconItemView *pItem, uint32 iOldPos ) { return; }
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
void ResortInventory( void ) { m_aInventoryItems.RedoSort( true ); }
virtual void ValidateInventoryPositions( void );
// Derived inventory hooks
virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile );
virtual void ItemIsBeingRemoved( CEconItemView *pItem ) { return; }
// Get the index for the item in our inventory utlvector
int GetIndexForItem( CEconItemView *pItem );
void DirtyItemHandles();
protected:
// The Steam Id of the player who owns this inventory
CSteamID m_OwnerID;
// The items the player has in his inventory, received from steam.
CUtlSortVector<CEconItemView,CInventoryListLess> m_aInventoryItems;
int m_iPendingRequests;
bool m_bGotItemsFromSteam;
GCSDK::CGCClientSharedObjectCache *m_pSOCache;
CUtlVector<GCSDK::ISharedObjectListener *> m_vecListeners;
CUtlVector< CEconItemViewHandle* > m_vecItemHandles;
friend class CInventoryManager;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CInventoryManager : public CAutoGameSystemPerFrame
{
DECLARE_CLASS_GAMEROOT( CInventoryManager, CAutoGameSystem );
public:
CInventoryManager( void );
// Adds the inventory to the list of inventories that should be maintained.
// This causes the game to load the items for the SteamID into this inventory.
// NOTE: This fires off a request to Steam. The data will not be filled out immediately.
void SteamRequestInventory( CPlayerInventory *pInventory, CSteamID pSteamID, IInventoryUpdateListener *pListener = NULL );
void PreInitGC();
void PostInitGC();
#ifdef CLIENT_DLL
void DropItem( itemid_t iItemID );
int DeleteUnknowns( CPlayerInventory *pInventory );
#endif
public:
//-----------------------------------------------------------------------
// IAutoServerSystem
//-----------------------------------------------------------------------
virtual bool Init( void ) OVERRIDE;
virtual void PostInit( void ) OVERRIDE;
virtual void Shutdown() OVERRIDE;
virtual void LevelInitPreEntity( void ) OVERRIDE;
virtual void LevelShutdownPostEntity( void ) OVERRIDE;
#ifdef CLIENT_DLL
// Gets called each frame
virtual void Update( float frametime ) OVERRIDE;
#endif
void GameServerSteamAPIActivated();
virtual CPlayerInventory *GetInventoryForAccount( uint32 iAccountID );
// We're generating a base item. We need to add the game-specific keys to the criteria so that it'll find the right base item.
virtual void AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria ) { return; }
#ifdef CLIENT_DLL
// Must be implemented by derived class
virtual bool EquipItemInLoadout( int iClass, int iSlot, itemid_t iItemID ) = 0;
virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CPlayerInventory; }
//-----------------------------------------------------------------------
// ITEM PRESETS
//-----------------------------------------------------------------------
// Is the given preset index valid?
bool IsPresetIndexValid( equipped_preset_t unPreset );
// Equip all items for the given class and preset (all the work is done on the GC -- this just
// sends the message up)
bool LoadPreset( equipped_class_t unClass, equipped_preset_t unPreset );
//-----------------------------------------------------------------------
// LOCAL INVENTORY
//
// On the client, we have a single inventory for the local player. Stored here, instead of in the
// local player entity, because players need to access it while not being connected to a server.
// Override GetLocalInventory() in your inventory manager and return your custom local inventory.
//-----------------------------------------------------------------------
virtual void UpdateLocalInventory( void );
virtual CPlayerInventory *GetLocalInventory( void ) { return NULL; }
// The local inventory is used to track discards & responses to. We need to
// make a decision about inventory space right after sending a delete request,
// so we predict the request will work.
void OnItemDeleted( CPlayerInventory *pInventory ) { if ( pInventory == GetLocalInventory() ) m_iPredictedDiscards--; }
virtual void PersonaName_Precache( uint32 unAccountID );
virtual const char *PersonaName_Get( uint32 unAccountID );
virtual void PersonaName_Store( uint32 unAccountID, const char *pPersonaName );
static void SendGCConnectedEvent( void );
// Returns the item at the specified backpack position
virtual CEconItemView *GetItemByBackpackPosition( int iBackpackPosition );
// Moves the item to the specified backpack position. If there's another item as that spot, it swaps positions with it.
virtual void MoveItemToBackpackPosition( CEconItemView *pItem, int iBackpackPosition );
// Tries to set the item to the specified backpack position. Passing in 0 will find the first empty position.
// FAILS if the backpack is full, or if that spot isn't clear. Returns false in that case.
virtual bool SetItemBackpackPosition( CEconItemView *pItem, uint32 iPosition = 0, bool bForceUnequip = false, bool bAllowOverflow = false );
// Sort the backpack items by the specified type
virtual void SortBackpackBy( uint32 iSortType );
void SortBackpackFinished( void );
bool IsInBackpackSort( void ) { return m_bInBackpackSort; }
void PredictedBackpackPosFilled( int iBackpackPos ) { m_PredictedFilledSlots.FindAndRemove( iBackpackPos ); }
// Tell the backend to move an item to a specified backend position
virtual void UpdateInventoryPosition( CPlayerInventory *pInventory, uint64 ulItemID, uint32 unNewInventoryPos );
virtual void UpdateInventoryEquippedState( CPlayerInventory *pInventory, uint64 ulItemID, equipped_class_t unClass, equipped_slot_t unSlot );
//-----------------------------------------------------------------------
// CLIENT PICKUP UI HANDLING
//-----------------------------------------------------------------------
// Get the number of items picked up
virtual int GetNumItemPickedUpItems( void ) { return 0; }
// Show the player a pickup screen with any items they've collected recently, if any
virtual bool ShowItemsPickedUp( bool bForce = false, bool bReturnToGame = true, bool bNoPanel = false );
// Show the player a pickup screen with the items they've crafted
virtual void ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices ) { return; }
// Force the player to discard an item to make room for a new item, if they have one.
// Returns true if the discard panel has been brought up, and the player will be forced to discard an item.
virtual bool CheckForRoomAndForceDiscard( void );
//-----------------------------------------------------------------------
// CLIENT ITEM PICKUP ACKNOWLEDGEMENT FILES
//
// This system avoids showing multiple pickups for items that we've found, but haven't been
// able to move out of unack'd position due to the GC being unavailable. We keep a list of
// items we've ack'd in a client file, and don't re-show pickups for them. When a GC item
// update tells us the item has moved out of the unack'd position, we remove it from our file.
//-----------------------------------------------------------------------
virtual void AcknowledgeItem ( CEconItemView *pItem, bool bMoveToBackpack = true ); // Client Acknowledges an item and moves it in to the backpack
bool HasBeenAckedByClient( CEconItemView *pItem ); // Returns true if it's in our client file
void SetAckedByClient( CEconItemView *pItem ); // Adds it to our client file
void SetAckedByGC( CEconItemView *pItem, bool bSave ); // Removes it from our client file
KeyValues *GetAckKeyForItem( CEconItemView *pItem );
void CleanAckFile( void );
void SaveAckFile( void );
private:
void VerifyAckFileLoaded( void );
KeyValues *m_pkvItemClientAckFile;
bool m_bClientAckDirty;
private:
// As we move items around in batches (on pickups usually) we need to know what slots will be filled
// by items we've moved, and haven't received a response from Steam.
CUtlVector<int> m_PredictedFilledSlots;
#endif
public:
virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
private:
//-----------------------------------------------------------------------
// Pending inventory requests
struct pendingreq_t
{
CPlayerInventory *pInventory;
CSteamID pID;
};
CUtlVector<pendingreq_t> m_hPendingInventoryRequests;
void RemovePendingRequest( CSteamID *pSteamID );
protected:
//-----------------------------------------------------------------------
// Inventory registry
void DeregisterInventory( CPlayerInventory *pInventory );
struct inventories_t
{
CPlayerInventory *pInventory;
IInventoryUpdateListener *pListener;
};
CUtlVector<inventories_t> m_pInventories;
friend class CPlayerInventory;
inline bool IsValidPlayerClass( equipped_class_t unClass );
#ifdef CLIENT_DLL
// Keep track of the number of items we've tried to discard, but haven't recieved responses on
int m_iPredictedDiscards;
typedef CUtlMap< uint32, CUtlString, int > tPersonaNamesByAccountID;
tPersonaNamesByAccountID m_mapPersonaNamesCache;
bool m_bInBackpackSort;
float m_flNextLoadPresetChange;
CMsgSetItemPositions m_msgPendingSetItemPositions;
CMsgLookupMultipleAccountNames m_msgPendingLookupAccountNames;
void OnPersonaStateChanged( PersonaStateChange_t *info );
CCallback< CInventoryManager, PersonaStateChange_t, false > m_sPersonaStateChangedCallback;
CUtlMap< uint64, bool > m_personaNameRequests;
#endif
};
//=================================================================================
// Implement these functions in your game code to create custom derived versions
CInventoryManager *InventoryManager( void );
CBasePlayer *GetPlayerBySteamID( const CSteamID &steamID );
//-----------------------------------------------------------------------------
// Purpose: Maintains a handle to an CEconItemView within an inventory. When
// the inventory gets updated and shuffles CEconItemViews around, this
// handle automatically updates its pointer to point to the new
// CEconItemView that has the same item_id
//-----------------------------------------------------------------------------
class CEconItemViewHandle
{
public:
CEconItemViewHandle()
: m_pItem( NULL )
, m_pInv( NULL )
, m_bPointerDirty( false )
{}
CEconItemViewHandle( CEconItemView* pItem )
: m_pItem( pItem )
, m_pInv( NULL )
, m_bPointerDirty( false )
{
SetItem( pItem );
}
virtual ~CEconItemViewHandle()
{
// Unregister us
if ( m_pInv )
{
m_pInv->RemoveItemHandle( this );
}
}
void SetItem( CEconItemView* pItem );
operator CEconItemView *( void ) const
{
return Get();
}
CEconItemView* operator->( void ) const
{
return Get();
}
void ItemIsBeingDeleted( const CEconItemView* pItem )
{
m_bPointerDirty = true;
// Inventory told us the item is going away
if ( m_pItem == pItem )
{
m_pItem = NULL;
}
}
void InventoryIsBeingDeleted()
{
m_pInv = NULL;
m_pItem = NULL;
m_bPointerDirty = false; // So we dont keep trying to look up the item
}
void MarkDirty()
{
m_bPointerDirty = true;
}
private:
CEconItemView* Get() const;
mutable bool m_bPointerDirty; // Used to mark when m_pItem is no longer valid
CPlayerInventory *m_pInv; // Inventory the item belongs to. Used to look up new CEconItemView
mutable CEconItemView* m_pItem; // The item.
uint64 m_nItemID; // ID of the item
CSteamID m_OwnerSteamID; // Steam ID of the item owner
};
#endif // ITEM_INVENTORY_H
+338
View File
@@ -0,0 +1,338 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//===================================================================
#include "cbase.h"
#include "econ_item_preset.h"
#include "tier1/generichash.h"
#ifdef GC_DLL
#include "gcsdk/sqlaccess/sqlaccess.h"
#endif
using namespace GCSDK;
#ifdef GC_DLL
IMPLEMENT_CLASS_MEMPOOL( CEconItemPerClassPresetData, 10 * 1000, UTLMEMORYPOOL_GROW_SLOW );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
CEconItemPerClassPresetData::CEconItemPerClassPresetData()
: m_unAccountID( 0 )
, m_unClassID( (equipped_class_t)-1 )
, m_unActivePreset( INVALID_PRESET_INDEX )
{
}
CEconItemPerClassPresetData::CEconItemPerClassPresetData( uint32 unAccountID, equipped_class_t unClassID )
: m_unAccountID( unAccountID )
, m_unClassID( unClassID )
, m_unActivePreset( 0 )
{
}
void CEconItemPerClassPresetData::SerializeToProtoBufItem( CSOClassPresetClientData& msgPresetData ) const
{
msgPresetData.set_account_id( m_unAccountID );
msgPresetData.set_class_id( m_unClassID );
msgPresetData.set_active_preset_id( m_unActivePreset );
}
void CEconItemPerClassPresetData::DeserializeFromProtoBufItem( const CSOClassPresetClientData &msgPresetData )
{
m_unAccountID = msgPresetData.account_id();
m_unClassID = msgPresetData.class_id();
m_unActivePreset = msgPresetData.active_preset_id();
}
bool CEconItemPerClassPresetData::BIsKeyLess( const CSharedObject& soRHS ) const
{
const CEconItemPerClassPresetData *soPresetData = assert_cast< const CEconItemPerClassPresetData * >( &soRHS );
Assert( m_unAccountID == soPresetData->m_unAccountID );
return m_unClassID < soPresetData->m_unClassID;
}
#ifdef GC
static bool BYieldingAddPresetItemRowsForSpecificPreset( GCSDK::CSQLAccess &sqlAccess, CSchItemPresetInstance& schItemPresetInstance, const CUtlVector<PresetSlotItem_t>& vecPresetData )
{
FOR_EACH_VEC( vecPresetData, j )
{
schItemPresetInstance.m_unSlotID = vecPresetData[j].m_unSlotID;
schItemPresetInstance.m_ulItemID = vecPresetData[j].m_ulItemOriginalID;
if ( !sqlAccess.BYieldingInsertRecord( &schItemPresetInstance ) )
return false;
}
return true;
}
bool CEconItemPerClassPresetData::BYieldingAddInsertToTransaction( GCSDK::CSQLAccess &sqlAccess )
{
// Write out the preset data for our selected items.
CSchItemPresetInstance schItemPresetInstance;
schItemPresetInstance.m_unAccountID = m_unAccountID;
schItemPresetInstance.m_unClassID = m_unClassID;
for ( int i = 0; i < ARRAYSIZE( m_PresetData ); i++ )
{
schItemPresetInstance.m_unPresetID = i;
if ( !BYieldingAddPresetItemRowsForSpecificPreset( sqlAccess, schItemPresetInstance, m_PresetData[i] ) )
return false;
}
// Write out the data for which preset is active for this class.
CSchSelectedItemPreset schSelectedItemPreset;
schSelectedItemPreset.m_unAccountID = m_unAccountID;
schSelectedItemPreset.m_unClassID = m_unClassID;
schSelectedItemPreset.m_unPresetID = m_unActivePreset;
if ( !sqlAccess.BYieldingInsertRecord( &schSelectedItemPreset ) )
return false;
return true;
}
bool CEconItemPerClassPresetData::BYieldingAddWriteToTransaction( GCSDK::CSQLAccess &sqlAccess, const CUtlVector< int > &fields )
{
Assert( sqlAccess.BInTransaction() );
FOR_EACH_VEC( fields, i )
{
const int iField = fields[i];
if ( iField == kPerClassPresetDataDirtyField_ActivePreset )
{
CSchSelectedItemPreset schSelectedItemPreset;
schSelectedItemPreset.m_unAccountID = m_unAccountID;
schSelectedItemPreset.m_unClassID = m_unClassID;
schSelectedItemPreset.m_unPresetID = m_unActivePreset;
if ( !sqlAccess.BYieldingUpdateRecord( schSelectedItemPreset, CSET_2_COL( CSchSelectedItemPreset, k_iField_unAccountID, k_iField_unClassID ), CSET_1_COL( CSchSelectedItemPreset, k_iField_unPresetID ) ) )
return false;
}
else if ( iField >= kPerClassPresetDataDirtyField_PresetData_Base )
{
int iDirtyPreset = iField - kPerClassPresetDataDirtyField_PresetData_Base;
Assert( iDirtyPreset >= 0 );
Assert( iDirtyPreset < ARRAYSIZE( m_PresetData ) );
// First, remove any existing rows for this preset.
CSchItemPresetInstance schItemPresetInstance;
schItemPresetInstance.m_unAccountID = m_unAccountID;
schItemPresetInstance.m_unClassID = m_unClassID;
schItemPresetInstance.m_unPresetID = iDirtyPreset;
if ( !sqlAccess.BYieldingDeleteRecords( schItemPresetInstance, CSET_3_COL( CSchItemPresetInstance, k_iField_unAccountID, k_iField_unPresetID, k_iField_unClassID ) ) )
return false;
// Don't write out data for our currently-equipped items. We'll handle these by
// writing them out as actually equipped.
if ( iDirtyPreset != GetActivePreset() )
{
// Add our new rows.
if ( !BYieldingAddPresetItemRowsForSpecificPreset( sqlAccess, schItemPresetInstance, m_PresetData[iDirtyPreset] ) )
return false;
}
}
}
return true;
}
bool CEconItemPerClassPresetData::BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess &sqlAccess )
{
CSchItemPresetInstance schItemPresetInstance;
schItemPresetInstance.m_unAccountID = m_unAccountID;
schItemPresetInstance.m_unClassID = m_unClassID;
if ( !sqlAccess.BYieldingDeleteRecords( schItemPresetInstance, CSET_2_COL( CSchItemPresetInstance, k_iField_unAccountID, k_iField_unClassID ) ) )
return false;
CSchSelectedItemPreset schSelectedItemPreset;
schSelectedItemPreset.m_unAccountID = m_unAccountID;
schSelectedItemPreset.m_unClassID = m_unClassID;
if ( !sqlAccess.BYieldingDeleteRecords( schSelectedItemPreset, CSET_2_COL( CSchSelectedItemPreset, k_iField_unAccountID, k_iField_unClassID ) ) )
return false;
return true;
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
bool CEconItemPerClassPresetData::BAddToMessage( CUtlBuffer & bufOutput ) const
{
CSOClassPresetClientData msgClientPresetData;
SerializeToProtoBufItem( msgClientPresetData );
return CProtoBufSharedObjectBase::SerializeToBuffer( msgClientPresetData, bufOutput );
}
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
bool CEconItemPerClassPresetData::BAddToMessage( std::string *pBuffer ) const
{
CSOClassPresetClientData msgClientPresetData;
SerializeToProtoBufItem( msgClientPresetData );
return msgClientPresetData.SerializeToString( pBuffer );
}
//----------------------------------------------------------------------------
// Purpose: Adds just the item ID to the message so that the client can find
// which item to destroy
//----------------------------------------------------------------------------
bool CEconItemPerClassPresetData::BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const
{
CSOClassPresetClientData msgClientPresetData;
msgClientPresetData.set_class_id( m_unClassID );
return CProtoBufSharedObjectBase::SerializeToBuffer( msgClientPresetData, bufDestroy );
}
//----------------------------------------------------------------------------
// Purpose: Adds just the item ID to the message so that the client can find
// which item to destroy
//----------------------------------------------------------------------------
bool CEconItemPerClassPresetData::BAddDestroyToMessage( std::string *pBuffer ) const
{
CSOClassPresetClientData msgClientPresetData;
msgClientPresetData.set_class_id( m_unClassID );
return msgClientPresetData.SerializeToString( pBuffer );
}
#endif
bool CEconItemPerClassPresetData::BParseFromMessage( const CUtlBuffer & buffer )
{
CSOClassPresetClientData msgClientPresetData;
if( !msgClientPresetData.ParseFromArray( buffer.Base(), buffer.TellMaxPut() ) )
return false;
DeserializeFromProtoBufItem( msgClientPresetData );
return true;
}
bool CEconItemPerClassPresetData::BParseFromMessage( const std::string &buffer )
{
CSOClassPresetClientData msgClientPresetData;
if( !msgClientPresetData.ParseFromString( buffer ) )
return false;
DeserializeFromProtoBufItem( msgClientPresetData );
return true;
}
//----------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------
bool CEconItemPerClassPresetData::BUpdateFromNetwork( const CSharedObject & objUpdate )
{
Copy( objUpdate );
return true;
}
void CEconItemPerClassPresetData::Copy( const CSharedObject & soRHS )
{
const CEconItemPerClassPresetData& rhs = static_cast<const CEconItemPerClassPresetData&>( soRHS );
m_unAccountID = rhs.m_unAccountID;
m_unClassID = rhs.m_unClassID;
m_unActivePreset = rhs.m_unActivePreset;
for ( int i = 0; i < ARRAYSIZE( m_PresetData ); i++ )
{
m_PresetData[i].CopyArray( rhs.m_PresetData[i].Base(), rhs.m_PresetData[i].Count() );
}
}
void CEconItemPerClassPresetData::Dump() const
{
#if 0
EmitInfo( SPEW_GC, SPEW_ALWAYS, LOG_ALWAYS, "preset id=%d class id=%d slot id=%d item id=%llu\n",
m_unPresetID, m_unClassID, m_unSlotID, m_ulItemID );
#endif
}
#ifdef GC_DLL
//----------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------
const CUtlVector<PresetSlotItem_t> *CEconItemPerClassPresetData::FindItemsForPresetIndex( equipped_preset_t unPreset ) const
{
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
return NULL;
return &m_PresetData[ unPreset ];
}
//----------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------
void CEconItemPerClassPresetData::SetActivePreset( equipped_preset_t unPreset )
{
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
return;
m_unActivePreset = unPreset;
}
//----------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------
void CEconItemPerClassPresetData::EquipItemIntoActivePresetSlot( equipped_slot_t unSlot, itemid_t unOriginalItemID )
{
Assert( GetItemSchema()->IsValidItemSlot( unSlot, EQUIP_TYPE_CLASS ) );
Assert( m_unActivePreset < ARRAYSIZE( m_PresetData ) );
auto& PresetData = m_PresetData[m_unActivePreset];
FOR_EACH_VEC( PresetData, i )
{
if ( PresetData[i].m_unSlotID == unSlot )
{
// If we're unequipping, stop tracking this slot.
if ( unOriginalItemID == INVALID_ITEM_ID )
{
PresetData.FastRemove( i );
}
// Otherwise store the current reference.
else
{
PresetData[i].m_ulItemOriginalID = unOriginalItemID;
}
return;
}
}
// We don't expect to get here without having an item equipped already, but it's possible if
// items get swapped around on the back end, or if we process messages out of order and/or drop
// some.
if ( unOriginalItemID != INVALID_ITEM_ID )
{
PresetSlotItem_t PresetSlotItem;
PresetSlotItem.m_unSlotID = unSlot;
PresetSlotItem.m_ulItemOriginalID = unOriginalItemID;
PresetData.AddToTail( PresetSlotItem );
}
}
//----------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------
void CEconItemPerClassPresetData::RemoveAllItemsFromPresetIndex( equipped_preset_t unPreset )
{
if ( unPreset >= ARRAYSIZE( m_PresetData ) )
return;
m_PresetData[unPreset].Purge();
}
#endif // GC_DLL
+102
View File
@@ -0,0 +1,102 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//===================================================================
#ifndef ECONITEMPRESET_H
#define ECONITEMPRESET_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/protobufsharedobject.h"
#include "gcsdk/gcclientsdk.h"
#include "base_gcmessages.pb.h"
#include "econ/econ_item_constants.h"
namespace GCSDK
{
class CSQLAccess;
};
class CSOClassPresetClientData;
typedef uint8 equipped_preset_t;
struct PresetSlotItem_t
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( PresetSlotItem_t );
#endif
equipped_slot_t m_unSlotID;
itemid_t m_ulItemOriginalID; // Original ID of the item in this slot. We store this instead of the current ID to avoid breaking presets when items get renamed, etc.
};
// --------------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------------
class CEconItemPerClassPresetData : public GCSDK::CSharedObject
{
#ifdef GC_DLL
DECLARE_CLASS_MEMPOOL( CEconItemPerClassPresetData );
#endif
public:
typedef GCSDK::CSharedObject BaseClass;
const static int k_nTypeID = k_EEconTypeItemPresetInstance;
virtual int GetTypeID() const OVERRIDE { return k_nTypeID; }
CEconItemPerClassPresetData();
CEconItemPerClassPresetData( uint32 unAccountID, equipped_class_t unClassID );
virtual bool BIsKeyLess( const CSharedObject& soRHS ) const;
#ifdef GC
virtual bool BYieldingAddInsertToTransaction( GCSDK::CSQLAccess &sqlAccess ) OVERRIDE;
virtual bool BYieldingAddWriteToTransaction( GCSDK::CSQLAccess &sqlAccess, const CUtlVector< int > &fields ) OVERRIDE;
virtual bool BYieldingAddRemoveToTransaction( GCSDK::CSQLAccess &sqlAccess ) OVERRIDE;
virtual bool BAddToMessage( CUtlBuffer & bufOutput ) const OVERRIDE;
virtual bool BAddToMessage( std::string *pBuffer ) const OVERRIDE;
virtual bool BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const OVERRIDE;
virtual bool BAddDestroyToMessage( std::string *pBuffer ) const OVERRIDE;
#endif
virtual bool BParseFromMessage( const CUtlBuffer & buffer ) OVERRIDE;
virtual bool BParseFromMessage( const std::string &buffer ) OVERRIDE;
virtual bool BUpdateFromNetwork( const CSharedObject & objUpdate ) OVERRIDE;
virtual void Copy( const CSharedObject & soRHS );
virtual void Dump() const;
void SerializeToProtoBufItem( CSOClassPresetClientData &msgPresetInstance ) const;
void DeserializeFromProtoBufItem( const CSOClassPresetClientData &msgPresetIntance );
enum
{
kPerClassPresetDataDirtyField_ActivePreset,
kPerClassPresetDataDirtyField_PresetData_Base,
};
#ifdef GC_DLL
const CUtlVector<PresetSlotItem_t> *FindItemsForPresetIndex( equipped_preset_t unPreset ) const;
void EquipItemIntoActivePresetSlot( equipped_slot_t unSlot, itemid_t unOriginalItemID );
void RemoveAllItemsFromPresetIndex( equipped_preset_t unPreset );
void SetActivePreset( equipped_preset_t unPreset );
equipped_class_t GetClass() const { return m_unClassID; }
#endif // GC_DLL
equipped_preset_t GetActivePreset() const { return m_unActivePreset; }
private:
CEconItemPerClassPresetData( const CEconItemPerClassPresetData& ) = delete;
void operator=( const CEconItemPerClassPresetData& ) = delete;
private:
uint32 m_unAccountID;
equipped_class_t m_unClassID;
equipped_preset_t m_unActivePreset;
CUtlVector<PresetSlotItem_t> m_PresetData[ CEconItemSchema::kMaxItemPresetCount ];
};
#endif // ECONITEMPRESET_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+694
View File
@@ -0,0 +1,694 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "tier1/KeyValues.h"
#include "econ_gcmessages.h"
#include "econ_item_system.h"
#include "econ_item_inventory.h"
#include "game_item_schema.h"
#include "gc_clientsystem.h"
#include "utldict.h"
#include "filesystem.h"
#include "steam/isteamhttp.h"
#if defined(CLIENT_DLL) || defined(GAME_DLL)
#include "gamestringpool.h"
#include "ihasattributes.h"
#include "tier0/icommandline.h"
#endif
#if defined(CLIENT_DLL)
#include "igameevents.h"
#endif
// FIXME FIXME FIXME
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
#include "tf_item_system.h"
#endif // defined(TF_DLL) || defined(TF_CLIENT_DLL)
#if defined (DOTA_CLIENT_DLL) || defined (DOTA_DLL)
#include "econ/dota_item_system.h"
#endif // defined (DOTA_CLIENT_DLL) || defined (DOTA_DLL)
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if ( defined( GAME_DLL ) || defined( CLIENT_DLL ) ) && ( defined( _DEBUG ) || defined( STAGING_ONLY ) )
ConVar item_debug( "item_debug", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY );
ConVar items_game_use_gc_copy( "items_game_use_gc_copy", "1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_ARCHIVE, "If set, items_game.txt will be stomped by the GC." );
ConVar item_debug_validation( "item_debug_validation", "1", FCVAR_REPLICATED | FCVAR_ARCHIVE, "If set, CEconEntity::ValidateEntityAttachedToPlayer behaves as it would in release builds and also allows bot players to take the same code path as real players." );
#endif
static ConVar item_quality_chance_unique( "item_quality_chance_unique", "0.1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is unique." );
static ConVar item_quality_chance_rare( "item_quality_chance_rare", "0.5", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is a rare." );
static ConVar item_quality_chance_common( "item_quality_chance_common", "1.0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Percentage chance that a random item is common." );
//-----------------------------------------------------------------------------
// Purpose: Get at the global item system
//-----------------------------------------------------------------------------
CEconItemSystem *ItemSystem( void )
{
static GameItemSystem_t *pSystem = NULL;
if ( !pSystem )
{
pSystem = new GameItemSystem_t();
}
return pSystem;
}
//-----------------------------------------------------------------------------
// Purpose: Global schema access, declared in game_item_schema.h
//-----------------------------------------------------------------------------
GameItemSchema_t *GetItemSchema()
{
return ItemSystem()->GetItemSchema();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEconItemSystem::CEconItemSystem( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEconItemSystem::~CEconItemSystem( void )
{
Shutdown();
}
//-----------------------------------------------------------------------------
// Purpose: Parse in our data files.
//-----------------------------------------------------------------------------
void CEconItemSystem::Init( void )
{
#if defined(USES_ECON_ITEMS)
ParseItemSchemaFile( "scripts/items/items_game.txt" );
#endif
#ifdef CLIENT_DLL
IGameEvent *event = gameeventmanager->CreateEvent( "item_schema_initialized" );
if ( event )
{
gameeventmanager->FireEventClientSide( event );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemSystem::Shutdown( void )
{
}
extern ConVar mp_tournament;
#ifdef GAME_DLL
ConVar mp_tournament_whitelist( "mp_tournament_whitelist", "item_whitelist.txt", FCVAR_NONE, "Specifies the item whitelist file to use." );
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemSystem::ReloadWhitelist( void )
{
// Default state of items depends on whether we're in tourney mode, and whether there's a whitelist
bool bDefault = true;
bool bFoundWhitelist = false;
KeyValues *pWhitelistKV = new KeyValues( "item_whitelist" );
#ifdef GAME_DLL
if ( mp_tournament.GetBool() && mp_tournament_whitelist.GetString() )
{
const char *pszWhitelistFile = mp_tournament_whitelist.GetString();
if ( pWhitelistKV->LoadFromFile( filesystem, pszWhitelistFile ) )
{
// Allow the whitelist to override the default, so they can turn it into a blacklist if they want to
bDefault = pWhitelistKV->GetBool( "unlisted_items_default_to" );
bFoundWhitelist = true;
}
else if ( pszWhitelistFile && pszWhitelistFile[0] )
{
Msg("Item Whitelist file '%s' could not be found. All items will be allowed.\n", pszWhitelistFile );
}
}
#endif
const CEconItemSchema::ItemDefinitionMap_t& mapItemDefs = m_itemSchema.GetItemDefinitionMap();
FOR_EACH_MAP_FAST( mapItemDefs, i )
{
mapItemDefs[i]->SetAllowedInMatch( bDefault );
}
// If we didn't find a file, we're done.
if ( !bFoundWhitelist )
return;
// Otherwise, go through the KVs and turn on the matching items.
Msg("Parsing item whitelist (default: %s)\n", bDefault ? "allowed" : "disallowed" );
pWhitelistKV = pWhitelistKV->GetFirstSubKey();
while ( pWhitelistKV )
{
bool bAllow = pWhitelistKV->GetBool();
const char *pszItemName = pWhitelistKV->GetName();
if ( pszItemName && pszItemName[0] && !FStrEq("unlisted_items_default_to", pszItemName) )
{
CEconItemDefinition *pItemDef = m_itemSchema.GetItemDefinitionByName( pszItemName );
if ( pItemDef )
{
pItemDef->SetAllowedInMatch( bAllow );
Msg(" -> %s '%s'\n", bAllow ? "Allowing" : "Removing", pszItemName );
}
else
{
Warning(" -> Could not find an item definition named '%s'\n", pszItemName );
}
}
pWhitelistKV = pWhitelistKV->GetNextKey();
}
Msg("Finished.\n");
}
#ifdef GAME_DLL
CON_COMMAND_F( item_show_whitelistable_definitions, "Lists the item definitions that can be whitelisted in the item_whitelist.txt file in tournament mode.", FCVAR_CHEAT )
{
Msg("Available item definitions for whitelisting:\n");
const CEconItemSchema::SortedItemDefinitionMap_t& mapItemDefs = ItemSystem()->GetItemSchema()->GetSortedItemDefinitionMap();
FOR_EACH_MAP( mapItemDefs, i )
{
const CEconItemDefinition *pItemDef = mapItemDefs[i];
if ( pItemDef && pItemDef->GetQuality() != AE_NORMAL && !pItemDef->IsHidden() )
{
Msg(" '%s'\n", pItemDef->GetDefinitionName() );
}
}
}
#endif // GAME_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconItemSystem::ResetAttribStringCache( void )
{
const CUtlMap<int, CEconItemAttributeDefinition, int> &mapDefs = m_itemSchema.GetAttributeDefinitionMap();
FOR_EACH_MAP_FAST( mapDefs, i )
{
mapDefs[i].ClearStringCache();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconItemSystem::DecryptItemFiles( KeyValues *pKV, const char *pName )
{
char szFullName[512];
Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", pName );
FileHandle_t f = filesystem->Open( szFullName, "rb", "MOD" );
if (!f)
{
#if !defined(CSTRIKE_DLL)
Warning("No %s file found. May be unable to create items.\n", pName );
#endif // CSTRIKE_DLL
return false;
}
int fileSize = filesystem->Size(f);
char *buffer = (char*)MemAllocScratch(fileSize + 1);
Assert(buffer);
filesystem->Read(buffer, fileSize, f); // read into local buffer
buffer[fileSize] = 0; // null terminate file as EOF
filesystem->Close( f ); // close file after reading
UTIL_DecodeICE( (unsigned char*)buffer, fileSize, GetEncryptionKey() );
bool retOK = pKV->LoadFromBuffer( szFullName, buffer, filesystem );
MemFreeScratch();
if ( !retOK )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Read the specified item schema file. Init the item schema with the contents
//-----------------------------------------------------------------------------
void CEconItemSystem::ParseItemSchemaFile( const char *pFilename )
{
CUtlVector< CUtlString > vecErrors;
bool bSuccess = m_itemSchema.BInit( pFilename, "MOD", &vecErrors );
if( !bSuccess )
{
FOR_EACH_VEC( vecErrors, nError )
{
// we want this to be an Error because several
// places rely on loading a valid item schema
Error( "%s\n", vecErrors[nError].String() );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Generate a random item matching the specified criteria
//-----------------------------------------------------------------------------
item_definition_index_t CEconItemSystem::GenerateRandomItem( CItemSelectionCriteria *pCriteria, entityquality_t *outEntityQuality )
{
// First, pick a random item quality (use the one passed in first)
if ( !pCriteria->BQualitySet() )
{
pCriteria->SetQuality( GetRandomQualityForItem() );
}
pCriteria->SetIgnoreEnabledFlag( true );
// Determine which item templates match the criteria
CUtlVector<item_definition_index_t> vecMatches;
const CEconItemSchema::ItemDefinitionMap_t &mapDefs = m_itemSchema.GetItemDefinitionMap();
HackMakeValidList:
FOR_EACH_MAP_FAST( mapDefs, i )
{
if ( pCriteria->BEvaluate( mapDefs[i] ) )
{
vecMatches.AddToTail( mapDefs.Key( i ) );
}
}
// No valid items?
int iValidItems = vecMatches.Count();
if ( !iValidItems )
{
// If we were searching for a unique item, drop back to a non-unique
if ( pCriteria->GetQuality() == AE_UNIQUE )
{
pCriteria->SetQuality( GetRandomQualityForItem( true ) );
goto HackMakeValidList;
}
return INVALID_ITEM_DEF_INDEX;
}
// Choose a random match
int iChosenIdx = RandomInt( 0, (iValidItems-1) );
item_definition_index_t iChosenItem = vecMatches[iChosenIdx];
const CEconItemDefinition *pItemDef = m_itemSchema.GetItemDefinition( iChosenItem );
if ( !pItemDef )
return INVALID_ITEM_DEF_INDEX;
// If we haven't specified an entity quality, we want to use the item's specified one
if ( pCriteria->GetQuality() == AE_USE_SCRIPT_VALUE )
{
int32 iScriptQuality = pItemDef->GetQuality();
pCriteria->SetQuality( iScriptQuality == AE_UNDEFINED ? GetRandomQualityForItem( true ) : iScriptQuality );
}
// If we haven't specified an item level, we want to use the item's specified one.
if ( !pCriteria->BItemLevelSet() )
{
pCriteria->SetItemLevel( RandomInt( pItemDef->GetMinLevel(), pItemDef->GetMaxLevel() ) );
}
if ( outEntityQuality )
{
*outEntityQuality = pCriteria->GetQuality();
}
return iChosenItem;
}
//-----------------------------------------------------------------------------
// Purpose: Return a random quality for the item specified
//-----------------------------------------------------------------------------
entityquality_t CEconItemSystem::GetRandomQualityForItem( bool bPreventUnique )
{
// Start on the rarest, and work backwards
if ( !bPreventUnique )
{
if ( RandomFloat(0,1) < item_quality_chance_unique.GetFloat() )
return AE_UNIQUE;
}
if ( RandomFloat(0,1) < item_quality_chance_rare.GetFloat() )
return AE_RARITY2;
if ( RandomFloat(0,1) < item_quality_chance_common.GetFloat() )
return AE_RARITY1;
return AE_NORMAL;
}
static ISteamHTTP *GetISteamHTTP()
{
if ( steamapicontext != NULL && steamapicontext->SteamHTTP() )
{
return steamapicontext->SteamHTTP();
}
#ifndef CLIENT_DLL
if ( steamgameserverapicontext != NULL )
{
return steamgameserverapicontext->SteamHTTP();
}
#endif
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Common functionality for using our raw buffer data to initialize
// the schema when safe.
//-----------------------------------------------------------------------------
bool IDelayedSchemaData::InitializeSchemaInternal( CEconItemSchema *pItemSchema, CUtlBuffer& bufRawData, bool bInitAsBinary, uint32 nExpectedVersion )
{
Msg( "Applying new item schema, version %08X\n", nExpectedVersion );
CUtlVector<CUtlString> vecErrors;
bool bSuccess = bInitAsBinary
? pItemSchema->BInitBinaryBuffer( bufRawData, &vecErrors )
: pItemSchema->BInitTextBuffer( bufRawData, &vecErrors );
if( bSuccess )
{
// Sanity-check that we received the version that they sent us
uint32 nOurVersion = pItemSchema->GetVersion();
if ( nExpectedVersion != 0 && nOurVersion != nExpectedVersion )
{
Warning( "**WARNING** Item schema mismatch after update!\n" );
Warning( "GC told us to expect %08X, we got %08X\n", nExpectedVersion, nOurVersion );
}
}
else
{
Warning( "**WARNING** Failed to apply item schema!\n" );
FOR_EACH_VEC( vecErrors, nError )
{
Warning( "%s\n", vecErrors[nError].Get() );
}
}
return bSuccess;
}
//-----------------------------------------------------------------------------
// Purpose: The GC sent us a single block of binary data.
//-----------------------------------------------------------------------------
class DelayedSchemaData_GCDirectData : public IDelayedSchemaData
{
public:
DelayedSchemaData_GCDirectData( const std::string& strBuffer )
: m_bufRawData( strBuffer.data(), strBuffer.size(), CUtlBuffer::READ_ONLY )
{
//
}
virtual bool InitializeSchema( CEconItemSchema *pItemSchema )
{
return InitializeSchemaInternal( pItemSchema, m_bufRawData, true, 0 );
}
private:
CUtlBuffer m_bufRawData;
};
extern bool CheckValveSignature( const void *data, uint32 nDataSize, const void *signature, uint32 nSignatureSize );
//-----------------------------------------------------------------------------
// Purpose: We received a text file from an HTML request.
//-----------------------------------------------------------------------------
class DelayedSchemaData_HTTPResponseData : public IDelayedSchemaData
{
public:
DelayedSchemaData_HTTPResponseData( ISteamHTTP *pHTTP, HTTPRequestHandle handleHTTPRequest, uint32 unBodySize, uint32 nExpectedVersion, const std::string &sSignature )
: m_nExpectedVersion( nExpectedVersion )
{
Assert( pHTTP );
m_bufRawData.SetBufferType( true, true );
m_bufRawData.SeekPut( CUtlBuffer::SEEK_HEAD, unBodySize );
m_bValid = pHTTP->GetHTTPResponseBodyData( handleHTTPRequest, (uint8*)m_bufRawData.Base(), m_bufRawData.TellPut() );
if ( m_bValid )
m_bValid = CheckValveSignature( m_bufRawData.Base(), m_bufRawData.TellPut(), sSignature.c_str(), sSignature.length() );
}
virtual bool InitializeSchema( CEconItemSchema *pItemSchema )
{
if ( !m_bValid )
return false;
return InitializeSchemaInternal( pItemSchema, m_bufRawData, false, m_nExpectedVersion );
}
private:
bool m_bValid;
CUtlBuffer m_bufRawData;
uint32 m_nExpectedVersion;
};
#define GC_ITEM_SCHEMA_UPDATE_APPLIED "Applied updated item schema from GC. %d bytes, version %08X.\n"
#define GC_ITEM_SCHEMA_UPDATE_QUEUED "Received %d bytes item schema version %08X direct data; update is queued.\n"
//-----------------------------------------------------------------------------
// Purpose: Update the item schema from the GC
//-----------------------------------------------------------------------------
class CGCUpdateItemSchema : public GCSDK::CGCClientJob
{
public:
CGCUpdateItemSchema( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {
m_szUrl[0] = '\0';
m_nExpectedVersion = 0;
bHTTPCompleted = false;
}
char m_szUrl[512];
uint32 m_nExpectedVersion;
bool bHTTPCompleted;
CCallResult< CGCUpdateItemSchema, HTTPRequestCompleted_t > callback;
std::string m_sSignature;
virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
{
GCSDK::CProtoBufMsg< CMsgUpdateItemSchema > msg( pNetPacket );
#if ( defined( GAME_DLL ) || defined( CLIENT_DLL ) ) && ( defined( _DEBUG ) || defined( STAGING_ONLY ) )
const bool bUseGCCopy = items_game_use_gc_copy.GetBool();
#else
const bool bUseGCCopy = true;
#endif
if ( bUseGCCopy == false && k_EUniversePublic != GetUniverse() )
{
Msg( "Loading item schema from local file.\n" );
KeyValuesAD pItemsGameKV( "ItemsGameFile" );
if ( pItemsGameKV->LoadFromFile( g_pFullFileSystem, "scripts/items/items_game.txt", "GAME" ) )
{
CUtlBuffer buffer;
pItemsGameKV->WriteAsBinary( buffer );
CUtlVector< CUtlString > vecErrors;
bool bSuccess = ItemSystem()->GetItemSchema()->BInitBinaryBuffer( buffer, &vecErrors );
if( !bSuccess )
{
FOR_EACH_VEC( vecErrors, nError )
{
Warning( "%s\n", vecErrors[nError].Get() );
}
}
}
return true;
}
// Check if we're already up-to-date
m_nExpectedVersion = msg.Body().item_schema_version();
uint32 nCurrentSchemaVersion = ItemSystem()->GetItemSchema()->GetVersion();
if ( m_nExpectedVersion != 0 && m_nExpectedVersion == nCurrentSchemaVersion )
{
Msg( "Current item schema is up-to-date with version %08X.\n", nCurrentSchemaVersion );
return true;
}
m_sSignature = msg.Body().signature();
// !TEST!
//const char *szURL = "http://cdn.beta.steampowered.com/apps/440/scripts/items/items_game.b8b7a85b4dd98b139957004b86ec0bc070a59d18.txt";
if ( msg.Body().has_items_game() )
{
bool bDidInit = ItemSystem()->GetItemSchema()->MaybeInitFromBuffer( new DelayedSchemaData_GCDirectData( msg.Body().items_game() ) );
Msg( bDidInit ? GC_ITEM_SCHEMA_UPDATE_APPLIED : GC_ITEM_SCHEMA_UPDATE_QUEUED, (int)msg.Body().items_game().size(), m_nExpectedVersion );
}
else
{
// Remember URL
const char *szURL = msg.Body().items_game_url().c_str();
if ( !szURL || !szURL[0] )
{
Warning( "GC sent malformed CGCUpdateItemSchema message: No schema data, no URL\n" );
}
else
{
Q_strncpy( m_szUrl, szURL, sizeof( m_szUrl ) );
//Msg( "Fetching %s to update item schema\n", m_szUrl );
// Send an HTTP request for the file
ISteamHTTP *pHTTP = GetISteamHTTP();
if ( !pHTTP )
{
//Warning( "Can't get ISteamHTTP to update item schema\n");
return true;
}
HTTPRequestHandle hReq = pHTTP->CreateHTTPRequest( k_EHTTPMethodGET, m_szUrl );
pHTTP->SetHTTPRequestNetworkActivityTimeout( hReq, 10 );
SteamAPICall_t hCall;
if ( !pHTTP->SendHTTPRequest( hReq, &hCall ) )
{
Warning( "Failed to update item schema: couldn't fetch %s\n", m_szUrl );
return true;
}
//
// *Wait* for completion.
//
// This is important. The GC needs to be able to safely assume that
// we will not process the next message until we have finished
// dealing with this one.
//
bHTTPCompleted = false;
#ifndef CLIENT_DLL
if ( steamgameserverapicontext != NULL && pHTTP == steamgameserverapicontext->SteamHTTP() )
{
callback.SetGameserverFlag();
}
#endif
callback.Set( hCall, this, &CGCUpdateItemSchema::OnHTTPCompleted );
// Wait for it to finish.
while ( !bHTTPCompleted )
{
BYieldingWaitOneFrame();
}
}
}
return true;
}
void OnHTTPCompleted( HTTPRequestCompleted_t *arg, bool bFailed )
{
// Clear flag, no matter what else, so we can stop yielding
bHTTPCompleted = true;
ISteamHTTP *pHTTP = GetISteamHTTP();
Assert( pHTTP );
if ( !pHTTP ) return;
if ( arg->m_eStatusCode != k_EHTTPStatusCode200OK )
{
Warning( "Failed to update item schema: HTTP status %d fetching %s\n", arg->m_eStatusCode, m_szUrl );
}
else
{
if ( !arg->m_bRequestSuccessful )
{
bFailed = true;
}
if ( !bFailed )
{
uint32 unBodySize;
if ( !pHTTP->GetHTTPResponseBodySize( arg->m_hRequest, &unBodySize ) )
{
Assert( false );
bFailed = true;
}
else
{
bool bDidInit = ItemSystem()->GetItemSchema()->MaybeInitFromBuffer( new DelayedSchemaData_HTTPResponseData( pHTTP, arg->m_hRequest, unBodySize, m_nExpectedVersion, m_sSignature ) );
Msg( bDidInit ? GC_ITEM_SCHEMA_UPDATE_APPLIED : GC_ITEM_SCHEMA_UPDATE_QUEUED, unBodySize, m_nExpectedVersion );
}
}
if ( bFailed )
{
Warning( "Failed to update item schema from %s\n", m_szUrl );
}
}
pHTTP->ReleaseHTTPRequest( arg->m_hRequest );
}
};
GC_REG_JOB( GCSDK::CGCClient, CGCUpdateItemSchema, "CGCUpdateItemSchema", k_EMsgGCUpdateItemSchema, GCSDK::k_EServerTypeGCClient );
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Update the item schema from the GC
//-----------------------------------------------------------------------------
CON_COMMAND_F( econ_show_items_with_tag, "Lists the item definitions that have a specified tag.", FCVAR_CLIENTDLL )
{
if ( args.ArgC() != 2 )
return;
econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( args.Arg( 1 ) );
FOR_EACH_MAP( GetItemSchema()->GetSortedItemDefinitionMap(), i )
{
const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinitionMap()[i];
if ( pItemDef->HasEconTag( tagHandle ) )
{
Msg(" '%s'\n", pItemDef->GetDefinitionName() );
}
}
}
#endif // CLIENT_DLL
#ifdef STAGING_ONLY
//-----------------------------------------------------------------------------
// Purpose: Update the item schema from the GC
//-----------------------------------------------------------------------------
#ifdef CLIENT_DLL
CON_COMMAND_F( cl_reload_local_item_schema, "Reloads the local item schema copy.", FCVAR_CLIENTDLL )
#else
CON_COMMAND_F( sv_reload_local_item_schema, "Reloads the local item schema copy.", FCVAR_GAMEDLL )
#endif
{
#ifdef CLIENT_DLL
engine->ClientCmd_Unrestricted( "cmd sv_reload_local_item_schema" );
#endif
Msg( "Loading item schema from local file.\n" );
KeyValuesAD pItemsGameKV( "ItemsGameFile" );
if ( pItemsGameKV->LoadFromFile( g_pFullFileSystem, "scripts/items/items_game.txt", "GAME" ) )
{
CUtlBuffer buffer;
pItemsGameKV->WriteAsBinary( buffer );
CUtlVector< CUtlString > vecErrors;
bool bSuccess = ItemSystem()->GetItemSchema()->BInitBinaryBuffer( buffer, &vecErrors );
if( !bSuccess )
{
FOR_EACH_VEC( vecErrors, nError )
{
Warning( "%s\n", vecErrors[nError].Get() );
}
}
}
}
#endif
+86
View File
@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ECON_ITEM_SYSTEM_H
#define ECON_ITEM_SYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#include "econ_item_view.h"
#include "game_item_schema.h"
//==================================================================================
// ITEM SYSTEM
//==================================================================================
#define GC_MOTD_CACHE_FILE "cfg/motd_entries.txt"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEconItemSystem
{
public:
CEconItemSystem( void );
virtual ~CEconItemSystem( void );
// Setup & parse in the item data files.
void Init( void );
void Shutdown( void );
// Return the static item data for the specified item index
GameItemDefinition_t *GetStaticDataForItemByDefIndex( item_definition_index_t iItemDefIndex )
{
return (GameItemDefinition_t *)m_itemSchema.GetItemDefinition( iItemDefIndex );
}
CEconItemDefinition *GetStaticDataForItemByName( const char *pszDefName )
{
return m_itemSchema.GetItemDefinitionByName( pszDefName );
}
CEconItemAttributeDefinition *GetStaticDataForAttributeByDefIndex( attrib_definition_index_t iAttribDefinitionIndex )
{
return m_itemSchema.GetAttributeDefinition( iAttribDefinitionIndex );
}
CEconItemAttributeDefinition *GetStaticDataForAttributeByName( const char *pszDefName )
{
return m_itemSchema.GetAttributeDefinitionByName( pszDefName );
}
// Select and return a random item's definition index matching the specified criteria
item_definition_index_t GenerateRandomItem( CItemSelectionCriteria *pCriteria, entityquality_t *outEntityQuality );
// Select and return the base item definition index for a class's load-out slot
// Note: baseitemcriteria_t is game-specific and/or may not exist!
virtual item_definition_index_t GenerateBaseItem( struct baseitemcriteria_t *pCriteria ) { return INVALID_ITEM_DEF_INDEX; }
// Return a random item quality
entityquality_t GetRandomQualityForItem( bool bPreventUnique = false );
// Decrypt the item files and return the keyvalue
bool DecryptItemFiles( KeyValues *pKV, const char *pName );
GameItemSchema_t *GetItemSchema() { return &m_itemSchema; }
// Open the server's whitelist, and if it exists, set the appropriate items allowed.
void ReloadWhitelist( void );
void ResetAttribStringCache( void );
protected:
// Read the specified item schema file. Init the item schema with the contents
void ParseItemSchemaFile( const char *pFilename );
// Key to decrypt the item description files
const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"A5fSXbf7"; }
private:
GameItemSchema_t m_itemSchema;
};
CEconItemSystem *ItemSystem( void );
#endif // ECON_ITEM_SYSTEM_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+455
View File
@@ -0,0 +1,455 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ECON_ITEM_CONSTANTS_H
#define ECON_ITEM_CONSTANTS_H
#ifdef _WIN32
#pragma once
#endif
#include "game_item_schema.h"
#include "econ_item_constants.h"
#include "localization_provider.h"
#include "econ_item_interface.h"
#include "econ_item.h"
#if defined(CLIENT_DLL)
#include "iclientrenderable.h"
#endif
#if defined(TF_DLL)
#include "tf_item_schema.h"
#endif
#if defined(CLIENT_DLL)
#define CEconItemView C_EconItemView
#endif
#if defined(GC_DLL)
#error "econ_item_view.h is not intended to be built on the GC!"
#endif
#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
#define ENABLE_ATTRIBUTE_CURRENCY_TRACKING 1
#else
#define ENABLE_ATTRIBUTE_CURRENCY_TRACKING 0
#endif
class CEconItemAttribute;
class CAttributeManager;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CAttributeList
{
friend class CEconItemView;
friend class CTFPlayer;
DECLARE_CLASS_NOBASE( CAttributeList );
public:
DECLARE_EMBEDDED_NETWORKVAR();
DECLARE_DATADESC();
CAttributeList();
void operator=( const CAttributeList &src );
void Init();
void SetManager( CAttributeManager *pManager );
void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const;
// Remove all attributes on this item
void DestroyAllAttributes( void );
void AddAttribute( CEconItemAttribute *pAttribute );
// Remove an attribute by name
void RemoveAttribute( const CEconItemAttributeDefinition *pAttrDef );
void RemoveAttributeByIndex( int iIndex );
public:
// Returns the attribute that matches the attribute defname
const CEconItemAttribute *GetAttributeByName( const char *pszAttribDefName ) const;
// Returns the attribute that matches the attribute id
const CEconItemAttribute *GetAttributeByID( int iAttributeID ) const;
// The only way to set the value of an attribute after its creation is through the attribute list
// that contains it. This way the matching attribute manager is told one of its attributes has changed.
void SetRuntimeAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float flValue );
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
void SetRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef, int iRefundableCurrency );
int GetRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef ) const;
void AdjustRuntimeAttributeRefundableCurrency( const CEconItemAttributeDefinition *pAttrDef, int iRefundableCurrencyAdjustment )
{
SetRuntimeAttributeRefundableCurrency( pAttrDef, GetRuntimeAttributeRefundableCurrency( pAttrDef ) + iRefundableCurrencyAdjustment );
}
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
private:
void NotifyManagerOfAttributeValueChanges();
// Attribute accessing
int GetNumAttributes( void ) const { return m_Attributes.Count(); }
CEconItemAttribute *GetAttribute( int iIndex ) { Assert( iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; }
const CEconItemAttribute *GetAttribute( int iIndex ) const { Assert( iIndex >= 0 && iIndex < m_Attributes.Count()); return &m_Attributes[iIndex]; }
// Our list of attributes
CUtlVector<CEconItemAttribute> m_Attributes;
CAttributeManager *m_pManager;
};
//-----------------------------------------------------------------------------
// Purpose: An attribute that knows how to read itself from a datafile, describe itself to the user,
// and serialize itself between Servers, Clients, and Steam.
// Unlike the attributes created in the Game DLL, this attribute doesn't know how to actually
// do anything in the game, it just knows how to describe itself.
//-----------------------------------------------------------------------------
class CEconItemAttribute
{
DECLARE_CLASS_NOBASE( CEconItemAttribute );
public:
DECLARE_EMBEDDED_NETWORKVAR();
CEconItemAttribute();
CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, float flValue );
CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, uint32 unValue );
void operator=( const CEconItemAttribute &val );
// Get the index of this attribute's definition inside the script file
attrib_definition_index_t GetAttribIndex( void ) const { return m_iAttributeDefinitionIndex; }
void SetAttribIndex( attrib_definition_index_t iIndex ) { m_iAttributeDefinitionIndex = iIndex; }
// Get the static data contained in this attribute's definition
const CEconItemAttributeDefinition *GetStaticData( void ) const;
// Get the float value of this attribute.
//float GetValue( void ) const;
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
int GetRefundableCurrency( void ) const { return m_nRefundableCurrency; }
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
private:
// The only way to set the value of an attribute after its creation is through the attribute list
// that contains it. This way the matching attribute manager is told one of its attributes has changed.
// Set the float value of this attribute.
// Note that the value must be stored as a float!
void SetValue( float flValue );
// Set the value of this attribute as an unsigned integer.
// Note that the value must be stored as an integer!
// See CEconItemAttributeDefinition
void SetIntValue( uint32 unValue );
friend class CAttributeList;
void Init( void );
//--------------------------------------------------------
private:
// This is the index of the attribute into the attributes read from the data files
CNetworkVar( attrib_definition_index_t, m_iAttributeDefinitionIndex );
// This is the value of the attribute. Used to modify the item's variables.
CNetworkVar( float, m_flValue );
#if ENABLE_ATTRIBUTE_CURRENCY_TRACKING
// This is the value that the attribute was first set to by an item definition
CNetworkVar( int, m_nRefundableCurrency );
#endif // ENABLE_ATTRIBUTE_CURRENCY_TRACKING
};
//-----------------------------------------------------------------------------
// Purpose: An item that knows how to read itself from a datafile, describe itself to the user,
// and serialize itself between Servers, Clients, and Steam.
//
// In the client DLL, we derive it from CDefaultClientRenderable so that
// it can be passed in the pProxyData parameter of material proxies.
//-----------------------------------------------------------------------------
#if defined(CLIENT_DLL)
class CEconItemView : public CDefaultClientRenderable, public CMaterialOverrideContainer< IEconItemInterface >
#else
class CEconItemView : public CMaterialOverrideContainer< IEconItemInterface >
#endif
{
DECLARE_CLASS_NOBASE( CEconItemView );
public:
DECLARE_EMBEDDED_NETWORKVAR();
DECLARE_DATADESC();
public:
CEconItemView();
CEconItemView( const CEconItemView &src );
~CEconItemView();
CEconItemView& operator=( const CEconItemView &src );
bool operator==( const CEconItemView &other ) const;
bool operator!=( const CEconItemView &other ) const { return !operator==( other ); }
virtual const GameItemDefinition_t *GetItemDefinition() const
{
return GetStaticData();
}
public:
// IEconItemInterface implementation.
virtual itemid_t GetID() const { return GetItemID(); }
virtual int32 GetQuality() const;
virtual style_index_t GetStyle() const;
virtual uint8 GetFlags() const;
virtual eEconItemOrigin GetOrigin() const;
virtual int GetQuantity() const;
uint64 GetOriginalID() const { return GetSOCData() ? GetSOCData()->GetOriginalID() : 0; }
virtual const char *GetCustomName() const;
virtual const char *GetCustomDesc() const;
virtual bool GetInUse() const { return GetSOCData() ? GetSOCData()->GetInUse() : false; }
virtual void IterateAttributes( class IEconItemAttributeIterator *pIterator ) const OVERRIDE;
bool IsValid( void ) const { return m_bInitialized; }
void Invalidate( void ) { m_bInitialized = false; m_iItemDefinitionIndex = INVALID_ITEM_DEF_INDEX; m_iItemID = INVALID_ITEM_ID; }
void InvalidateColor() { m_bColorInit = false; }
void InvalidateOverrideColor() { m_bPaintOverrideInit = false; }
// Initialize from the specified data
// client will load SO cache as needed
void Init( int iDefIndex, int iQuality, int iLevel, uint32 iAccountID = 0 );
void SetInitialized( bool bInit ) { m_bInitialized = bInit; }
// Get the static data contained in this item's definition
GameItemDefinition_t *GetStaticData( void ) const;
void SetNonSOEconItem( CEconItem* pItem ) { m_pNonSOEconItem.SetItem( pItem ); }
void OnAttributeValuesChanged()
{
NetworkStateChanged();
MarkDescriptionDirty();
}
private:
void EnsureDescriptionIsBuilt( void ) const;
void MarkDescriptionDirty( void );
public:
void SetGrayedOutReason( const char *pszGrayedOutReason );
// Set & Get the index of this item's definition inside the script file
void SetItemDefIndex( item_definition_index_t iIndex ) { m_iItemDefinitionIndex = iIndex; MarkDescriptionDirty(); }
virtual item_definition_index_t GetItemDefIndex( void ) const { return m_iItemDefinitionIndex; }
// Set & Get the quality & level of this item.
void SetItemQuality( int iQuality ) { m_iEntityQuality = iQuality; MarkDescriptionDirty(); }
int GetItemQuality( void ) const { return m_iEntityQuality; }
void SetItemLevel( uint32 unLevel ) { m_iEntityLevel = unLevel; MarkDescriptionDirty(); }
uint32 GetItemLevel( void ) const { return m_iEntityLevel; }
int GetItemQuantity() const;
#ifdef CLIENT_DLL
void SetIsTradeItem( bool bIsTradeItem ) { m_bIsTradeItem = bIsTradeItem; MarkDescriptionDirty(); }
void SetItemQuantity( int iQuantity ) { m_iEntityQuantity = iQuantity; MarkDescriptionDirty(); }
void SetClientItemFlags( uint8 unFlags );
void SetItemStyleOverride( style_index_t unNewStyleOverride );
void SetItemOriginOverride( eEconItemOrigin unNewOriginOverride );
#endif
style_index_t GetItemStyle() const;
// Access the worldwide global index of this item
void SetItemID( itemid_t iIdx ) { m_iItemID = iIdx; m_iItemIDHigh = (m_iItemID >> 32); m_iItemIDLow = (m_iItemID & 0xFFFFFFFF); }
#ifdef CLIENT_DLL
// On the client, we need to rebuild it from the high & low networked pieces
itemid_t GetItemID( void ) const { uint64 iTmp = ((((int64)m_iItemIDHigh)<<32) | m_iItemIDLow); return (itemid_t)iTmp; }
#else
itemid_t GetItemID( void ) const { return m_iItemID; }
#endif
uint32 GetAccountID( void ) const { return m_iAccountID; }
void SetOverrideAccountID( uint32 nAccountID ) { m_iAccountID = nAccountID; }
// Access the inventory position of this item
void SetInventoryPosition( uint32 iPosition ) { m_iInventoryPosition = iPosition; }
const uint32 GetInventoryPosition( void ) const { return m_iInventoryPosition; }
// Return the model to use for model panels containing this item
const char *GetInventoryModel( void );
// Return the image to use for model panels containing this item
const char *GetInventoryImage( void );
bool GetInventoryImageData( int *iPosition, int *iSize );
const char *GetInventoryOverlayImage( int idx );
int GetInventoryOverlayImageCount( void );
// Return the model to use when displaying this model on the player character model, if any
const char *GetPlayerDisplayModel( int iClass, int iTeam ) const;
// Return the model to use when displaying this model in the world. See the notes on this in econ_item_schema.h
const char *GetWorldDisplayModel() const;
const char *GetExtraWearableModel() const;
const char *GetExtraWearableViewModel() const;
const char *GetVisionFilteredDisplayModel() const;
// Return the load-out slot that this item must be placed into
int GetAnimationSlot( void ) const;
// Return an int that indicates whether the item should be dropped from a dead owner.
int GetDropType( void );
// Remove all attributes on this item
void DestroyAllAttributes( void );
void InitNetworkedDynamicAttributesForDemos( void );
// Items that have attributes that modify their RGB values
int GetModifiedRGBValue( bool bAltColor=false );
// Returns the UGC file ID of the custom texture assigned to this item. If non-zero, then it has a custom texture.
uint64 GetCustomUserTextureID();
CEconItem *GetSOCData( void ) const;
bool IsEquipped( void ) const { return GetSOCData() && GetSOCData()->IsEquipped(); }
bool IsEquippedForClass( equipped_class_t unClass ) const { return GetSOCData() && GetSOCData()->IsEquippedForClass( unClass ); }
equipped_slot_t GetEquippedPositionForClass( equipped_class_t unClass ) const { return GetSOCData() ? GetSOCData()->GetEquippedPositionForClass( unClass ) : INVALID_EQUIPPED_SLOT; }
// Attached particle systems
int GetQualityParticleType() const;
int GetSkin( int iTeam, bool bViewmodel = false ) const;
public:
// ...
CAttributeList *GetAttributeList() { return &m_AttributeList; }
const CAttributeList *GetAttributeList() const { return &m_AttributeList; }
public:
virtual CEconItemPaintKitDefinition *GetCustomPainkKitDefinition( void ) const { return GetItemDefinition()->GetCustomPainkKitDefinition(); }
#ifdef CLIENT_DLL
void SetWeaponSkinBase( ITexture* pBaseTex );
void SetWeaponSkinBaseCompositor( ITextureCompositor * pTexCompositor );
inline void SetWeaponSkinGeneration( RTime32 nGeneration ) { m_nWeaponSkinGeneration = nGeneration; }
inline void SetWeaponSkinGenerationTeam( int iTeam ) { m_iLastGeneratedTeamSkin = iTeam; }
inline void SetWeaponSkinBaseCreateFlags( uint32 flags ) { m_unWeaponSkinBaseCreateFlags = flags; }
void CancelWeaponSkinComposite( );
inline void SetWeaponSkinUseHighRes( bool bUseHighRes ) { m_bWeaponSkinUseHighRes = bUseHighRes; }
inline void SetWeaponSkinUseLowRes( bool bUseLowRes ) { m_bWeaponSkinUseLowRes = bUseLowRes; }
inline ITexture *GetWeaponSkinBase() const { return m_pWeaponSkinBase; }
inline ITextureCompositor *GetWeaponSkinBaseCompositor() const { return m_pWeaponSkinBaseCompositor; }
inline uint32 GetWeaponSkinBaseCreateFlags() const { return m_unWeaponSkinBaseCreateFlags; }
inline RTime32 GetWeaponSkinGeneration() const { return m_nWeaponSkinGeneration; }
inline int GetWeaponSkinGenerationTeam() const { return m_iLastGeneratedTeamSkin; }
inline bool ShouldWeaponSkinUseHighRes() const { return m_bWeaponSkinUseHighRes; }
inline bool ShouldWeaponSkinUseLowRes() const { return m_bWeaponSkinUseLowRes; }
#endif // CLIENT_DLL
inline int GetTeamNumber() const { return m_iTeamNumber; }
inline void SetTeamNumber( int iTeamNumber ) { m_iTeamNumber = iTeamNumber; }
protected:
// Index of the item definition in the item script file.
CNetworkVar( item_definition_index_t, m_iItemDefinitionIndex );
// The quality of this item.
CNetworkVar( int, m_iEntityQuality );
// The level of this item.
CNetworkVar( uint32, m_iEntityLevel );
// The global index of this item, worldwide.
itemid_t m_iItemID;
CNetworkVar( uint32, m_iItemIDHigh );
CNetworkVar( uint32, m_iItemIDLow );
// Account ID of the person who has this in their inventory
CNetworkVar( uint32, m_iAccountID );
// Position inside the player's inventory
CNetworkVar( uint32, m_iInventoryPosition );
// This is an alternate source of data, if this item models something that isn't in the SO cache.
CEconItemHandle m_pNonSOEconItem;
#if defined( CLIENT_DLL )
// exist on the client only
bool m_bIsTradeItem;
int m_iEntityQuantity;
uint8 m_unClientFlags;
// clients have the ability to force a style on an item view -- this is used for store previews,
// character panels, etc.
style_index_t m_unOverrideStyle;
// clients can also force an origin on an item view -- this is used for crafting item previews
eEconItemOrigin m_unOverrideOrigin;
#endif
bool m_bColorInit;
bool m_bPaintOverrideInit;
bool m_bHasPaintOverride;
float m_flOverrideIndex;
uint32 m_unRGB;
uint32 m_unAltRGB;
#ifdef CLIENT_DLL
ITexture* m_pWeaponSkinBase;
ITextureCompositor* m_pWeaponSkinBaseCompositor;
RTime32 m_nWeaponSkinGeneration;
uint32 m_unWeaponSkinBaseCreateFlags;
int m_iLastGeneratedTeamSkin;
bool m_bWeaponSkinUseHighRes;
bool m_bWeaponSkinUseLowRes;
#endif // CLIENT_DLL
CNetworkVar( int, m_iTeamNumber );
CNetworkVar( bool, m_bInitialized );
#ifdef CLIENT_DLL // we avoid using "BUILD_ITEM_NAME_AND_DESC" to prevent everything depending on the CEconItemDescription
public:
// Return the single-line name of this item.
const wchar_t *GetItemName( void ) const;
// Return the full structure with all of our description lines.
const class CEconItemDescription *GetDescription() const { EnsureDescriptionIsBuilt(); return m_pDescription; }
private:
mutable class CEconItemDescription *m_pDescription;
mutable char *m_pszGrayedOutReason;
// IClientRenderable
virtual const Vector& GetRenderOrigin( void ) { return vec3_origin; }
virtual const QAngle& GetRenderAngles( void ) { return vec3_angle; }
virtual bool ShouldDraw( void ) { return false; }
virtual bool IsTransparent( void ) { return false;}
virtual const matrix3x4_t &RenderableToWorldTransform() { static matrix3x4_t mat; SetIdentityMatrix( mat ); return mat; }
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
#endif
private:
CNetworkVarEmbedded( CAttributeList, m_AttributeList );
CNetworkVarEmbedded( CAttributeList, m_NetworkedDynamicAttributesForDemos );
// Some custom gamemodes are using server plugins to modify weapon attributes.
// This variable allows them to completely set their own attributes on a weapon
// and have the client and server ignore the static attributes.
CNetworkVar( bool, m_bOnlyIterateItemViewAttributes );
};
#ifdef CLIENT_DLL
bool DoesItemPassSearchFilter( const class IEconItemDescription *pDescription, const wchar_t* wszFilter );
CBasePlayer *GetPlayerByAccountID( uint32 unAccountID );
#endif // CLIENT_DLL
#endif // ECON_ITEM_CONSTANTS_H
+71
View File
@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Functions related to dynamic recipes
//
//=============================================================================
#include "cbase.h"
#include "econ_quests.h"
#ifndef GC_DLL
#include "quest_objective_manager.h"
#endif
bool IsQuestItemUnidentified( const CEconItem* pQuestItem )
{
return pQuestItem && IsUnacknowledged( pQuestItem->GetInventoryToken() );
}
bool IsQuestItemReadyToTurnIn( const IEconItemInterface* pQuestItem )
{
uint32 nRequiredPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxStandardPoints();
uint32 nEarnedStandardPoints = GetEarnedStandardPoints( pQuestItem );
uint32 nEarnedBonusPoints = GetEarnedBonusPoints( pQuestItem );
return ( nEarnedStandardPoints + nEarnedBonusPoints ) >= nRequiredPoints;
}
bool IsQuestItemFullyCompleted( const IEconItemInterface* pQuestItem )
{
uint32 nRequiredStandardPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxStandardPoints();
uint32 nRequiredBonusPoints = pQuestItem->GetItemDefinition()->GetQuestDef()->GetMaxBonusPoints();
uint32 nEarnedStandardPoints = GetEarnedStandardPoints( pQuestItem );
uint32 nEarnedBonusPoints = GetEarnedBonusPoints( pQuestItem );
return ( nEarnedStandardPoints + nEarnedBonusPoints ) == ( nRequiredStandardPoints + nRequiredBonusPoints );
}
uint32 GetEarnedStandardPoints( const IEconItemInterface* pQuestItem )
{
#ifndef GC_DLL
const CQuestItemTracker* pItemTracker = assert_cast< const CQuestItemTracker* >( QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( pQuestItem->GetID() ) );
if ( pItemTracker )
{
return pItemTracker->GetEarnedStandardPoints();
}
#endif
uint32 nEarnedStandardPoints = 0;
static CSchemaAttributeDefHandle pAttribDef_EarnedStandardPoints( "quest earned standard points" );
pQuestItem->FindAttribute( pAttribDef_EarnedStandardPoints, &nEarnedStandardPoints );
return nEarnedStandardPoints;
}
uint32 GetEarnedBonusPoints( const IEconItemInterface* pQuestItem )
{
#ifndef GC_DLL
const CQuestItemTracker* pItemTracker = assert_cast< const CQuestItemTracker* >( QuestObjectiveManager()->GetTypedTracker< CQuestItemTracker* >( pQuestItem->GetID() ) );
if ( pItemTracker )
{
return pItemTracker->GetEarnedBonusPoints();
}
#endif
uint32 nEarnedBonusPoints = 0;
static CSchemaAttributeDefHandle pAttribDef_EarnedBonusPoints( "quest earned bonus points" );
pQuestItem->FindAttribute( pAttribDef_EarnedBonusPoints, &nEarnedBonusPoints );
return nEarnedBonusPoints;
}
+22
View File
@@ -0,0 +1,22 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Functions related to quests
//
//=============================================================================
#ifndef ECON_QUESTS
#define ECON_QUESTS
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Given a quest item, return if the quest is considered "unidentified"
//-----------------------------------------------------------------------------
bool IsQuestItemUnidentified( const CEconItem* pQuestItem );
bool IsQuestItemReadyToTurnIn( const IEconItemInterface* pQuestItem );
bool IsQuestItemFullyCompleted( const IEconItemInterface* pQuestItem );
uint32 GetEarnedStandardPoints( const IEconItemInterface* pQuestItem );
uint32 GetEarnedBonusPoints( const IEconItemInterface* pQuestItem );
#endif // ECON_QUESTS
File diff suppressed because it is too large Load Diff
+621
View File
@@ -0,0 +1,621 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Common objects and utilities related to the in-game item store
//
//=============================================================================
#ifndef ECON_STORE_H
#define ECON_STORE_H
#ifdef _WIN32
#pragma once
#endif
#include "UtlSortVector.h"
#include "vstdlib/IKeyValuesSystem.h"
#include "econ/econ_storecategory.h"
#ifdef CLIENT_DLL
#include "client_community_market.h"
#endif // CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Error code enum for purchase messages
//-----------------------------------------------------------------------------
enum EPurchaseResult
{
k_EPurchaseResultOK = 1, // Success
k_EPurchaseResultFail = 2, // Generic error
k_EPurchaseResultInvalidParam = 3, // Invalid parameter
k_EPurchaseResultInternalError = 4, // Internal error
k_EPurchaseResultNotApproved = 5, // Tried to finalize a transaction that has not yet been approved
k_EPurchaseResultAlreadyCommitted = 6, // Tried to finalize a transaction that has already been committed
k_EPurchaseResultUserNotLoggedIn = 7, // User is not logged into Steam
k_EPurchaseResultWrongCurrency = 8, // Microtransaction's currency does not match user's wallet currency
k_EPurchaseResultAccountError = 9, // User's account does not exist or is temporarily unavailable
k_EPurchaseResultInvalidItem = 10, // User is trying to purchase an item that doesn't exist or is not for sale
k_EPurchaseResultNotEnoughBackpackSpace = 11, // User did not have enough backpack space
k_EPurchaseResultLimitedQuantityItemsUnavailable = 12, // User tried to purchase limited-quantity items but there weren't enough left in stock
k_EPurchaseResultInsufficientFunds = 100, // User does not have wallet funds
k_EPurchaseResultTimedOut = 101, // Time limit for finalization has been exceeded
k_EPurchaseResultAcctDisabled = 102, // Steam account is disabled
k_EPurchaseResultAcctCannotPurchase = 103, // Steam account is not allowed to make a purchase
k_EMicroTxnResultFailedFraudChecks = 104, // Fraud checks inside of Steam failed
k_EPurchaseResultOldPriceSheet = 150, // Information on the purchase didn't match the current price sheet
k_EPurchaseResultTxnNotFound = 151 // Could not find the transaction specified
};
const char *PchNameFromEPurchaseResult( EPurchaseResult ePurchaseState );
//-----------------------------------------------------------------------------
// Purpose: State of a transaction
//
// WARNING: VALUES STORED IN DATABASE. DO NOT RENUMBER!!!
//-----------------------------------------------------------------------------
enum EPurchaseState
{
k_EPurchaseStateInvalid = 0, // Invalid
k_EPurchaseStateInit = 1, // We have sent InitPurchase to Steam
k_EPurchaseStateWaitingForAuthorization = 2, // We have gotten initial authorization from Steam. Waiting for user to authorize.
k_EPurchaseStatePending = 3, // We are attempting to commit the transaction
k_EPurchaseStateComplete = 4, // The transaction was successful
k_EPurchaseStateFailed = 5, // The transaction failed
k_EPurchaseStateCanceled = 6, // The transaction was canceled
k_EPurchaseStateRefunded = 7, // The transaction was refunded
k_EPurchaseStateChargeback = 8, // The transaction was charged back
k_EPurchaseStateChargebackReversed = 9, // A chargeback has failed and we got the money
k_EPurchaseStateLast = k_EPurchaseStateChargebackReversed,
};
const char *PchNameFromEPurchaseState( EPurchaseState ePurchaseState );
// DO NOT RENUMBER! These values are stored in the audit log table.
enum EGCTransactionAuditReason
{
k_EGCTransactionAudit_GCTransactionCompleted = 0, // The transaction completed successfully on the GC.
k_EGCTransactionAudit_GCTransactionInit = 1, // The transaction was initialized.
k_EGCTransactionAudit_GCTransactionPostInit = 2, // The result of attempting to initialize the transaction. This is where the SteamTxnID is set.
k_EGCTransactionAudit_GCTransactionFinalize = 3, // We have started to finalize the transaction (so probably set it to pending).
k_EGCTransactionAudit_GCTransactionFinalizeFailed = 4, // Our attempt to finalize the transaction failed for some reason (not due to a timeout).
k_EGCTransactionAudit_GCTransactionCanceled = 5, // The client requested that we cancel the transaction.
k_EGCTransactionAudit_SteamFailedMismatch = 6, // Steam failed the transaction but we did not.
k_EGCTransactionAudit_GCRemovePurchasedItems = 7, // We are attempting to remove the purchased items from their backpack (due to rollback or failure).
k_EGCTransactionAudit_GCTransactionInsert = 8, // We are inserting a transaction, usually one created by a web interface (i.e.: a cd-key operation) instead of a standard store interaction.
k_EGCTransactionAudit_GCTransactionCompletedPostChargeback = 9, // We thought this transaction had been charged back but Steam came back later and told us it was successful after all.
k_EGCTransactionAuditLast = k_EGCTransactionAudit_GCTransactionCompletedPostChargeback,
};
const char *PchNameFromEGCTransactionAuditReason( EGCTransactionAuditReason eAuditReason );
enum EGCTransactionAuditInsertReason
{
k_EGCTransactionAuditInsert_Invalid = 0, //
k_EGCTransactionAuditInsert_CDKey = 1, // A CD Key was used for this transaction.
k_EGCTransactionAuditInsert_SettlementNoMatch_Failed = 2, // We inserted a failed record during settlement to unblock the process.
k_EGCTransactionAuditInsert_SettlementNoMatch_Pending = 3, // We inserted a pending record during settlement to unblock the process.
k_EGCTransactionAuditInsertLast = k_EGCTransactionAuditInsert_SettlementNoMatch_Pending,
};
//-----------------------------------------------------------------------------
// Purpose: Currencies we support
//
// WARNING: VALUES STORED IN DATABASE. DO NOT RENUMBER!!!
// WARNING: THESE DON'T MATCH THE STEAM NUMERIC IDS!!! WE TALK USING CURRENCY
// CODES LIKE "VND" AND IF YOU SAY "15" TERRIBLE THINGS WILL HAPPEN
//-----------------------------------------------------------------------------
enum ECurrency
{
k_ECurrencyFirst = 0,
k_ECurrencyUSD = 0,
k_ECurrencyGBP = 1,
k_ECurrencyEUR = 2,
k_ECurrencyRUB = 3,
k_ECurrencyBRL = 4,
// space for Dota currencies
k_ECurrencyJPY = 8,
k_ECurrencyNOK = 9,
k_ECurrencyIDR = 10,
k_ECurrencyMYR = 11,
k_ECurrencyPHP = 12,
k_ECurrencySGD = 13,
k_ECurrencyTHB = 14,
k_ECurrencyVND = 15,
k_ECurrencyKRW = 16,
k_ECurrencyTRY = 17,
k_ECurrencyUAH = 18,
k_ECurrencyMXN = 19,
k_ECurrencyCAD = 20,
k_ECurrencyAUD = 21,
k_ECurrencyNZD = 22,
k_ECurrencyPLN = 23,
k_ECurrencyCHF = 24,
k_ECurrencyCNY = 25,
k_ECurrencyTWD = 26,
k_ECurrencyHKD = 27,
k_ECurrencyINR = 28,
k_ECurrencyAED = 29,
k_ECurrencySAR = 30,
k_ECurrencyZAR = 31,
k_ECurrencyCOP = 32,
k_ECurrencyPEN = 33,
k_ECurrencyCLP = 34,
// NOTE: Not actually the Maximum currency value, but the Terminator for the possible currency code range.
k_ECurrencyMax = 35,
// make this a big number so we can avoid having to move it when we add another currency type
k_ECurrencyInvalid = 255,
k_ECurrencyCDKeyTransaction = k_ECurrencyInvalid,
};
// Macro for looping across all valid currencies
#define FOR_EACH_CURRENCY( _i ) for ( ECurrency _i = GetFirstValidCurrency(); _i != k_ECurrencyInvalid; _i = GetNextValidCurrency( _i ) )
const char *PchNameFromECurrency( ECurrency eCurrency ); // NOTE: Defined with ENUMSTRINGS_START/ENUMSTRINGS_REVERSE macros
ECurrency ECurrencyFromName( const char *pchName ); //
inline bool BIsCurrencyValid( ECurrency eCurrency )
{
switch ( eCurrency )
{
case k_ECurrencyUSD:
case k_ECurrencyGBP:
case k_ECurrencyEUR:
case k_ECurrencyRUB:
case k_ECurrencyBRL:
case k_ECurrencyJPY:
case k_ECurrencyNOK:
case k_ECurrencyIDR:
case k_ECurrencyMYR:
case k_ECurrencyPHP:
case k_ECurrencySGD:
case k_ECurrencyTHB:
case k_ECurrencyVND:
case k_ECurrencyKRW:
case k_ECurrencyTRY:
case k_ECurrencyUAH:
case k_ECurrencyMXN:
case k_ECurrencyCAD:
case k_ECurrencyAUD:
case k_ECurrencyNZD:
//case k_ECurrencyPLN:
case k_ECurrencyCHF:
case k_ECurrencyCNY:
case k_ECurrencyTWD:
case k_ECurrencyHKD:
case k_ECurrencyINR:
case k_ECurrencyAED:
case k_ECurrencySAR:
case k_ECurrencyZAR:
case k_ECurrencyCOP:
case k_ECurrencyPEN:
case k_ECurrencyCLP:
return true;
}
return false;
}
inline ECurrency GetFirstValidCurrency()
{
for ( int i = k_ECurrencyFirst; i < k_ECurrencyMax; i++ )
{
if ( BIsCurrencyValid( (ECurrency)i ) )
return (ECurrency)i;
}
return k_ECurrencyInvalid;
}
inline ECurrency GetNextValidCurrency( ECurrency ePrevious )
{
for ( int i = ePrevious + 1; i < k_ECurrencyMax; i++ )
{
if ( BIsCurrencyValid( (ECurrency)i ) )
return (ECurrency)i;
}
return k_ECurrencyInvalid;
}
//-----------------------------------------------------------------------------
// Purpose: Simple struct for pairing a sort type with a localization string
//-----------------------------------------------------------------------------
struct ItemSortTypeData_t
{
const char *szSortDesc; // localization string
uint32 iSortType; // maps to the GC-specific sort value
};
// Description of a single item for sale
struct econ_store_entry_t
{
// Constructor
econ_store_entry_t()
: m_pchCategoryTags( NULL ),
m_unGiftSteamPackageID( 0 ),
m_bHighlighted( false )
{
V_memset( m_unBaseCosts, 0, sizeof(m_unBaseCosts) );
V_memset( m_unSaleCosts, 0, sizeof(m_unSaleCosts) );
}
void SetItemDefinitionIndex( item_definition_index_t usDefIndex );
item_definition_index_t GetItemDefinitionIndex() const { return m_usDefIndex; }
void InitCategoryTags( const char *pTags ); // Sets m_pchCategoryTags and initializes m_vecTagIds and m_fRentalPriceScale
bool IsListedInCategory( StoreCategoryID_t unID ) const; // Is this item listed in the given category?
bool IsListedInSubcategories( const CEconStoreCategoryManager::StoreCategory_t &Category ) const; // Is this item listed in one of Category's subcategories?
bool IsListedInCategoryOrSubcategories( const CEconStoreCategoryManager::StoreCategory_t &Category ) const; // Is this item listed in Category or one of Category's subcategories?
bool IsOnSale( ECurrency eCurrency ) const;
bool IsRentable() const;
#ifdef CLIENT_DLL
bool HasDiscount( ECurrency eCurrency, item_price_t *out_punOptionalBasePrice ) const; // returns true if we're on sale or if we're a bundle with a discounted total price
#endif // CLIENT_DLL
item_price_t GetCurrentPrice( ECurrency eCurrency ) const;
float GetRentalPriceScale() const;
uint32 GetGiftSteamPackageID() const { return m_unGiftSteamPackageID; }
// Helper function -- so we do this calculation in a single place.
static item_price_t GetDiscountedPrice( ECurrency eCurrency, item_price_t unBasePrice, float fDiscountPercentage );
static item_price_t CalculateSalePrice( const econ_store_entry_t* pSaleStoreEntry, ECurrency eCurrency, float fDiscountPercentage, int32 *out_pAdjustedDiscountPercentage = NULL );
item_price_t GetBasePrice( ECurrency eCurrency ) const
{
Assert( eCurrency >= k_ECurrencyFirst );
Assert( eCurrency < k_ECurrencyMax );
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
return 0;
#ifdef CLIENT_DLL
if ( m_bIsMarketItem )
{
const client_market_data_t *pClientMarketData = GetClientMarketData( GetItemDefinitionIndex(), AE_UNIQUE );
if ( !pClientMarketData )
return 0;
return pClientMarketData->m_unLowestPrice;
}
#endif
// Weird-looking pattern: we're making sure that the value we're about to return fits correctly
// into the variable we're about to put it into. We do this to avoid integer conversion problems,
// especially overflow (!) where someone changes one of the return type or the storage type but
// not the other.
Assert( (item_price_t)m_unBaseCosts[eCurrency] == m_unBaseCosts[eCurrency] );
return m_unBaseCosts[eCurrency];
}
item_price_t GetSalePrice( ECurrency eCurrency ) const
{
Assert( eCurrency >= k_ECurrencyFirst );
Assert( eCurrency < k_ECurrencyMax );
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
return 0;
#ifdef CLIENT_DLL
if ( m_bIsMarketItem )
{
const client_market_data_t *pClientMarketData = GetClientMarketData( GetItemDefinitionIndex(), AE_UNIQUE );
if ( !pClientMarketData )
return 0;
return pClientMarketData->m_unLowestPrice;
}
#endif
// Weird-looking pattern: we're making sure that the value we're about to return fits correctly
// into the variable we're about to put it into. We do this to avoid integer conversion problems,
// especially overflow (!) where someone changes one of the return type or the storage type but
// not the other.
Assert( (item_price_t)m_unSaleCosts[eCurrency] == m_unSaleCosts[eCurrency] );
return m_unSaleCosts[eCurrency];
}
uint16 GetQuantity() const
{
return m_usQuantity;
}
const char* GetDate() const
{
return m_strDate.Get();
}
bool CanPreview() const
{
// No previewing of new items or weapons.
return m_bPreviewAllowed;
}
void SetQuantity( uint16 usQuantity )
{
Assert( usQuantity > 0 );
m_usQuantity = usQuantity;
}
void ValidatePrice( ECurrency eCurrency, item_price_t unPrice );
void SetBasePrice( ECurrency eCurrency, item_price_t unPrice )
{
Assert( eCurrency >= k_ECurrencyFirst );
Assert( eCurrency < k_ECurrencyMax );
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
return;
ValidatePrice( eCurrency, unPrice );
m_unBaseCosts[eCurrency] = unPrice;
}
void SetSalePrice( ECurrency eCurrency, item_price_t unPrice )
{
Assert( eCurrency >= k_ECurrencyFirst );
Assert( eCurrency < k_ECurrencyMax );
if ( !( eCurrency >= 0 && eCurrency < k_ECurrencyMax ) )
return;
ValidatePrice( eCurrency, unPrice );
// It's legal to have a sale price of zero, meaninig "this item is not on sale" in this
// currency.
// Assert( unPrice > 0 );
m_unSaleCosts[eCurrency] = unPrice;
}
void SetSteamGiftPackageID( uint32 unGiftSteamPackageID )
{
m_unGiftSteamPackageID = unGiftSteamPackageID;
}
void SetDate( const char* pszDate )
{
m_strDate.Set( pszDate );
}
bool IsValidCategoryTagIndex( uint32 iIndex ) const
{
AssertMsg( m_vecCategoryTags.IsValidIndex( iIndex ), "Category tag index out of range." );
return m_vecCategoryTags.IsValidIndex( iIndex );
}
uint32 GetCategoryTagCount() const
{
return m_vecCategoryTags.Count();
}
const char *GetCategoryTagNameFromIndex( uint32 iIndex ) const
{
if ( !IsValidCategoryTagIndex( iIndex ) )
return NULL;
return m_vecCategoryTags[ iIndex ].m_strName;
}
StoreCategoryID_t GetCategoryTagIDFromIndex( uint32 iIndex ) const;
const char *GetCategoryTagString() const
{
return m_pchCategoryTags;
}
bool m_bLimited; // Item is a limited sale
bool m_bNew; // Item is new
bool m_bHighlighted; // Item is highlighted
CUtlString m_strDate; // Date Added
bool m_bSoldOut; // True if the item is sold out from the store (for example if the item is a ticket or another physical item)
bool m_bPreviewAllowed; // Is this item previewable?
bool m_bIsPackItem; // Is this item a pack item? Pack items are items which are not individually for sale, but are sold via a bundle known as a "pack bundle"
bool m_bIsMarketItem; // Is Market Item Link
private:
item_definition_index_t m_usDefIndex; // DefIndex of the item
// Private data so that we can check in the accessor functions that the data fits before returning it.
item_price_t m_unBaseCosts[k_ECurrencyMax]; // Costs of the items indexed by ECurrency -- if the items are on sale, this will be the current sale price
item_price_t m_unSaleCosts[k_ECurrencyMax]; // Original costs of the items indexed by ECurrency -- if the items are on sale, this will be the pre-sale price
uint16 m_usQuantity; // Quantity sold in a single purchase (ie., dueling pistols come in stacks of five)
float m_fRentalPriceScale; // 100.0 or greater means "unavailable to rent"
uint32 m_unGiftSteamPackageID; // if non-zero, when this item is purchased (including inside bundles, etc.), grant a gift copy of this Steam package
struct CategoryTag_t
{
CUtlString m_strName; // Individual tag name, like "Weapons," "New," etc.
StoreCategoryID_t m_unID; // The category ID
};
CCopyableUtlVector< CategoryTag_t > m_vecCategoryTags; // Category tag data
const char *m_pchCategoryTags; // All tags - this string will something like: "New" or "Weapons+New" etc.
};
#ifdef GC_DLL
struct econ_store_timed_sale_item_t
{
item_definition_index_t m_unItemDef;
float m_fPricePercentage; // 100.0 = regular price; 50.0 = half price
};
struct econ_store_timed_sale_t
{
bool m_bSaleCurrentlyActive; // set in ::UpdatePricesForTimedSales()
CUtlConstString m_sIdentifier; // can't point to memory in the base KV because we toss it afterwards
RTime32 m_SaleStartTime;
RTime32 m_SaleEndTime;
CUtlVector<econ_store_timed_sale_item_t> m_vecSaleItems;
// Work around protected default vector constructor.
econ_store_timed_sale_t() { }
econ_store_timed_sale_t( const econ_store_timed_sale_t& other )
: m_bSaleCurrentlyActive( other.m_bSaleCurrentlyActive )
, m_sIdentifier( other.m_sIdentifier )
, m_SaleStartTime( other.m_SaleStartTime )
, m_SaleEndTime( other.m_SaleEndTime )
{
m_vecSaleItems.CopyArray( other.m_vecSaleItems.Base(), other.m_vecSaleItems.Count() );
}
};
#endif // GC_DLL
// Spend xxx amount of money, get a free item from the loot list
struct store_promotion_spend_for_free_item_t
{
const CEconItemDefinition *m_pItemDef;
item_price_t m_rgusPriceThreshold[k_ECurrencyMax]; // Price threshold to get an item from the loot list indexed by ECurrency
};
//-----------------------------------------------------------------------------
// Purpose: Class that represents what's currently for sale in TF
//-----------------------------------------------------------------------------
typedef enum
{
kEconStoreSortType_Price_HighestToLowest = 0,
kEconStoreSortType_Price_LowestToHighest = 1,
kEconStoreSortType_DevName_AToZ = 2,
kEconStoreSortType_DevName_ZToA = 3,
kEconStoreSortType_Name_AToZ = 4,
kEconStoreSortType_Name_ZToA = 5,
kEconStoreSortType_ItemDefIndex = 6,
kEconStoreSortType_ReverseItemDefIndex = 7,
kEconStoreSortType_DateNewest = 8,
kEconStoreSortType_DateOldest = 9,
} eEconStoreSortType;
struct price_point_map_key_t
{
item_price_t m_unPriceUSD;
ECurrency m_eCurrency;
static bool Less( const price_point_map_key_t& a, const price_point_map_key_t& b )
{
if ( a.m_eCurrency == b.m_eCurrency )
return a.m_unPriceUSD < b.m_unPriceUSD;
return a.m_eCurrency < b.m_eCurrency;
}
};
typedef CUtlMap<price_point_map_key_t, item_price_t> CurrencyPricePointMap_t;
class CEconStorePriceSheet
{
public:
typedef CUtlMap<item_definition_index_t, econ_store_entry_t> StoreEntryMap_t;
typedef CUtlMap<const char *, float> RentalPriceScaleMap_t;
typedef CUtlVector<item_definition_index_t> FeaturedItems_t;
CEconStorePriceSheet();
~CEconStorePriceSheet();
bool InitFromKV( KeyValues *pKVPrices );
// Gets or sets the version stamp. This is just a number the GC can use
// to know if the client is in sync without sending it down on every
// request.
RTime32 GetVersionStamp( void ) const { return m_RTimeVersionStamp; }
void SetVersionStamp( RTime32 stamp ) { m_RTimeVersionStamp = stamp; }
uint32 GetHashForAllItems() const { return m_unHashForAllItems; }
typedef CUtlMap<uint16, econ_store_entry_t> EconStoreEntryMap_t;
EconStoreEntryMap_t &GetEntries() { return m_mapEntries; }
#ifdef GC_DLL
econ_store_entry_t *GetEntryWriteable( item_definition_index_t unDefIndex );
#endif // GC_DLL
const StoreEntryMap_t &GetEntries() const { return m_mapEntries; }
const CEconStoreCategoryManager::StoreCategory_t *GetFeaturedItems( void ) { return &m_FeaturedItems; }
const econ_store_entry_t *GetEntry( item_definition_index_t usDefIndex ) const;
uint32 GetFeaturedItemIndex() const { return m_unFeaturedItemIndex; }
void SetFeaturedItemIndex( uint32 unIdx ) { m_unFeaturedItemIndex = unIdx; }
void SetEconStoreSortType( eEconStoreSortType eType ) { m_eEconStoreSortType = eType; }
eEconStoreSortType GetEconStoreSortType() { return m_eEconStoreSortType; }
const store_promotion_spend_for_free_item_t *GetStorePromotion_SpendForFreeItem() const { return &m_StorePromotionSpendForFreeItem; }
const CEconItemDefinition * GetStorePromotion_FirstTimePurchaseItem() const { return m_pStorePromotionFirstTimePurchaseItem; }
const CEconItemDefinition * GetStorePromotion_FirstTimeWebPurchaseItem() const { return m_pStorePromotionFirstTimeWebPurchaseItem; }
uint32 GetPreviewPeriod() const { return m_unPreviewPeriod; }
uint32 GetBonusDiscountPeriod() const { return m_unBonusDiscountPeriod; }
float GetPreviewPeriodDiscount() const { return m_flPreviewPeriodDiscount; }
bool BItemExistsInPriceSheet( item_definition_index_t unDefIndex ) const;
float GetRentalPriceScale( const char *pszCategory ) const
{
RentalPriceScaleMap_t::IndexType_t i = m_mapRentalPriceScales.Find( pszCategory );
if ( i == RentalPriceScaleMap_t::InvalidIndex() )
return 1.0f;
return m_mapRentalPriceScales[i];
}
KeyValues *GetRawData() const { return m_pKVRaw; }
#ifdef GC_DLL
void UpdatePricesForTimedSales( const RTime32 curTime );
void DumpTimeSaleState( const RTime32 curTime ) const;
#endif // GC_DLL
#ifdef CLIENT_DLL
const FeaturedItems_t& GetFeaturedItems() const { return m_vecFeaturedItems; }
#endif // CLIENT_DLL
private:
bool BInitEntryFromKV( KeyValues *pKVEntry );
#ifdef CLIENT_DLL
bool BInitMarketEntryFromKV( KeyValues *pKVEntry );
#endif // CLIENT_DLL
#ifdef GC_DLL
bool InitTimedSaleEntryFromKV( KeyValues *pKVTimedSaleEntry );
bool VerifyTimedSaleEntries();
#endif // GC_DLL
private:
void Clear();
uint32 CalculateHashFromItems() const;
KeyValues *m_pKVRaw;
RTime32 m_RTimeVersionStamp;
CEconStoreCategoryManager::StoreCategory_t m_FeaturedItems; // Special section, not a tab, kept outside m_vecContents
StoreEntryMap_t m_mapEntries;
RentalPriceScaleMap_t m_mapRentalPriceScales;
store_promotion_spend_for_free_item_t m_StorePromotionSpendForFreeItem;
CEconItemDefinition* m_pStorePromotionFirstTimePurchaseItem;
CEconItemDefinition* m_pStorePromotionFirstTimeWebPurchaseItem;
#ifdef CLIENT_DLL
FeaturedItems_t m_vecFeaturedItems;
#endif // CLIENT_DLL
#ifdef GC_DLL
CUtlVector<econ_store_timed_sale_t> m_vecTimedSales;
#endif // GC_DLL
// changes based on experiments
uint32 m_unFeaturedItemIndex;
eEconStoreSortType m_eEconStoreSortType;
uint32 m_unPreviewPeriod;
uint32 m_unBonusDiscountPeriod;
float m_flPreviewPeriodDiscount;
uint32 m_unHashForAllItems;
// price point lookup
CurrencyPricePointMap_t m_mapCurrencyPricePoints;
};
#ifdef CLIENT_DLL
void MakeMoneyString( wchar_t *pchDest, uint32 nDest, item_price_t unPrice, ECurrency eCurrencyCode );
bool ShouldUseNewStore();
int GetStoreVersion();
#endif // CLIENT_DLL
const CEconStorePriceSheet *GetEconPriceSheet();
#endif // ECON_STORE_H
+267
View File
@@ -0,0 +1,267 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for generating store meta data. Abstract methods need
// to be overridden on a per-product basis.
//
//-------------------------------------------------------------------------------------------------------------------------------
#include "cbase.h"
#include "econ_storecategory.h"
#include "econ_store.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-------------------------------------------------------------------------------------------------------------------------------
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Invalid = (StoreCategoryID_t)0;
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_New = CEconStoreCategoryManager::GetCategoryID( "New" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Weapons = CEconStoreCategoryManager::GetCategoryID( "Weapons" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Limited = CEconStoreCategoryManager::GetCategoryID( "Limited" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Maps = CEconStoreCategoryManager::GetCategoryID( "Maps" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Cosmetics = CEconStoreCategoryManager::GetCategoryID( "Cosmetics" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Taunts = CEconStoreCategoryManager::GetCategoryID( "Taunts" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Tools = CEconStoreCategoryManager::GetCategoryID( "Tools" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Bundles = CEconStoreCategoryManager::GetCategoryID( "Bundles" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Collections= CEconStoreCategoryManager::GetCategoryID( "Collections" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Popular = CEconStoreCategoryManager::GetCategoryID( "Popular" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_OnSale = CEconStoreCategoryManager::GetCategoryID( "OnSale" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Featured = CEconStoreCategoryManager::GetCategoryID( "Featured" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_ClassBundles = CEconStoreCategoryManager::GetCategoryID( "Class_Bundles" );
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Highlighted = CEconStoreCategoryManager::GetCategoryID( "Highlighted" );
//-------------------------------------------------------------------------------------------------------------------------------
CEconStoreCategoryManager::CEconStoreCategoryManager()
{
m_unHomeCategoryID = k_CategoryID_Invalid;
}
bool CEconStoreCategoryManager::BInit( CEconStorePriceSheet *pPriceSheet, KeyValues *pStoreMetaDataKV )
{
KeyValues *pCategoriesKV = pStoreMetaDataKV->FindKey( "categories" );
if ( !pCategoriesKV )
{
AssertMsg( 0, "Could not find 'categories' subkey!" );
return false;
}
FOR_EACH_TRUE_SUBKEY( pCategoriesKV, pKVCurCategory )
{
const int iIndex = m_vecCategories.AddToTail();
StoreCategory_t &curCategory = m_vecCategories[ iIndex ];
if ( !BInitCategory( pPriceSheet, &curCategory, pKVCurCategory ) )
return false;
// If the current category is the home page, cache off its ID
if ( curCategory.m_bIsHome )
{
m_unHomeCategoryID = curCategory.m_unID;
}
}
// Verify that any parents point to valid categories
FOR_EACH_VEC( m_vecCategories, i )
{
const StoreCategory_t &curCategory = m_vecCategories[i];
// Skip current category if it refers to invalid, which is fine
if ( curCategory.m_unParentCategoryID == k_CategoryID_Invalid )
continue;
// A category can't be a parent to itself
if ( curCategory.m_unID == curCategory.m_unParentCategoryID )
{
AssertMsg( 0, "Store category %s is using itself as a parent category!", curCategory.m_pchName );
}
// Attempt to find the current section's parent ID
bool bFound = false;
FOR_EACH_VEC( m_vecCategories, j )
{
// Don't compare against self
if ( i == j )
continue;
if ( m_vecCategories[j].m_unID == curCategory.m_unParentCategoryID )
{
bFound = true;
break;
}
}
// If we couldn't find the current section's parent ID, assert
if ( !bFound )
{
AssertMsg( 0, "Category %s refers to an unknown parent category - check your spelling!", curCategory.m_pchName );
}
}
// Setup child category lists - looping twice to keep this code clean and easy to read
FOR_EACH_VEC( m_vecCategories, i )
{
const StoreCategory_t &curCategory = m_vecCategories[i];
if ( k_CategoryID_Invalid == curCategory.m_unParentCategoryID )
continue;
StoreCategory_t *pParentCategory = GetStoreCategoryFromID( curCategory.m_unParentCategoryID );
if ( !pParentCategory )
continue;
pParentCategory->m_vecSubcategories.AddToTail( &curCategory );
}
return true;
}
//-------------------------------------------------------------------------------------------------------------------------------
bool CEconStoreCategoryManager::BInitCategory( CEconStorePriceSheet *pPriceSheet, StoreCategory_t *pCategory, KeyValues* pKVTab )
{
const char *pDefaultResFile = "Resource/UI/econ/store/v2/StorePage.res";
// Get the main category name
const char* pCategoryName = pKVTab->GetName();
if ( !pCategoryName || !pCategoryName[0] )
{
AssertMsg( 0, "Invalid category name!" );
return false;
}
const bool bIsHome = pKVTab->GetBool( "home", false );
pCategory->m_bIsHome = bIsHome;
pCategory->m_pchRawName = pCategoryName;
pCategory->m_unID = GetCategoryID( pCategoryName );
pCategory->m_bUseLargeCells = pKVTab->GetBool( "use_large_cells", false );
pCategory->m_bVisible = pKVTab->GetBool( "visible", true );
pCategory->m_bInGameOnly = pKVTab->GetBool( "ingame_only", false );
pCategory->m_bDefaultTab = pKVTab->GetBool( "default", false );
#if defined( GC_DLL )
// Until we replace the in-game store with the web store, we have this hacky override property, so
// that we can call the home page "HOME" in the game client and "TOP SELLERS" on the web. The home page
// will be evolving shortly to include a lot more than just a list of top sellers.
const char *pchLabelTokenWebOverride = pKVTab->GetString( "web_label_token_override", NULL );
#else
const char *pchLabelTokenWebOverride = NULL;
#endif
pCategory->m_pchName = pchLabelTokenWebOverride ? pchLabelTokenWebOverride : pKVTab->GetString( "label_token", "#Store_Unknown" );
pCategory->m_pchPageClass = pKVTab->GetString( "page_class", "CStorePage" );
pCategory->m_pchPageRes = pKVTab->GetString( "page_res", pDefaultResFile );
pCategory->m_pchSortType = pKVTab->GetString( "sort_type", "" );
// Important for web store but not needed for VGUI store
#if defined( GC_DLL )
if ( !bIsHome )
{
const char *pchDropdownPrefabName = pKVTab->GetString( "dropdown_prefab", NULL );
pCategory->m_pDropdownPrefab = GEconStoreMetaData()->FindDropdownPrefab( pchDropdownPrefabName );
if ( !pCategory->m_pDropdownPrefab )
{
AssertMsg( pCategory->m_pDropdownPrefab, CFmtStr( "Invalid dropdown prefab name, '%s'!", pchDropdownPrefabName ).Access() );
return false;
}
}
else
{
pCategory->m_pDropdownPrefab = NULL;
}
#endif
// Look for a parent category for non-home categories
if ( !bIsHome )
{
const char *pParentCategoryName = pKVTab->GetString( "parent", NULL );
if ( pParentCategoryName )
{
pCategory->m_unParentCategoryID = GetCategoryID( pParentCategoryName );
}
else
{
pCategory->m_unParentCategoryID = k_CategoryID_Invalid;
}
}
return true;
}
bool CEconStoreCategoryManager::BOnPriceSheetLoaded( CEconStorePriceSheet *pPriceSheet )
{
// Go through all categories/subcategories and add a list of items to each.
// If an item belongs to a subcategory, it will also be added to its parent category. For example,
// a hat will be added to both the "hats" subcategory and the "items" parent category.
FOR_EACH_VEC( m_vecCategories, iCategory )
{
StoreCategory_t &Category = m_vecCategories[iCategory];
// find all entries that match
const CEconStorePriceSheet::EconStoreEntryMap_t &mapEntries = pPriceSheet->GetEntries();
FOR_EACH_MAP_FAST( mapEntries, idx )
{
const econ_store_entry_t &entry = mapEntries[idx];
if ( entry.IsListedInCategoryOrSubcategories( Category ) )
{
Category.m_vecEntries.InsertNoSort( entry.GetItemDefinitionIndex() );
}
}
}
return true;
}
//-------------------------------------------------------------------------------------------------------------------------------
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::GetCategoryID( const char *pCategoryName )
{
// Make the input lower case
CUtlString strLowerCase = pCategoryName;
strLowerCase.ToLower();
return CRC32_ProcessSingleBuffer( (void*)strLowerCase.Get(), strLowerCase.Length() );
}
//-------------------------------------------------------------------------------------------------------------------------------
const CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID ) const
{
return const_cast< CEconStoreCategoryManager * >( this )->GetStoreCategoryFromID( unID );
}
CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID )
{
if ( k_CategoryID_Invalid != unID )
{
FOR_EACH_VEC( m_vecCategories, i )
{
if ( unID == m_vecCategories[i].m_unID )
return &m_vecCategories[i];
}
}
return NULL;
}
//-------------------------------------------------------------------------------------------------------------------------------
static CEconStoreCategoryManager *gs_pEconStoreCategoryManager = NULL;
CEconStoreCategoryManager *GEconStoreCategoryManager()
{
if ( !gs_pEconStoreCategoryManager )
{
gs_pEconStoreCategoryManager = new CEconStoreCategoryManager();
}
return gs_pEconStoreCategoryManager;
}
void ClearEconStoreCategoryManager()
{
delete gs_pEconStoreCategoryManager;
gs_pEconStoreCategoryManager = NULL;
}
+110
View File
@@ -0,0 +1,110 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//-------------------------------------------------------------------------------------------------------------------------------
#ifndef ECON_STORECATEGORY_H
#define ECON_STORECATEGORY_H
#ifdef _WIN32
#pragma once
#endif
#if defined( GC_DLL )
#include "econ/econ_storemetadata.h"
#endif
//-------------------------------------------------------------------------------------------------------------------------------
typedef CRC32_t StoreCategoryID_t;
//-------------------------------------------------------------------------------------------------------------------------------
// sort by price highest to lowest
class CEconStoreEntryLess
{
public:
bool Less( const uint16& lhs, const uint16& rhs, void *pContext );
};
//-------------------------------------------------------------------------------------------------------------------------------
class CEconStoreCategoryManager
{
public:
CEconStoreCategoryManager();
bool BInit( CEconStorePriceSheet *pPriceSheet, KeyValues *pStoreMetaDataKV );
bool BOnPriceSheetLoaded( CEconStorePriceSheet *pPriceSheet );
static StoreCategoryID_t GetCategoryID( const char *pCategoryName );
static StoreCategoryID_t k_CategoryID_Invalid;
static StoreCategoryID_t k_CategoryID_New;
static StoreCategoryID_t k_CategoryID_Weapons;
static StoreCategoryID_t k_CategoryID_Limited;
static StoreCategoryID_t k_CategoryID_Maps;
static StoreCategoryID_t k_CategoryID_Cosmetics;
static StoreCategoryID_t k_CategoryID_Taunts;
static StoreCategoryID_t k_CategoryID_Tools;
static StoreCategoryID_t k_CategoryID_Bundles;
static StoreCategoryID_t k_CategoryID_Collections;
static StoreCategoryID_t k_CategoryID_Popular;
static StoreCategoryID_t k_CategoryID_OnSale;
static StoreCategoryID_t k_CategoryID_Featured;
static StoreCategoryID_t k_CategoryID_ClassBundles;
static StoreCategoryID_t k_CategoryID_Highlighted;
struct StoreCategory_t
{
StoreCategory_t() { V_memset( this, 0, sizeof( StoreCategory_t ) ); }
int GetNumSubcategories() const { return m_vecSubcategories.Count(); }
bool HasSubcategories() const { return m_vecSubcategories.Count() > 1; }
bool BIsSubcategory() const { return m_unParentCategoryID != CEconStoreCategoryManager::k_CategoryID_Invalid; }
bool m_bIsHome:1; // Home page? Default=no.
bool m_bUseLargeCells:1; // Display large icons in the store. Default=no.
bool m_bDefaultTab:1; // Is this the default tab? Default=no
bool m_bVisible:1; // Should this tab be displayed in the store? Default=yes.
bool m_bInGameOnly:1; // Is this category only to be displayed in the in-game store (vs. the web store)?
const char *m_pchRawName; // Raw name of the tab
const char *m_pchName; // Name of the tab
const char *m_pchPageClass; // Code class of the store page.
const char *m_pchSortType; // How to sort the page.
const char *m_pchPageRes; // Res file to use for the page.
StoreCategoryID_t m_unID; // A unique ID that is stable across sessions
StoreCategoryID_t m_unParentCategoryID;
CUtlVector<const StoreCategory_t *> m_vecSubcategories; // A list of ID's for all subcategories
CUtlSortVector<uint16, CEconStoreEntryLess> m_vecEntries; // Vector of items for sale
#if defined( GC_DLL )
const CEconStoreMetaData::DropdownPrefabInfo_t *m_pDropdownPrefab;
#endif
};
const StoreCategoryID_t GetHomeCategoryID() const { Assert( m_unHomeCategoryID != k_CategoryID_Invalid ); return m_unHomeCategoryID; }
const StoreCategory_t *GetStoreCategoryFromID( StoreCategoryID_t unID ) const;
int GetNumCategories( void ) const { return m_vecCategories.Count(); }
const StoreCategory_t *GetCategoryFromIndex( int i ) const { Assert(i >= 0 && i < m_vecCategories.Count()); return &m_vecCategories[i]; }
StoreCategory_t *GetFeaturedItems() const { return NULL; }
private:
bool BInitCategory( CEconStorePriceSheet *pPriceSheet, StoreCategory_t *pCategory, KeyValues *pKVTab );
StoreCategory_t *GetStoreCategoryFromID( StoreCategoryID_t unID );
CUtlVector< StoreCategory_t > m_vecCategories;
StoreCategoryID_t m_unHomeCategoryID; // The ID for the home tab
};
//-------------------------------------------------------------------------------------------------------------------------------
CEconStoreCategoryManager *GEconStoreCategoryManager();
void ClearEconStoreCategoryManager();
//-------------------------------------------------------------------------------------------------------------------------------
#endif
+860
View File
@@ -0,0 +1,860 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "econ_wearable.h"
#include "vcollide_parse.h"
#ifdef CLIENT_DLL
#include "functionproxy.h"
#include "c_te_effect_dispatch.h"
#endif // CLIENT_DLL
#ifdef TF_CLIENT_DLL
#include "c_team.h"
#include "tf_shareddefs.h"
#include "tf_weapon_jar.h"
#include "c_tf_player.h"
#endif // TF_CLIENT_DLL
#ifdef TF_DLL
#include "tf_player.h"
#endif // TF_DLL
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( wearable_item, CEconWearable );
IMPLEMENT_NETWORKCLASS_ALIASED( EconWearable, DT_WearableItem )
// Network Table --
BEGIN_NETWORK_TABLE( CEconWearable, DT_WearableItem )
END_NETWORK_TABLE()
// -- Network Table
// Data Desc --
BEGIN_DATADESC( CEconWearable )
END_DATADESC()
// -- Data Desc
PRECACHE_REGISTER( wearable_item );
IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableItem, DT_TFWearableItem )
// Network Table --
BEGIN_NETWORK_TABLE( CTFWearableItem, DT_TFWearableItem )
END_NETWORK_TABLE()
// -- Network Table
// Data Desc --
BEGIN_DATADESC( CTFWearableItem )
END_DATADESC()
// -- Data Desc
//-----------------------------------------------------------------------------
// SHARED CODE
//-----------------------------------------------------------------------------
CEconWearable::CEconWearable()
{
m_bAlwaysAllow = false;
};
void CEconWearable::InternalSetPlayerDisplayModel( void )
{
int iClass = 0;
int iTeam = 0;
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
if ( pTFPlayer )
{
iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
iTeam = pTFPlayer->GetTeamNumber();
}
#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
// Set our model to the player model
CEconItemView *pItem = GetAttributeContainer()->GetItem();
if ( pItem && pItem->IsValid() )
{
const char *pszPlayerDisplayModel = pItem->GetPlayerDisplayModel( iClass, iTeam );
if ( pszPlayerDisplayModel )
{
if ( pItem->GetStaticData()->IsContentStreamable() )
{
modelinfo->RegisterDynamicModel( pszPlayerDisplayModel, IsClient() );
if ( pItem->GetVisionFilteredDisplayModel() && pItem->GetVisionFilteredDisplayModel()[ 0 ] != '\0' )
{
modelinfo->RegisterDynamicModel( pItem->GetVisionFilteredDisplayModel(), IsClient() );
}
}
SetModel( pszPlayerDisplayModel );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Set up the item. GC data may not be available here depending on
// where we're called from.
//-----------------------------------------------------------------------------
void CEconWearable::Spawn( void )
{
InitializeAttributes();
Precache();
InternalSetPlayerDisplayModel();
BaseClass::Spawn();
AddEffects( EF_BONEMERGE );
AddEffects( EF_BONEMERGE_FASTCULL );
#if !defined( CLIENT_DLL )
SetCollisionGroup( COLLISION_GROUP_WEAPON );
SetBlocksLOS( false );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Player touches the item. Currently wearables don't appear in the
// world, so this is only called directly during equipment assignment.
//-----------------------------------------------------------------------------
void CEconWearable::GiveTo( CBaseEntity *pOther )
{
CBasePlayer *pPlayer = ToBasePlayer(pOther);
if ( !pPlayer )
return;
#if !defined( CLIENT_DLL )
pPlayer->EquipWearable( this );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconWearable::RemoveFrom( CBaseEntity *pOther )
{
CBasePlayer *pPlayer = ToBasePlayer(pOther);
if ( !pPlayer )
return;
#if !defined( CLIENT_DLL )
pPlayer->RemoveWearable( this );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEconWearable::GetSkin( void )
{
CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call.
if ( pItem )
{
int iSkin = pItem->GetSkin( GetTeamNumber() );
if ( iSkin > -1 )
{
return iSkin;
}
}
return ( GetTeamNumber() == (LAST_SHARED_TEAM+1) ) ? 0 : 1;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the item to the player.
//-----------------------------------------------------------------------------
void CEconWearable::Equip( CBasePlayer* pOwner )
{
if ( !CanEquip( pOwner ) )
{
RemoveFrom( pOwner );
return;
}
SetTouch( NULL );
SetAbsVelocity( vec3_origin );
CBaseEntity *pFollowEntity = pOwner;
if ( IsViewModelWearable() )
{
pFollowEntity = pOwner->GetViewModel();
}
FollowEntity( pFollowEntity, true );
SetOwnerEntity( pOwner );
ReapplyProvision();
ChangeTeam( pOwner->GetTeamNumber() );
m_nSkin = GetSkin();
#ifdef GAME_DLL
UpdateModelToClass();
UpdateBodygroups( pOwner, true );
PlayAnimForPlaybackEvent( WAP_ON_SPAWN );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Remove item from the player.
//-----------------------------------------------------------------------------
void CEconWearable::UnEquip( CBasePlayer* pOwner )
{
#ifdef CLIENT_DLL
SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
#endif
#ifdef GAME_DLL
UpdateBodygroups( pOwner, false );
#endif
StopFollowingEntity();
SetOwnerEntity( NULL );
ReapplyProvision();
}
/*
//-----------------------------------------------------------------------------
// Purpose: Hides or shows masked bodygroups associated with this item.
//-----------------------------------------------------------------------------
bool CEconWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
{
if ( !pOwner )
return false;
CAttributeContainer *pCont = GetAttributeContainer();
if ( !pCont )
return false;
CEconItemView *pItem = pCont->GetItem();
if ( !pItem )
return false;
int iTeam = pOwner->GetTeamNumber();
int iNumBodyGroups = pItem->GetNumModifiedBodyGroups( iTeam );
for ( int i=0; i<iNumBodyGroups; ++i )
{
int iBody = 0;
const char *pszBodyGroup = pItem->GetModifiedBodyGroup( iTeam, i, iBody );
int iBodyGroup = pOwner->FindBodygroupByName( pszBodyGroup );
if ( iBodyGroup == -1 )
continue;
pOwner->SetBodygroup( iBodyGroup, iState );
}
return true;
}
*/
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconWearable::OnWearerDeath( void )
{
#ifdef CLIENT_DLL
UpdateParticleSystems();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEconWearable::GetDropType()
{
CAttributeContainer *pCont = GetAttributeContainer();
if ( !pCont )
return 0;
CEconItemView *pItem = pCont->GetItem();
if ( pItem )
return pItem->GetDropType();
else
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Ensures that a player's correct body groups are enabled on client respawn.
//-----------------------------------------------------------------------------
void CEconWearable::UpdateWearableBodyGroups( CBasePlayer* pPlayer )
{
if ( !pPlayer )
return;
for ( int i=0; i<pPlayer->GetNumWearables(); ++i )
{
CEconWearable* pItem = pPlayer->GetWearable(i);
if ( !pItem )
continue;
// Dynamic models which are not yet rendering do not modify bodygroups
if ( pItem->IsDynamicModelLoading() )
continue;
// On the client, ignore items that aren't valid.
#ifdef TF_CLIENT_DLL
if ( pItem->EntityDeemedInvalid() )
continue;
#endif
int nVisibleState = 1;
#ifdef TF_CLIENT_DLL
if ( pItem->ShouldHideForVisionFilterFlags() )
{
// Items that shouldn't draw (pyro-vision filtered) shouldn't change any body group states
// unless they have no model (hatless hats)
nVisibleState = 0;
}
#endif
pItem->UpdateBodygroups( pPlayer, nVisibleState );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFWearableItem::CTFWearableItem()
{
}
//-----------------------------------------------------------------------------
// SERVER ONLY CODE
//-----------------------------------------------------------------------------
#if defined( GAME_DLL )
#endif
//-----------------------------------------------------------------------------
// CLIENT ONLY CODE
//-----------------------------------------------------------------------------
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose: Mirror should draw logic.
//-----------------------------------------------------------------------------
ShadowType_t CEconWearable::ShadowCastType()
{
if ( ShouldDraw() )
{
return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
}
return SHADOWS_NONE;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconWearable::ShouldDraw( void )
{
CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
if ( !pPlayerOwner )
{
return false;
}
bool bUseViewModel = !pPlayerOwner->ShouldDrawThisPlayer();
// Don't show view models if we're drawing the real player, and don't show non view models if using view models.
if ( bUseViewModel )
{
// VM mode.
if ( !IsViewModelWearable() )
{
return false;
}
}
else
{
// Non-viewmodel mode.
if ( IsViewModelWearable() )
{
return false;
}
}
if ( !ShouldDrawWhenPlayerIsDead() && !pPlayerOwner->IsAlive() )
{
return false;
}
if ( pPlayerOwner->GetTeamNumber() == TEAM_SPECTATOR )
{
return false;
}
return BaseClass::ShouldDraw();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconWearable::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
// Update our visibility in case our parents' has changed.
UpdateVisibility();
UpdateParticleSystems();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEconWearable::ClientThink( void )
{
BaseClass::ClientThink();
UpdateParticleSystems();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEconWearable::ShouldDrawParticleSystems( void )
{
// Make sure the entity we're attaching to is being drawn
CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
if ( !pPlayerOwner )
{
Assert ( "CEconWearable has no owner?" ); // Not sure what this means - is is visible or not?
return false;
}
if ( pPlayerOwner->ShouldDrawThisPlayer() )
{
return true;
}
return false;
}
RenderGroup_t CEconWearable::GetRenderGroup()
{
if ( IsViewModelWearable() )
return RENDER_GROUP_VIEW_MODEL_TRANSLUCENT;
return BaseClass::GetRenderGroup();
}
//-----------------------------------------------------------------------------
// Purpose: Wearable tint colors
//-----------------------------------------------------------------------------
class CProxyItemTintColor : public CResultProxy
{
public:
void OnBind( void *pC_BaseEntity )
{
Assert( m_pResult );
Vector vResult = Vector( 0, 0, 0 );
if ( pC_BaseEntity )
{
CEconItemView *pScriptItem = NULL;
IClientRenderable *pRend = (IClientRenderable *)pC_BaseEntity;
C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
if ( pEntity )
{
CEconEntity *pItem = dynamic_cast< CEconEntity* >( pEntity );
if ( pItem )
{
pScriptItem = pItem->GetAttributeContainer()->GetItem();
}
else if ( pEntity->GetOwnerEntity() )
{
// Try the owner (for viewmodels, etc).
pEntity = pEntity->GetOwnerEntity();
pItem = dynamic_cast< CEconEntity* >( pEntity );
if ( pItem )
{
pScriptItem = pItem->GetAttributeContainer()->GetItem();
}
}
}
else
{
// Proxy data can be a script created item itself, if we're in a vgui CModelPanel
pScriptItem = dynamic_cast< CEconItemView* >( pRend );
}
#ifdef TF_CLIENT_DLL
if ( !pScriptItem )
{
// Might be a throwable
CTFWeaponBaseGrenadeProj *pProjectile = dynamic_cast< CTFWeaponBaseGrenadeProj* >( pEntity );
if ( pProjectile )
{
CEconEntity *pItem = dynamic_cast< CEconEntity* >( pProjectile->GetLauncher() );
if ( pItem )
{
pScriptItem = pItem->GetAttributeContainer()->GetItem();
}
}
}
if ( pScriptItem && pScriptItem->IsValid() )
{
const bool bAltColor = pEntity && pEntity->GetTeam() > 0
? pEntity->GetTeam()->GetTeamNumber() == TF_TEAM_BLUE
: pScriptItem->GetFlags() & kEconItemFlagClient_ForceBlueTeam
? true
: false;
int iModifiedRGB = pScriptItem->GetModifiedRGBValue( bAltColor );
if ( iModifiedRGB )
{
// The attrib returns a packed RGB with values between 0 & 255 packed into the bottom 3 bytes.
Color clr = Color( ((iModifiedRGB & 0xFF0000) >> 16), ((iModifiedRGB & 0xFF00) >> 8), (iModifiedRGB & 0xFF) );
vResult.x = clamp( clr.r() * (1.f / 255.0f), 0.f, 1.0f );
vResult.y = clamp( clr.g() * (1.f / 255.0f), 0.f, 1.0f );
vResult.z = clamp( clr.b() * (1.f / 255.0f), 0.f, 1.0f );
}
}
#endif // TF_CLIENT_DLL
}
m_pResult->SetVecValue( vResult.x, vResult.y, vResult.z );
}
};
EXPOSE_INTERFACE( CProxyItemTintColor, IMaterialProxy, "ItemTintColor" IMATERIAL_PROXY_INTERFACE_VERSION );
//============================================================================================================================
extern ConVar r_propsmaxdist;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_EconWearableGib::C_EconWearableGib()
{
m_fDeathTime = -1;
m_iHealth = 0;
m_bParented = false;
m_bDelayedInit = false;
}
C_EconWearableGib::~C_EconWearableGib()
{
PhysCleanupFrictionSounds( this );
VPhysicsDestroyObject();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_EconWearableGib::Initialize( bool bWillBeParented )
{
m_bParented = bWillBeParented;
return InitializeAsClientEntity( STRING( GetModelName() ), RENDER_GROUP_OPAQUE_ENTITY );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CStudioHdr* C_EconWearableGib::OnNewModel()
{
CStudioHdr* pCStudioHdr = BaseClass::OnNewModel();
if ( m_bDelayedInit && !IsDynamicModelLoading() )
{
FinishModelInitialization();
}
return pCStudioHdr;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EconWearableGib::SpawnClientEntity( void )
{
if ( !IsDynamicModelLoading() )
{
FinishModelInitialization();
}
else
{
m_bDelayedInit = true;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_EconWearableGib::FinishModelInitialization( void )
{
UpdateThinkState();
const model_t *mod = GetModel();
if ( mod )
{
Vector mins, maxs;
modelinfo->GetModelBounds( mod, mins, maxs );
SetCollisionBounds( mins, maxs );
}
if ( !m_bParented )
{
// Create the object in the physics system
solid_t tmpSolid;
if ( !PhysModelParseSolid( tmpSolid, this, GetModelIndex() ) )
{
DevMsg("C_EconWearableGib::FinishModelInitialization: PhysModelParseSolid failed for entity %i.\n", GetModelIndex() );
return false;
}
else
{
m_pPhysicsObject = VPhysicsInitNormal( SOLID_VPHYSICS, 0, false, &tmpSolid );
if ( !m_pPhysicsObject )
{
// failed to create a physics object
DevMsg(" C_EconWearableGib::FinishModelInitialization: VPhysicsInitNormal() failed for %s.\n", STRING(GetModelName()) );
return false;
}
}
}
Spawn();
if ( m_fadeMinDist < 0 )
{
// start fading out at 75% of r_propsmaxdist
m_fadeMaxDist = r_propsmaxdist.GetFloat();
m_fadeMinDist = r_propsmaxdist.GetFloat() * 0.75f;
}
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
UpdatePartitionListEntry();
CollisionProp()->UpdatePartition();
SetBlocksLOS( false ); // this should be a small object
// Set up shadows; do it here so that objects can change shadowcasting state
CreateShadow();
UpdateVisibility();
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EconWearableGib::Spawn()
{
BaseClass::Spawn();
m_takedamage = DAMAGE_EVENTS_ONLY;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_EconWearableGib::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
{
bShouldRetry = false;
// Always valid as long as we're not parented to anything
return (GetMoveParent() == NULL);
}
#define WEARABLE_FADEOUT_TIME 1.0f
//-----------------------------------------------------------------------------
// Purpose: Figure out if we need to think or not
//-----------------------------------------------------------------------------
bool C_EconWearableGib::UpdateThinkState( void )
{
if ( m_fDeathTime > 0 )
{
// If we're in the active fadeout portion, think rapidly. Otherwise, wait for that time.
if ( (m_fDeathTime - gpGlobals->curtime) > WEARABLE_FADEOUT_TIME )
{
SetNextClientThink( m_fDeathTime - WEARABLE_FADEOUT_TIME );
}
else
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
return true;
}
SetNextClientThink( CLIENT_THINK_NEVER );
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EconWearableGib::ClientThink( void )
{
if ( (m_fDeathTime > 0) && ((m_fDeathTime - gpGlobals->curtime) <= WEARABLE_FADEOUT_TIME) )
{
if ( m_fDeathTime <= gpGlobals->curtime )
{
Release(); // Die
return;
}
// fade out
float alpha = (m_fDeathTime - gpGlobals->curtime) / WEARABLE_FADEOUT_TIME;
SetRenderMode( kRenderTransTexture );
SetRenderColorA( alpha * 256 );
}
UpdateThinkState();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EconWearableGib::StartFadeOut( float fDelay )
{
m_fDeathTime = gpGlobals->curtime + fDelay + WEARABLE_FADEOUT_TIME;
UpdateThinkState();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EconWearableGib::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
{
IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
if( !pPhysicsObject )
return;
Vector dir = pTrace->endpos - pTrace->startpos;
int iDamage = 0;
if ( iDamageType & DMG_BLAST )
{
iDamage = VectorLength( dir );
dir *= 500; // adjust impact strenght
// apply force at object mass center
pPhysicsObject->ApplyForceCenter( dir );
}
else
{
Vector hitpos;
VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
VectorNormalize( dir );
// guess avg damage
if ( iDamageType == DMG_BULLET )
{
iDamage = 30;
}
else
{
iDamage = 50;
}
dir *= 4000; // adjust impact strenght
// apply force where we hit it
pPhysicsObject->ApplyForceOffset( dir, hitpos );
}
}
#if 0
#ifdef _DEBUG
#include "econ_item_system.h"
static CUtlVector< const char * > s_possibleModels;
static CUtlVector< const GameItemDefinition_t * > s_possibleDefinitions;
void Dbg_TestDynamicWearableGibs( void )
{
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
C_EconWearableGib *pEntity = new C_EconWearableGib();
if ( !pEntity )
return;
Vector forward;
pLocalPlayer->EyeVectors( &forward );
trace_t tr;
UTIL_TraceLine( pLocalPlayer->EyePosition(), pLocalPlayer->EyePosition() + (forward * 256), MASK_NPCSOLID, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
Vector position = tr.endpos;
if ( s_possibleModels.Count() == 0 )
{
FOR_EACH_MAP( ItemSystem()->GetItemSchema()->GetItemDefinitionMap(), nDefn )
{
const GameItemDefinition_t *pDefn = dynamic_cast<GameItemDefinition_t *>( ItemSystem()->GetItemSchema()->GetItemDefinitionMap()[nDefn] );
if ( !pDefn )
continue;
const char *pszModel = pDefn->GetPlayerDisplayModel( 0 );
if ( pszModel && pszModel[0] && pszModel[0] != '?' && pDefn->BLoadOnDemand() && pDefn->GetDropType() == ITEM_DROP_TYPE_DROP )
{
s_possibleModels.AddToTail( pszModel );
s_possibleDefinitions.AddToTail( pDefn );
}
}
}
Assert( s_possibleModels.Count() );
int spawnIndex = random->RandomInt( 0, s_possibleModels.Count() - 1 );
const char *pszModelName = s_possibleModels[ spawnIndex ];
const GameItemDefinition_t *pDefn = s_possibleDefinitions[ spawnIndex ];
Msg( "Spawning: %s\n", pszModelName );
pEntity->SetModelName( AllocPooledString( pszModelName ) );
pEntity->SetAbsOrigin( position );
pEntity->SetAbsAngles( vec3_angle );
pEntity->SetOwnerEntity( pLocalPlayer );
pEntity->ChangeTeam( pLocalPlayer->GetTeamNumber() ); // our gibs will match our team; this will probably not be used for anything besides team coloring
// Copy the script created item data over
pEntity->GetAttributeContainer()->GetItem()->Init( pDefn->GetDefinitionIndex(), pDefn->GetQuality(), pDefn->GetMinLevel(), true );
if ( !pEntity->Initialize( false ) )
{
pEntity->Release();
return;
}
pEntity->StartFadeOut( 15.0f );
return;
IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
if ( !pPhysicsObject )
{
pEntity->Release();
return;
}
// randomize velocity by 5%
Vector rndVel = Vector(0,0,100);
pPhysicsObject->AddVelocity( &rndVel, &vec3_origin );
}
static ConCommand dbg_testdynamicwearablegib( "dbg_testdynamicwearablegib", Dbg_TestDynamicWearableGibs, "", FCVAR_CHEAT );
#endif // _DEBUG
#endif
#endif // client only
+138
View File
@@ -0,0 +1,138 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ECON_WEARABLE_H
#define ECON_WEARABLE_H
#ifdef _WIN32
#pragma once
#endif
#include "econ_entity.h"
enum
{
MAX_WEARABLES_SENT_FROM_SERVER =
#ifdef LOADOUT_MAX_WEARABLES_COUNT // we actually do want to just check for macro definition here -- undefined means "fall back to whatever default"
LOADOUT_MAX_WEARABLES_COUNT
#else
8 // hard-coded constant to match old behavior
#endif
};
#if defined( CLIENT_DLL )
#define CEconWearable C_EconWearable
#define CTFWearableItem C_TFWearableItem
#endif
enum
{
ITEM_DROP_TYPE_NULL,
ITEM_DROP_TYPE_NONE,
ITEM_DROP_TYPE_DROP,
ITEM_DROP_TYPE_BREAK,
};
class CEconWearable : public CEconEntity
{
DECLARE_CLASS( CEconWearable, CEconEntity );
public:
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
CEconWearable();
virtual bool IsWearable( void ) const { return true; }
// Shared
virtual void Spawn( void );
virtual void GiveTo( CBaseEntity *pOther );
virtual void RemoveFrom( CBaseEntity *pOther );
virtual bool CanEquip( CBaseEntity *pOther ) { return true; }
virtual void Equip( CBasePlayer *pOwner );
virtual void UnEquip( CBasePlayer* pOwner );
virtual void OnWearerDeath( void );
virtual int GetDropType( void );
// virtual bool UpdateBodygroups( CBasePlayer* pOwner, int iState );
void SetAlwaysAllow( bool bVal ) { m_bAlwaysAllow = bVal; }
bool AlwaysAllow( void ) { return m_bAlwaysAllow; }
virtual bool IsViewModelWearable( void ) { return false; }
// Server
#if defined( GAME_DLL )
#endif
// Client
#if defined( CLIENT_DLL )
virtual ShadowType_t ShadowCastType() OVERRIDE;
virtual bool ShouldDraw();
virtual bool ShouldDrawWhenPlayerIsDead() { return true; }
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
virtual bool ShouldDrawParticleSystems( void );
virtual RenderGroup_t GetRenderGroup();
#endif
virtual int GetSkin( void );
// Static
static void UpdateWearableBodyGroups( CBasePlayer *pPlayer );
protected:
virtual void InternalSetPlayerDisplayModel( void );
private:
bool m_bAlwaysAllow; // Wearable will not be removed by ManageRegularWeapons. Only use this for wearables managed by other items!
};
//-----------------------------------------------------------------------------
// Purpose: For backwards compatibility with older demos
//-----------------------------------------------------------------------------
class CTFWearableItem : public CEconWearable
{
DECLARE_CLASS( CTFWearableItem, CEconWearable );
public:
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
CTFWearableItem();
};
#ifdef CLIENT_DLL
// Clientside wearable physics props. Used to have wearables fall off dying players.
class C_EconWearableGib : public CEconEntity
{
DECLARE_CLASS( C_EconWearableGib, CEconEntity );
public:
C_EconWearableGib();
~C_EconWearableGib();
bool Initialize( bool bWillBeParented );
bool FinishModelInitialization( void );
virtual CStudioHdr *OnNewModel( void );
virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry );
virtual void SpawnClientEntity();
virtual void Spawn();
virtual void ClientThink( void );
void StartFadeOut( float fDelay );
virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
virtual CollideType_t GetCollideType( void ) { return ENTITY_SHOULD_RESPOND; }
bool UpdateThinkState( void );
private:
bool m_bParented;
bool m_bDelayedInit;
float m_fDeathTime; // Point at which this object self destructs.
// The default of -1 indicates the object shouldn't destruct.
};
#endif
#endif // ECON_WEARABLE_H
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef GAME_ITEM_SCHEMA_H
#define GAME_ITEM_SCHEMA_H
#ifdef _WIN32
#pragma once
#endif
#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
// TF
class CTFItemSchema;
class CTFItemDefinition;
class CTFItemSystem;
typedef CTFItemSchema GameItemSchema_t;
typedef CTFItemDefinition GameItemDefinition_t;
typedef CTFItemSystem GameItemSystem_t;
#include "tf_item_schema.h"
#elif defined( DOTA_CLIENT_DLL ) || defined( DOTA_DLL ) || defined ( DOTA_GC_DLL )
// DOTA
class CDOTAItemSchema;
class CDOTAItemDefinition;
class CDOTAItemSystem;
typedef CDOTAItemSchema GameItemSchema_t;
typedef CDOTAItemDefinition GameItemDefinition_t;
typedef CDOTAItemSystem GameItemSystem_t;
#include "econ/dota_item_schema.h"
#else
// Fallback Case
class CEconItemSchema;
class CEconItemDefinition;
class CEconItemSystem;
typedef CEconItemSchema GameItemSchema_t;
typedef CEconItemDefinition GameItemDefinition_t;
typedef CEconItemSystem GameItemSystem_t;
#include "econ_item_schema.h"
#endif
extern GameItemSchema_t *GetItemSchema();
#endif // GAME_ITEM_SYSTEM_H
+46
View File
@@ -0,0 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef IHASATTRIBUTES_H
#define IHASATTRIBUTES_H
#ifdef _WIN32
#pragma once
#endif
//#include "attribute_manager.h"
class CAttributeManager;
class CAttributeContainer;
class CBaseEntity;
class CAttributeList;
// To allow an entity to have attributes, derive it from IHasAttributes and
// contain an CAttributeManager in it. Then:
// - Call InitializeAttributes() before your entity's Spawn()
// - Call AddAttribute() to add attributes to the entity
// - Call all the CAttributeManager hooks at the appropriate times in your entity.
// To get networking of the attributes to work on your entity:
// - Add this to your entity's send table:
// SendPropDataTable( SENDINFO_DT( m_AttributeManager ), &REFERENCE_SEND_TABLE(DT_AttributeManager) ),
// - Call this inside your entity's OnDataChanged():
// GetAttributeManager()->OnDataChanged( updateType );
//-----------------------------------------------------------------------------
// Purpose: Derive from this if your entity wants to contain attributes.
//-----------------------------------------------------------------------------
class IHasAttributes
{
public:
virtual CAttributeManager *GetAttributeManager( void ) = 0;
virtual CAttributeContainer *GetAttributeContainer( void ) = 0;
virtual CBaseEntity *GetAttributeOwner( void ) = 0;
virtual CAttributeList *GetAttributeList( void ) = 0;
// Reapply yourself to whoever you should be providing attributes to.
virtual void ReapplyProvision( void ) = 0;
};
#endif // IHASATTRIBUTES_H
+24
View File
@@ -0,0 +1,24 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef IHASOWNER_H
#define IHASOWNER_H
#ifdef _WIN32
#pragma once
#endif
class CBaseEntity;
//-----------------------------------------------------------------------------
// Purpose: Allows an entity to access its owner regardless of entity type
//-----------------------------------------------------------------------------
class IHasOwner
{
public:
virtual CBaseEntity *GetOwnerViaInterface( void ) = 0;
};
#endif // IHASOWNER_H
@@ -0,0 +1,614 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CItemSelectionCriteria, which serves as a criteria for selection
// of a econ item
//
//=============================================================================
#include "cbase.h"
#include "item_selection_criteria.h"
#include "gcsdk/gcsystemmsgs.h"
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
#include "tf_gcmessages.h"
#endif
#include "gcsdk/enumutils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// copied from \common\econ_item_view.h
#define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
ENUMSTRINGS_START( EItemCriteriaOperator )
{ k_EOperator_String_EQ, "string==" },
{ k_EOperator_String_Not_EQ, "!string==" },
{ k_EOperator_Float_EQ, "float==" },
{ k_EOperator_Float_Not_EQ, "!float==" },
{ k_EOperator_Float_LT, "float<" },
{ k_EOperator_Float_Not_LT, "!float<" },
{ k_EOperator_Float_LTE, "float<=" },
{ k_EOperator_Float_Not_LTE, "!float<=" },
{ k_EOperator_Float_GT, "float>" },
{ k_EOperator_Float_Not_GT, "!float>" },
{ k_EOperator_Float_GTE, "float>=" },
{ k_EOperator_Float_Not_GTE, "!float>=" },
{ k_EOperator_Subkey_Contains, "contains" },
{ k_EOperator_Subkey_Not_Contains, "!contains" },
ENUMSTRINGS_REVERSE( EItemCriteriaOperator, k_EItemCriteriaOperator_Count )
using namespace GCSDK;
//-----------------------------------------------------------------------------
// Purpose: Copy Constructor
//-----------------------------------------------------------------------------
CItemSelectionCriteria::CItemSelectionCriteria( const CItemSelectionCriteria &that )
{
(*this) = that;
}
//-----------------------------------------------------------------------------
// Purpose: Operator=
//-----------------------------------------------------------------------------
CItemSelectionCriteria &CItemSelectionCriteria::operator=( const CItemSelectionCriteria &rhs )
{
// Leverage the serialization code we already have for the copy
CSOItemCriteria msgTemp;
rhs.BSerializeToMsg( msgTemp );
BDeserializeFromMsg( msgTemp );
return *this;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CItemSelectionCriteria::~CItemSelectionCriteria( void )
{
m_vecConditions.PurgeAndDeleteElements();
}
//-----------------------------------------------------------------------------
// Purpose: Look through our conditions and find the first of the specified type,
// and return the value it's looking for.
//-----------------------------------------------------------------------------
const char *CItemSelectionCriteria::GetValueForFirstConditionOfType( EItemCriteriaOperator eType ) const
{
// Only supporting this for string conditions right now
Assert( eType == k_EOperator_String_EQ || eType == k_EOperator_String_Not_EQ );
FOR_EACH_VEC( m_vecConditions, i )
{
if ( m_vecConditions[i]->GetEOp() == eType )
return m_vecConditions[i]->GetValue();
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Look through our conditions and find the first of the specified type,
// and return the value it's looking for.
//-----------------------------------------------------------------------------
const char *CItemSelectionCriteria::GetFieldForFirstConditionOfType( EItemCriteriaOperator eType ) const
{
FOR_EACH_VEC( m_vecConditions, i )
{
if ( m_vecConditions[i]->GetEOp() == eType )
return m_vecConditions[i]->GetField();
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Initialize from a KV structure
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BInitFromKV( KeyValues *pKVCriteria )
{
// Read in the base fields
if ( pKVCriteria->FindKey( "level" ) )
{
SetItemLevel( pKVCriteria->GetInt( "level" ) );
}
if ( pKVCriteria->FindKey( "quality" ) )
{
uint8 nQuality;
if ( !GetItemSchema()->BGetItemQualityFromName( pKVCriteria->GetString( "quality" ), &nQuality ) )
return false;
SetQuality( nQuality );
}
if ( pKVCriteria->FindKey( "inventoryPos" ) )
{
SetInitialInventory( pKVCriteria->GetInt( "inventoryPos" ) );
}
if ( pKVCriteria->FindKey( "quantity" ) )
{
SetInitialQuantity( pKVCriteria->GetInt( "quantity" ) );
}
if ( pKVCriteria->FindKey( "ignore_enabled" ) )
{
SetIgnoreEnabledFlag( pKVCriteria->GetBool( "ignore_enabled" ) );
}
if ( pKVCriteria->FindKey( "tags" ) )
{
SetTags( pKVCriteria->GetString( "tags" ) );
}
KeyValues *pKVConditions = pKVCriteria->FindKey( "conditions", true );
FOR_EACH_TRUE_SUBKEY( pKVConditions, pKVElement )
{
// Check for required fields
if ( !pKVElement->FindKey( "field" ) ||
!pKVElement->FindKey( "operator" ) ||
!pKVElement->FindKey( "value" ) )
return false;
const char *pszField = pKVElement->GetString( "field" );
bool bRequired = pKVElement->GetBool( "required" );
const char *pszValue = pKVElement->GetString( "value" );
// Get the operator
const char *pszOperator = pKVElement->GetString( "operator" );
EItemCriteriaOperator eOp = EItemCriteriaOperatorFromName( pszOperator );
if ( k_EItemCriteriaOperator_Count == eOp )
return false;
BAddCondition( pszField, eOp, pszValue, bRequired );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemSelectionCriteria::SetTags( const char *pszTags )
{
m_vecTags.Purge();
m_strTags = pszTags;
CSplitString splitString( pszTags, " " );
for ( int i=0; i<splitString.Count(); ++i )
{
econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( splitString[i] );
if ( !m_vecTags.HasElement( tagHandle ) )
{
m_vecTags.AddToTail( tagHandle );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BAddCondition( CItemSelectionCriteria::ICondition *pCondition )
{
CPlainAutoPtr<ICondition> pConditionPtr( pCondition );
// Check for condition limit
if ( UCHAR_MAX == GetConditionsCount() )
{
AssertMsg( false, "Too many conditions on a a CItemSelectionCriteria. Max: 255" );
return false;
}
m_vecConditions.AddToTail( pConditionPtr.Detach() );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Adds a condition to the selection criteria
// Input: pszField - Field to evaluate on
// eOp - Operator to apply to the value of the field
// flValue - The value to compare.
// bRequired - When true, causes BEvauluate to fail if pszField doesn't
// exist in the KV being checked.
// Output: True if the condition was added, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
{
// Enforce maximum string lengths
if ( Q_strlen( pszField ) >= k_cchCreateItemLen )
return false;
// Create the appropriate condition for the operator
switch ( eOp )
{
case k_EOperator_Float_EQ:
case k_EOperator_Float_Not_EQ:
case k_EOperator_Float_LT:
case k_EOperator_Float_Not_LT:
case k_EOperator_Float_LTE:
case k_EOperator_Float_Not_LTE:
case k_EOperator_Float_GT:
case k_EOperator_Float_Not_GT:
case k_EOperator_Float_GTE:
case k_EOperator_Float_Not_GTE:
return BAddCondition( new CFloatCondition( pszField, eOp, flValue, bRequired ) );
default:
AssertMsg1( false, "Bad operator (%d) passed to BAddCondition. Float based operator required for this overload.", eOp );
return false;
}
}
//-----------------------------------------------------------------------------
// Purpose: Adds a condition to the selection criteria
// Input: pszField - Field to evaluate on
// eOp - Operator to apply to the value of the field
// pszValue - The value to compare.
// bRequired - When true, causes BEvauluate to fail if pszField doesn't
// exist in the KV being checked.
// Output: True if the condition was added, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired )
{
// Enforce maximum string lengths
if ( Q_strlen( pszField ) >= k_cchCreateItemLen || Q_strlen( pszValue ) >= k_cchCreateItemLen )
return false;
// Create the appropriate condition for the operator
switch ( eOp )
{
case k_EOperator_String_EQ:
case k_EOperator_String_Not_EQ:
return BAddCondition( new CStringCondition( pszField, eOp, pszValue, bRequired ) );
return true;
case k_EOperator_Subkey_Contains:
case k_EOperator_Subkey_Not_Contains:
return BAddCondition( new CSetCondition( pszField, eOp, pszValue, bRequired ) );
return true;
default:
// Try the float operators
return BAddCondition( pszField, eOp, Q_atof( pszValue ), bRequired );
}
}
//-----------------------------------------------------------------------------
// Purpose: Checks if a given item matches the item selection criteria
// Input: itemDef - The item definition to evaluate against
// Output: True is the item passes the filter, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BEvaluate( const CEconItemDefinition* pItemDef ) const
{
// Disabled items never match
if ( !m_bIgnoreEnabledFlag && !pItemDef->BEnabled() )
return false;
// Filter against level
if ( BItemLevelSet() && (GetItemLevel() != AE_USE_SCRIPT_VALUE) &&
( GetItemLevel() < pItemDef->GetMinLevel() || GetItemLevel() > pItemDef->GetMaxLevel() ) )
return false;
// Filter against quality
if ( BQualitySet() && (GetQuality() != AE_USE_SCRIPT_VALUE) )
{
if ( GetQuality() != pItemDef->GetQuality() )
{
// Filter out item defs that have a non-any quality if we have a non-matching & non-any quality criteria
if ( k_unItemQuality_Any != GetQuality() && k_unItemQuality_Any != pItemDef->GetQuality() )
return false;
}
}
// Filter against the additional conditions
FOR_EACH_VEC( m_vecConditions, i )
{
if ( !m_vecConditions[i]->BItemDefinitionPassesCriteria( pItemDef ) )
return false;
}
// Check if we have "any" tags
if ( m_vecTags.Count() > 0 )
{
bool bHasTag = false;
FOR_EACH_VEC( m_vecTags, i )
{
if ( pItemDef->HasEconTag( m_vecTags[i] ) )
{
bHasTag = true;
break;
}
}
if ( !bHasTag )
{
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Determines if the item matches this condition of the criteria
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
// Output: True is the item matches, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CCondition::BEvaluate( KeyValues *pKVItem ) const
{
KeyValues *pKVField = pKVItem->FindKey( m_sField.String() );
// Treat an empty string as a missing field as well.
bool bIsEmptyString = false;
if ( m_EOp == k_EOperator_String_EQ || m_EOp == k_EOperator_String_Not_EQ )
{
const char *pszItemVal = pKVField ? pKVField->GetString() : NULL;
bIsEmptyString = ( pszItemVal == NULL || pszItemVal[0] == '\0' );
}
// Deal with missing fields
if ( NULL == pKVField || bIsEmptyString )
{
if ( m_bRequired )
return false;
else
return true;
}
// Run the operator specific check
bool bRet = BInternalEvaluate( pKVItem );
// If this is a "not" operator, reverse the result
if ( m_EOp & k_EOperator_Not )
return !bRet;
else
return bRet;
}
//-----------------------------------------------------------------------------
// Purpose: Runs the operator specific check for this condition
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
// Output: True is the item matches, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CStringCondition::BInternalEvaluate( KeyValues *pKVItem ) const
{
Assert( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp );
if( !( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp ) )
return false;
const char *pszItemVal = pKVItem->GetString( m_sField.String() );
return ( 0 == Q_stricmp( m_sValue.String(), pszItemVal ) );
}
bool CItemSelectionCriteria::CStringCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
{
CCondition::BSerializeToMsg( msg );
msg.set_string_value( m_sValue.Get() );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Runs the operator specific check for this condition
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
// Output: True is the item matches, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CSetCondition::BInternalEvaluate( KeyValues *pKVItem ) const
{
Assert( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp );
if( !( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp ) )
return false;
return ( NULL != pKVItem->FindKey( m_sField.String() )->FindKey( m_sValue.String() ) );
}
bool CItemSelectionCriteria::CSetCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
{
CCondition::BSerializeToMsg( msg );
msg.set_string_value( m_sValue.Get() );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Runs the operator specific check for this condition
// Input: pKVItem - Pointer to the raw KeyValues definition of the item
// Output: True is the item matches, false otherwise
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CFloatCondition::BInternalEvaluate( KeyValues *pKVItem ) const
{
float itemValue = pKVItem->GetFloat( m_sField.String() );
switch ( m_EOp )
{
case k_EOperator_Float_EQ:
case k_EOperator_Float_Not_EQ:
return ( itemValue == m_flValue );
case k_EOperator_Float_LT:
case k_EOperator_Float_Not_LT:
return ( itemValue < m_flValue );
case k_EOperator_Float_LTE:
case k_EOperator_Float_Not_LTE:
return ( itemValue <= m_flValue );
case k_EOperator_Float_GT:
case k_EOperator_Float_Not_GT:
return ( itemValue > m_flValue );
case k_EOperator_Float_GTE:
case k_EOperator_Float_Not_GTE:
return ( itemValue >= m_flValue );
default:
AssertMsg1( false, "Unknown operator: %d", m_EOp );
return false;
}
}
bool CItemSelectionCriteria::CFloatCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
{
CCondition::BSerializeToMsg( msg );
msg.set_float_value( m_flValue );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Serialize the item selection criteria to the given message
// Input: msg - The message to serialize to.
// Output: True if the operation was successful, false otherwise.
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BSerializeToMsg( CSOItemCriteria & msg ) const
{
msg.set_item_level( m_unItemLevel );
msg.set_item_quality( m_nItemQuality );
msg.set_item_level_set( m_bItemLevelSet );
msg.set_item_quality_set( m_bQualitySet );
msg.set_initial_inventory( m_unInitialInventory );
msg.set_initial_quantity( m_unInitialQuantity );
msg.set_ignore_enabled_flag( m_bIgnoreEnabledFlag );
msg.set_tags( m_strTags );
FOR_EACH_VEC( m_vecConditions, i )
{
CSOItemCriteriaCondition *pConditionMsg = msg.add_conditions();
m_vecConditions[i]->BSerializeToMsg( *pConditionMsg );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Deserializes the item selection criteria from the given message
// Input: msg - The message to deserialize from.
// Output: True if the operation was successful, false otherwise.
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::BDeserializeFromMsg( const CSOItemCriteria & msg )
{
m_unItemLevel = msg.item_level();
m_nItemQuality = msg.item_quality();
m_bItemLevelSet = msg.item_level_set();
m_bQualitySet = msg.item_quality_set();
m_unInitialInventory = msg.initial_inventory();
m_unInitialQuantity = msg.initial_quantity();
m_bIgnoreEnabledFlag = msg.ignore_enabled_flag();
SetTags( msg.tags().c_str() );
uint32 unCount = msg.conditions_size();
m_vecConditions.EnsureCapacity( unCount );
for ( uint32 i = 0; i < unCount; i++ )
{
const CSOItemCriteriaCondition & cond = msg.conditions( i );
EItemCriteriaOperator eOp = (EItemCriteriaOperator)cond.op();
bool bRequired = cond.required();
// Read the value specific to the condition and add the condition
switch ( eOp )
{
case k_EOperator_Float_EQ:
case k_EOperator_Float_Not_EQ:
case k_EOperator_Float_LT:
case k_EOperator_Float_Not_LT:
case k_EOperator_Float_LTE:
case k_EOperator_Float_Not_LTE:
case k_EOperator_Float_GT:
case k_EOperator_Float_Not_GT:
case k_EOperator_Float_GTE:
case k_EOperator_Float_Not_GTE:
{
if ( !BAddCondition( cond.field().c_str(), eOp, cond.float_value(), bRequired ) ) return false;
break;
}
case k_EOperator_String_EQ:
case k_EOperator_String_Not_EQ:
case k_EOperator_Subkey_Contains:
case k_EOperator_Subkey_Not_Contains:
{
if ( !BAddCondition( cond.field().c_str(), eOp, cond.string_value().c_str(), bRequired ) ) return false;
break;
}
default:
AssertMsg1( false, "Unknown operator (%d) read.", eOp );
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Serializes a condition to a message.
// Input: msg - The message to serialize to.
// Output: True if the operation was successful, false otherwise.
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
{
msg.set_op( m_EOp );
msg.set_field( m_sField.String() );
msg.set_required( m_bRequired );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItemSelectionCriteria::CCondition::BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const
{
return BEvaluate( pItemDef->GetRawDefinition() );
}
// Validation
#ifdef DBGFLAG_VALIDATE
//-----------------------------------------------------------------------------
// Purpose: Run a global validation pass on all of our data structures and memory
// allocations.
// Input: validator - Our global validator object
// pchName - Our name (typically a member var in our container)
//-----------------------------------------------------------------------------
void CItemSelectionCriteria::Validate( CValidator &validator, const char *pchName )
{
VALIDATE_SCOPE();
ValidateObj( m_vecConditions );
FOR_EACH_VEC( m_vecConditions, i )
{
ValidatePtr( m_vecConditions[i] );
}
}
void CItemSelectionCriteria::CCondition::Validate( CValidator &validator, const char *pchName )
{
ValidateObj( m_sField );
}
void CItemSelectionCriteria::CStringCondition::Validate( CValidator &validator, const char *pchName )
{
CCondition::Validate( validator, pchName );
ValidateObj( m_sValue );
}
void CItemSelectionCriteria::CSetCondition::Validate( CValidator &validator, const char *pchName )
{
CCondition::Validate( validator, pchName );
ValidateObj( m_sValue );
}
#endif
+290
View File
@@ -0,0 +1,290 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CItemSelectionCriteria, which serves as a criteria for selection
// of a econ item
//
//=============================================================================
#ifndef ITEM_SELECTION_CRITERIA_H
#define ITEM_SELECTION_CRITERIA_H
#ifdef _WIN32
#pragma once
#endif
// Maximum string length in item create APIs
const int k_cchCreateItemLen = 64;
// Operators for BAddNewItemCriteria
enum EItemCriteriaOperator
{
k_EOperator_String_EQ = 0, // Field is string equal to value
k_EOperator_Not = 1, // Logical not
k_EOperator_String_Not_EQ = 1, // Field is not string equal to value
k_EOperator_Float_EQ = 2, // Field as a float is equal to value
k_EOperator_Float_Not_EQ = 3, // Field as a float is not equal to value
k_EOperator_Float_LT = 4, // Field as a float is less than value
k_EOperator_Float_Not_LT = 5, // Field as a float is not less than value
k_EOperator_Float_LTE = 6, // Field as a float is less than or equal value
k_EOperator_Float_Not_LTE = 7, // Field as a float is not less than or equal value
k_EOperator_Float_GT = 8, // Field as a float is greater than value
k_EOperator_Float_Not_GT = 9, // Field as a float is not greater than value
k_EOperator_Float_GTE = 10, // Field as a float is greater than or equal value
k_EOperator_Float_Not_GTE = 11, // Field as a float is not greater than or equal value
k_EOperator_Subkey_Contains = 12, // Field contains value as a subkey
k_EOperator_Subkey_Not_Contains = 13, // Field does not contain value as a subkey
// Must be last
k_EItemCriteriaOperator_Count = 14,
};
EItemCriteriaOperator EItemCriteriaOperatorFromName( const char *pch );
const char *PchNameFromEItemCriteriaOperator( int eItemCriteriaOperator );
class CEconItemSchema;
class CEconItemDefinition;
class CSOItemCriteria;
class CSOItemCriteriaCondition;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// CItemSelectionCriteria
// A class that contains all the conditions a server needs to specify what
// kind of random item they wish to generate.
//-----------------------------------------------------------------------------
class CItemSelectionCriteria
{
public:
// Constructors and destructor
CItemSelectionCriteria() :
m_bItemLevelSet( false ),
m_unItemLevel( 0 ),
m_bQualitySet( false ),
m_nItemQuality( k_unItemQuality_Any ),
m_unInitialInventory( 0 ),
m_bInitialQuantitySet( false ),
m_unInitialQuantity( 1 ),
m_bIgnoreEnabledFlag( false )
{
}
CItemSelectionCriteria( const CItemSelectionCriteria &that );
CItemSelectionCriteria &operator=( const CItemSelectionCriteria& rhs );
~CItemSelectionCriteria();
// Accessors and Settors
bool BItemLevelSet( void ) const { return m_bItemLevelSet; }
uint32 GetItemLevel( void ) const { Assert( m_bItemLevelSet ); return m_unItemLevel; }
void SetItemLevel( uint32 unLevel ) { m_unItemLevel = unLevel; m_bItemLevelSet = true; }
bool BQualitySet( void ) const { return m_bQualitySet; }
int32 GetQuality( void ) const { Assert( m_bQualitySet ); return m_nItemQuality; }
void SetQuality( int32 nQuality ) { m_nItemQuality = nQuality; m_bQualitySet = true; }
uint32 GetInitialInventory( void ) const { return m_unInitialInventory; }
void SetInitialInventory( uint32 unInventory ) { m_unInitialInventory = unInventory; }
bool BInitialQuantitySet( void ) const { return m_bQualitySet; }
uint32 GetInitialQuantity( void ) const { Assert( m_bQualitySet ); return m_unInitialQuantity; }
void SetInitialQuantity( uint32 unQuantity ) { m_unInitialQuantity = unQuantity; m_bInitialQuantitySet = true; }
void SetIgnoreEnabledFlag( bool bIgnore ) { m_bIgnoreEnabledFlag = bIgnore; }
// Tags
void SetTags( const char *pszTags );
// Add conditions to the criteria
class ICondition
{
public:
virtual ~ICondition() { }
virtual bool BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const = 0;
virtual EItemCriteriaOperator GetEOp() const { return k_EItemCriteriaOperator_Count; }
virtual const char *GetField() const { return ""; }
virtual const char *GetValue() const { return ""; }
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const { Assert( !"BSerializeToMsg() called on for unimplementing ICondition!" ); return false; }
};
bool BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired );
bool BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired );
bool BAddCondition( ICondition *pCondition );
int GetConditionsCount() { return m_vecConditions.Count(); }
const char *GetValueForFirstConditionOfType( EItemCriteriaOperator eType ) const;
const char *GetFieldForFirstConditionOfType( EItemCriteriaOperator eType ) const;
// Alternate ways of initializing
bool BInitFromKV( KeyValues *pKVCriteria );
// Serializes the criteria to and from messages
bool BSerializeToMsg( CSOItemCriteria & msg ) const;
bool BDeserializeFromMsg( const CSOItemCriteria & msg );
// Evaluates an item definition against this criteria. Returns true if
// the definition passes the filter
bool BEvaluate( const CEconItemDefinition* pItemDef ) const;
// Validation
#ifdef DBGFLAG_VALIDATE
void Validate( CValidator &validator, const char *pchName );
#endif
private:
//-----------------------------------------------------------------------------
// CItemSelectionCriteria::CCondition
// Represents one condition of the criteria
//-----------------------------------------------------------------------------
class CCondition : public ICondition
{
public:
CCondition( const char *pszField, EItemCriteriaOperator eOp, bool bRequired )
: m_sField( pszField ), m_EOp( eOp ), m_bRequired( bRequired )
{
}
// ICondition interface.
virtual bool BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const OVERRIDE;
// Serializes the condition to the message
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
// Validation
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName );
#endif
EItemCriteriaOperator GetEOp( void ) const OVERRIDE { return m_EOp; }
virtual const char *GetField( void ) const OVERRIDE { return m_sField.Get(); }
virtual const char *GetValue( void ) const OVERRIDE { Assert(0); return NULL; }
private:
// Returns if the given KeyValues block passes this condition
// Performs common checks and calls BInternalEvaluate
bool BEvaluate( KeyValues *pKVItem ) const;
protected:
// Returns true if applying the element's operator on m_sField of
// pKVItem returns true. This is only called if m_pszField exists in pKVItem
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const = 0;
// The field of the raw KeyValue form of the item definition to check
CUtlString m_sField;
// The operator this clause uses
EItemCriteriaOperator m_EOp;
// When true, BEvaluate returns false if m_sField does not exist in pKVItem
bool m_bRequired;
};
//-----------------------------------------------------------------------------
// CItemSelectionCriteria::CStringCondition
// CCondition that handles the string-based operators
//-----------------------------------------------------------------------------
class CStringCondition : public CCondition
{
public:
CStringCondition( const char *pszField, EItemCriteriaOperator eOp, const char *pszValue, bool bRequired )
: CCondition( pszField, eOp, bRequired ), m_sValue( pszValue )
{
}
virtual ~CStringCondition( ) { }
virtual const char *GetValue( void ) const OVERRIDE { return m_sValue.Get(); }
// Validation
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName );
#endif
protected:
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
// The value to check against
CUtlString m_sValue;
};
//-----------------------------------------------------------------------------
// CItemSelectionCriteria::CFloatCondition
// CCondition that handles the float-based operators
//-----------------------------------------------------------------------------
class CFloatCondition : public CCondition
{
public:
CFloatCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
: CCondition( pszField, eOp, bRequired ), m_flValue( flValue )
{
}
virtual ~CFloatCondition( ) { }
protected:
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
// The value to check against
float m_flValue;
};
//-----------------------------------------------------------------------------
// CItemSelectionCriteria::CSetCondition
// CCondition that handles subkey checks
//-----------------------------------------------------------------------------
class CSetCondition : public CCondition
{
public:
CSetCondition( const char *pszField, EItemCriteriaOperator eOp, const char *pszValue, bool bRequired )
: CCondition( pszField, eOp, bRequired ), m_sValue( pszValue )
{
}
virtual ~CSetCondition( ) { }
// Validation
#ifdef DBGFLAG_VALIDATE
virtual void Validate( CValidator &validator, const char *pchName );
#endif
protected:
virtual bool BInternalEvaluate( KeyValues *pKVItem ) const;
virtual bool BSerializeToMsg( CSOItemCriteriaCondition & msg ) const;
// The subkey to look for
CUtlString m_sValue;
};
// True if item level is specified in this criteria
bool m_bItemLevelSet;
// The level of the item to generate
uint32 m_unItemLevel;
// True if quality is specified in this criteria
bool m_bQualitySet;
// The quality of the item to generate
int32 m_nItemQuality;
// The initial inventory token of the item
uint32 m_unInitialInventory;
// True if initial quantity is specified in this criteria.
bool m_bInitialQuantitySet;
// The initial quantity of the item
uint32 m_unInitialQuantity;
// Enforced explicit quality matching
bool m_bForcedQualityMatch;
// Ignoring enabled flag (used when crafting)
bool m_bIgnoreEnabledFlag;
// A list of tags
CUtlString m_strTags;
CUtlVector<econ_tag_handle_t> m_vecTags;
// A list of the conditions
CUtlVector<ICondition *> m_vecConditions;
};
#endif //ITEM_SELECTION_CRITERIA_H
+199
View File
@@ -0,0 +1,199 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "cbase.h"
#include "localization_provider.h"
enum { kScratchBufferSize = 1024 };
// ----------------------------------------------------------------------------
// Find a localized string, but return something safe if the key is null or the localized
// string is missing.
// ----------------------------------------------------------------------------
locchar_t* CLocalizationProvider::FindSafe( const char* pchKey ) const
{
if ( pchKey )
{
locchar_t* wszLocalized = Find( pchKey );
if ( !wszLocalized )
{
#ifdef STAGING_ONLY
return const_cast< locchar_t* >(LOCCHAR("<NULL LOC STRING>")); // Super janky cast alert! This method should really return a const locchar_t* but making that change breaks all the callsites...fix later.
#else
return const_cast<locchar_t*>(LOCCHAR(""));
#endif
}
else
{
return wszLocalized;
}
}
else
{
#ifdef STAGING_ONLY
return const_cast<locchar_t*>(LOCCHAR("<NULL LOC KEY>"));
#else
return const_cast<locchar_t*>(LOCCHAR(""));
#endif
}
}
#ifdef GC
#include "gcsdk/gcbase.h"
// GC Localization implementation
static CGCLocalizationProvider *GGCLocalizationProvider()
{
static CGCLocalizationProvider *g_pGCLocalizationProvider = NULL;
if ( !g_pGCLocalizationProvider )
g_pGCLocalizationProvider = new CGCLocalizationProvider( GGCGameBase() );
return g_pGCLocalizationProvider;
}
CLocalizationProvider *GLocalizationProvider()
{
AssertMsg( false, "Using global localization provider in GC - All strings will be in English. For proper localization, CLocalizationProvider instance should be created and passed in." );
return GGCLocalizationProvider();
}
locchar_t *CGCLocalizationProvider::Find( const char *pchKey ) const
{
// we emulate VGUI's behavior of returning an empty string for keys that are not found
return (locchar_t*)m_pGC->LocalizeToken( pchKey, m_eLang, false );
}
bool CGCLocalizationProvider::BEnsureCleanUTF8Truncation( char *unicodeOutput )
{
int nStringLength = V_strlen( unicodeOutput );
// make sure we're not in the middle of a multibyte character
int iPos = nStringLength - 1;
char c = unicodeOutput[iPos];
if ( (c & 0x80) != 0 )
{
// not an ascii char, so do some multibyte char checking
int cBytes = 0;
// count up all continuation bytes
while ( (c & 0xC0) == 0x80 && iPos > 0 ) // first two bits are 10xxxx, continuation
{
cBytes++;
c = unicodeOutput[--iPos];
}
// make sure we had the expected number of continuation bytes for the last
// multibyte lead character
bool bTruncateOK = true;
if ( ( c & 0xF8 ) == 0xF0 ) // first 5 bits are 11110, should be 3 following bytes
bTruncateOK = ( cBytes == 3 );
else if ( ( c & 0xF0 ) == 0xE0 ) // first 4 bits are 1110, should be 2 following bytes
bTruncateOK = ( cBytes == 2 );
else if ( ( c & 0xE0 ) == 0xC0 ) // first 3 bits are 110, should be 1 following byte
bTruncateOK = ( cBytes == 1 );
// if we truncated in the middle of a multi-byte char, move the end point back to this character
if ( !bTruncateOK )
unicodeOutput[iPos] = '\0';
return !bTruncateOK;
}
return false;
}
void CGCLocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc_In, CUtlConstString *out_ansi ) const
{
*out_ansi = loc_In;
}
void CGCLocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const
{
wchar_t utf16_Scratch[kScratchBufferSize];
V_UTF8ToUnicode( loc_In, utf16_Scratch, kScratchBufferSize );
*out_unicode = utf16_Scratch;
}
void CGCLocalizationProvider::ConvertUTF8ToLocchar( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const
{
*out_loc = utf8_In;
}
int CGCLocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const
{
Q_strncpy( ansi, loc, ansiBufferSize );
return 0;
}
int CGCLocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const
{
return V_UTF8ToUnicode( loc, unicode, unicodeBufferSize );
}
void CGCLocalizationProvider::ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const
{
Q_strncpy( locchar, utf8, loccharBufferSize );
}
#else
CLocalizationProvider *GLocalizationProvider()
{
static CVGUILocalizationProvider g_VGUILocalizationProvider;
return &g_VGUILocalizationProvider;
}
// vgui localization implementation
CVGUILocalizationProvider::CVGUILocalizationProvider()
{
}
locchar_t *CVGUILocalizationProvider::Find( const char *pchKey ) const
{
return (locchar_t*)g_pVGuiLocalize->Find( pchKey );
}
void CVGUILocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc_In, CUtlConstString *out_ansi ) const
{
char ansi_Scratch[kScratchBufferSize];
g_pVGuiLocalize->ConvertUnicodeToANSI( loc_In, ansi_Scratch, kScratchBufferSize );
*out_ansi = ansi_Scratch;
}
void CVGUILocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const
{
*out_unicode = loc_In;
}
void CVGUILocalizationProvider::ConvertUTF8ToLocchar( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const
{
locchar_t loc_Scratch[kScratchBufferSize];
V_UTF8ToUnicode( utf8_In, loc_Scratch, kScratchBufferSize );
*out_loc = loc_Scratch;
}
void CVGUILocalizationProvider::ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const
{
V_UTF8ToUnicode( utf8, locchar, loccharBufferSize );
}
int CVGUILocalizationProvider::ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const
{
return g_pVGuiLocalize->ConvertUnicodeToANSI( loc, ansi, ansiBufferSize );
}
int CVGUILocalizationProvider::ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const
{
Q_wcsncpy( unicode, loc, unicodeBufferSize );
return 0;
}
#endif
+103
View File
@@ -0,0 +1,103 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: provide a layer of abstraction between GC and vgui localization systems
//
//=============================================================================
#ifndef LOCALIZATION_PROVIDER_H
#define LOCALIZATION_PROVIDER_H
#ifdef _WIN32
#pragma once
#endif
#include "language.h"
#include "ilocalize.h"
// interface matches a subset of VGUI functions
class CLocalizationProvider
{
public:
virtual locchar_t *Find( const char *pchKey ) const = 0;
locchar_t* FindSafe( const char* pchKey ) const;
// new interface
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const = 0;
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const = 0;
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const = 0;
// old C-style interface
virtual int ConvertLoccharToANSI( const locchar_t *loc, OUT_Z_BYTECAP(ansiBufferSize) char *ansi, int ansiBufferSize ) const = 0;
virtual int ConvertLoccharToUnicode( const locchar_t *loc, OUT_Z_BYTECAP(unicodeBufferSize) wchar_t *unicode, int unicodeBufferSize ) const = 0;
virtual void ConvertUTF8ToLocchar( const char *utf8, OUT_Z_BYTECAP(loccharBufferSize) locchar_t *locchar, int loccharBufferSize ) const = 0;
virtual ELanguage GetELang() const = 0;
};
CLocalizationProvider *GLocalizationProvider();
#ifdef GC
// GC localization is handled by the GC itself
class CGCLocalizationProvider : public CLocalizationProvider
{
public:
CGCLocalizationProvider( CGCGameBase *pGC, ELanguage eLang = k_Lang_English )
{
m_pGC = pGC;
m_eLang = eLang;
}
static bool BEnsureCleanUTF8Truncation( char *unicodeOutput );
virtual locchar_t *Find( const char *pchKey ) const;
// new interface
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const;
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const;
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const;
// old C-style interface
virtual int ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const;
virtual int ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const;
virtual void ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const;
virtual ELanguage GetELang() const { return m_eLang; }
private:
CGCGameBase *m_pGC;
ELanguage m_eLang;
};
#else
#include "vgui/ILocalize.h"
extern vgui::ILocalize *g_pVGuiLocalize;
// Game localization is handled by vgui
class CVGUILocalizationProvider : public CLocalizationProvider
{
public:
CVGUILocalizationProvider();
virtual locchar_t *Find( const char *pchKey ) const;
// new interface
virtual void ConvertLoccharToANSI ( const locchar_t *loc_In, CUtlConstString *out_ansi ) const;
virtual void ConvertLoccharToUnicode( const locchar_t *loc_In, CUtlConstWideString *out_unicode ) const;
virtual void ConvertUTF8ToLocchar ( const char *utf8_In, CUtlConstStringBase<locchar_t> *out_loc ) const;
// old C-style interface
virtual int ConvertLoccharToANSI( const locchar_t *loc, char *ansi, int ansiBufferSize ) const;
virtual int ConvertLoccharToUnicode( const locchar_t *loc, wchar_t *unicode, int unicodeBufferSize ) const;
virtual void ConvertUTF8ToLocchar( const char *utf8, locchar_t *locchar, int loccharBufferSize ) const;
virtual ELanguage GetELang() const { return k_Lang_None; }
};
#endif
#endif // LOCALIZATION_PROVIDER_H