Page 1 of 1

[CS:S] PreEvent player_death calling after death

Posted: Tue Jul 12, 2016 6:42 pm
by Jake

Syntax: Select all

@PreEvent('player_death')
def pre_player_death(game_event) :
player = Player.from_userid(game_event['userid'])
if player.dead :
print('player dead already')


I'm trying to destroy a player's weapons before death but the weapons are dropped before this PreEvent is fired. Is there another way?

Re: [CS:S] PreEvent player_death calling after death

Posted: Tue Jul 12, 2016 7:09 pm
by Ayuto
What exactly do you want to achieve with this? One thing I can think of is hooking drop_weapon and check if the dropping player is dead.

Re: [CS:S] PreEvent player_death calling after death

Posted: Tue Jul 12, 2016 7:37 pm
by Jake
I want to remove any weapons that are dropped manually or on death to prevent spam. drop_weapon is what I was looking for, thanks

Syntax: Select all

@EntityPreHook(EntityCondition.is_player, 'drop_weapon')
def pre_drop_weapon(args) :
if args[1] :
weapon = make_object(Weapon, args[1])
weapon.remove()

Re: [CS:S] PreEvent player_death calling after death

Posted: Wed Jul 13, 2016 2:53 am
by L'In20Cible
Since you do nothing else on the Weapon object, you could optimize quite a bit:

Syntax: Select all

# Can't indent first line? hm...
weapon = make_object(BaseEntity, args[1])
weapon.destroy()

Re: [CS:S] PreEvent player_death calling after death

Posted: Wed Jul 13, 2016 3:18 pm
by BackRaw
L'In20Cible wrote:Since you do nothing else on the Weapon object, you could optimize quite a bit:

Syntax: Select all

# Can't indent first line? hm...
weapon = make_object(BaseEntity, args[1])
weapon.destroy()

A little bit OT but: how is destroy() different from remove()?

Re: [CS:S] PreEvent player_death calling after death

Posted: Wed Jul 13, 2016 3:37 pm
by L'In20Cible
The result will be the same, but execution time will be way faster. remove() is bound to the Kill input (so we internally have to loop through all classes, lookup the datamaps, etc. till we find the correct pointer to dynamically call) while destroy() is wrapping its factory (direct call to what the input itself is doing internally - minus the fact that we have to internally look for it in the global dictionary), plus the fact that you skip two classes in the hierarchy to instanciate (Weapon → Entity → BaseEntity), in that specific case. However, remove_entity() would have been faster, but got removed (not sure why) which is also a regression since now we internally rely on the entity's classname instead of only its pointer (which breaks the update of my parachute plugin (where the model is literally an entity named "parachute") now that I think about it).

Re: [CS:S] PreEvent player_death calling after death

Posted: Wed Jul 13, 2016 5:47 pm
by Ayuto
L'In20Cible wrote:However, remove_entity() would have been faster, but got removed (not sure why) which is also a regression since now we internally rely on the entity's classname instead of only its pointer (which breaks the update of my parachute plugin (where the model is literally an entity named "parachute") now that I think about it).

remove_entity() was only working with indexes, so I decided to add the destroy() method. I didn't adopt the implementation of remove_entity(), because it was implemented differently for every engine (I think we even used the factory method in L4D2 and I'm not sure if the hammerid implementation was really working properly). However, I just took a closer look at the implementation of the factory's Destroy() method and it's just calling INetworkable::Release(), which simply deletes the entity immediately. That might be a bit risky. Otherwise I have no idea why the global entity list maintains a delete list. So, the best way might be using UTIL_Remove() or calling the kill input (which calls UTIL_Remove() at some point) in BaseEntity.destroy().

Re: [CS:S] PreEvent player_death calling after death

Posted: Thu Jul 14, 2016 4:37 am
by L'In20Cible
Ayuto wrote:remove_entity() was only working with indexes, so I decided to add the destroy() method. I didn't adopt the implementation of remove_entity(), because it was implemented differently for every engine (I think we even used the factory method in L4D2 and I'm not sure if the hammerid implementation was really working properly).
Yeah, forgot how messy and hacky it was for some engines. The hammerid patch was working on CS:GO (I think blade was also implemented this way, if I remember correctly), but was feeling pointless.

Ayuto wrote:However, I just took a closer look at the implementation of the factory's Destroy() method and it's just calling INetworkable::Release(), which simply deletes the entity immediately. That might be a bit risky. Otherwise I have no idea why the global entity list maintains a delete list.
I believe the engine is storing deleted entities, so it doesn't reuse the slot before they have been correctly broadcasted to clients. Deleting the entity immediately, may cause issues, according to the documentation of UTIL_Remove:

Syntax: Select all

// Purpose: Sets the entity up for deletion.  Entity will not actually be deleted
// until the next frame, so there can be no pointer errors.


Which probably makes sure all tasks (motioning, rendering, broadcasting, etc) are done before freeding the actual pointer. Using Destroy()/INetworkable::Release() may have undefined behavior, I guess.

Ayuto wrote:So, the best way might be using UTIL_Remove() or calling the kill input (which calls UTIL_Remove() at some point) in BaseEntity.destroy().


Definetly. In my opinion, we should implement BaseEntity.destroy() as BaseEntity.remove() calling the InputKill function (now that it is possible on the cpp side!) internally. That way we remove the need to rely on the classname, we make sure the entity is marked for deletion and correctly handled over freeding the address and hoping for the best.

A bit off topic but, back to this quote:
Ayuto wrote:remove_entity() was only working with indexes

We currently have a lot of wrapper which accepts index, and internally convert to pointer passing them to engine calls. This was done this way, before BaseEntity, pointers, etc. being wrapped. I guess that now, we should definetly avoid extra cast by making them accepting the pointer directly (and by pointer I mean the actual BaseEntity objects). Some InputVariant/TakeDamageInfo methods, that I can think off. Do we all agree with that? This will break some plugins, but better doing it now.

Re: [CS:S] PreEvent player_death calling after death

Posted: Thu Jul 14, 2016 5:34 am
by Ayuto
L'In20Cible wrote:I guess that now, we should definetly avoid extra cast by making them accepting the pointer directly (and by pointer I mean the actual BaseEntity objects). Some InputVariant/TakeDamageInfo methods, that I can think off. Do we all agree with that? This will break some plugins, but better doing it now.
Yep, agreed! :smile:

Re: [CS:S] PreEvent player_death calling after death

Posted: Thu Jul 14, 2016 10:07 pm
by burnSTATION
Ideally you would just make this change in your config files

mp_death_drop_gun 0

Re: [CS:S] PreEvent player_death calling after death

Posted: Thu Jul 14, 2016 10:14 pm
by Ayuto
That cvar only exists in CS:GO, but not in CS:S.