Page 1 of 2

Regenerate map under existing factory, any ideas?

Posted: Sun Dec 30, 2018 10:08 am
by Dixi
I have reasonably sized base (360 hours playtime, 1k SPM, 1 rocket/min, ~8000 rockets launched) started on 0.15 map. Biters present on a map, normal settings.
Since change to 0.16 new chunks are generated by different algorithm so map looks inconsistent. But I used to it, to some degree. In 0.17 map generating will likely change again.

I don't want to spend another ~300 hours of gameplay to build a new base of similar size on a new 0.17 map. And I still like to expand existing base.
I wonder is it possible to destroy whole map, while keeping structures, and communications intact, and have it regenerated whole?
I understand that water areas and all mineral deposits will move, and at some areas cliffs might appear, but fixing my base after such "disaster" looks much more interesting for me, comparing to fresh start from scratch.

Empty explored chunks of map can be easily destroyed by mod, and then regenerated by game as new. But is it possible to destroy terrain in a chunk without affecting other structures? Or to mark all chunks "needed to be map generated"? For sample, when I manually shoot from an artillery cannon to a maximum distance, map is likely generated "on a fly" under flying cannon shell. Is it possible to use same mechanic, by marking whole map for regeneration?

Re: Regenerate map under existing factory, any ideas?

Posted: Sun Dec 30, 2018 12:13 pm
by steinio
At least you can delete generated chunks which are still empty (without buildings of you)
https://mods.factorio.com/mod/DeleteEmptyChunks

Re: Regenerate map under existing factory, any ideas?

Posted: Sun Dec 30, 2018 2:04 pm
by Dixi
Yes I know about that and another similar but older mods.
But question is about replacing whole map.
I suppose it might be done in LUA, by telling to engine that map need to be regenerated chunk by chunk.
Mentioned above mod also iterate all chunks, checking some conditions, and in the end deleting some chunks. After that deleted pieces getting regenerated by game engine.
In my case deleting chunks probably will not work, since player structures are also store there, are they? Or not?

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 12:17 am
by Jap2.0
Dixi wrote:
Sun Dec 30, 2018 2:04 pm
Yes I know about that and another similar but older mods.
But question is about replacing whole map.
I suppose it might be done in LUA, by telling to engine that map need to be regenerated chunk by chunk.
Mentioned above mod also iterate all chunks, checking some conditions, and in the end deleting some chunks. After that deleted pieces getting regenerated by game engine.
In my case deleting chunks probably will not work, since player structures are also store there, are they? Or not?
I believe they are. Does anyone know if it would be possible to store the contents of a chunk, delete it, regenerate it, and restore the contents (possibly landfilling/removing trees/cliffs) via mod? It seems like something that should be possible but I wouldn't know.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 8:49 am
by darkfrei

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 9:07 am
by Dixi
darkfrei wrote:
Mon Dec 31, 2018 8:49 am
You are need https://mods.factorio.com/mod/NewGamePlus
That is an interesting option but not the thing I'm looking for.
I want to keep existing base, not to get in a new world, while keeping research and full pockets.
Jap2.0 wrote:
Mon Dec 31, 2018 12:17 am
Does anyone know if it would be possible to store the contents of a chunk, delete it, regenerate it, and restore the contents (possibly landfilling/removing trees/cliffs) via mod?
Are you sure that engine creates map only on empty chunks?
In API calls there are methods

request_to_generate_chunks(position, radius)
force_generate_chunk_requests()
set_chunk_generated_status(position, status)

I wonder what will happen if one calls
request_to_generate_chunks({0,0}, 1000)
Will it wipe the map and generate new or only terrain will regenerate, as I want?

I can't find chunk structure description. I afraid, that that it's actually C++ game data, that can be referenced from LUA calls, and only limited methods are available to us.

Update.
So far results were .... umm ... unexpected.
/c game.player.surface.request_to_generate_chunks({0,0}, 1000)
Freezes the game and crushed: game, steam, web browser. Probably, because it tried to allocate too much RAM.
Smaller request
/c game.player.surface.request_to_generate_chunks({0,0}, 100)
drops FPS/UPS to 3 for a minute. When operation was complete, nothing changes.

It seems that map on chunks with player owned structures are not generated by above call.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 10:23 am
by orzelek
It's a bit of a guess but I think you might need to set status of all chunks first.
Calling just generate will check they are there already and skip them.
Setting them all to defines.chunk_generated_status.nothing might cause some reaction - I did not try so it might do nothing as well :D

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 10:24 am
by darkfrei
Dixi wrote:
Mon Dec 31, 2018 9:07 am
darkfrei wrote:
Mon Dec 31, 2018 8:49 am
You are need https://mods.factorio.com/mod/NewGamePlus
That is an interesting option but not the thing I'm looking for.
I want to keep existing base, not to get in a new world, while keeping research and full pockets.
Ohh, then you can try https://mods.factorio.com/mod/nicefill, it makes new generated hidden map surface and when you place landfill, it takes tiles from hidden surface and places correctly and smooth.

