Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Commit

Permalink
Add HookValue natives
Browse files Browse the repository at this point in the history
These allow SourceMod plugins to transform values based on attribute classes in the same way the game does it.

This means they don't have to implement rules based on calling GetValue for multiple names and multiple entities.
  • Loading branch information
nosoop committed Oct 4, 2019
1 parent 1aafac0 commit 417513b
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 1 deletion.
16 changes: 16 additions & 0 deletions gamedata/tf2.attributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@
"linux" "@_ZN14CAttributeList20DestroyAllAttributesEv"
"mac" "@_ZN14CAttributeList20DestroyAllAttributesEv"
}
"CAttributeManager::AttribHookValue<float>"
{
// (float value, string_t attrClass, CBaseEntity* ent, CUtlVector<CBaseEntity*> *reentrant, bool const_str)
// called in unique x-ref to "ubercharge_ammo" on Windows
"library" "server"
"linux" "@_ZN17CAttributeManager15AttribHookValueIfEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb"
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x8B\x0D\x2A\x2A\x2A\x2A\x53\x56\x57\x33\xF6\x33\xFF\x89\x75\xF4\x89\x7D\xF8\x8B\x41\x08\x85\xC0\x74\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x6B"
}
"CAttributeManager::AttribHookValue<int>"
{
// (int value, string_t attrClass, CBaseEntity* ent, CUtlVector<CBaseEntity*> *reentrant, bool const_str)
// called in unique x-ref to "mod_max_primary_clip_override" on Windows
"library" "server"
"linux" "@_ZN17CAttributeManager15AttribHookValueIiEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb"
"windows" "\x55\x8B\xEC\x83\xEC\x10\x8B\x0D\x2A\x2A\x2A\x2A\x53\x56\x57\x33\xFF\x33\xDB\x89\x7D\xF0\x89\x5D\xF4\x8B\x41\x08\x85\xC0\x74\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x6B"
}
"CTFPlayer::AddCustomAttribute" //(const char*, float, float), returns void
{
"library" "server"
Expand Down
22 changes: 22 additions & 0 deletions scripting/include/tf2attributes.inc
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,28 @@ native void TF2Attrib_AddCustomPlayerAttribute(int client, const char[] strAttri
*/
native void TF2Attrib_RemoveCustomPlayerAttribute(int client, const char[] strAttrib);

/**
* Applies a transformation to the given initial value, following the rules according to the given attribute class.
*
* @param flInitial Initial float value.
* @param attrClass The attribute class, as from the "attribute_class" key in items_game.
* @param iEntity The entity that should be checked. Checking players also checks their equipped items.
*
* @return Transformed initial value.
*/
native float TF2Attrib_HookValueFloat(float flInitial, const char[] attrClass, int iEntity);

/**
* Applies a transformation to the given initial value, following the rules according to the given attribute class.
*
* @param iInitial Initial float value.
* @param attrClass The attribute class, as from the "attribute_class" key in items_game.
* @param iEntity The entity that should be checked. Checking players also checks their equipped items.
*
* @return Transformed initial value.
*/
native int TF2Attrib_HookValueInt(int nInitial, const char[] attrClass, int iEntity);

/**
* Gets whether the plugin loaded without ANY errors.
* For the purpose of allowing dependencies to ignore the plugin if this returns false.
Expand Down
74 changes: 73 additions & 1 deletion scripting/tf2attributes.sp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#define PLUGIN_NAME "[TF2] TF2Attributes"
#define PLUGIN_AUTHOR "FlaminSarge"
#define PLUGIN_VERSION "1.3.3@nosoop-1.5.0"
#define PLUGIN_VERSION "1.3.3@nosoop-1.6.0"
#define PLUGIN_CONTACT "http://forums.alliedmods.net/showthread.php?t=210221"
#define PLUGIN_DESCRIPTION "Functions to add/get attributes for TF2 players/items"

Expand All @@ -34,6 +34,8 @@ Handle hSDKRemoveAttribute;
Handle hSDKDestroyAllAttributes;
Handle hSDKAddCustomAttribute;
Handle hSDKRemoveCustomAttribute;
Handle hSDKAttributeHookFloat;
Handle hSDKAttributeHookInt;

static bool g_bPluginReady = false;
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
Expand Down Expand Up @@ -66,6 +68,8 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
CreateNative("TF2Attrib_IsValidAttributeName", Native_IsValidAttributeName);
CreateNative("TF2Attrib_AddCustomPlayerAttribute", Native_AddCustomAttribute);
CreateNative("TF2Attrib_RemoveCustomPlayerAttribute", Native_RemoveCustomAttribute);
CreateNative("TF2Attrib_HookValueFloat", Native_HookValueFloat);
CreateNative("TF2Attrib_HookValueInt", Native_HookValueInt);
CreateNative("TF2Attrib_IsReady", Native_IsReady);

//unused, backcompat I guess?
Expand Down Expand Up @@ -197,6 +201,32 @@ public void OnPluginStart() {
SetFailState("Could not initialize call to CTFPlayer::AddCustomAttribute");
}

StartPrepSDKCall(SDKCall_Static);
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "CAttributeManager::AttribHookValue<float>");
PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); // initial value
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); // attribute class
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); // CBaseEntity* entity
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // CUtlVector<CBaseEntity*>, set to nullptr
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); // bool const_string
hSDKAttributeHookFloat = EndPrepSDKCall();
if (!hSDKAttributeHookFloat) {
SetFailState("Could not initialize call to CAttributeManager::AttribHookValue<float>");
}

StartPrepSDKCall(SDKCall_Static);
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "CAttributeManager::AttribHookValue<int>");
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // initial value
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); // attribute class
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); // CBaseEntity* entity
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // CUtlVector<CBaseEntity*>, set to nullptr
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); // bool const_string
hSDKAttributeHookInt = EndPrepSDKCall();
if (!hSDKAttributeHookInt) {
SetFailState("Could not initialize call to CAttributeManager::AttribHookValue<int>");
}

CreateConVar("tf2attributes_version", PLUGIN_VERSION, "TF2Attributes version number", FCVAR_NOTIFY);

g_bPluginReady = true;
Expand Down Expand Up @@ -618,6 +648,48 @@ public int Native_RemoveCustomAttribute(Handle plugin, int numParams) {
return;
}

/* native float TF2Attrib_HookValueFloat(float flInitial, const char[] attrClass, int iEntity); */
public int Native_HookValueFloat(Handle plugin, int numParams) {
/**
* CAttributeManager::AttribHookValue<float>(float value, string_t attr_class,
* CBaseEntity const* entity, CUtlVector<CBaseEntity*> reentrantList,
* bool is_const_str);
*
* `value` is the value that is returned after modifiers based on `attr_class`.
* `reentrantList` seems to be a list of entities to ignore?
* `is_const_str` is true iff the `attr_class` is hardcoded
* (i.e., it's at a fixed location) -- this is never true from a plugin
* This determines if the game uses AllocPooledString_StaticConstantStringPointer
* (when is_const_str == true) or AllocPooledString (false).
*/
float initial = GetNativeCell(1);

int buflen;
GetNativeStringLength(2, buflen);
char[] attrClass = new char[++buflen];
GetNativeString(2, attrClass, buflen);

int entity = GetNativeCell(3);

return SDKCall(hSDKAttributeHookFloat, initial, attrClass, entity,
Address_Null, false);
}

/* native float TF2Attrib_HookValueInt(int nInitial, const char[] attrClass, int iEntity); */
public int Native_HookValueInt(Handle plugin, int numParams) {
int initial = GetNativeCell(1);

int buflen;
GetNativeStringLength(2, buflen);
char[] attrClass = new char[++buflen];
GetNativeString(2, attrClass, buflen);

int entity = GetNativeCell(3);

return SDKCall(hSDKAttributeHookInt, initial, attrClass, entity,
Address_Null, false);
}

/* helper functions */

static Address GetItemSchema() {
Expand Down

0 comments on commit 417513b

Please sign in to comment.