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.
267 lines
10 KiB
267 lines
10 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Base class for generating store meta data. Abstract methods need |
|
// to be overridden on a per-product basis. |
|
// |
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
#include "cbase.h" |
|
#include "econ_storecategory.h" |
|
#include "econ_store.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Invalid = (StoreCategoryID_t)0; |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_New = CEconStoreCategoryManager::GetCategoryID( "New" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Weapons = CEconStoreCategoryManager::GetCategoryID( "Weapons" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Limited = CEconStoreCategoryManager::GetCategoryID( "Limited" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Maps = CEconStoreCategoryManager::GetCategoryID( "Maps" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Cosmetics = CEconStoreCategoryManager::GetCategoryID( "Cosmetics" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Taunts = CEconStoreCategoryManager::GetCategoryID( "Taunts" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Tools = CEconStoreCategoryManager::GetCategoryID( "Tools" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Bundles = CEconStoreCategoryManager::GetCategoryID( "Bundles" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Collections= CEconStoreCategoryManager::GetCategoryID( "Collections" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Popular = CEconStoreCategoryManager::GetCategoryID( "Popular" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_OnSale = CEconStoreCategoryManager::GetCategoryID( "OnSale" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Featured = CEconStoreCategoryManager::GetCategoryID( "Featured" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_ClassBundles = CEconStoreCategoryManager::GetCategoryID( "Class_Bundles" ); |
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::k_CategoryID_Highlighted = CEconStoreCategoryManager::GetCategoryID( "Highlighted" ); |
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
CEconStoreCategoryManager::CEconStoreCategoryManager() |
|
{ |
|
m_unHomeCategoryID = k_CategoryID_Invalid; |
|
} |
|
|
|
bool CEconStoreCategoryManager::BInit( CEconStorePriceSheet *pPriceSheet, KeyValues *pStoreMetaDataKV ) |
|
{ |
|
KeyValues *pCategoriesKV = pStoreMetaDataKV->FindKey( "categories" ); |
|
if ( !pCategoriesKV ) |
|
{ |
|
AssertMsg( 0, "Could not find 'categories' subkey!" ); |
|
return false; |
|
} |
|
|
|
FOR_EACH_TRUE_SUBKEY( pCategoriesKV, pKVCurCategory ) |
|
{ |
|
const int iIndex = m_vecCategories.AddToTail(); |
|
StoreCategory_t &curCategory = m_vecCategories[ iIndex ]; |
|
if ( !BInitCategory( pPriceSheet, &curCategory, pKVCurCategory ) ) |
|
return false; |
|
|
|
// If the current category is the home page, cache off its ID |
|
if ( curCategory.m_bIsHome ) |
|
{ |
|
m_unHomeCategoryID = curCategory.m_unID; |
|
} |
|
} |
|
|
|
// Verify that any parents point to valid categories |
|
FOR_EACH_VEC( m_vecCategories, i ) |
|
{ |
|
const StoreCategory_t &curCategory = m_vecCategories[i]; |
|
|
|
// Skip current category if it refers to invalid, which is fine |
|
if ( curCategory.m_unParentCategoryID == k_CategoryID_Invalid ) |
|
continue; |
|
|
|
// A category can't be a parent to itself |
|
if ( curCategory.m_unID == curCategory.m_unParentCategoryID ) |
|
{ |
|
AssertMsg( 0, "Store category %s is using itself as a parent category!", curCategory.m_pchName ); |
|
} |
|
|
|
// Attempt to find the current section's parent ID |
|
bool bFound = false; |
|
FOR_EACH_VEC( m_vecCategories, j ) |
|
{ |
|
// Don't compare against self |
|
if ( i == j ) |
|
continue; |
|
|
|
if ( m_vecCategories[j].m_unID == curCategory.m_unParentCategoryID ) |
|
{ |
|
bFound = true; |
|
break; |
|
} |
|
} |
|
|
|
// If we couldn't find the current section's parent ID, assert |
|
if ( !bFound ) |
|
{ |
|
AssertMsg( 0, "Category %s refers to an unknown parent category - check your spelling!", curCategory.m_pchName ); |
|
} |
|
} |
|
|
|
// Setup child category lists - looping twice to keep this code clean and easy to read |
|
FOR_EACH_VEC( m_vecCategories, i ) |
|
{ |
|
const StoreCategory_t &curCategory = m_vecCategories[i]; |
|
|
|
if ( k_CategoryID_Invalid == curCategory.m_unParentCategoryID ) |
|
continue; |
|
|
|
StoreCategory_t *pParentCategory = GetStoreCategoryFromID( curCategory.m_unParentCategoryID ); |
|
if ( !pParentCategory ) |
|
continue; |
|
|
|
pParentCategory->m_vecSubcategories.AddToTail( &curCategory ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
bool CEconStoreCategoryManager::BInitCategory( CEconStorePriceSheet *pPriceSheet, StoreCategory_t *pCategory, KeyValues* pKVTab ) |
|
{ |
|
const char *pDefaultResFile = "Resource/UI/econ/store/v2/StorePage.res"; |
|
|
|
// Get the main category name |
|
const char* pCategoryName = pKVTab->GetName(); |
|
if ( !pCategoryName || !pCategoryName[0] ) |
|
{ |
|
AssertMsg( 0, "Invalid category name!" ); |
|
return false; |
|
} |
|
|
|
const bool bIsHome = pKVTab->GetBool( "home", false ); |
|
pCategory->m_bIsHome = bIsHome; |
|
|
|
pCategory->m_pchRawName = pCategoryName; |
|
pCategory->m_unID = GetCategoryID( pCategoryName ); |
|
|
|
pCategory->m_bUseLargeCells = pKVTab->GetBool( "use_large_cells", false ); |
|
pCategory->m_bVisible = pKVTab->GetBool( "visible", true ); |
|
pCategory->m_bInGameOnly = pKVTab->GetBool( "ingame_only", false ); |
|
pCategory->m_bDefaultTab = pKVTab->GetBool( "default", false ); |
|
|
|
#if defined( GC_DLL ) |
|
// Until we replace the in-game store with the web store, we have this hacky override property, so |
|
// that we can call the home page "HOME" in the game client and "TOP SELLERS" on the web. The home page |
|
// will be evolving shortly to include a lot more than just a list of top sellers. |
|
const char *pchLabelTokenWebOverride = pKVTab->GetString( "web_label_token_override", NULL ); |
|
#else |
|
const char *pchLabelTokenWebOverride = NULL; |
|
#endif |
|
pCategory->m_pchName = pchLabelTokenWebOverride ? pchLabelTokenWebOverride : pKVTab->GetString( "label_token", "#Store_Unknown" ); |
|
|
|
pCategory->m_pchPageClass = pKVTab->GetString( "page_class", "CStorePage" ); |
|
pCategory->m_pchPageRes = pKVTab->GetString( "page_res", pDefaultResFile ); |
|
pCategory->m_pchSortType = pKVTab->GetString( "sort_type", "" ); |
|
|
|
// Important for web store but not needed for VGUI store |
|
#if defined( GC_DLL ) |
|
if ( !bIsHome ) |
|
{ |
|
const char *pchDropdownPrefabName = pKVTab->GetString( "dropdown_prefab", NULL ); |
|
pCategory->m_pDropdownPrefab = GEconStoreMetaData()->FindDropdownPrefab( pchDropdownPrefabName ); |
|
if ( !pCategory->m_pDropdownPrefab ) |
|
{ |
|
AssertMsg( pCategory->m_pDropdownPrefab, CFmtStr( "Invalid dropdown prefab name, '%s'!", pchDropdownPrefabName ).Access() ); |
|
return false; |
|
} |
|
} |
|
else |
|
{ |
|
pCategory->m_pDropdownPrefab = NULL; |
|
} |
|
#endif |
|
|
|
// Look for a parent category for non-home categories |
|
if ( !bIsHome ) |
|
{ |
|
const char *pParentCategoryName = pKVTab->GetString( "parent", NULL ); |
|
if ( pParentCategoryName ) |
|
{ |
|
pCategory->m_unParentCategoryID = GetCategoryID( pParentCategoryName ); |
|
} |
|
else |
|
{ |
|
pCategory->m_unParentCategoryID = k_CategoryID_Invalid; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool CEconStoreCategoryManager::BOnPriceSheetLoaded( CEconStorePriceSheet *pPriceSheet ) |
|
{ |
|
// Go through all categories/subcategories and add a list of items to each. |
|
// If an item belongs to a subcategory, it will also be added to its parent category. For example, |
|
// a hat will be added to both the "hats" subcategory and the "items" parent category. |
|
FOR_EACH_VEC( m_vecCategories, iCategory ) |
|
{ |
|
StoreCategory_t &Category = m_vecCategories[iCategory]; |
|
|
|
// find all entries that match |
|
const CEconStorePriceSheet::EconStoreEntryMap_t &mapEntries = pPriceSheet->GetEntries(); |
|
FOR_EACH_MAP_FAST( mapEntries, idx ) |
|
{ |
|
const econ_store_entry_t &entry = mapEntries[idx]; |
|
|
|
if ( entry.IsListedInCategoryOrSubcategories( Category ) ) |
|
{ |
|
Category.m_vecEntries.InsertNoSort( entry.GetItemDefinitionIndex() ); |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
/*static*/ StoreCategoryID_t CEconStoreCategoryManager::GetCategoryID( const char *pCategoryName ) |
|
{ |
|
// Make the input lower case |
|
CUtlString strLowerCase = pCategoryName; |
|
strLowerCase.ToLower(); |
|
|
|
return CRC32_ProcessSingleBuffer( (void*)strLowerCase.Get(), strLowerCase.Length() ); |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
const CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID ) const |
|
{ |
|
return const_cast< CEconStoreCategoryManager * >( this )->GetStoreCategoryFromID( unID ); |
|
} |
|
|
|
CEconStoreCategoryManager::StoreCategory_t *CEconStoreCategoryManager::GetStoreCategoryFromID( StoreCategoryID_t unID ) |
|
{ |
|
if ( k_CategoryID_Invalid != unID ) |
|
{ |
|
FOR_EACH_VEC( m_vecCategories, i ) |
|
{ |
|
if ( unID == m_vecCategories[i].m_unID ) |
|
return &m_vecCategories[i]; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
static CEconStoreCategoryManager *gs_pEconStoreCategoryManager = NULL; |
|
CEconStoreCategoryManager *GEconStoreCategoryManager() |
|
{ |
|
if ( !gs_pEconStoreCategoryManager ) |
|
{ |
|
gs_pEconStoreCategoryManager = new CEconStoreCategoryManager(); |
|
} |
|
|
|
return gs_pEconStoreCategoryManager; |
|
} |
|
|
|
void ClearEconStoreCategoryManager() |
|
{ |
|
delete gs_pEconStoreCategoryManager; |
|
gs_pEconStoreCategoryManager = NULL; |
|
} |