PreHook cancel/modify damage

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
Pudge90
Member
Posts: 33
Joined: Sun Jan 14, 2018 6:18 pm
Location: Germany

PreHook cancel/modify damage

Postby Pudge90 » Sun Jan 21, 2018 2:46 pm

I'd like to cancel/modify incoming damage to a Player. I dont wanna go with the 'player_hurt' and then afterwards heal the victim by the amount of damage it just took because the victim could be already dead. So I'd like to prevent the damage before damage is acutally happening. I read something about the PreHook but have no idea how exactly that works.
I think that what I want to do is prehooking on_take_damage.
viewtopic.php?f=20&t=798&hilit=damage+prehook&start=20

But it would be great if someone could explain how the prehooking itself works :grin: Especially what kind of 'things' can I prehook ? If I prehook on_take_damage, how do I get the attacker.index and the victim.index ?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: PreHook cancel/modify damage

Postby Ayuto » Sun Jan 21, 2018 3:33 pm

Yes, a pre-hook is exactly what you need. Here is a small example:

Syntax: Select all

from players.entity import Player
from entities.hooks import EntityPreHook
from entities.hooks import EntityCondition
from entities import TakeDamageInfo
import memory

@EntityPreHook(EntityCondition.is_player, 'on_take_damage')
def pre_on_take_damage(args):
victim = memory.make_object(Player, args[0])
info = memory.make_object(TakeDamageInfo, args[1])
attacker = Player(info.attacker)
if attacker.is_player():
victim.say(f'I have been attacker by {attacker.name}.')
else:
# E.g. if you take damage from the world.
info.damage = 0 # Block the damage
You can hook pretty much everything. You only need to find the address of the function you want to hook in memory. Source.Python already provides the address of several functions. One example is on_take_damage. That's why you can create a hook on that function so easily.
User avatar
Pudge90
Member
Posts: 33
Joined: Sun Jan 14, 2018 6:18 pm
Location: Germany

Re: PreHook cancel/modify damage

Postby Pudge90 » Mon Jan 22, 2018 7:44 am

Okay thanks, works like a charm!
Yet I still have some questions for the further understanding:
1. Is there a list of addresses where I can find 'on_take_damage' and more ?
2. Where is args getting its values from?
3. In this specific case, how do I know that args[0] contains the pointer to the victim and args[1] the pointer to damageinfo and not the other way around?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: PreHook cancel/modify damage

Postby Ayuto » Mon Jan 22, 2018 6:52 pm

The list of built-in functions/addresses depends on the game and the entity (e.g. players have other functions than other entities). You can use the following snippet to print a list of functions, their arguments and their return types:

Syntax: Select all

from entities.entity import Entity
from memory import Function

# Search for a player entity.
entity = Entity.find('player')
if entity is None:
raise ValueError('No entity found')

for attr in sorted(dir(entity)):
obj = getattr(entity, attr)
if isinstance(obj, Function):
print(
attr,
tuple(map(lambda x: x.name, obj.arguments)),
obj.return_type)
If I run this snippet on CS:S with a bot on my server, I get the following output:

Code: Select all

# Function name, arguments, return type
add_account ('POINTER', 'INT', 'BOOL', 'BOOL', 'STRING') VOID
add_context ('POINTER', 'POINTER') VOID
add_output ('POINTER', 'POINTER') VOID
autobuy ('POINTER',) VOID
become_ragdoll ('POINTER', 'POINTER') VOID
blind ('POINTER', 'FLOAT', 'FLOAT', 'FLOAT') VOID
bump_weapon ('POINTER', 'POINTER') BOOL
buy_internal ('POINTER', 'STRING') INT
clear_context ('POINTER', 'POINTER') VOID
clear_parent ('POINTER', 'POINTER') VOID
deafen ('POINTER', 'FLOAT') VOID
disable_damage_forces ('POINTER', 'POINTER') VOID
disable_shadow ('POINTER', 'POINTER') VOID
dispatch_effect ('POINTER', 'POINTER') VOID
dispatch_response ('POINTER', 'POINTER') VOID
drop_weapon ('POINTER', 'POINTER', 'POINTER', 'POINTER') VOID
enable_damage_forces ('POINTER', 'POINTER') VOID
enable_shadow ('POINTER', 'POINTER') VOID
end_touch ('POINTER', 'POINTER') VOID
equip_weapon ('POINTER', 'POINTER') VOID
fire_user1 ('POINTER', 'POINTER') VOID
fire_user2 ('POINTER', 'POINTER') VOID
fire_user3 ('POINTER', 'POINTER') VOID
fire_user4 ('POINTER', 'POINTER') VOID
give_named_item ('POINTER', 'STRING', 'INT') POINTER
ignite ('POINTER', 'POINTER') VOID
ignite_hitbox_fire_scale ('POINTER', 'POINTER') VOID
ignite_lifetime ('POINTER', 'POINTER') VOID
ignite_num_hitbox_fires ('POINTER', 'POINTER') VOID
increment_death_count ('POINTER', 'INT') VOID
increment_frag_count ('POINTER', 'INT') VOID
kill_hierarchy ('POINTER', 'POINTER') VOID
killed_npc ('POINTER', 'POINTER') VOID
on_rescue_zone_touch ('POINTER', 'POINTER') VOID
on_take_damage ('POINTER', 'POINTER') INT
post_think ('POINTER',) VOID
pre_think ('POINTER',) VOID
rebuy ('POINTER',) VOID
remove_context ('POINTER', 'POINTER') VOID
run_command ('POINTER', 'POINTER', 'POINTER') VOID
set_damage_filter ('POINTER', 'POINTER') VOID
set_fog_controller ('POINTER', 'POINTER') VOID
set_hud_visibility ('POINTER', 'POINTER') VOID
set_lighting_origin ('POINTER', 'POINTER') VOID
set_lighting_origin_hack ('POINTER', 'POINTER') VOID
set_model_scale ('POINTER', 'POINTER') VOID
set_parent ('POINTER', 'POINTER', 'INT') VOID
set_parent_attachment ('POINTER', 'POINTER') VOID
set_parent_attachment_maintain_offset ('POINTER', 'POINTER') VOID
set_transmit ('POINTER', 'POINTER', 'BOOL') VOID
start_touch ('POINTER', 'POINTER') VOID
switch_team ('POINTER', 'INT') VOID
teleport ('POINTER', 'POINTER', 'POINTER', 'POINTER') VOID
touch ('POINTER', 'POINTER') VOID
use ('POINTER', 'POINTER') VOID
weapon_switch ('POINTER', 'POINTER', 'INT') BOOL
args retrieves the values directly from CPU registers (e.g. from the ESP register, which is the stack register). Hooking functions or doing stuff with the memory module in general is quite low-level and dangerous (you can easily crash your server if you don't know what you are doing).

Regarding your last question:
You need to know the signature of the function in memory. E. g. in this case it's CCSPlayer::OnTakeDamage(CTakeDamageInfo const&). args[0] is the this-pointer in case of a function that is part of a class. So, in this case it's an instance of the CCSPlayer class. args[1] is the first argument of the function, args[2] would be the second argument, etc. Though, in this case there is only one argument.
User avatar
Pudge90
Member
Posts: 33
Joined: Sun Jan 14, 2018 6:18 pm
Location: Germany

Re: PreHook cancel/modify damage

Postby Pudge90 » Tue Jan 23, 2018 1:17 am

phew, thanks for the detailled response. Still, it'll take me a while to truly understand why things work the way they do :grin:

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 33 guests