local path = nether.path local in_mapgen_env = nether.env_type == "ssm_mapgen" -- vars local v = nether.v local nether_middle = v.nether_middle local f_bottom_scale = v.f_bottom_scale local f_h_min = v.f_h_min local f_h_max = v.f_h_max local tree_rarity = v.tree_rarity local glowflower_rarity = v.glowflower_rarity local grass_rarity = v.grass_rarity local mushroom_rarity = v.mushroom_rarity local nether_start = v.nether_start local NETHER_HEIGHT = v.NETHER_HEIGHT local NETHER_RANDOM = v.NETHER_RANDOM local GLOWSTONE_FREQ_ROOF = v.GLOWSTONE_FREQ_ROOF local LAVA_FREQ = v.LAVA_FREQ local nether_structure_freq = v.nether_structure_freq local NETHER_SHROOM_FREQ = v.NETHER_SHROOM_FREQ local NETHER_BOTTOM = v.NETHER_BOTTOM local nether_buildings = v.nether_buildings local nether_weird_noise = dofile(path .. "/weird_mapgen_noise.lua") -- Weierstrass function stuff from https://github.com/slemonide/gen local get_ws_list do local SIZE = 1000 local ssize = math.ceil(math.abs(SIZE)) local function do_ws_func(depth, a, x) local n = math.pi * x / (16 * SIZE) local y = 0 for k=1,depth do y = y + math.sin(k^a * n) / k^a end return SIZE * y / math.pi end local chunksize = minetest.settings:get"chunksize" or 5 local ws_lists = {} get_ws_list = function(a,x) ws_lists[a] = ws_lists[a] or {} local v = ws_lists[a][x] if v then return v end v = {} for x=x,x + (chunksize*16 - 1) do local y = do_ws_func(ssize, a, x) v[x] = y end ws_lists[a][x] = v return v end end local function dif(z1, z2) return math.abs(z1-z2) end local function pymg(x1, x2, z1, z2) return math.max(dif(x1, x2), dif(z1, z2)) end -- Generated variables --~ local NETHER_ROOF_ABS = (nether_middle - NETHER_RANDOM) local f_yscale_top = (f_h_max-f_h_min)/2 local f_yscale_bottom = f_yscale_top/2 --HADES_THRONE_STARTPOS_ABS = {x=HADES_THRONE_STARTPOS.x, y=(NETHER_BOTTOM + --HADES_THRONE_STARTPOS.y), z=HADES_THRONE_STARTPOS.z} --LAVA_Y = (NETHER_BOTTOM + LAVA_HEIGHT) --HADES_THRONE_ABS = {} --HADES_THRONE_ENDPOS_ABS = {} --HADES_THRONE_GENERATED = minetest.get_worldpath() .. "/netherhadesthrone.txt" --NETHER_SPAWNPOS_ABS = {x=NETHER_SPAWNPOS.x, y=(NETHER_BOTTOM + --NETHER_SPAWNPOS.y), z=NETHER_SPAWNPOS.z} --[[for i,v in ipairs(HADES_THRONE) do v.pos.x = v.pos.x + HADES_THRONE_STARTPOS_ABS.x v.pos.y = v.pos.y + HADES_THRONE_STARTPOS_ABS.y v.pos.z = v.pos.z + HADES_THRONE_STARTPOS_ABS.z HADES_THRONE_ABS[i] = v end local htx = 0 local hty = 0 local htz = 0 for i,v in ipairs(HADES_THRONE_ABS) do if v.pos.x > htx then htx = v.pos.x end if v.pos.y > hty then hty = v.pos.y end if v.pos.z > htz then htz = v.pos.z end end HADES_THRONE_ENDPOS_ABS = {x=htx, y=hty, z=htz}]] local c, nether_tree_nodes, contents_defined local function define_contents() if not contents_defined then c, nether_tree_nodes = nether.query_contents() contents_defined = true end end local pr local function return_nether_ore(id, glowstone) if glowstone and pr:next(0,GLOWSTONE_FREQ_ROOF) == 1 then return c.glowstone end if id == c.coal then return c.netherrack_tiled end if id == c.gravel then return c.netherrack_black end if id == c.diamond then return c.netherrack_blue end if id == c.mese then return c.white end return c.netherrack end local f_perlins = {} -- abs(v) < 1-(persistance^octaves))/(1-persistance) = amp --local perlin1 = minetest.get_perlin(13,3, 0.5, 50) --Get map specific perlin -- local perlin2 = minetest.get_perlin(133,3, 0.5, 10) -- local perlin3 = minetest.get_perlin(112,3, 0.5, 5) local tmp = f_yscale_top*4 local tmp2 = tmp/f_bottom_scale local perlins = { { -- amp 1.75 seed = 13, octaves = 3, persist = 0.5, spread = {x=50, y=50, z=50}, scale = 1, offset = 0, }, {-- amp 1.75 seed = 133, octaves = 3, persist = 0.5, spread = {x=10, y=10, z=10}, scale = 1, offset = 0, }, {-- amp 1.75 seed = 112, octaves = 3, persist = 0.5, spread = {x=5, y=5, z=5}, scale = 1, offset = 0, }, --[[forest_bottom = { seed = 11, octaves = 3, persist = 0.8, spread = {x=tmp2, y=tmp2, z=tmp2}, scale = 1, offset = 0, },]] forest_top = {-- amp 2.44 seed = 21, octaves = 3, persist = 0.8, spread = {x=tmp, y=tmp, z=tmp}, scale = 1, offset = 0, }, } -- buffers, see https://forum.minetest.net/viewtopic.php?f=18&t=16043 local pelin_maps local pmap1 = {} local pmap2 = {} local pmap3 = {} local pmap_f_top = {} local data = {} local structures_enabled = true local vine_maxlength = math.floor(NETHER_HEIGHT/4+0.5) -- Create the Nether local function on_generated(minp, maxp, seed) --avoid big map generation if not (maxp.y >= NETHER_BOTTOM-100 and minp.y <= nether_start) then return end local t1 = minetest.get_us_time() nether:inform("generates at: x=["..minp.x.."; "..maxp.x.."]; y=[" .. minp.y.."; "..maxp.y.."]; z=["..minp.z.."; "..maxp.z.."]", 2) define_contents() local buildings = 0 if maxp.y <= NETHER_BOTTOM then buildings = 1 elseif minp.y <= nether_buildings then buildings = 2 end local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") vm:get_data(data) local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} pr = PseudoRandom(seed+33) local tab,num = {},1 local trees,num_trees = {},1 --local perlin1 = minetest.get_perlin(13,3, 0.5, 50) --local perlin2 = minetest.get_perlin(133,3, 0.5, 10) --local perlin3 = minetest.get_perlin(112,3, 0.5, 5) local side_length = maxp.x - minp.x + 1 local map_lengths_xyz = {x=side_length, y=side_length, z=side_length} if not pelin_maps then pelin_maps = { a = minetest.get_perlin_map(perlins[1], map_lengths_xyz), b = minetest.get_perlin_map(perlins[2], map_lengths_xyz), c = minetest.get_perlin_map(perlins[3], map_lengths_xyz), forest_top = minetest.get_perlin_map(perlins.forest_top, map_lengths_xyz), } end pelin_maps.a:get_2d_map_flat({x=minp.x, y=minp.z}, pmap1) pelin_maps.b:get_2d_map_flat({x=minp.x, y=minp.z}, pmap2) pelin_maps.c:get_2d_map_flat({x=minp.x, y=minp.z}, pmap3) local forest_possible = maxp.y > f_h_min and minp.y < f_h_max --local pmap_f_bottom = minetest.get_perlin_map(perlins.forest_bottom, -- map_lengths_xyz):get_2d_map_flat({x=minp.x, y=minp.z}) local perlin_f_bottom, strassx, strassz if forest_possible then perlin_f_bottom = minetest.get_perlin(11, 3, 0.8, tmp2) pelin_maps.forest_top:get_2d_map_flat({x=minp.x, y=minp.z}, pmap_f_top) strassx = get_ws_list(2, minp.x) strassz = get_ws_list(2, minp.z) end local num2, tab2 if buildings >= 1 then num2 = 1 tab2 = nether_weird_noise({x=minp.x, y=nether_buildings-79, z=minp.z}, pymg, 200, 8, 10, side_length-1) end local count = 0 for z=minp.z, maxp.z do for x=minp.x, maxp.x do count = count+1 local test = pmap1[count]+1 local test2 = pmap2[count] local test3 = math.abs(pmap3[count]) local t = math.floor(test*3+0.5) local h if test2 < 0 then h = math.floor(test2*3+0.5)-1 else h = 3+t+pr:next(0,NETHER_RANDOM) end local generate_vine = false if test3 >= 0.72+pr:next(0,NETHER_RANDOM)/10 and pr:next(0,NETHER_RANDOM) == 1 then generate_vine = true end local bottom = NETHER_BOTTOM+h local top = nether_middle-pr:next(0,NETHER_RANDOM)+t local py_h = 0 local difn, noisp, py_h_g if buildings >= 1 then py_h = tab2[num2].y num2 = num2+1 difn = nether_buildings-py_h if difn == 5 then noisp = 1 elseif difn < 5 then noisp = 2 end py_h_g = nether_buildings-7 end local vi = area:index(x, minp.y, z) if buildings == 1 and noisp then if noisp == 1 then for _ = 1,side_length do data[vi] = c.netherrack_brick vi = vi + area.ystride end else for _ = 1,side_length do data[vi] = c.lava vi = vi + area.ystride end end else local r_structure = pr:next(1,nether_structure_freq) local r_shroom = pr:next(1,NETHER_SHROOM_FREQ) local r_glowstone = pr:next(0,GLOWSTONE_FREQ_ROOF) local r_vine_length = pr:next(1,vine_maxlength) local f_bottom, f_top, is_forest, f_h_dirt if forest_possible then local p = {x=math.floor(x/f_bottom_scale), z=math.floor(z/f_bottom_scale)} local pstr = p.x.." "..p.z if not f_perlins[pstr] then f_perlins[pstr] = math.floor(f_h_min + (math.abs( perlin_f_bottom:get_2d{x=p.x, y=p.z} + 1)) * f_yscale_bottom + 0.5) end local top_noise = pmap_f_top[count]+1 if top_noise < 0 then top_noise = -top_noise/10 --nether:inform("ERROR: (perlin noise) ".. -- pmap_f_top[count].." is not inside [-1; 1]", 1) end f_top = math.floor(f_h_max - top_noise*f_yscale_top + 0.5) f_bottom = f_perlins[pstr]+pr:next(0,f_bottom_scale-1) is_forest = f_bottom < f_top f_h_dirt = f_bottom-pr:next(0,1) end for y=minp.y, maxp.y do local d_p_addp = data[vi] --if py_h >= maxp.y-4 then if y <= py_h and noisp then if noisp == 1 then data[vi] = c.netherrack_brick elseif noisp == 2 then if y == py_h then data[vi] = c.netherrack_brick elseif y == py_h_g and pr:next(1,3) <= 2 then data[vi] = c.netherrack elseif y <= py_h_g then data[vi] = c.lava else data[vi] = c.air end end elseif d_p_addp ~= c.air then if is_forest and y == f_bottom then data[vi] = c.nether_dirt_top elseif is_forest and y < f_bottom and y >= f_h_dirt then data[vi] = c.nether_dirt elseif is_forest and y == f_h_dirt-1 then data[vi] = c.nether_dirt_bottom elseif is_forest and y == f_h_dirt+1 then if pr:next(1,tree_rarity) == 1 then trees[num_trees] = {x=x, y=y, z=z} num_trees = num_trees+1 elseif pr:next(1,mushroom_rarity) == 1 then data[vi] = c.nether_shroom elseif pr:next(1,glowflower_rarity) == 1 then data[vi] = c.glowflower elseif pr:next(1,grass_rarity) == 1 then data[vi] = c.nether_grass[pr:next(1,3)] else data[vi] = c.air end elseif is_forest and y > f_bottom and y < f_top then if not nether_tree_nodes[d_p_addp] then data[vi] = c.air end elseif is_forest and y == f_top then local sel = math.floor(strassx[x]+strassz[z]+0.5)%10 if sel <= 5 then data[vi] = return_nether_ore(d_p_addp, true) elseif sel == 6 then data[vi] = c.netherrack_black elseif sel == 7 then data[vi] = c.glowstone else data[vi] = c.air end elseif y <= NETHER_BOTTOM then if y <= bottom then data[vi] = return_nether_ore(d_p_addp, true) else data[vi] = c.lava end elseif r_structure == 1 and y == bottom then tab[num] = {x=x, y=y-1, z=z} num = num+1 elseif y <= bottom then if pr:next(1,LAVA_FREQ) == 1 then data[vi] = c.lava else data[vi] = return_nether_ore(d_p_addp, false) end elseif r_shroom == 1 and r_structure ~= 1 and y == bottom+1 then data[vi] = c.nether_shroom elseif (y == top and r_glowstone == 1) then data[vi] = c.glowstone elseif y >= top then data[vi] = return_nether_ore(d_p_addp, true) elseif y <= top-1 and generate_vine and y >= top-r_vine_length then data[vi] = c.nether_vine else data[vi] = c.air end end vi = vi + area.ystride end end end end nether:inform("most stuff set", 2, t1) local t2 = minetest.get_us_time() local bl_cnt = 0 local tr_cnt = 0 local tr_snd_cnt = 0 if structures_enabled then -- Blood netherstructures bl_cnt = #tab for i = 1, #tab do nether.grow_netherstructure_into(area, data, tab[i], true) end end if bl_cnt > 0 then nether:inform(bl_cnt .. " blood structures set", 2, t2) end t2 = minetest.get_us_time() vm:set_data(data) -- vm:set_lighting(12) -- vm:calc_lighting() -- vm:update_liquids() if not in_mapgen_env then vm:write_to_map(false) end nether:inform("data written", 2, t2) t2 = minetest.get_us_time() if forest_possible then -- Forest trees if in_mapgen_env then -- Trees can get too big (>16 nodes in one direction) for usual -- overgeneration onion layer. nether.grow_tree will make new vmanips -- to emerge blank (= ignore-filled) blocks to overcome this. But the -- main server thread needs to do this. tr_snd_cnt = #trees local trees_hashed = {} for i = 1, #trees do trees_hashed[i] = minetest.hash_node_position(trees[i]) end assert(minetest.save_gen_notify("nether:please_grow_trees", trees_hashed)) else tr_cnt = #trees for i = 1, #trees do nether.grow_tree(trees[i], true) end end end if tr_cnt + tr_snd_cnt > 0 then nether:inform(string.format("%s trees set, %s trees sent", tr_cnt, tr_snd_cnt), 2, t2) end if in_mapgen_env then assert(minetest.save_gen_notify("nether:please_fix_light", {minp, maxp})) else t2 = minetest.get_us_time() minetest.fix_light(minp, maxp) nether:inform("light fixed", 2, t2) end nether:inform("done", 1, t1) end if in_mapgen_env then minetest.register_on_generated(function(_, minp, maxp, blockseed) return on_generated(minp, maxp, blockseed) end) else minetest.register_on_generated(on_generated) end