surface.get_chunks() iterator single call ?

Place to get help with not working mods / modding interface.
Post Reply
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1524
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

surface.get_chunks() iterator single call ?

Post by binbinhfr »

Hi,

I want to parse thru chunks of the map, but not in one single for loop like this :

Code: Select all

for chunk in surf.get_chunks() do
(...)
I want to treat one chunk per game tick in the on_tick event.
So I suppose that I have to call this iterator one by one, keeping memory of where I am in global, but I cannot figure out how to write it...
I tried this but it does not work... (I am not very familiar with LUA deep programming)

Code: Select all

	if global.refresh_chunk == nil then
		global.refresh_chunks = surf.get_chunks()
	end
	
	global.refresh_chunk = global.refresh_chunks()
	
	if global.refresh_chunk ~= nil then
		local chunk = global.refresh_chunk
		local a = {{chunk.x * 32, chunk.y * 32}, {chunk.x * 32 + 32, chunk.y * 32 + 32}}
My mods on the Factorio Mod Portal :geek:

Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: surface.get_chunks() iterator single call ?

Post by Nexela »

Don't kill the messenger. While they are not supported there are always coroutines

function interface.test(player)
co = coroutine.create(function ()
for chunk in game.players[player.index].surface.get_chunks() do
player.print("x:".. chunk.x .."y:"..chunk.y)
coroutine.yield()
end
end)
end

function interface.test2()
coroutine.resume(co)
end

Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: surface.get_chunks() iterator single call ?

Post by Nexela »

Don't mind me though I am just on the coroutines chapter!

User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1524
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by binbinhfr »

... Thx Nexela but I do not see how it helps me... :-)

what I want is to write a function that each time I call it, returns a different chunk of the map, and parsing at the end all the chunks (and looping to first one if needed).

For the moment, I created a table containing all the chunks and I use next() on this table, but I wonder if their is a nicer way to do it,
directly using this surf.get_chunks() which seems to be an iterator by itself.
My mods on the Factorio Mod Portal :geek:

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by aubergine18 »

If you have the iterator function, each time you call it directly you should get next iteration, until you get to the end in which case it will return nil, after which if you try it again it should start at beginning.

Example of custom Lua iterators gives some insight in to how they work:

* http://stackoverflow.com/questions/2362 ... -lua-pairs
* http://lua-users.org/wiki/GeneralizedPairsAndIpairs

Now, I don't know how the chunk iterator actually works - depending on implementation it might reset itself every tick or something weird like that. Also, it's likely that its list of chunks is a snapshot of the exposed chunks at the moment when the iterator was created, meaning any subsequently exposed chunks might not be available to the iterator - in which case at the end of each iteration (when you get nil back from the iterator) it would probably be worth getting a fresh iterator.

As for co-routines, I'm not sure how reliable they will be in MP - particularly as they would run at different speeds not tied to game state on each computer, they would almost certainly cause desync.
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by aubergine18 »

Addendum: get_chunks() isn't the iterator, it returns an iterator.

Code: Select all

local iterator = someSurface.get_chunks()
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1524
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by binbinhfr »

Yes I already read all that, but what I am looking for is the syntax.
How do I get next chunk ? I tested several syntaxes, but none works.
So if you have an idea, please write the little piece of code to show me an example.
The iterator should be supposed to return key,chunk but it does not seem to work...
My mods on the Factorio Mod Portal :geek:

Veden
Filter Inserter
Filter Inserter
Posts: 294
Joined: Wed Jul 13, 2016 3:54 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by Veden »

The following is how I got around the iterator in Rampant.

Code: Select all

function onChunkGenerated(event)
    if (event.surface.index == 1) then
        chunks[#chunks+1] = event
    end
end
so when a chunk is generated you store that into a list in global.

Code: Select all

local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
    onChunkGenerated({ surface = surface, 
                       area = { left_top = { x = chunk.x * 32,
                                             y = chunk.y * 32 }}})
end
or on init you can iterate existing chunks to start the list

then to process the list at whatever pace you would like you would do the following

Code: Select all

function doOneStep(chunks)
    local chunk = chunks[global.currentChunk]
    .... doProcessing ....
    global.currentChunkPointer = global.currentChunkPointer + 1
    if (global.currentChunkPointer == #chunks) then
        global.currentChunkPointer = 1
    end
end

User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1524
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by binbinhfr »

Yes, that's basically what I do for the moment : maintain a list of chunks in global and circling thru it.
But I was wondering if there was a more direct way to do it, just using this iterator that seems to be hidden somewhere in this surface.get_chunks() ...
My mods on the Factorio Mod Portal :geek:

Veden
Filter Inserter
Filter Inserter
Posts: 294
Joined: Wed Jul 13, 2016 3:54 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by Veden »

According to https://wiki.factorio.com/index.php?tit ... _Lifecycle functions can be serialized but cannot contain upvalues (closures) which I believe iterators have to do to maintain state across function calls.

Veden
Filter Inserter
Filter Inserter
Posts: 294
Joined: Wed Jul 13, 2016 3:54 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by Veden »

Code: Select all

  
   if global.refresh_chunk == nil then
      global.refresh_chunks = surf.get_chunks()
   end
   
   global.refresh_chunk = global.refresh_chunks(nil, nil)
   
   if global.refresh_chunk ~= nil then
      local chunk = global.refresh_chunk
      local a = {{chunk.x * 32, chunk.y * 32}, {chunk.x * 32 + 32, chunk.y * 32 + 32}}
gives you the one step you are looking for, but it does not persist the current position across saves and no combination of parameters seems to make a difference it always starts at the beginning.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: surface.get_chunks() iterator single call ?

Post by aubergine18 »

It sounds like the iterator returned by get_chunks() is only returning key and value, but not the source table, hence it not working across ticks. That makes sense, because it avoids having to unnecessarily typecast the full table to lua on the first iteration (so if you break out of the iteration early, you save a whole load of processing, and if you don't you don't incur any extra processing).

You could potentially create a custom iterator to iterate over the custom list (or just use lua standard 'next' function which returns a ready made iterator) although not sure there's any benefit to doing that especially if the list can change from time to time. Might as well just do it manually, remembering current position in the list and reset to 1 after reaching #list.
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

Post Reply

Return to “Modding help”