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.