⚠️ SearchlightAssault ⚠️


Adds a game map and searchlights which sweep for foes at great range, alerting you while directing adjacent turrets to snipe spotted foes. Designed to dovetail with the early-mid game, searchlights provide: - Circuit network interfaces for search & detection I/O - Incentive to automate lamp & combinator production in the early game - New tactics to assault biter bases without leap-frogging turrets!

Content
7 days ago
1.1 - 2.0
12.8K
Combat

b Crash

2 years ago

Removed an enemy in editor mode (deleted, not killed) - possible the same case via script

The mod ⚠️ SearchlightAssault ⚠️ (1.2.6) caused a non-recoverable error.
Please report this error to the mod author.

Error while running event SearchlightAssault::on_tick (ID 0)
LuaEntity API call when LuaEntity was invalid.
stack traceback:
[C]: in function 'newindex'
__SearchlightAssault
/control-gestalt.lua:188: in function 'CheckElectricNeeds'
SearchlightAssault/control.lua:194: in function <SearchlightAssault/control.lua:191>

2 years ago
(updated 2 years ago)

Unfortunately, the map editor does not fire on_killed() / on_mined() events in some situations. Most scripts raise such events, so they're usually fine...

I've done the best I can to make my mod robust against the map editor, but I can't do anything more to fix such crashes without making my mod cause more lag.
If you find any mods / scripts that cause such issues, please let me know so I can investigate and possibly work out a compatibility patch.

In the future, I plan to rework things within my mod, and can possibly bypass or improve the issue.

But for now, I recommend you always remove entities in the map editor by not using the entity-tab while the mod is active.

2 years ago

Seems like a validity check would be all it takes:

export.CheckElectricNeeds = function()
  for _, g in pairs(global.gestalts) do
    if g.turtle.valid then  -- ADDED
      g.turtle.active = g.light.energy > 0
    -- else
      -- Remove entity from global table
    end
  end
end
2 years ago
(updated 2 years ago)

Yes, that would fix probably 99% of cases.
(I suspect its possible that any number of my other functions that reference entities could wind up referencing something invalidated by the map editor right before onTick() is called, not just CheckElectricNeeds())

But that function is the biggest source of lag in the mod for all players, since it's run in onTick(). I made it as small as I know how to, so adding another branching statement there is possibly halving the amount of searchlights players can use without lag...

So I'd be increasing lag for everyone just to fix a mitigable problem for the portion of players who use map editor.

I'd rather not make that trade off, since I'm working on a major update to improve performance right now. After I finish the refactor that involves, I'll be in a better position to look at adding the validity check.
But what I really should do is just ask Wube for a mod-interface update to fix the missing onDeath/Mined event...

2 years ago

That would help somewhat, but not in every case. Mods can use entity.destroy() without raising an event. According to the wiki, you can pass on "raise_destroy = true", but raise_destroy will be false per default. So, even if players don't use the editor, entities you've stored in your table could be invalid because they've been destroyed by other mods.

2 years ago
(updated 2 years ago)

True.

Right now I'm mostly praying that modders aren't destroying content their mod didn't make without setting raise_destroy. I haven't seen anyone report cases of bad behavior like that, so far..
(My own mod does a little bit of bad behavior, so at release, I included a runtime setting to let players stop my mod from trying to range-boost (silently destroying and replacing) specified turrets that might have their own hidden entities.)

At any rate, I'm still hopeful that after I finish refactoring in my next major update, I can be more aggressive with .valid checks without impacting lag.

2 years ago

It looks like there's a registration / callback feature I've overlooked that sidesteps all the map-editor / raise_destroy=true stuff.
https://forums.factorio.com/viewtopic.php?p=566301#p566301

I'll just update to use it sometime today.

2 years ago

Right now I'm mostly praying that modders aren't destroying content their mod didn't make without setting raise_destroy. I haven't seen anyone report cases of bad behavior like that, so far..

Nevertheless, as a rule of thumb, you should always assume the worst! :-) Currently, I have to completely restructure the GUI of my character selector mod. The old one was OK while there were only a few new characters players could choose from and I thought I could leave the GUI as it is for at least a year. Then all of a sudden there is a mod that adds about 20 new characters, so my GUI has become completely unusable overnight.

(My own mod does a little bit of bad behavior, so at release, I included a runtime setting to let players stop my mod from trying to range-boost (silently destroying and replacing) specified turrets that might have their own hidden entities.)

That will certainly cause trouble at some point! You should give other mods a chance to blacklist their entities with your mod. Just provide a remote interface with a function where they can pass on the names of their prototypes, put them in a list and store that in your global table. In on_init or on_configuration_changed, use that list to build event filters, and apply these to your destroy events. If another mod calls your remote function, add the new prototype names, rebuild the event filters and register the events again with the new filters.

That is some overhead, but it will only cause delays after starting or loading a game. Moreover, the game itself will filter out any blacklisted entities; that's more efficient than anything you could do in Lua, and your events shouldn't be raised quite as often.

At any rate, I'm still hopeful that after I finish refactoring in my next major update, I can be more aggressive with .valid checks without impacting lag.

Getting the value of a setting, searching for entities on a surface, using game.get_filtered_*_prototypes() -- things like that involve expensive operations and should be avoided whenever possible (best way is to run such a command once and cache the return values in a global variable). But if you already have an entity, checking its validity involves just reading a flag on that entity and won't cause much of a lag.

2 years ago

That will certainly cause trouble at some point! You should give other mods a chance to blacklist their entities with your mod. Just provide a remote interface with a function where they can pass on the names of their prototypes, put them in a list and store that in your global table. In on_init or on_configuration_changed, use that list to build event filters, and apply these to your destroy events. If another mod calls your remote function, add the new prototype names, rebuild the event filters and register the events again with the new filters.

That sounds sensible, I'll put it on my backlog.

2 years ago

I ran a stress test with 4 thousand searchlights and tested how impactful the on_tick() entity.valid checks I'd need are.
It was about a 12% cost to UPS, which I'm not happy about, but it isn't too bad considering how many lights that is. So I'm going to go ahead and put it in. There will probably still be some edge cases that it doesn't cover, but hopefully everyone will still be satisfied.

I also implemented the LuaBootstrap.register_on_entity_destroyed() callback so the map editor should be pretty robust now.

I have released version 1.2.9 with these changes.
The new version should start to appear in the mod portal shortly.
If you don't see it in-game you can download it manually here: https://mods.factorio.com/mod/SearchlightAssault/downloads

2 years ago

You should give other mods a chance to blacklist their entities with your mod. Just provide a remote interface with a function where they can pass on the names of their prototypes, put them in a list and store that in your global table.

Finally done as of version 2.2.2 :)

New response