mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2025-07-03 17:00:42 +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
|
|
157
gridmanager.lua
157
gridmanager.lua
@ -1,6 +1,6 @@
|
|||||||
-- Manages grid loading, writing and generation
|
-- 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 = {}
|
local registered_on_grid_loaded = {}
|
||||||
function mapgen_rivers.register_on_grid_loaded(func)
|
function mapgen_rivers.register_on_grid_loaded(func)
|
||||||
@ -21,128 +21,85 @@ local function offset_conv(o)
|
|||||||
return (o + 0.5) * (1/256)
|
return (o + 0.5) * (1/256)
|
||||||
end
|
end
|
||||||
|
|
||||||
local grid_maps_list = {
|
local floor = math.floor
|
||||||
dem = {bytes=2, signed=true},
|
local sbyte, schar = string.byte, string.char
|
||||||
lakes = {bytes=2, signed=true},
|
local unpk = unpack
|
||||||
dirs = {bytes=1, signed=false},
|
|
||||||
rivers = {bytes=4, signed=false},
|
|
||||||
|
|
||||||
offset_x = {bytes=1, signed=true, conv=offset_conv},
|
-- Loading files
|
||||||
offset_y = {bytes=1, signed=true, conv=offset_conv},
|
|
||||||
|
-- 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)
|
local function load_file(filename, bytes, signed, size, converter)
|
||||||
if grid.load_method ~= "full" then
|
local file = io.open(datapath .. filename, 'rb')
|
||||||
minetest.log("warning", ("Could not apply data conversion for load method %s"):format(grid.load_method))
|
if file then
|
||||||
return false
|
converter = converter or false
|
||||||
|
return setmetatable({file=file, bytes=bytes, signed=signed, size=size, conv=converter}, loader_mt)
|
||||||
end
|
end
|
||||||
if grid.conv_applied then
|
end
|
||||||
|
|
||||||
|
function mapgen_rivers.load_or_generate_grid()
|
||||||
|
-- First, check whether a grid is already loaded
|
||||||
|
if mapgen_rivers.grid then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local size = grid.size.x * grid.size.y
|
-- If not, try to load the grid from the files
|
||||||
for mapname, params in pairs(grid_maps_list) do
|
local sfile = io.open(datapath .. 'size', 'r')
|
||||||
local conv = params.conv
|
if not sfile then
|
||||||
if conv then
|
dofile(mapgen_rivers.modpath .. "/pregenerate.lua")
|
||||||
local map = grid[mapname]
|
collectgarbage()
|
||||||
for i=1, size do
|
|
||||||
map[i] = conv(map[i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
grid.conv_applied = true
|
|
||||||
|
|
||||||
return true
|
sfile = io.open(datapath .. 'size', 'r')
|
||||||
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)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Fall back to loading the grid from the files
|
|
||||||
local sfile = io.open(world_data .. 'size', 'r')
|
|
||||||
if not sfile then
|
if not sfile then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local x, z = sfile:read('*n'), sfile:read('*n')
|
local x, z = sfile:read('*n'), sfile:read('*n')
|
||||||
if not x or not z then
|
if not x or not z then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if load_method == "full" then
|
minetest.log("action", '[mapgen_rivers] Loading grid')
|
||||||
minetest.log("action", '[mapgen_rivers] Loading full grid')
|
|
||||||
elseif load_method == "interactive" then
|
|
||||||
minetest.log("action", '[mapgen_rivers] Loading grid as interactive loaders')
|
|
||||||
end
|
|
||||||
|
|
||||||
grid = {
|
local grid = {
|
||||||
load_method = load_method,
|
|
||||||
size = {x=x, y=z},
|
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
|
mapgen_rivers.grid = grid
|
||||||
on_grid_loaded_callback(grid)
|
on_grid_loaded_callback(grid)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
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 .. 'settings.lua')
|
||||||
dofile(modpath .. 'gridmanager.lua')
|
dofile(modpath .. 'gridmanager.lua')
|
||||||
dofile(modpath .. 'gridio.lua')
|
|
||||||
dofile(modpath .. 'polygons.lua')
|
dofile(modpath .. 'polygons.lua')
|
||||||
dofile(modpath .. 'heightmap.lua')
|
dofile(modpath .. 'heightmap.lua')
|
||||||
dofile(modpath .. 'mapgen.lua')
|
dofile(modpath .. 'mapgen.lua')
|
||||||
|
dofile(modpath .. 'spawn.lua')
|
||||||
|
|
||||||
minetest.register_on_mods_loaded(function()
|
minetest.register_on_mods_loaded(mapgen_rivers.load_or_generate_grid)
|
||||||
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)
|
|
||||||
|
64
mapgen.lua
64
mapgen.lua
@ -28,12 +28,13 @@ local floor, min = math.floor, math.min
|
|||||||
|
|
||||||
local data = {}
|
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_x_map = {}
|
||||||
local noise_z_map = {}
|
local noise_z_map = {}
|
||||||
local noise_distort_map = {}
|
local noise_distort_map = {}
|
||||||
local noise_heat_map = {}
|
local noise_heat_map = {}
|
||||||
local noise_heat_blend_map = {}
|
local noise_heat_blend_map = {}
|
||||||
|
local noise_cave = {}
|
||||||
local mapsize
|
local mapsize
|
||||||
local init = false
|
local init = false
|
||||||
|
|
||||||
@ -41,6 +42,18 @@ local sumtime = 0
|
|||||||
local sumtime2 = 0
|
local sumtime2 = 0
|
||||||
local ngen = 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)
|
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)))
|
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_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)
|
noise_heat_blend_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.heat_blend, chulens)
|
||||||
end
|
end
|
||||||
|
if use_caves then
|
||||||
|
noise_cave_obj = minetest.get_perlin_map(np_cave, mapsize)
|
||||||
|
end
|
||||||
init = true
|
init = true
|
||||||
end
|
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_obj:get_2d_map_flat(minp2d, noise_heat_map)
|
||||||
noise_heat_blend_obj:get_2d_map_flat(minp2d, noise_heat_blend_map)
|
noise_heat_blend_obj:get_2d_map_flat(minp2d, noise_heat_blend_map)
|
||||||
end
|
end
|
||||||
|
if use_caves then
|
||||||
|
noise_cave_obj:get_3d_map_flat(minp, noise_cave)
|
||||||
|
end
|
||||||
local terrain_map, lake_map, incr, i_origin
|
local terrain_map, lake_map, incr, i_origin
|
||||||
|
|
||||||
if use_distort then
|
if use_distort then
|
||||||
@ -103,6 +121,7 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
|||||||
end
|
end
|
||||||
i2d = i2d-chulens.x
|
i2d = i2d-chulens.x
|
||||||
end
|
end
|
||||||
|
i2d = i2d+chulens.x
|
||||||
end
|
end
|
||||||
|
|
||||||
local pminp = {x=floor(xmin), z=floor(zmin)}
|
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 not, skip chunk
|
||||||
if is_empty then
|
if is_empty then
|
||||||
|
if use_biomegen_mod and biomegen.skip_chunk then
|
||||||
|
biomegen.skip_chunk(minp, maxp)
|
||||||
|
end
|
||||||
|
|
||||||
local t = os.clock() - t0
|
local t = os.clock() - t0
|
||||||
ngen = ngen + 1
|
ngen = ngen + 1
|
||||||
sumtime = sumtime + t
|
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_stone = minetest.get_content_id("mapgen_stone")
|
||||||
local c_water = minetest.get_content_id("mapgen_water_source")
|
local c_water = minetest.get_content_id("mapgen_water_source")
|
||||||
local c_rwater = minetest.get_content_id("mapgen_river_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
|
local c_dirt, c_lawn, c_dirtsnow, c_snow, c_sand, c_ice
|
||||||
if use_biomes then
|
if use_biomes then
|
||||||
@ -173,7 +197,7 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
|||||||
if use_biomes then
|
if use_biomes then
|
||||||
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
|
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
|
||||||
end
|
end
|
||||||
local terrain, lake
|
local terrain, lake, caveness
|
||||||
if not use_distort then
|
if not use_distort then
|
||||||
terrain = terrain_map[i2d]
|
terrain = terrain_map[i2d]
|
||||||
lake = lake_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])
|
lake = min(lake_map[i0], lake_map[i1], lake_map[i2], lake_map[i3])
|
||||||
end
|
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
|
if y <= maxp.y then
|
||||||
|
|
||||||
local is_lake = lake > terrain
|
local is_lake = lake > terrain
|
||||||
@ -244,10 +272,32 @@ function mapgen_rivers.make_chunk(minp, maxp, seed)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if use_biomegen_mod then
|
if use_biomegen_mod then
|
||||||
biomegen.generate_all(data, a, vm, minp, maxp, seed)
|
biomegen.generate_biomes(data, a, minp, maxp)
|
||||||
else
|
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)
|
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)
|
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
|
end
|
||||||
|
|
||||||
vm:set_lighting({day = 0, night = 0})
|
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))
|
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
|
||||||
end
|
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()
|
minetest.register_on_shutdown(function()
|
||||||
local avg = sumtime / ngen
|
local avg = sumtime / ngen
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
-- Generate the grid using terrainlib_lua
|
-- Generate the grid using terrainlib_lua
|
||||||
-- Only called on first mapgen, if there is no grid yet
|
-- Only called on first mapgen, if there is no grid yet
|
||||||
|
|
||||||
|
-- Constants
|
||||||
|
|
||||||
local EvolutionModel = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/erosion.lua')
|
local EvolutionModel = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/erosion.lua')
|
||||||
local twist = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/twist.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_width = mapgen_rivers.settings.margin_width / blocksize
|
||||||
local margin_elev = mapgen_rivers.settings.margin_elev
|
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 function margin(dem, width, elev)
|
||||||
local X, Y = dem.X, dem.Y
|
local X, Y = dem.X, dem.Y
|
||||||
for i=1, width do
|
for i=1, width do
|
||||||
@ -49,21 +54,22 @@ local function margin(dem, width, elev)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mapgen_rivers.pregenerate(grid)
|
-- Generate grid
|
||||||
local size = grid.size
|
|
||||||
|
|
||||||
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.")
|
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"))
|
local seed = tonumber(minetest.get_mapgen_setting("seed"):sub(-10))
|
||||||
np_base.seed = (np_base.seed or 0) + seed
|
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})
|
local dem = nobj_base:get_3d_map_flat({x=0, y=0, z=0})
|
||||||
dem.X = size.x
|
dem.X = X
|
||||||
dem.Y = size.y
|
dem.Y = Y
|
||||||
|
|
||||||
if use_margin then
|
if use_margin then
|
||||||
margin(dem, margin_width, margin_elev)
|
margin(dem, margin_width, margin_elev)
|
||||||
@ -97,20 +103,48 @@ function mapgen_rivers.pregenerate(grid)
|
|||||||
|
|
||||||
local mfloor = math.floor
|
local mfloor = math.floor
|
||||||
local mmin, mmax = math.min, math.max
|
local mmin, mmax = math.min, math.max
|
||||||
|
local unpk, schar = unpack, string.char
|
||||||
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
|
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
|
||||||
for i=1, size.x*size.y do
|
for i=1, X*Y do
|
||||||
offset_x[i] = mmin(mmax(offset_x[i]*256, -128), 127)
|
offset_x[i] = mmin(mmax(offset_x[i]*256, -128), 127)
|
||||||
offset_y[i] = mmin(mmax(offset_y[i]*256, -128), 127)
|
offset_y[i] = mmin(mmax(offset_y[i]*256, -128), 127)
|
||||||
end
|
end
|
||||||
|
|
||||||
grid.dem = model.dem
|
-- Write data
|
||||||
grid.lakes = model.lakes
|
|
||||||
grid.dirs = model.dirs
|
|
||||||
grid.rivers = model.rivers
|
|
||||||
grid.offset_x = offset_x
|
|
||||||
grid.offset_y = offset_y
|
|
||||||
|
|
||||||
grid.load_method = "full"
|
local datapath = mapgen_rivers.world_data_path
|
||||||
grid.conv_applied = false
|
minetest.mkdir(datapath)
|
||||||
collectgarbage()
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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'),
|
tectonic_speed = def_setting('tectonic_speed', 'number'),
|
||||||
evol_time = def_setting('evol_time', 'number'),
|
evol_time = def_setting('evol_time', 'number'),
|
||||||
evol_time_step = def_setting('evol_time_step', '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 = {
|
mapgen_rivers.noise_params = {
|
||||||
base = def_setting("np_base", "noise"),
|
base = def_setting("np_base", "noise"),
|
||||||
distort_x = def_setting("np_distort_x", "noise"),
|
distort_x = def_setting("np_distort_x", "noise"),
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
"tectonic_speed": 70,
|
"tectonic_speed": 70,
|
||||||
"evol_time": 10,
|
"evol_time": 10,
|
||||||
"evol_time_step": 1,
|
"evol_time_step": 1,
|
||||||
"load_all": false,
|
|
||||||
|
|
||||||
"np_base": {
|
"np_base": {
|
||||||
"offset": 0,
|
"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.
|
# This results in mountains being more covered by snow.
|
||||||
mapgen_rivers_elevation_chill (Elevation chill) float 0.25 0.0 5.0
|
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]
|
[Landscape evolution parameters]
|
||||||
|
|
||||||
# Modelled landscape evolution time, in arbitrary units
|
# 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