Can you make an entity despawn after a while?
Can you make an entity despawn after a while?
Hello,
I was wondering if there is way to make a "simple-entity" have a duration/despawn -timer? So far I haven't been able to find a way to make them disappear after a couple of seconds. The only things that I have been able to find, are ghosts, character-corpse, smoke-with-trigger, but none of them has the commands that I am looking for.
I was wondering if there is way to make a "simple-entity" have a duration/despawn -timer? So far I haven't been able to find a way to make them disappear after a couple of seconds. The only things that I have been able to find, are ghosts, character-corpse, smoke-with-trigger, but none of them has the commands that I am looking for.
Re: Can you make an entity despawn after a while?
Hi! I think you must use control scripting. Listen to the entity-created events and store the new entities in your global table:Leoncio wrote: Mon Apr 24, 2023 5:34 pm Hello,
I was wondering if there is way to make a "simple-entity" have a duration/despawn -timer?
Code: Select all
local function register_entity(event)
local tick = event.tick
local entity = event.entity or -- script_raised_built
event.created_entity or -- on_built_entity
event.destination -- on_entity_cloned
local remove_tick = tick + 5*60*60 -- 5 minutes (60 ticks per second, 60 seconds per minute)
if not global.remove_at then
global.remove_at = {}
end
global.remove_at[remove_tick] = global.remove_at[remove_tick] or {}
table.insert(global.remove_at[remove_tick], entity)
end
script.on_event(defines.events.script_raised_built, register_entity)
script.on_event(defines.events.on_built_entity, register_entity)
script.on_event(defines.events.on_entity_cloned, register_entity)
Code: Select all
local function remove_entities(event)
local remove = global.remove_at and global.remove_at[event.tick]
if remove then
for e, entity in pairs(remove) do
if entity.valid then
entity.destroy()
end
end
global.remove_at[event.tick] = nil
if not next(global.remove_at[event.tick] then
global.remove_at = nil
end
end
end
script.on_event(defines.events.on_tick, remove_entities)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Re: Can you make an entity despawn after a while?
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?

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",
flags = {"placeable-neutral", "placeable-off-grid"},
map_color = {r = 40, g = 110, b = 245, a = 0.7},
icon = "__rock_gun__/graphics/rock/rock_icon.png",
icon_size = 64, icon_mipmaps = 4,
subgroup = "grass",
collision_box = {{-0.24, -0.24},{0.24, 0.24}},
collision_mask = {"player-layer", "train-layer"},
selection_box = {{-0.5, -0.5},{0.5, 0.5}},
render_layer = "object",
count_as_rock_for_filtered_deconstruction = true,
mined_sound = { filename = "__base__/sound/deconstruct-bricks.ogg" },
vehicle_impact_sound = { filename = "__base__/sound/car-stone-impact.ogg", volume = 0.5 },
max_health = 300,
pictures =
{
},
}
})
Re: Can you make an entity despawn after a while?
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 usedLeoncio 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", … })
Code: Select all
local entity = event.entity or -- script_raised_built
event.created_entity or -- on_built_entity
event.destination -- on_entity_cloned
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
Code: Select all
global.remove_at = global.remove_at or {}
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]
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
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)
Code: Select all
{type = "force", force = "neutral"}
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)
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

