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

377 lines
14 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: EconItemFactory: Manages rolling for items requested by the game server
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_item_view_helpers.h"
  8. #include "playerdecals_signature.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. using namespace GCSDK;
  12. //-----------------------------------------------------------------------------
  13. // Purpose: Constructor
  14. //-----------------------------------------------------------------------------
  15. CEconItemFactory::CEconItemFactory( )
  16. : m_ulNextObjID( 0 )
  17. , m_bIsInitialized( false )
  18. {
  19. }
  20. //-----------------------------------------------------------------------------
  21. itemid_t CEconItemFactory::GetNextID()
  22. {
  23. if( !m_bIsInitialized || !GGCBase()->IsGCRunningType( GC_TYPE_MASTER ) )
  24. {
  25. AssertMsg( m_bIsInitialized, "Critical Error: Attempting to get a new item ID without loading in the starting ID first!!!" );
  26. AssertMsg( GGCBase()->IsGCRunningType( GC_TYPE_MASTER ), "Critical Error: Attempting to get an item ID on the non-master GC, this will get out of sync" );
  27. return INVALID_ITEM_ID;
  28. }
  29. return m_ulNextObjID++;
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose: Initializes the item factory and schema. Return false if init failed
  33. //-----------------------------------------------------------------------------
  34. bool CEconItemFactory::BYieldingInit()
  35. {
  36. CUtlVector< CUtlString > vecErrors;
  37. bool bRet = m_schema.BInit( "scripts/items/unencrypted/items_master.txt", "GAME", &vecErrors );
  38. FOR_EACH_VEC( vecErrors, nError )
  39. {
  40. EmitError( SPEW_GC, "%s\n", vecErrors[nError].Get() );
  41. }
  42. static const char *pchMaxIDQuery = "SELECT MAX( ID ) FROM "
  43. "( select Max(ID) AS ID FROM Item UNION SELECT MAX(ID) AS ID FROM ForeignItem ) as tbl";
  44. CSQLAccess sqlAccess;
  45. if( !sqlAccess.BYieldingExecuteSingleResult<uint64, uint64>( NULL, pchMaxIDQuery, k_EGCSQLType_int64, &m_ulNextObjID, NULL ) )
  46. {
  47. EmitError( SPEW_GC, "Failed to read max item ID" );
  48. return false;
  49. }
  50. m_ulNextObjID++; // our next ID is one past the current max ID
  51. m_bIsInitialized = bRet;
  52. return bRet;
  53. }
  54. static const CEconItemQualityDefinition *GetQualityDefinitionForItemCreation( const CItemSelectionCriteria *pOptionalCriteria, const CEconItemDefinition *pItemDef )
  55. {
  56. Assert( pItemDef );
  57. // Do we have a quality specified? If so, is it a valid quality? If not, we fall back to the
  58. // quality specified by the item definition, the schema, etc.
  59. uint8 unQuality = k_unItemQuality_Any;
  60. // Quality specified in generation request via criteria?
  61. if ( pOptionalCriteria && pOptionalCriteria->BQualitySet() )
  62. {
  63. unQuality = pOptionalCriteria->GetQuality();
  64. }
  65. // If not: quality specified in item definition?
  66. if ( unQuality == k_unItemQuality_Any )
  67. {
  68. unQuality = pItemDef->GetQuality();
  69. }
  70. // Final fallback: default quality in schema.
  71. if ( unQuality == k_unItemQuality_Any )
  72. {
  73. unQuality = GetItemSchema()->GetDefaultQuality();
  74. }
  75. AssertMsg( unQuality != k_unItemQuality_Any, "Unable to locate valid quality!" );
  76. return GetItemSchema()->GetQualityDefinition( unQuality );
  77. }
  78. static const CEconItemRarityDefinition *GetRarityDefinitionForItemCreation( const CItemSelectionCriteria *pOptionalCriteria, const CEconItemDefinition *pItemDef )
  79. {
  80. Assert( pItemDef );
  81. // Do we have a quality specified? If so, is it a valid quality? If not, we fall back to the
  82. // quality specified by the item definition, the schema, etc.
  83. uint8 unRarity = k_unItemRarity_Any;
  84. // Quality specified in generation request via criteria?
  85. if ( pOptionalCriteria && pOptionalCriteria->BRaritySet() )
  86. {
  87. unRarity = pOptionalCriteria->GetRarity();
  88. }
  89. // If not: quality specified in item definition?
  90. if ( unRarity == k_unItemRarity_Any )
  91. {
  92. unRarity = pItemDef->GetRarity();
  93. }
  94. // Final fallback: default quality in schema.
  95. if ( unRarity == k_unItemRarity_Any )
  96. {
  97. unRarity = 1;
  98. }
  99. AssertMsg( unRarity != k_unItemRarity_Any, "Unable to locate valid rarity!" );
  100. return GetItemSchema()->GetRarityDefinition( unRarity );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose: Creates an item matching the incoming item selection criteria
  104. // Input: pItem - Pointer to the item to fill in
  105. // criteria - The criteria that the generated item must match
  106. // Output: True if a matching item could be generated, false otherwise
  107. //-----------------------------------------------------------------------------
  108. CEconItem *CEconItemFactory::CreateRandomItem( const CEconGameAccount *pGameAccount, const CItemSelectionCriteria &criteria )
  109. {
  110. // Find a matching item definition.
  111. const CEconItemDefinition *pItemDef = RollItemDefinition( criteria );
  112. if ( NULL == pItemDef )
  113. {
  114. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with no matching definition\n" );
  115. return NULL;
  116. }
  117. const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( &criteria, pItemDef );
  118. if ( NULL == pQualityDef )
  119. {
  120. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with unknown quality\n" );
  121. return NULL;
  122. }
  123. const CEconItemRarityDefinition *pRarityDef = GetRarityDefinitionForItemCreation( &criteria, pItemDef );
  124. if ( NULL == pRarityDef )
  125. {
  126. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateRandomItem(): Item creation request with unknown rarity\n" );
  127. return NULL;
  128. }
  129. // At this point we have everything that can fail will already have failed, so we can safely
  130. // create an item and just move properties over to it.
  131. CEconItem *pItem = new CEconItem();
  132. pItem->SetItemID( GetNextID() );
  133. pItem->SetDefinitionIndex( pItemDef->GetDefinitionIndex() );
  134. pItem->SetItemLevel( criteria.BItemLevelSet() ? criteria.GetItemLevel() : pItemDef->RollItemLevel() );
  135. pItem->SetQuality( pQualityDef->GetDBValue() );
  136. pItem->SetRarity( pRarityDef->GetDBValue() );
  137. pItem->SetInventoryToken( criteria.GetInitialInventory() );
  138. pItem->SetQuantity( criteria.GetInitialQuantity() );
  139. // don't set account ID
  140. // Add any custom attributes we need
  141. AddGCGeneratedAttributesToItem( pGameAccount, pItem );
  142. // Set any painkit data specified
  143. const char *pchPaintKit = criteria.GetValueForFirstConditionOfFieldName( "*paintkit" );
  144. if ( pchPaintKit )
  145. {
  146. const char *pchWear = criteria.GetValueForFirstConditionOfFieldName( "*wear" );
  147. item_list_entry_t itemInit;
  148. itemInit.m_nItemDef = pItemDef->GetDefinitionIndex();
  149. itemInit.m_nPaintKit = atoi( pchPaintKit );
  150. itemInit.m_nPaintKitSeed = 0;
  151. itemInit.m_flPaintKitWear = pchWear ? atof( pchWear ) : 0.001;
  152. pItem->InitAttributesDroppedFromListEntry( &itemInit );
  153. }
  154. return pItem;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: Creates an item based on a specific item definition index
  158. // Input: pItem - Pointer to the item to fill in
  159. // unDefinitionIndex - The definition index of the item to create
  160. // Output: True if a matching item could be generated, false otherwise
  161. //-----------------------------------------------------------------------------
  162. CEconItem *CEconItemFactory::CreateSpecificItem( const CEconGameAccount *pGameAccount, item_definition_index_t unDefinitionIndex, ECreateItemPolicy_t eCreateItemPolicy )
  163. {
  164. if ( !pGameAccount )
  165. return NULL;
  166. // Find the matching index
  167. const CEconItemDefinition *pItemDef = m_schema.GetItemDefinition( unDefinitionIndex );
  168. if ( NULL == pItemDef )
  169. {
  170. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with no matching definition (def index %u)\n", unDefinitionIndex );
  171. return NULL;
  172. }
  173. const CEconItemQualityDefinition *pQualityDef = GetQualityDefinitionForItemCreation( NULL, pItemDef );
  174. if ( NULL == pQualityDef )
  175. {
  176. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with unknown quality\n" );
  177. return NULL;
  178. }
  179. const CEconItemRarityDefinition *pRarityDef = GetRarityDefinitionForItemCreation( NULL, pItemDef );
  180. if ( NULL == pRarityDef )
  181. {
  182. EmitWarning( SPEW_GC, 2, "CEconItemFactory::CreateSpecificItem(): Item creation request with unknown rarity\n" );
  183. return NULL;
  184. }
  185. CEconItem *pItem = new CEconItem();
  186. if ( eCreateItemPolicy & k_ECreateItemPolicy_NoSqlItemID )
  187. pItem->SetItemID( 0ull );
  188. else
  189. pItem->SetItemID( GetNextID() );
  190. pItem->SetDefinitionIndex( unDefinitionIndex );
  191. pItem->SetItemLevel( pItemDef->RollItemLevel() );
  192. pItem->SetQuality( pQualityDef->GetDBValue() );
  193. pItem->SetRarity( pRarityDef->GetDBValue() );
  194. // don't set inventory token
  195. pItem->SetQuantity( MAX( 1, pItemDef->GetDefaultDropQuantity() ) );
  196. pItem->SetAccountID( pGameAccount->Obj().m_unAccountID );
  197. // Add any custom attributes we need
  198. AddGCGeneratedAttributesToItem( pGameAccount, pItem );
  199. return pItem;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: Randomly chooses an item definition that matches the criteria
  203. // Input: sCriteria - The criteria that the generated item must match
  204. // Output: The chosen item definition, or NULL if no item could be selected
  205. //-----------------------------------------------------------------------------
  206. const CEconItemDefinition *CEconItemFactory::RollItemDefinition( const CItemSelectionCriteria &criteria ) const
  207. {
  208. // Determine which item templates match the criteria
  209. CUtlVector<int> vecMatches;
  210. const CEconItemSchema::ItemDefinitionMap_t &mapDefs = m_schema.GetItemDefinitionMap();
  211. FOR_EACH_MAP_FAST( mapDefs, i )
  212. {
  213. if ( criteria.BEvaluate( mapDefs[i], m_schema ) )
  214. {
  215. vecMatches.AddToTail( mapDefs.Key( i ) );
  216. }
  217. }
  218. if ( 0 == vecMatches.Count() )
  219. return NULL;
  220. // Choose a random match
  221. int iIndex = RandomInt( 0, vecMatches.Count() - 1 );
  222. return m_schema.GetItemDefinition( vecMatches[iIndex] );
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose: Generates attributes that the item definition insists it always has, but must be generated by the GC
  226. // Input:
  227. //-----------------------------------------------------------------------------
  228. void CEconItemFactory::AddGCGeneratedAttributesToItem( const CEconGameAccount *pGameAccount, CEconItem *pItem ) const
  229. {
  230. const CEconItemDefinition *pDef = m_schema.GetItemDefinition( pItem->GetDefinitionIndex() );
  231. if ( !pDef )
  232. return;
  233. const CUtlVector<static_attrib_t> &vecStaticAttribs = pDef->GetStaticAttributes();
  234. // Only generate attributes that force the GC to generate them (so they vary per item created)
  235. FOR_EACH_VEC( vecStaticAttribs, i )
  236. {
  237. if ( vecStaticAttribs[i].m_bForceGCToGenerate )
  238. {
  239. ApplyStaticAttributeToItem( pItem, vecStaticAttribs[i], pGameAccount );
  240. }
  241. }
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose:
  245. //-----------------------------------------------------------------------------
  246. void CEconItemFactory::ApplyStaticAttributeToItem( CEconItem *pItem, const static_attrib_t& staticAttrib, const CEconGameAccount *pGameAccount, const CCopyableUtlVector< uint32 > *vecValues, float flRangeMin, float flRangeMax ) const
  247. {
  248. static CSchemaAttributeDefHandle pAttr_ElevateQuality( "elevate quality" );
  249. static CSchemaAttributeDefHandle pAttr_SetItemTextureWear( "set item texture wear" );
  250. static CSchemaAttributeDefHandle pAttr_SprayTintID( "spray tint id" );
  251. static CSchemaAttributeDefHandle pAttr_SpraysRemaining( "sprays remaining" );
  252. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( staticAttrib.iDefIndex );
  253. Assert( pAttrDef );
  254. // Special-case the elevate-quality attribute.
  255. if ( pAttrDef->GetDefinitionIndex() == pAttr_ElevateQuality->GetDefinitionIndex() )
  256. {
  257. //AssertMsg( CEconItem::GetTypedAttributeType<CSchemaAttributeType_Default>( pAttrDef ), "Elevate quality attribute doesn't have the right type!" );
  258. pItem->SetQuality( staticAttrib.m_value.asFloat );
  259. return;
  260. }
  261. static CSchemaItemDefHandle hItemSpray( "spray" );
  262. static CSchemaItemDefHandle hItemSprayPaint( "spraypaint" );
  263. // Special-case the sprays remaining to mean unsealing the spray into spray paint
  264. if ( pAttr_SpraysRemaining && hItemSpray && hItemSprayPaint && pItem->GetDefinitionIndex() == hItemSpray->GetDefinitionIndex() &&
  265. pAttrDef->GetDefinitionIndex() == pAttr_SpraysRemaining->GetDefinitionIndex() )
  266. {
  267. pItem->SetDefinitionIndex( hItemSprayPaint->GetDefinitionIndex() );
  268. pItem->SetFlag( kEconItemFlag_NonEconomy );
  269. pItem->SetDynamicAttributeValue( pAttr_SpraysRemaining, uint32( PLAYERDECALS_NUMCHARGES ) );
  270. return;
  271. }
  272. attribute_data_union_t attrValue = staticAttrib.m_value;
  273. // pick from 'values' if they exist. Otherwise use min/max ranges specified.
  274. if ( vecValues && ( *vecValues ).Count() != 0 )
  275. {
  276. uint32 uiRandIndex = CEconItemSchema::GetRandomStream().RandomInt( 0, ( *vecValues ).Count() - 1 );
  277. if ( pAttrDef->IsStoredAsFloat() )
  278. {
  279. attrValue.asFloat = ( *vecValues ).Element( uiRandIndex );
  280. }
  281. else
  282. {
  283. attrValue.asUint32 = ( *vecValues ).Element( uiRandIndex );
  284. }
  285. }
  286. else if ( flRangeMin != 0.0f || flRangeMax != 0.0 )
  287. {
  288. if ( pAttrDef->IsStoredAsFloat() )
  289. {
  290. attrValue.asFloat = CEconItemSchema::GetRandomStream().RandomFloat( flRangeMin, flRangeMax );
  291. }
  292. else
  293. {
  294. attrValue.asUint32 = CEconItemSchema::GetRandomStream().RandomInt( flRangeMin, flRangeMax );
  295. }
  296. }
  297. if ( pAttr_SetItemTextureWear && staticAttrib.iDefIndex == pAttr_SetItemTextureWear->GetDefinitionIndex() )
  298. {
  299. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinition( pItem->GetCustomPaintKitIndex() );
  300. if ( pPaintKit )
  301. {
  302. attrValue.asFloat = RemapValClamped( attrValue.asFloat, 0.0f, 1.0f, pPaintKit->flWearRemapMin, pPaintKit->flWearRemapMax );
  303. }
  304. }
  305. #if ECON_SPRAY_TINT_IDS_FLOAT_COLORSPACE
  306. if ( pAttr_SprayTintID && staticAttrib.iDefIndex == pAttr_SprayTintID->GetDefinitionIndex()
  307. && pAttr_SprayTintID->IsStoredAsInteger()
  308. && ( attrValue.asUint32 & 0xFF ) )
  309. { // Generation of random HSV space tints
  310. attrValue.asUint32 = CombinedTintIDMakeFromIDHSVu( attrValue.asUint32,
  311. CEconItemSchema::GetRandomStream().RandomInt( 0x00, 0x7F ),
  312. CEconItemSchema::GetRandomStream().RandomInt( 0x00, 0x7F ),
  313. CEconItemSchema::GetRandomStream().RandomInt( 0x00, 0x7F ) );
  314. }
  315. #endif
  316. // Custom attribute initialization code?
  317. pAttrDef->GetAttributeType()->LoadOrGenerateEconAttributeValue( pItem, pAttrDef, staticAttrib.m_pszCustomLogic, attrValue, pGameAccount );
  318. }