Hooked 'end_touch' function crashes server when weapon is picked up

Please post any questions about developing your plugin here. Please use the search function before posting!
Silver Zero
Junior Member
Posts: 6
Joined: Thu Jul 05, 2018 4:16 pm
Location: Poland

Hooked 'end_touch' function crashes server when weapon is picked up

Postby Silver Zero » Thu Jul 05, 2018 8:32 pm

Hello,

There is an example of plugin for debugging 'end_touch' hooks.
When plugin is loaded and I try to pick up a weapon server "crashes" .

Source.Python info:

Code: Select all

--------------------------------------------------------
Checksum      : d2a4f6977f9edad7c5e6ebf1c7b44b6a
Date          : 2018-07-05 17:53:13.616464
OS            : Windows-7-6.1.7601-SP1
Game          : css
SP version    : 654
Github commit : 972547be070e74a3f785284cefef53d98fab83c8
Server plugins:
   00: Source.Python, (C) 2012-2018, Source.Python Team.
SP plugins:
   00: test
--------------------------------------------------------

Plugin code:

Syntax: Select all

# ../test/test.py

from entities.hooks import EntityPostHook
from entities.hooks import EntityPreHook
from entities.hooks import EntityCondition
from entities.helpers import index_from_pointer
from messages.base import SayText2

@EntityPreHook(EntityCondition.is_player, 'end_touch')
def pre_ent_end_touch(args):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Pre End Touched: {index1} Touching: {index2}")
# SayText2(f"Pre End Touched: {index1} Touching: {index2}").send()

@EntityPostHook(EntityCondition.is_player, 'end_touch')
def post_ent_end_touch(args, ret):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Post End Touched: {index1} Touching: {index2}")
# SayText2(f"Post End Touched: {index1} Touching: {index2}").send()

Console output:

Code: Select all

[...]
Counter-Strike: Source
Map: de_dust2
Players: 1 / 16
Build: 4017558
Server Number: 1

[...]

Pre End Touched: 0 Touching: 1
Post End Touched: 0 Touching: 1
Pre End Touched: 1 Touching: 0
Post End Touched: 1 Touching: 0
Pre End Touched: 45 Touching: 1
Post End Touched: 45 Touching: 1
Pre End Touched: 0 Touching: 1
Post End Touched: 0 Touching: 1
Pre End Touched: 1 Touching: 0
Post End Touched: 1 Touching: 0
Pre End Touched: 45 Touching: 1
Pre End Touched: 1 Touching: 1 # moment when weapon is picked up
Post End Touched: 1 Touching: 1

Post End Touched: 1 Touching: 1
Post End Touched: 1 Touching: 1
Post End Touched: 1 Touching: 1
# Rest of console output is endless stream of "Post End Touched: 1 Touching: 1", ends when server is closed


I've tried to fix it with filtering,

Syntax: Select all

if index1 == index2:
return

but it only suppresses console output and server still crashes.

Reproducing crash:
1. Start server/game (with -condebug launch option for generating console.log)
2. Load this plugin
3. Drop weapon, then try to pick it up
4. Server/game "crashes" (writing to console output still works so exit server/game to avoid big console.log file)

Is there a way to fix this?

Thanks for help.
User avatar
L'In20Cible
Project Leader
Posts: 1105
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Hooked 'end_touch' function crashes server when weapon is picked up

Postby L'In20Cible » Thu Jul 05, 2018 10:21 pm

The crash occurs because the end_touch method is calling itself for the parent of the this pointer. You need to block the original call and call the method for the parent yourself without invoking the hook. Here is an example for the "touch" method:
viewtopic.php?f=20&t=1447&p=9615#p9615
Silver Zero
Junior Member
Posts: 6
Joined: Thu Jul 05, 2018 4:16 pm
Location: Poland

Re: Hooked 'end_touch' function crashes server when weapon is picked up

Postby Silver Zero » Fri Jul 06, 2018 8:27 am