A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Re: Can you make an entity despawn after a while?
Thanks for the reply!
I've been trying to implement the script as good as I can, but I still getting error messages that I don't understand what it means.
the code that I have been running in the control.lua is
But I am getting an error box when loading a new map, the message is: "Key "filter" not found in property tree at ROOT[0]"
Any idea what it means?
I've been trying to implement the script as good as I can, but I still getting error messages that I don't understand what it means.
the code that I have been running in the control.lua is
Code: Select all
local function register_entity(event)
local tick = event.tick
local entity = event.entity or -- script_raised_built
event.created_entity or -- on_built_entity
event.destination -- on_entity_cloned
local remove_tick = tick + 5*60--5*60*60 -- 5 minutes (60 ticks per second, 60 seconds per minute)
if not global.remove_at then
global.remove_at = {}
script.on_event(defines.events.on_tick, remove_entities)
end
global.remove_at[remove_tick] = global.remove_at[remove_tick] or {}
table.insert(global.remove_at[remove_tick], entity)
end
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)
local function remove_entities(event)
local remove = global.remove_at and global.remove_at[event.tick]
if remove then
for e, entity in pairs(remove) do
if entity.valid then
entity.destroy()
end
end
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
end
script.on_event(defines.events.on_tick, remove_entities)
Any idea what it means?
Re: Can you make an entity despawn after a while?
Sorry, there was a typo in my code! It must be:Leoncio wrote: Sat Apr 29, 2023 10:07 am I am getting an error box when loading a new map, the message is: "Key "filter" not found in property tree at ROOT[0]"
Any idea what it means?
Code: Select all
local filters = {
{filter = "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)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Re: Can you make an entity despawn after a while?
Thank you!
I will load now, however, the entity wont despawn. Should the entire code be in control.lua? Should I do something else to the entity to make it interact with the event script?
I will load now, however, the entity wont despawn. Should the entire code be in control.lua? Should I do something else to the entity to make it interact with the event script?
Re: Can you make an entity despawn after a while?
Yes, all of that should be in control.lua (or in a file loaded by it via "require()").Leoncio wrote: Sat Apr 29, 2023 11:53 am I will load now, however, the entity wont despawn. Should the entire code be in control.lua?
If you place down a new entity, is it stored in the global table? Add this at the top of control.lua:Should I do something else to the entity to make it interact with the event script?
Code: Select all
-- Support for "Global variable viewer"
if script.active_mods["gvv"] then
require("__gvv__.gvv")()
log("Enabled support for gvv!")
end
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Re: Can you make an entity despawn after a while?
What would the code for adding log() to my code be?Pi-C wrote: Sat Apr 29, 2023 1:04 pm Then add this mod, reload the game, and type "/gvv" in the chat window to open the GUI of gvv. You can then inspect the contents of your global table. Also, you should add "log()" commands to your code so you can follow what happens and see whether the part that should destroy the entities is actually run.
Re: Can you make an entity despawn after a while?
Look here for a description of the "serpent" library and "log()" function. You could log just a short fixed-text message to indicate which branch of an if-else-then statement has been taken, you could log the value of a variable or the contents of a table, or what arguments have been passed on to a function. Here's an example:
Code: Select all
local function register_entity(event)
log("Entered function register_entity("..serpent.line(event)..")")
local tick = event.tick
local entity = event.entity or -- script_raised_built
event.created_entity or -- on_built_entity
event.destination -- on_entity_cloned
log(string.format("entity: %s \"%s\" (%s)",
entity and entity.type or "nil",
entity and entity.name or "nil",
entity and entity.unit_number or "nil"))
local remove_tick = tick + 5*60--5*60*60 -- 5 minutes (60 ticks per second, 60 seconds per minute)
log("remove_tick: "..remove_tick)
if not global.remove_at then
log("Creating global.remove_at!")
global.remove_at = {}
script.on_event(defines.events.on_tick, remove_entities)
end
global.remove_at[remove_tick] = global.remove_at[remove_tick] or {}
table.insert(global.remove_at[remove_tick], entity)
log("global.remove_at: "..serpent.block(global.remove_at))
log("Leaving function register_entity()")
end
Actually, it's a good idea to put a wrapper around log(), so that you can turn it off when you release your mod. Logging is useful while you're working on your mod, but you shouldn't spam the log files of your users. The wrapper could be as simple as this (insert at top of control.lua):
Code: Select all
-- Change value to "false" before releasing the mod!
ENABLE_LOGGING = true
local my_log
if ENABLE_LOGGING then
my_log = function(msg)
log(msg)
end
else
my_log = function() end
end
Code: Select all
my_log("Creating global.remove_at!")
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!