Aaron Suen 9879a23680 Mapgen determinism
This should cause maps that have the same
seeds to have much more similar results
than before, e.g. sponge deposits will be in
the same places determined by seed and not
random each regeneration of the map.

- Mapgen shared now provides an RNG which
  will be deterministic when feasible, for
  repeatable mapgen results.
- Make existing rng-using mapgen hooks use
  the new deterministic RNG.
- Mapgen shared hooks are also run in
  deterministic order too.
- Tidy up mapgen_shared API a little more.
2020-06-20 23:48:29 -04:00

65 lines
2.0 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore
= math, minetest, nodecore
local math_floor
= math.floor
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local maxy = -8
local miny = maxy - 8
local c_sand = minetest.get_content_id("nc_terrain:sand")
local c_water = minetest.get_content_id("nc_terrain:water_source")
local c_sponge = minetest.get_content_id(modname .. ":sponge_living")
local function spawn(area, data, x, y, z, rng)
local total = 0
nodecore.scan_flood({x = x, y = y, z = z}, 5, function(p)
if rng() < 0.01 then return true end
if p.y > y and rng() > 0.1 then return false end
local idx = area:index(p.x, p.y - 1, p.z)
if data[idx] ~= c_sponge and data[idx] ~= c_sand then return false end
idx = area:index(p.x, p.y, p.z)
if data[idx] ~= c_water then return false end
data[idx] = c_sponge
total = total + 1
if total >= 20 then return true end
end)
end
nodecore.register_mapgen_shared({
label = "sponges",
func = function(minp, maxp, area, data, _, _, _, rng)
if minp.y > maxy or maxp.y < miny then return end
local rawqty = rng() * (maxp.x - minp.x + 1)
* (maxp.z - minp.z + 1) / (64 * 64)
local qty = math_floor(rawqty)
if rng() < (rawqty - qty) then qty = qty + 1 end
for _ = 1, qty do
local x = math_floor(rng() * (maxp.x - minp.x + 1)) + minp.x
local z = math_floor(rng() * (maxp.z - minp.z + 1)) + minp.z
local starty = maxp.y
if starty > (maxy + 1) then starty = (maxy + 1) end
local endy = minp.y
if endy < miny then endy = miny end
local waterabove = nil
for y = starty, endy, -1 do
local idx = area:index(x, y, z)
local cur = data[idx]
if cur == c_water then
waterabove = true
elseif cur == c_sand and waterabove then
spawn(area, data, x, y + 1, z, rng)
break
else
break
end
end
end
end
})