diff --git a/mods/lzr_globals/init.lua b/mods/lzr_globals/init.lua index 53f8df75..79b73f9f 100644 --- a/mods/lzr_globals/init.lua +++ b/mods/lzr_globals/init.lua @@ -25,10 +25,6 @@ lzr_globals.MENU_SHIP_EDITOR_OFFSET = vector.new(13, 10, 31) lzr_globals.MENU_SHIP_SPEAKER_OFFSET = vector.new(6, 9, 25) lzr_globals.MENU_SHIP_TELEVISION_OFFSET = vector.new(5, 9, 25) lzr_globals.MENU_PLAYER_SPAWN_POS = vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_SPAWN_OFFSET) -lzr_globals.WATER_LEVEL = 1 -lzr_globals.SEABED_LEVEL = -1000 -lzr_globals.SEASTONE_LEVEL = -1002 -lzr_globals.DEEP_OCEAN_Z = -20000 lzr_globals.GRAVITY = tonumber(minetest.settings:get("movement_gravity")) or 9.81 lzr_globals.LASER_GLOW = 3 lzr_globals.LASER_ALPHA = 0x8E @@ -38,6 +34,10 @@ lzr_globals.PARROT_SPAWN_OFFSET = vector.new(0, 0.01, 0) lzr_globals.MAX_RECEIVER_RECALLS = 5 +-- WARNING: This value is duplicated in lzr_mapgen. +-- Only change this value when also changing lzr_mapgen! +lzr_globals.DEEP_OCEAN_Z = -20000 + -- Maximum number of nodes the player can see. We do this because -- the map is segmented in multiple zones (e.g. islands, deep ocean) -- with visible seams. By making sure the player is always far enough diff --git a/mods/lzr_levels/init.lua b/mods/lzr_levels/init.lua index 43061e2b..6aff6a39 100644 --- a/mods/lzr_levels/init.lua +++ b/mods/lzr_levels/init.lua @@ -370,7 +370,7 @@ function lzr_levels.reset_area(clear, start_pos, size, start_pos_protected, size aprot_min, aprot_max) else lzr_mapgen.generate_piece(start_pos, vector.add(start_pos, size), - false, aprot_min, aprot_max) + nil, aprot_min, aprot_max) end -- Also clear objects diff --git a/mods/lzr_mapgen/islands_decorations.lua b/mods/lzr_mapgen/decorations.lua similarity index 100% rename from mods/lzr_mapgen/islands_decorations.lua rename to mods/lzr_mapgen/decorations.lua diff --git a/mods/lzr_mapgen/init.lua b/mods/lzr_mapgen/init.lua index 20557917..bea85508 100644 --- a/mods/lzr_mapgen/init.lua +++ b/mods/lzr_mapgen/init.lua @@ -20,6 +20,11 @@ lzr_mapgen.get_backdrop_description = function(id) return backdrop_descriptions[id] end +dofile(minetest.get_modpath("lzr_mapgen").."/settings.lua") dofile(minetest.get_modpath("lzr_mapgen").."/aliases.lua") -dofile(minetest.get_modpath("lzr_mapgen").."/islands.lua") -dofile(minetest.get_modpath("lzr_mapgen").."/islands_decorations.lua") +dofile(minetest.get_modpath("lzr_mapgen").."/decorations.lua") + +-- The mapgen script will both run in the global environment +-- and the mapgen environment. See mapgen.lua to learn why. +dofile(minetest.get_modpath("lzr_mapgen").."/mapgen.lua") +minetest.register_mapgen_script(minetest.get_modpath("lzr_mapgen").."/mapgen.lua") diff --git a/mods/lzr_mapgen/islands.lua b/mods/lzr_mapgen/mapgen.lua similarity index 63% rename from mods/lzr_mapgen/islands.lua rename to mods/lzr_mapgen/mapgen.lua index 4c12257f..adfe4fe7 100644 --- a/mods/lzr_mapgen/islands.lua +++ b/mods/lzr_mapgen/mapgen.lua @@ -1,3 +1,68 @@ +-- The main mapgen code. + +--[[ THIS FILE WILL BE RUN TWICE! +1) In the global Minetest environment, +2) In the heavily-restricted threaded mapgen environment + +This means this file is very restricted and only has +access to functions that are available in both the +global and the mapgen environment. Refer to Minetest's +Lua API documentation for details. + +In the global environment, this file runs to expose the +function lzr_mapgen.generate_piece, but it does not call +minetest.register_on_generated. + +In the mapgen environment, it uses +minetest.register_on_generated, but it does not modify +the global environment. + +The reason this file is called twice is to avoid code +duplication. +]] + +-- This variable will be true when we're in the mapgen +-- environment. The mapgen environment does not have +-- access to global variables, so if lzr_mapgen does +-- not exist, we can decude we must be the mapgen +-- environment. +local IS_IN_MAPGEN_ENVIRONMENT = not minetest.global_exists("lzr_mapgen") + + +--[[ MAPGEN OVERVIEW: +The mapgen has two main zones: + +Deep Ocean: The Deep Ocean is a very simple zone and very fast +to generate, it's just a flat layer of water with a flat seabed +way below the surface. Perfect to spawn the ship in. + +Islands: Islands is a beautiful zone using 2D Perlin +noise, featuring tropical islands, palms, plants, hills, and +a “hilly” ocean floor. It is derived from the [islands] mod +by TheTermos, released under the MIT License in 2019. + +Both zones are separated on the Z axis by DEEP_OCEAN_Z. + +There is a hard ugly seam between both zones, so it is +important the game action happens far away from this +seam. +]] + + +-- Some basic values for mapgen coordinates + +-- Water will be at this Y level, all the way down to SEABED_LEVEL+1 +local WATER_LEVEL = 1 +-- The seabed will be at this Y level, all the way down to SEASTONE_LEVEL+1 (deep ocean only) +local SEABED_LEVEL = -1000 +-- The seastone will be at and below this Y level, all the way down to the bottom of the world (deep ocean only) +local SEASTONE_LEVEL = -1002 + +-- The deep ocean will begin when the Z coordinate is this value or lower. +-- WARNING: This value is duplicated in lzr_globals. +-- When you change it, you MUST also change it in lzr_globals! +local DEEP_OCEAN_Z = -20000 + local floor = math.floor local ceil = math.ceil local min = math.min @@ -94,22 +159,6 @@ local base_heightmap = {} local result_heightmap = {} --- Set singlenode mapgen (air nodes only). --- Disable the engine lighting calculation since that will be done for a --- mapchunk of air nodes and will be incorrect after we place nodes. - -minetest.set_mapgen_setting('mg_name', 'singlenode', true) -minetest.set_mapgen_setting('flags', 'nolight', true) -minetest.set_mapgen_setting('seed', '5436146057422610855', true) - -minetest.set_mapgen_setting("mg_biome_np_heat", - "90,0,(1000,1000,1000),5349,3,0.5,2", - true) - -minetest.set_mapgen_setting("mg_biome_np_humidity", - "54,10,(1000,1000,1000),5349,3,0.5,2", - true) - -- Get the content IDs for the nodes used. local c_stone = minetest.get_content_id("lzr_core:stone") @@ -147,29 +196,33 @@ local function get_terrain_height(theight,hheight,cheight) return theight end -lzr_mapgen.generate_piece = function(minp, maxp, is_on_generated, prot_min, prot_max) +-- Generate a piece of the map and set nodes in the specified area. +-- * minp: Minimum position of the area +-- * maxp: Maximum position of the area +-- * vm: VoxelManip object (only required when calling this function in the mapgen environment. Set to nil otherwise) +-- * prot_min: Minimum position of protected area. The protected area will NOT be overwritten by this function +-- * prot_min: Maximum position of protected area +local generate_piece = function(minp, maxp, vm, prot_min, prot_max) local sidelen_x = maxp.x - minp.x + 1 local sidelen_z = maxp.z - minp.z + 1 local permapdims3d = {x = sidelen_x, y = sidelen_z} - local clear = is_on_generated ~= true + local clear = IS_IN_MAPGEN_ENVIRONMENT ~= true -- voxelmanip stuff - local vm, emin, emax - if is_on_generated then - vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - else + if not vm then vm = minetest.get_voxel_manip(minp, maxp) - emin, emax = vm:get_emerged_area() end + local emin, emax = vm:get_emerged_area() + local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} vm:get_data(data) -- If we are fully outside the islands area, -- we can switch to the ultra-fast deep ocean -- algorithm. - local generate_islands = maxp.z > lzr_globals.DEEP_OCEAN_Z + local generate_islands = maxp.z > DEEP_OCEAN_Z local isln_terrain = nil local isln_var = nil local isln_hills = nil @@ -238,12 +291,12 @@ lzr_mapgen.generate_piece = function(minp, maxp, is_on_generated, prot_min, prot if not prot_min or not vector.in_area(mpos, prot_min, prot_max) then local vi = area:index(x, y, z) -- Deep ocean - if z <= lzr_globals.DEEP_OCEAN_Z then - if y <= lzr_globals.SEASTONE_LEVEL then + if z <= DEEP_OCEAN_Z then + if y <= SEASTONE_LEVEL then data[vi] = c_stone - elseif y <= lzr_globals.SEABED_LEVEL then + elseif y <= SEABED_LEVEL then data[vi] = c_seabed - elseif y <= lzr_globals.WATER_LEVEL then + elseif y <= WATER_LEVEL then data[vi] = c_water elseif clear then data[vi] = minetest.CONTENT_AIR @@ -271,37 +324,36 @@ lzr_mapgen.generate_piece = function(minp, maxp, is_on_generated, prot_min, prot end vm:set_data(data) + if generate_islands then minetest.generate_decorations(vm) minetest.generate_ores(vm) - if is_on_generated then + if IS_IN_MAPGEN_ENVIRONMENT then vm:calc_lighting() + else + vm:write_to_map(true) end - vm:write_to_map(true) - minetest.after(0,function() - minetest.fix_light(minp, maxp) - end) - else + elseif not IS_IN_MAPGEN_ENVIRONMENT then vm:write_to_map(true) end - - end --- On generated function. - --- 'minp' and 'maxp' are the minimum and maximum positions of the mapchunk that --- define the 3D volume. - -minetest.register_on_generated(function(minp, maxp, seed) - -- Start time of mapchunk generation. - local t0 = os.clock() - lzr_mapgen.generate_piece(minp, maxp, true) - -- Print generation time of this mapchunk. - local chugent = ceil((os.clock() - t0) * 1000) - minetest.log("action", "[lzr_mapgen] Mapchunk generation time for piece at " .. minetest.pos_to_string(minp)..": " .. chugent .. " ms") -end) - - +if IS_IN_MAPGEN_ENVIRONMENT then + minetest.log("action", "[lzr_mapgen] mapgen script successfully run in mapgen environment") + -- On generated function for the mapgen environment + minetest.register_on_generated(function(vmanip, minp, maxp) + -- Start time of mapchunk generation. + local t0 = os.clock() + generate_piece(minp, maxp, vmanip) + -- Print generation time of this mapchunk. + local chugent = ceil((os.clock() - t0) * 1000) + minetest.log("action", "[lzr_mapgen] Mapchunk generation time for piece at " .. minetest.pos_to_string(minp)..": " .. chugent .. " ms") + end) +else + minetest.log("action", "[lzr_mapgen] mapgen script successfully run in global environment") + -- Expose generate_piece to the global environment when this file does not + -- run as mapgen thrad + lzr_mapgen.generate_piece = generate_piece +end diff --git a/mods/lzr_mapgen/settings.lua b/mods/lzr_mapgen/settings.lua new file mode 100644 index 00000000..43aa3ed7 --- /dev/null +++ b/mods/lzr_mapgen/settings.lua @@ -0,0 +1,23 @@ +-- Mapgen settings + + +-- Set singlenode mapgen +minetest.set_mapgen_setting('mg_name', 'singlenode', true) + +-- Disable the engine lighting calculation since that will be done for a +-- mapchunk of air nodes and will be incorrect after we place nodes. +minetest.set_mapgen_setting('flags', 'nolight', true) + +-- Set a fixed seed so the islands backdrop used by levels +-- will stay consistent for all players +minetest.set_mapgen_setting('seed', '5436146057422610855', true) + +minetest.set_mapgen_setting("mg_biome_np_heat", + "90,0,(1000,1000,1000),5349,3,0.5,2", + true) + +minetest.set_mapgen_setting("mg_biome_np_humidity", + "54,10,(1000,1000,1000),5349,3,0.5,2", + true) + +