diff --git a/gamedata/tf2.econ_data.txt b/gamedata/tf2.econ_data.txt index 0ad7abc..410fec9 100644 --- a/gamedata/tf2.econ_data.txt +++ b/gamedata/tf2.econ_data.txt @@ -66,6 +66,11 @@ "linux" "18" "windows" "18" } + "CEconItemDefinition::m_AttributeList" + { + "linux" "28" + "windows" "28" + } "CEconItemDefinition::m_pszLocalizedItemName" { // set near x-ref "Test Item %d" diff --git a/scripting/include/tf_econ_data.inc b/scripting/include/tf_econ_data.inc index 8cbeae6..c019900 100644 --- a/scripting/include/tf_econ_data.inc +++ b/scripting/include/tf_econ_data.inc @@ -50,6 +50,15 @@ native int TF2Econ_GetItemSlot(int defindex, TFClassType playerClass); */ native bool TF2Econ_GetItemLevelRange(int defindex, int &iMinLevel, int &iMaxLevel); +/** + * Returns an `ArrayList` containing attribute defindex / value pairs corresponding to the given + * item definition, or `null` if not a valid item definition. + * + * This handle is owned by the calling plugin, so it should be `delete`d when not needed + * anymore. + */ +native ArrayList TF2Econ_GetItemStaticAttributes(int defindex); + /** * Returns an arbiitrary string from an item definition's KeyValues structure. * You may use subkey notation ('/') to retrieve nested values. @@ -105,6 +114,10 @@ native bool TF2Econ_IsAttributeHidden(int defindex); /** * Returns true if the attribute is stored as an integer (corresponds to the "stored_as_integer" * key). + * + * Not sure when this is actually used -- certain attributes such as + * "mod max primary clip override" are flagged as true, but are float values when retrieved + * via `TF2Econ_GetItemStaticAttributes()`. */ native bool TF2Econ_IsAttributeStoredAsInteger(int defindex); diff --git a/scripting/tf_econ_data.sp b/scripting/tf_econ_data.sp index d2bb6da..3c3acfa 100644 --- a/scripting/tf_econ_data.sp +++ b/scripting/tf_econ_data.sp @@ -13,7 +13,7 @@ #include <stocksoup/handles> #include <stocksoup/memory> -#define PLUGIN_VERSION "0.8.1" +#define PLUGIN_VERSION "0.9.0" public Plugin myinfo = { name = "[TF2] Econ Data", author = "nosoop", @@ -45,6 +45,7 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) { CreateNative("TF2Econ_GetItemClassName", Native_GetItemClassName); CreateNative("TF2Econ_GetItemSlot", Native_GetItemSlot); CreateNative("TF2Econ_GetItemLevelRange", Native_GetItemLevelRange); + CreateNative("TF2Econ_GetItemStaticAttributes", Native_GetItemStaticAttributes); CreateNative("TF2Econ_GetItemDefinitionString", Native_GetItemDefinitionString); // global items @@ -130,6 +131,8 @@ public void OnPluginStart() { GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_u8MinLevel"); offs_CEconItemDefinition_u8MaxLevel = GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_u8MaxLevel"); + offs_CEconItemDefinition_AttributeList = + GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_AttributeList"); offs_CEconItemDefinition_pszLocalizedItemName = GameConfGetAddressOffset(hGameConf, "CEconItemDefinition::m_pszLocalizedItemName"); offs_CEconItemDefinition_pszItemClassname = diff --git a/scripting/tf_econ_data/item_definition.sp b/scripting/tf_econ_data/item_definition.sp index f3566e0..0ac883e 100644 --- a/scripting/tf_econ_data/item_definition.sp +++ b/scripting/tf_econ_data/item_definition.sp @@ -1,6 +1,7 @@ Address offs_CEconItemDefinition_pKeyValues, offs_CEconItemDefinition_u8MinLevel, offs_CEconItemDefinition_u8MaxLevel, + offs_CEconItemDefinition_AttributeList, offs_CEconItemDefinition_pszLocalizedItemName, offs_CEconItemDefinition_pszItemClassname, offs_CEconItemDefinition_pszItemName; @@ -92,6 +93,36 @@ bool GetItemLevelRange(int defindex, int &iMinLevel, int &iMaxLevel) { return true; } +public int Native_GetItemStaticAttributes(Handle hPlugin, int nParams) { + int defindex = GetNativeCell(1); + + Address pItemDef = GetEconItemDefinition(defindex); + if (!pItemDef) { + return view_as<int>(INVALID_HANDLE); + } + + // get size from CUtlVector + int nAttribs = LoadFromAddress( + pItemDef + offs_CEconItemDefinition_AttributeList + view_as<Address>(0x0C), + NumberType_Int32); + Address pAttribList = DereferencePointer(pItemDef + offs_CEconItemDefinition_AttributeList); + + // struct { attribute_defindex, value } + ArrayList attributeList = new ArrayList(2, nAttribs); + for (int i; i < nAttribs; i++) { + // TODO push attributes to list + Address pStaticAttrib = pAttribList + view_as<Address>(i * 0x08); + + int attrIndex = LoadFromAddress(pStaticAttrib, NumberType_Int16); + any attrValue = LoadFromAddress(pStaticAttrib + view_as<Address>(0x04), + NumberType_Int32); + + attributeList.Set(i, attrIndex, 0); + attributeList.Set(i, attrValue, 1); + } + return MoveHandle(attributeList, hPlugin); +} + public int Native_GetItemDefinitionString(Handle hPlugin, int nParams) { int defindex = GetNativeCell(1); int keylen;