Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1401 lines
48 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: CEconItem, a shared object for econ items
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_item.h"
  8. #include "econ_item_schema.h"
  9. #include "smartptr.h"
  10. #ifdef CSTRIKE15
  11. #include "cstrike15_gcmessages.pb.h"
  12. #endif
  13. #define ECON_ITEM_SET_NOT_YET_SCANNED 0xFFu
  14. #define ECON_ITEM_SET_INVALID 0xFEu
  15. using namespace GCSDK;
  16. #ifdef CLIENT_DLL
  17. #include "bannedwords.h"
  18. #endif
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. /*static*/ const schema_attribute_stat_bucket_t *CSchemaAttributeStats::m_pHead;
  22. #ifndef GC_DLL
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Utility function to match two items based on their item views
  25. //-----------------------------------------------------------------------------
  26. bool ItemsMatch( CEconItemView *pCurItem, CEconItemView *pNewItem )
  27. {
  28. if ( !pNewItem || !pNewItem->IsValid() || !pCurItem || !pCurItem->IsValid() )
  29. return false;
  30. // If we already have an item in this slot but is not the same type, nuke it (changed classes)
  31. // We don't need to do this for non-base items because they've already been verified above.
  32. bool bHasNonBase = pNewItem ? pNewItem->GetItemQuality() != AE_NORMAL : false;
  33. if ( bHasNonBase )
  34. {
  35. // If the item isn't the one we're supposed to have, nuke it
  36. if ( pCurItem->GetItemID() != pNewItem->GetItemID() || pCurItem->GetItemID() == 0 || pNewItem->GetItemID() == 0 )
  37. {
  38. /*
  39. Msg("Removing %s because its global index (%d) doesn't match the loadout's (%d)\n", p->GetDebugName(),
  40. pCurItem->GetItemID(),
  41. pNewItem->GetItemID() );
  42. */
  43. return false;
  44. }
  45. }
  46. else
  47. {
  48. if ( pCurItem->GetItemQuality() != AE_NORMAL || (pCurItem->GetItemIndex() != pNewItem->GetItemIndex()) )
  49. {
  50. //Msg("Removing %s because it's not the right type for the class.\n", p->GetDebugName() );
  51. return false;
  52. }
  53. }
  54. return true;
  55. }
  56. #endif
  57. //-----------------------------------------------------------------------------
  58. // Purpose: Utility function to convert datafile strings to ints.
  59. //-----------------------------------------------------------------------------
  60. int StringFieldToInt( const char *szValue, const char **pValueStrings, int iNumStrings, bool bDontAssert )
  61. {
  62. if ( !szValue || !szValue[0] )
  63. return -1;
  64. for ( int i = 0; i < iNumStrings; i++ )
  65. {
  66. if ( !Q_stricmp(szValue, pValueStrings[i]) )
  67. return i;
  68. }
  69. if ( !bDontAssert )
  70. {
  71. Assert( !"Missing value in StringFieldToInt()!" );
  72. }
  73. return -1;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Utility function to convert datafile strings to ints.
  77. //-----------------------------------------------------------------------------
  78. int StringFieldToInt( const char *szValue, const CUtlVector<const char *>& vecValueStrings, bool bDontAssert )
  79. {
  80. return StringFieldToInt( szValue, (const char **)&vecValueStrings[0], vecValueStrings.Count(), bDontAssert );
  81. }
  82. //////////////////////////////////////////////////////////////////////////
  83. //
  84. // Implementation of CS:GO optimized custom data object
  85. //
  86. static inline uint32 ComputeEconItemCustomDataOptimizedObjectAllocationSize( uint32 numAttributes )
  87. {
  88. uint32 numBytesNeeded = sizeof( CEconItem::CustomDataOptimizedObject_t ) + numAttributes*sizeof( CEconItem::attribute_t );
  89. // Since we know that attributes are allocated in SBH we can allocate more memory then needed to allow
  90. // for less memory copying when growing the container -
  91. if ( sizeof( CEconItem::attribute_t ) < 8 )
  92. numBytesNeeded = ( ( numBytesNeeded <= 128 ) ? ( ( numBytesNeeded + 7 ) / 8 ) * 8 : ( ( numBytesNeeded + 31 ) / 32 ) * 32 ); // round up to SBH boundaries
  93. return numBytesNeeded;
  94. }
  95. void HelperDumpMemStatsEconItemAttributes() {}
  96. bool Helper_IsSticker( const CEconItemDefinition * pEconItemDefinition )
  97. {
  98. static CSchemaItemDefHandle hItemDefCompare( "sticker" );
  99. return pEconItemDefinition && hItemDefCompare && pEconItemDefinition->IsTool() && ( pEconItemDefinition->GetDefinitionIndex() == hItemDefCompare->GetDefinitionIndex() );
  100. }
  101. bool Helper_IsSpray( const CEconItemDefinition * pEconItemDefinition )
  102. {
  103. static CSchemaItemDefHandle hItemDefCompare( "spray" );
  104. static CSchemaItemDefHandle hItemDefCompare2( "spraypaint" );
  105. return pEconItemDefinition && pEconItemDefinition->IsTool() && (
  106. ( hItemDefCompare && ( pEconItemDefinition->GetDefinitionIndex() == hItemDefCompare->GetDefinitionIndex() ) )
  107. || ( hItemDefCompare2 && ( pEconItemDefinition->GetDefinitionIndex() == hItemDefCompare2->GetDefinitionIndex() ) )
  108. )
  109. ;
  110. }
  111. bool Helper_IsGraphicTool( const CEconItemDefinition * pEconItemDefinition )
  112. {
  113. return Helper_IsSticker( pEconItemDefinition ) || Helper_IsSpray( pEconItemDefinition );
  114. }
  115. CEconItem::CustomDataOptimizedObject_t * CEconItem::CustomDataOptimizedObject_t::Alloc( uint32 numAttributes )
  116. {
  117. uint32 numBytesNeeded = ComputeEconItemCustomDataOptimizedObjectAllocationSize( numAttributes );
  118. CEconItem::CustomDataOptimizedObject_t *ptr = reinterpret_cast< CEconItem::CustomDataOptimizedObject_t * >( malloc( numBytesNeeded ) );
  119. ptr->m_equipInstanceSlot1 = INVALID_EQUIPPED_SLOT_BITPACKED;
  120. ptr->m_numAttributes = numAttributes;
  121. return ptr;
  122. }
  123. CEconItem::attribute_t * CEconItem::CustomDataOptimizedObject_t::AddAttribute( CustomDataOptimizedObject_t * &rptr )
  124. {
  125. uint32 numAttributesOld = rptr->m_numAttributes;
  126. uint32 numBytesOldAllocated = ComputeEconItemCustomDataOptimizedObjectAllocationSize( numAttributesOld );
  127. uint32 numBytesNeededNew = ComputeEconItemCustomDataOptimizedObjectAllocationSize( numAttributesOld + 1 );
  128. if ( numBytesNeededNew > numBytesOldAllocated )
  129. {
  130. CEconItem::CustomDataOptimizedObject_t *ptr = CEconItem::CustomDataOptimizedObject_t::Alloc( numAttributesOld + 1 );
  131. Q_memcpy( ptr, rptr, sizeof( CEconItem::CustomDataOptimizedObject_t ) + rptr->m_numAttributes*sizeof( CEconItem::attribute_t ) );
  132. free( rptr );
  133. rptr = ptr;
  134. }
  135. rptr->m_numAttributes = numAttributesOld + 1;
  136. return rptr->GetAttribute( numAttributesOld );
  137. }
  138. void CEconItem::CustomDataOptimizedObject_t::RemoveAndFreeAttrMemory( uint32 idxAttributeInArray )
  139. {
  140. Assert( m_numAttributes );
  141. Assert( idxAttributeInArray < m_numAttributes );
  142. attribute_t *pAttr = GetAttribute( idxAttributeInArray );
  143. CEconItem::FreeAttributeMemory( pAttr );
  144. uint32 idxLastAttribute = m_numAttributes - 1;
  145. if ( idxAttributeInArray != idxLastAttribute )
  146. {
  147. Q_memcpy( pAttr, GetAttribute( idxLastAttribute ), sizeof( CEconItem::attribute_t ) );
  148. }
  149. m_numAttributes = idxLastAttribute;
  150. }
  151. void CEconItem::CustomDataOptimizedObject_t::FreeObjectAndAttrMemory()
  152. {
  153. CEconItem::attribute_t *pAttr = reinterpret_cast< CEconItem::attribute_t * >( this + 1 );
  154. CEconItem::attribute_t *pAttrEnd = pAttr + m_numAttributes;
  155. for ( ; pAttr < pAttrEnd; ++ pAttr )
  156. {
  157. CEconItem::FreeAttributeMemory( pAttr );
  158. }
  159. free( this );
  160. }
  161. // --------------------------------------------------------------------------
  162. // Purpose:
  163. // --------------------------------------------------------------------------
  164. CEconItem::CEconItem()
  165. : BaseClass( ),
  166. m_pCustomDataOptimizedObject( NULL )
  167. {
  168. m_ulID = 0;
  169. m_ulOriginalID = 0;
  170. m_iItemSet = ECON_ITEM_SET_NOT_YET_SCANNED;
  171. #ifndef GC_DLL
  172. m_bSOUpdateFrame = -1;
  173. #endif
  174. m_unAccountID = 0;
  175. m_unInventory = 0;
  176. m_unLevel = 0;
  177. m_nQuality = 0;
  178. m_unOrigin = 0;
  179. m_nRarity = 0;
  180. m_unFlags = 0;
  181. m_dirtybitInUse = 0;
  182. }
  183. // --------------------------------------------------------------------------
  184. // Purpose:
  185. // --------------------------------------------------------------------------
  186. CEconItem::~CEconItem()
  187. {
  188. if ( m_pCustomDataOptimizedObject )
  189. m_pCustomDataOptimizedObject->FreeObjectAndAttrMemory();
  190. }
  191. // --------------------------------------------------------------------------
  192. // Purpose:
  193. // --------------------------------------------------------------------------
  194. void CEconItem::CopyAttributesFrom( const CEconItem& source )
  195. {
  196. // Copy attributes -- each new instance needs to be allocated and then copied into by somewhere
  197. // that knows what the actual type is. Rather than do anything type-specific here, we just have each
  198. // attribute serialize it's value to a bytestream and then deserialize it. This is as safe as we can
  199. // make it but sort of silly wasteful.
  200. for ( int i = 0; i < source.GetDynamicAttributeCountInternal(); i++ )
  201. {
  202. attribute_t const &attr = source.GetDynamicAttributeInternal( i );
  203. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( attr.m_unDefinitionIndex );
  204. Assert( pAttrDef );
  205. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  206. Assert( pAttrType );
  207. std::string sBytes;
  208. pAttrType->ConvertEconAttributeValueToByteStream( attr.m_value, &sBytes );
  209. pAttrType->LoadByteStreamToEconAttributeValue( this, pAttrDef, sBytes );
  210. }
  211. }
  212. void CEconItem::CopyWithoutAttributesFrom( const CEconItem& rhs )
  213. {
  214. // We do destructive operations on our local object, including freeing attribute memory, as part of
  215. // the copy, so we force self-copies to be a no-op.
  216. if ( &rhs == this )
  217. {
  218. Assert( false ); // this probably not what you want!! This will not wipe attributes on the item.
  219. return;
  220. }
  221. m_ulID = rhs.m_ulID;
  222. SetOriginalID( rhs.GetOriginalID() );
  223. m_unAccountID = rhs.m_unAccountID;
  224. m_unDefIndex = rhs.m_unDefIndex;
  225. m_unLevel = rhs.m_unLevel;
  226. m_nQuality = rhs.m_nQuality;
  227. m_nRarity = rhs.m_nRarity;
  228. m_unInventory = rhs.m_unInventory;
  229. SetQuantity( rhs.GetQuantity() );
  230. m_unFlags = rhs.m_unFlags;
  231. m_unOrigin = rhs.m_unOrigin;
  232. m_dirtybitInUse = rhs.m_dirtybitInUse;
  233. m_iItemSet = rhs.m_iItemSet;
  234. if ( m_pCustomDataOptimizedObject )
  235. {
  236. m_pCustomDataOptimizedObject->FreeObjectAndAttrMemory();
  237. m_pCustomDataOptimizedObject = NULL;
  238. }
  239. }
  240. // --------------------------------------------------------------------------
  241. // Purpose:
  242. // --------------------------------------------------------------------------
  243. CEconItem &CEconItem::operator=( const CEconItem& rhs )
  244. {
  245. // We do destructive operations on our local object, including freeing attribute memory, as part of
  246. // the copy, so we force self-copies to be a no-op.
  247. if ( &rhs == this )
  248. return *this;
  249. // Copy all plain data
  250. CopyWithoutAttributesFrom( rhs );
  251. //
  252. // see -- CopyAttributesFrom( rhs );
  253. //
  254. // copied for more efficient memory management
  255. //
  256. if ( rhs.m_pCustomDataOptimizedObject && rhs.m_pCustomDataOptimizedObject->m_numAttributes )
  257. {
  258. uint32 numAttributes = rhs.m_pCustomDataOptimizedObject->m_numAttributes;
  259. m_pCustomDataOptimizedObject = CustomDataOptimizedObject_t::Alloc( numAttributes );
  260. for ( uint32 i = 0; i < numAttributes; ++ i )
  261. {
  262. attribute_t const &attr = * rhs.m_pCustomDataOptimizedObject->GetAttribute( i );
  263. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( attr.m_unDefinitionIndex );
  264. Assert( pAttrDef );
  265. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  266. Assert( pAttrType );
  267. std::string sBytes;
  268. pAttrType->ConvertEconAttributeValueToByteStream( attr.m_value, &sBytes );
  269. // Make an efficient copy of the attribute at the end of the array
  270. attribute_t *pEconAttribCopy = m_pCustomDataOptimizedObject->GetAttribute( i );
  271. pEconAttribCopy->m_unDefinitionIndex = pAttrDef->GetDefinitionIndex();
  272. pAttrType->InitializeNewEconAttributeValue( &pEconAttribCopy->m_value );
  273. pAttrType->LoadByteStreamToEconAttributeValue( this, pAttrDef, sBytes );
  274. }
  275. }
  276. // Transfer equip state as well
  277. if ( rhs.m_pCustomDataOptimizedObject )
  278. {
  279. // Attributes transfer can allocate optimized custom data, but if we had no attributes then allocate it here
  280. if ( !m_pCustomDataOptimizedObject )
  281. m_pCustomDataOptimizedObject = CustomDataOptimizedObject_t::Alloc( 0 );
  282. // Transfer equip state values as well
  283. m_pCustomDataOptimizedObject->m_equipInstanceSlot1 = rhs.m_pCustomDataOptimizedObject->m_equipInstanceSlot1;
  284. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = rhs.m_pCustomDataOptimizedObject->m_equipInstanceClass1;
  285. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = rhs.m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit;
  286. }
  287. return *this;
  288. }
  289. // --------------------------------------------------------------------------
  290. // Purpose:
  291. // --------------------------------------------------------------------------
  292. void CEconItem::SetItemID( itemid_t ulID )
  293. {
  294. uint64 ulOldID = m_ulID;
  295. m_ulID = ulID;
  296. // only overwrite if we don't have an original id currently and we are a new item cloned off an old item
  297. if ( ulOldID != 0 && ulOldID != ulID && m_ulOriginalID == 0 && ulID != INVALID_ITEM_ID && ulOldID != INVALID_ITEM_ID )
  298. {
  299. SetOriginalID( ulOldID );
  300. }
  301. }
  302. // --------------------------------------------------------------------------
  303. // Purpose:
  304. // --------------------------------------------------------------------------
  305. itemid_t CEconItem::GetOriginalID() const
  306. {
  307. return m_ulOriginalID ? m_ulOriginalID : m_ulID;
  308. }
  309. // --------------------------------------------------------------------------
  310. // Purpose:
  311. // --------------------------------------------------------------------------
  312. void CEconItem::SetOriginalID( itemid_t ulOriginalID )
  313. {
  314. if ( ulOriginalID != m_ulID )
  315. m_ulOriginalID = ulOriginalID;
  316. }
  317. int32 CEconItem::GetRarity() const
  318. {
  319. int nDefRarity = GetItemDefinition() ? GetItemDefinition()->GetRarity() : 1;
  320. bool bIsTool = GetItemDefinition() ? GetItemDefinition()->IsTool() : false;
  321. const CEconItemRarityDefinition *pImmortal = GetItemSchema()->GetRarityDefinitionByName( "immortal" );
  322. if ( nDefRarity == pImmortal->GetDBValue() )
  323. {
  324. // Items that had their definition marked as immortal just use that!
  325. return nDefRarity;
  326. }
  327. // Check if the item has its rarity set in the database
  328. if ( m_nRarity != k_unItemRarity_Any )
  329. {
  330. // HACK: The default value for rarity used to be 0 and some coins and passes were created that way,
  331. // but since their rarity should have been k_unItemRarity_Any they actually need to fall back to the definition rarity
  332. if ( !( m_nRarity == 0 && ( nDefRarity >= 6 || bIsTool ) ) )
  333. {
  334. return m_nRarity;
  335. }
  336. }
  337. return nDefRarity;
  338. }
  339. // --------------------------------------------------------------------------
  340. // Purpose:
  341. // --------------------------------------------------------------------------
  342. uint16 CEconItem::GetQuantity() const
  343. {
  344. return 1;
  345. }
  346. // --------------------------------------------------------------------------
  347. // Purpose:
  348. // --------------------------------------------------------------------------
  349. void CEconItem::SetQuantity( uint16 unQuantity )
  350. {
  351. Assert( unQuantity <= 1 );
  352. }
  353. // --------------------------------------------------------------------------
  354. // Purpose:
  355. // --------------------------------------------------------------------------
  356. void CEconItem::InitAttributesDroppedFromListEntry( item_list_entry_t const *pEntryInfo )
  357. {
  358. const CEconItemDefinition *pItemDef = GetItemDefinition();
  359. // Set the paint kit
  360. if ( pEntryInfo )
  361. {
  362. extern bool Helper_IsGraphicTool( const CEconItemDefinition * pEconItemDefinition );
  363. if ( pEntryInfo->m_nStickerKit && pItemDef && Helper_IsGraphicTool( pItemDef ) )
  364. {
  365. const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinition( pEntryInfo->m_nStickerKit );
  366. if ( pStickerKit )
  367. {
  368. static CSchemaAttributeDefHandle pAttr_StickerKit( "sticker slot 0 id" );
  369. if ( pAttr_StickerKit )
  370. {
  371. SetDynamicAttributeValue( pAttr_StickerKit, pEntryInfo->m_nStickerKit );
  372. }
  373. SetRarity( EconRarity_CombinedItemAndPaintRarity( pItemDef->GetRarity(), pStickerKit->nRarity ) );
  374. }
  375. }
  376. else if ( pEntryInfo->m_nPaintKit )
  377. {
  378. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinition( pEntryInfo->m_nPaintKit );
  379. if ( pPaintKit )
  380. {
  381. static CSchemaAttributeDefHandle pAttr_PaintKit( "set item texture prefab" );
  382. if ( pAttr_PaintKit )
  383. {
  384. AddOrSetCustomAttribute( pAttr_PaintKit->GetDefinitionIndex(), pEntryInfo->m_nPaintKit );
  385. }
  386. static CSchemaAttributeDefHandle pAttr_PaintKitSeed( "set item texture seed" );
  387. if ( pAttr_PaintKitSeed && ( pEntryInfo->m_nPaintKitSeed >= -1 ) )
  388. {
  389. int nSeed = pEntryInfo->m_nPaintKitSeed;
  390. if ( nSeed < 0 )
  391. {
  392. nSeed = RandomInt( 0, 1000 );
  393. }
  394. AddOrSetCustomAttribute( pAttr_PaintKitSeed->GetDefinitionIndex(), nSeed );
  395. }
  396. static CSchemaAttributeDefHandle pAttr_PaintKitWear( "set item texture wear" );
  397. if ( pAttr_PaintKitWear && ( pEntryInfo->m_flPaintKitWear >= -1.1 ) )
  398. {
  399. float flWear = pEntryInfo->m_flPaintKitWear;
  400. if ( flWear < 0 )
  401. {
  402. flWear = RandomFloat();
  403. }
  404. AddOrSetCustomAttribute( pAttr_PaintKitWear->GetDefinitionIndex(),
  405. RemapValClamped( flWear, 0.0f, 1.0f, pPaintKit->flWearRemapMin, pPaintKit->flWearRemapMax ) );
  406. }
  407. SetRarity( EconRarity_CombinedItemAndPaintRarity( GetItemDefinition()->GetRarity(), pPaintKit->nRarity ) );
  408. }
  409. }
  410. else if ( pEntryInfo->m_nMusicKit )
  411. {
  412. const CEconMusicDefinition *pMusicDef = GetItemSchema()->GetMusicDefinition( pEntryInfo->m_nMusicKit );
  413. if ( pMusicDef )
  414. {
  415. static CSchemaAttributeDefHandle pAttr_Music( "music id" );
  416. if ( pAttr_Music )
  417. {
  418. SetDynamicAttributeValue( pAttr_Music, pEntryInfo->m_nMusicKit );
  419. }
  420. }
  421. }
  422. }
  423. if ( pItemDef )
  424. {
  425. int nDefaultDropQuality = pItemDef->GetDefaultDropQuality();
  426. if ( nDefaultDropQuality != k_unItemQuality_Any )
  427. {
  428. SetQuality( nDefaultDropQuality );
  429. }
  430. }
  431. }
  432. // --------------------------------------------------------------------------
  433. // Purpose:
  434. // --------------------------------------------------------------------------
  435. static const char *GetCustomNameOrAttributeDesc( const CEconItem *pItem, const CEconItemAttributeDefinition *pAttrDef )
  436. {
  437. if ( !pAttrDef )
  438. {
  439. // If we didn't specify the attribute in the schema we can't possibly have an
  440. // answer. This isn't really an error in that case.
  441. return NULL;
  442. }
  443. const char *pszStrContents;
  444. if ( FindAttribute_UnsafeBitwiseCast<CAttribute_String>( pItem, pAttrDef, &pszStrContents ) )
  445. {
  446. #ifdef CLIENT_DLL
  447. if ( pszStrContents && *pszStrContents )
  448. g_BannedWords.CensorBannedWordsInplace( const_cast< char * >( pszStrContents ) );
  449. #endif
  450. return pszStrContents;
  451. }
  452. return NULL;
  453. }
  454. // --------------------------------------------------------------------------
  455. // Purpose:
  456. // --------------------------------------------------------------------------
  457. static void SetCustomNameOrDescAttribute( CEconItem *pItem, const CEconItemAttributeDefinition *pAttrDef, const char *pszNewValue )
  458. {
  459. Assert( pItem );
  460. if ( !pAttrDef )
  461. {
  462. // If we didn't specify the attribute in the schema, that's fine if we're setting
  463. // the empty name/description string, but it isn't fine if we're trying to set
  464. // actual content.
  465. AssertMsg( !pszNewValue, "Attempt to set non-empty value for custom name/desc with no attribute present." );
  466. return;
  467. }
  468. // Removing existing value?
  469. if ( !pszNewValue || !pszNewValue[0] )
  470. {
  471. pItem->RemoveDynamicAttribute( pAttrDef );
  472. return;
  473. }
  474. CAttribute_String attrStr;
  475. attrStr.set_value( pszNewValue );
  476. pItem->SetDynamicAttributeValue( pAttrDef, attrStr );
  477. }
  478. // --------------------------------------------------------------------------
  479. // Purpose:
  480. // --------------------------------------------------------------------------
  481. const char *CEconItem::GetCustomName() const
  482. {
  483. static CSchemaAttributeDefHandle pAttrDef_CustomName( "custom name attr" );
  484. return GetCustomNameOrAttributeDesc( this, pAttrDef_CustomName );
  485. }
  486. // --------------------------------------------------------------------------
  487. // Purpose:
  488. // --------------------------------------------------------------------------
  489. void CEconItem::SetCustomName( const char *pName )
  490. {
  491. static CSchemaAttributeDefHandle pAttrDef_CustomName( "custom name attr" );
  492. SetCustomNameOrDescAttribute( this, pAttrDef_CustomName, pName );
  493. }
  494. // --------------------------------------------------------------------------
  495. // Purpose:
  496. // --------------------------------------------------------------------------
  497. bool CEconItem::IsEquipped() const
  498. {
  499. return m_pCustomDataOptimizedObject && ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED );
  500. }
  501. // --------------------------------------------------------------------------
  502. // Purpose:
  503. // --------------------------------------------------------------------------
  504. bool CEconItem::IsEquippedForClass( equipped_class_t unClass ) const
  505. {
  506. return m_pCustomDataOptimizedObject && ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED ) &&
  507. ( // CS:GO optimized test - equip class is 0 or 2/3
  508. ( unClass == m_pCustomDataOptimizedObject->m_equipInstanceClass1 ) ||
  509. ( ( unClass == 3 ) && ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 2 ) && ( m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit != 0 ) )
  510. );
  511. }
  512. // --------------------------------------------------------------------------
  513. // Purpose:
  514. // --------------------------------------------------------------------------
  515. equipped_slot_t CEconItem::GetEquippedPositionForClass( equipped_class_t unClass ) const
  516. {
  517. return IsEquippedForClass( unClass ) ? m_pCustomDataOptimizedObject->m_equipInstanceSlot1 : INVALID_EQUIPPED_SLOT;
  518. }
  519. // --------------------------------------------------------------------------
  520. // Purpose:
  521. // --------------------------------------------------------------------------
  522. void CEconItem::UpdateEquippedState( EquippedInstance_t equipInstance )
  523. {
  524. // If it's invalid we need to remove it
  525. if ( equipInstance.m_unEquippedSlot == INVALID_EQUIPPED_SLOT )
  526. {
  527. if ( m_pCustomDataOptimizedObject && ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED ) )
  528. {
  529. if ( equipInstance.m_unEquippedClass == m_pCustomDataOptimizedObject->m_equipInstanceClass1 )
  530. {
  531. if ( m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit )
  532. {
  533. // Move the 2nd class down
  534. if ( equipInstance.m_unEquippedClass == 2 )
  535. { // leave it equipped for class 3
  536. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = 3;
  537. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  538. return;
  539. }
  540. else
  541. {
  542. Assert( equipInstance.m_unEquippedClass == 2 ); // weird case, claims to be equipped for both classes, but first class is invalid!
  543. }
  544. }
  545. // Fully unequip
  546. m_pCustomDataOptimizedObject->m_equipInstanceSlot1 = INVALID_EQUIPPED_SLOT_BITPACKED;
  547. if ( !m_pCustomDataOptimizedObject->m_numAttributes )
  548. {
  549. m_pCustomDataOptimizedObject->FreeObjectAndAttrMemory();
  550. m_pCustomDataOptimizedObject = NULL;
  551. }
  552. return;
  553. }
  554. else if ( ( equipInstance.m_unEquippedClass == 3 ) && ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 2 ) && ( m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit != 0 ) )
  555. {
  556. // was equipped for both, unequipping 3rd class
  557. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  558. return;
  559. }
  560. }
  561. // item was not equipped to begin with
  562. return;
  563. }
  564. // If this item is already equipped
  565. if ( m_pCustomDataOptimizedObject && ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED ) )
  566. {
  567. m_pCustomDataOptimizedObject->m_equipInstanceSlot1 = equipInstance.m_unEquippedSlot;
  568. switch ( equipInstance.m_unEquippedClass )
  569. {
  570. case 0: // non-team item
  571. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = 0;
  572. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  573. return;
  574. case 2:
  575. if ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 3 )
  576. {
  577. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = 2;
  578. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 1;
  579. }
  580. else
  581. {
  582. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = 2;
  583. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  584. }
  585. return;
  586. case 3:
  587. if ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 2 )
  588. {
  589. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 1;
  590. }
  591. else
  592. {
  593. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = 3;
  594. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  595. }
  596. return;
  597. default:
  598. Assert( false );
  599. return;
  600. }
  601. }
  602. // Otherwise this item has not been equipped yet
  603. if ( !m_pCustomDataOptimizedObject )
  604. {
  605. m_pCustomDataOptimizedObject = CustomDataOptimizedObject_t::Alloc( 0 );
  606. }
  607. m_pCustomDataOptimizedObject->m_equipInstanceSlot1 = equipInstance.m_unEquippedSlot;
  608. m_pCustomDataOptimizedObject->m_equipInstanceClass1 = equipInstance.m_unEquippedClass;
  609. m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit = 0;
  610. }
  611. // --------------------------------------------------------------------------
  612. // Purpose:
  613. // --------------------------------------------------------------------------
  614. const char *CEconItem::GetCustomDesc() const
  615. {
  616. static CSchemaAttributeDefHandle pAttrDef_CustomDesc( "custom desc attr" );
  617. return GetCustomNameOrAttributeDesc( this, pAttrDef_CustomDesc );
  618. }
  619. // --------------------------------------------------------------------------
  620. // Purpose:
  621. // --------------------------------------------------------------------------
  622. void CEconItem::SetCustomDesc( const char *pDesc )
  623. {
  624. static CSchemaAttributeDefHandle pAttrDef_CustomDesc( "custom desc attr" );
  625. SetCustomNameOrDescAttribute( this, pAttrDef_CustomDesc, pDesc );
  626. }
  627. int CEconItem::GetItemSetIndex() const
  628. {
  629. // If we already cached it, use that one
  630. if ( m_iItemSet != ECON_ITEM_SET_NOT_YET_SCANNED )
  631. return ( ( m_iItemSet == ECON_ITEM_SET_INVALID ) ? -1 : m_iItemSet );
  632. // Mark it as cached and invalid
  633. m_iItemSet = ECON_ITEM_SET_INVALID;
  634. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( GetDefinitionIndex() );
  635. if ( !pItemDef )
  636. return ( ( m_iItemSet == ECON_ITEM_SET_INVALID ) ? -1 : m_iItemSet );
  637. // They might not have any possible sets
  638. const CUtlVector< int > &itemSets = pItemDef->GetItemSets();
  639. if ( itemSets.Count() == 0 )
  640. return ( ( m_iItemSet == ECON_ITEM_SET_INVALID ) ? -1 : m_iItemSet );
  641. // Paint kit specified, so we need to match it
  642. int nPaintKit = GetCustomPaintKitIndex();
  643. FOR_EACH_VEC( itemSets, nItemSet )
  644. {
  645. int nItemSetIndex = itemSets[ nItemSet ];
  646. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( nItemSetIndex );
  647. if ( !pItemSetDef )
  648. continue;
  649. FOR_EACH_VEC( pItemSetDef->m_ItemEntries, i )
  650. {
  651. if ( pItemSetDef->m_ItemEntries[ i ].m_nItemDef != pItemDef->GetDefinitionIndex() ||
  652. pItemSetDef->m_ItemEntries[ i ].m_nPaintKit != nPaintKit )
  653. {
  654. continue;
  655. }
  656. m_iItemSet = nItemSetIndex;
  657. return ( ( m_iItemSet == ECON_ITEM_SET_INVALID ) ? -1 : m_iItemSet );
  658. }
  659. }
  660. return ( ( m_iItemSet == ECON_ITEM_SET_INVALID ) ? -1 : m_iItemSet );
  661. }
  662. // --------------------------------------------------------------------------
  663. // Purpose:
  664. // --------------------------------------------------------------------------
  665. bool CEconItem::GetInUse() const
  666. {
  667. return m_dirtybitInUse != 0;
  668. }
  669. // --------------------------------------------------------------------------
  670. // Purpose:
  671. // --------------------------------------------------------------------------
  672. void CEconItem::SetInUse( bool bInUse )
  673. {
  674. m_dirtybitInUse = bInUse ? 1 : 0;
  675. }
  676. // --------------------------------------------------------------------------
  677. // Purpose:
  678. // --------------------------------------------------------------------------
  679. const GameItemDefinition_t *CEconItem::GetItemDefinition() const
  680. {
  681. const CEconItemDefinition *pRet = GetItemSchema()->GetItemDefinition( GetDefinitionIndex() );
  682. const GameItemDefinition_t *pTypedRet = dynamic_cast<const GameItemDefinition_t *>( pRet );
  683. AssertMsg( pRet == pTypedRet, "Item definition of inappropriate type." );
  684. return pTypedRet;
  685. }
  686. // --------------------------------------------------------------------------
  687. // Purpose:
  688. // --------------------------------------------------------------------------
  689. bool CEconItem::IsTradable() const
  690. {
  691. return !m_dirtybitInUse
  692. && IEconItemInterface::IsTradable();
  693. }
  694. // --------------------------------------------------------------------------
  695. // Purpose:
  696. // --------------------------------------------------------------------------
  697. bool CEconItem::IsMarketable() const
  698. {
  699. return !m_dirtybitInUse
  700. && IEconItemInterface::IsMarketable();
  701. }
  702. void CEconItem::IterateAttributes( IEconItemAttributeIterator *pIterator ) const
  703. {
  704. Assert( pIterator );
  705. // custom attributes?
  706. for ( int i = 0; i < GetDynamicAttributeCountInternal(); i++ )
  707. {
  708. attribute_t const &attrib = GetDynamicAttributeInternal( i );
  709. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( attrib.m_unDefinitionIndex );
  710. if ( !pAttrDef )
  711. continue;
  712. if ( !pAttrDef->GetAttributeType()->OnIterateAttributeValue( pIterator, pAttrDef, attrib.m_value ) )
  713. return;
  714. }
  715. // in static attributes?
  716. const CEconItemDefinition *pItemDef = GetItemDefinition();
  717. if ( !pItemDef )
  718. return;
  719. pItemDef->IterateAttributes( pIterator );
  720. }
  721. // --------------------------------------------------------------------------
  722. // Purpose:
  723. // --------------------------------------------------------------------------
  724. bool CEconItem::IsUsableInCrafting() const
  725. {
  726. return !m_dirtybitInUse
  727. && IEconItemInterface::IsUsableInCrafting();
  728. }
  729. // --------------------------------------------------------------------------
  730. // Purpose:
  731. // --------------------------------------------------------------------------
  732. int CEconItem::GetDynamicAttributeCountInternal() const
  733. {
  734. return m_pCustomDataOptimizedObject ? m_pCustomDataOptimizedObject->m_numAttributes : 0;
  735. }
  736. // --------------------------------------------------------------------------
  737. // Purpose:
  738. // --------------------------------------------------------------------------
  739. const CEconItem::attribute_t & CEconItem::GetDynamicAttributeInternal( int iAttrIndexIntoArray ) const
  740. {
  741. Assert( iAttrIndexIntoArray >= 0 );
  742. Assert( iAttrIndexIntoArray < GetDynamicAttributeCountInternal() );
  743. return *m_pCustomDataOptimizedObject->GetAttribute( iAttrIndexIntoArray );
  744. }
  745. // --------------------------------------------------------------------------
  746. // Purpose:
  747. // --------------------------------------------------------------------------
  748. CEconItem::attribute_t *CEconItem::FindDynamicAttributeInternal( const CEconItemAttributeDefinition *pAttrDef )
  749. {
  750. Assert( pAttrDef );
  751. if ( m_pCustomDataOptimizedObject )
  752. {
  753. attribute_t *pAttr = m_pCustomDataOptimizedObject->GetAttribute( 0 );
  754. attribute_t *pAttrEnd = pAttr + m_pCustomDataOptimizedObject->m_numAttributes;
  755. for ( ; pAttr < pAttrEnd; ++pAttr )
  756. {
  757. if ( pAttr->m_unDefinitionIndex == pAttrDef->GetDefinitionIndex() )
  758. return pAttr;
  759. }
  760. }
  761. return NULL;
  762. }
  763. // --------------------------------------------------------------------------
  764. // Purpose:
  765. // --------------------------------------------------------------------------
  766. void CEconItem::AddCustomAttribute( uint16 usDefinitionIndex, float flValue )
  767. {
  768. attribute_t &attrib = AddDynamicAttributeInternal();
  769. attrib.m_unDefinitionIndex = usDefinitionIndex;
  770. attrib.m_value.asFloat = flValue;
  771. }
  772. // --------------------------------------------------------------------------
  773. // Purpose:
  774. // --------------------------------------------------------------------------
  775. void CEconItem::AddOrSetCustomAttribute( uint16 usDefinitionIndex, float flValue )
  776. {
  777. attribute_t *pAttrib = FindDynamicAttributeInternal( GetItemSchema()->GetAttributeDefinition( usDefinitionIndex ) );
  778. if ( NULL != pAttrib )
  779. {
  780. pAttrib->m_value.asFloat = flValue;
  781. return;
  782. }
  783. AddCustomAttribute( usDefinitionIndex, flValue );
  784. }
  785. // --------------------------------------------------------------------------
  786. // Purpose:
  787. // --------------------------------------------------------------------------
  788. CEconItem::attribute_t &CEconItem::AddDynamicAttributeInternal()
  789. {
  790. if ( !m_pCustomDataOptimizedObject )
  791. return * ( m_pCustomDataOptimizedObject = CustomDataOptimizedObject_t::Alloc( 1 ) )->GetAttribute( 0 );
  792. else
  793. return * CustomDataOptimizedObject_t::AddAttribute( m_pCustomDataOptimizedObject );
  794. }
  795. // --------------------------------------------------------------------------
  796. // Purpose:
  797. // --------------------------------------------------------------------------
  798. void CEconItem::RemoveDynamicAttribute( const CEconItemAttributeDefinition *pAttrDef )
  799. {
  800. Assert( pAttrDef );
  801. Assert( pAttrDef->GetDefinitionIndex() != INVALID_ITEM_DEF_INDEX );
  802. if ( m_pCustomDataOptimizedObject )
  803. {
  804. attribute_t *pAttr = m_pCustomDataOptimizedObject->GetAttribute( 0 );
  805. attribute_t *pAttrStart = pAttr;
  806. attribute_t *pAttrEnd = pAttr + m_pCustomDataOptimizedObject->m_numAttributes;
  807. for ( ; pAttr < pAttrEnd; ++pAttr )
  808. {
  809. if ( pAttr->m_unDefinitionIndex == pAttrDef->GetDefinitionIndex() )
  810. {
  811. m_pCustomDataOptimizedObject->RemoveAndFreeAttrMemory( pAttr - pAttrStart );
  812. return;
  813. }
  814. }
  815. }
  816. }
  817. // --------------------------------------------------------------------------
  818. // Purpose:
  819. // --------------------------------------------------------------------------
  820. /*static*/ void CEconItem::FreeAttributeMemory( CEconItem::attribute_t *pAttrib )
  821. {
  822. Assert( pAttrib );
  823. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( pAttrib->m_unDefinitionIndex );
  824. Assert( pAttrDef );
  825. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  826. Assert( pAttrType );
  827. pAttrType->UnloadEconAttributeValue( &pAttrib->m_value );
  828. }
  829. // --------------------------------------------------------------------------
  830. // Purpose: This item has been traded. Give it an opportunity to update any internal
  831. // properties in response.
  832. // --------------------------------------------------------------------------
  833. void CEconItem::OnTransferredOwnership()
  834. {
  835. /** Removed for partner depot **/
  836. }
  837. // --------------------------------------------------------------------------
  838. // Purpose: Parses the bits required to create a econ item from the message.
  839. // Overloaded to include support for attributes.
  840. // --------------------------------------------------------------------------
  841. bool CEconItem::BParseFromMessage( const CUtlBuffer & buffer )
  842. {
  843. CSOEconItem msgItem;
  844. if( !msgItem.ParseFromArray( buffer.Base(), buffer.TellMaxPut() ) )
  845. return false;
  846. DeserializeFromProtoBufItem( msgItem );
  847. return true;
  848. }
  849. // --------------------------------------------------------------------------
  850. // Purpose: Parses the bits required to create a econ item from the message.
  851. // Overloaded to include support for attributes.
  852. // --------------------------------------------------------------------------
  853. bool CEconItem::BParseFromMessage( const std::string &buffer )
  854. {
  855. CSOEconItem msgItem;
  856. if( !msgItem.ParseFromString( buffer ) )
  857. return false;
  858. DeserializeFromProtoBufItem( msgItem );
  859. return true;
  860. }
  861. //----------------------------------------------------------------------------
  862. // Purpose: Overrides all the fields in msgLocal that are present in the
  863. // network message
  864. //----------------------------------------------------------------------------
  865. bool CEconItem::BUpdateFromNetwork( const CSharedObject & objUpdate )
  866. {
  867. const CEconItem & econObjUpdate = (const CEconItem &)objUpdate;
  868. *this = econObjUpdate;
  869. return true;
  870. }
  871. //----------------------------------------------------------------------------
  872. // Purpose: Adds the relevant bits to update this object to the message. This
  873. // must include any relevant information about which fields are being
  874. // updated. This is called once for all subscribers.
  875. //----------------------------------------------------------------------------
  876. static CSOEconItem g_msgEconItem;
  877. bool CEconItem::BAddToMessage( std::string *pBuffer ) const
  878. {
  879. VPROF_BUDGET( "CEconItem::BAddToMessage::std::string", VPROF_BUDGETGROUP_STEAM );
  880. //this function is called A LOT, therefore we use a static item to avoid a lot of re-allocations. However, this means that
  881. //this should never be re-entrant
  882. g_msgEconItem.Clear();
  883. SerializeToProtoBufItem( g_msgEconItem );
  884. return g_msgEconItem.SerializeToString( pBuffer );
  885. }
  886. //----------------------------------------------------------------------------
  887. // Purpose: Adds just the item ID to the message so that the client can find
  888. // which item to destroy
  889. //----------------------------------------------------------------------------
  890. bool CEconItem::BAddDestroyToMessage( std::string *pBuffer ) const
  891. {
  892. CSOEconItem msgItem;
  893. msgItem.set_id( GetItemID() );
  894. return msgItem.SerializeToString( pBuffer );
  895. }
  896. //----------------------------------------------------------------------------
  897. // Purpose: Returns true if this is less than than the object in soRHS. This
  898. // comparison is deterministic, but it may not be pleasing to a user
  899. // since it is just going to compare raw memory. If you need a sort
  900. // that is user-visible you will need to do it at a higher level that
  901. // actually knows what the data in these objects means.
  902. //----------------------------------------------------------------------------
  903. bool CEconItem::BIsKeyLess( const CSharedObject & soRHS ) const
  904. {
  905. Assert( GetTypeID() == soRHS.GetTypeID() );
  906. const CEconItem & soSchemaRHS = (const CEconItem &)soRHS;
  907. return m_ulID < soSchemaRHS.m_ulID;
  908. }
  909. //----------------------------------------------------------------------------
  910. // Purpose: Copy the data from the specified schema shared object into this.
  911. // Both objects must be of the same type.
  912. //----------------------------------------------------------------------------
  913. void CEconItem::Copy( const CSharedObject & soRHS )
  914. {
  915. *this = (const CEconItem &)soRHS;
  916. }
  917. //----------------------------------------------------------------------------
  918. // Purpose: Dumps diagnostic information about the shared object
  919. //----------------------------------------------------------------------------
  920. void CEconItem::Dump() const
  921. {
  922. CSOEconItem msgItem;
  923. SerializeToProtoBufItem( msgItem );
  924. CProtoBufSharedObjectBase::Dump( msgItem );
  925. }
  926. //-----------------------------------------------------------------------------
  927. // Purpose: Deserializes an item from a KV object
  928. // Input: pKVItem - Pointer to the KV structure that represents an item
  929. // schema - Econ item schema used for decoding human readable names
  930. // pVecErrors - Pointer to a vector where human readable errors will
  931. // be added
  932. // Output: True if the item deserialized successfully, false otherwise
  933. //-----------------------------------------------------------------------------
  934. bool CEconItem::BDeserializeFromKV( KeyValues *pKVItem, const CEconItemSchema &pschema, CUtlVector<CUtlString> *pVecErrors )
  935. {
  936. Assert( NULL != pKVItem );
  937. if ( NULL == pKVItem )
  938. return false;
  939. // The basic properties
  940. SetItemID( pKVItem->GetUint64( "ID", INVALID_ITEM_ID ) );
  941. SetInventoryToken( pKVItem->GetInt( "InventoryPos", GetUnacknowledgedPositionFor(UNACK_ITEM_DROPPED) ) ); // Start by assuming it's a drop
  942. SetQuantity( pKVItem->GetInt( "Quantity", 1 ) );
  943. // Look up the following properties based on names from the schema
  944. const CEconItemQualityDefinition *pQuality = NULL;
  945. const CEconItemDefinition *pItemDef = NULL;
  946. const char *pchDefName = pKVItem->GetString( "DefName" );
  947. pItemDef = pschema.GetItemDefinitionByName( pchDefName );
  948. if( !pItemDef )
  949. {
  950. if ( pVecErrors )
  951. {
  952. pVecErrors->AddToTail( CUtlString( CFmtStr( "Item definition \"%s\" not found", pchDefName ) ) );
  953. }
  954. // we can't do any reasonable validation with no item def, so just stop here
  955. return false;
  956. }
  957. SetDefinitionIndex( pItemDef->GetDefinitionIndex() );
  958. uint8 unValueGet = 0;
  959. const char *pchQualityName = pKVItem->GetString( "QualityName" );
  960. if( !pchQualityName || ! *pchQualityName )
  961. {
  962. // set the default quality for the definition
  963. if( pItemDef->GetQuality() == k_unItemQuality_Any )
  964. {
  965. if ( NULL == pVecErrors )
  966. return false;
  967. pVecErrors->AddToTail( CUtlString( CFmtStr( "Quality was not specified and this item def doesn't define one either." ) ) );
  968. }
  969. else
  970. {
  971. SetQuality( pItemDef->GetQuality() );
  972. }
  973. }
  974. else if ( !pschema.BGetItemQualityFromName( pchQualityName, &unValueGet ) || (( m_nQuality = unValueGet ),true) || k_unItemQuality_Any == GetQuality() )
  975. {
  976. if ( NULL == pVecErrors )
  977. return false;
  978. pVecErrors->AddToTail( CUtlString( CFmtStr( "Quality \"%s\" not found", pchQualityName ) ) );
  979. }
  980. else
  981. {
  982. pQuality = pschema.GetQualityDefinition( GetQuality() );
  983. }
  984. const char *pchRarityName = pKVItem->GetString( "RarityName" );
  985. if( !pchRarityName || ! *pchRarityName )
  986. {
  987. // set the default quality for the definition
  988. if( pItemDef->GetRarity() == k_unItemRarity_Any )
  989. {
  990. if ( NULL == pVecErrors )
  991. return false;
  992. pVecErrors->AddToTail( CUtlString( CFmtStr( "Rarity was not specified and this item def doesn't define one either." ) ) );
  993. }
  994. else
  995. {
  996. SetRarity( pItemDef->GetRarity() );
  997. }
  998. }
  999. else if ( !pschema.BGetItemRarityFromName( pchRarityName, &unValueGet ) || (( m_nRarity = unValueGet ),true) || k_unItemRarity_Any == GetRarity() )
  1000. {
  1001. if ( NULL == pVecErrors )
  1002. return false;
  1003. pVecErrors->AddToTail( CUtlString( CFmtStr( "Rarity \"%s\" not found", pchRarityName ) ) );
  1004. }
  1005. // make sure the level is sane
  1006. SetItemLevel( pKVItem->GetInt( "Level", pItemDef->GetMinLevel() ) );
  1007. // read the flags
  1008. uint8 unFlags = GetFlags();
  1009. if( pKVItem->GetInt( "flag_cannot_trade", 0 ) )
  1010. {
  1011. unFlags |= kEconItemFlag_CannotTrade;
  1012. }
  1013. else
  1014. {
  1015. unFlags = unFlags & ~kEconItemFlag_CannotTrade;
  1016. }
  1017. if( pKVItem->GetInt( "flag_cannot_craft", 0 ) )
  1018. {
  1019. unFlags |= kEconItemFlag_CannotBeUsedInCrafting;
  1020. }
  1021. else
  1022. {
  1023. unFlags = unFlags & ~kEconItemFlag_CannotBeUsedInCrafting;
  1024. }
  1025. if( pKVItem->GetInt( "flag_non_economy", 0 ) )
  1026. {
  1027. unFlags |= kEconItemFlag_NonEconomy;
  1028. }
  1029. else
  1030. {
  1031. unFlags = unFlags & ~kEconItemFlag_NonEconomy;
  1032. }
  1033. SetFlag( unFlags );
  1034. // Deserialize the attributes
  1035. KeyValues *pKVAttributes = pKVItem->FindKey( "Attributes" );
  1036. if ( NULL != pKVAttributes )
  1037. {
  1038. FOR_EACH_SUBKEY( pKVAttributes, pKVAttr )
  1039. {
  1040. // Try to load each line into an attribute in memory. It's possible that if we fail to successfully
  1041. // load some attribute contents here we'll leak small amounts of memory, but if that happens we're
  1042. // going to fail to start up anyway so we don't really care.
  1043. static_attrib_t staticAttrib;
  1044. if ( !staticAttrib.BInitFromKV_SingleLine( __FUNCTION__, pKVAttr, pVecErrors ) )
  1045. continue;
  1046. const CEconItemAttributeDefinition *pAttrDef = staticAttrib.GetAttributeDefinition();
  1047. Assert( pAttrDef );
  1048. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  1049. Assert( pAttrType );
  1050. // Load the attribute contents into memory on the item.
  1051. pAttrType->LoadEconAttributeValue( this, pAttrDef, staticAttrib.m_value );
  1052. // Free up our temp loading memory.
  1053. pAttrType->UnloadEconAttributeValue( &staticAttrib.m_value );
  1054. }
  1055. }
  1056. return ( NULL == pVecErrors || 0 == pVecErrors->Count() );
  1057. }
  1058. // --------------------------------------------------------------------------
  1059. // Purpose:
  1060. // --------------------------------------------------------------------------
  1061. void CEconItem::SerializeToProtoBufItem( CSOEconItem &msgItem ) const
  1062. {
  1063. msgItem.set_id( m_ulID );
  1064. msgItem.set_account_id( m_unAccountID );
  1065. msgItem.set_def_index( m_unDefIndex );
  1066. msgItem.set_level( m_unLevel );
  1067. msgItem.set_quality( m_nQuality );
  1068. msgItem.set_rarity( m_nRarity );
  1069. msgItem.set_inventory( m_unInventory );
  1070. msgItem.set_quantity( GetQuantity() );
  1071. msgItem.set_flags( m_unFlags );
  1072. msgItem.set_origin( m_unOrigin );
  1073. msgItem.set_in_use( m_dirtybitInUse );
  1074. if ( m_pCustomDataOptimizedObject )
  1075. {
  1076. //
  1077. // Write our custom attributes
  1078. //
  1079. attribute_t const *pAttr = m_pCustomDataOptimizedObject->GetAttribute( 0 );
  1080. attribute_t const *pAttrEnd = pAttr + m_pCustomDataOptimizedObject->m_numAttributes;
  1081. for ( ; pAttr < pAttrEnd; ++pAttr )
  1082. {
  1083. const attribute_t & attr = *pAttr;
  1084. // skip over attributes we don't understand
  1085. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( attr.m_unDefinitionIndex );
  1086. if ( !pAttrDef )
  1087. continue;
  1088. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  1089. Assert( pAttrType );
  1090. CSOEconItemAttribute *pMsgAttr = msgItem.add_attribute();
  1091. pMsgAttr->set_def_index( attr.m_unDefinitionIndex );
  1092. pAttrType->ConvertEconAttributeValueToByteStream( attr.m_value, pMsgAttr->mutable_value_bytes() );
  1093. }
  1094. //
  1095. // Write equipped instances
  1096. //
  1097. if ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED )
  1098. {
  1099. CSOEconItemEquipped *pMsgEquipped = msgItem.add_equipped_state();
  1100. pMsgEquipped->set_new_class( m_pCustomDataOptimizedObject->m_equipInstanceClass1 );
  1101. pMsgEquipped->set_new_slot( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 );
  1102. if ( m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit && ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 2 ) )
  1103. {
  1104. pMsgEquipped = msgItem.add_equipped_state();
  1105. pMsgEquipped->set_new_class( 3 );
  1106. pMsgEquipped->set_new_slot( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 );
  1107. }
  1108. }
  1109. }
  1110. #ifndef GC_DLL // no need to send original IDs outside of GC
  1111. if ( m_ulID != GetOriginalID() )
  1112. msgItem.set_original_id( GetOriginalID() );
  1113. #endif
  1114. #if 0
  1115. // Names and descriptions are now attributes, no need to duplicate them here (perf)
  1116. const char *pszCustomName = GetCustomName();
  1117. if ( pszCustomName )
  1118. {
  1119. msgItem.set_custom_name( pszCustomName );
  1120. }
  1121. const char *pszCustomDesc = GetCustomDesc();
  1122. if ( pszCustomDesc )
  1123. {
  1124. msgItem.set_custom_desc( pszCustomDesc );
  1125. }
  1126. #endif
  1127. }
  1128. // --------------------------------------------------------------------------
  1129. // Purpose:
  1130. // --------------------------------------------------------------------------
  1131. void CEconItem::DeserializeFromProtoBufItem( const CSOEconItem &msgItem )
  1132. {
  1133. VPROF_BUDGET( "CEconItem::DeserializeFromProtoBufItem()", VPROF_BUDGETGROUP_STEAM );
  1134. // Start by resetting
  1135. if ( m_pCustomDataOptimizedObject )
  1136. {
  1137. m_pCustomDataOptimizedObject->FreeObjectAndAttrMemory();
  1138. m_pCustomDataOptimizedObject = NULL;
  1139. }
  1140. // Now copy from the message
  1141. m_ulID = msgItem.id();
  1142. SetOriginalID( msgItem.has_original_id() ? msgItem.original_id() : m_ulID );
  1143. m_unAccountID = msgItem.account_id();
  1144. m_unDefIndex = msgItem.def_index();
  1145. m_nQuality = msgItem.quality();
  1146. m_nRarity = msgItem.rarity();
  1147. m_unInventory = msgItem.inventory();
  1148. m_unFlags = msgItem.flags();
  1149. m_unOrigin = msgItem.origin();
  1150. //the default value of these fields will be switched from zero to 1 since almost all items have 1 for both of these. However, to
  1151. //ensure a smooth transition, we ensure that the values are always 1 (zero is invalid for these). This can be removed after a few
  1152. //versions and the GC/client/server are all in sync
  1153. m_unLevel = MAX( 1, msgItem.level() );
  1154. SetQuantity( MAX( 1, msgItem.quantity() ) );
  1155. m_dirtybitInUse = msgItem.in_use() ? 1 : 0;
  1156. // set name if any
  1157. if( msgItem.has_custom_name() )
  1158. {
  1159. SetCustomName( msgItem.custom_name().c_str() );
  1160. }
  1161. // set desc if any
  1162. if( msgItem.has_custom_desc() )
  1163. {
  1164. SetCustomDesc( msgItem.custom_desc().c_str() );
  1165. }
  1166. // read the attributes
  1167. for( int nAttr = 0; nAttr < msgItem.attribute_size(); nAttr++ )
  1168. {
  1169. // skip over old-format messages
  1170. const CSOEconItemAttribute& msgAttr = msgItem.attribute( nAttr );
  1171. if ( msgAttr.has_value() || !msgAttr.has_value_bytes() )
  1172. continue;
  1173. // skip over attributes we don't understand
  1174. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( msgAttr.def_index() );
  1175. if ( !pAttrDef )
  1176. continue;
  1177. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  1178. Assert( pAttrType );
  1179. pAttrType->LoadByteStreamToEconAttributeValue( this, pAttrDef, msgAttr.value_bytes() );
  1180. }
  1181. // Check to see if the item has an interior object.
  1182. Assert( !msgItem.has_interior_item() );
  1183. // update equipped state
  1184. for ( int i = 0; i < msgItem.equipped_state_size(); i++ )
  1185. {
  1186. UpdateEquippedState( msgItem.equipped_state(i).new_class(), msgItem.equipped_state(i).new_slot() );
  1187. }
  1188. }
  1189. int CEconItem::GetEquippedInstanceArray( EquippedInstanceArray_t &equips ) const
  1190. {
  1191. //build up a list of the equip instances we need to copy over, since as we equip new items into that slot, it will unequip these other items
  1192. equips.RemoveAll();
  1193. if ( m_pCustomDataOptimizedObject && ( m_pCustomDataOptimizedObject->m_equipInstanceSlot1 != INVALID_EQUIPPED_SLOT_BITPACKED ) )
  1194. {
  1195. EquippedInstance_t instEquip( m_pCustomDataOptimizedObject->m_equipInstanceClass1, m_pCustomDataOptimizedObject->m_equipInstanceSlot1 );
  1196. equips.AddToTail( instEquip );
  1197. if ( m_pCustomDataOptimizedObject->m_equipInstanceClass2Bit && ( m_pCustomDataOptimizedObject->m_equipInstanceClass1 == 2 ) )
  1198. {
  1199. instEquip.m_unEquippedClass = 3;
  1200. equips.AddToTail( instEquip );
  1201. }
  1202. }
  1203. return equips.Count();
  1204. }