So I tweaked regeneration to not break my buildings with water, feel free to use it in the mod if you decide so.
Code: Select all
local function rebuild_nauvis()
local nauvis_name = "nauvis"
local nauvis_copy_name = "nauvis-copy"
local chunksize = 32
if not game.surfaces[nauvis_copy_name] then
game.create_surface(nauvis_copy_name)
end
local nauvis = game.surfaces[nauvis_name]
local nauvis_copy = game.surfaces[nauvis_copy_name]
local function chunk_key(x,y) return x*1000000000 + y end
local chunks = {}
for chunk in nauvis.get_chunks() do
chunks[chunk_key(chunk.x,chunk.y)] = chunk
end
local deleted_chunks = { }
-- make the new chunks
for _, chunk in pairs(chunks) do
local count = 0
count = nauvis.count_entities_filtered{
area = {{chunk.x * 32 - 12, chunk.y * 32 - 12}, {chunk.x * 32 + 32 + 12, chunk.y * 32 + 32 + 12}},
force = game.forces["player"],
limit = 1
}
if count > 0 then
-- there are forces here so copy tiles
nauvis_copy.request_to_generate_chunks({x = chunk.x * chunksize, y = chunk.y * chunksize}, 0)
else
-- no forces, just delete and remake
nauvis.delete_chunk(chunk)
chunks[_] = nil
deleted_chunks[_] = chunk
end
end
nauvis_copy.force_generate_chunk_requests()
-- copy tiles from generated copy to main
local water_tiles = {["water-green"] = true,["deepwater-green"] = true,["water"] = true,["deepwater"] = true}
local tiles = {}
for _, chunk in pairs(chunks) do
for y = 0, 31, 1 do
for x = 0, 31, 1 do
local position = {
x = chunk.x * chunksize + x,
y = chunk.y * chunksize + y
}
local tile_name = nauvis_copy.get_tile(position.x, position.y).name
local copy = true
if (water_tiles[tile_name]) then -- don't copy water over entities
local count = 0
count = nauvis.count_entities_filtered{
area = {{x - math.random(7,9), y - math.random(7,9)}, {x + math.random(7,9), y + math.random(7,9)}},
force = game.forces["player"],
limit = 1
}
if count > 0 then
--tile_name = "mineral-tan-dirt-1"
tile_name = nil
end
end
if tile_name then table.insert(tiles, {name = tile_name, position = position}) end
end
end
end
nauvis.set_tiles(tiles, true)
-- nauvis.regenerate_decorative() -- does not work properly, everything is at highest density
game.delete_surface(nauvis_copy)
-- done, now smooth border tiles
local step = 0 --doesn't work until next tick?
local function continue(event)
if step >= 10 then return end
step = step + 1
if step == 5 then
--only chunks with living neighbours participiate
for _, chunk in pairs(deleted_chunks) do
if not chunks[chunk_key(chunk.x-1,chunk.y)]
and not chunks[chunk_key(chunk.x+1,chunk.y)]
and not chunks[chunk_key(chunk.x,chunk.y-1)]
and not chunks[chunk_key(chunk.x,chunk.y+1)]
and not chunks[chunk_key(chunk.x-1,chunk.y-1)]
and not chunks[chunk_key(chunk.x+1,chunk.y+1)]
then
deleted_chunks[_] = nil
else -- generate them so can edit
nauvis.request_to_generate_chunks({x = chunk.x * chunksize+1, y = chunk.y * chunksize+1}, 0)
end
end
nauvis.force_generate_chunk_requests()
return
end
if step ~= 10 then return end
-- copy border tiles from living neighbours over generated water tiles
local tiles = {}
for _, chunk in pairs(deleted_chunks) do
log("Processing deleted chunk " .. chunk.x .. "," .. chunk.y ..", generated:" .. tostring(nauvis.is_chunk_generated({chunk.x,chunk.y})))
for v = 1, 6, 1 do -- 6 neighbours
local cx
local cy
local min = 0
local max = 31
if v == 1 then
cx = chunk.x
cy = chunk.y - 1
elseif v == 2 then
cx = chunk.x
cy = chunk.y + 1
elseif v == 3 then
cx = chunk.x - 1
cy = chunk.y
elseif v == 4 then
cx = chunk.x + 1
cy = chunk.y
elseif v == 5 then
cx = chunk.x - 1
cy = chunk.y - 1
min = 1
max = 1
elseif v == 6 then
cx = chunk.x + 1
cy = chunk.y + 1
min = 1
max = 1
end
local chunkFromPos = {x = cx, y = cy}
-- if there it's a living neightbour
if (nauvis.is_chunk_generated(chunkFromPos)) and chunks[chunk_key(chunkFromPos.x, chunkFromPos.y)] then
for m = min, max, 1 do
local count = math.random(0,3)
if count~=0 then
local position = { x = chunk.x * chunksize, y = chunk.y * chunksize }
local ox = 0
local oy = 0
if v == 1 then
position.x = position.x + m
position.y = position.y + 0
oy = -1
elseif v == 2 then
position.x = position.x + m
position.y = position.y + chunksize - 1
oy = 1
elseif v == 3 then
position.x = position.x + 0
position.y = position.y + m
ox = -1
elseif v == 4 then
position.x = position.x + chunksize - 1
position.y = position.y + m
ox = 1
elseif v == 5 then
position.x = position.x
position.y = position.y
ox = -1
oy = -1
elseif v == 6 then
position.x = position.x + chunksize - 1
position.y = position.y + chunksize - 1
ox = 1
oy = 1
end
local position_from = { x = position.x + ox, y = position.y + oy }
for c = 0,count-1,1 do
local dest = { x = position.x - ox * c, y = position.y - oy * c}
local current_name = nauvis.get_tile(dest.x, dest.y).name
if water_tiles[current_name] then
local new_name = nauvis.get_tile(position_from.x, position_from.y).name
if not water_tiles[new_name] then
log("Copying tile from " .. serpent.block(position_from) .. " " .. new_name .." to " .. serpent.block(dest) .. " " .. current_name)
table.insert(tiles, {name = new_name, position = dest})
end
end
end
end
end
end
end
end
nauvis.set_tiles(tiles, true)
game.print("Nauvis Regeneration Complete")
end
script.on_event(defines.events.on_tick, continue)
end
And also I used this code to increase water:
Code: Select all
local global_bias = 5 -- elevation level
local segmentation_devider = 1.1
local noise = require("noise")
local tne = noise.to_noise_expression
local function make_basis_noise_function(seed0,seed1,outscale0,inscale0)
outscale0 = outscale0 or 1
inscale0 = inscale0 or 1/outscale0
return function(x,y,inscale,outscale)
return tne{
type = "function-application",
function_name = "factorio-basis-noise",
arguments = {
x = tne(x),
y = tne(y),
seed0 = tne(seed0),
seed1 = tne(seed1),
input_scale = tne((inscale or 1) * inscale0),
output_scale = tne((outscale or 1) * outscale0)
}
}
end
end
-- Returns a multioctave noise function where each octave's noise is multiplied by some other noise
-- by default 'some other noise' is the basis noise at 17x lower frequency,
-- normalized around 0.5 and clamped between 0 and 1
local function make_multioctave_modulated_noise_function(params)
local seed0 = params.seed0 or 1
local seed1 = params.seed1 or 1
local octave_count = params.octave_count or 1
local octave0_output_scale = params.octave0_output_scale or 1
local octave0_input_scale = params.octave0_input_scale or 1
local octave_output_scale_multiplier = params.octave_output_scale_multiplier or 2
local octave_input_scale_multiplier = params.octave_input_scale_multiplier or 1/2
local basis_noise_function = params.basis_noise_function or make_basis_noise_function(seed0, seed1)
local modulation_noise_function = params.modulation_noise_function or function(x,y)
return noise.clamp(basis_noise_function(x,y)+0.5, 0, 1)
end
-- input scale of modulation relative to each octave's base input scale
local mris = params.modulation_relative_input_scale or 1/17
return function(x,y)
local outscale = octave0_output_scale
local inscale = octave0_input_scale
local result = 0
for i=1,octave_count do
local noise = basis_noise_function(x*inscale, y*inscale)
local modulation = modulation_noise_function(x*(inscale*mris), y*(inscale*mris))
result = result + (outscale * noise * modulation)
outscale = outscale * octave_output_scale_multiplier
inscale = inscale * octave_input_scale_multiplier
end
return result
end
end
local function make_multioctave_noise_function(seed0,seed1,octaves,octave_output_scale_multiplier,octave_input_scale_multiplier,output_scale0,input_scale0)
octave_output_scale_multiplier = octave_output_scale_multiplier or 2
octave_input_scale_multiplier = octave_input_scale_multiplier or 1 / octave_output_scale_multiplier
return function(x,y,inscale,outscale)
return tne{
type = "function-application",
function_name = "factorio-multioctave-noise",
arguments = {
x = tne(x),
y = tne(y),
seed0 = tne(seed0),
seed1 = tne(seed1),
input_scale = tne((inscale or 1) * (input_scale0 or 1)),
output_scale = tne((outscale or 1) * (output_scale0 or 1)),
octaves = tne(octaves),
octave_output_scale_multiplier = tne(octave_output_scale_multiplier),
octave_input_scale_multiplier = tne(octave_input_scale_multiplier),
}
}
end
end
local function make_split_multioctave_noise_function(seed0,seed1,octaveses,octave_output_scale_multiplier,octave_input_scale_multiplier,output_scale0,input_scale0)
output_scale0 = output_scale0 or 1
input_scale0 = input_scale0 or 1
octave_output_scale_multiplier = octave_output_scale_multiplier or 1
octave_input_scale_multiplier = octave_input_scale_multiplier or 1
local funx = {}
for i=1,#octaveses do
funx[i] = make_multioctave_noise_function(seed0,seed1,octaveses[i],octave_output_scale_multiplier,octave_input_scale_multiplier,output_scale0,input_scale0)
output_scale0 = output_scale0 * octave_output_scale_multiplier ^ octaveses[i]
input_scale0 = input_scale0 * octave_input_scale_multiplier ^ octaveses[i]
end
return funx
end
data:extend({
{
type = "noise-expression",
name = "default-elevation",
expression = noise.define_noise_function( function(x,y,tile,map)
local plateau_octaves = 3
local lf_octaves = 6
local seg = map.segmentation_multiplier / segmentation_devider
x = x * seg + 10000 -- Move the point where 'fractal similarity' is obvious off into the boonies
y = y * seg
local rdi = tile.tier / 8 -- ridge distance-based influcence
local high_ridge = 16 + rdi + noise.clamp(rdi, 0, 2) * make_multioctave_noise_function(map.seed, 7, 2, 3)(x,y,1/256,1)
local low_ridge = -16 - rdi
local plateau_noise = make_multioctave_noise_function(map.seed, 9, plateau_octaves, 1/3, 3, 4, 1/128)
local plateaus = noise.max(make_basis_noise_function(map.seed, 10, 8, 1/1024)(x,y) - 8, 3 - tile.tier)
local high_freq_noise = make_multioctave_modulated_noise_function{
seed0 = map.seed,
seed1 = 11,
octave_count = 6,
octave0_output_scale = 1/8,
octave0_input_scale = 1/4,
octave_output_scale_multiplier = 2,
octave_input_scale_multiplier = 1/3,
}
local low_freq_noise = make_multioctave_modulated_noise_function{
seed0 = map.seed,
seed1 = 8,
octave_count = lf_octaves,
octave0_output_scale = 1,
octave0_input_scale = 1/8,
}
local very_low_freq_noise = make_basis_noise_function(map.seed, 9, 20, 1/1024)
local basis = low_freq_noise(x,y) + very_low_freq_noise(x,y)
local ridged1 = noise.ridge(basis, low_ridge, high_ridge)
local normal = noise.max(ridged1 + high_freq_noise(x,y), plateaus + plateau_noise(x,y)) + global_bias
-- Multily elevation by low-frequency noise to make hilly and non-hilly areas
local hill_modulation = noise.clamp(make_multioctave_noise_function(map.seed, 12, 4, 2, 1/3)(x,y,1/256,3/4) - 2, 0.1, 1.0)
-- Elevation below which hill modulation has no effect.
-- Set to slightly above the water level so that flat plains don't all become a giant beach/sandbar thing.
-- To do its job it just has to be lower than the first row of cliffs.
local hill_modulation_identity = map.finite_water_level + 3
return noise.min(normal, hill_modulation * (normal - hill_modulation_identity) + hill_modulation_identity)
end)
}
})