From dda70cfe4c33b8416eece0809ed0596e05ddf4c5 Mon Sep 17 00:00:00 2001 From: nosoop Date: Thu, 23 Mar 2023 09:08:58 -0700 Subject: [PATCH] Add TF2Econ_GetAttributeList native --- gamedata/tf2.econ_data.txt | 13 ++++++ scripting/include/tf_econ_data.inc | 23 ++++++++++ scripting/tf_econ_data.sp | 70 +++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/gamedata/tf2.econ_data.txt b/gamedata/tf2.econ_data.txt index 0519d2d..fb4d6f4 100644 --- a/gamedata/tf2.econ_data.txt +++ b/gamedata/tf2.econ_data.txt @@ -270,6 +270,12 @@ "linux" "252" "windows" "252" } + "CEconItemSchema::m_AttributeMap" + { + // accessed in loop at CEconItemSchema::GetAttributeDefinitionByName + "linux" "448" + "windows" "448" + } "CEconItemSchema::m_EquipRegions" { // the smaller of the two offsets in CEconItemSchema::GetEquipRegionIndexByName() @@ -339,6 +345,13 @@ "linux" "8" "windows" "8" } + "sizeof(CEconItemAttributeDefinition)" + { + // used for iterating over the attribute map + // this does not include the members of the map itself + "linux" "68" + "windows" "68" + } } } } diff --git a/scripting/include/tf_econ_data.inc b/scripting/include/tf_econ_data.inc index d0ab0ab..ce9961d 100644 --- a/scripting/include/tf_econ_data.inc +++ b/scripting/include/tf_econ_data.inc @@ -38,6 +38,14 @@ enum TFEconParticleSet { */ typedef ItemFilterCriteria = function bool(int itemdef, any data); +/** + * Callback for `TF2Econ_GetAttributeList`. Return `true` if the specified attribute definition + * index should be added to the returned `ArrayList`. + * + * This prototype is the same as `TF2Econ_GetItemList`. Take care to not mix up the callbacks. + */ +typedef AttributeFilterCriteria = function bool(int attrdef, any data); + /** * Returns true if there is an item corresponding to the given item definition index. * TF_ITEMDEF_DEFAULT returns false here. @@ -135,6 +143,8 @@ native bool TF2Econ_GetItemDefinitionString(int itemdef, const char[] key, * callback is passed in, the ArrayList only contains defindexes that the callback returned * `true` on. * + * The resulting ArrayList does not have a defined order. + * * This handle is owned by the calling plugin, so it should be `delete`d when not needed * anymore. */ @@ -212,6 +222,19 @@ native bool TF2Econ_GetAttributeDefinitionString(int attrdef, const char[] key, */ native int TF2Econ_TranslateAttributeNameToDefinitionIndex(const char[] name); +/** + * Returns an ArrayList containing all valid attribute definition indices. If an + * AttributeFilterCriteria callback is passed in, the ArrayList only contains attribute + * definition indices that the callback returned `true` on. + * + * The resulting ArrayList does not have a defined order. + * + * This handle is owned by the calling plugin, so it should be `delete`d when not needed + * anymore. + */ +native ArrayList TF2Econ_GetAttributeList(AttributeFilterCriteria func = INVALID_FUNCTION, + any data = 0); + /** * Stores the quality name in the given buffer and returns true if given a valid quality value, * otherwise returns false; diff --git a/scripting/tf_econ_data.sp b/scripting/tf_econ_data.sp index 64ef310..dd69d74 100644 --- a/scripting/tf_econ_data.sp +++ b/scripting/tf_econ_data.sp @@ -13,7 +13,7 @@ #include #include -#define PLUGIN_VERSION "0.18.4" +#define PLUGIN_VERSION "0.19.0" public Plugin myinfo = { name = "[TF2] Econ Data", author = "nosoop", @@ -24,7 +24,11 @@ public Plugin myinfo = { Address offs_CEconItemSchema_ItemQualities, offs_CEconItemSchema_ItemList, - offs_CEconItemSchema_nItemCount; + offs_CEconItemSchema_nItemCount, + offs_CEconItemSchema_AttributeMap; + +#define ATTRDEF_MAP_OFFSET (view_as
(0x14)) +Address sizeof_CEconItemAttributeDefinition; #include "tf_econ_data/attached_particle_systems.sp" #include "tf_econ_data/loadout_slot.sp" @@ -90,6 +94,9 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) { CreateNative("TF2Econ_TranslateAttributeNameToDefinitionIndex", Native_TranslateAttributeNameToDefinitionIndex); + // global attributes + CreateNative("TF2Econ_GetAttributeList", Native_GetAttributeList); + // quality information CreateNative("TF2Econ_GetQualityName", Native_GetQualityName); CreateNative("TF2Econ_TranslateQualityNameToValue", Native_TranslateQualityNameToValue); @@ -243,6 +250,8 @@ public void OnPluginStart() { GameConfGetAddressOffset(hGameConf, "CEconItemSchema::m_ItemList"); offs_CEconItemSchema_nItemCount = GameConfGetAddressOffset(hGameConf, "CEconItemSchema::m_nItemCount"); + offs_CEconItemSchema_AttributeMap = + GameConfGetAddressOffset(hGameConf, "CEconItemSchema::m_AttributeMap"); offs_CEconItemSchema_EquipRegions = GameConfGetAddressOffset(hGameConf, "CEconItemSchema::m_EquipRegions"); offs_CEconItemSchema_ParticleSystemTree = @@ -296,6 +305,8 @@ public void OnPluginStart() { "CProtoBufScriptObjectDefinitionManager::m_PaintList"); sizeof_static_attrib_t = GameConfGetAddressOffset(hGameConf, "sizeof(static_attrib_t)"); + sizeof_CEconItemAttributeDefinition = GameConfGetAddressOffset(hGameConf, + "sizeof(CEconItemAttributeDefinition)"); delete hGameConf; @@ -363,6 +374,61 @@ int Native_GetItemList(Handle hPlugin, int nParams) { return MoveHandle(itemList, hPlugin); } +int Native_GetAttributeList(Handle hPlugin, int nParams) { + Function func = GetNativeFunction(1); + any data = GetNativeCell(2); + + Address pSchema = GetEconItemSchema(); + if (!pSchema) { + return 0; + } + + ArrayList attributeList = new ArrayList(); + + // this implements FOR_EACH_MAP_FAST + int nAttributeCapacity = LoadFromAddress( + pSchema + offs_CEconItemSchema_AttributeMap + view_as
(0x4), + NumberType_Int32); + + Address pAttributeData = DereferencePointer(pSchema + offs_CEconItemSchema_AttributeMap); + for (int i; i < nAttributeCapacity; i++) { + Address pAttributeDataItem = pAttributeData + + view_as
(i) * (sizeof_CEconItemAttributeDefinition + ATTRDEF_MAP_OFFSET); + + // the struct has 0x14 bytes (ATTRDEF_MAP_OFFSET) preceding the definition + // some internal map data + int index = LoadFromAddress(pAttributeDataItem, NumberType_Int32); + if (index == i) { + continue; + } + + Address pAttributeDefinition = pAttributeDataItem + ATTRDEF_MAP_OFFSET; + int attrdef = LoadFromAddress( + pAttributeDefinition + offs_CEconItemAttributeDefinition_iAttributeDefinitionIndex, + NumberType_Int16); + if (!attrdef) { + continue; + } + + if (func == INVALID_FUNCTION) { + attributeList.Push(attrdef); + continue; + } + + bool result; + Call_StartFunction(hPlugin, func); + Call_PushCell(attrdef); + Call_PushCell(data); + Call_Finish(result); + + if (result) { + attributeList.Push(attrdef); + } + } + + return MoveHandle(attributeList, hPlugin); +} + int Native_GetItemSchemaAddress(Handle hPlugin, int nParams) { return view_as(GetEconItemSchema()); }