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