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.

3708 lines
121 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_item_view.h"
  8. #include "econ_item_system.h"
  9. #include "econ_item_description.h"
  10. #include "econ_item_inventory.h"
  11. #include "econ_gcmessages.h"
  12. // For localization
  13. #include "tier3/tier3.h"
  14. #include "vgui/ILocalize.h"
  15. #include "tier2/p4helpers.h"
  16. #include "p4lib/ip4.h"
  17. #include "imageutils.h"
  18. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  19. #include "isaverestore.h"
  20. #include "dt_utlvector_send.h"
  21. #include "dt_utlvector_recv.h"
  22. #endif
  23. #ifdef CLIENT_DLL
  24. #ifndef DEDICATED
  25. #include "vgui_controls/Panel.h"
  26. #include "vgui/IScheme.h"
  27. #endif
  28. #endif
  29. #if defined(TF_CLIENT_DLL)
  30. #include "tf_duel_summary.h"
  31. #include "econ_contribution.h"
  32. #include "tf_player_info.h"
  33. #include "tf_gcmessages.h"
  34. #include "c_tf_freeaccount.h"
  35. #endif
  36. #if defined(DOTA_DLL)
  37. #include "dota_sharedfuncs.h"
  38. #endif
  39. #include "activitylist.h"
  40. #if defined(CSTRIKE_CLIENT_DLL)
  41. #include "materialsystem/icompositetexturegenerator.h"
  42. #include "materialsystem/icustommaterialmanager.h"
  43. #include "mathlib/camera.h"
  44. #include "tier3/mdlutils.h"
  45. #include "irendertorthelperobject.h"
  46. #include "cs_weapon_parse.h"
  47. #include "cs_custom_weapon_visualsdata_processor.h"
  48. #include "cs_custom_clothing_visualsdata_processor.h"
  49. #include "cs_custom_epidermis_visualsdata_processor.h"
  50. #include "cs_custom_embroider_visualsdata_processor.h"
  51. #include "cs_custom_texture_saver.h"
  52. #include "materialsystem/imaterialvar.h"
  53. #endif //#if defined(CSTRIKE_CLIENT_DLL)
  54. // memdbgon must be the last include file in a .cpp file!!!
  55. #include "tier0/memdbgon.h"
  56. #define ECON_ITEM_ICON_CACHE_VERSION 0x10
  57. // Dynamic attributes in the the Econ_Item SOCache need to be networked for demo recording!
  58. #define ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  59. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  60. // Networking tables for attributes
  61. BEGIN_NETWORK_TABLE_NOBASE( CEconItemAttribute, DT_ScriptCreatedAttribute )
  62. // Note: we are networking the value as an int, even though it's a "float", because really it isn't
  63. // a float. It's 32 raw bits.
  64. #ifndef CLIENT_DLL
  65. SendPropInt( SENDINFO(m_iAttributeDefinitionIndex), -1, SPROP_UNSIGNED ),
  66. SendPropInt( SENDINFO_NAME(m_flValue, m_iRawValue32), 32, SPROP_UNSIGNED ),
  67. SendPropInt( SENDINFO_NAME(m_flInitialValue, m_iRawInitialValue32), 32, SPROP_UNSIGNED ),
  68. SendPropInt( SENDINFO(m_nRefundableCurrency), -1, SPROP_UNSIGNED ),
  69. SendPropBool( SENDINFO(m_bSetBonus) ),
  70. #else
  71. RecvPropInt( RECVINFO(m_iAttributeDefinitionIndex) ),
  72. RecvPropInt( RECVINFO_NAME(m_flValue, m_iRawValue32) ),
  73. RecvPropFloat( RECVINFO(m_flValue), SPROP_NOSCALE ), // for demo compatibility only
  74. RecvPropInt( RECVINFO_NAME(m_flInitialValue, m_iRawInitialValue32) ),
  75. RecvPropInt( RECVINFO( m_nRefundableCurrency ) ),
  76. RecvPropBool( RECVINFO( m_bSetBonus ) ),
  77. #endif
  78. END_NETWORK_TABLE()
  79. #endif
  80. #if defined(CSTRIKE_CLIENT_DLL)
  81. CCSCustomTextureSaver g_Generated_Texture_Saver;
  82. #endif //#if defined(CSTRIKE_CLIENT_DLL)
  83. //-----------------------------------------------------------------------------
  84. // Purpose:
  85. //-----------------------------------------------------------------------------
  86. CEconItemAttribute::CEconItemAttribute( void )
  87. {
  88. Init();
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. void CEconItemAttribute::Init( void )
  94. {
  95. m_iAttributeDefinitionIndex = (attrib_definition_index_t)-1;
  96. m_flValue = 0.0f;
  97. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  98. m_flInitialValue = 0;
  99. m_nRefundableCurrency = 0;
  100. m_bSetBonus = false;
  101. #endif
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose:
  105. //-----------------------------------------------------------------------------
  106. CEconItemAttribute & CEconItemAttribute::operator=( const CEconItemAttribute &val )
  107. {
  108. m_iAttributeDefinitionIndex = val.m_iAttributeDefinitionIndex;
  109. m_flValue = val.m_flValue;
  110. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  111. m_flInitialValue = m_flValue;
  112. m_bSetBonus = val.m_bSetBonus;
  113. #endif
  114. return *this;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. CEconItemAttribute::CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, float flValue )
  120. {
  121. Init();
  122. m_iAttributeDefinitionIndex = iAttributeIndex;
  123. SetValue( flValue );
  124. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  125. m_flInitialValue = m_flValue;
  126. #endif
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. CEconItemAttribute::CEconItemAttribute( const attrib_definition_index_t iAttributeIndex, uint32 unValue )
  132. {
  133. Init();
  134. m_iAttributeDefinitionIndex = iAttributeIndex;
  135. SetIntValue( unValue );
  136. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  137. m_flInitialValue = m_flValue;
  138. #endif
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. //-----------------------------------------------------------------------------
  143. void CEconItemAttribute::SetValue( float flValue )
  144. {
  145. // Assert( GetStaticData() && GetStaticData()->IsStoredAsFloat() );
  146. m_flValue = flValue;
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. //-----------------------------------------------------------------------------
  151. float CEconItemAttribute::GetValue( void ) const
  152. {
  153. // Assert( GetStaticData() && GetStaticData()->IsStoredAsFloat() );
  154. return m_flValue;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose:
  158. //-----------------------------------------------------------------------------
  159. void CEconItemAttribute::SetIntValue( uint32 unValue )
  160. {
  161. // @note we don't check the storage type here, because this is how it is set from the data file
  162. // Note that numbers approaching two billion cannot be stored in a float
  163. // representation because they will map to NaNs. Numbers below 16 million
  164. // will fail if denormals are disabled.
  165. m_flValue = *(float*)&unValue;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. uint32 CEconItemAttribute::GetIntValue( void ) const
  171. {
  172. // Assert( GetStaticData() && GetStaticData()->IsStoredAsInteger() );
  173. return *(uint32*)&m_flValue;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. const CEconItemAttributeDefinition *CEconItemAttribute::GetStaticData( void ) const
  179. {
  180. return GetItemSchema()->GetAttributeDefinition( m_iAttributeDefinitionIndex );
  181. }
  182. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  183. #if defined( ECON_NETWORK_ATTRIBUTES ) || defined( ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS )
  184. BEGIN_NETWORK_TABLE_NOBASE( CAttributeList, DT_AttributeList )
  185. #if !defined( CLIENT_DLL )
  186. SendPropUtlVectorDataTable( m_Attributes, MAX_ATTRIBUTES_PER_ITEM, DT_ScriptCreatedAttribute ),
  187. #else
  188. RecvPropUtlVectorDataTable( m_Attributes, MAX_ATTRIBUTES_PER_ITEM, DT_ScriptCreatedAttribute ),
  189. #endif // CLIENT_DLL
  190. END_NETWORK_TABLE()
  191. #endif // #ifdef defined( ECON_NETWORK_ATTRIBUTES ) || defined( ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS )
  192. BEGIN_DATADESC_NO_BASE( CAttributeList )
  193. END_DATADESC()
  194. #endif // #if defined(CLIENT_DLL) || defined(GAME_DLL)
  195. #if defined(CLIENT_DLL)
  196. bool CEconItemView::m_sbHasCleanedInventoryImageCacheDir = false;
  197. #endif //#if defined(CLIENT_DLL)
  198. //===========================================================================================================================
  199. // SCRIPT CREATED ITEMS
  200. //===========================================================================================================================
  201. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  202. BEGIN_NETWORK_TABLE_NOBASE( CEconItemView, DT_ScriptCreatedItem )
  203. #if !defined( CLIENT_DLL )
  204. SendPropInt( SENDINFO( m_iItemDefinitionIndex ), 20, SPROP_UNSIGNED ),
  205. SendPropInt( SENDINFO( m_iEntityLevel ), 8 ),
  206. //SendPropInt( SENDINFO( m_iItemID ), 64, SPROP_UNSIGNED ),
  207. SendPropInt( SENDINFO( m_iItemIDHigh ), 32, SPROP_UNSIGNED ),
  208. SendPropInt( SENDINFO( m_iItemIDLow ), 32, SPROP_UNSIGNED ),
  209. SendPropInt( SENDINFO( m_iAccountID ), 32, SPROP_UNSIGNED ),
  210. SendPropInt( SENDINFO( m_iEntityQuality ), 5 ),
  211. SendPropBool( SENDINFO( m_bInitialized ) ),
  212. SendPropString( SENDINFO( m_szCustomName ) ),
  213. #ifdef ECON_NETWORK_ATTRIBUTES
  214. SendPropDataTable(SENDINFO_DT(m_AttributeList), &REFERENCE_SEND_TABLE(DT_AttributeList)),
  215. #endif // #ifdef ECON_NETWORK_ATTRIBUTES
  216. #ifdef ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  217. SendPropDataTable(SENDINFO_DT(m_NetworkedDynamicAttributesForDemos), &REFERENCE_SEND_TABLE(DT_AttributeList)),
  218. #endif // #ifdef ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  219. #else
  220. RecvPropInt( RECVINFO( m_iItemDefinitionIndex ) ),
  221. RecvPropInt( RECVINFO( m_iEntityLevel ) ),
  222. //RecvPropInt( RECVINFO( m_iItemID ) ),
  223. RecvPropInt( RECVINFO( m_iItemIDHigh ) ),
  224. RecvPropInt( RECVINFO( m_iItemIDLow ) ),
  225. RecvPropInt( RECVINFO( m_iAccountID ) ),
  226. RecvPropInt( RECVINFO( m_iEntityQuality ) ),
  227. RecvPropBool( RECVINFO( m_bInitialized ) ),
  228. RecvPropString( RECVINFO( m_szCustomName ) ),
  229. #ifdef ECON_NETWORK_ATTRIBUTES
  230. RecvPropDataTable(RECVINFO_DT(m_AttributeList), 0, &REFERENCE_RECV_TABLE(DT_AttributeList)),
  231. #endif // #ifdef ECON_NETWORK_ATTRIBUTES
  232. #ifdef ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  233. RecvPropDataTable(RECVINFO_DT(m_NetworkedDynamicAttributesForDemos), 0, &REFERENCE_RECV_TABLE(DT_AttributeList)),
  234. #endif // #ifdef ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  235. #endif // CLIENT_DLL
  236. END_NETWORK_TABLE()
  237. BEGIN_DATADESC_NO_BASE( CEconItemView )
  238. DEFINE_FIELD( m_iItemDefinitionIndex, FIELD_SHORT ),
  239. DEFINE_FIELD( m_iEntityQuality, FIELD_INTEGER ),
  240. DEFINE_FIELD( m_iEntityLevel, FIELD_INTEGER ),
  241. DEFINE_FIELD( m_iItemID, FIELD_INTEGER ),
  242. // DEFINE_FIELD( m_wszItemName, FIELD_STRING ), Regenerated post-save
  243. // DEFINE_FIELD( m_szItemName, FIELD_STRING ), Regenerated post-save
  244. // DEFINE_FIELD( m_szAttributeDescription, FIELD_STRING ), Regenerated post-save
  245. // m_AttributeLineColors // Regenerated post-save
  246. // m_Attributes // Custom handling in Save()/Restore()
  247. DEFINE_FIELD( m_bInitialized, FIELD_BOOLEAN ),
  248. DEFINE_EMBEDDED( m_AttributeList ),
  249. END_DATADESC()
  250. #endif
  251. //-----------------------------------------------------------------------------
  252. // Purpose:
  253. //-----------------------------------------------------------------------------
  254. CEconItemView::CEconItemView( void )
  255. {
  256. m_iItemDefinitionIndex = 0;
  257. m_iEntityQuality = (int)AE_UNDEFINED;
  258. m_iEntityLevel = 0;
  259. SetItemID(0);
  260. m_iInventoryPosition = 0;
  261. m_bInitialized = false;
  262. m_iAccountID = 0;
  263. m_pNonSOEconItem = NULL;
  264. #if defined( CLIENT_DLL )
  265. m_bIsTradeItem = false;
  266. m_iEntityQuantity = 1;
  267. m_iRarityOverride = -1;
  268. m_iQualityOverride = 0;
  269. m_unClientFlags = 0;
  270. m_unOverrideStyle = INVALID_STYLE_INDEX;
  271. m_bInventoryImageRgbaRequested = false;
  272. m_bInventoryImageTriedCache = false;
  273. m_nInventoryImageRgbaWidth = 0;
  274. m_nInventoryImageRgbaHeight = 0;
  275. m_pImageReadyCallback = NULL;
  276. m_pRenderToRTData = NULL;
  277. m_pScratchVTF = NULL;
  278. m_pRenderToRTMDL = NULL;
  279. m_hAsyncControl = NULL;
  280. m_asyncFixupState = AFS_Init;
  281. #endif
  282. m_szCustomNameOverride[ 0 ] = '\0';
  283. m_bKillEaterTypesCached = false;
  284. m_nKillEaterValuesCacheFrame = -2;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose:
  288. //-----------------------------------------------------------------------------
  289. CEconItemView::~CEconItemView( void )
  290. {
  291. #ifdef CLIENT_DLL
  292. // don't want to call this during destruction
  293. m_pImageReadyCallback = NULL;
  294. g_InventoryItemUpdateManager.RemoveItemViewFromFixupList( this );
  295. if ( InventoryManager() )
  296. {
  297. InventoryManager()->OnDestroyEconItemView( this );
  298. }
  299. if ( m_asyncFixupState == AFS_LoadingInProgress )
  300. {
  301. if ( filesystem && m_hAsyncControl )
  302. {
  303. filesystem->AsyncAbort( m_hAsyncControl );
  304. filesystem->AsyncRelease( m_hAsyncControl );
  305. }
  306. m_hAsyncControl = NULL;
  307. m_asyncFixupState = AFS_Init;
  308. }
  309. #endif
  310. DestroyAllAttributes();
  311. Cleanup();
  312. }
  313. void CEconItemView::Cleanup( void )
  314. {
  315. MarkDescriptionDirty();
  316. #if defined( CSTRIKE_CLIENT_DLL )
  317. for ( int i = 0; i < m_ppVisualsDataProcessors.Count(); i++ )
  318. {
  319. if ( m_ppVisualsDataProcessors[ i ] != NULL )
  320. {
  321. m_ppVisualsDataProcessors[ i ]->Release();
  322. m_ppVisualsDataProcessors[ i ] = NULL;
  323. }
  324. }
  325. m_ppVisualsDataProcessors.RemoveAll();
  326. if ( m_pRenderToRTData != NULL )
  327. {
  328. g_pRenderToRTHelper->DestroyRenderToRTData( m_pRenderToRTData );
  329. m_pRenderToRTData = NULL;
  330. }
  331. if ( m_pRenderToRTMDL != NULL )
  332. {
  333. delete m_pRenderToRTMDL;
  334. m_pRenderToRTMDL = NULL;
  335. }
  336. if ( m_pScratchVTF != NULL )
  337. {
  338. DestroyVTFTexture( m_pScratchVTF );
  339. m_pScratchVTF = NULL;
  340. }
  341. m_pStickerMaterials.RemoveAll();
  342. #endif //#if defined( CSTRIKE_CLIENT_DLL )
  343. if ( m_pNonSOEconItem )
  344. {
  345. delete m_pNonSOEconItem;
  346. m_pNonSOEconItem = NULL;
  347. }
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose:
  351. //-----------------------------------------------------------------------------
  352. CEconItemView::CEconItemView( const CEconItemView &src )
  353. {
  354. m_pNonSOEconItem = NULL;
  355. #if defined( CSTRIKE_CLIENT_DLL )
  356. m_bInventoryImageRgbaRequested = false;
  357. m_bInventoryImageTriedCache = false;
  358. m_pImageReadyCallback = NULL;
  359. m_pRenderToRTData = NULL;
  360. m_pScratchVTF = NULL;
  361. m_pRenderToRTMDL = NULL;
  362. m_hAsyncControl = NULL;
  363. m_asyncFixupState = AFS_Init;
  364. #endif
  365. *this = src;
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Purpose:
  369. //-----------------------------------------------------------------------------
  370. void CEconItemView::Init( int iDefIndex, int iQuality, int iLevel, uint32 iAccountID )
  371. {
  372. m_AttributeList.Init();
  373. m_NetworkedDynamicAttributesForDemos.Init();
  374. m_szCustomName.GetForModify()[0] = '\0';
  375. m_iItemDefinitionIndex = iDefIndex;
  376. const CEconItemDefinition *pData = GetStaticData();
  377. if ( !pData )
  378. {
  379. // We've got an item that we don't have static data for.
  380. return;
  381. }
  382. SetItemID(0);
  383. m_bInitialized = true;
  384. m_iAccountID = iAccountID;
  385. if ( iQuality == AE_USE_SCRIPT_VALUE )
  386. {
  387. m_iEntityQuality = pData->GetQuality();
  388. // Kyle says: this is a horrible hack because AE_UNDEFINED will get stuffed into a uint8 when
  389. // loaded into the item definition, but then read back out into a regular int here.
  390. if ( m_iEntityQuality == (uint8)AE_UNDEFINED )
  391. {
  392. m_iEntityQuality = (int)AE_NORMAL;
  393. }
  394. }
  395. else if ( iQuality == k_unItemQuality_Any )
  396. {
  397. m_iEntityQuality = (int) AE_UNIQUE;
  398. }
  399. else
  400. {
  401. m_iEntityQuality = iQuality;
  402. }
  403. if ( iLevel == AE_USE_SCRIPT_VALUE )
  404. {
  405. m_iEntityLevel = pData->RollItemLevel();
  406. }
  407. else
  408. {
  409. m_iEntityLevel = iLevel;
  410. }
  411. // We made changes to quality, level, etc. so mark the description as dirty.
  412. MarkDescriptionDirty();
  413. }
  414. bool CEconItemView::Init( CEconItem* pItem )
  415. {
  416. Init( pItem->GetDefinitionIndex(), pItem->GetQuality(), pItem->GetItemLevel(), pItem->GetAccountID() );
  417. if ( !IsValid() )
  418. {
  419. return false;
  420. }
  421. SetItemID( pItem->GetItemID() );
  422. SetInventoryPosition( pItem->GetInventoryToken() );
  423. return true;
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Purpose:
  427. //-----------------------------------------------------------------------------
  428. CEconItemView& CEconItemView::operator=( const CEconItemView& src )
  429. {
  430. Cleanup();
  431. m_iItemDefinitionIndex = src.m_iItemDefinitionIndex;
  432. m_iEntityQuality = src.m_iEntityQuality;
  433. m_iEntityLevel = src.m_iEntityLevel;
  434. SetItemID( src.GetItemID() );
  435. m_iInventoryPosition = src.m_iInventoryPosition;
  436. m_bInitialized = src.m_bInitialized;
  437. m_iAccountID = src.m_iAccountID;
  438. m_pNonSOEconItem = src.m_pNonSOEconItem;
  439. #if defined( CLIENT_DLL )
  440. m_bIsTradeItem = src.m_bIsTradeItem;
  441. m_iEntityQuantity = src.m_iEntityQuantity;
  442. m_iRarityOverride = src.m_iRarityOverride;
  443. m_iQualityOverride = src.m_iQualityOverride;
  444. m_unClientFlags = src.m_unClientFlags;
  445. m_unOverrideStyle = src.m_unOverrideStyle;
  446. #endif //#if defined( CLIENT_DLL )
  447. #if defined( CSTRIKE_CLIENT_DLL )
  448. if ( src.m_bInventoryImageRgbaRequested )
  449. {
  450. m_bInventoryImageRgbaRequested = src.m_bInventoryImageRgbaRequested;
  451. m_bInventoryImageTriedCache = src.m_bInventoryImageTriedCache;
  452. m_nInventoryImageRgbaWidth = src.m_nInventoryImageRgbaWidth;
  453. m_nInventoryImageRgbaHeight = src.m_nInventoryImageRgbaHeight;
  454. m_pImageReadyCallback = src.m_pImageReadyCallback;
  455. if ( src.m_inventoryImageRgba.TellPut() > 0 )
  456. {
  457. m_inventoryImageRgba.EnsureCapacity( src.m_inventoryImageRgba.TellPut() );
  458. m_inventoryImageRgba.CopyBuffer( src.m_inventoryImageRgba );
  459. }
  460. else
  461. {
  462. m_inventoryImageRgba.Purge();
  463. }
  464. }
  465. else
  466. {
  467. m_nInventoryImageRgbaWidth = 0;
  468. m_nInventoryImageRgbaHeight = 0;
  469. m_bInventoryImageRgbaRequested = false;
  470. m_bInventoryImageTriedCache = false;
  471. m_inventoryImageRgba.Purge();
  472. m_pImageReadyCallback = NULL;
  473. }
  474. src.DuplicateCustomMaterialsToOther( this );
  475. // copy and addref processors from src
  476. for ( int i = 0; i < src.m_ppVisualsDataProcessors.Count(); i++ )
  477. {
  478. if ( src.m_ppVisualsDataProcessors[ i ] != NULL )
  479. {
  480. m_ppVisualsDataProcessors.AddToTail( src.m_ppVisualsDataProcessors[ i ] );
  481. src.m_ppVisualsDataProcessors[ i ]->AddRef();
  482. }
  483. }
  484. #endif //#if defined( CSTRIKE_CLIENT_DLL )
  485. DestroyAllAttributes();
  486. m_AttributeList = src.m_AttributeList;
  487. m_NetworkedDynamicAttributesForDemos = src.m_NetworkedDynamicAttributesForDemos;
  488. if ( src.m_szCustomNameOverride[0] != '\0' )
  489. {
  490. V_strncpy(m_szCustomNameOverride, src.m_szCustomNameOverride, sizeof( m_szCustomNameOverride ) );
  491. }
  492. V_strncpy( m_szCustomName.GetForModify(), src.m_szCustomName.Get(), MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE );
  493. return *this;
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose:
  497. //-----------------------------------------------------------------------------
  498. bool CEconItemView::operator==( const CEconItemView &other ) const
  499. {
  500. if ( IsValid() != other.IsValid() )
  501. return false;
  502. if ( (GetItemID() > 0 || other.GetItemID() > 0) && GetItemID() != other.GetItemID() )
  503. return false;
  504. if ( GetItemIndex() != other.GetItemIndex() )
  505. return false;
  506. return true;
  507. }
  508. //-----------------------------------------------------------------------------
  509. // Purpose:
  510. //-----------------------------------------------------------------------------
  511. const GameItemDefinition_t *CEconItemView::GetStaticData( void ) const
  512. {
  513. const CEconItemDefinition *pRet = GetItemSchema()->GetItemDefinition( m_iItemDefinitionIndex );
  514. const GameItemDefinition_t *pTypedRet = dynamic_cast<const GameItemDefinition_t *>( pRet );
  515. AssertMsg( pRet == pTypedRet, "Item definition of inappropriate type." );
  516. return pTypedRet;
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Purpose:
  520. //-----------------------------------------------------------------------------
  521. int32 CEconItemView::GetQuality() const
  522. {
  523. #if defined( CLIENT_DLL )
  524. if ( m_iQualityOverride )
  525. return m_iQualityOverride;
  526. #endif
  527. return GetSOCData()
  528. ? GetSOCData()->GetQuality()
  529. #ifdef TF_CLIENT_DLL
  530. : GetFlags() & kEconItemFlagClient_StoreItem
  531. ? AE_UNIQUE
  532. #endif
  533. : ( ( m_iEntityQuality.Get() > int( AE_NORMAL ) ) ? m_iEntityQuality.Get() : int( AE_NORMAL ) );
  534. }
  535. int32 CEconItemView::GetRarity() const
  536. {
  537. #if defined( CLIENT_DLL )
  538. if ( m_iRarityOverride > -1 )
  539. return m_iRarityOverride;
  540. #endif
  541. if ( GetSOCData() && ( GetSOCData()->GetRarity() != k_unItemRarity_Any ) )
  542. {
  543. return GetSOCData()->GetRarity();
  544. }
  545. else
  546. {
  547. int nRarity = GetItemDefinition()->GetRarity();
  548. const CPaintKit *pPaintKit = GetCustomPaintKit();
  549. if ( pPaintKit && pPaintKit->nID != 0 )
  550. {
  551. nRarity = EconRarity_CombinedItemAndPaintRarity( nRarity, pPaintKit->nRarity );
  552. }
  553. else if ( GetItemDefinition()->GetDefinitionIndex() < SCHEMA_BASE_ITEM_MAX )
  554. {
  555. nRarity = 0; // Stock
  556. }
  557. return nRarity;
  558. }
  559. // TODO: This should probably return EconRarity_CombinedItemAndPaintRarity( pItemDef->GetRarity(), pPaintKit->nRarity )
  560. // but there is no known case where the absence of paint consideration is a problem.
  561. // If it ain't broken, doth one fixeth?
  562. }
  563. //-----------------------------------------------------------------------------
  564. // Purpose:
  565. //-----------------------------------------------------------------------------
  566. style_index_t CEconItemView::GetStyle() const
  567. {
  568. return GetItemStyle();
  569. }
  570. //-----------------------------------------------------------------------------
  571. // Purpose:
  572. //-----------------------------------------------------------------------------
  573. uint8 CEconItemView::GetFlags() const
  574. {
  575. uint8 unSOCFlags = GetSOCData() ? GetSOCData()->GetFlags() : 0;
  576. #if !defined( GAME_DLL )
  577. return unSOCFlags | m_unClientFlags;
  578. #else // defined( GAME_DLL )
  579. return unSOCFlags;
  580. #endif // !defined( GAME_DLL )
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Purpose:
  584. //-----------------------------------------------------------------------------
  585. eEconItemOrigin CEconItemView::GetOrigin() const
  586. {
  587. return GetSOCData() ? GetSOCData()->GetOrigin() : kEconItemOrigin_Invalid;
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Purpose:
  591. //-----------------------------------------------------------------------------
  592. uint16 CEconItemView::GetQuantity() const
  593. {
  594. return GetItemQuantity();
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose:
  598. //-----------------------------------------------------------------------------
  599. const char *CEconItemView::GetCustomName() const
  600. {
  601. if ( m_szCustomNameOverride[ 0 ] != '\0' )
  602. {
  603. return m_szCustomNameOverride;
  604. }
  605. // If we have an so cache for this item, use the attribute in it
  606. if ( GetSOCData() )
  607. return GetSOCData()->GetCustomName();
  608. extern ConVar sv_spec_use_tournament_content_standards;
  609. #if defined (CLIENT_DLL)
  610. // If no SO cache, use anything networked from the server or
  611. // null if that string is empty (to support legacy behavior of this function)
  612. if ( *m_szCustomName )
  613. {
  614. if ( CDemoPlaybackParameters_t const *pParameters = engine->GetDemoPlaybackParameters() )
  615. {
  616. if ( pParameters->m_bAnonymousPlayerIdentity )
  617. return NULL;
  618. }
  619. extern ConVar cl_spec_use_tournament_content_standards;
  620. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer( );
  621. if ( ( pLocalPlayer->IsSpectator( ) || pLocalPlayer->IsHLTV( ) ) &&
  622. ( sv_spec_use_tournament_content_standards.GetBool( ) || cl_spec_use_tournament_content_standards.GetBool( ) ) )
  623. return NULL;
  624. return m_szCustomName;
  625. }
  626. #endif
  627. return NULL;
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose:
  631. //-----------------------------------------------------------------------------
  632. const char *CEconItemView::GetCustomDesc() const
  633. {
  634. return GetSOCData() ? GetSOCData()->GetCustomDesc() : NULL;
  635. }
  636. int CEconItemView::GetItemSetIndex() const
  637. {
  638. return GetSOCData() ? GetSOCData()->GetItemSetIndex() : -1;
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Purpose:
  642. //-----------------------------------------------------------------------------
  643. void CEconItemView::Invalidate( void )
  644. {
  645. m_bInitialized = false;
  646. m_iItemDefinitionIndex = m_iItemID = 0;
  647. if ( m_pNonSOEconItem )
  648. {
  649. delete m_pNonSOEconItem;
  650. m_pNonSOEconItem = NULL;
  651. }
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose:
  655. //-----------------------------------------------------------------------------
  656. void CEconItemView::IterateAttributes( class IEconItemAttributeIterator *pIterator ) const
  657. {
  658. Assert( pIterator );
  659. // First, we iterate over the attributes we have local copies of. If we have any attribute
  660. // values here they'll override whatever values we would otherwise have pulled from our
  661. // definition/CEconItem.
  662. for ( int i = 0; i < GetNumAttributes(); i++ )
  663. {
  664. const CEconItemAttribute *pAttrInst = GetAttribute(i);
  665. Assert( pAttrInst );
  666. const CEconItemAttributeDefinition *pAttrDef = pAttrInst->GetStaticData();
  667. if ( !pAttrDef )
  668. continue;
  669. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  670. Assert( pAttrType );
  671. Assert( pAttrType->BSupportsGameplayModificationAndNetworking() );
  672. attribute_data_union_t value;
  673. value.asFloat = pAttrInst->GetValue();
  674. if ( !pAttrType->OnIterateAttributeValue( pIterator, pAttrDef, value ) )
  675. return;
  676. }
  677. // This wraps any other iterator class and will prevent double iteration of any attributes
  678. // that exist on us.
  679. class CEconItemAttributeIterator_EconItemViewWrapper : public IEconItemAttributeIterator
  680. {
  681. public:
  682. CEconItemAttributeIterator_EconItemViewWrapper( const CEconItemView *pEconItemView, IEconItemAttributeIterator *pIterator )
  683. : m_pEconItemView( pEconItemView )
  684. , m_pIterator( pIterator )
  685. {
  686. Assert( m_pEconItemView );
  687. Assert( m_pIterator );
  688. }
  689. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
  690. {
  691. Assert( pAttrDef );
  692. return m_pEconItemView->GetAttributeByDefIndex( pAttrDef->GetDefinitionIndex() )
  693. ? true
  694. : m_pIterator->OnIterateAttributeValue( pAttrDef, value );
  695. }
  696. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value )
  697. {
  698. Assert( pAttrDef );
  699. return m_pEconItemView->GetAttributeByDefIndex( pAttrDef->GetDefinitionIndex() )
  700. ? true
  701. : m_pIterator->OnIterateAttributeValue( pAttrDef, value );
  702. }
  703. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value )
  704. {
  705. Assert( pAttrDef );
  706. return m_pEconItemView->GetAttributeByDefIndex( pAttrDef->GetDefinitionIndex() )
  707. ? true
  708. : m_pIterator->OnIterateAttributeValue( pAttrDef, value );
  709. }
  710. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const Vector& value )
  711. {
  712. Assert( pAttrDef );
  713. return m_pEconItemView->GetAttributeByDefIndex( pAttrDef->GetDefinitionIndex() )
  714. ? true
  715. : m_pIterator->OnIterateAttributeValue( pAttrDef, value );
  716. }
  717. private:
  718. const CEconItemView *m_pEconItemView;
  719. IEconItemAttributeIterator *m_pIterator;
  720. };
  721. CEconItemAttributeIterator_EconItemViewWrapper iteratorWrapper( this, pIterator );
  722. // Next, iterate over our database-backed item if we have one... if we do have a DB
  723. // backing for our item here, that will also feed in the definition attributes.
  724. if ( GetSOCData() )
  725. {
  726. GetSOCData()->IterateAttributes( &iteratorWrapper );
  727. }
  728. #ifdef ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS
  729. else if ( GetItemID() > 0 )
  730. {
  731. // Since there's no persistent data available, try the networked values!
  732. for ( int i = 0; i < m_NetworkedDynamicAttributesForDemos.GetNumAttributes(); i++ )
  733. {
  734. const CEconItemAttribute *pAttrInst = m_NetworkedDynamicAttributesForDemos.GetAttribute(i);
  735. Assert( pAttrInst );
  736. const CEconItemAttributeDefinition *pAttrDef = pAttrInst->GetStaticData();
  737. if ( !pAttrDef )
  738. continue;
  739. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  740. Assert( pAttrType );
  741. attribute_data_union_t value;
  742. value.asFloat = pAttrInst->GetValue();
  743. if ( !pAttrType->OnIterateAttributeValue( pIterator, pAttrDef, value ) )
  744. return;
  745. }
  746. if ( GetStaticData() )
  747. {
  748. GetStaticData()->IterateAttributes( &iteratorWrapper );
  749. }
  750. }
  751. #endif
  752. // If we didn't have a DB backing, we can still iterate over our item definition
  753. // attributes ourselves. This can happen if we're previewing an item in the store, etc.
  754. else if ( GetStaticData() )
  755. {
  756. GetStaticData()->IterateAttributes( &iteratorWrapper );
  757. }
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Purpose:
  761. //-----------------------------------------------------------------------------
  762. void CEconItemView::EnsureDescriptionIsBuilt() const
  763. {
  764. /** Removed for partner depot **/
  765. }
  766. //-----------------------------------------------------------------------------
  767. // Purpose:
  768. //-----------------------------------------------------------------------------
  769. void CEconItemView::MarkDescriptionDirty()
  770. {
  771. /** Removed for partner depot **/
  772. }
  773. //-----------------------------------------------------------------------------
  774. // Purpose:
  775. //-----------------------------------------------------------------------------
  776. void CEconItemView::SetGrayedOutReason( const char *pszGrayedOutReason )
  777. {
  778. /** Removed for partner depot **/
  779. }
  780. //-----------------------------------------------------------------------------
  781. // Purpose:
  782. //-----------------------------------------------------------------------------
  783. int CEconItemView::GetItemQuantity() const
  784. {
  785. CEconItem *pSOCData = GetSOCData();
  786. if ( pSOCData )
  787. {
  788. return pSOCData->GetQuantity();
  789. }
  790. #ifdef CLIENT_DLL
  791. return m_iEntityQuantity;
  792. #else
  793. return 1;
  794. #endif
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose:
  798. //-----------------------------------------------------------------------------
  799. style_index_t CEconItemView::GetItemStyle() const
  800. {
  801. #ifdef CLIENT_DLL
  802. // Are we overriding the backing store style?
  803. if ( m_unOverrideStyle != INVALID_STYLE_INDEX )
  804. return m_unOverrideStyle;
  805. #endif // CLIENT_DLL
  806. // CEconItem *pSOCData = GetSOCData();
  807. // if ( pSOCData )
  808. // return pSOCData->GetStyle();
  809. return INVALID_STYLE_INDEX;
  810. }
  811. #ifdef CLIENT_DLL
  812. //-----------------------------------------------------------------------------
  813. // Purpose:
  814. //-----------------------------------------------------------------------------
  815. void CEconItemView::SetClientItemFlags( uint8 unFlags )
  816. {
  817. // Generally speaking, we have two uses for client flags:
  818. //
  819. // - we don't have a backing store (a real CEconItem) but want to pretend we do
  820. // for purposes of generating tooltips, graying out icons, etc.
  821. //
  822. // - we may or may not have a backing store but want to shove client-specific
  823. // information into the structure -- things like "this is the item being
  824. // actively previewed", etc.
  825. //
  826. // If neither of these two cases is true, then we're going to get unexpected
  827. // behavior where the GC and the client disagree about the item flags and then
  828. // Terrible Things happen. We assert to make sure we're in one of the above cases.
  829. Assert( !GetSOCData() || (unFlags & kEconItemFlags_CheckFlags_AllGCFlags) == 0 );
  830. m_unClientFlags = unFlags;
  831. MarkDescriptionDirty();
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose:
  835. //-----------------------------------------------------------------------------
  836. void CEconItemView::SetItemStyleOverride( style_index_t unNewStyleOverride )
  837. {
  838. // We should only ever override the style on items that don't have a real
  839. // backing store or we'll start getting disagreements about what the client
  840. // wants to happen and what's being stored on the GC. Unfortunately we can't
  841. // assert on this because we do it sometimes when previewing items.
  842. //Assert( !GetSOCData() );
  843. m_unOverrideStyle = unNewStyleOverride;
  844. MarkDescriptionDirty();
  845. }
  846. #endif // CLIENT_DLL
  847. //-----------------------------------------------------------------------------
  848. // Purpose:
  849. //-----------------------------------------------------------------------------
  850. CEconItem *CEconItemView::GetSOCData( void ) const
  851. {
  852. if ( m_pNonSOEconItem )
  853. return m_pNonSOEconItem;
  854. #ifdef CLIENT_DLL
  855. // We need to find the inventory that contains this item. If we're not connected
  856. // to a server, and the owner is the same as the local player, use the local inventory.
  857. // We need to do this for trading, since we are subscribed to the other person's cache.
  858. if ( !engine->IsInGame() && GetSteamIDFromSOID( InventoryManager()->GetLocalInventory()->GetOwner() ).GetAccountID() == m_iAccountID )
  859. return InventoryManager()->GetLocalInventory()->GetSOCDataForItem( GetItemID() );
  860. #endif // CLIENT_DLL
  861. // We're in-game. Find the inventory with our account ID.
  862. CPlayerInventory *pInventory = InventoryManager()->GetInventoryForAccount( m_iAccountID );
  863. #if defined ( CLIENT_DLL )
  864. Assert( !pInventory || pInventory == InventoryManager()->GetLocalInventory() );
  865. #endif
  866. if ( pInventory )
  867. return pInventory->GetSOCDataForItem( GetItemID() );
  868. return NULL;
  869. }
  870. itemid_t CEconItemView::GetFauxItemIDFromDefinitionIndex( void ) const
  871. {
  872. return m_iItemDefinitionIndex
  873. ? CombinedItemIdMakeFromDefIndexAndPaint( m_iItemDefinitionIndex, 0 )
  874. : 0ull; // invalid items cannot represent a faux ItemID
  875. }
  876. // Purpose: Return the model to use for model panels containing this item
  877. //-----------------------------------------------------------------------------
  878. const char *CEconItemView::GetInventoryModel( void )
  879. {
  880. if ( !GetStaticData() )
  881. return NULL;
  882. return GetStaticData()->GetInventoryModel();
  883. }
  884. bool CEconItemView::IsStickerTool( void )
  885. {
  886. const GameItemDefinition_t *pStaticData = GetStaticData();
  887. if ( !pStaticData )
  888. return false;
  889. if ( pStaticData->IsTool() && pStaticData->GetEconTool() && ( pStaticData->GetEconTool()->GetCapabilities() & ITEM_CAP_CAN_STICKER ) != 0 )
  890. return true;
  891. return false;
  892. }
  893. IMaterial *CEconItemView::GetToolStickerMaterial( void )
  894. {
  895. if ( !IsStickerTool() )
  896. return NULL;
  897. uint32 nStickerId = GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 );
  898. if ( nStickerId > 0 && GetItemSchema() && GetItemSchema()->GetStickerKitDefinition( nStickerId ) )
  899. {
  900. char szDesiredStickerMaterialPath[128];
  901. V_snprintf( szDesiredStickerMaterialPath, sizeof(szDesiredStickerMaterialPath),
  902. "materials/models/weapons/customization/stickers/%s.vmt",
  903. GetItemSchema()->GetStickerKitDefinition( nStickerId )->sMaterialPath.String() );
  904. IMaterial *pMatStickerOverride = materials->FindMaterial( szDesiredStickerMaterialPath, TEXTURE_GROUP_OTHER, false );
  905. if ( pMatStickerOverride->IsErrorMaterial() )
  906. {
  907. KeyValues *pSpecificStickerMaterialKeyValues = new KeyValues( "vmt" );
  908. KeyValues::AutoDelete autodelete_pSpecificStickerMaterialKeyValues( pSpecificStickerMaterialKeyValues );
  909. if ( pSpecificStickerMaterialKeyValues->LoadFromFile( g_pFullFileSystem, szDesiredStickerMaterialPath, "GAME" ) )
  910. {
  911. //pSpecificStickerMaterialKeyValues->SetString( "$envmap", "Editor/cube_vertigo" );
  912. //pSpecificStickerMaterialKeyValues->SetString( "$aotexture", "models/weapons/customization/rif_famas/rif_famas_decal_A" );
  913. //KeyValuesDumpAsDevMsg( pSpecificStickerMaterialKeyValues, 2 );
  914. pMatStickerOverride = materials->CreateMaterial( szDesiredStickerMaterialPath, pSpecificStickerMaterialKeyValues );
  915. }
  916. autodelete_pSpecificStickerMaterialKeyValues.Detach();
  917. if ( !pMatStickerOverride->IsErrorMaterial() )
  918. return pMatStickerOverride;
  919. }
  920. }
  921. return NULL;
  922. }
  923. //-----------------------------------------------------------------------------
  924. // Purpose: Return the image to use for model panels containing this item
  925. //-----------------------------------------------------------------------------
  926. const char *CEconItemView::GetInventoryImage( void ) const
  927. {
  928. const GameItemDefinition_t *pStaticData = GetStaticData();
  929. if ( !pStaticData )
  930. return NULL;
  931. const CEconStyleInfo *pStyle = GetStaticData()->GetStyleInfo( GetItemStyle() );
  932. static CSchemaAttributeDefHandle pAttr_AlternateIcon( "alternate icon" );
  933. uint32 unAlternateIcon = 0;
  934. extern bool Helper_IsGraphicTool( const CEconItemDefinition * pEconItemDefinition );
  935. static CSchemaItemDefHandle hItemDefMusicKit( "musickit" );
  936. static CSchemaItemDefHandle hItemDefMusicKitDefault( "musickit_default" );
  937. #ifdef DOTA_DLL
  938. if ( pStaticData->GetCapabilities() & ITEM_CAP_USES_ESSENCE )
  939. {
  940. // Backwards compatibility to eggs, which were implemented before this feature.
  941. return pStaticData->GetAlternateIcon( GetEggColor( this ) );
  942. }
  943. else if ( FindAttribute( pAttr_AlternateIcon, &unAlternateIcon ) )
  944. {
  945. return pStaticData->GetAlternateIcon( unAlternateIcon );
  946. }
  947. else if ( pStyle && pStyle->GetIcon() )
  948. {
  949. return pStaticData->GetAlternateIcon( pStyle->GetIcon() );
  950. }
  951. #else
  952. if ( FindAttribute( pAttr_AlternateIcon, &unAlternateIcon ) )
  953. {
  954. return GetItemSchema()->GetAlternateIcon( unAlternateIcon )->GetInventoryImage();
  955. }
  956. else if ( pStyle && pStyle->GetIcon() )
  957. {
  958. return GetItemSchema()->GetAlternateIcon( pStyle->GetIcon() )->GetInventoryImage();
  959. }
  960. else if ( Helper_IsGraphicTool( GetItemDefinition() ) )
  961. {
  962. uint32 nStickerId = GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 );
  963. if ( const CStickerKit *pStickerKitDef = ( ( nStickerId > 0 ) ? GetItemSchema()->GetStickerKitDefinition( nStickerId ) : NULL ) )
  964. {
  965. char const *szResult = pStickerKitDef->GetIconURLLarge();
  966. // exclude code providing a different image for client UI, client will color-multiply on its own
  967. #if SPRAY_TINT_IMAGE_FOR_CLIENT_UI
  968. static CSchemaAttributeDefHandle pAttr_SprayTintID( "spray tint id" );
  969. uint32 unSprayTintID = 0;
  970. if ( pAttr_SprayTintID && FindAttribute( pAttr_SprayTintID, &unSprayTintID ) && unSprayTintID )
  971. {
  972. unSprayTintID = CombinedTintIDGetHSVID( unSprayTintID );
  973. if ( ! ( char * ) m_autoptrInventoryImageGeneratedPath )
  974. m_autoptrInventoryImageGeneratedPath.reset( new char[ MAX_PATH ] );
  975. int nImagePathLen = V_strlen( szResult );
  976. Assert( nImagePathLen + 4 < MAX_PATH );
  977. if ( ( nImagePathLen > 6 ) && !V_stricmp( szResult + nImagePathLen - 6, "_large" ) )
  978. {
  979. V_snprintf( m_autoptrInventoryImageGeneratedPath, MAX_PATH, "%.*s_%u_large", nImagePathLen - 6, szResult, unSprayTintID );
  980. }
  981. else
  982. {
  983. V_snprintf( m_autoptrInventoryImageGeneratedPath, MAX_PATH, "%s_%u", szResult, unSprayTintID );
  984. }
  985. szResult = m_autoptrInventoryImageGeneratedPath;
  986. }
  987. #endif
  988. return szResult;
  989. }
  990. }
  991. else if (
  992. ( hItemDefMusicKit && GetItemDefinition()->GetDefinitionIndex() == hItemDefMusicKit->GetDefinitionIndex() ) ||
  993. ( hItemDefMusicKitDefault && GetItemDefinition()->GetDefinitionIndex() == hItemDefMusicKitDefault->GetDefinitionIndex() )
  994. )
  995. {
  996. static const CEconItemAttributeDefinition *pAttr_MusicID = GetItemSchema()->GetAttributeDefinitionByName( "music id" );
  997. uint32 unMusicID;
  998. if ( FindAttribute( pAttr_MusicID, &unMusicID ) )
  999. {
  1000. const CEconMusicDefinition *pMusicDef = GetItemSchema()->GetMusicDefinition( unMusicID );
  1001. if ( pMusicDef )
  1002. {
  1003. return pMusicDef->GetInventoryImage();
  1004. }
  1005. }
  1006. }
  1007. #endif
  1008. return GetStaticData()->GetInventoryImage();
  1009. }
  1010. // Does this item use a custom generated image due to a custom paint and wear
  1011. bool CEconItemView::HasGeneratedInventoryImage( void ) const
  1012. {
  1013. return GetCustomPaintKitIndex() != 0 && ( GetCustomPaintKitWear() != 0.0f || GetCustomPaintKitSeed() != 0 );
  1014. }
  1015. //-----------------------------------------------------------------------------
  1016. // Purpose: Return the drawing data for the image to use for model panels containing this item
  1017. //-----------------------------------------------------------------------------
  1018. bool CEconItemView::GetInventoryImageData( int *iPosition, int *iSize )
  1019. {
  1020. if ( !GetStaticData() )
  1021. return false;
  1022. for ( int i = 0; i < 2; i++ )
  1023. {
  1024. iPosition[i] = GetStaticData()->GetInventoryImagePosition(i);
  1025. iSize[i] = GetStaticData()->GetInventoryImageSize(i);
  1026. }
  1027. return true;
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose: Return the image to use for model panels containing this item
  1031. //-----------------------------------------------------------------------------
  1032. const char *CEconItemView::GetInventoryOverlayImage( int idx )
  1033. {
  1034. if ( !GetStaticData() )
  1035. return NULL;
  1036. return GetStaticData()->GetInventoryOverlayImage( idx );
  1037. }
  1038. int CEconItemView::GetInventoryOverlayImageCount( void )
  1039. {
  1040. if ( !GetStaticData() )
  1041. return 0;
  1042. return GetStaticData()->GetInventoryOverlayImageCount();
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. // Purpose: Return the model to use when displaying this model on the player character model, if any
  1046. //-----------------------------------------------------------------------------
  1047. const char *CEconItemView::GetPlayerDisplayModel( int iClass ) const
  1048. {
  1049. const CEconItemDefinition *pDef = GetStaticData();
  1050. if ( !pDef )
  1051. return NULL;
  1052. // If we have styles, give the style system a chance to change the mesh used for this
  1053. // player class.
  1054. if ( pDef->GetNumStyles() )
  1055. {
  1056. const CEconStyleInfo *pStyle = pDef->GetStyleInfo( GetItemStyle() );
  1057. // It's possible to get back a NULL pStyle if GetItemStyle() returns INVALID_STYLE_INDEX.
  1058. if ( pStyle )
  1059. {
  1060. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  1061. // TF styles support per-class models.
  1062. const CTFStyleInfo *pTFStyle = assert_cast<const CTFStyleInfo *>( pStyle );
  1063. if ( pTFStyle->GetPlayerDisplayModel( iClass ) )
  1064. return pTFStyle->GetPlayerDisplayModel( iClass );
  1065. #endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  1066. if ( pStyle->GetBasePlayerDisplayModel() )
  1067. return pStyle->GetBasePlayerDisplayModel();
  1068. }
  1069. }
  1070. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  1071. // If we don't have a style, we still a couple potential overrides.
  1072. if ( iClass >= 0 && iClass < LOADOUT_COUNT )
  1073. {
  1074. // We don't support overriding meshes in the visuals section, but we might still be overriding
  1075. // the model for each class at the schema level.
  1076. const CTFItemDefinition *pTFDef = dynamic_cast<const CTFItemDefinition *>( pDef );
  1077. if ( pTFDef )
  1078. {
  1079. const char *pszModel = pTFDef->GetPlayerDisplayModel(iClass);
  1080. if ( pszModel && pszModel[0] )
  1081. return pszModel;
  1082. }
  1083. }
  1084. #endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  1085. return pDef->GetBasePlayerDisplayModel();
  1086. }
  1087. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  1088. //-----------------------------------------------------------------------------
  1089. // Purpose:
  1090. //-----------------------------------------------------------------------------
  1091. int CEconItemView::GetSkin() const
  1092. {
  1093. // Do we have a style set?
  1094. if ( GetStaticData()->GetNumStyles() )
  1095. return GetStaticData()->GetStyleSkin( GetItemStyle() );
  1096. // Do we have per-team skins set?
  1097. const AssetInfo *pVisData = GetStaticData()->GetAssetInfo();
  1098. if ( pVisData )
  1099. return pVisData->iSkin;
  1100. return 0;
  1101. }
  1102. #endif // defined(CLIENT_DLL) || defined(GAME_DLL)
  1103. //-----------------------------------------------------------------------------
  1104. // Purpose:
  1105. //-----------------------------------------------------------------------------
  1106. const char *CEconItemView::GetIconDisplayModel()
  1107. {
  1108. const CEconItemDefinition *pData = GetStaticData();
  1109. if ( !pData )
  1110. return NULL;
  1111. return pData->GetIconDisplayModel();
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose:
  1115. //-----------------------------------------------------------------------------
  1116. const char *CEconItemView::GetPedestalDisplayModel()
  1117. {
  1118. const CEconItemDefinition *pData = GetStaticData();
  1119. if ( !pData )
  1120. return NULL;
  1121. static CSchemaItemDefHandle hItemDefMusicKit( "musickit" );
  1122. static CSchemaItemDefHandle hItemDefMusicKitDefault( "musickit_default" );
  1123. if (
  1124. ( hItemDefMusicKit && GetItemDefinition()->GetDefinitionIndex() == hItemDefMusicKit->GetDefinitionIndex() ) ||
  1125. ( hItemDefMusicKitDefault && GetItemDefinition()->GetDefinitionIndex() == hItemDefMusicKitDefault->GetDefinitionIndex() )
  1126. )
  1127. {
  1128. static const CEconItemAttributeDefinition *pAttr_MusicID = GetItemSchema()->GetAttributeDefinitionByName( "music id" );
  1129. uint32 unMusicID;
  1130. if ( FindAttribute( pAttr_MusicID, &unMusicID ) )
  1131. {
  1132. const CEconMusicDefinition *pMusicDef = GetItemSchema()->GetMusicDefinition( unMusicID );
  1133. if ( pMusicDef )
  1134. {
  1135. return pMusicDef->GetPedestalDisplayModel();
  1136. }
  1137. }
  1138. }
  1139. return pData->GetPedestalDisplayModel();
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Purpose:
  1143. //-----------------------------------------------------------------------------
  1144. const char *CEconItemView::GetBuyMenuDisplayModel()
  1145. {
  1146. const CEconItemDefinition *pData = GetStaticData();
  1147. if ( !pData )
  1148. return NULL;
  1149. return pData->GetBuyMenuDisplayModel();
  1150. }
  1151. //-----------------------------------------------------------------------------
  1152. // Purpose:
  1153. //-----------------------------------------------------------------------------
  1154. const char *CEconItemView::GetWorldDroppedModel()
  1155. {
  1156. const CEconItemDefinition *pData = GetStaticData();
  1157. if ( !pData )
  1158. return NULL;
  1159. return pData->GetWorldDroppedModel();
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. // Purpose:
  1163. //-----------------------------------------------------------------------------
  1164. const char *CEconItemView::GetMagazineModel()
  1165. {
  1166. const CEconItemDefinition *pData = GetStaticData();
  1167. if ( !pData )
  1168. return NULL;
  1169. return pData->GetMagazineModel();
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // Purpose:
  1173. //-----------------------------------------------------------------------------
  1174. const char *CEconItemView::GetScopeLensMaskModel()
  1175. {
  1176. const CEconItemDefinition *pData = GetStaticData();
  1177. if ( !pData )
  1178. return NULL;
  1179. return pData->GetScopeLensMaskModel();
  1180. }
  1181. //-----------------------------------------------------------------------------
  1182. // Purpose:
  1183. //-----------------------------------------------------------------------------
  1184. const char *CEconItemView::GetStatTrakModelByType( int nStatTrakType )
  1185. {
  1186. const CEconItemDefinition *pData = GetStaticData();
  1187. if ( !pData )
  1188. return NULL;
  1189. return pData->GetStatTrakModelByType( nStatTrakType );
  1190. }
  1191. //-----------------------------------------------------------------------------
  1192. // Purpose:
  1193. //-----------------------------------------------------------------------------
  1194. const char *CEconItemView::GetUidModel()
  1195. {
  1196. const CEconItemDefinition *pData = GetStaticData();
  1197. if ( !pData )
  1198. return NULL;
  1199. return pData->GetUidModel();
  1200. }
  1201. // Purpose:
  1202. #if defined(CSTRIKE_CLIENT_DLL)
  1203. const char *CEconItemView::GetStickerSlotModelBySlotIndex( int nIndex )
  1204. {
  1205. const CEconItemDefinition *pData = GetStaticData();
  1206. if ( !pData )
  1207. return NULL;
  1208. return pData->GetStickerSlotModelBySlotIndex( nIndex );
  1209. }
  1210. int CEconItemView::GetNumSupportedStickerSlots( void )
  1211. {
  1212. const CEconItemDefinition *pData = GetStaticData();
  1213. if ( !pData )
  1214. return 0;
  1215. return pData->GetNumSupportedStickerSlots();
  1216. }
  1217. Vector CEconItemView::GetStickerSlotWorldProjectionStartBySlotIndex( int nIndex )
  1218. {
  1219. const CEconItemDefinition *pData = GetStaticData();
  1220. if ( !pData )
  1221. return Vector(0,0,0);
  1222. return pData->GetStickerSlotWorldProjectionStartBySlotIndex( nIndex );
  1223. }
  1224. Vector CEconItemView::GetStickerSlotWorldProjectionEndBySlotIndex( int nIndex )
  1225. {
  1226. const CEconItemDefinition *pData = GetStaticData();
  1227. if ( !pData )
  1228. return Vector(0,0,0);
  1229. return pData->GetStickerSlotWorldProjectionEndBySlotIndex( nIndex );
  1230. }
  1231. const char *CEconItemView::GetStickerWorldModelBoneParentNameBySlotIndex( int nIndex )
  1232. {
  1233. const CEconItemDefinition *pData = GetStaticData();
  1234. if ( !pData )
  1235. return NULL;
  1236. return pData->GetStickerWorldModelBoneParentNameBySlotIndex( nIndex );
  1237. }
  1238. const char *CEconItemView::GetStickerSlotMaterialBySlotIndex( int nIndex )
  1239. {
  1240. const CEconItemDefinition *pData = GetStaticData();
  1241. if ( !pData )
  1242. return NULL;
  1243. return pData->GetStickerSlotMaterialBySlotIndex( nIndex );
  1244. }
  1245. IMaterial *CEconItemView::GetStickerIMaterialBySlotIndex( int nIndex, bool bThirdPerson )
  1246. {
  1247. FOR_EACH_VEC( m_pStickerMaterials, i )
  1248. {
  1249. if (m_pStickerMaterials[i].m_nSlotIndex == nIndex)
  1250. {
  1251. if ( bThirdPerson == true )
  1252. {
  1253. return m_pStickerMaterials[i].m_pMaterialReferenceThirdPerson;
  1254. }
  1255. else
  1256. {
  1257. return m_pStickerMaterials[i].m_pMaterialReferenceFirstPerson;
  1258. }
  1259. }
  1260. }
  1261. return NULL;
  1262. }
  1263. #endif //(CSTRIKE_CLIENT_DLL)
  1264. //-----------------------------------------------------------------------------
  1265. // Purpose:
  1266. //-----------------------------------------------------------------------------
  1267. const char *CEconItemView::GetWorldDisplayModel()
  1268. {
  1269. const CEconItemDefinition *pData = GetStaticData();
  1270. if ( !pData )
  1271. return NULL;
  1272. return pData->GetWorldDisplayModel();
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. // Purpose:
  1276. //-----------------------------------------------------------------------------
  1277. const char *CEconItemView::GetExtraWearableModel()
  1278. {
  1279. const CEconItemDefinition *pData = GetStaticData();
  1280. if ( !pData )
  1281. return NULL;
  1282. return pData->GetExtraWearableModel();
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. // Purpose:
  1286. //-----------------------------------------------------------------------------
  1287. int CEconItemView::GetQualityParticleType()
  1288. {
  1289. static attachedparticlesystem_t *pSparkleSystem = GetItemSchema()->FindAttributeControlledParticleSystem( "community_sparkle" );
  1290. CEconItem* pItem = GetSOCData();
  1291. if ( !pItem )
  1292. return 0;
  1293. if( GetSOCData()->GetQuality() == AE_SELFMADE || GetSOCData()->GetQuality() == AE_COMMUNITY )
  1294. return pSparkleSystem ? pSparkleSystem->nSystemID : 0;
  1295. else
  1296. return 0;
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // Purpose: Return the animation set that this item wants the player to use (ie., melee, item1, pda)
  1300. //-----------------------------------------------------------------------------
  1301. int CEconItemView::GetAnimationSlot( void )
  1302. {
  1303. if ( !GetStaticData() )
  1304. return -1;
  1305. #if defined( CSTRIKE_DLL ) || defined( CSTRIKE_GC_DLL )
  1306. return -1;
  1307. #else
  1308. return GetStaticData()->GetAnimSlot();
  1309. #endif
  1310. }
  1311. //-----------------------------------------------------------------------------
  1312. // Purpose: Return an int that indicates whether the item should be dropped from a dead owner.
  1313. //-----------------------------------------------------------------------------
  1314. int CEconItemView::GetDropType( void )
  1315. {
  1316. if ( !GetStaticData() )
  1317. return 0;
  1318. return GetStaticData()->GetDropType();
  1319. }
  1320. //-----------------------------------------------------------------------------
  1321. // Purpose:
  1322. //-----------------------------------------------------------------------------
  1323. void CEconItemView::DestroyAllAttributes( void )
  1324. {
  1325. m_AttributeList.DestroyAllAttributes();
  1326. m_NetworkedDynamicAttributesForDemos.DestroyAllAttributes();
  1327. NetworkStateChanged();
  1328. MarkDescriptionDirty();
  1329. }
  1330. #if defined ( GAME_DLL )
  1331. void CEconItemView::UpdateNetworkedCustomName()
  1332. {
  1333. const char* szName = GetSOCData() ? GetSOCData()->GetCustomName() : NULL;
  1334. if ( szName )
  1335. {
  1336. V_strncpy( m_szCustomName.GetForModify(), szName, MAX_ITEM_CUSTOM_NAME_DATABASE_SIZE );
  1337. }
  1338. }
  1339. #endif
  1340. // Done once, the first time need these values, since new KillEater attributes cannot be added during play
  1341. //
  1342. void CEconItemView::GenerateKillEaterTypeVector()
  1343. {
  1344. m_vCachedKillEaterTypes.RemoveAll();
  1345. m_vCachedKillEaterValues.RemoveAll();
  1346. for ( int i = 0; i < GetKillEaterAttrPairCount(); i++ )
  1347. {
  1348. const CEconItemAttributeDefinition *pScoreTypeAttribDef = GetKillEaterAttrPair_Type(i);
  1349. if ( !pScoreTypeAttribDef )
  1350. continue;
  1351. attrib_value_t nValue;
  1352. if ( FindAttribute( pScoreTypeAttribDef, &nValue ) )
  1353. {
  1354. m_vCachedKillEaterTypes.Insert( nValue );
  1355. }
  1356. }
  1357. }
  1358. void CEconItemView::GetKillEaterTypes( CUtlSortVector<uint32> &types )
  1359. {
  1360. if ( !m_bKillEaterTypesCached )
  1361. {
  1362. GenerateKillEaterTypeVector();
  1363. m_bKillEaterTypesCached = true;
  1364. }
  1365. types = m_vCachedKillEaterTypes;
  1366. return;
  1367. }
  1368. int32 CEconItemView::GetKillEaterValueByType( uint32 uKillEaterType )
  1369. {
  1370. uint32 uiThisSectionOfCodeMightHaveBugs = 1;
  1371. /*
  1372. BUG - BUG - BUG - BUG - BUG - BUG
  1373. There are a bunch of bugs with the way StatTrak values are networked.
  1374. I fixed it in shipped code, but cannot back merge the fix due to how
  1375. concepts changed in trunk. Together with additional StatTrak module
  1376. and new attribute networking it's highly likely that this system needs
  1377. to be rewritten. If somebody integrates this to rel and sees this huge
  1378. diff then make sure you test all combinations of following:
  1379. Weapon Type Test Cases
  1380. ------------------- -----------------
  1381. non-StatTrak weapon live match, you playing with your own weapon
  1382. StatTrak weapon with 0 kills live match, somebody else on TEAM_SPECTATOR watching you
  1383. StatTrak weapon with >0 kills live match, watching via GOTV master connection on TV port of active game server
  1384. StatTrak weapon getting a kill from 0 live match, watching via GOTV relay, relay connected to GOTV master
  1385. StatTrak weapon with >0 kills getting a kill playing back GOTV demo while logged in to Steam as your own account
  1386. playing back GOTV demo while logged in to Steam as a different account
  1387. all the above cases, but StatTrak weapon
  1388. wielded by non-owner
  1389. Change: 1958395
  1390. Date: 10/18/2013 2:52:36 PM
  1391. Client: vitaliy_valve_csgo_work_2012
  1392. User: vitaliy
  1393. Status: submitted
  1394. Type: public
  1395. Description:
  1396. [ CSGO - StatTrak's GOTV and Demos ]
  1397. Fixed different code paths that were incorrectly
  1398. handling bitpatterns of stattrak values.
  1399. When networking -1 value as only 20 bits on the
  1400. recieving side we would not get -1, but rather some
  1401. large 20-bit number and that was causing bad display.
  1402. Also on GOTV relays we wouldn't have the SO caches
  1403. of players and we were incorrectly sending bitpattern
  1404. for the fallback value through a bunch of broken attrlist
  1405. code that would on the display end get float bit pattern
  1406. into an integer pointer resulting in a garbage number.
  1407. Now StatTrak guns seem to display all correct values
  1408. in game, in GOTV demos, on GOTV masters and on GOTV
  1409. relays.
  1410. Also increased streams count to 6 for new UI.
  1411. JobStatus:
  1412. Jobs:
  1413. Files:
  1414. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/client/cstrike15/Scaleform/HUD/sfhudweaponpanel.cpp#22
  1415. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/client/cstrike15/Scaleform/components/scaleformcomponent_streams.cpp#6
  1416. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/shared/econ/econ_entity.cpp#15
  1417. BUG - BUG - BUG - BUG - BUG - BUG
  1418. BUG - BUG - BUG - BUG - BUG - BUG
  1419. There are a bunch of bugs with the way StatTrak values are networked.
  1420. I fixed it in shipped code, but cannot back merge the fix due to how
  1421. concepts changed in trunk. Together with additional StatTrak module
  1422. and new attribute networking it's highly likely that this system needs
  1423. to be rewritten. If somebody integrates this to rel and sees this huge
  1424. diff then make sure you test all combinations of following:
  1425. Weapon Type Test Cases
  1426. ------------------- -----------------
  1427. non-StatTrak weapon live match, you playing with your own weapon
  1428. StatTrak weapon with 0 kills live match, somebody else on TEAM_SPECTATOR watching you
  1429. StatTrak weapon with >0 kills live match, watching via GOTV master connection on TV port of active game server
  1430. StatTrak weapon getting a kill from 0 live match, watching via GOTV relay, relay connected to GOTV master
  1431. StatTrak weapon with >0 kills getting a kill playing back GOTV demo while logged in to Steam as your own account
  1432. playing back GOTV demo while logged in to Steam as a different account
  1433. all the above cases, but StatTrak weapon
  1434. wielded by non-owner
  1435. Change: 1958395
  1436. Date: 10/18/2013 2:52:36 PM
  1437. Client: vitaliy_valve_csgo_work_2012
  1438. User: vitaliy
  1439. Status: submitted
  1440. Type: public
  1441. Description:
  1442. [ CSGO - StatTrak's GOTV and Demos ]
  1443. Fixed different code paths that were incorrectly
  1444. handling bitpatterns of stattrak values.
  1445. When networking -1 value as only 20 bits on the
  1446. recieving side we would not get -1, but rather some
  1447. large 20-bit number and that was causing bad display.
  1448. Also on GOTV relays we wouldn't have the SO caches
  1449. of players and we were incorrectly sending bitpattern
  1450. for the fallback value through a bunch of broken attrlist
  1451. code that would on the display end get float bit pattern
  1452. into an integer pointer resulting in a garbage number.
  1453. Now StatTrak guns seem to display all correct values
  1454. in game, in GOTV demos, on GOTV masters and on GOTV
  1455. relays.
  1456. Also increased streams count to 6 for new UI.
  1457. JobStatus:
  1458. Jobs:
  1459. Files:
  1460. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/client/cstrike15/Scaleform/HUD/sfhudweaponpanel.cpp#22
  1461. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/client/cstrike15/Scaleform/components/scaleformcomponent_streams.cpp#6
  1462. //depot/Valve/branch/cstrike15_pcbeta/source/cstrike15/src/game/shared/econ/econ_entity.cpp#15
  1463. BUG - BUG - BUG - BUG - BUG - BUG
  1464. */
  1465. ++ uiThisSectionOfCodeMightHaveBugs;
  1466. CEconItem *pSOItem = GetSOCData();
  1467. if ( pSOItem && m_nKillEaterValuesCacheFrame >= pSOItem->GetSOUpdateFrame() ) // The SO cache has not been recently updated
  1468. {
  1469. // ..so we return our cached values
  1470. CUtlHashtable<uint32, int32>::handle_t hh = m_vCachedKillEaterValues.Find( uKillEaterType );
  1471. if ( m_vCachedKillEaterValues.IsValidHandle( hh ) )
  1472. return m_vCachedKillEaterValues.Element( hh );
  1473. }
  1474. #ifdef CLIENT_DLL
  1475. pSOItem = 0;
  1476. #endif
  1477. // Only use fallback if there's no SO cache!
  1478. int32 nKillEater = -1;
  1479. // TODO: This function does not update the killeater count after each kill; rather it only updates when the weapon
  1480. // is instantiated in the world (buying)
  1481. for ( int32 i = 0; i < GetKillEaterAttrPairCount(); i++ )
  1482. {
  1483. const CEconItemAttributeDefinition *pKillEaterAltScoreTypeAttrDef = GetKillEaterAttrPair_Type( i );
  1484. if ( !pKillEaterAltScoreTypeAttrDef )
  1485. continue;
  1486. attrib_value_t unValue;
  1487. if ( !FindAttribute( pKillEaterAltScoreTypeAttrDef, &unValue ) )
  1488. continue;
  1489. // If this isn't the type we're tracking, ignore it
  1490. if ( unValue != uKillEaterType )
  1491. continue;
  1492. const CEconItemAttributeDefinition *pKillEaterAltAttrDef = GetKillEaterAttrPair_Score( i );
  1493. if ( pKillEaterAltAttrDef )
  1494. {
  1495. // To get live attribute changes we need to get them from the SOCache because the instance of EconItemView won't have them until we spawn a new copy.
  1496. attrib_value_t unKillEaterAltScore = 0;
  1497. if ( pSOItem )
  1498. {
  1499. if ( pSOItem->FindAttribute( pKillEaterAltAttrDef, &unKillEaterAltScore ) )
  1500. {
  1501. nKillEater = unKillEaterAltScore;
  1502. }
  1503. }
  1504. else
  1505. {
  1506. if ( FindAttribute( pKillEaterAltAttrDef, &unKillEaterAltScore ) )
  1507. {
  1508. // The fallback might be larger
  1509. nKillEater = Max( nKillEater, (int32)unKillEaterAltScore );
  1510. }
  1511. }
  1512. break;
  1513. }
  1514. }
  1515. if ( !pSOItem )
  1516. {
  1517. // Don't cache when playing back from networked dynamic attributes
  1518. m_vCachedKillEaterValues.Remove( uKillEaterType );
  1519. m_vCachedKillEaterValues.Insert( uKillEaterType, nKillEater );
  1520. }
  1521. m_nKillEaterValuesCacheFrame = gpGlobals->framecount;
  1522. return nKillEater;
  1523. }
  1524. #if defined(CSTRIKE_CLIENT_DLL)
  1525. IVisualsDataProcessor *CEconItemView::GetVisualsDataProcessorByName( const char* szName ) const
  1526. {
  1527. FOR_EACH_VEC( m_ppVisualsDataProcessors, i )
  1528. {
  1529. IVisualsDataProcessor* pVDP = m_ppVisualsDataProcessors[ i ];
  1530. if ( V_strcmp( pVDP->GetOriginalMaterialBaseName(), szName ) == 0 )
  1531. return pVDP;
  1532. }
  1533. return NULL;
  1534. }
  1535. void CEconItemView::CreateCustomClothingMaterials( const char *pchSkinIdent, int nSlotId, int nTeam, bool bIgnorePicMip, CompositeTextureSize_t diffuseTextureSize )
  1536. {
  1537. int nPaintKit = GetCustomPaintKitIndex();
  1538. if ( nPaintKit == 0 ) // default paintkit, no need to composite
  1539. return;
  1540. if ( !GetPlayerDisplayModel( 0 ) )
  1541. {
  1542. AssertMsg1( false, "Failed to GetPlayerDisplayModel for %s.", pchSkinIdent );
  1543. return;
  1544. }
  1545. //read in paint kit
  1546. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinition( nPaintKit );
  1547. if ( !pPaintKit )
  1548. {
  1549. AssertMsg2( false, "Failed to find paintkit index %i for %s.", nPaintKit, pchSkinIdent);
  1550. return;
  1551. }
  1552. MDLHandle_t modelHandle = mdlcache->FindMDL( GetPlayerDisplayModel( 0 ) );
  1553. //MDLHandle_t modelHandle = mdlcache->FindMDL( GetWorldDisplayModel() );
  1554. if ( modelHandle == MDLHANDLE_INVALID )
  1555. {
  1556. AssertMsg1( false, "Failed to find player model handle for %s.", pchSkinIdent );
  1557. return;
  1558. }
  1559. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( modelHandle );
  1560. int nSeed = GetCustomPaintKitSeed();
  1561. float flWear = GetCustomPaintKitWear( 0 );
  1562. const CUtlVector< WeaponPaintableMaterial_t > *pPaintData = GetStaticData()->GetPaintData();
  1563. int nNumMaterialsToPaint = pPaintData->Count();
  1564. for ( int nCustomMaterialIndex = 0; nCustomMaterialIndex < nNumMaterialsToPaint; nCustomMaterialIndex++ )
  1565. {
  1566. CCSClothingVisualsDataCompare clothingCompareObject;
  1567. clothingCompareObject.m_nIndex = nPaintKit;
  1568. clothingCompareObject.m_nSeed = nSeed;
  1569. clothingCompareObject.m_flWear = flWear;
  1570. clothingCompareObject.m_nModelID = GetItemIndex();
  1571. clothingCompareObject.m_nLOD = 0;
  1572. clothingCompareObject.m_nTeamId = -1; // may need this later to differentiate teams
  1573. clothingCompareObject.m_bMirrorPattern = (*pPaintData)[ nCustomMaterialIndex ].m_bMirrorPattern;
  1574. clothingCompareObject.m_nMaterialId = nCustomMaterialIndex;
  1575. CCSClothingVisualsDataProcessor* pVisualsDataProcessor = new CCSClothingVisualsDataProcessor( Move(clothingCompareObject), &( (*pPaintData)[ nCustomMaterialIndex ] ), "CustomCharacter" );
  1576. bool bCreatedMaterial = false;
  1577. if ( pVisualsDataProcessor->HasCustomMaterial() )
  1578. {
  1579. // find the material in the models materials to get its index (used for overriding)
  1580. bool bFound = false;
  1581. int nModelMaterialIndex;
  1582. char szBaseName[ MAX_PATH ];
  1583. for ( nModelMaterialIndex = 0; nModelMaterialIndex < pStudioHdr->numtextures; nModelMaterialIndex++ )
  1584. {
  1585. mstudiotexture_t *pTexture = pStudioHdr->pTexture( nModelMaterialIndex );
  1586. V_FileBase( pTexture->pszName(), szBaseName, sizeof( szBaseName ) );
  1587. if ( V_stricmp( szBaseName, pVisualsDataProcessor->GetOriginalMaterialBaseName() ) == 0 )
  1588. {
  1589. bFound = true;
  1590. break;
  1591. }
  1592. }
  1593. if ( !bFound )
  1594. {
  1595. DevMsg( "Original material not found! Name: %s \n", pVisualsDataProcessor->GetOriginalMaterialBaseName() );
  1596. }
  1597. else
  1598. {
  1599. m_ppVisualsDataProcessors.AddToTail( pVisualsDataProcessor );
  1600. pVisualsDataProcessor->AddRef();
  1601. KeyValues *pVMTKeyValues = pVisualsDataProcessor->GenerateCustomMaterialKeyValues();
  1602. Assert( pVMTKeyValues );
  1603. CUtlVector< SCompositeTextureInfo > vecTextureInfo;
  1604. int nIndex = vecTextureInfo.AddToTail();
  1605. vecTextureInfo[nIndex].m_size = diffuseTextureSize;
  1606. vecTextureInfo[nIndex].m_format = COMPOSITE_TEXTURE_FORMAT_DXT5;
  1607. vecTextureInfo[nIndex].m_nMaterialParamID = MATERIAL_PARAM_ID_BASE_DIFFUSE_TEXTURE;
  1608. vecTextureInfo[nIndex].m_bSRGB = true;
  1609. vecTextureInfo[nIndex].m_pVisualsDataProcessor = pVisualsDataProcessor;
  1610. if (pVMTKeyValues->FindKey("$bumpmap", false))
  1611. {
  1612. nIndex = vecTextureInfo.AddToTail();
  1613. vecTextureInfo[nIndex].m_size = diffuseTextureSize;
  1614. vecTextureInfo[nIndex].m_format = COMPOSITE_TEXTURE_FORMAT_DXT5;
  1615. vecTextureInfo[nIndex].m_nMaterialParamID = MATERIAL_PARAM_ID_BUMP_MAP;
  1616. vecTextureInfo[nIndex].m_bSRGB = false;
  1617. vecTextureInfo[nIndex].m_pVisualsDataProcessor = pVisualsDataProcessor;
  1618. }
  1619. if (pVMTKeyValues->FindKey("$masks1", false))
  1620. {
  1621. nIndex = vecTextureInfo.AddToTail();
  1622. vecTextureInfo[nIndex].m_size = diffuseTextureSize;
  1623. vecTextureInfo[nIndex].m_format = COMPOSITE_TEXTURE_FORMAT_DXT5;
  1624. vecTextureInfo[nIndex].m_nMaterialParamID = MATERIAL_PARAM_ID_MASKS1_MAP;
  1625. vecTextureInfo[nIndex].m_bSRGB = false;
  1626. vecTextureInfo[nIndex].m_pVisualsDataProcessor = pVisualsDataProcessor;
  1627. }
  1628. ICustomMaterial *pCustomMaterial = g_pMaterialSystem->GetCustomMaterialManager()->GetOrCreateCustomMaterial( pVMTKeyValues, vecTextureInfo, bIgnorePicMip );
  1629. delete pVMTKeyValues; // copied inside GetCustomMaterial, no longer needed
  1630. if ( pCustomMaterial )
  1631. {
  1632. SetCustomMaterial( pCustomMaterial, nModelMaterialIndex );
  1633. bCreatedMaterial = true;
  1634. }
  1635. }
  1636. }
  1637. pVisualsDataProcessor->Release();
  1638. }
  1639. mdlcache->Release( modelHandle );
  1640. }
  1641. void CEconItemView::SetCustomNameOverride( const char *pszCustomName )
  1642. {
  1643. V_strncpy( m_szCustomNameOverride, pszCustomName, sizeof( m_szCustomNameOverride ) );
  1644. }
  1645. bool CEconItemView::ItemHasAnyStickersApplied( void )
  1646. {
  1647. return ( GetNumSupportedStickerSlots() > 0 && m_pStickerMaterials.Count() > 0 );
  1648. }
  1649. bool CEconItemView::ItemHasAnyFreeStickerSlots( void )
  1650. {
  1651. return ( GetNumSupportedStickerSlots() != m_pStickerMaterials.Count() );
  1652. }
  1653. int CEconItemView::GetStickerSlotFirstFreeFromIndex( int nIndex )
  1654. {
  1655. if ( !ItemHasAnyFreeStickerSlots() )
  1656. return -1;
  1657. for ( int i=0; i<=GetNumSupportedStickerSlots(); i++ )
  1658. {
  1659. if ( nIndex >= GetNumSupportedStickerSlots() )
  1660. nIndex = 0;
  1661. if ( !GetStickerAttributeBySlotIndexInt( nIndex, k_EStickerAttribute_ID, 0 ) )
  1662. return nIndex;
  1663. nIndex++;
  1664. }
  1665. return -1;
  1666. }
  1667. #ifdef _DEBUG
  1668. ConVar stickers_debug_material_spew( "stickers_debug_material_spew", "0", FCVAR_DEVELOPMENTONLY, "Spew generated sticker materials to the console." );
  1669. extern ConVar stickers_debug_randomize;
  1670. ConVar stickers_debug_randomize_min_index( "stickers_debug_randomize_min_index", "28", FCVAR_DEVELOPMENTONLY, "" );
  1671. ConVar stickers_debug_randomize_max_index( "stickers_debug_randomize_max_index", "47", FCVAR_DEVELOPMENTONLY, "" );
  1672. ConVar stickers_always_regenerate( "stickers_always_regenerate", "0", FCVAR_DEVELOPMENTONLY, "Don't attempt to load cached sticker materials" );
  1673. char g_szStickersOverridePath[256];
  1674. ConVar stickers_override_path_enabled( "stickers_override_path_enabled", "0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "" );
  1675. ConVar stickers_override_wear( "stickers_override_wear", "0.0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "" );
  1676. ConVar stickers_override_scale( "stickers_override_scale", "1.0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "" );
  1677. ConVar stickers_override_rotation( "stickers_override_rotation", "0.0", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "" );
  1678. void cc_StickersOverridePath(const CCommand& args)
  1679. {
  1680. //e.g.: "stickers2/banana.vmt"
  1681. V_StripExtension( args[1], g_szStickersOverridePath, sizeof(g_szStickersOverridePath) );
  1682. stickers_always_regenerate.SetValue(1);
  1683. stickers_override_path_enabled.SetValue(1);
  1684. }
  1685. static ConCommand stickers_override_path("stickers_override_path", cc_StickersOverridePath, "", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT );
  1686. #endif
  1687. extern ConVar cl_righthand;
  1688. void CEconItemView::GenerateStickerMaterials( void )
  1689. {
  1690. //create sticker materials per item using the base sticker material for a particular slot + the item's sticker attributes for that slot
  1691. if ( !GetItemSchema() )
  1692. return;
  1693. int nSupportedStickerSlots = GetNumSupportedStickerSlots();
  1694. m_pStickerMaterials.RemoveAll();
  1695. for ( int i=0; i<nSupportedStickerSlots; i++ )
  1696. {
  1697. uint32 nStickerId = GetStickerAttributeBySlotIndexInt( i, k_EStickerAttribute_ID, 0 );
  1698. #ifdef _DEBUG
  1699. if ( stickers_debug_randomize.GetBool() )
  1700. {
  1701. if ( stickers_debug_randomize_min_index.GetInt() != -1 && stickers_debug_randomize_max_index.GetInt() != -1 )
  1702. {
  1703. stickers_debug_randomize_min_index.SetValue( MAX( stickers_debug_randomize_min_index.GetInt(), 0 ) );
  1704. stickers_debug_randomize_max_index.SetValue( MIN( stickers_debug_randomize_max_index.GetInt(), GetItemSchema()->GetStickerKitDefinitionCount()-1 ) );
  1705. nStickerId = RandomInt( stickers_debug_randomize_min_index.GetInt(), stickers_debug_randomize_max_index.GetInt() );
  1706. }
  1707. else
  1708. {
  1709. nStickerId = RandomInt( 1, GetItemSchema()->GetStickerKitDefinitionCount()-1 );
  1710. }
  1711. }
  1712. #endif
  1713. if ( nStickerId <= 0
  1714. #ifdef _DEBUG
  1715. && !stickers_override_path_enabled.GetBool()
  1716. #endif
  1717. )
  1718. continue; // the sticker id for this slot is invalid, no need to build a sticker material
  1719. //get additional sticker attributes
  1720. float flStickerWear = GetStickerAttributeBySlotIndexFloat( i, k_EStickerAttribute_Wear, 0.0f );
  1721. float flStickerScale = GetStickerAttributeBySlotIndexFloat( i, k_EStickerAttribute_Scale, 1.0f );
  1722. float flStickerRotation = GetStickerAttributeBySlotIndexFloat( i, k_EStickerAttribute_Rotation, 0.0f );
  1723. #ifdef _DEBUG
  1724. if ( stickers_debug_randomize.GetBool() )
  1725. {
  1726. //get additional sticker attributes
  1727. flStickerWear = RandomFloat( 0.2f, 0.8f );
  1728. flStickerScale = RandomFloat( 0.95f, 1.05f );
  1729. flStickerRotation = RandomFloat( -10.0f, 10.0f );
  1730. }
  1731. if ( stickers_override_path_enabled.GetBool() )
  1732. {
  1733. //get additional sticker attributes
  1734. flStickerWear = stickers_override_wear.GetFloat();
  1735. flStickerScale = stickers_override_scale.GetFloat();
  1736. flStickerRotation = stickers_override_rotation.GetFloat();
  1737. }
  1738. #endif
  1739. //get the sticker base material path
  1740. const char *szStickerBaseMaterialPath = GetStickerSlotMaterialBySlotIndex(i);
  1741. if ( !szStickerBaseMaterialPath || szStickerBaseMaterialPath[0] == 0 )
  1742. {
  1743. #ifdef _DEBUG
  1744. ConColorMsg( Color(240,170,10,255), "Failed to get the base material path for sticker ID: %i\n", nStickerId );
  1745. #endif
  1746. continue; //failed to get the base material path
  1747. }
  1748. char szStickerShortName[32]; //this is the base name of the material AND model, by convention. e.g. "pist_deagle_decal_A"
  1749. V_FileBase( szStickerBaseMaterialPath, szStickerShortName, sizeof(szStickerShortName) );
  1750. const CStickerKit* pStickerKit = GetItemSchema()->GetStickerKitDefinition(nStickerId);
  1751. const char *szStickerMaterialSchemaName;
  1752. //get the sticker material schema name, e.g.: "navi"
  1753. #ifdef _DEBUG
  1754. if ( stickers_override_path_enabled.GetBool() )
  1755. {
  1756. szStickerMaterialSchemaName = g_szStickersOverridePath;
  1757. }
  1758. else
  1759. #endif
  1760. if (pStickerKit)
  1761. {
  1762. szStickerMaterialSchemaName = pStickerKit->sMaterialPath.String();
  1763. }
  1764. else
  1765. {
  1766. #ifdef _DEBUG
  1767. ConColorMsg(Color(240, 170, 10, 255), "Sticker kit definition is invalid for sticker ID: %i\n", nStickerId );
  1768. #endif
  1769. continue; //sticker kit definition is invalid
  1770. }
  1771. if ( !szStickerMaterialSchemaName || szStickerMaterialSchemaName[0] == 0 )
  1772. {
  1773. #ifdef _DEBUG
  1774. ConColorMsg(Color(240, 170, 10, 255), "Failed to get material schema name: %s\n", szStickerBaseMaterialPath);
  1775. #endif
  1776. continue; //failed to get material schema name
  1777. }
  1778. //build the full material vmt path from the schema name
  1779. char szStickerMaterialPath[MAX_PATH];
  1780. if ( pStickerKit && pStickerKit->bMaterialPathIsAbsolute )
  1781. {
  1782. V_snprintf( szStickerMaterialPath, sizeof(szStickerMaterialPath), "%s", szStickerMaterialSchemaName );
  1783. }
  1784. else
  1785. {
  1786. V_snprintf( szStickerMaterialPath, sizeof(szStickerMaterialPath), "materials/models/weapons/customization/stickers/%s.vmt", szStickerMaterialSchemaName );
  1787. }
  1788. //generate a unique but deterministic char sequence using rotation, scale, wear
  1789. char szStickerUniqueParamStr[32];
  1790. V_snprintf( szStickerUniqueParamStr, sizeof(szStickerUniqueParamStr), "%f_%f_%f", flStickerRotation, flStickerScale, flStickerWear );
  1791. int nParamHash = HashStringCaseless( szStickerUniqueParamStr );
  1792. //generate the desired material names
  1793. char szDesiredStickerMaterialNameFirstPerson[128];
  1794. V_snprintf( szDesiredStickerMaterialNameFirstPerson, sizeof(szDesiredStickerMaterialNameFirstPerson), "sticker_%s_%s_%i_1st", szStickerShortName, szStickerMaterialSchemaName, nParamHash );
  1795. char szDesiredStickerMaterialNameThirdPerson[128];
  1796. V_snprintf( szDesiredStickerMaterialNameThirdPerson, sizeof(szDesiredStickerMaterialNameThirdPerson), "sticker_%s_%s_%i_3rd", szStickerShortName, szStickerMaterialSchemaName, nParamHash );
  1797. //these materials may already exist, try to find them
  1798. IMaterial *stickerMaterialFirstPerson = materials->FindProceduralMaterial( szDesiredStickerMaterialNameFirstPerson, TEXTURE_GROUP_OTHER );
  1799. IMaterial *stickerMaterialThirdPerson = materials->FindProceduralMaterial( szDesiredStickerMaterialNameThirdPerson, TEXTURE_GROUP_OTHER );
  1800. #ifdef _DEBUG
  1801. if ( stickers_debug_material_spew.GetBool() )
  1802. {
  1803. if ( !stickerMaterialFirstPerson->IsErrorMaterial() )
  1804. {
  1805. ConColorMsg( Color(240,170,10,255), "Found pre-existing 1st-person sticker material: %s\n", szDesiredStickerMaterialNameFirstPerson );
  1806. }
  1807. if ( !stickerMaterialThirdPerson->IsErrorMaterial() )
  1808. {
  1809. ConColorMsg( Color(240,170,10,255), "Found pre-existing 3rd-person sticker material: %s\n", szDesiredStickerMaterialNameThirdPerson );
  1810. }
  1811. }
  1812. #endif
  1813. //if it exists already, great - otherwise we need to create it
  1814. if ( stickerMaterialFirstPerson->IsErrorMaterial() || stickerMaterialThirdPerson->IsErrorMaterial()
  1815. #ifdef _DEBUG
  1816. || stickers_always_regenerate.GetBool()
  1817. #endif
  1818. )
  1819. {
  1820. //load the specific sticker material params, these are needed for both first and third person versions
  1821. KeyValues *pSpecificStickerMaterialKeyValues = new KeyValues( "vmt" );
  1822. KeyValues::AutoDelete autodelete_pSpecificStickerMaterialKeyValues( pSpecificStickerMaterialKeyValues );
  1823. if ( !pSpecificStickerMaterialKeyValues->LoadFromFile( g_pFullFileSystem, szStickerMaterialPath, "GAME" ) )
  1824. {
  1825. #ifdef _DEBUG
  1826. ConColorMsg(Color(240, 170, 10, 255), "Failed to load specific sticker material keyvalues: %s\n", szStickerMaterialPath);
  1827. #endif
  1828. continue; //failed to load specific sticker material keyvalues
  1829. }
  1830. //set wear, scale and rotation params in the specific sticker keyvalues
  1831. pSpecificStickerMaterialKeyValues->SetFloat( "$wearprogress", flStickerWear );
  1832. pSpecificStickerMaterialKeyValues->SetFloat( "$patternrotation", flStickerRotation );
  1833. pSpecificStickerMaterialKeyValues->SetFloat( "$patternscale", flStickerScale );
  1834. if ( stickerMaterialFirstPerson->IsErrorMaterial()
  1835. #ifdef _DEBUG
  1836. || stickers_always_regenerate.GetBool()
  1837. #endif
  1838. )
  1839. {
  1840. //first person stickers need the base material params for custom per-sticker AO and wear remapping
  1841. KeyValues *pFirstPersonKeyValues = new KeyValues( "vmt" );
  1842. KeyValues::AutoDelete autodelete_pFirstPersonKeyValues( pFirstPersonKeyValues );
  1843. if ( !pFirstPersonKeyValues->LoadFromFile( g_pFullFileSystem, szStickerBaseMaterialPath, "GAME" ) )
  1844. {
  1845. #ifdef _DEBUG
  1846. ConColorMsg(Color(240, 170, 10, 255), "Failed to load base material keyvalues: %s\n", szStickerBaseMaterialPath);
  1847. #endif
  1848. continue; //failed to load base material keyvalues
  1849. }
  1850. if ( cl_righthand.GetBool() == false )
  1851. {
  1852. // left-handed viewmodels flip their stickers so they render correctly
  1853. pFirstPersonKeyValues->SetInt( "$mirrorhorizontal", 1 );
  1854. }
  1855. //now combine the keyvalues - this will produce the final sticker material params
  1856. pFirstPersonKeyValues->MergeFrom( pSpecificStickerMaterialKeyValues, KeyValues::MERGE_KV_UPDATE );
  1857. //now add the relevant sticker slot proxy list
  1858. KeyValues *pFirstPersonStickerProxyKeyValues = new KeyValues("vmt");
  1859. KeyValues::AutoDelete autodelete_pFirstPersonStickerProxyKeyValues(pFirstPersonStickerProxyKeyValues);
  1860. char szStickerMaterialProxyListPath[MAX_PATH];
  1861. V_snprintf(szStickerMaterialProxyListPath, sizeof(szStickerMaterialProxyListPath),
  1862. "materials/models/weapons/customization/stickers/default/sticker_proxies_%i.vmt", i);
  1863. if ( pFirstPersonStickerProxyKeyValues->LoadFromFile(g_pFullFileSystem, szStickerMaterialProxyListPath, "GAME"))
  1864. {
  1865. pFirstPersonKeyValues->MergeFrom( pFirstPersonStickerProxyKeyValues, KeyValues::MERGE_KV_UPDATE );
  1866. }
  1867. autodelete_pFirstPersonStickerProxyKeyValues.Detach();
  1868. #ifdef _DEBUG
  1869. if ( !stickerMaterialFirstPerson->IsErrorMaterial() && stickers_always_regenerate.GetBool())
  1870. {
  1871. ConColorMsg( Color(240,170,10,255), "WARNING: stickers_always_regenerate is TRUE, regenerating: %s\n", szDesiredStickerMaterialNameFirstPerson );
  1872. stickerMaterialFirstPerson->SetShaderAndParams( pFirstPersonKeyValues );
  1873. stickerMaterialFirstPerson->RefreshPreservingMaterialVars();
  1874. }
  1875. else
  1876. #endif
  1877. {
  1878. //create a new material with the final sticker material params
  1879. stickerMaterialFirstPerson = materials->CreateMaterial(szDesiredStickerMaterialNameFirstPerson, pFirstPersonKeyValues);
  1880. stickerMaterialFirstPerson->Refresh();
  1881. }
  1882. #ifdef _DEBUG
  1883. if ( stickers_debug_material_spew.GetBool() )
  1884. {
  1885. ConColorMsg( Color(240,170,10,255), "Generated first person sticker material: %s\n", szDesiredStickerMaterialNameFirstPerson );
  1886. KeyValuesDumpAsDevMsg( pFirstPersonKeyValues, 2 );
  1887. }
  1888. #endif
  1889. autodelete_pFirstPersonKeyValues.Detach();
  1890. }
  1891. if ( stickerMaterialThirdPerson->IsErrorMaterial()
  1892. #ifdef _DEBUG
  1893. || stickers_always_regenerate.GetBool()
  1894. #endif
  1895. )
  1896. {
  1897. //create a 'thirdperson' material that only needs the specific sticker material params and a special $thirdperson param set
  1898. KeyValues *pThirdPersonKeyValues = new KeyValues("WeaponDecal");
  1899. KeyValues::AutoDelete autodelete_pThirdPersonKeyValues(pThirdPersonKeyValues);
  1900. pThirdPersonKeyValues->MergeFrom( pSpecificStickerMaterialKeyValues, KeyValues::MERGE_KV_UPDATE );
  1901. pThirdPersonKeyValues->SetInt( "$thirdperson", 1 );
  1902. #ifdef _DEBUG
  1903. if ( !stickerMaterialThirdPerson->IsErrorMaterial() && stickers_always_regenerate.GetBool())
  1904. {
  1905. ConColorMsg( Color(240,170,10,255), "WARNING: stickers_always_regenerate is TRUE, regenerating: %s\n", szDesiredStickerMaterialNameThirdPerson );
  1906. stickerMaterialThirdPerson->SetShaderAndParams( pThirdPersonKeyValues );
  1907. stickerMaterialThirdPerson->RefreshPreservingMaterialVars();
  1908. }
  1909. else
  1910. #endif
  1911. {
  1912. stickerMaterialThirdPerson = materials->CreateMaterial( szDesiredStickerMaterialNameThirdPerson, pThirdPersonKeyValues );
  1913. stickerMaterialThirdPerson->Refresh();
  1914. }
  1915. #ifdef _DEBUG
  1916. if ( stickers_debug_material_spew.GetBool() )
  1917. {
  1918. ConColorMsg( Color(240,170,10,255), "Generated third person sticker material: %s\n", szDesiredStickerMaterialNameThirdPerson );
  1919. KeyValuesDumpAsDevMsg( pThirdPersonKeyValues, 2 );
  1920. }
  1921. #endif
  1922. autodelete_pThirdPersonKeyValues.Detach();
  1923. }
  1924. }
  1925. //add material references for the materials to the econ item sticker material list
  1926. int nNewStickerIndex = m_pStickerMaterials.AddToTail();
  1927. m_pStickerMaterials[ nNewStickerIndex ].m_pMaterialReferenceFirstPerson.Init(stickerMaterialFirstPerson);
  1928. m_pStickerMaterials[ nNewStickerIndex ].m_pMaterialReferenceThirdPerson.Init(stickerMaterialThirdPerson);
  1929. m_pStickerMaterials[ nNewStickerIndex ].m_nSlotIndex = i;
  1930. }
  1931. }
  1932. void CEconItemView::UpdateGeneratedMaterial( bool bIgnorePicMip, CompositeTextureSize_t diffuseTextureSize )
  1933. {
  1934. if ( diffuseTextureSize != COMPOSITE_TEXTURE_SIZE_512 )
  1935. {
  1936. ClearCustomMaterials();
  1937. }
  1938. if ( ( GetCustomMaterialCount() == 0 ) && GetStaticData() )
  1939. {
  1940. const char *pItemClass = GetStaticData()->GetItemClass();
  1941. if ( pItemClass )
  1942. {
  1943. if ( V_strcmp( pItemClass, "tool" ) == 0 )
  1944. {
  1945. // paint
  1946. }
  1947. else if ( V_strcmp( pItemClass, "wearable_item" ) == 0 )
  1948. {
  1949. // clothing items
  1950. int nTeam = -1; // should remove this? Will we do anything team specific?
  1951. int nSlotId = GetStaticData()->GetLoadoutSlot( nTeam );
  1952. if ( GetStaticData()->GetPaintData()->Count() > 0 )
  1953. {
  1954. CreateCustomClothingMaterials( GetStaticData()->GetDefinitionName(), nSlotId, nTeam, bIgnorePicMip, diffuseTextureSize );
  1955. }
  1956. }
  1957. else
  1958. {
  1959. WEAPON_FILE_INFO_HANDLE handle = LookupWeaponInfoSlot( pItemClass );
  1960. if ( handle != GetInvalidWeaponInfoHandle() )
  1961. {
  1962. int nWeaponId = WeaponIdFromString( pItemClass );
  1963. if ( GetStaticData()->GetPaintData()->Count() > 0 )
  1964. {
  1965. CreateCustomWeaponMaterials( nWeaponId, bIgnorePicMip, diffuseTextureSize );
  1966. }
  1967. }
  1968. }
  1969. }
  1970. }
  1971. }
  1972. void CEconItemView::CreateCustomWeaponMaterials( int nWeaponId, bool bIgnorePicMip, CompositeTextureSize_t diffuseTextureSize )
  1973. {
  1974. if ( !GetWorldDisplayModel() )
  1975. {
  1976. AssertMsg1( false, "Failed to GetWorldDisplayModel for %s.", WeaponIdAsString((CSWeaponID)nWeaponId) );
  1977. return;
  1978. }
  1979. //read in paint kit
  1980. int nPaintKit = GetCustomPaintKitIndex();
  1981. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinition( nPaintKit );
  1982. if ( !pPaintKit )
  1983. {
  1984. AssertMsg2( false, "Failed to find paintkit index %i for %s.", nPaintKit, WeaponIdAsString((CSWeaponID)nWeaponId) );
  1985. return;
  1986. }
  1987. MDLHandle_t modelHandle = mdlcache->FindMDL( GetWorldDisplayModel() );
  1988. if ( modelHandle == MDLHANDLE_INVALID )
  1989. {
  1990. AssertMsg1( false, "Failed to find world display model handle for %s.", WeaponIdAsString((CSWeaponID)nWeaponId) );
  1991. return;
  1992. }
  1993. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( modelHandle );
  1994. //read in random seed
  1995. int nSeed = GetCustomPaintKitSeed();
  1996. float flWear = GetCustomPaintKitWear( pPaintKit->flWearDefault );
  1997. const CUtlVector< WeaponPaintableMaterial_t > *pPaintData = GetStaticData()->GetPaintData();
  1998. int nNumMaterialsToPaint = pPaintKit->bOnlyFirstMaterial ? 1 : pPaintData->Count();
  1999. for ( int nCustomMaterialIndex = 0; nCustomMaterialIndex < nNumMaterialsToPaint; nCustomMaterialIndex++ )
  2000. {
  2001. CCSWeaponVisualsDataCompare compareObject;
  2002. compareObject.m_nIndex = nPaintKit;
  2003. compareObject.m_nSeed = nSeed;
  2004. compareObject.m_flWear = flWear;
  2005. compareObject.m_nModelID = nWeaponId;
  2006. compareObject.m_nLOD = 1;
  2007. compareObject.m_flWeaponLength = (*pPaintData)[ nCustomMaterialIndex ].m_flWeaponLength;
  2008. compareObject.m_flUVScale = (*pPaintData)[ nCustomMaterialIndex ].m_flUVScale;
  2009. CCSWeaponVisualsDataProcessor* pVisualsDataProcessor = new CCSWeaponVisualsDataProcessor( Move(compareObject), &( (*pPaintData)[ nCustomMaterialIndex ] ), "CustomWeapon" );
  2010. bool bCreatedMaterial = false;
  2011. if ( pVisualsDataProcessor->HasCustomMaterial() )
  2012. {
  2013. // find the material in the models materials to get it's index (used for overriding)
  2014. bool bFound = false;
  2015. int nModelMaterialIndex;
  2016. char szBaseName[ MAX_PATH ];
  2017. for ( nModelMaterialIndex = 0; nModelMaterialIndex < pStudioHdr->numtextures; nModelMaterialIndex++ )
  2018. {
  2019. mstudiotexture_t *pTexture = pStudioHdr->pTexture( nModelMaterialIndex );
  2020. V_FileBase( pTexture->pszName(), szBaseName, sizeof( szBaseName ) );
  2021. if ( V_stricmp( szBaseName, pVisualsDataProcessor->GetOriginalMaterialBaseName() ) == 0 )
  2022. {
  2023. bFound = true;
  2024. break;
  2025. }
  2026. }
  2027. if ( !bFound )
  2028. {
  2029. DevMsg( "Original material not found! Name: %s \n \n", pVisualsDataProcessor->GetOriginalMaterialBaseName() );
  2030. }
  2031. else
  2032. {
  2033. m_ppVisualsDataProcessors.AddToTail( pVisualsDataProcessor );
  2034. pVisualsDataProcessor->AddRef();
  2035. KeyValues *pVMTKeyValues = pVisualsDataProcessor->GenerateCustomMaterialKeyValues();
  2036. Assert( pVMTKeyValues );
  2037. CUtlVector< SCompositeTextureInfo > vecTextureInfo;
  2038. int nIndex = vecTextureInfo.AddToTail();
  2039. vecTextureInfo[ nIndex ].m_size = diffuseTextureSize;
  2040. vecTextureInfo[ nIndex ].m_format = COMPOSITE_TEXTURE_FORMAT_DXT5;
  2041. vecTextureInfo[ nIndex ].m_nMaterialParamID = MATERIAL_PARAM_ID_BASE_DIFFUSE_TEXTURE;
  2042. vecTextureInfo[ nIndex ].m_bSRGB = true;
  2043. vecTextureInfo[ nIndex ].m_pVisualsDataProcessor = pVisualsDataProcessor;
  2044. nIndex = vecTextureInfo.AddToTail();
  2045. vecTextureInfo[ nIndex ].m_size = ( diffuseTextureSize != COMPOSITE_TEXTURE_SIZE_512 ) ? static_cast< CompositeTextureSize_t > ( Q_log2( pPaintKit->nViewModelExponentOverrideSize ) ) : COMPOSITE_TEXTURE_SIZE_256;
  2046. vecTextureInfo[ nIndex ].m_format = COMPOSITE_TEXTURE_FORMAT_DXT1;
  2047. vecTextureInfo[ nIndex ].m_nMaterialParamID = MATERIAL_PARAM_ID_PHONG_EXPONENT_TEXTURE;
  2048. vecTextureInfo[ nIndex ].m_bSRGB = false;
  2049. vecTextureInfo[ nIndex ].m_pVisualsDataProcessor = pVisualsDataProcessor;
  2050. ICustomMaterial *pCustomMaterial = g_pMaterialSystem->GetCustomMaterialManager()->GetOrCreateCustomMaterial( pVMTKeyValues, vecTextureInfo, bIgnorePicMip );
  2051. delete pVMTKeyValues; // copied inside GetCustomMaterial, no longer needed
  2052. if ( pCustomMaterial )
  2053. {
  2054. SetCustomMaterial( pCustomMaterial, nModelMaterialIndex );
  2055. bCreatedMaterial = true;
  2056. }
  2057. }
  2058. }
  2059. pVisualsDataProcessor->Release();
  2060. }
  2061. mdlcache->Release( modelHandle );
  2062. }
  2063. #endif
  2064. #ifdef CLIENT_DLL
  2065. ConVar econ_enable_inventory_images( "econ_enable_inventory_images", "1", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY, "allow inventory image rendering for use by scaleform" );
  2066. ConVar econ_inventory_image_pinboard( "econ_inventory_image_pinboard", "0", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY );
  2067. void CEconItemView::Update( void )
  2068. {
  2069. if ( !econ_enable_inventory_images.GetBool() || g_pRenderToRTHelper == NULL )
  2070. return;
  2071. // if an async load from cache is in progress, just return
  2072. if ( m_asyncFixupState == AFS_LoadingInProgress )
  2073. return;
  2074. // if we need to render our inventory image rgba, then attempt to now
  2075. if ( m_bInventoryImageRgbaRequested && m_pRenderToRTData == NULL && m_inventoryImageRgba.TellPut() == 0 )
  2076. {
  2077. if ( !m_bInventoryImageTriedCache )
  2078. {
  2079. // See if we've already got it on disc
  2080. if ( LoadCachedInventoryImage() )
  2081. {
  2082. return;
  2083. }
  2084. m_bInventoryImageTriedCache = true;
  2085. }
  2086. UpdateGeneratedMaterial( true );
  2087. // check to see if we can render now (custom materials ready?)
  2088. for ( int i = 0; i < GetCustomMaterialCount(); i++ )
  2089. {
  2090. if ( GetCustomMaterial( i ) && !GetCustomMaterial( i )->IsValid() )
  2091. {
  2092. InventoryManager()->InsertMaterialGenerationJob( this );
  2093. return;
  2094. }
  2095. }
  2096. m_pScratchVTF = CreateVTFTexture();
  2097. m_pRenderToRTMDL = new CMergedMDL;
  2098. m_pRenderToRTMDL->SetMDL( GetIconDisplayModel(), this );
  2099. m_pRenderToRTData = g_pRenderToRTHelper->CreateRenderToRTData( m_pRenderToRTMDL, m_pScratchVTF );
  2100. m_pRenderToRTData->m_pszIconNameSuffix = GetStaticData()->GetDefinitionName();
  2101. const InventoryImageData_t *pInventoryImageData = GetStaticData()->GetInventoryImageData();
  2102. if ( pInventoryImageData )
  2103. {
  2104. if ( econ_inventory_image_pinboard.GetBool() )
  2105. {
  2106. // Force the camera to a nice position for the pinboard
  2107. m_pRenderToRTData->m_cameraAngles = QAngle( 0.0f, -90.0f, 0.0f );
  2108. m_pRenderToRTData->m_cameraOffset = Vector( -25.0f, 0.0f, 0.0f );
  2109. }
  2110. else
  2111. {
  2112. matrix3x4_t matCamera;
  2113. m_pRenderToRTMDL->SetupBonesForAttachmentQueries();
  2114. if ( m_pRenderToRTMDL->GetAttachment( "camera_inventory", matCamera ) )
  2115. {
  2116. MatrixAngles( matCamera, m_pRenderToRTData->m_cameraAngles, m_pRenderToRTData->m_cameraOffset );
  2117. m_pRenderToRTData->m_bUsingExplicitModelCameraPosAnglesFromAttachment = true;
  2118. }
  2119. else
  2120. {
  2121. if ( pInventoryImageData->m_pCameraAngles )
  2122. {
  2123. m_pRenderToRTData->m_cameraAngles = *( pInventoryImageData->m_pCameraAngles );
  2124. }
  2125. if ( pInventoryImageData->m_pCameraOffset )
  2126. {
  2127. m_pRenderToRTData->m_cameraOffset = *( pInventoryImageData->m_pCameraOffset );
  2128. }
  2129. }
  2130. }
  2131. if ( pInventoryImageData->m_cameraFOV != -1.0f )
  2132. {
  2133. m_pRenderToRTData->m_cameraFOV = pInventoryImageData->m_cameraFOV;
  2134. }
  2135. int nLightDescIndex = ( pInventoryImageData->m_bOverrideDefaultLight ) ? 0 : m_pRenderToRTData->m_LightingState.m_nLocalLightCount;
  2136. for ( int i = 0; i < MATERIAL_MAX_LIGHT_COUNT; i++ )
  2137. {
  2138. if ( pInventoryImageData->m_pLightDesc[i] && nLightDescIndex < MATERIAL_MAX_LIGHT_COUNT )
  2139. {
  2140. m_pRenderToRTData->m_LightingState.m_pLocalLightDesc[ nLightDescIndex ] = *( pInventoryImageData->m_pLightDesc[ i ] );
  2141. nLightDescIndex++;
  2142. }
  2143. }
  2144. m_pRenderToRTData->m_LightingState.m_nLocalLightCount = nLightDescIndex;
  2145. }
  2146. g_pRenderToRTHelper->StartRenderToRT( m_pRenderToRTData );
  2147. }
  2148. if ( m_pRenderToRTData && m_pRenderToRTData->m_stage == RENDER_TO_RT_STAGE_DONE )
  2149. {
  2150. unsigned char *pSourceImage = m_pScratchVTF->ImageData( 0, 0, 0 );
  2151. // copy out the result into our buffer, allowing less than the full height (we use 4:3 icon images in CS:GO)
  2152. m_inventoryImageRgba.Purge();
  2153. if ( m_nInventoryImageRgbaWidth == m_pScratchVTF->Width() && m_nInventoryImageRgbaHeight <= m_pScratchVTF->Height() )
  2154. {
  2155. m_inventoryImageRgba.EnsureCapacity( m_nInventoryImageRgbaWidth * m_nInventoryImageRgbaHeight * 4 );
  2156. m_inventoryImageRgba.Put( pSourceImage, m_nInventoryImageRgbaWidth * m_nInventoryImageRgbaHeight * 4 );
  2157. }
  2158. else
  2159. {
  2160. // this normally shouldn't occur, but if it did then it's likely the requested width doesn't match the RenderToRtHelper RT width (currently that's 256)
  2161. Assert(0);
  2162. }
  2163. // call back to update the image in the UI
  2164. if ( m_pImageReadyCallback )
  2165. {
  2166. uint64 nItemID = GetItemID();
  2167. if ( !nItemID )
  2168. nItemID = CombinedItemIdMakeFromDefIndexAndPaint( GetItemDefinition()->GetDefinitionIndex(), GetCustomPaintKitIndex() );
  2169. // Request to save the buffer before calling the callback - that way the callback
  2170. // can modify m_inventoryImageRgba, such as swapping channels (ef when wrting the PNG file),
  2171. // without affecting the cached image
  2172. SaveInventoryImage( m_inventoryImageRgba );
  2173. m_pImageReadyCallback( this, m_inventoryImageRgba, m_nInventoryImageRgbaWidth, m_nInventoryImageRgbaHeight, nItemID );
  2174. m_inventoryImageRgba.Purge(); // no longer need to keep this buffer around
  2175. m_bInventoryImageRgbaRequested = false; // clear the requested flag, so that it can be requested again
  2176. m_bInventoryImageTriedCache = false; // clear tried cache flag, since it's now in the cache and we want it to get from there next time.
  2177. }
  2178. g_pRenderToRTHelper->DestroyRenderToRTData( m_pRenderToRTData );
  2179. m_pRenderToRTData = NULL;
  2180. delete m_pRenderToRTMDL;
  2181. m_pRenderToRTMDL = NULL;
  2182. DestroyVTFTexture( m_pScratchVTF );
  2183. m_pScratchVTF = NULL;
  2184. // No longer need the custom material - inventory image has been generated !
  2185. ClearCustomMaterials();
  2186. return;
  2187. }
  2188. if ( m_inventoryImageRgba.TellPut() == 0 && m_bInventoryImageRgbaRequested )
  2189. {
  2190. InventoryManager()->InsertMaterialGenerationJob( this );
  2191. }
  2192. }
  2193. static float g_pAttribWearMins[ 3 ] = { 0.00f, 0.20f, 0.56f };
  2194. static float g_pAttribWearMaxs[ 3 ] = { 0.07f, 0.48f, 1.00f };
  2195. char g_szGeneratingTradingIconPath[ MAX_PATH ] = "";
  2196. void BuildInventoryImagePath( char *pchOutfile, int nMaxPath, const char *pchDefName, const char *pchPaintKitName, bool bWear, float flWear, bool bLarge )
  2197. {
  2198. const char *pchOutputFolder = "resource/Flash/econ/default_generated/";
  2199. if ( g_szGeneratingTradingIconPath[ 0 ] )
  2200. {
  2201. pchOutputFolder = g_szGeneratingTradingIconPath;
  2202. }
  2203. if ( bWear )
  2204. {
  2205. V_snprintf( pchOutfile, nMaxPath, "%s%s_%s_%s%s.png",
  2206. pchOutputFolder,
  2207. pchDefName,
  2208. pchPaintKitName,
  2209. ( flWear >= g_pAttribWearMins[ 2 ] ? "heavy" : ( flWear <= g_pAttribWearMaxs[ 0 ] ? "light" : "medium" ) ),
  2210. bLarge ? "_large" : "" );
  2211. }
  2212. else
  2213. {
  2214. //if reading the wear attribute fails, don't try to pack any attributes into the output image name
  2215. if ( !pchPaintKitName )
  2216. {
  2217. V_snprintf( pchOutfile, nMaxPath, "%s%s%s.png",
  2218. pchOutputFolder, pchDefName, bLarge ? "_large" : "" );
  2219. }
  2220. else
  2221. {
  2222. V_snprintf( pchOutfile, nMaxPath, "%s%s_%s%s.png",
  2223. pchOutputFolder, pchDefName, pchPaintKitName, bLarge ? "_large" : "" );
  2224. }
  2225. }
  2226. }
  2227. void SaveAndAddToP4( char *outfile, CUtlBuffer &outBuffer, bool bSkipAdd )
  2228. {
  2229. bool bNewFile = false;
  2230. FileHandle_t hFileOut = g_pFullFileSystem->Open( outfile, "rb" );
  2231. if ( hFileOut != FILESYSTEM_INVALID_HANDLE )
  2232. {
  2233. g_pFullFileSystem->Close( hFileOut );
  2234. }
  2235. else
  2236. {
  2237. bNewFile = true;
  2238. }
  2239. hFileOut = g_pFullFileSystem->Open( outfile, "wb" );
  2240. if ( hFileOut != FILESYSTEM_INVALID_HANDLE )
  2241. {
  2242. g_pFullFileSystem->Write( outBuffer.Base(), outBuffer.TellPut(), hFileOut );
  2243. g_pFullFileSystem->Close( hFileOut );
  2244. }
  2245. if ( bNewFile && !bSkipAdd )
  2246. {
  2247. char szFullIconPath[ MAX_PATH ];
  2248. g_pFullFileSystem->RelativePathToFullPath( outfile, "MOD", szFullIconPath, sizeof( szFullIconPath ) );
  2249. if ( !p4->IsFileInPerforce( szFullIconPath ) )
  2250. {
  2251. DevMsg( "P4 Add: %s\n", outfile );
  2252. g_p4factory->SetDummyMode( p4 == NULL );
  2253. g_p4factory->SetOpenFileChangeList( "Item Icons Auto Checkout" );
  2254. CP4AutoAddFile autop4_add( szFullIconPath );
  2255. }
  2256. else
  2257. {
  2258. DevMsg( "File Already in P4: %s\n", szFullIconPath );
  2259. }
  2260. }
  2261. }
  2262. void InventoryImageReadyCallback( const CEconItemView *pItemView, CUtlBuffer &rawImageRgba, int nWidth, int nHeight, uint64 nItemID )
  2263. {
  2264. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( pItemView->GetStaticData()->GetDefinitionIndex() );
  2265. if ( !pItemDef )
  2266. return;
  2267. // It's actually BGRA! Swap B and R to get RGBA!
  2268. for ( int i = 0; i < rawImageRgba.Size(); i += 4 )
  2269. {
  2270. if ( i + 3 > rawImageRgba.Size() )
  2271. break;
  2272. unsigned char *pCurrent = reinterpret_cast< unsigned char* >( rawImageRgba.Base() ) + i;
  2273. unsigned char chTemp = *pCurrent;
  2274. *pCurrent = *( pCurrent + 2 );
  2275. *( pCurrent + 2 ) = chTemp;
  2276. }
  2277. CUtlBuffer outBuffer;
  2278. ImgUtl_WriteRGBAAsPNGToBuffer( reinterpret_cast< const unsigned char *>( rawImageRgba.Base() ), nWidth, nHeight, outBuffer );
  2279. static CSchemaAttributeDefHandle pAttr_PaintKitWear( "set item texture wear" );
  2280. float flWear = 0.0f;
  2281. bool bHasWear = FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItemView, pAttr_PaintKitWear, &flWear );
  2282. char outfile[ MAX_PATH ];
  2283. BuildInventoryImagePath( outfile, sizeof( outfile ),
  2284. pItemView->GetStaticData()->GetDefinitionName(),
  2285. pItemView->GetCustomPaintKitIndex() == 0 ? NULL : pItemView->GetCustomPaintKit()->sName.String(),
  2286. bHasWear, flWear,
  2287. false );
  2288. SaveAndAddToP4( outfile, outBuffer, econ_inventory_image_pinboard.GetBool() );
  2289. if ( g_szGeneratingTradingIconPath[ 0 ] && !econ_inventory_image_pinboard.GetBool() )
  2290. {
  2291. BuildInventoryImagePath( outfile, sizeof( outfile ),
  2292. pItemView->GetStaticData()->GetDefinitionName(),
  2293. pItemView->GetCustomPaintKitIndex() == 0 ? NULL : pItemView->GetCustomPaintKit()->sName.String(),
  2294. bHasWear, flWear,
  2295. true );
  2296. SaveAndAddToP4( outfile, outBuffer, false );
  2297. }
  2298. }
  2299. void CEconItemView::SaveInventoryImageAsPNG( int nWidth, int nHeight )
  2300. {
  2301. GetInventoryImageRgba( nWidth, nHeight, InventoryImageReadyCallback );
  2302. InventoryManager()->InsertMaterialGenerationJob( this );
  2303. }
  2304. struct KeyValueWith64BitID_t
  2305. {
  2306. uint64 nID;
  2307. KeyValues *pKV;
  2308. };
  2309. class CIconKeyValuesLess
  2310. {
  2311. public:
  2312. bool Less( KeyValueWith64BitID_t * const & src1, KeyValueWith64BitID_t * const & src2, void *pCtx )
  2313. {
  2314. return ( src1->nID < src2->nID );
  2315. }
  2316. };
  2317. const CUtlBuffer* CEconItemView::GetInventoryImageRgba( int nWidth, int nHeight, ImageReadyCallback_t pImageReadyCallback )
  2318. {
  2319. if ( !econ_enable_inventory_images.GetBool() )
  2320. {
  2321. m_inventoryImageRgba.EnsureCapacity( nWidth * nHeight * sizeof( int ) );
  2322. // just make a blank image of the size requested
  2323. for ( int i = 0; i < nWidth * nHeight; i++ )
  2324. {
  2325. m_inventoryImageRgba.PutInt( 0 );
  2326. }
  2327. return &m_inventoryImageRgba;
  2328. }
  2329. if ( !m_bInventoryImageRgbaRequested )
  2330. {
  2331. InventoryManager()->InsertMaterialGenerationJob( this );
  2332. }
  2333. m_bInventoryImageRgbaRequested = true;
  2334. if ( ( nWidth != m_nInventoryImageRgbaWidth ) || ( nHeight != m_nInventoryImageRgbaHeight ) )
  2335. {
  2336. m_inventoryImageRgba.Purge();
  2337. m_nInventoryImageRgbaWidth = nWidth;
  2338. m_nInventoryImageRgbaHeight = nHeight;
  2339. }
  2340. if ( m_inventoryImageRgba.TellPut() == 0 )
  2341. {
  2342. Assert( !m_pImageReadyCallback || ( m_pImageReadyCallback == pImageReadyCallback ) ); // only support generating one image at a time
  2343. m_pImageReadyCallback = pImageReadyCallback;
  2344. }
  2345. return &m_inventoryImageRgba;
  2346. }
  2347. bool CEconItemView::CanGenerateInventoryImageRgba()
  2348. {
  2349. // we can currently only generate images for weapons and gloves
  2350. // when that changes, we need to update this code.
  2351. if ( econ_enable_inventory_images.GetBool() )
  2352. {
  2353. if ( GetStaticData() )
  2354. {
  2355. const char *pItemClass = GetStaticData()->GetItemClass();
  2356. if ( pItemClass && V_strnicmp( pItemClass, "weapon_", 7 ) == 0 )
  2357. {
  2358. return true;
  2359. }
  2360. const char* szSubPos = GetStaticData()->GetRawDefinition()->GetString( "item_sub_position", NULL );
  2361. if ( szSubPos && V_stricmp( "clothing_hands", szSubPos ) == 0 )
  2362. {
  2363. return !GetItemDefinition()->IsDefaultSlotItem();
  2364. }
  2365. }
  2366. #if 0 // Relies on prebuilt maps of item tags which isn't in staging yet
  2367. if ( HasTag( "Weapon" ) )
  2368. {
  2369. return true;
  2370. }
  2371. if ( HasTag( "Hands" ) )
  2372. {
  2373. return true;
  2374. }
  2375. #endif
  2376. }
  2377. return false;
  2378. }
  2379. void CEconItemView::ClearInventoryImageRgba()
  2380. {
  2381. m_inventoryImageRgba.Purge();
  2382. int nItemIdHigh = m_iItemIDHigh.Get();
  2383. int nItemIdLow = m_iItemIDLow.Get();
  2384. if ( m_iItemID == 0 )
  2385. {
  2386. nItemIdHigh = 0xFFFFFFFF;
  2387. nItemIdLow = ( GetItemDefinition()->GetDefinitionIndex() << 16 );
  2388. nItemIdLow += GetCustomPaintKitIndex();
  2389. }
  2390. char szFileName[ MAX_PATH ];
  2391. V_snprintf( szFileName, sizeof( szFileName ), ECON_ITEM_GENERATED_ICON_DIR "%X-%X-%X.iic", ECON_ITEM_ICON_CACHE_VERSION, nItemIdHigh, nItemIdLow );
  2392. if ( g_pFullFileSystem->FileExists( szFileName ) )
  2393. g_pFullFileSystem->RemoveFile( szFileName );
  2394. InventoryManager()->InsertMaterialGenerationJob( this );
  2395. }
  2396. static void AsyncLoadCachedIntevtoryImageCallback( const FileAsyncRequest_t &request, int numReadBytes, FSAsyncStatus_t asyncStatus )
  2397. {
  2398. CEconItemView *pEconItemView = reinterpret_cast< CEconItemView * >( request.pContext );
  2399. if ( pEconItemView )
  2400. {
  2401. pEconItemView->m_nNumAsyncReadBytes = numReadBytes;
  2402. pEconItemView->m_asyncStatus = asyncStatus;
  2403. pEconItemView->m_asyncFixupState = CEconItemView::AFS_LoadingDone;
  2404. g_InventoryItemUpdateManager.AddItemViewToFixupList( pEconItemView );
  2405. }
  2406. }
  2407. void CEconItemView::FinishLoadCachedInventoryImage( void* pData, int numReadBytes, FSAsyncStatus_t asyncStatus )
  2408. {
  2409. if ( asyncStatus == FSASYNC_OK )
  2410. {
  2411. if ( m_pImageReadyCallback )
  2412. {
  2413. uint64 nItemID = GetItemID();
  2414. if ( !nItemID )
  2415. {
  2416. nItemID = CombinedItemIdMakeFromDefIndexAndPaint( GetItemDefinition()->GetDefinitionIndex(), GetCustomPaintKitIndex() );
  2417. }
  2418. m_pImageReadyCallback( this, m_inventoryImageRgba, m_nInventoryImageRgbaWidth, m_nInventoryImageRgbaHeight, nItemID );
  2419. }
  2420. m_bInventoryImageRgbaRequested = false; // clear the requested flag, so that it can be requested again
  2421. }
  2422. else
  2423. {
  2424. m_bInventoryImageTriedCache = true;
  2425. InventoryManager()->InsertMaterialGenerationJob( this );
  2426. }
  2427. m_inventoryImageRgba.Purge(); // no longer need to keep this buffer around
  2428. m_asyncFixupState = AFS_FixupDone;
  2429. // it's possible to get here without m_hAsyncControl being set when async mode is not on.
  2430. if ( m_hAsyncControl )
  2431. {
  2432. filesystem->AsyncRelease( m_hAsyncControl );
  2433. m_hAsyncControl = NULL;
  2434. }
  2435. }
  2436. bool CEconItemView::LoadCachedInventoryImage( void )
  2437. {
  2438. if ( !m_pImageReadyCallback )
  2439. return false;
  2440. // already Async Loading
  2441. if ( m_asyncFixupState == AFS_LoadingInProgress )
  2442. return true;
  2443. CleanInventoryImageCacheDir();
  2444. GenerateCachedInventoryImageName();
  2445. const int nBuffSize = ECON_ITEM_GENERATED_ICON_WIDTH * ECON_ITEM_GENERATED_ICON_HEIGHT * 4;
  2446. m_inventoryImageRgba.EnsureCapacity( nBuffSize );
  2447. // Already pending
  2448. Assert ( !m_hAsyncControl );
  2449. m_inventoryImageRgba.SeekPut( CUtlBuffer::SEEK_HEAD, nBuffSize );
  2450. // async load the file
  2451. FileAsyncRequest_t fileRequest;
  2452. fileRequest.pContext = (void *)this;
  2453. fileRequest.pfnCallback = ::AsyncLoadCachedIntevtoryImageCallback;
  2454. fileRequest.pData = m_inventoryImageRgba.Base();
  2455. fileRequest.pszFilename = m_szCurrentLoadCachedFileName;
  2456. fileRequest.priority = -1;
  2457. // queue for async load
  2458. filesystem->AsyncRead( fileRequest, &m_hAsyncControl );
  2459. // it's possible to get here without m_hAsyncControl being set when async mode is not on.
  2460. if ( m_hAsyncControl )
  2461. {
  2462. m_asyncFixupState = AFS_LoadingInProgress;
  2463. }
  2464. return true;
  2465. }
  2466. void CEconItemView::SaveInventoryImage( CUtlBuffer &rawImageRgba )
  2467. {
  2468. GenerateCachedInventoryImageName();
  2469. CUtlBuffer *pBuffer = new CUtlBuffer();
  2470. pBuffer->EnsureCapacity( rawImageRgba.TellPut() );
  2471. pBuffer->CopyBuffer( rawImageRgba );
  2472. FSAsyncStatus_t status = g_pFullFileSystem->AsyncWriteFile( m_szCurrentLoadCachedFileName, pBuffer, pBuffer->TellPut(), true );
  2473. if ( status < FSASYNC_OK )
  2474. {
  2475. Msg( "EconItemView: Failed to write cache file %s\n", m_szCurrentLoadCachedFileName );
  2476. }
  2477. }
  2478. void CEconItemView::GenerateCachedInventoryImageName()
  2479. {
  2480. int nItemIdHigh = m_iItemIDHigh.Get();
  2481. int nItemIdLow = m_iItemIDLow.Get();
  2482. if (m_iItemID == 0)
  2483. {
  2484. nItemIdHigh = 0xFFFFFFFF;
  2485. nItemIdLow = (GetItemDefinition()->GetDefinitionIndex() << 16);
  2486. nItemIdLow += GetCustomPaintKitIndex();
  2487. // Get the wear attribute
  2488. static CSchemaAttributeDefHandle pAttr_PaintKitWear( "set item texture wear" );
  2489. float flWear = 0.0f;
  2490. bool bHasWear = FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttr_PaintKitWear, &flWear );
  2491. if ( bHasWear )
  2492. {
  2493. int nItemWear = ( flWear >= g_pAttribWearMins[ 2 ] ) ? 2 : ( flWear <= g_pAttribWearMaxs[ 0 ] ? 0 : 1 );
  2494. V_snprintf( m_szCurrentLoadCachedFileName, sizeof( m_szCurrentLoadCachedFileName ), ECON_ITEM_GENERATED_ICON_DIR "%X-%X-%X-%X.iic", ECON_ITEM_ICON_CACHE_VERSION, nItemIdHigh, nItemIdLow, nItemWear );
  2495. }
  2496. else
  2497. {
  2498. V_snprintf( m_szCurrentLoadCachedFileName, sizeof( m_szCurrentLoadCachedFileName ), ECON_ITEM_GENERATED_ICON_DIR "%X-%X-%X.iic", ECON_ITEM_ICON_CACHE_VERSION, nItemIdHigh, nItemIdLow );
  2499. }
  2500. }
  2501. else
  2502. {
  2503. V_snprintf( m_szCurrentLoadCachedFileName, sizeof( m_szCurrentLoadCachedFileName ), ECON_ITEM_GENERATED_ICON_DIR "%X-%X-%X.iic", ECON_ITEM_ICON_CACHE_VERSION, nItemIdHigh, nItemIdLow );
  2504. }
  2505. }
  2506. void CEconItemView::CleanInventoryImageCacheDir( void )
  2507. {
  2508. // Only do this check once per session
  2509. // and ensure that we've loaded at least one item into the inventory before doing the check
  2510. if ( m_sbHasCleanedInventoryImageCacheDir || InventoryManager()->GetLocalInventory()->GetItemCount() == 0 )
  2511. return;
  2512. // Only do this once per session!
  2513. m_sbHasCleanedInventoryImageCacheDir = true;
  2514. // Loop through all the cache files in the cache dir and delete ones that are an older version
  2515. FileFindHandle_t hSearchFile;
  2516. char szPath[ 512 ];
  2517. Q_strncpy( szPath, ECON_ITEM_GENERATED_ICON_DIR "*.iic", sizeof( szPath ) );
  2518. //char szCorrectPrefix[ MAX_PATH ];
  2519. //V_snprintf( szCorrectPrefix, sizeof( szCorrectPrefix ), "%X-", ECON_ITEM_ICON_CACHE_VERSION );
  2520. const char *pchFileName = g_pFullFileSystem->FindFirstEx( szPath, "MOD", &hSearchFile );
  2521. if ( pchFileName )
  2522. {
  2523. while ( pchFileName )
  2524. {
  2525. // read in exactly 3 numbers from the name
  2526. uint32 nVersion = 0;
  2527. uint32 nItemIdHigh = 0;
  2528. uint32 nItemIdLow = 0;
  2529. uint32 nItemWear = 0;
  2530. int nScanResult = sscanf( pchFileName, "%X-%X-%X-%X.iic", &nVersion, &nItemIdHigh, &nItemIdLow, &nItemWear );
  2531. bool bWipeIt = ( nScanResult != 3 ) && ( nScanResult != 4 );
  2532. if ( !bWipeIt )
  2533. {
  2534. if ( nVersion != ECON_ITEM_ICON_CACHE_VERSION )
  2535. {
  2536. bWipeIt = true;
  2537. }
  2538. else if ( nItemIdHigh != 0xFFFFFFFF )
  2539. {
  2540. bWipeIt = ( nScanResult != 3 ); // don't expect to have the wear in this case (item coming from the inventory)
  2541. if ( !bWipeIt )
  2542. {
  2543. // If we don't still have that item wipe it!
  2544. itemid_t ullItem = ( static_cast< uint64 >( nItemIdHigh ) << 32 ) + static_cast< uint64 >( nItemIdLow ) ;
  2545. bWipeIt = !InventoryManager()->GetLocalInventory()->GetInventoryItemByItemID( ullItem );
  2546. }
  2547. }
  2548. }
  2549. if ( bWipeIt )
  2550. {
  2551. char szFileName[ MAX_PATH ];
  2552. V_snprintf( szFileName, sizeof( szFileName ), ECON_ITEM_GENERATED_ICON_DIR "%s", pchFileName );
  2553. g_pFullFileSystem->RemoveFile( szFileName );
  2554. }
  2555. pchFileName = g_pFullFileSystem->FindNext( hSearchFile );
  2556. }
  2557. g_pFullFileSystem->FindClose( hSearchFile );
  2558. }
  2559. }
  2560. #endif
  2561. void CEconItemView::InitNetworkedDynamicAttributesForDemos( void )
  2562. {
  2563. #if defined( ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS )
  2564. if ( !GetSOCData() )
  2565. return;
  2566. m_NetworkedDynamicAttributesForDemos.DestroyAllAttributes();
  2567. bool bAdded = false;
  2568. const uint32 nNumAttributes = GetSOCData()->m_pCustomDataOptimizedObject ? GetSOCData()->m_pCustomDataOptimizedObject->m_numAttributes : 0;
  2569. for ( uint32 nAttr = 0; nAttr < nNumAttributes; nAttr++ )
  2570. {
  2571. const CEconItem::attribute_t &attr = * GetSOCData()->m_pCustomDataOptimizedObject->GetAttribute( nAttr );
  2572. const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinition( attr.m_unDefinitionIndex );
  2573. if ( !pDef )
  2574. continue;
  2575. const ISchemaAttributeType *pAttributeType = pDef->GetAttributeType();
  2576. if ( pAttributeType && !pAttributeType->BSupportsGameplayModificationAndNetworking() )
  2577. continue;
  2578. float flValue = 0.0f;
  2579. if ( pDef->IsStoredAsFloat() )
  2580. {
  2581. flValue = attr.m_value.asFloat;
  2582. }
  2583. else
  2584. {
  2585. flValue = *reinterpret_cast< const float* >( &attr.m_value.asUint32 );
  2586. }
  2587. CEconItemAttribute attribute( attr.m_unDefinitionIndex, flValue );
  2588. m_NetworkedDynamicAttributesForDemos.AddAttribute( &attribute );
  2589. bAdded = true;
  2590. }
  2591. if ( bAdded )
  2592. {
  2593. NetworkStateChanged();
  2594. }
  2595. #endif // #ifdef ECON_NETWORK_ATTRIBUTES
  2596. }
  2597. void CEconItemView::UpdateNetworkedDynamicAttributesForDemos( attrib_definition_index_t nDef, float flNewValue )
  2598. {
  2599. for( int nAttr = 0; nAttr < m_NetworkedDynamicAttributesForDemos.GetNumAttributes(); nAttr++ )
  2600. {
  2601. CEconItemAttribute *pAttribute = m_NetworkedDynamicAttributesForDemos.GetAttribute( nAttr );
  2602. if ( !pAttribute || pAttribute->GetAttribIndex() != nDef )
  2603. continue;
  2604. CEconItemAttribute attribute( nDef, flNewValue );
  2605. *pAttribute = attribute;
  2606. return;
  2607. }
  2608. }
  2609. //-----------------------------------------------------------------------------
  2610. // Purpose:
  2611. //-----------------------------------------------------------------------------
  2612. void CEconItemView::AddAttribute( CEconItemAttribute *pAttribute )
  2613. {
  2614. m_AttributeList.AddAttribute( pAttribute );
  2615. #ifdef ECON_NETWORK_ATTRIBUTES
  2616. NetworkStateChanged();
  2617. #endif // #ifdef ECON_NETWORK_ATTRIBUTES
  2618. MarkDescriptionDirty();
  2619. }
  2620. //-----------------------------------------------------------------------------
  2621. // Purpose: Remove an attribute by name
  2622. //-----------------------------------------------------------------------------
  2623. void CEconItemView::SetOrAddAttributeValueByName( const char *pszAttribDefName, float flValue )
  2624. {
  2625. m_AttributeList.SetOrAddAttributeValueByName( pszAttribDefName, flValue );
  2626. MarkDescriptionDirty();
  2627. }
  2628. //-----------------------------------------------------------------------------
  2629. // Purpose: Remove an attribute by name
  2630. //-----------------------------------------------------------------------------
  2631. void CEconItemView::RemoveAttribute( const char *pszAttribDefName )
  2632. {
  2633. m_AttributeList.RemoveAttribute( pszAttribDefName );
  2634. MarkDescriptionDirty();
  2635. }
  2636. const bool CEconItemView::GetCombinedAttributeClassValue( float &flValue, string_t iszAttribClass ) const
  2637. {
  2638. for( int i = 0; i < m_AttributeList.m_Attributes.Count(); i++ )
  2639. {
  2640. const CEconItemAttribute *pAttrib = &(m_AttributeList.m_Attributes[ i ]);
  2641. if ( pAttrib )
  2642. {
  2643. const CEconItemAttributeDefinition *pStaticData = pAttrib->GetStaticData();
  2644. if ( pStaticData->GetCachedClass() == iszAttribClass )
  2645. {
  2646. switch ( pStaticData->GetDescriptionFormat() )
  2647. {
  2648. case ATTDESCFORM_VALUE_IS_PERCENTAGE:
  2649. case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
  2650. {
  2651. flValue *= pAttrib->GetValue();
  2652. }
  2653. return true;
  2654. case ATTDESCFORM_VALUE_IS_ADDITIVE:
  2655. case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
  2656. {
  2657. flValue += pAttrib->GetValue();
  2658. }
  2659. return true;
  2660. case ATTDESCFORM_VALUE_IS_REPLACE:
  2661. {
  2662. flValue = pAttrib->GetValue();
  2663. }
  2664. return true;
  2665. case ATTDESCFORM_VALUE_IS_OR:
  2666. {
  2667. int iTmp = flValue;
  2668. iTmp |= (int)pAttrib->GetValue();
  2669. flValue = iTmp;
  2670. }
  2671. return true;
  2672. default:
  2673. // Unknown value format.
  2674. Assert( 0 );
  2675. return true;
  2676. }
  2677. }
  2678. }
  2679. }
  2680. return false;
  2681. }
  2682. //-----------------------------------------------------------------------------
  2683. // Purpose: Returns the attribute matching the specified class, carried by this entity, if it exists.
  2684. //-----------------------------------------------------------------------------
  2685. CEconItemAttribute *CEconItemView::GetAttributeByClass( const char *szAttribClass )
  2686. {
  2687. return m_AttributeList.GetAttributeByClass( szAttribClass );
  2688. }
  2689. const CEconItemAttribute *CEconItemView::GetAttributeByClass( const char *szAttribClass ) const
  2690. {
  2691. return m_AttributeList.GetAttributeByClass( szAttribClass );
  2692. }
  2693. //-----------------------------------------------------------------------------
  2694. // Purpose: Returns the attribute that matches the attribute def index, if it exists
  2695. //-----------------------------------------------------------------------------
  2696. CEconItemAttribute *CEconItemView::GetAttributeByDefIndex( int iAttributeDefIndex )
  2697. {
  2698. return m_AttributeList.GetAttributeByDefIndex( iAttributeDefIndex );
  2699. }
  2700. const CEconItemAttribute *CEconItemView::GetAttributeByDefIndex( int iAttributeDefIndex ) const
  2701. {
  2702. return m_AttributeList.GetAttributeByDefIndex( iAttributeDefIndex );
  2703. }
  2704. //-----------------------------------------------------------------------------
  2705. // Purpose: Returns the attribute that matches the def name, if it exists
  2706. //-----------------------------------------------------------------------------
  2707. CEconItemAttribute *CEconItemView::GetAttributeByName( const char *pszAttribDefName )
  2708. {
  2709. return m_AttributeList.GetAttributeByName( pszAttribDefName );
  2710. }
  2711. const CEconItemAttribute *CEconItemView::GetAttributeByName( const char *pszAttribDefName ) const
  2712. {
  2713. return m_AttributeList.GetAttributeByName( pszAttribDefName );
  2714. }
  2715. extern const char *g_EffectTypes[NUM_EFFECT_TYPES];
  2716. //-----------------------------------------------------------------------------
  2717. // Purpose:
  2718. //-----------------------------------------------------------------------------
  2719. #ifdef CLIENT_DLL
  2720. const wchar_t *CEconItemView::GetItemName( bool bUncustomized /*= false*/ ) const
  2721. {
  2722. static const wchar_t *pwzDefaultName = L"";
  2723. /** Removed for partner depot **/
  2724. return pwzDefaultName;
  2725. }
  2726. #endif
  2727. //-----------------------------------------------------------------------------
  2728. // Purpose: Get RGB modifying attribute value
  2729. //-----------------------------------------------------------------------------
  2730. int CEconItemView::GetModifiedRGBValue( bool bAltColor )
  2731. {
  2732. enum
  2733. {
  2734. kPaintConstant_Default = 0,
  2735. kPaintConstant_OldTeamColor = 1,
  2736. };
  2737. static CSchemaAttributeDefHandle pAttr_Paint( "set item tint rgb" );
  2738. static CSchemaAttributeDefHandle pAttr_Paint2( "set item tint rgb 2" );
  2739. // If we have no base paint color we don't do anything special.
  2740. float fRGB;
  2741. if ( !FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttr_Paint, &fRGB ) )
  2742. return kPaintConstant_Default;
  2743. // See if we also have a secondary paint color.
  2744. uint32 unRGB = (uint32)fRGB,
  2745. unRGBAlt;
  2746. float fRGBAlt;
  2747. // Backwards compatibility for old team colored items.
  2748. if ( unRGB == kPaintConstant_OldTeamColor )
  2749. {
  2750. unRGB = RGB_INT_RED;
  2751. unRGBAlt = RGB_INT_BLUE;
  2752. }
  2753. else if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttr_Paint2, &fRGBAlt ) )
  2754. {
  2755. unRGBAlt = (uint32)fRGBAlt;
  2756. }
  2757. else
  2758. {
  2759. // By default our secondary color will match our primary if we can't find a replacement.
  2760. unRGBAlt = unRGB;
  2761. }
  2762. return bAltColor ? unRGBAlt : unRGB;
  2763. }
  2764. int CEconItemView::GetCustomPaintKitIndex( void ) const
  2765. {
  2766. static CSchemaAttributeDefHandle pAttr_PaintKit( "set item texture prefab" );
  2767. // If we have no base paint kit color we don't do anything special.
  2768. float flIndex;
  2769. if ( !FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttr_PaintKit, &flIndex ) )
  2770. {
  2771. return 0;
  2772. }
  2773. return flIndex;
  2774. }
  2775. const char* CEconItemView::GetCustomPaintKitDbgName( void ) const
  2776. {
  2777. int idx = GetCustomPaintKitIndex();
  2778. const CPaintKit* pKit = GetItemSchema()->GetPaintKitDefinition( idx );
  2779. return pKit ? pKit->sName.Get() : "<UNPAINTED>";
  2780. }
  2781. bool CEconItemView::IsStyleUnlocked( int iStyle ) const
  2782. {
  2783. const CEconStyleInfo* pStyle = GetItemDefinition()->GetStyleInfo( iStyle );
  2784. if ( pStyle && !pStyle->GetUnlockInfo()->IsLockable() )
  2785. return true;
  2786. // Do we have the style unlocked?
  2787. static CSchemaAttributeDefHandle pAttr_UnlockedStyles( "unlocked styles" );
  2788. uint32 nUnlockedStyles;
  2789. if ( FindAttribute( pAttr_UnlockedStyles, &nUnlockedStyles ) )
  2790. {
  2791. if ( nUnlockedStyles & (1 << iStyle) )
  2792. {
  2793. return true;
  2794. }
  2795. }
  2796. return false;
  2797. }
  2798. bool CEconItemView::CanCollect( CEconItemView &subject )
  2799. {
  2800. #if 0
  2801. int nItemSet = GetItemSetIndex();
  2802. if ( nItemSet < 0 )
  2803. return false;
  2804. CEconItemSchema *pSchema = GetItemSchema();
  2805. if ( !pSchema )
  2806. return false;
  2807. const CEconItemSetDefinition *pItemSet = pSchema->GetItemSetByIndex( nItemSet );
  2808. if ( !pItemSet )
  2809. return false;
  2810. if ( !pItemSet->m_bIsCollection )
  2811. return false;
  2812. // Check and see if subject is in our item set.
  2813. FOR_EACH_VEC( pItemSet->m_ItemEntries, i )
  2814. {
  2815. unsigned int iIndex = pItemSet->m_ItemEntries[i].m_nItemDef;
  2816. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( iIndex );
  2817. if ( !pItemDef )
  2818. continue;
  2819. if ( subject.GetStaticData()->GetDefinitionIndex() != pItemDef->GetDefinitionIndex() )
  2820. continue;
  2821. // Check and see if this item is already collected.
  2822. CEconItem* pItem = GetSOCData();
  2823. if ( !pItem )
  2824. continue;
  2825. const CEconItemAttributeDefinition* pCollectionAttrib = GetItemSchema()->GetAttributeDefinitionByName( "collection bits" );
  2826. if ( !pCollectionAttrib )
  2827. continue;
  2828. float flValue = 0;
  2829. pItem->HasCustomAttribute( pCollectionAttrib->GetDefinitionIndex(), &flValue );
  2830. uint32 iCollectionBits = *(int *) &flValue;
  2831. if ( iCollectionBits & (1 << i) )
  2832. {
  2833. return false;
  2834. }
  2835. else
  2836. {
  2837. return true;
  2838. }
  2839. }
  2840. #endif
  2841. return false;
  2842. }
  2843. uint64 CEconItemView::GetCustomUserTextureID()
  2844. {
  2845. static CSchemaAttributeDefHandle pAttr_CustomTextureLo( "custom texture lo" );
  2846. static CSchemaAttributeDefHandle pAttr_CustomTextureHi( "custom texture hi" );
  2847. uint32 unLowVal, unHighVal;
  2848. const bool bHasLowVal = FindAttribute( pAttr_CustomTextureLo, &unLowVal ),
  2849. bHasHighVal = FindAttribute( pAttr_CustomTextureHi, &unHighVal );
  2850. // We should have both, or neither. We should never have just one
  2851. Assert( bHasLowVal == bHasHighVal );
  2852. if ( bHasLowVal && bHasHighVal )
  2853. {
  2854. return ((uint64)unHighVal << 32) | (uint64)unLowVal;
  2855. }
  2856. // No attribute set
  2857. return 0;
  2858. }
  2859. const CPaintKit *CEconItemView::GetCustomPaintKit( void ) const
  2860. {
  2861. int nPaintKit = GetCustomPaintKitIndex();
  2862. return GetItemSchema()->GetPaintKitDefinition( nPaintKit );
  2863. }
  2864. //-----------------------------------------------------------------------------
  2865. // Purpose:
  2866. //-----------------------------------------------------------------------------
  2867. CAttributeList::CAttributeList()
  2868. {
  2869. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2870. m_pManager = NULL;
  2871. #endif
  2872. m_Attributes.Purge();
  2873. }
  2874. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2875. //-----------------------------------------------------------------------------
  2876. // Purpose:
  2877. //-----------------------------------------------------------------------------
  2878. void CAttributeList::SetManager( CAttributeManager *pManager )
  2879. {
  2880. m_pManager = pManager;
  2881. }
  2882. #endif
  2883. //-----------------------------------------------------------------------------
  2884. // Purpose:
  2885. //-----------------------------------------------------------------------------
  2886. void CAttributeList::Init()
  2887. {
  2888. m_Attributes.Purge();
  2889. }
  2890. //-----------------------------------------------------------------------------
  2891. // Purpose:
  2892. //-----------------------------------------------------------------------------
  2893. void CAttributeList::IterateAttributes( class IEconItemAttributeIterator *pIterator )
  2894. {
  2895. Assert( pIterator );
  2896. FOR_EACH_VEC( m_Attributes, i )
  2897. {
  2898. CEconItemAttribute *pAttrInst = &m_Attributes[i];
  2899. const CEconItemAttributeDefinition *pAttrDef = pAttrInst->GetStaticData();
  2900. if ( !pAttrDef )
  2901. continue;
  2902. const ISchemaAttributeType *pAttrType = pAttrDef->GetAttributeType();
  2903. Assert( pAttrType );
  2904. Assert( pAttrType->BSupportsGameplayModificationAndNetworking() );
  2905. attribute_data_union_t value;
  2906. value.asFloat = pAttrInst->GetValue();
  2907. if ( !pAttrType->OnIterateAttributeValue( pIterator, pAttrDef, value ) )
  2908. return;
  2909. }
  2910. }
  2911. //-----------------------------------------------------------------------------
  2912. // Purpose:
  2913. //-----------------------------------------------------------------------------
  2914. void CAttributeList::DestroyAllAttributes( void )
  2915. {
  2916. if ( m_Attributes.Count() )
  2917. {
  2918. m_Attributes.Purge();
  2919. UpdateManagerCache();
  2920. #if defined( ECON_NETWORK_ATTRIBUTES ) || defined( ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS )
  2921. NetworkStateChanged();
  2922. #endif // #if defined( ECON_NETWORK_ATTRIBUTES ) || defined( ECON_NETWORK_DYNAMIC_ATTRIBUTES_FOR_DEMOS )
  2923. }
  2924. }
  2925. //-----------------------------------------------------------------------------
  2926. // Purpose:
  2927. //-----------------------------------------------------------------------------
  2928. void CAttributeList::AddAttribute( CEconItemAttribute *pAttribute )
  2929. {
  2930. Assert( pAttribute );
  2931. // Only add attributes to the attribute list if they have a definition we can
  2932. // pull data from.
  2933. if ( !pAttribute->GetStaticData() )
  2934. return;
  2935. m_Attributes.AddToTail( *pAttribute );
  2936. #ifdef ECON_NETWORK_ATTRIBUTES
  2937. NetworkStateChanged();
  2938. #endif // #ifdef ECON_NETWORK_ATTRIBUTES
  2939. UpdateManagerCache();
  2940. }
  2941. //-----------------------------------------------------------------------------
  2942. // Purpose: Remove an attribute by name
  2943. //-----------------------------------------------------------------------------
  2944. void CAttributeList::SetOrAddAttributeValueByName( const char *pszAttribDefName, float flValue )
  2945. {
  2946. // This should already be in the string table
  2947. const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttribDefName );
  2948. if ( !pDef )
  2949. return;
  2950. int iAttributes = GetNumAttributes();
  2951. for ( int i = 0; i < iAttributes; i++ )
  2952. {
  2953. CEconItemAttribute *pAttribute = GetAttribute(i);
  2954. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  2955. // Never combine into set bonus attributes, they're recreated regularly
  2956. if ( pAttribute->m_bSetBonus )
  2957. continue;
  2958. #endif
  2959. if ( pAttribute->GetAttribIndex() == pDef->GetDefinitionIndex() )
  2960. {
  2961. pAttribute->SetValue( flValue );
  2962. return;
  2963. }
  2964. }
  2965. // Didn't find it. Add a new one.
  2966. CEconItemAttribute attribute( pDef->GetDefinitionIndex(), flValue );
  2967. AddAttribute( &attribute );
  2968. }
  2969. //-----------------------------------------------------------------------------
  2970. // Purpose: Remove an attribute by name
  2971. //-----------------------------------------------------------------------------
  2972. void CAttributeList::RemoveAttribute( const char *pszAttribDefName )
  2973. {
  2974. int iAttributes = m_Attributes.Count();
  2975. for ( int i = 0; i < iAttributes; i++ )
  2976. {
  2977. if ( !strcmp( m_Attributes[i].GetStaticData()->GetDefinitionName(), pszAttribDefName ) )
  2978. {
  2979. m_Attributes.Remove( i );
  2980. UpdateManagerCache();
  2981. return;
  2982. }
  2983. }
  2984. }
  2985. //-----------------------------------------------------------------------------
  2986. // Purpose: Remove an attribute by index
  2987. //-----------------------------------------------------------------------------
  2988. void CAttributeList::RemoveAttributeByIndex( int iIndex )
  2989. {
  2990. if ( iIndex < 0 || iIndex >= GetNumAttributes() )
  2991. return;
  2992. m_Attributes.Remove( iIndex );
  2993. UpdateManagerCache();
  2994. }
  2995. //-----------------------------------------------------------------------------
  2996. // Purpose: Returns the attribute matching the specified class, carried by this entity, if it exists.
  2997. //-----------------------------------------------------------------------------
  2998. CEconItemAttribute *CAttributeList::GetAttributeByClass( const char *szAttribClass )
  2999. {
  3000. int iAttributes = GetNumAttributes();
  3001. for ( int i = 0; i < iAttributes; i++ )
  3002. {
  3003. CEconItemAttribute *pAttr = GetAttribute( i );
  3004. Assert( pAttr && pAttr->GetStaticData() );
  3005. if ( pAttr && pAttr->GetStaticData() && !V_strcmp( pAttr->GetStaticData()->GetAttributeClass(), szAttribClass ) )
  3006. return pAttr;
  3007. }
  3008. return NULL;
  3009. }
  3010. const CEconItemAttribute *CAttributeList::GetAttributeByClass( const char *szAttribClass ) const
  3011. {
  3012. int iAttributes = GetNumAttributes();
  3013. for ( int i = 0; i < iAttributes; i++ )
  3014. {
  3015. const CEconItemAttribute *pAttr = GetAttribute( i );
  3016. Assert( pAttr && pAttr->GetStaticData() );
  3017. if ( pAttr && pAttr->GetStaticData() && !V_strcmp( pAttr->GetStaticData()->GetAttributeClass(), szAttribClass ) )
  3018. return pAttr;
  3019. }
  3020. return NULL;
  3021. }
  3022. //-----------------------------------------------------------------------------
  3023. // Purpose:
  3024. //-----------------------------------------------------------------------------
  3025. CEconItemAttribute *CAttributeList::GetAttributeByDefIndex( uint16 unAttrDefIndex )
  3026. {
  3027. int iAttributes = GetNumAttributes();
  3028. for ( int i = 0; i < iAttributes; i++ )
  3029. {
  3030. CEconItemAttribute *pAttr = GetAttribute( i );
  3031. Assert( pAttr && pAttr->GetStaticData() );
  3032. if ( pAttr && pAttr->GetStaticData() && pAttr->GetStaticData()->GetDefinitionIndex() == unAttrDefIndex )
  3033. return pAttr;
  3034. }
  3035. return NULL;
  3036. }
  3037. const CEconItemAttribute *CAttributeList::GetAttributeByDefIndex( uint16 unAttrDefIndex ) const
  3038. {
  3039. int iAttributes = GetNumAttributes();
  3040. for ( int i = 0; i < iAttributes; i++ )
  3041. {
  3042. const CEconItemAttribute *pAttr = GetAttribute( i );
  3043. Assert( pAttr && pAttr->GetStaticData() );
  3044. if ( pAttr && pAttr->GetStaticData() && pAttr->GetStaticData()->GetDefinitionIndex() == unAttrDefIndex )
  3045. return pAttr;
  3046. }
  3047. return NULL;
  3048. }
  3049. //-----------------------------------------------------------------------------
  3050. // Purpose:
  3051. //-----------------------------------------------------------------------------
  3052. CEconItemAttribute *CAttributeList::GetAttributeByName( const char *pszAttribDefName )
  3053. {
  3054. const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttribDefName );
  3055. if ( !pDef )
  3056. return NULL;
  3057. int iAttributes = m_Attributes.Count();
  3058. for ( int i = 0; i < iAttributes; i++ )
  3059. {
  3060. if ( m_Attributes[i].GetStaticData()->GetDefinitionIndex() == pDef->GetDefinitionIndex() )
  3061. return &m_Attributes[i];
  3062. }
  3063. return NULL;
  3064. }
  3065. const CEconItemAttribute *CAttributeList::GetAttributeByName( const char *pszAttribDefName ) const
  3066. {
  3067. const CEconItemAttributeDefinition *pDef = GetItemSchema()->GetAttributeDefinitionByName( pszAttribDefName );
  3068. if ( !pDef )
  3069. return NULL;
  3070. int iAttributes = m_Attributes.Count();
  3071. for ( int i = 0; i < iAttributes; i++ )
  3072. {
  3073. if ( m_Attributes[i].GetStaticData()->GetDefinitionIndex() == pDef->GetDefinitionIndex() )
  3074. return &m_Attributes[i];
  3075. }
  3076. return NULL;
  3077. }
  3078. //-----------------------------------------------------------------------------
  3079. // Purpose:
  3080. //-----------------------------------------------------------------------------
  3081. CAttributeList& CAttributeList::operator=( const CAttributeList& src )
  3082. {
  3083. m_Attributes = src.m_Attributes;
  3084. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3085. // HACK: We deliberately don't copy managers, because attributelists are contained inside
  3086. // CEconItemViews, which we duplicate inside CItemModelPanels all the time. If the manager
  3087. // is copied, copies will mess with the attribute caches of the copied item.
  3088. // Our manager will be setup properly by the CAttributeManager itself if we have an associated entity.
  3089. m_pManager = NULL;
  3090. #endif
  3091. return *this;
  3092. }
  3093. //-----------------------------------------------------------------------------
  3094. // Purpose:
  3095. //-----------------------------------------------------------------------------
  3096. void CAttributeList::SetValue( CEconItemAttribute *pAttrib, float flValue )
  3097. {
  3098. #ifdef DEBUG
  3099. FOR_EACH_VEC( m_Attributes, i )
  3100. {
  3101. if ( &m_Attributes[i] == pAttrib )
  3102. {
  3103. pAttrib->SetValue( flValue );
  3104. return;
  3105. }
  3106. }
  3107. // Someone's not being honest, and setting an attribute's value via a CAttributeList that doesn't contain it.
  3108. Assert( 0 );
  3109. #else
  3110. pAttrib->SetValue( flValue );
  3111. UpdateManagerCache();
  3112. #endif
  3113. }
  3114. //-----------------------------------------------------------------------------
  3115. // Purpose:
  3116. //-----------------------------------------------------------------------------
  3117. void CAttributeList::UpdateManagerCache( void )
  3118. {
  3119. #if defined(CLIENT_DLL) || defined(GAME_DLL)
  3120. if ( m_pManager )
  3121. {
  3122. m_pManager->ClearCache();
  3123. }
  3124. #endif
  3125. }