The Salt Boss
|

03-10-2012
, 21:46
DHooks (Dynamic Hooks - Dev Preview)
|
#1
|
Oh no, not ANOTHER hooks extension!!!
This extension is not just ANOTHER hooks extension  But rather allows sourcemod plugins to create their own hooks.
Note that you cannot set or get a unknown param/return's value.
As a basic note, if the return type is void there won’t be a return handle pushed to the callback. If there is no params no param handle will be pushed. If this pointer is set to ignore this won’t be pushed.
Example/Test Plugin
PHP Code:
#pragma semicolon 1 #include <sourcemod> #include <sdktools> #include <dhooks>
// int CBaseCombatCharacter::BloodColor(void) new Handle:hBloodColor;
// bool CBaseCombatCharacter::Weapon_CanUse(CBaseCombatWeapon *) new Handle:hHookCanUse;
// Vector CBasePlayer::GetPlayerMaxs() new Handle:hGetMaxs;
// string_t CBaseEntity::GetModelName(void) new Handle:hGetModelName;
// bool CGameRules::CanHaveAmmo(CBaseCombatCharacter *, int) new Handle:hCanHaveAmmo;
// void CBaseEntity::SetModel(char const*) new Handle:hSetModel;
//float CCSPlayer::GetPlayerMaxSpeed() new Handle:hGetSpeed;
//int CCSPlayer::OnTakeDamage(CTakeDamageInfo const&) new Handle:hTakeDamage;
// bool CBaseEntity::AcceptInput(char const*, CBaseEntity*, CBaseEntity*, variant_t, int) new Handle:hAcceptInput;
//int CBaseCombatCharacter::GiveAmmo(int, int, bool) new Handle:hGiveAmmo;
// CVEngineServer::ClientPrintf(edict_t *, char const*) new Handle:hClientPrintf;
public OnPluginStart() { new Handle:temp = LoadGameConfigFile("dhooks-test.games"); if(temp == INVALID_HANDLE) { SetFailState("Why you no has gamedata?"); } new offset; offset = GameConfGetOffset(temp, "BloodColor"); hBloodColor = DHookCreate(offset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, BloodColorPost); offset = GameConfGetOffset(temp, "GetModelName"); hGetModelName = DHookCreate(offset, HookType_Entity, ReturnType_String, ThisPointer_CBaseEntity, GetModelName); offset = GameConfGetOffset(temp, "GetMaxs"); hGetMaxs = DHookCreate(offset, HookType_Entity, ReturnType_Vector, ThisPointer_Ignore, GetMaxsPost); offset = GameConfGetOffset(temp, "CanUse"); hHookCanUse = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, CanUsePost); DHookAddParam(hHookCanUse, HookParamType_CBaseEntity); offset = GameConfGetOffset(temp, "CanHaveAmmo"); hCanHaveAmmo = DHookCreate(offset, HookType_GameRules, ReturnType_Bool, ThisPointer_Ignore, CanHaveAmmoPost); DHookAddParam(hCanHaveAmmo, HookParamType_CBaseEntity); DHookAddParam(hCanHaveAmmo, HookParamType_Int); offset = GameConfGetOffset(temp, "SetModel"); hSetModel = DHookCreate(offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, SetModel); DHookAddParam(hSetModel, HookParamType_CharPtr); offset = GameConfGetOffset(temp, "AcceptInput"); hAcceptInput = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, AcceptInput); DHookAddParam(hAcceptInput, HookParamType_CharPtr); DHookAddParam(hAcceptInput, HookParamType_CBaseEntity); DHookAddParam(hAcceptInput, HookParamType_CBaseEntity); DHookAddParam(hAcceptInput, HookParamType_Object, 20, DHookPass_ByVal|DHookPass_ODTOR|DHookPass_OCTOR|DHookPass_OASSIGNOP); //varaint_t is a union of 12 (float[3]) plus two int type params 12 + 8 = 20 DHookAddParam(hAcceptInput, HookParamType_Int); offset = GameConfGetOffset(temp, "GetMaxPlayerSpeed"); hGetSpeed = DHookCreate(offset, HookType_Entity, ReturnType_Float, ThisPointer_CBaseEntity, GetMaxPlayerSpeedPost); offset = GameConfGetOffset(temp, "GiveAmmo"); hGiveAmmo = DHookCreate(offset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, GiveAmmo); DHookAddParam(hGiveAmmo, HookParamType_Int); DHookAddParam(hGiveAmmo, HookParamType_Int); DHookAddParam(hGiveAmmo, HookParamType_Bool); offset = GameConfGetOffset(temp, "OnTakeDamage"); hTakeDamage = DHookCreate(offset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, OnTakeDamage); DHookAddParam(hTakeDamage, HookParamType_ObjectPtr, -1, DHookPass_ByRef); DHookAddEntityListener(ListenType_Created, EntityCreated); //Add client printf hook pThis requires effort StartPrepSDKCall(SDKCall_Static); if(!PrepSDKCall_SetFromConf(temp, SDKConf_Signature, "CreateInterface")) { SetFailState("Failed to get CreateInterface"); CloseHandle(temp); } PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL); PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); new String:iface[64]; if(!GameConfGetKeyValue(temp, "EngineInterface", iface, sizeof(iface))) { SetFailState("Failed to get engine interface name"); CloseHandle(temp); } new Handle:call = EndPrepSDKCall(); new Address:addr = SDKCall(call, iface, 0); CloseHandle(call); if(!addr) { SetFailState("Failed to get engine ptr"); } offset = GameConfGetOffset(temp, "ClientPrintf"); hClientPrintf = DHookCreate(offset, HookType_Raw, ReturnType_Void, ThisPointer_Ignore, Hook_ClientPrintf); DHookAddParam(hClientPrintf, HookParamType_Edict); DHookAddParam(hClientPrintf, HookParamType_CharPtr); DHookRaw(hClientPrintf, false, addr); CloseHandle(temp); }
public MRESReturn:Hook_ClientPrintf(Handle:hParams) { new client = DHookGetParam(hParams, 1); decl String:buffer[1024]; DHookGetParamString(hParams, 2, buffer, sizeof(buffer)); PrintToChat(client, "BUFFER %s", buffer); return MRES_Ignored; }
public MRESReturn:AcceptInput(pThis, Handle:hReturn, Handle:hParams) { new String:command[128]; DHookGetParamString(hParams, 1, command, sizeof(command)); new type = DHookGetParamObjectPtrVar(hParams, 4, 16,ObjectValueType_Int); new String:wtf[128]; DHookGetParamObjectPtrString(hParams, 4, 0, ObjectValueType_String, wtf, sizeof(wtf)); PrintToServer("Command %s Type %i String %s", command, type, wtf); DHookSetReturn(hReturn, false); return MRES_Supercede; }
public OnMapStart() { //Hook Gamerules function in map start DHookGamerules(hCanHaveAmmo, true, RemovalCB); }
public OnClientPutInServer(client) { DHookEntity(hSetModel, false, client, RemovalCB); DHookEntity(hHookCanUse, true, client, RemovalCB); DHookEntity(hGetSpeed, true, client, RemovalCB); DHookEntity(hGiveAmmo, false, client); DHookEntity(hGetModelName, true, client); DHookEntity(hTakeDamage, false, client); DHookEntity(hGetMaxs, true, client, RemovalCB); DHookEntity(hBloodColor, true, client); }
public EntityCreated(entity, const String:classname[]) { if(strcmp(classname, "point_servercommand") == 0) { DHookEntity(hAcceptInput, false, entity); } }
//int CCSPlayer::OnTakeDamage(CTakeDamageInfo const&) public MRESReturn:OnTakeDamage(pThis, Handle:hReturn, Handle:hParams) { PrintToServer("DHooksHacks = Victim %i, Attacker %i, Inflictor %i, Damage %f", pThis, DHookGetParamObjectPtrVar(hParams, 1, 40, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 36, ObjectValueType_Ehandle), DHookGetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float)); if(pThis <= MaxClients && pThis > 0 && !IsFakeClient(pThis)) { DHookSetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float, 0.0); PrintToChat(pThis, "Pimping your hp"); } }
// int CBaseCombatCharacter::GiveAmmo(int, int, bool) public MRESReturn:GiveAmmo(pThis, Handle:hReturn, Handle:hParams) { PrintToChat(pThis, "Giving %i of %i supress %i", DHookGetParam(hParams, 1), DHookGetParam(hParams, 2), DHookGetParam(hParams, 3)); return MRES_Ignored; }
// void CBaseEntity::SetModel(char const*) public MRESReturn:SetModel(pThis, Handle:hParams) { //Change all bot skins to phoenix one if(IsFakeClient(pThis)) { DHookSetParamString(hParams, 1, "models/player/t_phoenix.mdl"); return MRES_ChangedHandled; } return MRES_Ignored; }
//float CCSPlayer::GetPlayerMaxSpeed() public MRESReturn:GetMaxPlayerSpeedPost(pThis, Handle:hReturn) { //Make bots slow if(IsFakeClient(pThis)) { DHookSetReturn(hReturn, 100.0); return MRES_Override; } return MRES_Ignored; }
// bool CGameRules::CanHaveAmmo(CBaseCombatCharacter *, int) public MRESReturn:CanHaveAmmoPost(Handle:hReturn, Handle:hParams) { PrintToServer("Can has ammo? %s %i", DHookGetReturn(hReturn)?"true":"false", DHookGetParam(hParams, 2)); return MRES_Ignored; }
// string_t CBaseEntity::GetModelName(void) public MRESReturn:GetModelName(pThis, Handle:hReturn) { new String:returnval[128]; DHookGetReturnString(hReturn, returnval, sizeof(returnval)); if(IsFakeClient(pThis)) { PrintToServer("It is a bot, Model should be: models/player/t_phoenix.mdl It is %s", returnval); } return MRES_Ignored; }
// Vector CBasePlayer::GetPlayerMaxs() public MRESReturn:GetMaxsPost(Handle:hReturn) { new Float:vec[3]; DHookGetReturnVector(hReturn, vec); PrintToServer("Get maxes %.3f, %.3f, %.3f", vec[0], vec[1], vec[2]); return MRES_Ignored; }
// bool CBaseCombatCharacter::Weapon_CanUse(CBaseCombatWeapon *) public MRESReturn:CanUsePost(pThis, Handle:hReturn, Handle:hParams) { //Bots get nothing. if(IsFakeClient(pThis)) { DHookSetReturn(hReturn, false); return MRES_Override; } return MRES_Ignored; }
// int CBaseCombatCharacter::BloodColor(void) public MRESReturn:BloodColorPost(pThis, Handle:hReturn) { //Change the bots blood color to goldish yellow if(IsFakeClient(pThis)) { DHookSetReturn(hReturn, 2); return MRES_Supercede; } return MRES_Ignored; }
public RemovalCB(hookid) { PrintToServer("Removed hook %i", hookid); }
Note: Gamerule hooks are removed OnMapEnd so you must hook them again in OnMapStart. Entity hooks are removed when the entity is removed.
Thats all there is to it!
Since this is a dev preview crashes can happen. I mostly tested in CS: S Windows. If you experience a crash please post the function, game, OS, and code.
Changelog: - 1.0.1-pre-alpha
- Added Raw hook (allows passing class pointer)
- Fixed certain hooks unhooking randomly.
- 1.0.2-alpha
- Added support for more params (new max is 10)
- Added ability to add entity listeners (To hook OnEntityCreated and OnEntityDestroyed)
- Changed from pre-alpha to alpha
- 1.0.3-alpha
- Fixed various memory leaks.
- Fixed requiring latest gamehelpers i face
- 1.0.4-alpha
- Added support for Object pointer params (CTakeDamage in OnTakeDamage for example)
- Removed the need for a removal callback when hooking (Its not mandatory now).
- 1.0.5-alpha
- Fixed a crash when a hook was removed that had no removal callback.
- 1.0.6-alpha
- Fixed a crash on newer engines.
- 1.0.7-alpha
- Fixed a crash with strings
- Fixed a crash on new engines
- Added support for CS:GO
- Added support for edict_t
- 1.0.8-alpha
- Added support for getting the address of |this|
- 1.0.9-alpha
- Removed asserts from OnEntityCreated
- 1.0.11-alpha
- Made engine specific builds so that it works with tf2 again.
- Hopefully fixed crashes in CS:GO in OnEntityCreated
- Fixed a bug using Edict params.
- Requires SM 1.5 and MM:S 1.9+
- 1.0.12-alpha
- Fixed crashing when accessing NULL pointers
- Added native to check if a param is NULL before accessing it (DHookIsNullParam)
- 1.0.13-alpha
- Fixed a memory leak when unhooking entities.
- Removed the need for gamedata by switching to SDKHooks entity listeners.
- 2.0.0-dev
- Added ability to handle params with a size other than 4
- Restructed how hooking was handled
- Fixed multiple memory leaks
- Use SDKHooks for entity listeners
- Remove the need for SDK specific builds
- Updated to use AMBuild2
- General code rewrite
- Added mac support.
- Automated builds!
- 2.0.1-dev
- Fixed not being able to read or set returns that were pointers.
- Updated test plugin for SM 1.7+
- 2.0.3-dev
- Fix not being able to block void functions.
- Fix not being able to change Vector params.
- 2.0.4-dev
- Fix raw hooks incorrectly comparing and passing incorrect callback functions.
- Fix not being able to change Object Vector params.
- 2.0.5-dev
- Fix using ThrowNativeError outside of natives. (SM 1.8+)
- 2.0.6-dev
- Fixed not being able to set Vector return values.
- 2.1.0-dev
- Fixed a multitude of object param related issues.
- Added new enum values to DHookPassFlag to be used for objects.
- 2.1.1-dev
- Fixed incorrectly unhooking non entity hooks in OnEntityDestroyed
- Fixed not ending context (Thanks BoTox)
- 2.2.0-dev
- Fixed potential crash
- Add support for setting callback when hooking instead of on create only (Allows creating post/pre hooks with one handle)
When installing DHooks2 make sure to remove any previous bin's of DHooks(1)
DHooks2 REQUIRES SourceMod 1.7+
hg93+ REQUIRES SourceMod 1.8+
Credits:
dvander - Helping with asm and being a huge help overall.
KyleS - Input and reviewing my shitty commits.
psychonic - Quacking and helping with buildbot along with coding questions.
asherkin - SourceHook info.
Powerlord - Debugging and fixing crashes.
Links:
Source : https://bitbucket.org/Drifter321/dhooks2
Waterfall : https://builds.alliedmods.net/drifter/waterfall
Builds : http://users.alliedmods.net/~drifter/builds/dhooks/
DHooks with detour support (credit to Peace-Maker)
https://forums.alliedmods.net/showpo...&postcount=589
Last edited by Dr!fter; 05-04-2018 at 10:00.
|
|