Page 1 of 1

Entity removed without raising an event

Posted: Tue Jan 03, 2023 9:07 pm
by mami
Is it possible for an entity to be removed from a world without raising an event?

I have a reoccurring bug in my mod where essential entities seemingly disappear during or before on_configuration_changed without my mod detecting them and updating.

My mod has code that must be run when specific entities are at all removed from the world, or else the mod will crash later. What do I have to do to guarantee that that code gets run on removal. I would like to see the list of events I need to listen to, to double check I got them all, and I would like to know anything else I need to check for.

Re: Entity removed without raising an event

Posted: Wed Jan 04, 2023 12:19 am
by InappropriatePenguin
mami wrote:
Tue Jan 03, 2023 9:07 pm
Is it possible for an entity to be removed from a world without raising an event?
Yes. Any entities destroyed by script using LuaEntity::destroy won't raise any events by default, unless raise_destroy=true is passed in that function call. Players placing waterfill under an entity is one other common one that destroys entities without raising events (though it is now fortunately solvable). Another example is if a surface were to get deleted that has a bunch of entities. You won't get any of the "standard" removal events for those entities that got deleted along with it.
mami wrote:
Tue Jan 03, 2023 9:07 pm
My mod has code that must be run when specific entities are at all removed from the world, or else the mod will crash later. What do I have to do to guarantee that that code gets run on removal. I would like to see the list of events I need to listen to, to double check I got them all, and I would like to know anything else I need to check for.
The "standard" entity-removal events that you want to listen to are on_entity_died, on_player_mined_entity, on_robot_mined_entity, and script_raised_destroy. In these four events, you'll have access to the entity right before it gets destroyed.

There is one special event, on_entity_destroyed, that works a little differently. It fires within 1–2 ticks after entity removal so you won't get a valid entity as part of event data. Instead you'll get the registration_number and the entity's unit_number if it has one. In order for this event to fire for your entities, you have to have pre-registered them using register_on_entity_destroyed.

While that event might solve most of your issues, it's still not perfect because of the 1–2 ticks it might take for it to fire. Ultimately, there's no real substitute to verifying the validity of any LuaEntity you stored a reference to in global before trying to access it. Once you do come across an invalid entity there, you ought to have a way of skipping it and/or removing it from your data structures.

Re: Entity removed without raising an event

Posted: Wed Jan 04, 2023 3:58 am
by mami
to clarify, is on_entity_destroyed guaranteed to fire after removal no matter what?

Re: Entity removed without raising an event

Posted: Wed Jan 04, 2023 4:02 am
by mami
Also if I come across an invalid entity in global, is there a safe way to figure out what its unit_number was? A large part of why I can't use that solution, at least not easily and efficiently, is because I have some data structures that are indexed by the unit_number that need to be updated about the removed entity.

Re: Entity removed without raising an event

Posted: Wed Jan 04, 2023 5:45 am
by InappropriatePenguin
mami wrote:
Wed Jan 04, 2023 3:58 am
to clarify, is on_entity_destroyed guaranteed to fire after removal no matter what?
Yes, it is guaranteed to fire no matter what made your entity stop existing. The caveat is that it could take 1–2 ticks before the event fires and you have to register each entity you want that event to be raised for. Note that you will also be getting events for entities that other mods have registered in the same way.
mami wrote:
Wed Jan 04, 2023 4:02 am
Also if I come across an invalid entity in global, is there a safe way to figure out what its unit_number was? A large part of why I can't use that solution, at least not easily and efficiently, is because I have some data structures that are indexed by the unit_number that need to be updated about the removed entity.
Not from an invalid entity, no. You'll want to set up your data structures in such a way that whenever you're iterating over any group of entities, you know exactly what saved data they map to. If you're iterating over entity references that are stored directly in a table, you'll usually want that table to be indexed by unit_number for that reason.