nodecore-cd2025/mods/nc_api/mapgen_shared.lua
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

73 lines
2.0 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local PcgRandom, VoxelArea, ipairs, math, minetest, nodecore, table
= PcgRandom, VoxelArea, ipairs, math, minetest, nodecore, table
local math_floor, math_random, table_insert
= math.floor, math.random, table.insert
-- LUALOCALS > ---------------------------------------------------------
local mapgens = {}
nodecore.registered_mapgen_shared = mapgens
local singlenode = minetest.get_mapgen_setting("mg_name") == "singlenode"
local counters = {}
function nodecore.register_mapgen_shared(def)
local label = def.label
if not label then
label = minetest.get_current_modname()
local i = (counters[label] or 0) + 1
counters[label] = i
label = label .. ":" .. i
end
local prio = def.priority or 0
def.priority = prio
local min = 1
local max = #mapgens + 1
while max > min do
local try = math_floor((min + max) / 2)
local oldp = mapgens[try].priority
if (prio < oldp) or (prio == oldp and label > mapgens[try].label) then
min = try + 1
else
max = try
end
end
table_insert(mapgens, min, def)
end
local mapperlin
minetest.after(0, function() mapperlin = minetest.get_perlin(0, 1, 0, 1) end)
nodecore.register_on_generated("mapgen shared", function(minp, maxp)
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local data = vm:get_data()
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local rng = math_random
if PcgRandom then
local seed = mapperlin:get_3d({x = minp.x, y = minp.y, z = minp.z})
seed = math_floor((seed - math_floor(seed)) * 2 ^ 32 - 2 ^ 31)
local pcg = PcgRandom(seed)
rng = function(a, b)
if b then
return pcg:next(a, b)
elseif a then
return pcg:next(1, a)
end
return (pcg:next() + 2 ^ 31) / 2 ^ 32
end
end
for _, def in ipairs(mapgens) do
local en = def.enabled
if en == nil then en = not singlenode end
if en then
def.func(minp, maxp, area, data, vm, emin, emax, rng)
end
end
vm:set_data(data)
vm:write_to_map()
end)