Change return value inside EntityPostHook

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
InvisibleSoldiers
Junior Member
Posts: 16
Joined: Fri Mar 15, 2019 6:08 am

Change return value inside EntityPostHook

Postby InvisibleSoldiers » Sat Nov 02, 2019 4:17 am

I'm trying to convert SM plugin firebulletsfix to SP.

I hooked Weapon_ShootPosition. It should return Vector EyePosition.

Inside @EntityPostHook i want to return new value type of Vector, but i got exception:
TypeError: No registered converter was able to extract a C++ pointer to type class CPointer from this Python object of type Vector

This is my code:

Syntax: Select all

manager = TypeManager()
ecx_storage = {}

CBasePlayer = manager.create_type_from_file(
'CBasePlayer', PLUGIN_DATA_PATH / 'firebulletsfix' / 'memory' / 'csgo' / 'CBasePlayer.ini')


@EntityPreHook(EntityCondition.is_human_player,
lambda entity: make_object(CBasePlayer, entity.pointer).weapon_shootposition)
def entity_pre_hook(stack_data):
ecx_storage[stack_data.registers.esp.address.address] = index_from_pointer(stack_data[0])

@EntityPostHook(EntityCondition.is_human_player,
lambda entity: make_object(CBasePlayer, entity.pointer).weapon_shootposition)
def entity_post_hook(stack_data, ret):
index = ecx_storage.pop(stack_data.registers.esp.address.address)

print('post_weapon_shootposition')

return NULL_VECTOR
Last edited by InvisibleSoldiers on Sun Nov 03, 2019 12:09 am, edited 1 time in total.
User avatar
L'In20Cible
Project Leader
Posts: 1186
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Change Vector return value inside EntityPostHook

Postby L'In20Cible » Sat Nov 02, 2019 12:17 pm

In the future, please provide the following when you report a bug/request assistance:
  • Complete repro code (including imports section, etc.).
  • All relevant files (e.g. your custom types files).
  • Output of sp info.
Makes it easier for everyone that tries to reproduce and investigate the issue so they can just go ahead and load your code instead of fixing import errors, etc.

That being said, the return value must currently be a Pointer, so you must get it from your Vector first:

Syntax: Select all

from memory import get_object_pointer
...
return get_object_pointer(NULL_VECTOR)

It used to be the same for arguments you override, but for convenience I changed that into 7b4bea5 and the same should ideally be done for the return value here for consistency.

EDIT: Made that change into 2dc44b4 so once an official build is made available you will be able to return objects that have bound memory tools to it directly from your callbacks.
User avatar
InvisibleSoldiers
Junior Member
Posts: 16
Joined: Fri Mar 15, 2019 6:08 am

Re: Change Vector return value inside EntityPostHook

Postby InvisibleSoldiers » Sat Nov 02, 2019 7:07 pm

L'In20Cible wrote:

Syntax: Select all

from memory import get_object_pointer
...
return get_object_pointer(NULL_VECTOR)
.


I added get_object_pointer() but return value changes to unknown value, when i shoot the player bullets don't impact on a player.

SP INFO

Syntax: Select all

--------------------------------------------------------
Checksum : 07a3c1f8fdc0aa76c78c5617b7ed755e
Date : 2019-11-02 19:03:03.000368
OS : Windows-10-10.0.18362
Game : csgo
SP version : 692
Github commit : 71dc8bc4860bcfb5ae080516f3b5cbbdb26b1a40
Server plugins:
00: Source.Python, (C) 2012-2019, Source.Python Team.
SP plugins:
00: firebulletsfix
--------------------------------------------------------


PLUGIN_DATA_PATH / 'firebulletsfix' / 'memory' / 'csgo' / 'CBasePlayer.ini'

Syntax: Select all

[virtual_function]

[[weapon_shootposition]]
offset_linux = 290
offset_windows = 289
arguments = POINTER
return_type = POINTER


IMPORTS

Syntax: Select all

