So lets start with probably the most common usecase, tracking data for any/all surfaces within your own mod, this is typically done by going over all surfaces (and possibly iterating entities on them), and then listening to the on_surface_created in order to detect new surfaces, but surfaces can slip through these cracks.
(note that it doesn't seem unique for just the surface creation events, raising build events from on_init also get missed by mod A)
"mod A"
Code: Select all
script.on_init(function()
storage.surfacedata = {}
for _, surface in pairs(game.surfaces) do
storage.surfacedata[surface.index] = {some = "thing"}
end
end)
script.on_event(defines.events.on_surface_created, function(event)
log(string.format("surface '%s' created.", game.get_surface(event.surface_index).name))
storage.surfacedata[event.surface_index] = {foo = "bar"}
end)
script.on_event(defines.events.script_raised_built, function(event)
log(serpent.line(event.entity.position))
end)
commands.add_command("mod-a", nil, function(command)
log(serpent.block(storage.surfacedata))
end)
Code: Select all
script.on_init(function()
game.create_surface("on_init")
game.surfaces["nauvis"].create_entity{
name = "wooden-chest",
force = "neutral",
position = {0, 0},
raise_built = true,
}
end)
script.on_configuration_changed(function()
game.create_surface("on_configuration_changed")
game.surfaces["nauvis"].create_entity{
name = "wooden-chest",
force = "neutral",
position = {1, 0},
raise_built = true,
}
end)
-- non save-load stable example
script.on_event(defines.events.on_tick, function(event)
game.create_surface("on_tick")
game.surfaces["nauvis"].create_entity{
name = "wooden-chest",
force = "neutral",
position = {2, 0},
raise_built = true,
}
script.on_event(defines.events.on_tick, nil)
end)
- Script @__mod-a__/control.lua:10: surface 'on_init' created.
- Script @__mod-a__/control.lua:15: {x = 0.5, y = 0.5}
- Script @__mod-a__/control.lua:10: surface 'on_tick' created.
- Script @__mod-a__/control.lua:15: {x = 2.5, y = 0.5}
But when you create the world with A installed, save, enable B, load you'll see this:
- Script @__mod-a__/control.lua:10: surface 'on_configuration_changed' created.
- Script @__mod-a__/control.lua:15: {x = 1.5, y = 0.5}
- Script @__mod-a__/control.lua:10: surface 'on_tick' created.
- Script @__mod-a__/control.lua:15: {x = 2.5, y = 0.5}
Or in other words, even though A is already initialized (and thus "ready" to receive events) the surface creation event triggered by the on_init of mod B doesn't get picked up by mod A at all. (surface "on_init" did get created, and surfaces created in on_configuration_changed do seem to get picked up)
So yea is this a bug, or something worth clearly documenting that events fired from on_init do not trigger in existing mods, so everyone in their "A" should recheck for new entities just like they would in their on_init?
I often get around it by writing code like this, the first time i ran into this issue long ago it felt really weird, it still does, but at least this does work:
Code: Select all
local function refresh_surfacedata()
-- deleted old
for surface_index, surfacedata in pairs(storage.surfacedata) do
if surfacedata.surface.valid == false then
storage.surfacedata[surface_index] = nil
end
end
-- created new
for _, surface in pairs(game.surfaces) do
storage.surfacedata[surface.index] = storage.surfacedata[surface.index] or {
surface = surface,
}
end
end
script.on_init(function()
storage.surfacedata = {}
refresh_surfacedata()
end)
script.on_configuration_changed(function()
refresh_surfacedata()
end)
script.on_event(defines.events.on_surface_created, refresh_surfacedata)
script.on_event(defines.events.on_surface_deleted, refresh_surfacedata)