Re: Regenerate map under existing factory, any ideas?
Posted: Wed Jan 02, 2019 7:05 am
				
				I haven't noticed memory leaks.
Running game.player.force.clear_chart() afterwards forces the game to forget all map data so the map view looks nice after the surface update.
Another improvement would be to call game.delete_surface(nf_surface_name) once the script is done to reduce save game bloat from additional surfaces.
Deleting the whole surface at the end you might save some performance by omitting delete_chunk in the loop. Depends on how delete_surface and delete_chunk operate though. From my limited testing it seems faster to leave generated chunks and delete the complete surface as last step.
Here's the script preserving concrete while updating the surface beneath.
I turned it into a tiny mod automatically running the update as migration script for testing.
			Running game.player.force.clear_chart() afterwards forces the game to forget all map data so the map view looks nice after the surface update.
Another improvement would be to call game.delete_surface(nf_surface_name) once the script is done to reduce save game bloat from additional surfaces.
Deleting the whole surface at the end you might save some performance by omitting delete_chunk in the loop. Depends on how delete_surface and delete_chunk operate though. From my limited testing it seems faster to leave generated chunks and delete the complete surface as last step.
Here's the script preserving concrete while updating the surface beneath.
Code: Select all
local surface = game.surfaces["nauvis"]
if surface then 
  log ("creating temporary 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 ("updating tiles on surface "..surface.name)
  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 = {}
    local floor_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}})
          local tile_prototype = tile.prototype
          if tile_prototype and tile_prototype.layer >= 60 then -- player placed floors are layer 60 upwards            
            table.insert (floor_tiles, {name=tile.name, position = {x=x,y=y}})
          end
        end
      end
    end
    -- setting nf_surface tiles before covering the floor ensures mining concrete reveals the correct surface
    surface.set_tiles(tiles)
    surface.set_tiles(floor_tiles)  
    -- nf_surface.delete_chunk({x=chunk.x*32, y=chunk.y*32})
  end
  log ("cleaning up")
  game.delete_surface(nf_surface_name)
  for _,force in pairs(game.forces) do
    force.clear_chart()
  end
  log ("complete")
end