-- Variables local realm = { flat = false, -- Normal flat realm vertical = false, -- Vertical flat realm facing south invert = false, -- Inverted flat realm planet = true, -- Planet sphere dysonsphere = false, -- Dyson sphere tube = false, -- East-West tube world / O'Neill space colony cube = false, -- Planet cube dysoncube = false, -- Dyson cube } local TERRS = 64 -- Terrain scale for all realms below -- Normal and inverted flat realms local FLATY = 0 -- Surface y -- Vertical flat realm facing south local VERTZ = 0 -- Surface z -- Planet sphere and dyson sphere local SPHEX = 0 -- Centre x local SPHEZ = 0 -- ..z local SPHEY = 0 -- ..y local SPHER = 512 -- Surface radius -- Tube world local TUBEZ = 0 -- Axis z local TUBEY = 0 -- ..y local TUBER = 256 -- Surface radius local TUBEX = 4000 -- Endcap base +-x local TUBED = 256 -- Endcap dish depth -- Planet cube and dyson cube local CUBEX = 0 -- Centre x local CUBEZ = 0 -- ..z local CUBEY = 0 -- ..y local CUBER = 256 -- Surface radius -- Noise thresholds for density gradient 'grad' local TLAVA = 4 -- Lava core density threshold local ROCK = -1 -- Rocky terrain density threshold local CLOLOT = -0.9 -- Cloud low density threshold local CLOHIT = -0.89 -- Cloud high density threshold -- Noise thresholds for density field 'density' TODO (auto?) tune these local TSAND = -0.04 -- Sand density threshold local TSTONE = 0.1 -- Stone density threshold at sea level local TDIRT = 0.05 -- Dirt density threshold local TSURF = 0.03 -- Surface density threshold for flora generation -- Other parameters local TFIS = 0.01 -- Fissure width noise threshold local OCHA = 7 * 7 * 7 -- Ore 1/x chance per stone node local TCLOUD = 0.5 -- Cloud threshold, -2 = overcast, 2 = no cloud local flora = { APPCHA = 128, -- Apple tree maximum 1/x chance per surface node FLOCHA = 64, -- Flower 1/x chance per surface node GRACHA = 8, -- Grass 1/x chance per surface node CACCHA = 256, -- Cactus 1/x chance per surface node DSHCHA = 128, -- Dry shrub 1/x chance per surface node } -- Noise parameters -- 3D noise for rough terrain local np_terrain = { offset = 0, scale = 1, spread = {x = 96, y = 96, z = 96}, seed = 92, octaves = 3, persist = 0.67 } -- 3D noise for smooth terrain local np_smooth = { offset = 0, scale = 0.5, spread = {x = 192, y = 192, z = 192}, seed = 800911, octaves = 3, persist = 0.4 } -- 3D noise for terrain blend local np_terblen = { offset = 0, scale = 1, spread = {x = 192, y = 192, z = 192}, seed = -440002, octaves = 1, persist = 0.4 } -- 3D noise for temperature local np_temp = { offset = 0, scale = 1, spread = {x = 384, y = 384, z = 384}, seed = 9130, octaves = 2, persist = 0.4 } -- 3D noise for fissures local np_fissure = { offset = 0, scale = 1, spread = {x = 192, y = 192, z = 192}, seed = 108881, octaves = 3, persist = 0.5 } -- 3D noise for clouds local np_cloud = { offset = 0, scale = 1, spread = {x = 192, y = 192, z = 192}, seed = 2113, octaves = 4, persist = 0.7 } -- Do files dofile(minetest.get_modpath("flexrealm") .. "/nodes.lua") dofile(minetest.get_modpath("flexrealm") .. "/functions.lua") -- Mapgen parameters minetest.set_mapgen_params({mgname = "singlenode", flags = "nolight", water_level = -31000}) -- Initialize noise objects to nil local nobj_terrain = nil local nobj_smooth = nil local nobj_terblen = nil local nobj_fissure = nil local nobj_temp = nil local nobj_cloud = nil -- Localise noise buffers local nbuf_terrain local nbuf_smooth local nbuf_terblen local nbuf_fissure local nbuf_temp local nbuf_cloud -- On generated function minetest.register_on_generated(function(minp, maxp, seed) local t0 = os.clock() local x0 = minp.x local y0 = minp.y local z0 = minp.z local x1 = maxp.x local y1 = maxp.y local z1 = maxp.z local c_air = minetest.get_content_id("air") local c_meseblock = minetest.get_content_id("default:mese_block") local c_stodiam = minetest.get_content_id("default:stone_with_diamond") local c_stogold = minetest.get_content_id("default:stone_with_gold") local c_stocopp = minetest.get_content_id("default:stone_with_copper") local c_stoiron = minetest.get_content_id("default:stone_with_iron") local c_stocoal = minetest.get_content_id("default:stone_with_coal") local c_snowblock = minetest.get_content_id("default:snowblock") local c_ice = minetest.get_content_id("default:ice") local c_sastone = minetest.get_content_id("default:sandstone") local c_flrdirt = minetest.get_content_id("flexrealm:dirt") local c_flrgrass = minetest.get_content_id("flexrealm:grass") local c_flrsand = minetest.get_content_id("flexrealm:sand") local c_flrdesand = minetest.get_content_id("flexrealm:desand") local c_flrstone = minetest.get_content_id("flexrealm:stone") local c_flrdestone = minetest.get_content_id("flexrealm:destone") local c_flrcloud = minetest.get_content_id("flexrealm:cloud") local c_flrperfrost = minetest.get_content_id("flexrealm:perfrost") local c_flrwatzero = minetest.get_content_id("flexrealm:watzero") local c_flrlavazero = minetest.get_content_id("flexrealm:lavazero") local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} local data = vm:get_data() local p2data = vm:get_param2_data() local sidelen = x1 - x0 + 1 local facearea = sidelen ^ 2 local chulens = {x = sidelen, y = sidelen, z = sidelen} local minpos = {x = x0, y = y0, z = z0} nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, chulens) nobj_smooth = nobj_smooth or minetest.get_perlin_map(np_smooth, chulens) nobj_terblen = nobj_terblen or minetest.get_perlin_map(np_terblen, chulens) nobj_fissure = nobj_fissure or minetest.get_perlin_map(np_fissure, chulens) nobj_temp = nobj_temp or minetest.get_perlin_map(np_temp, chulens) nobj_cloud = nobj_cloud or minetest.get_perlin_map(np_cloud, chulens) local nvals_terrain = nobj_terrain:get3dMap_flat(minpos, nbuf_terrain) local nvals_smooth = nobj_smooth:get3dMap_flat(minpos, nbuf_smooth) local nvals_terblen = nobj_terblen:get3dMap_flat(minpos, nbuf_terblen) local nvals_fissure = nobj_fissure:get3dMap_flat(minpos, nbuf_fissure) local nvals_temp = nobj_temp:get3dMap_flat(minpos, nbuf_temp) local nvals_cloud = nobj_cloud:get3dMap_flat(minpos, nbuf_cloud) local ni = 1 for z = z0, z1 do for y = y0, y1 do local vi = area:index(x0, y, z) for x = x0, x1 do local nodid = data[vi] -- noise gradient local grad, sphexr, spheyr, sphezr, tubeyr, tubezr, cubexr, cubeyr, cubezr if realm.flat then grad = (FLATY - y) / TERRS elseif realm.vertical then grad = (z - VERTZ) / TERRS elseif realm.invert then grad = (y - FLATY) / TERRS elseif realm.planet or realm.dysonsphere then sphexr = x - SPHEX spheyr = y - SPHEY sphezr = z - SPHEZ local nodrad = math.sqrt(sphexr ^ 2 + spheyr ^ 2 + sphezr ^ 2) if realm.dysonsphere then grad = (nodrad - SPHER) / TERRS else grad = (SPHER - nodrad) / TERRS end elseif realm.tube then tubeyr = y - TUBEY tubezr = z - TUBEZ local nodrad = math.sqrt(tubeyr ^ 2 + tubezr ^ 2) grad = (nodrad - TUBER) / TERRS elseif realm.cube or realm.dysoncube then cubexr = x - CUBEX cubeyr = y - CUBEY cubezr = z - CUBEZ local noddis = math.max(math.abs(cubexr), math.abs(cubeyr), math.abs(cubezr)) if realm.dysoncube then grad = (noddis - CUBER) / TERRS else grad = (CUBER - noddis) / TERRS end end -- terrain blend local n_terblen = nvals_terblen[ni] local terblen = math.min(math.max(n_terblen + 0.5, 0), 1) local terno = nvals_terrain[ni] * (1 - terblen) + nvals_smooth[ni] * terblen if grad > 0 then -- make oceans shallower terno = terno / 2 end -- density field local density if realm.tube then if math.abs(x) > TUBEX then -- endcaps local wall = ((math.abs(x) - TUBEX) / TUBED) ^ 2 * TUBER / TERRS density = terno + grad + wall else density = terno + grad end else density = terno + grad end -- thin fine materials with altitude local tstone = TSTONE * (1 - grad / ROCK) local altprop = math.max(1 + grad, 0) -- get biome local desert = false -- desert biome local grassland = false -- grassland biome local forest = false -- deciduous forest biome local tundra = false -- tundra biome local temp = nvals_temp[ni] + grad if density > 0 or grad > 0 then -- if terrain or water calculate biome if temp > 0.4 then desert = true elseif temp > 0.0 then grassland = true elseif temp > -0.4 then forest = true else tundra = true end end -- caves boolean local nofis = math.abs(nvals_fissure[ni]) > TFIS -- if surface node away from chunk boundary get up direction for flora local surf = false if density <= TSURF -- surface node and x > x0 and x < x1 and y > y0 and y < y1 and z > z0 and z < z1 then surf = true end -- get up direction at point -- nodrot 0 = y+, 12 = x+, 16 = x-, 4 = z+, 8 = z-, 20 = y- local nodrot = 0 if surf then if realm.flat then nodrot = 0 elseif realm.vertical then nodrot = 8 elseif realm.invert then nodrot = 20 elseif realm.planet then if spheyr > math.abs(sphexr) and spheyr > math.abs(sphezr) then nodrot = 0 elseif spheyr < -math.abs(sphexr) and spheyr < -math.abs(sphezr) then nodrot = 20 elseif sphexr > math.abs(spheyr) and sphexr > math.abs(sphezr) then nodrot = 12 elseif sphexr < -math.abs(spheyr) and sphexr < -math.abs(sphezr) then nodrot = 16 elseif sphezr > math.abs(sphexr) and sphezr > math.abs(spheyr) then nodrot = 4 elseif sphezr < -math.abs(sphexr) and sphezr < -math.abs(spheyr) then nodrot = 8 end elseif realm.dysonsphere then if spheyr > math.abs(sphexr) and spheyr > math.abs(sphezr) then nodrot = 20 elseif spheyr < -math.abs(sphexr) and spheyr < -math.abs(sphezr) then nodrot = 0 elseif sphexr > math.abs(spheyr) and sphexr > math.abs(sphezr) then nodrot = 16 elseif sphexr < -math.abs(spheyr) and sphexr < -math.abs(sphezr) then nodrot = 12 elseif sphezr > math.abs(sphexr) and sphezr > math.abs(spheyr) then nodrot = 8 elseif sphezr < -math.abs(sphexr) and sphezr < -math.abs(spheyr) then nodrot = 4 end elseif realm.tube then if tubeyr > math.abs(tubezr) then nodrot = 20 elseif tubeyr < -math.abs(tubezr) then nodrot = 0 elseif tubezr > math.abs(tubeyr) then nodrot = 8 elseif tubezr < -math.abs(tubeyr) then nodrot = 4 end elseif realm.cube then if cubeyr > math.abs(cubexr) and cubeyr > math.abs(cubezr) then nodrot = 0 elseif cubeyr < -math.abs(cubexr) and cubeyr < -math.abs(cubezr) then nodrot = 20 elseif cubexr > math.abs(cubeyr) and cubexr > math.abs(cubezr) then nodrot = 12 elseif cubexr < -math.abs(cubeyr) and cubexr < -math.abs(cubezr) then nodrot = 16 elseif cubezr > math.abs(cubexr) and cubezr > math.abs(cubeyr) then nodrot = 4 elseif cubezr < -math.abs(cubexr) and cubezr < -math.abs(cubeyr) then nodrot = 8 end elseif realm.dysoncube then if cubeyr > math.abs(cubexr) and cubeyr > math.abs(cubezr) then nodrot = 20 elseif cubeyr < -math.abs(cubexr) and cubeyr < -math.abs(cubezr) then nodrot = 0 elseif cubexr > math.abs(cubeyr) and cubexr > math.abs(cubezr) then nodrot = 16 elseif cubexr < -math.abs(cubeyr) and cubexr < -math.abs(cubezr) then nodrot = 12 elseif cubezr > math.abs(cubexr) and cubezr > math.abs(cubeyr) then nodrot = 8 elseif cubezr < -math.abs(cubexr) and cubezr < -math.abs(cubeyr) then nodrot = 4 end end end -- mapgen if grad >= TLAVA and realm.planet or realm.cube then -- lava core data[vi] = c_flrlavazero elseif density >= tstone and nofis then -- stone if (density >= 0.5 and density <= 0.55) or (density >= 0.3 and density <= 0.4) or (density >= 0.2 and density <= 0.25) then data[vi] = c_sastone elseif desert then data[vi] = c_flrdestone elseif math.random(OCHA) == 2 and density >= TSTONE then -- ores local osel = math.random(34) if osel == 34 then data[vi] = c_meseblock elseif osel >= 31 then data[vi] = c_stodiam elseif osel >= 28 then data[vi] = c_stogold elseif osel >= 19 then data[vi] = c_stocopp elseif osel >= 10 then data[vi] = c_stoiron else data[vi] = c_stocoal end else data[vi] = c_flrstone end elseif density > 0 and density < tstone then -- fine materials if grad >= TSAND then data[vi] = c_flrsand -- sand elseif nofis or (not nofis and grad > TSAND) then -- fine materials cut by fissures above sand level only if density >= TDIRT then if desert then data[vi] = c_flrdesand elseif tundra then data[vi] = c_flrperfrost else data[vi] = c_flrdirt end else -- else surface nodes if tundra then data[vi] = c_snowblock elseif forest then data[vi] = c_flrgrass if surf and math.random(flora.APPCHA) == 2 then flexrealm_appletree(x, y, z, nodrot, area, data, p2data) elseif surf and math.random(flora.FLOCHA) == 2 then flexrealm_flower(x, y, z, nodrot, area, data, p2data) elseif surf and math.random(flora.GRACHA) == 2 then flexrealm_grass(x, y, z, nodrot, area, data, p2data) end elseif grassland then data[vi] = c_flrgrass if surf and math.random(flora.GRACHA) == 2 then flexrealm_grass(x, y, z, nodrot, area, data, p2data) elseif surf and math.random(flora.FLOCHA) == 2 then flexrealm_flower(x, y, z, nodrot, area, data, p2data) end elseif desert then data[vi] = c_flrdesand if surf and math.random(flora.CACCHA) == 2 then flexrealm_cactus(x, y, z, nodrot, area, data, p2data) elseif surf and math.random(flora.DSHCHA) == 2 then flexrealm_dryshrub(x, y, z, nodrot, area, data, p2data) end end end end elseif temp < -0.6 and grad > 0 and grad <= 0.05 and density <= 0 then -- sea ice if nodid == c_air then data[vi] = c_ice end elseif grad > 0 and density <= 0 then -- sea water if nodid == c_air then data[vi] = c_flrwatzero end elseif grad >= CLOLOT and grad <= CLOHIT then -- clouds local xrq = 16 * math.floor((x - x0) / 16) local yrq = 16 * math.floor((y - y0) / 16) local zrq = 16 * math.floor((z - z0) / 16) local qixyz = zrq * facearea + yrq * sidelen + xrq + 1 if nvals_cloud[qixyz] > TCLOUD then data[vi] = c_flrcloud end end ni = ni + 1 vi = vi + 1 end end end vm:set_data(data) vm:set_param2_data(p2data) vm:calc_lighting() vm:write_to_map(data) local chugent = math.ceil((os.clock() - t0) * 1000) print ("[flexrealm] " .. chugent) end)