So if your surface is "nauvis" then hidden surface will be "NiceFill_nauvis" and you can make reading from one surface and rewrite chunks on your surface.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 11:05 am
by Dixi
I've checked NiceFill mod LUA code. I understand how he creates a new surface and calls map generator to create terrain chunks there, but I don't understand how to copy chunks (or tiles) from there to primary surface. In NiceFill that method might be a little complicated since he wants to copy only "landiffled" tiles, and sometimes 1-2 tiles around them for terrain blending or to make land-water borders looks correctly.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 11:10 am
by staviq
darkfrei wrote:
Mon Dec 31, 2018 10:24 am
Ohh, then you can try https://mods.factorio.com/mod/nicefill, it makes new generated hidden map surface and when you place landfill, it takes tiles from hidden surface and places correctly and smooth.

So if your surface is "nauvis" then hidden surface will be "NiceFill_nauvis" and you can make reading from one surface and rewrite chunks on your surface.
I was thinking at some point about adding a "cleanup" function to NiceFill, that would traverse chunks and fix inconsistent ground texture, and i might actually do it now that somebody actually has use for it.
There is however a problem of foliage, aka decorations that NiceFill currently ignores. I need to think about it.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 11:16 am
by Dixi
staviq wrote:
Mon Dec 31, 2018 11:10 am
I was thinking at some point about adding a "cleanup" function to NiceFill, that would traverse chunks and fix inconsistent ground texture, and i might actually do it now that somebody actually has use for it.
There is however a problem of foliage, aka decorations that NiceFill currently ignores. I need to think about it.
Do you mean that copying just tiles or whole chunks from new generated surface to original "nauvis" is not enough, and it won't make map "like a new"? "foliage, aka decorations" - are they additional objects on a map? Are they like player structures, attached to some tiles?

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 11:48 am
by darkfrei
Useful links:
https://lua-api.factorio.com/latest/LuaGameScript.html
https://lua-api.factorio.com/latest/Lua ... rator.html
https://lua-api.factorio.com/latest/LuaSurface.html

Here is the code that you looking for:
code
It makes new hidden map surface, copy settings from old surface, than replaces your map with new generated tiles.

Before:
2018-12-31 12_49_35-Window.png
2018-12-31 12_49_35-Window.png (2.63 KiB) Viewed 6348 times
After:
2018-12-31 12_49_26-Window.png
2018-12-31 12_49_26-Window.png (3.69 KiB) Viewed 6348 times

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 2:16 pm
by darkfrei
Optimized code, needs much more time, but works with megabases.

Code: Select all

/c
log ('start')
local surface = game.player.surface
local nf_surface_name = 'nf_'..surface.name
if not game.surfaces[('nf_'..surface.name)] then
  local settings = surface.map_gen_settings
  settings.autoplace_controls["enemy-base"] = {frequency="none",size="none",richness="none"}
  settings.autoplace_controls["trees"] = {frequency="none",size="none",richness="none"}
  settings.autoplace_settings =
      { entity = {treat_missing_as_default = false, settings = {frequency = "none", size = "none", richness = "none"}},
        decorative = {treat_missing_as_default = false, settings = {frequency = "none", size = "none", richness="none"}}}
  settings.water = "none"
  settings.starting_area = "none"
  settings.peaceful_mode = true
  settings.cliff_settings = {cliff_elevation_0 = 0, cliff_elevation_interval = 0, name = "cliff"}
  game.create_surface(nf_surface_name, settings)
end
log ('hidden map is created')
local nf_surface = game.surfaces[nf_surface_name]
for chunk in surface.get_chunks() do
  if not nf_surface.is_chunk_generated({x=chunk.x, y=chunk.y}) then
    nf_surface.request_to_generate_chunks({x=chunk.x*32, y=chunk.y*32}, 0)
  end
  nf_surface.force_generate_chunk_requests()
  local tiles = {}
  for x = (chunk.x*32), (chunk.x*32+31) do
    for y = (chunk.y*32), (chunk.y*32+31) do
      local tile = surface.get_tile(x, y)
      if tile.collides_with("ground-tile") then
        local nf_tile = nf_surface.get_tile(x, y)
        table.insert (tiles, {name=nf_tile.name, position = {x=x,y=y}})
      end
    end
  end
  surface.set_tiles(tiles)
  nf_surface.delete_chunk({x=chunk.x*32, y=chunk.y*32})
end
log ('complete')
Example:
I have one 500 hours long save game from 0.15, save file is about 92 MB, it has 96469 chunks and need up to about 14.7 GB of memory. It was ready in 1837 seconds or about 30 minutes.

Before:
2018-12-31 13_14_15-Window.png
2018-12-31 13_14_15-Window.png (158.63 KiB) Viewed 6313 times
After:
2018-12-31 16_03_14-Window.png
2018-12-31 16_03_14-Window.png (139.33 KiB) Viewed 6313 times

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 2:56 pm
by Dixi
Yes this code works. But it does not moves whole player made structures to a new map. It only replacing old terrain types with new, without any changes to geography and ore deposits. As staviq correctly mentioned, new copied terrain will looks really flat and lifeless, since we do not copy foliage and other decorations.