Thank you for help. I've modified this code to return void whenever function is called. So far (5 minutes of testing), code is working and i didn't notice any drawbacks of using this, but I don't know if it has any negative impact on game logic.

Syntax: Select all

# ../test/test.py

from entities.entity import Entity
from entities.hooks import EntityPostHook
from entities.hooks import EntityPreHook
from entities.hooks import EntityCondition
from entities.helpers import index_from_pointer
from messages.base import SayText2
from memory import DataType

@EntityPreHook(EntityCondition.is_player, 'end_touch')
def pre_ent_end_touch(args):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Pre End Touched: {index1} Touching: {index2}")
#SayText2(f"Pre End Touched: {index1} Touching: {index2}").send()

return DataType.VOID

@EntityPostHook(EntityCondition.is_player, 'end_touch')
def post_ent_end_touch(args, ret):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Post End Touched: {index1} Touching: {index2}")
#SayText2(f"Post End Touched: {index1} Touching: {index2}").send()

return DataType.VOID


Because of this I want to ask another questions. Can this code be considered "correct"? If not, there is some better ways to do this?

Edit: Actually, returning void only works for EntityPreHook. EntityPostHook alone still crashes, even with returning void.
If I want to hook only post "end_touch", I must do this with following code:

Syntax: Select all

@EntityPreHook(EntityCondition.is_player, 'end_touch')    
def pre_ent_end_touch(args):
return DataType.VOID

@EntityPostHook(EntityCondition.is_player, 'end_touch')
def post_ent_end_touch(args, ret):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Post End Touched: {index1} Touching: {index2}")
#SayText2(f"Post End Touched: {index1} Touching: {index2}").send()
User avatar
L'In20Cible
Project Leader
Posts: 1105
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: Hooked 'end_touch' function crashes server when weapon is picked up

Postby L'In20Cible » Tue Jul 10, 2018 11:48 pm

Silver Zero wrote:I don't know if it has any negative impact on game logic.

It can have some negative impact for some entities, depending of their parenting chain. What you want to do is add the following in your pre-hook callback so that it notice the parent that the touching have ended:

Syntax: Select all

# Get the parent of the entity
handle = make_object(BaseEntity, args[0]).get_property_int('m_pParent')

# Is the parent valid?
if handle != -1:

# Get an Entity instance of the parent
parent = Entity(index_from_inthandle(handle))

# Call the end_touch function for the parent without invoking the hooks
parent.end_touch.call_trampoline(other)
Silver Zero
Junior Member
Posts: 6
Joined: Thu Jul 05, 2018 4:16 pm
Location: Poland

Re: Hooked 'end_touch' function crashes server when weapon is picked up

Postby Silver Zero » Wed Jul 11, 2018 10:19 am

Alright. So the correct code should look like this:

Syntax: Select all

# ../test/test.py

from entities.entity import Entity, BaseEntitiy
from entities.hooks import EntityPostHook, EntityPreHook
from entities.hooks import EntityCondition
from entities.helpers import index_from_pointer
from entities.helpers import index_from_inthandle
from messages.base import SayText2
from memory import DataType, make_object

@EntityPreHook(EntityCondition.is_player, 'end_touch')
def pre_ent_end_touch(args):
handle = make_object(BaseEntity, args[0]).parent_inthandle

if handle != -1:
parent = Entity(index_from_inthandle(handle))
parent.end_touch.call_trampoline(parent)

return DataType.VOID

@EntityPostHook(EntityCondition.is_player, 'end_touch')
def post_ent_end_touch(args, ret):
index1 = index_from_pointer(args[0])
index2 = index_from_pointer(args[1])

print(f"Post End Touched: {index1} Touching: {index2}")
#SayText2(f"Post End Touched: {index1} Touching: {index2}").send()


Pre-hook function returns void and parent entity is noticed when 'end_touch' occurs, so everything should be fine now. Probably :grin:.
Thanks again for help.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 9 guests