from entities.hooks import EntityPostHook, EntityCondition, EntityPreHook
from memory.manager import TypeManager
from memory import get_object_pointer, make_object
from entities.helpers import index_from_pointer
from listeners import OnPlayerRunCommand
from paths import PLUGIN_DATA_PATH
from mathlib import Vector
from players.entity import Player

CODE

Syntax: Select all

manager = TypeManager()
old_weapon_shoot_pos = {}
ecx_storage = {}

CBasePlayer = manager.create_type_from_file(
'CBasePlayer', PLUGIN_DATA_PATH / 'firebulletsfix' / 'memory' / 'csgo' / 'CBasePlayer.ini')


@EntityPreHook(EntityCondition.is_human_player,
lambda entity: make_object(CBasePlayer, entity.pointer).weapon_shootposition)
def entity_pre_hook(stack_data):
ecx_storage[stack_data.registers.esp.address.address] = index_from_pointer(stack_data[0])

@EntityPostHook(EntityCondition.is_human_player,
lambda entity: make_object(CBasePlayer, entity.pointer).weapon_shootposition)
def entity_post_hook(stack_data, ret):
pindex = ecx_storage.pop(stack_data.registers.esp.address.address)

return get_object_pointer(old_weapon_shoot_pos[pindex])

@OnPlayerRunCommand
def on_player_run_cmd(player, user_cmd):
old_weapon_shoot_pos[player.index] = player.eye_angle
User avatar
L'In20Cible
Project Leader
Posts: 1186
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Change Vector return value inside EntityPostHook

Postby L'In20Cible » Sat Nov 02, 2019 11:23 pm

That function return the eye location, not the angle so you need to use:

Syntax: Select all

@OnPlayerRunCommand
def on_player_run_cmd(player, user_cmd):
old_weapon_shoot_pos[player.index] = player.eye_location

Also, it is never good practice to store Player.eye_angle as is for later use because that property is wrapping an address in the player's structure meaning that by the time you read your stored instance it will have been changed and updated to the current player's angle rather than still being the angle at the time you stored it. Either store raw values and reconstruct your object later, or make a copy first. That is not necessary with Player.eye_location because a copy is already returned by the internal operator but just mentioning it for informational purposes; if you store a mutable object, make sure your are owning it.
User avatar
InvisibleSoldiers
Junior Member
Posts: 16
Joined: Fri Mar 15, 2019 6:08 am

Re: Change Vector return value inside EntityPostHook

Postby InvisibleSoldiers » Sat Nov 02, 2019 11:56 pm

L'In20Cible wrote:

Thank you! :embarrassed:
Also, I noticed that i can return old eye_location inside PreHook bypassing PostHook and low level stuff with registers. Is that all right, although using PostHook in original SourceMod plugin?
User avatar
L'In20Cible
Project Leader
Posts: 1186
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Change Vector return value inside EntityPostHook

Postby L'In20Cible » Sun Nov 03, 2019 12:24 am

InvisibleSoldiers wrote:
L'In20Cible wrote:

Thank you! :embarrassed:
Also, I noticed that i can return old eye_location inside PreHook bypassing PostHook and low level stuff with registers. Is that all right, although using PostHook in original SourceMod plugin?

Yes, that is fine and probably better as well. Another thing you should change, is the following:

Syntax: Select all

return get_object_pointer(old_weapon_shoot_pos[pindex])

To:

Syntax: Select all

ret = old_weapon_shoot_pos.pop(pindex, None)
if ret is not None:
ret = get_object_pointer(ret)
return ret

So that you cleanup once you are done with the stored value, and let the function continue normally if the index is not in your dictionary.

EDIT: Just to add more info; the only times you want to use a post hook is when;

  • You want to do stuff after the original function was called that cannot be done before.
  • You want to evaluate the value that will be returned to the caller and do specific stuff based on it.
In your case, you only want to override the returned value, so no need to let the original function executes because you already know you override it no matter what (at least, if you have a value cached for that player, hence where the modification I proposed above becomes handy).

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 2 guests