diff --git a/csgo_gc/inventory.cpp b/csgo_gc/inventory.cpp index bf7c95c..abd1384 100644 --- a/csgo_gc/inventory.cpp +++ b/csgo_gc/inventory.cpp @@ -524,6 +524,13 @@ bool Inventory::UnlockCrate(uint64_t crateId, keyId, key->second.def_index(), crateId); return false; } + + if (!m_itemSchema.IsKeyCompatibleWithCrate(key->second.def_index(), crate->second.def_index())) + { + Platform::Print("UnlockCrate: key item %llu def %u is not compatible with crate %llu def %u\n", + keyId, key->second.def_index(), crateId, crate->second.def_index()); + return false; + } } // CASE OPENING @@ -853,11 +860,11 @@ bool Inventory::ApplySticker(const CMsgApplySticker &message, return false; } + uint32_t targetDefIndex = 0; CSOEconItem *item = nullptr; - if (message.baseitem_defidx()) { - item = &CreateItem(message.baseitem_defidx(), ItemOriginBaseItem, UnacknowledgedInvalid); + targetDefIndex = message.baseitem_defidx(); } else { @@ -868,9 +875,31 @@ bool Inventory::ApplySticker(const CMsgApplySticker &message, return false; } + targetDefIndex = it->second.def_index(); item = &it->second; } + if (sticker->second.def_index() == ItemSchema::ItemPatch) + { + if (!m_itemSchema.CanApplyPatchToDefIndex(targetDefIndex)) + { + Platform::Print("ApplySticker: patch item %llu cannot be applied to target def %u (target item %llu)\n", + message.sticker_item_id(), targetDefIndex, message.item_item_id()); + return false; + } + } + else if (!m_itemSchema.CanApplyStickerToDefIndex(targetDefIndex)) + { + Platform::Print("ApplySticker: sticker item %llu cannot be applied to target def %u (target item %llu)\n", + message.sticker_item_id(), targetDefIndex, message.item_item_id()); + return false; + } + + if (message.baseitem_defidx()) + { + item = &CreateItem(message.baseitem_defidx(), ItemOriginBaseItem, UnacknowledgedInvalid); + } + assert(item); // get the sticker kit def index @@ -1174,6 +1203,13 @@ bool Inventory::NameItem(uint64_t nameTagId, return false; } + if (!m_itemSchema.CanNameDefIndex(it->second.def_index())) + { + Platform::Print("NameItem: target %llu def %u is not nameable by name tag %llu\n", + itemId, it->second.def_index(), nameTagId); + return false; + } + it->second.mutable_custom_name()->assign(name); ToSingleObject(update, it->second); @@ -1211,6 +1247,13 @@ bool Inventory::NameBaseItem(uint64_t nameTagId, return false; } + if (!m_itemSchema.CanNameDefIndex(defIndex)) + { + Platform::Print("NameBaseItem: base def %u is not nameable by name tag %llu\n", + defIndex, nameTagId); + return false; + } + CSOEconItem &item = CreateItem(defIndex, ItemOriginBaseItem, UnacknowledgedInvalid); item.mutable_custom_name()->assign(name); diff --git a/csgo_gc/item_schema.cpp b/csgo_gc/item_schema.cpp index 005bf58..ea83141 100644 --- a/csgo_gc/item_schema.cpp +++ b/csgo_gc/item_schema.cpp @@ -68,6 +68,9 @@ ItemInfo::ItemInfo(uint32_t defIndex) , m_quality{ ItemSchema::QualityNormal } , m_level{ 1 } , m_supplyCrateSeries{ 0 } + , m_canSticker{ false } + , m_canPatch{ false } + , m_nameable{ false } , m_isCoupon{ false } , m_willProduceStatTrak{ false } { @@ -736,6 +739,38 @@ void ItemSchema::ParseItemRecursive(ItemInfo &info, const KeyValue &itemKey, con info.m_willProduceStatTrak = itemKey.GetNumber("will_produce_stattrak", false); + const KeyValue *capabilities = itemKey.GetSubkey("capabilities"); + if (capabilities) + { + const KeyValue *canSticker = capabilities->GetSubkey("can_sticker"); + if (canSticker) + { + info.m_canSticker = FromString(canSticker->String()) != 0; + } + + const KeyValue *canPatch = capabilities->GetSubkey("can_patch"); + if (canPatch) + { + info.m_canPatch = FromString(canPatch->String()) != 0; + } + + const KeyValue *nameable = capabilities->GetSubkey("nameable"); + if (nameable) + { + info.m_nameable = FromString(nameable->String()) != 0; + } + } + + const KeyValue *tool = itemKey.GetSubkey("tool"); + if (tool) + { + std::string_view restriction = tool->GetString("restriction"); + if (restriction.size()) + { + info.m_toolRestriction = restriction; + } + } + const KeyValue *attributes = itemKey.GetSubkey("attributes"); if (attributes) { @@ -1430,3 +1465,38 @@ bool ItemSchema::IsStatTrakSwapToolDefIndex(uint32_t defIndex) const return ItemInfoContains(*info, "stattrak") && ItemInfoContains(*info, "swap"); } + +bool ItemSchema::IsKeyCompatibleWithCrate(uint32_t keyDefIndex, uint32_t crateDefIndex) const +{ + const ItemInfo *keyInfo = ItemInfoByDefIndex(keyDefIndex); + const ItemInfo *crateInfo = ItemInfoByDefIndex(crateDefIndex); + if (!keyInfo || !crateInfo) + { + return false; + } + + if (keyInfo->m_toolRestriction.empty() || crateInfo->m_toolRestriction.empty()) + { + return true; + } + + return keyInfo->m_toolRestriction == crateInfo->m_toolRestriction; +} + +bool ItemSchema::CanApplyStickerToDefIndex(uint32_t defIndex) const +{ + const ItemInfo *info = ItemInfoByDefIndex(defIndex); + return info && info->m_canSticker; +} + +bool ItemSchema::CanApplyPatchToDefIndex(uint32_t defIndex) const +{ + const ItemInfo *info = ItemInfoByDefIndex(defIndex); + return info && info->m_canPatch; +} + +bool ItemSchema::CanNameDefIndex(uint32_t defIndex) const +{ + const ItemInfo *info = ItemInfoByDefIndex(defIndex); + return info && info->m_nameable; +} diff --git a/csgo_gc/item_schema.h b/csgo_gc/item_schema.h index 4ca68e9..d8b5762 100644 --- a/csgo_gc/item_schema.h +++ b/csgo_gc/item_schema.h @@ -33,6 +33,10 @@ class ItemInfo uint32_t m_supplyCrateSeries; // cases only std::string m_itemType; std::vector m_prefabs; + std::string m_toolRestriction; + bool m_canSticker; + bool m_canPatch; + bool m_nameable; // kludge for coupons so we can buy stuff from the store bool m_isCoupon; @@ -159,6 +163,10 @@ class ItemSchema bool IsKeyToolDefIndex(uint32_t defIndex) const; bool IsNameTagToolDefIndex(uint32_t defIndex) const; bool IsStatTrakSwapToolDefIndex(uint32_t defIndex) const; + bool IsKeyCompatibleWithCrate(uint32_t keyDefIndex, uint32_t crateDefIndex) const; + bool CanApplyStickerToDefIndex(uint32_t defIndex) const; + bool CanApplyPatchToDefIndex(uint32_t defIndex) const; + bool CanNameDefIndex(uint32_t defIndex) const; public: