I managed it to crash the game without a error report

Place to get help with not working mods / modding interface.
Paned
Inserter
Inserter
Posts: 21
Joined: Sun Mar 13, 2016 10:02 am
Contact:

I managed it to crash the game without a error report

Post by Paned »

Hi, somehow i made a mistake and i can not find my error.

my event calls this:

local arrayWithTiles = {"water", "deepwater", "water-green", "deepwater-green", "water-shallow", "water-mud", "water-wube"}


for chunk in game.surfaces[1].get_chunks() do
if game.surfaces[1].get_pollution({chunk.x,chunk.y}) > 1 then
area_fromChunk={left_top={x=chunk.x*32,y=chunk.y*32+31},right_bottom={x=chunk.x*32+31,y=chunk.y*32}}
if game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles}) then
game.print("found water")
end end so on ;-)

i tried it with limit too - made no difference

after my event fires that code line my game freezes and finaly crashes. So.. what did i do wrong? :D
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

Not sure what causes your crash, but this is wrong:

Code: Select all

if game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles}) then
    game.print("found water")
end
LuaSurface::find_tiles_filtered will always return an array with 0 or more elements, so the condition is always true. This will work as expected:

Code: Select all

if next(game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles})) then
    game.print("found water")
end
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Paned
Inserter
Inserter
Posts: 21
Joined: Sun Mar 13, 2016 10:02 am
Contact:

Re: I managed it to crash the game without a error report

Post by Paned »

uh, can you tell me why i have to use next there?
i thought i was going through the chunk table by the for loop - somehow i dont get it (sorry..)


i will try it :)
thank you for the fast support here - nice one! :)
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

Paned wrote: Fri Oct 03, 2025 3:58 pm uh, can you tell me why i have to use next there?
i thought i was going through the chunk table by the for loop - somehow i dont get it (sorry..)
If game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles}) doesn't find any water tiles, it won't return nil but {}. So you're not interested in whether there is a return value, but whether the array of found tiles has more than 0 elements. You could also use

Code: Select all

local found = game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles}) 
if #found > 0 then
    game.print("found water")
end
But because next( {} ) == nil, using next() is an easy way to find out whether a table is empty. Moreover, it will work not just for arrays (e.g. { 1, 2, 3, 4, 5 }), but also for tables (e.g. { [2] = true, [3] = false, [5] = 123 } or { index = 1, type = "item"}.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Paned
Inserter
Inserter
Posts: 21
Joined: Sun Mar 13, 2016 10:02 am
Contact:

Re: I managed it to crash the game without a error report

Post by Paned »

i do like the second version better :)

Thank you for helping me out here.

But still. As soon as this code is fired my game freezes :(

is there something wrong with the .find_tiles_filtered function?

edit:

Just because there might be something else wrong with it.. i post all i got in that file now. but if i comment the check for water out, it does work - it finds polluted chunks, if i write a display for chunk positions, it does that too.

maybe there is a more elegant way of doing what i did XD but i am no programmer just do this for fun atm :)
btw. does all water convert to "water-green" when the pollution gets high enough?

Code: Select all

local tick_t = 0
local arrayWithTiles = {"water", "deepwater", "water-green", "deepwater-green", "water-shallow", "water-mud", "water-wube"}

script.on_event(defines.events.on_tick, function(event)
  spawn_morphed_fish(event)
end)


function spawn_morphed_fish(event)
  if tick_t <= 600 then 
    tick_t = tick_t + 1
  else
	tick_t = tick_t - 600
	game.print("running")
	for chunk in game.surfaces[1].get_chunks() do
	  if game.surfaces[1].get_pollution({chunk.x,chunk.y}) > 1 then
	  --game.print(chunk.x .. ", ".. chunk.y)
	     game.print(chunk.x .. ", ".. chunk.y .. "is polluted")
	    local reg_entity_chunk ={}
		
		--reg_entity_chunk[1] = {chunk.x,chunk.y}
		
		local area_fromChunk={left_top={x=chunk.x*32,y=chunk.y*32+31},right_bottom={x=chunk.x*32+31,y=chunk.y*32}}
		local found = game.surfaces[1].find_tiles_filtered({area = area_fromChunk, name = arrayWithTiles}) 
		if #found > 0 then
		  game.print("found water in chunk".. chunk.x .. ", " .. chunk.y)
		end
	  end
    end
	
  end
end


robot256
Smart Inserter
Smart Inserter
Posts: 1288
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: I managed it to crash the game without a error report

Post by robot256 »

https://lua-api.factorio.com/latest/con ... ngBox.html

Here's your problem: the X and Y coordinate in Factorio are screen coordinates. Positive Y is *down*. Both X and Y need to have the smaller value in area.left_top and the bigger value in area.right_bottom. Because the area definition is "inside out", find_tiles_filtered() is probably getting into an infinite loop. This might be a bug worth reporting.
My mods: Multiple Unit Train Control, RGB Pipes, Shipping Containers, Rocket Log, Smart Artillery Wagons.
Maintainer of Auto Deconstruct, Cargo Ships, Vehicle Wagon, Honk, Shortwave.
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

Paned wrote: Sat Oct 04, 2025 7:58 am i do like the second version better :)

Thank you for helping me out here.

But still. As soon as this code is fired my game freezes :(

is there something wrong with the .find_tiles_filtered function?
I don't see anything wrong with it. It does run in a newly started game (inverted the condition for the pollution check, so things will happen if pollution < 1). However, I did get the freeze earlier (in a testing world where I'd moved the character around some more, and committed suicide with nukes several times – not sure if that would produce pollution). I guess the cause for the freeze is that you have too many chunks to deal with.
maybe there is a more elegant way of doing what i did XD but i am no programmer just do this for fun atm :)
There definitely are ways to make your mod more efficient:
  • Use on_nth_tick rather than the on_tick event.
  • If you iterate over LuaSurface::get_chunks(), you'll get ChunkPositionAndArea, so you don't have to calculate area_fromChunk!
  • It seems that LuaSurface::get_chunks() may return chunks that have not yet been generated. You could use LuaSurface::is_chunk_generated() and ignore those chunks.
Here's a rework of your code:

Code: Select all

local arrayWithTiles = {"water", "deepwater", "water-green", "deepwater-green", "water-shallow", "water-mud", "water-wube"}

function spawn_morphed_fish(event)
  Log("Running")
  local surface = game.surfaces[1]
  local found, pos

  for chunk in surface.get_chunks() do
    game.print("Checking chunk "..chunk.x ..", "..chunk.y)
    pos = {chunk.x, chunk.y}

    if surface.is_chunk_generated(pos) and surface.get_pollution(pos) > 1 then
      Log("is polluted")

      found = surface.find_tiles_filtered({area = chunk.area, name = arrayWithTiles})
      if #found > 0 then
        Log("Found water!")
      end
    end
  end
end


script.on_nth_tick(600, function(event)
  spawn_morphed_fish(event)
end)
However, I'm afraid this still may run quite slowly due to the potentially huge number of chunks on Nauvis: With 2 million tiles in each direction(-10^6 <= x <= 10^6, -10^6 <= y <= 10^6), there is a total of 4*10^12 tiles in total. As each chunk has 32^2 = 1024 tiles, there should be roughly 4 billion (4*10^9) chunks! That will definitely be hard on UPS …
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
robot256
Smart Inserter
Smart Inserter
Posts: 1288
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: I managed it to crash the game without a error report

Post by robot256 »

I believe surface.get_chunks() only returns generated chunks. That's why it returns an empty array right after the surface is created, because nothing has been generated yet. What Pi-C is a good way to do what you want.
My mods: Multiple Unit Train Control, RGB Pipes, Shipping Containers, Rocket Log, Smart Artillery Wagons.
Maintainer of Auto Deconstruct, Cargo Ships, Vehicle Wagon, Honk, Shortwave.
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

robot256 wrote: Sat Oct 04, 2025 10:00 pm I believe surface.get_chunks() only returns generated chunks.
That's what I thought, too! However, when I was looking for the description of LuaSurface::get_chunks(), I noticed that there also is LuaTerritory::get_chunks(), which has a slightly different description:

"Chunks may or may not be generated; use LuaSurface::is_chunk_generated to check a chunk's state before accessing it."

So I made another mini-mod for testing (see attachment). Start a new game with just that mod active, watch your log file, and you sure will be surprised! :mrgreen:
Attachments
test_0.0.2.zip
(891 Bytes) Downloaded 3 times
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Paned
Inserter
Inserter
Posts: 21
Joined: Sun Mar 13, 2016 10:02 am
Contact:

Re: I managed it to crash the game without a error report

Post by Paned »

Oh, wow thank you all for your feedback :)

i realy need some time now to get all of that in my brain :D


edit:

Ahh, i think that explains why my game is crashing :) thy robot256


Thank you for rewriting the code Pi-C
i know that it would be a large impact on the resources the game uses. so i was thinking - maybe there is a better way to find polluted chunks and maybe the event has not to be triggered so often - maybe it has only be triggered if the pollution number changes upwards (i got something in my mind that would work with part of the script)
I had not seen the on_nth_tick(tick, handler) function :D so i used what i had found - thank you, that saves the tick_t and the run on every tick for counting the variable up - nice :)

i now wonder.. maybe it is possible to exclude chunks where no water was found
mhh there are improvements possible, i see :D but for now, i will be happy, if my fish spawns in water and not on land :D :D :D (yepp, i tried it and it works, my fish swimms "underground")
robot256
Smart Inserter
Smart Inserter
Posts: 1288
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: I managed it to crash the game without a error report

Post by robot256 »

The best improvement would be if your code runs on the on_chunk_generated event. Look for water tiles, then add it to a list stored in storage. You will have a list of only generated chunks that have water tiles. Then you can use that list whenever you need to update.

The other optimization is to not use on_nth_tick. Instead, process a small number of chunks every tick. That avoids causing a huge lag spike every 10 seconds as you do them all at once.

If you only need to know if a chunk has water, and not where it is, instead of "find_tiles_filtered", use "count_tiles_filtered".
My mods: Multiple Unit Train Control, RGB Pipes, Shipping Containers, Rocket Log, Smart Artillery Wagons.
Maintainer of Auto Deconstruct, Cargo Ships, Vehicle Wagon, Honk, Shortwave.
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

robot256 wrote: Sun Oct 05, 2025 3:36 pm The best improvement would be if your code runs on the on_chunk_generated event.
This will work in games where the mod has been active right from the start. But if the mod was added to a running game, you'd miss all chunks that have already been generated. You can avoid that if you build your list of chunks in on_init:

Code: Select all

script.on_init(function()
	if game.tick > 0 then
	    for chunk in game.surfaces[1].get_chunks() do
	    	...
	    end
	end
end)
Look for water tiles, then add it to a list stored in storage. You will have a list of only generated chunks that have water tiles.
There are mods like Waterfill that manipulate tiles. So you should also act on these events:
  • on_player_built_tile
  • on_player_mined_tile
  • on_robot_built_tile
  • on_robot_mined_tile
  • on_space_platform_built_tile (?)
  • on_space_platform_mined_tile (?)
  • script_raised_set_tiles
The other optimization is to not use on_nth_tick. Instead, process a small number of chunks every tick. That avoids causing a huge lag spike every 10 seconds as you do them all at once.
Agreed, processing only some chunks would be better. But how do you do that – or, rather, how does get_chunks() work? When dealing with tables, you can use next(table, index), so it's possible to resume processing the table where you left off. But get_chunks() doesn't take any arguments …
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

robot256 wrote: Sun Oct 05, 2025 3:36 pm If you only need to know if a chunk has water, and not where it is, instead of "find_tiles_filtered", use "count_tiles_filtered".
@Paned named the function spawn_morphed_fish(), so I guess it is relevant where the water tiles are located. This poses another problem: how do you determine where to place fish? Imagine somebody water-filling a single tile (or a small canal of 1x5 tiles) – it really makes no sense to spawn fish in such small puddles, this should be done only in water bodies that are big enough for fish to swim. But how do you determine the size of such a water body?

Checking the neighbors of all water tiles may work, but I guess that will be hard on UPS as well. Also, let's say you decide on an area of 10x10 tiles for the minimum size of water bodies suitable for spawning fish: What if these 10x10 tiles are split among 2 to 4 chunks? The number of water tiles in each chunk would be considered too small to spawn fish, so you might end up with bodies of water where no fish is spawned although they would be big enough.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
robot256
Smart Inserter
Smart Inserter
Posts: 1288
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: I managed it to crash the game without a error report

Post by robot256 »

Pi-C wrote: Sun Oct 05, 2025 4:07 pm
robot256 wrote: The other optimization is to not use on_nth_tick. Instead, process a small number of chunks every tick. That avoids causing a huge lag spike every 10 seconds as you do them all at once.
Agreed, processing only some chunks would be better. But how do you do that – or, rather, how does get_chunks() work? When dealing with tables, you can use next(table, index), so it's possible to resume processing the table where you left off. But get_chunks() doesn't take any arguments …
get_chunks() returns a LuaChunkIterator object. This can be saved in storage and the chunk handles can be retrieved one at a time with the next() function. Keep getting chunks a few at a time (e.g. in a "for n=1,5 do" loop) until it returns nil. if you need to do another scan, start over with a new LuaChunkIterator object. Don't forget to check the iterator object .valid at the beginning of the event that reads it, in case the surface was deleted and the iterator is no longer valid.
My mods: Multiple Unit Train Control, RGB Pipes, Shipping Containers, Rocket Log, Smart Artillery Wagons.
Maintainer of Auto Deconstruct, Cargo Ships, Vehicle Wagon, Honk, Shortwave.
Pi-C
Smart Inserter
Smart Inserter
Posts: 1783
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: I managed it to crash the game without a error report

Post by Pi-C »

robot256 wrote: Sun Oct 05, 2025 4:38 pm get_chunks() returns a LuaChunkIterator object. This can be saved in storage and the chunk handles can be retrieved one at a time with the next() function. Keep getting chunks a few at a time (e.g. in a "for n=1,5 do" loop) until it returns nil. if you need to do another scan, start over with a new LuaChunkIterator object. Don't forget to check the iterator object .valid at the beginning of the event that reads it, in case the surface was deleted and the iterator is no longer valid.
Thanks, now I've got it! :-)
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!
robot256
Smart Inserter
Smart Inserter
Posts: 1288
Joined: Sun Mar 17, 2019 1:52 am
Contact:

Re: I managed it to crash the game without a error report

Post by robot256 »

Pi-C wrote: Sun Oct 05, 2025 8:59 pm
robot256 wrote: Sun Oct 05, 2025 4:38 pm get_chunks() returns a LuaChunkIterator object. This can be saved in storage and the chunk handles can be retrieved one at a time with the next() function. Keep getting chunks a few at a time (e.g. in a "for n=1,5 do" loop) until it returns nil. if you need to do another scan, start over with a new LuaChunkIterator object. Don't forget to check the iterator object .valid at the beginning of the event that reads it, in case the surface was deleted and the iterator is no longer valid.
Thanks, now I've got it! :-)
You can get clever with the optimization too. For example, each tick, loop getting next(chunks) each time. Break the loop after processing 5 generated chunks or 10,000 ungenerated chunks.
My mods: Multiple Unit Train Control, RGB Pipes, Shipping Containers, Rocket Log, Smart Artillery Wagons.
Maintainer of Auto Deconstruct, Cargo Ships, Vehicle Wagon, Honk, Shortwave.
Post Reply

Return to “Modding help”