206 lines
5.5 KiB
Lua

-- Parameters
local pathy = 8
-- Noises blended to create 'path'
local np_patha = {
offset = 0.0,
scale = 1,
spread = {x = 384, y = 384, z = 384},
seed = 11711,
octaves = 4,
persist = 0.6
}
local np_pathb = {
offset = 0.0,
scale = 1,
spread = {x = 384, y = 384, z = 384},
seed = 303,
octaves = 1,
persist = 0.5
}
-- Noises blended to create 'path2'
local np_pathc = {
offset = 0.0,
scale = 1,
spread = {x = 512, y = 512, z = 512},
seed = 7755,
octaves = 4,
persist = 0.6
}
local np_pathd = {
offset = 0.0,
scale = 1,
spread = {x = 512, y = 512, z = 512},
seed = 1001,
octaves = 1,
persist = 0.5
}
-- Blend between low and high octave noises
local np_blend = {
offset = 0.0,
scale = 6.0,
spread = {x = 256, y = 256, z = 256},
seed = 95059,
octaves = 1,
persist = 0.5
}
-- Nodes
minetest.register_node("track:road_black", {
description = "Road Black",
tiles = {"track_road_black.png"},
is_ground_content = false,
groups = {cracky = 3},
})
minetest.register_node("track:road_white", {
description = "Road White",
tiles = {"track_road_white.png"},
paramtype = "light",
light_source = 12,
is_ground_content = false,
groups = {cracky = 3},
})
-- Set mapgen flags to disable core mapgen decoration placement.
-- Tree decorations are placed using the Lua Voxel Manipulator after track generation
-- to avoid trees on track.
minetest.set_mapgen_setting("mg_flags", "caves,dungeons,light,nodecorations,biomes", true)
-- Constants
local c_roadblack = minetest.get_content_id("track:road_black")
local c_roadwhite = minetest.get_content_id("track:road_white")
-- Initialise noise object, noise table, voxelmanip table
local nobj_patha = nil
local nobj_pathb = nil
local nobj_pathc = nil
local nobj_pathd = nil
local nobj_blend = nil
local nvals_patha = {}
local nvals_pathb = {}
local nvals_pathc = {}
local nvals_pathd = {}
local nvals_blend = {}
local data = {}
-- On generated function
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y > pathy or maxp.y < pathy then
return
end
--local t1 = os.clock()
local x1 = maxp.x
local y1 = maxp.y
local z1 = maxp.z
local x0 = minp.x
local y0 = minp.y
local z0 = minp.z
-- Noise map extends from x0/z0 - 5 to x1/z1 + 4, one node larger than the track brush
-- centre generation area, to allow sign change of noise to be detected along minimum
-- edges of track brush centre generation area.
local mchudim = x1 - x0 + 1
local pmapdim = mchudim + 9
local pmapdims = {x = pmapdim, y = pmapdim, z = 1}
local pmapminp = {x = x0 - 5, y = z0 - 5}
nobj_patha = nobj_patha or minetest.get_perlin_map(np_patha, pmapdims)
nobj_pathb = nobj_pathb or minetest.get_perlin_map(np_pathb, pmapdims)
nobj_pathc = nobj_pathc or minetest.get_perlin_map(np_pathc, pmapdims)
nobj_pathd = nobj_pathd or minetest.get_perlin_map(np_pathd, pmapdims)
nobj_blend = nobj_blend or minetest.get_perlin_map(np_blend, pmapdims)
nobj_patha:get2dMap_flat(pmapminp, nvals_patha)
nobj_pathb:get2dMap_flat(pmapminp, nvals_pathb)
nobj_pathc:get2dMap_flat(pmapminp, nvals_pathc)
nobj_pathd:get2dMap_flat(pmapminp, nvals_pathd)
nobj_blend:get2dMap_flat(pmapminp, nvals_blend)
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
vm:get_data(data)
-- Track brush centre generation area extends from x0/z0 - 4 to x1/z1 + 4
for z = z0 - 4, z1 + 4 do
-- Initial noise index at x0 - 4
local ni = 1 + (z - (z0 - 5)) * pmapdim + 1
-- Initial blend, n_path and n_path2 values for adjacent node at x0 - 5
local xpreblend = (math.tanh(nvals_blend[(ni - 1)]) + 1) / 2
local n_xprepath = (1 - xpreblend) * nvals_patha[(ni - 1)] +
xpreblend * nvals_pathb[(ni - 1)]
local n_xprepath2 = (1 - xpreblend) * nvals_pathc[(ni - 1)] +
xpreblend * nvals_pathd[(ni - 1)]
for x = x0 - 4, x1 + 4 do
local blend = (math.tanh(nvals_blend[ni]) + 1) / 2
local n_path = (1 - blend) * nvals_patha[ni] + blend * nvals_pathb[ni]
local n_path2 = (1 - blend) * nvals_pathc[ni] + blend * nvals_pathd[ni]
-- blend, n_path and n_path2 values for adjacent node at z - 1
local zpreblend = (math.tanh(nvals_blend[(ni - pmapdim)]) + 1) / 2
local n_zprepath = (1 - zpreblend) * nvals_patha[(ni - pmapdim)] +
zpreblend * nvals_pathb[(ni - pmapdim)]
local n_zprepath2 = (1 - zpreblend) * nvals_pathc[(ni - pmapdim)] +
zpreblend * nvals_pathd[(ni - pmapdim)]
-- Detect sign change of n_path and n_path2 in x, z directions
if (n_path * n_xprepath < 0)
or (n_path * n_zprepath < 0)
or (n_path2 * n_xprepath2 < 0)
or (n_path2 * n_zprepath2 < 0)
-- Detect when n_path and n_path2 are simultaneously
-- very small, to smooth corners of junctions
or math.pow(math.abs(n_path), 0.1) *
math.pow(math.abs(n_path2), 0.1) < 0.5 then
-- Place track brush of radius 4
for k = -4, 4 do
local vi = area:index(x - 4, pathy, z + k)
for i = -4, 4 do
local radsq = (math.abs(i)) ^ 2 + (math.abs(k)) ^ 2
if radsq <= 15 then
data[vi] = c_roadblack
elseif radsq <= 20 then
local nodid = data[vi]
if nodid ~= c_roadblack then
data[vi] = c_roadwhite
end
end
vi = vi + 1
end
end
end
ni = ni + 1
-- Set adjacent node values to current values
n_xprepath = n_path
n_xprepath2 = n_path2
end
end
vm:set_data(data)
minetest.generate_decorations(vm)
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:write_to_map(data)
--local chugent = math.ceil((os.clock() - t1) * 1000)
--print ("[track] "..chugent.." ms")
end)