Aaron Suen a6308d8378 Don't pre-initialize stone strata arrays
The original theory was that preallocating the array forced lua
to use the "array part" of a table instead of the "hash part",
which should be faster since lookups are a simple linear offset
calculation and not a hash with collision check.

It turns out, however, that in empirical testing, whether the
array-preallocated or the naive-allocated version is faster depends
on circumstances, such as how sparse the array is, how uniform
access is, or how much other load the system is under.  This seems
to suggest that arrays are more computationally-efficient but less
cache-efficient, so cache evictions caused by other concurrent
processes may slow this method down significantly.

Worst-case performance will be the most noticeable here, since a
system that's heavily loaded would have the most need for speed
in the first place, so it's probably better generally to use the
naive allocation.

In all, the naive allocation method also seemed to be the least
sensitive to external factors.  In addition to the array method,
attempts to pre-compile the dynamic checks into a binary tree of
if/then statements (which could be JITted and optimized) failed
as well.
2021-04-07 07:44:13 -04:00

72 lines
1.8 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local error, ipairs, math, minetest, nodecore, pairs
= error, ipairs, math, minetest, nodecore, pairs
local math_floor
= math.floor
-- LUALOCALS > ---------------------------------------------------------
local thickness = 128
nodecore.stratadata = nodecore.memoize(function()
local data = {}
data.stratbyid = {}
data.altsbyid = {}
for k, v in pairs(minetest.registered_nodes) do
if v.strata then
local sn
for s, n in ipairs(v.strata) do
if n == k then sn = s end
end
if not sn then error(k .. " not found in own strata") end
local cid = minetest.get_content_id(k)
data.stratbyid[cid] = sn
data.altsbyid[cid] = {}
for s, n in ipairs(v.strata) do
data.altsbyid[cid][s] = minetest.get_content_id(n)
end
end
end
return data
end)
nodecore.register_mapgen_shared({
label = "stone strata",
func = function(minp, maxp, area, data, _, _, _, rng)
if minp.y > -64 then return end
local ai = area.index
local t = nodecore.hard_stone_strata
local sd = nodecore.stratadata()
local byid = sd.stratbyid
local alts = sd.altsbyid
for z = minp.z, maxp.z do
for y = minp.y, maxp.y do
local raw = y / -thickness
local strat = math_floor(raw)
local dither = raw - strat
if strat > t then
strat = t
dither = nil
elseif dither > (4 / thickness) then
dither = nil
else
dither = (dither * thickness + 1) / 5
end
local offs = ai(area, 0, y, z)
for x = minp.x, maxp.x do
local i = offs + x
if byid[data[i]] then
if dither and rng() >= dither then
data[i] = alts[data[i]][strat]
else
data[i] = alts[data[i]][strat + 1]
end
end
end
end
end
end,
priority = -100
})