mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2025-07-04 01:10:39 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
77b05f044a | |||
b406bebb7b | |||
dcc71225ae | |||
c8b96e2836 | |||
6017510df0 | |||
70418f9526 | |||
0e3c83e1d2 | |||
a91a13bbec | |||
146f009684 | |||
2cf3b19167 | |||
4697f9c948 | |||
ed832a0806 |
114
gridio.lua
114
gridio.lua
@ -1,114 +0,0 @@
|
||||
-- Input and output functions for grid maps
|
||||
|
||||
local worldpath = mapgen_rivers.world_data_path
|
||||
|
||||
local floor = math.floor
|
||||
local sbyte, schar = string.byte, string.char
|
||||
local unpk = unpack
|
||||
|
||||
-- Loading files
|
||||
local function load_full_map(filename, bytes, signed, size, converter)
|
||||
local file = io.open(worldpath .. filename, 'rb')
|
||||
local data = file:read('*all')
|
||||
if #data < bytes*size then
|
||||
data = minetest.decompress(data)
|
||||
end
|
||||
|
||||
local map = {}
|
||||
|
||||
for i=1, size do
|
||||
local i0 = (i-1)*bytes+1
|
||||
local elements = {data:byte(i0, i1)}
|
||||
local n = sbyte(data, i0)
|
||||
if signed and n >= 128 then
|
||||
n = n - 256
|
||||
end
|
||||
|
||||
for j=1, bytes-1 do
|
||||
n = n*256 + sbyte(data, i0+j)
|
||||
end
|
||||
|
||||
map[i] = n
|
||||
end
|
||||
file:close()
|
||||
|
||||
if converter then
|
||||
for i=1, size do
|
||||
map[i] = converter(map[i])
|
||||
end
|
||||
end
|
||||
|
||||
return map
|
||||
end
|
||||
|
||||
local loader_mt = {
|
||||
__index = function(loader, i)
|
||||
local file = loader.file
|
||||
local bytes = loader.bytes
|
||||
file:seek('set', (i-1)*bytes)
|
||||
local strnum = file:read(bytes)
|
||||
|
||||
local n = sbyte(strnum, 1)
|
||||
if loader.signed and n >= 128 then
|
||||
n = n - 256
|
||||
end
|
||||
|
||||
for j=2, bytes do
|
||||
n = n*256 + sbyte(strnum, j)
|
||||
end
|
||||
|
||||
if loader.conv then
|
||||
n = loader.conv(n)
|
||||
end
|
||||
loader[i] = n
|
||||
return n
|
||||
end,
|
||||
}
|
||||
|
||||
local function interactive_loader(filename, bytes, signed, size, converter)
|
||||
local file = io.open(worldpath .. filename, 'rb')
|
||||
if file then
|
||||
converter = converter or false
|
||||
return setmetatable({file=file, bytes=bytes, signed=signed, size=size, conv=converter}, loader_mt)
|
||||
end
|
||||
end
|
||||
|
||||
local load_methods = {
|
||||
full = load_full_map,
|
||||
interactive = interactive_loader,
|
||||
}
|
||||
|
||||
function mapgen_rivers.load_file(...)
|
||||
local load_method = mapgen_rivers.settings.load_method
|
||||
local load_func = load_methods[load_method]
|
||||
if load_func then
|
||||
return load_func(...)
|
||||
else
|
||||
minetest.log("error", ("[mapgen_rivers] Unknown load method %s"):format(load_method))
|
||||
end
|
||||
end
|
||||
|
||||
-- Writing files
|
||||
function mapgen_rivers.write_file(filename, data, bytes)
|
||||
local size = #data
|
||||
local file = io.open(worldpath .. filename, 'wb')
|
||||
|
||||
local bytelist = {}
|
||||
for j=1, bytes do
|
||||
bytelist[j] = 0
|
||||
end
|
||||
|
||||
for i=1, size do
|
||||
local n = floor(data[i])
|
||||
data[i] = n
|
||||
for j=bytes, 2, -1 do
|
||||
bytelist[j] = n % 256
|
||||
n = floor(n / 256)
|
||||
end
|
||||
bytelist[1] = n % 256
|
||||
|
||||
file:write(schar(unpk(bytelist)))
|
||||
end
|
||||
|
||||
file:close()
|
||||
end
|
155
gridmanager.lua
155
gridmanager.lua
@ -1,6 +1,6 @@
|
||||
-- Manages grid loading, writing and generation
|
||||
|
||||
local world_data = mapgen_rivers.world_data_path
|
||||
local datapath = mapgen_rivers.world_data_path
|
||||
|
||||
local registered_on_grid_loaded = {}
|
||||
function mapgen_rivers.register_on_grid_loaded(func)
|
||||
@ -21,128 +21,85 @@ local function offset_conv(o)
|
||||
return (o + 0.5) * (1/256)
|
||||
end
|
||||
|
||||
local grid_maps_list = {
|
||||
dem = {bytes=2, signed=true},
|
||||
lakes = {bytes=2, signed=true},
|
||||
dirs = {bytes=1, signed=false},
|
||||
rivers = {bytes=4, signed=false},
|
||||
local floor = math.floor
|
||||
local sbyte, schar = string.byte, string.char
|
||||
local unpk = unpack
|
||||
|
||||
offset_x = {bytes=1, signed=true, conv=offset_conv},
|
||||
offset_y = {bytes=1, signed=true, conv=offset_conv},
|
||||
-- Loading files
|
||||
|
||||
-- Never load the full map during mapgen. Instead, create an empty lookup table
|
||||
-- and read the file on-the-fly when an element is requested for the first time,
|
||||
-- using __index metamethod.
|
||||
local loader_mt = {
|
||||
__index = function(loader, i) -- Called when accessing a missing key
|
||||
local file = loader.file
|
||||
local bytes = loader.bytes
|
||||
file:seek('set', (i-1)*bytes)
|
||||
local strnum = file:read(bytes)
|
||||
|
||||
local n = sbyte(strnum, 1)
|
||||
if loader.signed and n >= 128 then
|
||||
n = n - 256
|
||||
end
|
||||
|
||||
for j=2, bytes do
|
||||
n = n*256 + sbyte(strnum, j)
|
||||
end
|
||||
|
||||
if loader.conv then
|
||||
n = loader.conv(n)
|
||||
end
|
||||
-- Cache key for next use
|
||||
loader[i] = n
|
||||
return n
|
||||
end,
|
||||
}
|
||||
|
||||
local function apply_grid_conversion(grid)
|
||||
if grid.load_method ~= "full" then
|
||||
minetest.log("warning", ("Could not apply data conversion for load method %s"):format(grid.load_method))
|
||||
return false
|
||||
local function load_file(filename, bytes, signed, size, converter)
|
||||
local file = io.open(datapath .. filename, 'rb')
|
||||
if file then
|
||||
converter = converter or false
|
||||
return setmetatable({file=file, bytes=bytes, signed=signed, size=size, conv=converter}, loader_mt)
|
||||
end
|
||||
if grid.conv_applied then
|
||||
return true
|
||||
end
|
||||
|
||||
local size = grid.size.x * grid.size.y
|
||||
for mapname, params in pairs(grid_maps_list) do
|
||||
local conv = params.conv
|
||||
if conv then
|
||||
local map = grid[mapname]
|
||||
for i=1, size do
|
||||
map[i] = conv(map[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
grid.conv_applied = true
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function mapgen_rivers.try_load_grid(grid)
|
||||
local load_method = mapgen_rivers.settings.load_method
|
||||
|
||||
-- First, check whether a grid is already loaded with the appropriate method
|
||||
if mapgen_rivers.grid and mapgen_rivers.grid.load_method == load_method then
|
||||
if not mapgen_rivers.grid.conv_applied then
|
||||
apply_grid_conversion(mapgen_rivers.grid)
|
||||
end
|
||||
return true
|
||||
-- Then, check the provided argument is a valid grid
|
||||
elseif grid and grid.load_method == load_method then
|
||||
if not mapgen_rivers.grid.conv_applied then
|
||||
apply_grid_conversion(grid)
|
||||
end
|
||||
mapgen_rivers.grid = grid
|
||||
on_grid_loaded_callback(grid)
|
||||
function mapgen_rivers.load_or_generate_grid()
|
||||
-- First, check whether a grid is already loaded
|
||||
if mapgen_rivers.grid then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Fall back to loading the grid from the files
|
||||
local sfile = io.open(world_data .. 'size', 'r')
|
||||
-- If not, try to load the grid from the files
|
||||
local sfile = io.open(datapath .. 'size', 'r')
|
||||
if not sfile then
|
||||
dofile(mapgen_rivers.modpath .. "/pregenerate.lua")
|
||||
collectgarbage()
|
||||
|
||||
sfile = io.open(datapath .. 'size', 'r')
|
||||
if not sfile then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local x, z = sfile:read('*n'), sfile:read('*n')
|
||||
if not x or not z then
|
||||
return false
|
||||
end
|
||||
|
||||
if load_method == "full" then
|
||||
minetest.log("action", '[mapgen_rivers] Loading full grid')
|
||||
elseif load_method == "interactive" then
|
||||
minetest.log("action", '[mapgen_rivers] Loading grid as interactive loaders')
|
||||
end
|
||||
minetest.log("action", '[mapgen_rivers] Loading grid')
|
||||
|
||||
grid = {
|
||||
load_method = load_method,
|
||||
local grid = {
|
||||
size = {x=x, y=z},
|
||||
dem = load_file('dem', 2, true, x*z),
|
||||
lakes = load_file('lakes', 2, true, x*z),
|
||||
dirs = load_file('dirs', 1, false, x*z),
|
||||
rivers = load_file('rivers', 4, false, x*z),
|
||||
offset_x = load_file('offset_x', 1, true, x*z, offset_conv),
|
||||
offset_y = load_file('offset_y', 1, true, x*z, offset_conv),
|
||||
}
|
||||
|
||||
for map, params in pairs(grid_maps_list) do
|
||||
grid[map] = mapgen_rivers.load_file(map, params.bytes, params.signed, x*z, params.conv)
|
||||
end
|
||||
grid.conv_applied = true
|
||||
|
||||
mapgen_rivers.grid = grid
|
||||
on_grid_loaded_callback(grid)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function mapgen_rivers.generate_grid()
|
||||
minetest.log("action", '[mapgen_rivers] Generating grid, this may take a while...')
|
||||
local grid = {}
|
||||
|
||||
local blocksize = mapgen_rivers.settings.blocksize
|
||||
local xsize = math.floor(mapgen_rivers.settings.map_x_size / blocksize)
|
||||
local zsize = math.floor(mapgen_rivers.settings.map_z_size / blocksize)
|
||||
grid.size = {x=xsize, y=zsize}
|
||||
grid.conv_applied = false
|
||||
|
||||
if not mapgen_rivers.pregenerate then
|
||||
minetest.log("error", "[mapgen_rivers] Pre-generation function is not available.")
|
||||
return false
|
||||
end
|
||||
|
||||
mapgen_rivers.pregenerate(grid)
|
||||
|
||||
return grid
|
||||
end
|
||||
|
||||
function mapgen_rivers.write_grid(grid)
|
||||
minetest.mkdir(world_data)
|
||||
|
||||
if grid.conv_applied then
|
||||
minetest.log("error", '[mapgen_rivers] Could not write grid if data conversion is already done')
|
||||
return false
|
||||
end
|
||||
|
||||
for map, params in pairs(grid_maps_list) do
|
||||
mapgen_rivers.write_file(map, grid[map], params.bytes)
|
||||
end
|
||||
|
||||
local sfile = io.open(world_data .. 'size', "w")
|
||||
sfile:write(grid.size.x..'\n'..grid.size.y)
|
||||
sfile:close()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
14
init.lua
14
init.lua
@ -8,19 +8,9 @@ mapgen_rivers.world_data_path = minetest.get_worldpath() .. '/river_data/'
|
||||
|
||||
dofile(modpath .. 'settings.lua')
|
||||
dofile(modpath .. 'gridmanager.lua')
|
||||
dofile(modpath .. 'gridio.lua')
|
||||
dofile(modpath .. 'polygons.lua')
|
||||
dofile(modpath .. 'heightmap.lua')
|
||||
dofile(modpath .. 'mapgen.lua')
|
||||
dofile(modpath .. 'spawn.lua')
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
local exist = mapgen_rivers.try_load_grid()
|
||||
|
||||
if not exist then -- If grid does not exist yet, generate it
|
||||
dofile(modpath .. 'pregenerate.lua')
|
||||
|
||||
local grid = mapgen_rivers.generate_grid()
|
||||
mapgen_rivers.write_grid(grid)
|
||||
mapgen_rivers.try_load_grid(grid) -- Reload if needed
|
||||
end
|
||||
end)
|
||||
minetest.register_on_mods_loaded(mapgen_rivers.load_or_generate_grid)
|
||||
|
64
mapgen.lua
64
mapgen.lua
@ -28,12 +28,13 @@ local floor, min = math.floor, math.min
|
||||
|
||||
local data = {}
|
||||
|
||||
local noise_x_obj, noise_z_obj, noise_distort_obj, noise_heat_obj, noise_heat_blend_obj
|
||||
local noise_x_obj, noise_z_obj, noise_distort_obj, noise_heat_obj, noise_heat_blend_obj, noise_cave_obj
|
||||
local noise_x_map = {}
|
||||
local noise_z_map = {}
|
||||
local noise_distort_map = {}
|
||||
local noise_heat_map = {}
|
||||
local noise_heat_blend_map = {}
|
||||
local noise_cave = {}
|
||||
local mapsize
|
||||
local init = false
|
||||
|
||||
@ -41,6 +42,18 @@ local sumtime = 0
|
||||
local sumtime2 = 0
|
||||
local ngen = 0
|
||||
|
||||
local use_caves = true
|
||||
local np_cave = {
|
||||
offset = 0,
|
||||
scale = 8,
|
||||
spread = {x=256, y=128, z=256},
|
||||
seed = -9152,
|
||||
octaves = 4,
|
||||
persist = 0.65,
|
||||
lacunarity = 2,
|
||||
flags = "absvalue",
|
||||
}
|
||||
|
||||
function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
minetest.log("info", ("[mapgen_rivers] Generating from %s to %s"):format(minetest.pos_to_string(minp), minetest.pos_to_string(maxp)))
|
||||
|
||||
@ -65,6 +78,9 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
noise_heat_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.heat, chulens)
|
||||
noise_heat_blend_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.heat_blend, chulens)
|
||||
end
|
||||
if use_caves then
|
||||
noise_cave_obj = minetest.get_perlin_map(np_cave, mapsize)
|
||||
end
|
||||
init = true
|
||||
end
|
||||
|
||||
@ -79,7 +95,9 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
noise_heat_obj:get_2d_map_flat(minp2d, noise_heat_map)
|
||||
noise_heat_blend_obj:get_2d_map_flat(minp2d, noise_heat_blend_map)
|
||||
end
|
||||
|
||||
if use_caves then
|
||||
noise_cave_obj:get_3d_map_flat(minp, noise_cave)
|
||||
end
|
||||
local terrain_map, lake_map, incr, i_origin
|
||||
|
||||
if use_distort then
|
||||
@ -103,6 +121,7 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
end
|
||||
i2d = i2d-chulens.x
|
||||
end
|
||||
i2d = i2d+chulens.x
|
||||
end
|
||||
|
||||
local pminp = {x=floor(xmin), z=floor(zmin)}
|
||||
@ -127,6 +146,10 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
|
||||
-- If not, skip chunk
|
||||
if is_empty then
|
||||
if use_biomegen_mod and biomegen.skip_chunk then
|
||||
biomegen.skip_chunk(minp, maxp)
|
||||
end
|
||||
|
||||
local t = os.clock() - t0
|
||||
ngen = ngen + 1
|
||||
sumtime = sumtime + t
|
||||
@ -141,6 +164,7 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
local c_stone = minetest.get_content_id("mapgen_stone")
|
||||
local c_water = minetest.get_content_id("mapgen_water_source")
|
||||
local c_rwater = minetest.get_content_id("mapgen_river_water_source")
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
local c_dirt, c_lawn, c_dirtsnow, c_snow, c_sand, c_ice
|
||||
if use_biomes then
|
||||
@ -173,7 +197,7 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
if use_biomes then
|
||||
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
|
||||
end
|
||||
local terrain, lake
|
||||
local terrain, lake, caveness
|
||||
if not use_distort then
|
||||
terrain = terrain_map[i2d]
|
||||
lake = lake_map[i2d]
|
||||
@ -195,6 +219,10 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
lake = min(lake_map[i0], lake_map[i1], lake_map[i2], lake_map[i3])
|
||||
end
|
||||
|
||||
if use_caves then
|
||||
noise_cave[nid] = noise_cave[nid] < math.min(math.max(terrain - y, 0), 100) ^ 0.5 / 10
|
||||
end
|
||||
|
||||
if y <= maxp.y then
|
||||
|
||||
local is_lake = lake > terrain
|
||||
@ -244,10 +272,32 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
end
|
||||
|
||||
if use_biomegen_mod then
|
||||
biomegen.generate_all(data, a, vm, minp, maxp, seed)
|
||||
else
|
||||
biomegen.generate_biomes(data, a, minp, maxp)
|
||||
end
|
||||
if use_caves then
|
||||
local i = 1
|
||||
for z=minp.z, maxp.z do
|
||||
for y=minp.y, maxp.y do
|
||||
local vi = a:index(minp.x, y, z)
|
||||
for x=minp.x, maxp.x do
|
||||
if noise_cave[i] then
|
||||
data[vi] = c_air
|
||||
end
|
||||
i = i + 1
|
||||
vi = vi + 1
|
||||
end
|
||||
end
|
||||
i = i + chulens.x -- Skip etra row
|
||||
end
|
||||
end
|
||||
vm:set_data(data)
|
||||
if use_biomegen_mod then
|
||||
biomegen.place_all_decos(data, a, vm, minp, maxp, seed)
|
||||
end
|
||||
minetest.generate_ores(vm, minp, maxp)
|
||||
if use_biomegen_mod then
|
||||
vm:get_data(data)
|
||||
biomegen.dust_top_nodes(data, a, vm, minp, maxp)
|
||||
end
|
||||
|
||||
vm:set_lighting({day = 0, night = 0})
|
||||
@ -262,7 +312,9 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
||||
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
|
||||
end
|
||||
|
||||
minetest.register_on_generated(mapgen_rivers.make_chunk)
|
||||
-- Enforce first position in mapgen callbacks
|
||||
table.insert(minetest.registered_on_generateds, 1, mapgen_rivers.make_chunk)
|
||||
--minetest.register_on_generated(mapgen_rivers.make_chunk)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
local avg = sumtime / ngen
|
||||
|
100
pregenerate.lua
100
pregenerate.lua
@ -1,6 +1,8 @@
|
||||
-- Generate the grid using terrainlib_lua
|
||||
-- Only called on first mapgen, if there is no grid yet
|
||||
|
||||
-- Constants
|
||||
|
||||
local EvolutionModel = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/erosion.lua')
|
||||
local twist = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/twist.lua')
|
||||
|
||||
@ -21,6 +23,9 @@ local use_margin = mapgen_rivers.settings.margin
|
||||
local margin_width = mapgen_rivers.settings.margin_width / blocksize
|
||||
local margin_elev = mapgen_rivers.settings.margin_elev
|
||||
|
||||
local X = math.floor(mapgen_rivers.settings.map_x_size / blocksize)
|
||||
local Y = math.floor(mapgen_rivers.settings.map_z_size / blocksize)
|
||||
|
||||
local function margin(dem, width, elev)
|
||||
local X, Y = dem.X, dem.Y
|
||||
for i=1, width do
|
||||
@ -49,33 +54,34 @@ local function margin(dem, width, elev)
|
||||
end
|
||||
end
|
||||
|
||||
function mapgen_rivers.pregenerate(grid)
|
||||
local size = grid.size
|
||||
-- Generate grid
|
||||
|
||||
if size.x * size.y > 4e6 then
|
||||
minetest.log("action", '[mapgen_rivers] Generating grid, this may take a while...')
|
||||
|
||||
if X*Y > 4e6 then
|
||||
minetest.log("warning", "[mapgen_rivers] You are going to generate a very large grid (>4M nodes). If you experience problems, you should increase blocksize or reduce map size.")
|
||||
end
|
||||
end
|
||||
|
||||
local seed = tonumber(minetest.get_mapgen_setting("seed"))
|
||||
np_base.seed = (np_base.seed or 0) + seed
|
||||
local seed = tonumber(minetest.get_mapgen_setting("seed"):sub(-10))
|
||||
np_base.seed = (np_base.seed or 0) + seed
|
||||
|
||||
local nobj_base = PerlinNoiseMap(np_base, {x=size.x, y=1, z=size.y})
|
||||
local nobj_base = PerlinNoiseMap(np_base, {x=X, y=1, z=Y})
|
||||
|
||||
local dem = nobj_base:get_3d_map_flat({x=0, y=0, z=0})
|
||||
dem.X = size.x
|
||||
dem.Y = size.y
|
||||
local dem = nobj_base:get_3d_map_flat({x=0, y=0, z=0})
|
||||
dem.X = X
|
||||
dem.Y = Y
|
||||
|
||||
if use_margin then
|
||||
if use_margin then
|
||||
margin(dem, margin_width, margin_elev)
|
||||
end
|
||||
end
|
||||
|
||||
local model = EvolutionModel(evol_params)
|
||||
model.dem = dem
|
||||
local ref_dem = model:define_isostasy(dem)
|
||||
local model = EvolutionModel(evol_params)
|
||||
model.dem = dem
|
||||
local ref_dem = model:define_isostasy(dem)
|
||||
|
||||
local tectonic_step = tectonic_speed * time_step
|
||||
collectgarbage()
|
||||
for i=1, niter do
|
||||
local tectonic_step = tectonic_speed * time_step
|
||||
collectgarbage()
|
||||
for i=1, niter do
|
||||
minetest.log("info", "[mapgen_rivers] Iteration " .. i .. " of " .. niter)
|
||||
|
||||
model:diffuse(time_step)
|
||||
@ -92,25 +98,53 @@ function mapgen_rivers.pregenerate(grid)
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
end
|
||||
model:flow()
|
||||
end
|
||||
model:flow()
|
||||
|
||||
local mfloor = math.floor
|
||||
local mmin, mmax = math.min, math.max
|
||||
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
|
||||
for i=1, size.x*size.y do
|
||||
local mfloor = math.floor
|
||||
local mmin, mmax = math.min, math.max
|
||||
local unpk, schar = unpack, string.char
|
||||
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
|
||||
for i=1, X*Y do
|
||||
offset_x[i] = mmin(mmax(offset_x[i]*256, -128), 127)
|
||||
offset_y[i] = mmin(mmax(offset_y[i]*256, -128), 127)
|
||||
end
|
||||
|
||||
-- Write data
|
||||
|
||||
local datapath = mapgen_rivers.world_data_path
|
||||
minetest.mkdir(datapath)
|
||||
|
||||
local sfile = io.open(datapath .. 'size', "w")
|
||||
sfile:write(X..'\n'..Y)
|
||||
sfile:close()
|
||||
|
||||
local function write_file(filename, data, bytes)
|
||||
local file = io.open(datapath .. filename, 'wb')
|
||||
|
||||
local bytelist = {}
|
||||
for j=1, bytes do
|
||||
bytelist[j] = 0
|
||||
end
|
||||
|
||||
grid.dem = model.dem
|
||||
grid.lakes = model.lakes
|
||||
grid.dirs = model.dirs
|
||||
grid.rivers = model.rivers
|
||||
grid.offset_x = offset_x
|
||||
grid.offset_y = offset_y
|
||||
for i=1, #data do
|
||||
local n = mfloor(data[i])
|
||||
data[i] = n
|
||||
for j=bytes, 2, -1 do
|
||||
bytelist[j] = n % 256
|
||||
n = mfloor(n / 256)
|
||||
end
|
||||
bytelist[1] = n % 256
|
||||
|
||||
grid.load_method = "full"
|
||||
grid.conv_applied = false
|
||||
collectgarbage()
|
||||
file:write(schar(unpk(bytelist)))
|
||||
end
|
||||
|
||||
file:close()
|
||||
end
|
||||
|
||||
write_file('dem', model.dem, 2)
|
||||
write_file('lakes', model.lakes, 2)
|
||||
write_file('dirs', model.dirs, 1)
|
||||
write_file('rivers', model.rivers, 4)
|
||||
write_file('offset_x', offset_x, 1)
|
||||
write_file('offset_y', offset_y, 1)
|
||||
|
@ -109,13 +109,8 @@ mapgen_rivers.settings = {
|
||||
tectonic_speed = def_setting('tectonic_speed', 'number'),
|
||||
evol_time = def_setting('evol_time', 'number'),
|
||||
evol_time_step = def_setting('evol_time_step', 'number'),
|
||||
|
||||
load_all = mtsettings:get_bool('mapgen_rivers_load_all')
|
||||
}
|
||||
|
||||
mapgen_rivers.settings.load_method =
|
||||
mapgen_rivers.settings.load_all and "full" or "interactive"
|
||||
|
||||
mapgen_rivers.noise_params = {
|
||||
base = def_setting("np_base", "noise"),
|
||||
distort_x = def_setting("np_distort_x", "noise"),
|
||||
|
@ -25,7 +25,6 @@
|
||||
"tectonic_speed": 70,
|
||||
"evol_time": 10,
|
||||
"evol_time_step": 1,
|
||||
"load_all": false,
|
||||
|
||||
"np_base": {
|
||||
"offset": 0,
|
||||
|
@ -70,11 +70,6 @@ mapgen_rivers_glacier_widening_factor (Glacier widening factor) float 8.0 1.0 20
|
||||
# This results in mountains being more covered by snow.
|
||||
mapgen_rivers_elevation_chill (Elevation chill) float 0.25 0.0 5.0
|
||||
|
||||
# If enabled, loads all grid data in memory at init time.
|
||||
# If disabled, data will be loaded on request and cached in memory.
|
||||
# It's recommended to disable it for very large maps (> 2000 grid nodes or so)
|
||||
mapgen_rivers_load_all (Load all data in memory) bool false
|
||||
|
||||
[Landscape evolution parameters]
|
||||
|
||||
# Modelled landscape evolution time, in arbitrary units
|
||||
|
119
spawn.lua
Normal file
119
spawn.lua
Normal file
@ -0,0 +1,119 @@
|
||||
local np_distort_x = mapgen_rivers.noise_params.distort_x
|
||||
local np_distort_z = mapgen_rivers.noise_params.distort_z
|
||||
local np_distort_amplitude = mapgen_rivers.noise_params.distort_amplitude
|
||||
|
||||
local nobj_distort_x, nobj_distort_z, nobj_distort_amplitude
|
||||
|
||||
local sea_level = mapgen_rivers.settings.sea_level
|
||||
local distort = mapgen_rivers.settings.distort
|
||||
|
||||
-- Linear interpolation
|
||||
local function interp(v00, v01, v11, v10, xf, zf)
|
||||
local v0 = v01*xf + v00*(1-xf)
|
||||
local v1 = v11*xf + v10*(1-xf)
|
||||
return v1*zf + v0*(1-zf)
|
||||
end
|
||||
|
||||
local function estimate_spawn_level(pos, use_distort)
|
||||
local x, z = pos.x, pos.z
|
||||
if distort and use_distort then
|
||||
nobj_distort_x = nobj_distort_x or minetest.get_perlin(np_distort_x)
|
||||
nobj_distort_z = nobj_distort_z or minetest.get_perlin(np_distort_z)
|
||||
nobj_distort_amplitude = nobj_distort_amplitude or minetest.get_perlin(np_distort_amplitude)
|
||||
|
||||
local amplitude = nobj_distort_amplitude:get_2d({x=pos.x, y=pos.z})
|
||||
x = x + nobj_distort_x:get_3d(pos)*amplitude
|
||||
z = z + nobj_distort_z:get_3d(pos)*amplitude
|
||||
end
|
||||
|
||||
local terrain, lakes = mapgen_rivers.make_heightmaps(
|
||||
{x=math.floor(x), z=math.floor(z) },
|
||||
{x=math.floor(x)+1, z=math.floor(z)+1}
|
||||
)
|
||||
|
||||
local ex, ez = x % 1, z % 1
|
||||
--local h = terrain[1]*(1-ex)*(1-ez) + terrain[2]*ex*(1-ez) + terrain[3]*(1-ex)*ez + terrain[4]*ex*ez
|
||||
local h = interp(terrain[1], terrain[2], terrain[4], terrain[3], ex, ez)
|
||||
local lake = math.min(lakes[1], lakes[2], lakes[3], lakes[4])
|
||||
|
||||
if h < lake or h <= sea_level then
|
||||
return false, h
|
||||
end
|
||||
|
||||
return true, h
|
||||
end
|
||||
|
||||
local function get_spawn_level(x, z)
|
||||
local pos = {x=x, z=z}
|
||||
local suitable, y = estimate_spawn_level(pos, false)
|
||||
if not suitable then
|
||||
return
|
||||
end
|
||||
|
||||
if not distort then
|
||||
return math.floor(y) + 1
|
||||
end
|
||||
|
||||
local low_bound = -math.huge
|
||||
local high_bound = math.huge
|
||||
local suitable_high = false
|
||||
|
||||
repeat
|
||||
pos.y = math.max(math.min(math.floor(y+0.5), high_bound-1), low_bound+1)
|
||||
suitable, y = estimate_spawn_level(pos, true)
|
||||
if y > pos.y then
|
||||
low_bound = pos.y
|
||||
else
|
||||
high_bound = pos.y
|
||||
suitable_high = suitable
|
||||
end
|
||||
until high_bound - low_bound <= 1
|
||||
|
||||
if not suitable_high then
|
||||
return
|
||||
end
|
||||
|
||||
return high_bound + 1
|
||||
end
|
||||
minetest.get_spawn_level = get_spawn_level
|
||||
|
||||
local rmax = 2000
|
||||
local function find_spawn_point(seed)
|
||||
local level = get_spawn_level(0, 0)
|
||||
if level then
|
||||
return {x=0, y=level, z=0}
|
||||
end
|
||||
|
||||
local pr = PcgRandom(seed or os.time())
|
||||
local incr = 16
|
||||
local r0 = 0
|
||||
|
||||
while r0 < rmax do
|
||||
local r1 = r0 + incr
|
||||
local r = pr:next(r0*r0+1, r1*r1) ^ 0.5
|
||||
local a = pr:next() / 2147483648 * math.pi
|
||||
|
||||
local x = math.floor(math.cos(a) * r + 0.5)
|
||||
local z = math.floor(math.sin(a) * r + 0.5)
|
||||
|
||||
level = get_spawn_level(x, z)
|
||||
if level then
|
||||
return {x=x, y=level, z=z}
|
||||
end
|
||||
r0 = r1
|
||||
end
|
||||
end
|
||||
|
||||
local function spawn_player(player)
|
||||
if minetest.settings:get("static_spawnpoint") then
|
||||
return
|
||||
end
|
||||
|
||||
local spawn_point = find_spawn_point()
|
||||
if spawn_point then
|
||||
player:set_pos(spawn_point)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_newplayer(spawn_player)
|
||||
minetest.register_on_respawnplayer(spawn_player)
|
Reference in New Issue
Block a user