It seems to me that task of coping existing base to a new map is more complicated then it was on first glance.

If I will not find another solution to move existing base to a new map, in the end, idea of NewGamePlus mod might be useful. Fill whole inventory with nuclear plant, some miners/smelters, factories, bots, and start on a new map with existing research tree. I only doubt that my pockets will carry enough stuff. Need to check NewGamePlus forum part, to see if anyone already made "shopping list" to fill my inventory most optimal way.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 3:54 pm
by Jap2.0
Well, I've been meaning to learn lua anyway...

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 8:34 pm
by Optera
darkfrei wrote:
Mon Dec 31, 2018 2:16 pm
Optimized code, needs much more time, but works with megabases.

Code: Select all

/c
log ('start')
local surface = game.player.surface
local nf_surface_name = 'nf_'..surface.name
if not game.surfaces[('nf_'..surface.name)] then
  local settings = surface.map_gen_settings
  settings.autoplace_controls["enemy-base"] = {frequency="none",size="none",richness="none"}
  settings.autoplace_controls["trees"] = {frequency="none",size="none",richness="none"}
  settings.autoplace_settings =
      { entity = {treat_missing_as_default = false, settings = {frequency = "none", size = "none", richness = "none"}},
        decorative = {treat_missing_as_default = false, settings = {frequency = "none", size = "none", richness="none"}}}
  settings.water = "none"
  settings.starting_area = "none"
  settings.peaceful_mode = true
  settings.cliff_settings = {cliff_elevation_0 = 0, cliff_elevation_interval = 0, name = "cliff"}
  game.create_surface(nf_surface_name, settings)
end
log ('hidden map is created')
local nf_surface = game.surfaces[nf_surface_name]
for chunk in surface.get_chunks() do
  if not nf_surface.is_chunk_generated({x=chunk.x, y=chunk.y}) then
    nf_surface.request_to_generate_chunks({x=chunk.x*32, y=chunk.y*32}, 0)
  end
  nf_surface.force_generate_chunk_requests()
  local tiles = {}
  for x = (chunk.x*32), (chunk.x*32+31) do
    for y = (chunk.y*32), (chunk.y*32+31) do
      local tile = surface.get_tile(x, y)
      if tile.collides_with("ground-tile") then
        local nf_tile = nf_surface.get_tile(x, y)
        table.insert (tiles, {name=nf_tile.name, position = {x=x,y=y}})
      end
    end
  end
  surface.set_tiles(tiles)
  nf_surface.delete_chunk({x=chunk.x*32, y=chunk.y*32})
end
log ('complete')
That's a nice way to update old saves to new map generator.
Would be even nicer though if you added a check so it doesn't remove all concrete.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 8:47 pm
by Dixi
Optera wrote:
Mon Dec 31, 2018 8:34 pm
Would be even nicer though if you added a check so it doesn't remove all concrete.
I think concrete is located in same layer as decorative foliage. And listed above code does not work with it - it only replace old tiles with new, according to changed map generator. So it's mostly cosmetic change.

Re: Regenerate map under existing factory, any ideas?

Posted: Mon Dec 31, 2018 9:22 pm
by darkfrei
Dixi wrote:
Mon Dec 31, 2018 8:47 pm
Optera wrote:
Mon Dec 31, 2018 8:34 pm
Would be even nicer though if you added a check so it doesn't remove all concrete.
I think concrete is located in same layer as decorative foliage. And listed above code does not work with it - it only replace old tiles with new, according to changed map generator. So it's mostly cosmetic change.
We have also hidden tiles under concrete, that must be replaced, but not the concrete, refined concrete, hazard concrete left and right, refined hazard concrete left and right. And stone path.

Re: Regenerate map under existing factory, any ideas?

Posted: Tue Jan 01, 2019 6:29 am
by Optera
Yes, and those hidden tiles must not be replaced with water, otherwise you get destroyed buildings or instant deaths when mining or replacing the concrete.
You can get that effect by using the creative modes magic wand to paint concrete over water.

PS:
You might also want to call game.player.force.clear_chart() afterwards so the map is forced to update.

Re: Regenerate map under existing factory, any ideas?

Posted: Wed Jan 02, 2019 12:11 am
by darkfrei
Optera wrote:
Tue Jan 01, 2019 6:29 am
Yes, and those hidden tiles must not be replaced with water, otherwise you get destroyed buildings or instant deaths when mining or replacing the concrete.
You can get that effect by using the creative modes magic wand to paint concrete over water.

PS:
You might also want to call game.player.force.clear_chart() afterwards so the map is forced to update.
Thanks! Hidden surface has no water, water by 'nauvis' will be not overwritten.

The clear_chart must help with memory leak. Maybe unchart_chunk(position, surface) https://lua-api.factorio.com/latest/Lua ... hart_chunk