From 47d39871d2af00515189b136694873dc6208e65d Mon Sep 17 00:00:00 2001 From: Paramat Date: Mon, 30 May 2016 20:55:04 +0100 Subject: [PATCH] Caverns. Fix node defs/crafting. Smaller emerge. Find cavern floor (#17) Large caverns using squashed 3D noise Less lava, more glowstone, no air pockets Preserve nether dungeons Allow light to spread from glowstone and make brighter Fix 'is ground content' settings, portals should not be excavated by overgenerated caves Rack drops itself as normal Make brick, fence, stair, slab groups consistent Use 'node sound gravel defaults' for sand Make brick crafting consistent with default Make fence recipe output number consistent with default Make 'emerge area' volume mimimum required size Add 'find nether target y' function to search for a cavern floor with space above for nether portal spawn --- init.lua | 261 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 190 insertions(+), 71 deletions(-) diff --git a/init.lua b/init.lua index f76c87d..02c467d 100644 --- a/init.lua +++ b/init.lua @@ -1,6 +1,25 @@ -- Parameters local NETHER_DEPTH = -5000 +local TCAVE = 0.6 +local BLEND = 128 + + +-- 3D noise + +local np_cave = { + offset = 0, + scale = 1, + spread = {x = 384, y = 128, z = 384}, -- squashed 3:1 + seed = 59033, + octaves = 5, + persist = 0.7 +} + + +-- Stuff + +local yblmax = NETHER_DEPTH - BLEND * 2 -- Functions @@ -42,7 +61,8 @@ local function build_portal(pos, target) for z = -2, 2 do if z ~= 0 then p.z = p.z + z - if minetest.registered_nodes[minetest.get_node(p).name].is_ground_content then + if minetest.registered_nodes[ + minetest.get_node(p).name].is_ground_content then minetest.remove_node(p) end p.z = p.z - z @@ -53,6 +73,28 @@ local function build_portal(pos, target) end end +local function find_nether_target_y(target_x, target_z) + local start_y = NETHER_DEPTH - math.random(500, 1500) -- Search start + local nobj_cave_point = minetest.get_perlin(np_cave) + local air = 0 -- Consecutive air nodes found + + for y = start_y, start_y - 4096, -1 do + local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z}) + + if nval_cave > TCAVE then -- Cavern + air = air + 1 + else -- Not cavern, check if 4 nodes of space above + if air >= 4 then + return y + 2 + else -- Not enough space, reset air to zero + air = 0 + end + end + end + + return y -- Fallback +end + local function move_check(p1, max, dir) local p = {x = p1.x, y = p1.y, z = p1.z} local d = math.abs(max - p1[dir]) / (max - p1[dir]) @@ -142,9 +184,9 @@ local function make_portal(pos) local target = {x = p1.x, y = p1.y, z = p1.z} target.x = target.x + 1 if target.y < NETHER_DEPTH then - target.y = math.random(-50, 20) + target.y = math.random(-32, 1) else - target.y = NETHER_DEPTH - math.random(500, 1500) + target.y = find_nether_target_y(target.x, target.z) end for d = 0, 3 do @@ -201,7 +243,7 @@ minetest.register_abm({ minetest.get_voxel_manip():read_from_map(target, target) if not minetest.get_node_or_nil(target) then minetest.emerge_area( - vector.subtract(target, 80), vector.add(target, 80)) + vector.subtract(target, 4), vector.add(target, 4)) end -- teleport the player minetest.after(3, function(obj, pos, target) @@ -271,6 +313,7 @@ minetest.register_node("nether:portal", { diggable = false, pointable = false, buildable_to = false, + is_ground_content = false, drop = "", light_source = 5, post_effect_color = {a = 180, r = 128, g = 0, b = 128}, @@ -287,7 +330,7 @@ minetest.register_node("nether:portal", { minetest.register_node(":default:obsidian", { description = "Obsidian", tiles = {"default_obsidian.png"}, - is_ground_content = true, + is_ground_content = false, sounds = default.node_sound_stone_defaults(), groups = {cracky = 1, level = 2}, @@ -350,12 +393,6 @@ minetest.register_node("nether:rack", { description = "Netherrack", tiles = {"nether_rack.png"}, is_ground_content = true, - drop = { - max_items = 1, - items = { - {rarity = 3, items = {"nether:rack"}}, - } - }, groups = {cracky = 3, level = 2}, sounds = default.node_sound_stone_defaults(), }) @@ -365,7 +402,7 @@ minetest.register_node("nether:sand", { tiles = {"nether_sand.png"}, is_ground_content = true, groups = {crumbly = 3, level = 2, falling_node = 1}, - sounds = default.node_sound_dirt_defaults({ + sounds = default.node_sound_gravel_defaults({ footstep = {name = "default_gravel_footstep", gain = 0.45}, }), }) @@ -374,7 +411,8 @@ minetest.register_node("nether:glowstone", { description = "Glowstone", tiles = {"nether_glowstone.png"}, is_ground_content = true, - light_source = 13, + light_source = 14, + paramtype = "light", groups = {cracky = 3, oddly_breakable_by_hand = 3}, sounds = default.node_sound_glass_defaults(), }) @@ -382,6 +420,7 @@ minetest.register_node("nether:glowstone", { minetest.register_node("nether:brick", { description = "Nether Brick", tiles = {"nether_brick.png"}, + is_ground_content = false, groups = {cracky = 2, level = 2}, sounds = default.node_sound_stone_defaults(), }) @@ -402,7 +441,7 @@ minetest.register_node("nether:fence_nether_brick", { type = "fixed", fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7}, }, - groups = {cracky = 3, level = 2}, + groups = {cracky = 2, level = 2}, sounds = default.node_sound_stone_defaults(), }) @@ -412,7 +451,7 @@ minetest.register_node("nether:fence_nether_brick", { stairs.register_stair_and_slab( "nether_brick", "nether:brick", - {cracky = 3, oddly_breakable_by_hand = 1}, + {cracky = 2, level = 2}, {"nether_brick.png"}, "nether stair", "nether slab", @@ -441,18 +480,15 @@ minetest.register_craftitem(":default:mese_crystal_fragment", { -- Crafting minetest.register_craft({ - output = "nether:brick", - type = "shapeless", + output = "nether:brick 4", recipe = { - "nether:rack", - "nether:rack", - "nether:rack", - "nether:rack", - }, + {"nether:rack", "nether:rack"}, + {"nether:rack", "nether:rack"}, + } }) minetest.register_craft({ - output = "nether:fence_nether_brick 16", + output = "nether:fence_nether_brick 6", recipe = { {"nether:brick", "nether:brick", "nether:brick"}, {"nether:brick", "nether:brick", "nether:brick"}, @@ -462,61 +498,141 @@ minetest.register_craft({ -- Mapgen -local air = minetest.get_content_id("air") -local stone_with_coal = minetest.get_content_id("default:stone_with_coal") -local stone_with_iron = minetest.get_content_id("default:stone_with_iron") -local stone_with_mese = minetest.get_content_id("default:stone_with_mese") -local stone_with_diamond = minetest.get_content_id("default:stone_with_diamond") -local stone_with_gold = minetest.get_content_id("default:stone_with_gold") -local stone_with_copper = minetest.get_content_id("default:stone_with_copper") -local gravel = minetest.get_content_id("default:gravel") -local dirt = minetest.get_content_id("default:dirt") -local sand = minetest.get_content_id("default:sand") -local cobble = minetest.get_content_id("default:cobble") -local mossycobble = minetest.get_content_id("default:mossycobble") -local stair_cobble = minetest.get_content_id("stairs:stair_cobble") -local lava_source = minetest.get_content_id("default:lava_source") -local lava_flowing = minetest.get_content_id("default:lava_flowing") +-- Initialize noise object and localise noise buffer -local glowstone = minetest.get_content_id("nether:glowstone") -local nethersand = minetest.get_content_id("nether:sand") -local netherbrick = minetest.get_content_id("nether:brick") -local netherrack = minetest.get_content_id("nether:rack") +local nobj_cave = nil +local nbuf_cave + + +-- Content ids + +local c_air = minetest.get_content_id("air") + +local c_stone_with_coal = minetest.get_content_id("default:stone_with_coal") +local c_stone_with_iron = minetest.get_content_id("default:stone_with_iron") +local c_stone_with_mese = minetest.get_content_id("default:stone_with_mese") +local c_stone_with_diamond = minetest.get_content_id("default:stone_with_diamond") +local c_stone_with_gold = minetest.get_content_id("default:stone_with_gold") +local c_stone_with_copper = minetest.get_content_id("default:stone_with_copper") +local c_mese = minetest.get_content_id("default:mese") + +local c_gravel = minetest.get_content_id("default:gravel") +local c_dirt = minetest.get_content_id("default:dirt") +local c_sand = minetest.get_content_id("default:sand") + +local c_cobble = minetest.get_content_id("default:cobble") +local c_mossycobble = minetest.get_content_id("default:mossycobble") +local c_stair_cobble = minetest.get_content_id("stairs:stair_cobble") + +local c_lava_source = minetest.get_content_id("default:lava_source") +local c_lava_flowing = minetest.get_content_id("default:lava_flowing") +local c_water_source = minetest.get_content_id("default:water_source") +local c_water_flowing = minetest.get_content_id("default:water_flowing") + +local c_glowstone = minetest.get_content_id("nether:glowstone") +local c_nethersand = minetest.get_content_id("nether:sand") +local c_netherbrick = minetest.get_content_id("nether:brick") +local c_netherrack = minetest.get_content_id("nether:rack") + + +-- On-generated function minetest.register_on_generated(function(minp, maxp, seed) - if maxp.y > NETHER_DEPTH then + if minp.y > NETHER_DEPTH then return end - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local data = vm:get_data() - local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} + local t1 = os.clock() - for vi in area:iterp(minp, maxp) do - local id = data[vi] - if id == air or - id == stone_with_coal or - id == stone_with_iron then - data[vi] = air - elseif id == stone_with_mese or - id == stone_with_diamond or - id == lava_source then - data[vi] = lava_source - elseif id == lava_flowing then - -- nothing - elseif id == stone_with_gold then - data[vi] = glowstone - elseif id == stone_with_copper or - id == gravel or - id == dirt or - id == sand then - data[vi] = nethersand - elseif id == cobble or - id == mossycobble or - id == stair_cobble then - data[vi] = netherbrick - else - data[vi] = netherrack + local x1 = maxp.x + local y1 = maxp.y + local z1 = maxp.z + local x0 = minp.x + local y0 = minp.y + local z0 = minp.z + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} + local data = vm:get_data() + + local x11 = emax.x -- Limits of mapchunk plus mapblock shell + local y11 = emax.y + local z11 = emax.z + local x00 = emin.x + local y00 = emin.y + local z00 = emin.z + + local ystride = x1 - x0 + 1 + local zstride = ystride * ystride + local chulens = {x = ystride, y = ystride, z = ystride} + local minposxyz = {x = x0, y = y0, z = z0} + + nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens) + local nvals_cave = nobj_cave:get3dMap_flat(minposxyz, nbuf_cave) + + for y = y00, y11 do -- Y loop first to minimise tcave calculations + local tcave + local in_chunk_y = false + if y >= y0 and y <= y1 then + if y > yblmax then + tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2 + else + tcave = TCAVE + end + in_chunk_y = true + end + + for z = z00, z11 do + local vi = area:index(x00, y, z) -- Initial voxelmanip index + local ni + local in_chunk_yz = in_chunk_y and z >= z0 and z <= z1 + + for x = x00, x11 do + if in_chunk_yz and x == x0 then + -- Initial noisemap index + ni = (z - z0) * zstride + (y - y0) * ystride + 1 + end + local in_chunk_yzx = in_chunk_yz and x >= x0 and x <= x1 -- In mapchunk + + local id = data[vi] -- Existing node + -- Cave air, cave liquids and dungeons are overgenerated, + -- convert these throughout mapchunk plus shell + if id == c_air or -- Air and liquids to air + id == c_lava_source or + id == c_lava_flowing or + id == c_water_source or + id == c_water_flowing then + data[vi] = c_air + -- Dungeons are preserved so we don't need + -- to check for cavern in the shell + elseif id == c_cobble or -- Dungeons (preserved) to netherbrick + id == c_mossycobble or + id == c_stair_cobble then + data[vi] = c_netherbrick + end + + if in_chunk_yzx then -- In mapchunk + if nvals_cave[ni] > tcave then -- Only excavate cavern in mapchunk + data[vi] = c_air + elseif id == c_mese then -- Mese block to lava + data[vi] = c_lava_source + elseif id == c_stone_with_gold or -- Precious ores to glowstone + id == c_stone_with_mese or + id == c_stone_with_diamond then + data[vi] = c_glowstone + elseif id == c_gravel or -- Blob ore to nethersand + id == c_dirt or + id == c_sand then + data[vi] = c_nethersand + else -- All else to netherstone + data[vi] = c_netherrack + end + + ni = ni + 1 -- Only increment noise index in mapchunk + end + + vi = vi + 1 + end end end @@ -525,4 +641,7 @@ minetest.register_on_generated(function(minp, maxp, seed) vm:calc_lighting() vm:update_liquids() vm:write_to_map() + + local chugent = math.ceil((os.clock() - t1) * 1000) + print ("[nether] generate chunk " .. chugent .. " ms") end)