Landfill undo

./lua/landfill undo.lua
--[[
  Truly undoes landfill. Regenerates the original chunks in a separate surface to see which water/
  shore tiles used to be under the landfill, copies from those tiles, and cleans up afterwards.

  Ends in an unterminated quote, intended to contain map pings.
  Will select a box region around all pings.
  Any number of pings 2+ will work, but it's most intuitive to ping 2 opposing corners, or 4 sides.
  Insert pings into the command line, and then a closing quote " before using.
--]]

/silent-command --[[ undo landfill 2.0 ]]
local function bounding_box_from_gps_tags(s)
  local a,b,c,d,m,M=1/0,1/0,-1/0,-1/0,math.min,math.max
  for x,y in s:gmatch("%[gps=([+-]?[%d%.]+),([+-]?[%d%.]+)%]")do a=m(a,x+0)b=m(b,y+0)c=M(c,x+0)d=M(d,y+0)end
  return{left_top={x=a,y=b},right_bottom={x=c,y=d}}
end
local function count_in(t, s)
  t[s] = (t[s] or 0) + 1
end
local function go2(gps)
  local surface = game.player.surface
  local s2 = game.create_surface("undo_landfill", surface.map_gen_settings)
  local bb = bounding_box_from_gps_tags(gps)
  local new_water,counts = {},{}
  for _,t in pairs(surface.find_tiles_filtered{area=bb, name="landfill"}) do
    local pos = t.position
    if surface.count_entities_filtered{collision_mask={"ghost-layer","object-layer","player-layer","rail-layer"}, area={left_top=pos, right_bottom={pos.x+1,pos.y+1}}} > 0 then
      count_in(counts, "skipped")
    else
      new_water[#new_water+1] = { position=pos, name="" }
      s2.request_to_generate_chunks(pos, 0)
    end
  end
  s2.force_generate_chunk_requests()
  for _,nw in pairs(new_water) do
    nw.name = s2.get_tile(nw.position.x, nw.position.y).name
    count_in(counts, nw.name)
  end
  surface.set_tiles(new_water)
  game.player.print("undo landfill:")
  for name,count in pairs(counts) do
    game.player.print("    "..name..": "..count)
  end
end
local function go(...)
  local ok, result = pcall(go2, ...)
  if not ok then game.player.print(result) end
  if game.get_surface("undo_landfill") then game.delete_surface("undo_landfill") end
end
go "