Leoncio wrote: Tue Apr 25, 2023 11:48 pm
Thanks for the reply and help!

I am so lost in what the piece of code that you posted means, which makes me unable to implement my entity to it, this is my entity that I want to give a despawn timer, how would the script code look like with this in mind?
Code: Select all
data:extend({
{
type = "simple-entity",
name = "rock-gun-block",
…
})
When you register an event handler, it will be called with the event data listed in the description of each event as a parameter. All events provide "name" (the numeric ID from defines.events[event.name]) and "tick", and all events except for on_tick provide at least one additional parameter. Now, on_built_entity, on_entity_cloned, and script_raised_built all provide the new entity, but they call it differently. Therefore, I used
Code: Select all
local entity = event.entity or -- script_raised_built
event.created_entity or -- on_built_entity
event.destination -- on_entity_cloned
in register_entity() to extract the new entity.
The table global.remove_at will only exist if at least one entity is scheduled for removal. Therefore, we must make sure the table is initialized before writing to it:
Code: Select all
if not global.remove_at then
global.remove_at = {}
end
This could be shortened to
Code: Select all
global.remove_at = global.remove_at or {}
But if you want to activate on_tick only when its needed (see below), the if-then construct is more convenient.
It's possible that several of your entities are created on the same tick, so global.remove_at[tick] should be a table to which you add all entities.
In remove_entities(event), the only parameters are {tick = uint, name = defines.events.on_tick}. We use
Code: Select all
local remove = global.remove_at and global.remove_at[event.tick]
to check that global.remove_at exists at all, and that at least one entity is scheduled for removal on this tick. If that is true, we loop over all entities in global.remove_at[event.tick] and destroy them if they are still valid. When this is done, we delete global.remove_at[event.tick], and when the last entry has been removed, we delete global.remove_at. If you want to use on_tick dynamically, then this would be the place to disable the event.
Now which entities do we react to? In the current state, the event would trigger whenever any entity is created, be it transport belts, assembling machines, cars, or even flying text. You obviously want to limit that. One way to do this is adding this at the start of the function register_entity:
Code: Select all
if not (entity.valid and entity.name == "rock-gun-block") then
return
end
That's feasible if you're interested in a number of different prototypes. For example, Autodrive has a feature that cars under its control will be healed when they crash into a tree, or that entities belonging to the same force as the car that damaged them will get back their full health -- so I must look at all entities that take damage. But in your case, you're really interested in only one prototype, and there's a better way for limiting the event: using event filters. This way, filtering is done directly by the game, which is faster than running Lua code for checking:
Code: Select all
local filters = {
{type = "name", name = "rock-gun-block"},
}
script.on_event(defines.events.on_built_entity, register_entity, filters)
script.on_event(defines.events.on_entity_cloned, register_entity, filters)
script.on_event(defines.events.script_raised_built, register_entity, filters)
Here, each line in "filters" is an array of filter conditions. If you wanted to do that, you could add another line like
Code: Select all
{type = "force", force = "neutral"}
The two filters would be ORed together, so the event would trigger whenever your entity OR any entity belonging to force "neutral" was created.
Finally, the handler for on_tick is activated. That should be everything that's needed in the most simple case where on_event is always running. It's not necessary to listen to on_entity_died etc.: If one of your entities is destroyed before its scheduled removal, it will be removed from the table when the function remove_entities is run for the scheduled tick.
However, while simple, this approach isn't really efficient (e.g., on_tick could run for an hour although none of your entities has been created). It's far better to register the event when an entity has been created, or in on_load:
Code: Select all
local function register_entity(event)
…
if not global.remove_at then
global.remove_at = {}
script.on_event(defines.events.on_tick, remove_entities)
end
…
end
script.on_load(function()
if global.remove_at then
script.on_event(defines.events.on_tick, remove_entities)
end
end)
and to turn it off when the last scheduled entity has been removed:
Code: Select all
local function remove_entities(event)
…
global.remove_at[event.tick] = nil
if not next(global.remove_at[event.tick] then
global.remove_at = nil
script.on_event(defines.events.on_tick, nil)
end
…
end
If you do this, you should also listen to on_entity_died, on_entity_destroyed, on_player_mined_entity, on_robot_mined_entity, and script_raised_destroy and remove the entity from global.remove_at[event.tick], and global.remove_at[event.tick] if no other entity removal is scheduled for event.tick, and global.remove_at if it is empty. But that's a bit tricky (e.g. script_raised_destroy will be raised after the after the entity has been destroyed, so you couldn't look up its unit_number anymore) and explaining that as well would mean putting up another wall of text, for which I'm too tired now.
