From b0093461a5b4abc1dadd4155c2578f7131c52127 Mon Sep 17 00:00:00 2001 From: evrooije Date: Sun, 22 Jul 2018 14:24:43 +0200 Subject: [PATCH] Completely different approach to the underground lighting problem as per paramat's recommendation a temporary "shadow caster" layer is written above the chunk when underground relative to the current layer. This works perfectly and lighting works properly while at the same time it is calculated by the engine. A major change in the API was however necessary to limit memory usage. The VM, are and VM data are now initialized in the multi_map core, and passed on to the generators as otherwise multiple data arrays were created (one for the shadow caster, one of the generator, one to remove the shadow caster again) and multiple calls to set_data and write_to_map... This is also much better in case generators are chained (i.e. multiple generators being called within a single mapgen on_generated call) --- multi_map_core/init.lua | 63 +++++++++++++++++++++++++-- multi_map_generators/mmgen_levels.lua | 24 +--------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/multi_map_core/init.lua b/multi_map_core/init.lua index 21a6bb4..e01d873 100644 --- a/multi_map_core/init.lua +++ b/multi_map_core/init.lua @@ -143,6 +143,17 @@ function multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, content_ end end +-- Helper to create a 1 node high plane on the specified y +function multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, y, content_id) + for z = minp.z, maxp.z do + local vi = area:index(minp.x, y, z) + for x = minp.x, maxp.x do + vm_data[vi] = content_id + vi = vi + 1 + end + end +end + local firstrun = true -- Global helpers for mapgens multi_map.c_ignore = nil @@ -153,6 +164,7 @@ multi_map.c_water = nil multi_map.c_lava = nil multi_map.c_bedrock = nil multi_map.c_skyrock = nil +multi_map.c_shadow_caster = nil minetest.register_on_mapgen_init(function(mapgen_params) if multi_map.number_of_layers * multi_map.layer_height > multi_map.map_height then @@ -171,6 +183,7 @@ minetest.register_on_generated(function(minp, maxp) multi_map.c_lava = minetest.get_content_id("default:lava_source") multi_map.c_bedrock = minetest.get_content_id(multi_map.bedrock) multi_map.c_skyrock = minetest.get_content_id(multi_map.skyrock) + multi_map.c_shadow_caster = minetest.get_content_id("multi_map_core:shadow_caster") firstrun = false end @@ -192,6 +205,7 @@ minetest.register_on_generated(function(minp, maxp) local vm_data = vm:get_data() multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, multi_map.c_bedrock) + vm:set_data(vm_data) vm:calc_lighting(false) vm:write_to_map(false) @@ -205,25 +219,55 @@ minetest.register_on_generated(function(minp, maxp) local vm_data = vm:get_data() multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, multi_map.c_skyrock) + vm:set_lighting({day=15, night=0}) vm:set_data(vm_data) vm:calc_lighting(false) vm:write_to_map(false) else + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) + local vm_data = vm:get_data() + local remove_shadow_caster = false + + -- Add a temporary stone layer above the chunk to ensure caves are dark + if multi_map.get_absolute_centerpoint() >= maxp.y then + if vm_data[area:index(minp.x, maxp.y + 1, minp.z)] == multi_map.c_ignore then + remove_shadow_caster = true + multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, maxp.y + 1, multi_map.c_shadow_caster) + end + end + local t = multi_map.generators[multi_map.current_layer] if not t then if multi_map.fallback_generator then - multi_map.fallback_generator.generator(multi_map.current_layer, minp, maxp, offset_minp, offset_maxp, multi_map.fallback_generator.arguments) + multi_map.fallback_generator.generator(multi_map.current_layer, vm, area, vm_data, minp, maxp, offset_minp, offset_maxp, multi_map.fallback_generator.arguments) else minetest.log("error", "Generator for layer "..multi_map.current_layer.." missing and no fallback specified, exiting mapgen!") return end else for i,f in ipairs(t) do - f.generator(multi_map.current_layer, minp, maxp, offset_minp, offset_maxp, f.arguments) + f.generator(multi_map.current_layer, vm, area, vm_data, minp, maxp, offset_minp, offset_maxp, f.arguments) end end + + vm:set_data(vm_data) + vm:calc_lighting() + vm:write_to_map() + vm:update_liquids() + + -- Remove the temporary stone shadow casting layer again, if needed + if remove_shadow_caster then + if vm_data[area:index(minp.x, maxp.y + 1, minp.z)] == multi_map.c_shadow_caster then + + multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, maxp.y + 1, multi_map.c_ignore) + vm:set_data(vm_data) + vm:write_to_map() + end + end + end end) @@ -239,6 +283,17 @@ minetest.register_node("multi_map_core:skyrock", { paramtype = "light", }) +minetest.register_node("multi_map_core:shadow_caster", { + description = "Multi Map Shadow Caster", + drawtype = "airlike", + is_ground_content = false, + sunlight_propagates = false, + walkable = false, + pointable = false, + diggable = false, + climbable = false, +}) + minetest.register_node("multi_map_core:bedrock", { description = "Multi Map Impenetrable Bedrock", drawtype = "normal", @@ -250,7 +305,7 @@ minetest.register_node("multi_map_core:bedrock", { climbable = false, }) - +--[[ function multi_map.calc_lighting(emin, emax, minp, maxp, propagate_shadow, ground_level) local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") multi_map.propagate_sunlight(vm, emin, emax, propagate_shadow, ground_level) @@ -312,7 +367,7 @@ function BitAND(a,b)--Bitwise and end return c end - +]]-- --[[ VoxelArea a(nmin, nmax); diff --git a/multi_map_generators/mmgen_levels.lua b/multi_map_generators/mmgen_levels.lua index 49bccbd..fdbdf2f 100644 --- a/multi_map_generators/mmgen_levels.lua +++ b/multi_map_generators/mmgen_levels.lua @@ -99,7 +99,7 @@ local nobj_spike = nil -- On generated function -function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_maxp) +function mmgen_levels.generate(current_layer, vm, area, data, minp, maxp, offset_minp, offset_maxp) local x1 = maxp.x local y1 = maxp.y local z1 = maxp.z @@ -109,11 +109,6 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma local oy1 = offset_maxp.y local oy0 = offset_minp.y - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} - local data = vm:get_data() - local light_data = vm:get_light_data() - local c_stone = minetest.get_content_id("default:stone") local c_sand = minetest.get_content_id("default:sand") local c_water = minetest.get_content_id("default:water_source") @@ -233,14 +228,6 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma end end --- if relative_y < 0 then --- if relative_y > -15 then --- light_data[vi] = 15 + relative_y --- else --- light_data[vi] = 0 --- end --- end - ni3d = ni3d + 1 ni2d = ni2d + 1 vi = vi + 1 @@ -251,13 +238,4 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma ni2d = ni2d + sidelen end - vm:set_data(data) --- vm:set_light_data(light_data) --- if oy0 < 0 then --- vm:set_lighting({day=0, night=0}) --- end - multi_map.calc_lighting(minp, maxp, minp, maxp, true) - vm:write_to_map() - vm:update_liquids() - end