From 3008b167b208ea281deb64df623716415ac974b5 Mon Sep 17 00:00:00 2001 From: Treer Date: Tue, 2 Feb 2021 19:15:51 +1100 Subject: [PATCH] climate_api support - add distance fog Add more appropriate/atmosphere distance fog to the nether, via climate_api mod to avoid conflicting with other mods. Any game or server with climate_api mod installed will be expecting climate_api to take control of sky values. --- depends.txt | 1 + init.lua | 90 +++++++++++++++++++++++++++++++++++++- mapgen.lua | 16 ++++++- mapgen_mantle.lua | 107 ++++++++++++++++++++++++++++++---------------- mod.conf | 2 +- 5 files changed, 174 insertions(+), 42 deletions(-) diff --git a/depends.txt b/depends.txt index 00f426a..2ccaf36 100644 --- a/depends.txt +++ b/depends.txt @@ -6,3 +6,4 @@ fire? loot? mesecons? moreblocks? +climate_api? diff --git a/init.lua b/init.lua index c09234e..7d75ad1 100644 --- a/init.lua +++ b/init.lua @@ -42,12 +42,18 @@ end -- Global Nether namespace nether = {} +nether.mapgen = {} -- Shared Nether mapgen namespace, for mapgen files to expose functions and constants nether.modname = minetest.get_current_modname() nether.path = minetest.get_modpath(nether.modname) nether.get_translator = S -- nether.useBiomes allows other mods to know whether they can register ores etc. in the Nether. -- See mapgen.lua for an explanation of why minetest.read_schematic is being checked nether.useBiomes = minetest.get_mapgen_setting("mg_name") ~= "v6" and minetest.read_schematic ~= nil +nether.fogColor = { -- only used if climate_api is installed + netherCaverns = "#1D0504", -- Distance-fog colour for classic nether + mantle = "#070916", -- Distance-fog colour for the Mantle region + geodes = "#300530" -- Distance-fog colour for secondary region +} -- Settings @@ -227,7 +233,89 @@ The expedition parties have found no diamonds or gold, and after an experienced end }) -end + + + -- Set appropriate nether distance-fog if climate_api is available + -- + -- Delegating to a mod like climate_api means nether won't unexpectedly stomp on the sky of + -- any other mod. + -- Skylayer is another mod which can perform this role, and skylayer support could be added + -- here as well. However skylayer doesn't provide a position-based method of specifying sky + -- colours out-of-the-box, so the nether mod will have to monitor when players enter and + -- leave the nether. + if minetest.get_modpath("climate_api") and minetest.global_exists("climate_api") and climate_api.register_weather ~= nil then + + climate_api.register_influence( + "nether_biome", + function(pos) + local result = "surface" + + if pos.y <= nether.DEPTH_CEILING and pos.y >= nether.DEPTH_FLOOR then + result = "nether" + + if nether.mapgen.getRegion ~= nil then + -- the biomes-based mapgen supports 2 extra regions + local regions = nether.mapgen.RegionEnum + local region = nether.mapgen.getRegion(pos) + if region == regions.Center or region == regions.CenterShell then + result = "mantle" + elseif region == regions.Negative or region == regions.NegativeShell then + result = "geode" + end + end + end + + return result + end + ) + + -- using sky type "plain" unfortunately means we don't get smooth fading transitions when + -- the color of the sky changes, but it seems to be the only way to obtain a sky colour + -- which doesn't brighten during the daytime. + local undergroundSky = { + sky_data = { + base_color = nil, + type = "plain", + textures = nil, + clouds = false, + }, + sun_data = { + visible = false, + sunrise_visible = false + }, + moon_data = { + visible = false + }, + star_data = { + visible = false + } + } + + local netherSky, mantleSky, geodeSky = table.copy(undergroundSky), table.copy(undergroundSky), table.copy(undergroundSky) + netherSky.sky_data.base_color = nether.fogColor.netherCaverns + mantleSky.sky_data.base_color = nether.fogColor.mantle + geodeSky.sky_data.base_color = nether.fogColor.geodes + + climate_api.register_weather( + "nether:nether", + { nether_biome = "nether" }, + { ["climate_api:skybox"] = netherSky } + ) + + climate_api.register_weather( + "nether:mantle", + { nether_biome = "mantle" }, + { ["climate_api:skybox"] = mantleSky } + ) + + climate_api.register_weather( + "nether:geode", + { nether_biome = "geode" }, + { ["climate_api:skybox"] = geodeSky } + ) + end + +end -- end of "if nether.NETHER_REALM_ENABLED..." -- Play bubbling lava sounds if player killed by lava diff --git a/mapgen.lua b/mapgen.lua index 12b50ba..022b6e3 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -45,7 +45,6 @@ local BASALT_COLUMN_LOWER_LIMIT = CENTER_CAVERN_LIMIT * 0.25 -- This value -- Shared Nether mapgen namespace -- For mapgen files to share functions and constants -nether.mapgen = {} local mapgen = nether.mapgen mapgen.TCAVE = TCAVE -- const needed in mapgen_mantle.lua @@ -257,6 +256,19 @@ mapgen.np_cave = { --flags = "" } +local cavePointPerlin = nil + +mapgen.getCavePointPerlin = function() + cavePointPerlin = cavePointPerlin or minetest.get_perlin(mapgen.np_cave) + return cavePointPerlin +end + +mapgen.getCavePerlinAt = function(pos) + cavePointPerlin = cavePointPerlin or minetest.get_perlin(mapgen.np_cave) + return cavePointPerlin:get3d(pos) +end + + -- Buffers and objects we shouldn't recreate every on_generate local nobj_cave = nil @@ -658,7 +670,7 @@ end -- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. function nether.find_nether_ground_y(target_x, target_z, start_y, player_name) - local nobj_cave_point = minetest.get_perlin(mapgen.np_cave) + local nobj_cave_point = mapgen.getCavePointPerlin() local air = 0 -- Consecutive air nodes found local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, "nether_portal") diff --git a/mapgen_mantle.lua b/mapgen_mantle.lua index e453e19..aa20187 100644 --- a/mapgen_mantle.lua +++ b/mapgen_mantle.lua @@ -49,7 +49,6 @@ local np_basalt = { local nobj_basalt = nil local nbuf_basalt = {} -local cavePerlin = nil -- Content ids @@ -414,52 +413,84 @@ mapgen.excavate_tunnel_to_center_of_the_nether = function(data, area, nvals_cave end +-- an enumerated list of the different regions in the nether +mapgen.RegionEnum = { + Overworld = "overworld", -- Outside the Nether / none of the regions in the Nether + Positive = "positive", -- The classic nether caverns are here - where cavePerlin > 0.6 + PositiveShell = "positive shell", -- the nether side of the wall/buffer area separating classic nether from the mantle + Center = "center", -- The Mantle caverns are here + CenterShell = "center shell", -- the mantle side of the wall/buffer area separating the positive and negative regions from the center region + Negative = "negative", -- Secondary/spare region - where cavePerlin < -0.6 + NegativeShell = "negative shell", -- the spare region side of the wall/buffer area separating the negative region from the mantle +} + + +-- Returns (region, noise) where region is a value from mapgen.RegionEnum +-- and noise is the unadjusted cave perlin value +mapgen.getRegion = function(pos) + + if pos.y > nether.DEPTH_CEILING or pos.y < nether.DEPTH_FLOOR then + return mapgen.RegionEnum.Overworld, nil + end + + local caveNoise = mapgen.getCavePerlinAt(pos) + local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(pos.y) + local tcave_adj, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(pos.y) + local tcave = mapgen.TCAVE + tcave_adj + local tmantle = mapgen.CENTER_REGION_LIMIT + centerRegionLimit_adj + local cavern_noise_adj = + mapgen.CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - + centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj so subtract centerRegionLimit_adj instead of adding + + local region + if caveNoise > tcave then + region = mapgen.RegionEnum.Positive + elseif -caveNoise > tcave then + region = mapgen.RegionEnum.Negative + elseif math_abs(caveNoise) < tmantle then + + if math_abs(caveNoise) + cavern_noise_adj < mapgen.CENTER_CAVERN_LIMIT then + region = mapgen.RegionEnum.Center + else + region = mapgen.RegionEnum.CenterShell + end + + elseif caveNoise > 0 then + region = mapgen.RegionEnum.PositiveShell + else + region = mapgen.RegionEnum.NegativeShell + end + + return region, caveNoise +end + + minetest.register_chatcommand("nether_whereami", - { + { description = "Describes which region of the nether the player is in", privs = {debug = true}, func = function(name, param) local player = minetest.get_player_by_name(name) if player == nil then return false, "Unknown player position" end + local playerPos = vector.round(player:get_pos()) - local pos = vector.round(player:get_pos()) - if pos.y > nether.DEPTH_CEILING or pos.y < nether.DEPTH_FLOOR then - return true, "The Overworld" - end + local region, caveNoise = mapgen.getRegion(playerPos) + local seaLevel, cavernLimitDistance = mapgen.find_nearest_lava_sealevel(playerPos.y) + local tcave_adj, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(playerPos.y) - cavePerlin = cavePerlin or minetest.get_perlin(mapgen.np_cave) - local densityNoise = cavePerlin:get_3d(pos) - local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(pos.y) - local tcave_adj, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(pos.y) - local tcave = mapgen.TCAVE + tcave_adj - local tmantle = mapgen.CENTER_REGION_LIMIT + centerRegionLimit_adj - local cavern_noise_adj = - mapgen.CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - - centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj so subtract centerRegionLimit_adj instead of adding + local regionLabels = { + [mapgen.RegionEnum.Overworld] = "The Overworld", + [mapgen.RegionEnum.Positive] = "Positive nether", + [mapgen.RegionEnum.PositiveShell] = "Shell between positive nether and center region", + [mapgen.RegionEnum.Center] = "Center/Mantle, inside cavern", + [mapgen.RegionEnum.CenterShell] = "Center/Mantle, but outside the caverns", + [mapgen.RegionEnum.Negative] = "Negative nether", + [mapgen.RegionEnum.NegativeShell] = "Shell between negative nether and center region" + } + local desc = regionLabels[region] - local desc - - if densityNoise > tcave then - desc = "Positive nether" - elseif -densityNoise > tcave then - desc = "Negative nether" - elseif math_abs(densityNoise) < tmantle then - desc = "Mantle" - - if math_abs(densityNoise) + cavern_noise_adj < mapgen.CENTER_CAVERN_LIMIT then - desc = desc .. " inside cavern" - else - desc = desc .. " but outside cavern" - end - - elseif densityNoise > 0 then - desc = "Shell between positive nether and center region" - else - desc = "Shell between negative nether and center region" - end - - local sea_pos = pos.y - sea_level + local sea_pos = playerPos.y - seaLevel if sea_pos > 0 then desc = desc .. ", " .. sea_pos .. "m above lava-sea level" else @@ -470,7 +501,7 @@ minetest.register_chatcommand("nether_whereami", desc = desc .. ", approaching y boundary of Nether" end - return true, "[Perlin " .. (math_floor(densityNoise * 1000) / 1000) .. "] " .. desc + return true, "[Perlin " .. (math_floor(caveNoise * 1000) / 1000) .. "] " .. desc end } ) diff --git a/mod.conf b/mod.conf index 5b6c73a..84a7a01 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,4 @@ name = nether description = Adds a deep underground realm with different mapgen that you can reach with obsidian portals. depends = stairs, default -optional_depends = moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire +optional_depends = moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire, climate_api