the inifinite loop is easily avoidable, i think you should do both, if you didn't pass in quality or fire the event i would need to read your code to know how many ticks after chunk spawn you recreate the bases, add a tick delay slightly longer then fetch all bases in that chunk and redo them.
With you firing the events ( no quality pass through ) i could specifically do an on event and check if the event was done by your mod ( make you an optional dependency ) and when you recreate bases i could then recreate them with quality.
With you passing through the quality ( i don't need to do anything not even optional dependency ).
If you ever recreate bases the moment they are made instead of n ticks later and don't fire events it is likely one of us will get an entity that is already null from the other person deleting it ( who knows which one of us it could be random per entity ). we both likely early return if its null and a base exists that was never "fixed" by the other mod which is where the raised_built is useful. firing this event would let you walk away from being n tickets behind and instead do it in the on event right away for base replacing and any other mods with compat issues simply need to leverage the raised_built by both firing it and using it to know when a new base is made by someone else they might need to edit. You would also leverage it with some kind of map to not edit a base at the same location twice and only delete / create if it's not what you wanted.
doing something like this to avoid infinite loops isn't too bad.
global.my_mod_processed_spawners = global.my_mod_processed_spawners or {}
local function get_spawner_key(surface, position)
return surface.name .. "" .. math.floor(position.x) .. "" .. math.floor(position.y)
end
local function on_entity_built(event)
local entity = event.created_entity or event.entity
if entity.valid and entity.type == "unit-spawner" then
local key = get_spawner_key(entity.surface, entity.position)
if global.my_mod_processed_spawners[key] then
return -- Already processed at this location
end
.........
global.my_mod_processed_spawners[key] = true
end
This would be a very basic solve, you likely want to use a TTL on the array so if its over a few minute old it likely doesn't count and is a "brand new" one again.
The one thing im not sure about is if we should use the create & destroy events as part of the entity destroy / create func calls or if we should instead send a "revive" event which would signal "this base didn't come from nowhere i recreated something that existed"