Team Fortress 2 Source Code as on 22/4/2020
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.

614 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CItemSelectionCriteria, which serves as a criteria for selection
  4. // of a econ item
  5. //
  6. //=============================================================================
  7. #include "cbase.h"
  8. #include "item_selection_criteria.h"
  9. #include "gcsdk/gcsystemmsgs.h"
  10. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  11. #include "tf_gcmessages.h"
  12. #endif
  13. #include "gcsdk/enumutils.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. // copied from \common\econ_item_view.h
  17. #define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
  18. ENUMSTRINGS_START( EItemCriteriaOperator )
  19. { k_EOperator_String_EQ, "string==" },
  20. { k_EOperator_String_Not_EQ, "!string==" },
  21. { k_EOperator_Float_EQ, "float==" },
  22. { k_EOperator_Float_Not_EQ, "!float==" },
  23. { k_EOperator_Float_LT, "float<" },
  24. { k_EOperator_Float_Not_LT, "!float<" },
  25. { k_EOperator_Float_LTE, "float<=" },
  26. { k_EOperator_Float_Not_LTE, "!float<=" },
  27. { k_EOperator_Float_GT, "float>" },
  28. { k_EOperator_Float_Not_GT, "!float>" },
  29. { k_EOperator_Float_GTE, "float>=" },
  30. { k_EOperator_Float_Not_GTE, "!float>=" },
  31. { k_EOperator_Subkey_Contains, "contains" },
  32. { k_EOperator_Subkey_Not_Contains, "!contains" },
  33. ENUMSTRINGS_REVERSE( EItemCriteriaOperator, k_EItemCriteriaOperator_Count )
  34. using namespace GCSDK;
  35. //-----------------------------------------------------------------------------
  36. // Purpose: Copy Constructor
  37. //-----------------------------------------------------------------------------
  38. CItemSelectionCriteria::CItemSelectionCriteria( const CItemSelectionCriteria &that )
  39. {
  40. (*this) = that;
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose: Operator=
  44. //-----------------------------------------------------------------------------
  45. CItemSelectionCriteria &CItemSelectionCriteria::operator=( const CItemSelectionCriteria &rhs )
  46. {
  47. // Leverage the serialization code we already have for the copy
  48. CSOItemCriteria msgTemp;
  49. rhs.BSerializeToMsg( msgTemp );
  50. BDeserializeFromMsg( msgTemp );
  51. return *this;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose: Destructor
  55. //-----------------------------------------------------------------------------
  56. CItemSelectionCriteria::~CItemSelectionCriteria( void )
  57. {
  58. m_vecConditions.PurgeAndDeleteElements();
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose: Look through our conditions and find the first of the specified type,
  62. // and return the value it's looking for.
  63. //-----------------------------------------------------------------------------
  64. const char *CItemSelectionCriteria::GetValueForFirstConditionOfType( EItemCriteriaOperator eType ) const
  65. {
  66. // Only supporting this for string conditions right now
  67. Assert( eType == k_EOperator_String_EQ || eType == k_EOperator_String_Not_EQ );
  68. FOR_EACH_VEC( m_vecConditions, i )
  69. {
  70. if ( m_vecConditions[i]->GetEOp() == eType )
  71. return m_vecConditions[i]->GetValue();
  72. }
  73. return NULL;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Look through our conditions and find the first of the specified type,
  77. // and return the value it's looking for.
  78. //-----------------------------------------------------------------------------
  79. const char *CItemSelectionCriteria::GetFieldForFirstConditionOfType( EItemCriteriaOperator eType ) const
  80. {
  81. FOR_EACH_VEC( m_vecConditions, i )
  82. {
  83. if ( m_vecConditions[i]->GetEOp() == eType )
  84. return m_vecConditions[i]->GetField();
  85. }
  86. return NULL;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose: Initialize from a KV structure
  90. //-----------------------------------------------------------------------------
  91. bool CItemSelectionCriteria::BInitFromKV( KeyValues *pKVCriteria )
  92. {
  93. // Read in the base fields
  94. if ( pKVCriteria->FindKey( "level" ) )
  95. {
  96. SetItemLevel( pKVCriteria->GetInt( "level" ) );
  97. }
  98. if ( pKVCriteria->FindKey( "quality" ) )
  99. {
  100. uint8 nQuality;
  101. if ( !GetItemSchema()->BGetItemQualityFromName( pKVCriteria->GetString( "quality" ), &nQuality ) )
  102. return false;
  103. SetQuality( nQuality );
  104. }
  105. if ( pKVCriteria->FindKey( "inventoryPos" ) )
  106. {
  107. SetInitialInventory( pKVCriteria->GetInt( "inventoryPos" ) );
  108. }
  109. if ( pKVCriteria->FindKey( "quantity" ) )
  110. {
  111. SetInitialQuantity( pKVCriteria->GetInt( "quantity" ) );
  112. }
  113. if ( pKVCriteria->FindKey( "ignore_enabled" ) )
  114. {
  115. SetIgnoreEnabledFlag( pKVCriteria->GetBool( "ignore_enabled" ) );
  116. }
  117. if ( pKVCriteria->FindKey( "tags" ) )
  118. {
  119. SetTags( pKVCriteria->GetString( "tags" ) );
  120. }
  121. KeyValues *pKVConditions = pKVCriteria->FindKey( "conditions", true );
  122. FOR_EACH_TRUE_SUBKEY( pKVConditions, pKVElement )
  123. {
  124. // Check for required fields
  125. if ( !pKVElement->FindKey( "field" ) ||
  126. !pKVElement->FindKey( "operator" ) ||
  127. !pKVElement->FindKey( "value" ) )
  128. return false;
  129. const char *pszField = pKVElement->GetString( "field" );
  130. bool bRequired = pKVElement->GetBool( "required" );
  131. const char *pszValue = pKVElement->GetString( "value" );
  132. // Get the operator
  133. const char *pszOperator = pKVElement->GetString( "operator" );
  134. EItemCriteriaOperator eOp = EItemCriteriaOperatorFromName( pszOperator );
  135. if ( k_EItemCriteriaOperator_Count == eOp )
  136. return false;
  137. BAddCondition( pszField, eOp, pszValue, bRequired );
  138. }
  139. return true;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. //-----------------------------------------------------------------------------
  144. void CItemSelectionCriteria::SetTags( const char *pszTags )
  145. {
  146. m_vecTags.Purge();
  147. m_strTags = pszTags;
  148. CSplitString splitString( pszTags, " " );
  149. for ( int i=0; i<splitString.Count(); ++i )
  150. {
  151. econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( splitString[i] );
  152. if ( !m_vecTags.HasElement( tagHandle ) )
  153. {
  154. m_vecTags.AddToTail( tagHandle );
  155. }
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. bool CItemSelectionCriteria::BAddCondition( CItemSelectionCriteria::ICondition *pCondition )
  162. {
  163. CPlainAutoPtr<ICondition> pConditionPtr( pCondition );
  164. // Check for condition limit
  165. if ( UCHAR_MAX == GetConditionsCount() )
  166. {
  167. AssertMsg( false, "Too many conditions on a a CItemSelectionCriteria. Max: 255" );
  168. return false;
  169. }
  170. m_vecConditions.AddToTail( pConditionPtr.Detach() );
  171. return true;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: Adds a condition to the selection criteria
  175. // Input: pszField - Field to evaluate on
  176. // eOp - Operator to apply to the value of the field
  177. // flValue - The value to compare.
  178. // bRequired - When true, causes BEvauluate to fail if pszField doesn't
  179. // exist in the KV being checked.
  180. // Output: True if the condition was added, false otherwise
  181. //-----------------------------------------------------------------------------
  182. bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
  183. {
  184. // Enforce maximum string lengths
  185. if ( Q_strlen( pszField ) >= k_cchCreateItemLen )
  186. return false;
  187. // Create the appropriate condition for the operator
  188. switch ( eOp )
  189. {
  190. case k_EOperator_Float_EQ:
  191. case k_EOperator_Float_Not_EQ:
  192. case k_EOperator_Float_LT:
  193. case k_EOperator_Float_Not_LT:
  194. case k_EOperator_Float_LTE:
  195. case k_EOperator_Float_Not_LTE:
  196. case k_EOperator_Float_GT:
  197. case k_EOperator_Float_Not_GT:
  198. case k_EOperator_Float_GTE:
  199. case k_EOperator_Float_Not_GTE:
  200. return BAddCondition( new CFloatCondition( pszField, eOp, flValue, bRequired ) );
  201. default:
  202. AssertMsg1( false, "Bad operator (%d) passed to BAddCondition. Float based operator required for this overload.", eOp );
  203. return false;
  204. }
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose: Adds a condition to the selection criteria
  208. // Input: pszField - Field to evaluate on
  209. // eOp - Operator to apply to the value of the field
  210. // pszValue - The value to compare.
  211. // bRequired - When true, causes BEvauluate to fail if pszField doesn't
  212. // exist in the KV being checked.
  213. // Output: True if the condition was added, false otherwise
  214. //-----------------------------------------------------------------------------
  215. bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired )
  216. {
  217. // Enforce maximum string lengths
  218. if ( Q_strlen( pszField ) >= k_cchCreateItemLen || Q_strlen( pszValue ) >= k_cchCreateItemLen )
  219. return false;
  220. // Create the appropriate condition for the operator
  221. switch ( eOp )
  222. {
  223. case k_EOperator_String_EQ:
  224. case k_EOperator_String_Not_EQ:
  225. return BAddCondition( new CStringCondition( pszField, eOp, pszValue, bRequired ) );
  226. return true;
  227. case k_EOperator_Subkey_Contains:
  228. case k_EOperator_Subkey_Not_Contains:
  229. return BAddCondition( new CSetCondition( pszField, eOp, pszValue, bRequired ) );
  230. return true;
  231. default:
  232. // Try the float operators
  233. return BAddCondition( pszField, eOp, Q_atof( pszValue ), bRequired );
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Checks if a given item matches the item selection criteria
  238. // Input: itemDef - The item definition to evaluate against
  239. // Output: True is the item passes the filter, false otherwise
  240. //-----------------------------------------------------------------------------
  241. bool CItemSelectionCriteria::BEvaluate( const CEconItemDefinition* pItemDef ) const
  242. {
  243. // Disabled items never match
  244. if ( !m_bIgnoreEnabledFlag && !pItemDef->BEnabled() )
  245. return false;
  246. // Filter against level
  247. if ( BItemLevelSet() && (GetItemLevel() != AE_USE_SCRIPT_VALUE) &&
  248. ( GetItemLevel() < pItemDef->GetMinLevel() || GetItemLevel() > pItemDef->GetMaxLevel() ) )
  249. return false;
  250. // Filter against quality
  251. if ( BQualitySet() && (GetQuality() != AE_USE_SCRIPT_VALUE) )
  252. {
  253. if ( GetQuality() != pItemDef->GetQuality() )
  254. {
  255. // Filter out item defs that have a non-any quality if we have a non-matching & non-any quality criteria
  256. if ( k_unItemQuality_Any != GetQuality() && k_unItemQuality_Any != pItemDef->GetQuality() )
  257. return false;
  258. }
  259. }
  260. // Filter against the additional conditions
  261. FOR_EACH_VEC( m_vecConditions, i )
  262. {
  263. if ( !m_vecConditions[i]->BItemDefinitionPassesCriteria( pItemDef ) )
  264. return false;
  265. }
  266. // Check if we have "any" tags
  267. if ( m_vecTags.Count() > 0 )
  268. {
  269. bool bHasTag = false;
  270. FOR_EACH_VEC( m_vecTags, i )
  271. {
  272. if ( pItemDef->HasEconTag( m_vecTags[i] ) )
  273. {
  274. bHasTag = true;
  275. break;
  276. }
  277. }
  278. if ( !bHasTag )
  279. {
  280. return false;
  281. }
  282. }
  283. return true;
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose: Determines if the item matches this condition of the criteria
  287. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  288. // Output: True is the item matches, false otherwise
  289. //-----------------------------------------------------------------------------
  290. bool CItemSelectionCriteria::CCondition::BEvaluate( KeyValues *pKVItem ) const
  291. {
  292. KeyValues *pKVField = pKVItem->FindKey( m_sField.String() );
  293. // Treat an empty string as a missing field as well.
  294. bool bIsEmptyString = false;
  295. if ( m_EOp == k_EOperator_String_EQ || m_EOp == k_EOperator_String_Not_EQ )
  296. {
  297. const char *pszItemVal = pKVField ? pKVField->GetString() : NULL;
  298. bIsEmptyString = ( pszItemVal == NULL || pszItemVal[0] == '\0' );
  299. }
  300. // Deal with missing fields
  301. if ( NULL == pKVField || bIsEmptyString )
  302. {
  303. if ( m_bRequired )
  304. return false;
  305. else
  306. return true;
  307. }
  308. // Run the operator specific check
  309. bool bRet = BInternalEvaluate( pKVItem );
  310. // If this is a "not" operator, reverse the result
  311. if ( m_EOp & k_EOperator_Not )
  312. return !bRet;
  313. else
  314. return bRet;
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Runs the operator specific check for this condition
  318. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  319. // Output: True is the item matches, false otherwise
  320. //-----------------------------------------------------------------------------
  321. bool CItemSelectionCriteria::CStringCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  322. {
  323. Assert( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp );
  324. if( !( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp ) )
  325. return false;
  326. const char *pszItemVal = pKVItem->GetString( m_sField.String() );
  327. return ( 0 == Q_stricmp( m_sValue.String(), pszItemVal ) );
  328. }
  329. bool CItemSelectionCriteria::CStringCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  330. {
  331. CCondition::BSerializeToMsg( msg );
  332. msg.set_string_value( m_sValue.Get() );
  333. return true;
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose: Runs the operator specific check for this condition
  337. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  338. // Output: True is the item matches, false otherwise
  339. //-----------------------------------------------------------------------------
  340. bool CItemSelectionCriteria::CSetCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  341. {
  342. Assert( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp );
  343. if( !( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp ) )
  344. return false;
  345. return ( NULL != pKVItem->FindKey( m_sField.String() )->FindKey( m_sValue.String() ) );
  346. }
  347. bool CItemSelectionCriteria::CSetCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  348. {
  349. CCondition::BSerializeToMsg( msg );
  350. msg.set_string_value( m_sValue.Get() );
  351. return true;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose: Runs the operator specific check for this condition
  355. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  356. // Output: True is the item matches, false otherwise
  357. //-----------------------------------------------------------------------------
  358. bool CItemSelectionCriteria::CFloatCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  359. {
  360. float itemValue = pKVItem->GetFloat( m_sField.String() );
  361. switch ( m_EOp )
  362. {
  363. case k_EOperator_Float_EQ:
  364. case k_EOperator_Float_Not_EQ:
  365. return ( itemValue == m_flValue );
  366. case k_EOperator_Float_LT:
  367. case k_EOperator_Float_Not_LT:
  368. return ( itemValue < m_flValue );
  369. case k_EOperator_Float_LTE:
  370. case k_EOperator_Float_Not_LTE:
  371. return ( itemValue <= m_flValue );
  372. case k_EOperator_Float_GT:
  373. case k_EOperator_Float_Not_GT:
  374. return ( itemValue > m_flValue );
  375. case k_EOperator_Float_GTE:
  376. case k_EOperator_Float_Not_GTE:
  377. return ( itemValue >= m_flValue );
  378. default:
  379. AssertMsg1( false, "Unknown operator: %d", m_EOp );
  380. return false;
  381. }
  382. }
  383. bool CItemSelectionCriteria::CFloatCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  384. {
  385. CCondition::BSerializeToMsg( msg );
  386. msg.set_float_value( m_flValue );
  387. return true;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose: Serialize the item selection criteria to the given message
  391. // Input: msg - The message to serialize to.
  392. // Output: True if the operation was successful, false otherwise.
  393. //-----------------------------------------------------------------------------
  394. bool CItemSelectionCriteria::BSerializeToMsg( CSOItemCriteria & msg ) const
  395. {
  396. msg.set_item_level( m_unItemLevel );
  397. msg.set_item_quality( m_nItemQuality );
  398. msg.set_item_level_set( m_bItemLevelSet );
  399. msg.set_item_quality_set( m_bQualitySet );
  400. msg.set_initial_inventory( m_unInitialInventory );
  401. msg.set_initial_quantity( m_unInitialQuantity );
  402. msg.set_ignore_enabled_flag( m_bIgnoreEnabledFlag );
  403. msg.set_tags( m_strTags );
  404. FOR_EACH_VEC( m_vecConditions, i )
  405. {
  406. CSOItemCriteriaCondition *pConditionMsg = msg.add_conditions();
  407. m_vecConditions[i]->BSerializeToMsg( *pConditionMsg );
  408. }
  409. return true;
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Purpose: Deserializes the item selection criteria from the given message
  413. // Input: msg - The message to deserialize from.
  414. // Output: True if the operation was successful, false otherwise.
  415. //-----------------------------------------------------------------------------
  416. bool CItemSelectionCriteria::BDeserializeFromMsg( const CSOItemCriteria & msg )
  417. {
  418. m_unItemLevel = msg.item_level();
  419. m_nItemQuality = msg.item_quality();
  420. m_bItemLevelSet = msg.item_level_set();
  421. m_bQualitySet = msg.item_quality_set();
  422. m_unInitialInventory = msg.initial_inventory();
  423. m_unInitialQuantity = msg.initial_quantity();
  424. m_bIgnoreEnabledFlag = msg.ignore_enabled_flag();
  425. SetTags( msg.tags().c_str() );
  426. uint32 unCount = msg.conditions_size();
  427. m_vecConditions.EnsureCapacity( unCount );
  428. for ( uint32 i = 0; i < unCount; i++ )
  429. {
  430. const CSOItemCriteriaCondition & cond = msg.conditions( i );
  431. EItemCriteriaOperator eOp = (EItemCriteriaOperator)cond.op();
  432. bool bRequired = cond.required();
  433. // Read the value specific to the condition and add the condition
  434. switch ( eOp )
  435. {
  436. case k_EOperator_Float_EQ:
  437. case k_EOperator_Float_Not_EQ:
  438. case k_EOperator_Float_LT:
  439. case k_EOperator_Float_Not_LT:
  440. case k_EOperator_Float_LTE:
  441. case k_EOperator_Float_Not_LTE:
  442. case k_EOperator_Float_GT:
  443. case k_EOperator_Float_Not_GT:
  444. case k_EOperator_Float_GTE:
  445. case k_EOperator_Float_Not_GTE:
  446. {
  447. if ( !BAddCondition( cond.field().c_str(), eOp, cond.float_value(), bRequired ) ) return false;
  448. break;
  449. }
  450. case k_EOperator_String_EQ:
  451. case k_EOperator_String_Not_EQ:
  452. case k_EOperator_Subkey_Contains:
  453. case k_EOperator_Subkey_Not_Contains:
  454. {
  455. if ( !BAddCondition( cond.field().c_str(), eOp, cond.string_value().c_str(), bRequired ) ) return false;
  456. break;
  457. }
  458. default:
  459. AssertMsg1( false, "Unknown operator (%d) read.", eOp );
  460. return false;
  461. }
  462. }
  463. return true;
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Purpose: Serializes a condition to a message.
  467. // Input: msg - The message to serialize to.
  468. // Output: True if the operation was successful, false otherwise.
  469. //-----------------------------------------------------------------------------
  470. bool CItemSelectionCriteria::CCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  471. {
  472. msg.set_op( m_EOp );
  473. msg.set_field( m_sField.String() );
  474. msg.set_required( m_bRequired );
  475. return true;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. //-----------------------------------------------------------------------------
  480. bool CItemSelectionCriteria::CCondition::BItemDefinitionPassesCriteria( const CEconItemDefinition *pItemDef ) const
  481. {
  482. return BEvaluate( pItemDef->GetRawDefinition() );
  483. }
  484. // Validation
  485. #ifdef DBGFLAG_VALIDATE
  486. //-----------------------------------------------------------------------------
  487. // Purpose: Run a global validation pass on all of our data structures and memory
  488. // allocations.
  489. // Input: validator - Our global validator object
  490. // pchName - Our name (typically a member var in our container)
  491. //-----------------------------------------------------------------------------
  492. void CItemSelectionCriteria::Validate( CValidator &validator, const char *pchName )
  493. {
  494. VALIDATE_SCOPE();
  495. ValidateObj( m_vecConditions );
  496. FOR_EACH_VEC( m_vecConditions, i )
  497. {
  498. ValidatePtr( m_vecConditions[i] );
  499. }
  500. }
  501. void CItemSelectionCriteria::CCondition::Validate( CValidator &validator, const char *pchName )
  502. {
  503. ValidateObj( m_sField );
  504. }
  505. void CItemSelectionCriteria::CStringCondition::Validate( CValidator &validator, const char *pchName )
  506. {
  507. CCondition::Validate( validator, pchName );
  508. ValidateObj( m_sValue );
  509. }
  510. void CItemSelectionCriteria::CSetCondition::Validate( CValidator &validator, const char *pchName )
  511. {
  512. CCondition::Validate( validator, pchName );
  513. ValidateObj( m_sValue );
  514. }
  515. #endif