diff --git a/multi_map_core/init.lua b/multi_map_core/init.lua index d3f0eac..d75dd18 100644 --- a/multi_map_core/init.lua +++ b/multi_map_core/init.lua @@ -5,11 +5,12 @@ if not mm then mm = multi_map end +-- External settings that can be set by mods using multi_map multi_map.number_of_layers = 24 -- How may layers to generate multi_map.layers_start_chunk = 0 -- Y level where to start generating layers, in chunks multi_map.layer_height_chunks = 32 -- Height of each layer, in chunks --- Either engine defaults or derived from above values +-- Either MT engine defaults or derived from above values, to be used for more readable calculations multi_map.layer_height = multi_map.layer_height_chunks * 80 multi_map.layers_start = multi_map.layers_start_chunk * 80 multi_map.map_height = 61840 @@ -19,14 +20,14 @@ multi_map.half_layer_height = multi_map.layer_height / 2 multi_map.current_layer = nil -- Can be overridden with someone's own values -multi_map.bedrock = "multi_map_core:bedrock" -multi_map.skyrock = "multi_map_core:skyrock" +multi_map.bedrock = "multi_map_core:bedrock" -- Node to use to fill the bottom of a layer +multi_map.skyrock = "multi_map_core:skyrock" -- Node to use to fill the top of a layer -- Whether to generate a bedrock layer under a layer/ skyrock above a layer multi_map.generate_bedrock = true multi_map.generate_skyrock = true --- Chain of generators +-- Table with generator chains multi_map.generators = {} -- When no suitable generator is found, this generator is used as a fallback multi_map.fallback_generator = nil @@ -43,6 +44,8 @@ function multi_map.set_current_layer(y) end end +-- Get the absolute y center centerpoint for a given layer +-- current_layer = the layer for which to calculate the centerpoint, or if nil the current layer that multi_map is processing function multi_map.get_absolute_centerpoint(current_layer) if current_layer then return multi_map.map_min + multi_map.layers_start + (current_layer * multi_map.layer_height) + multi_map.half_layer_height @@ -68,11 +71,16 @@ function multi_map.get_offset_y(y) end -- Get the absolute y position from a relative offset position --- layer = the layer we are in -- y = relative y value to be translated to absolute world y position -function multi_map.get_absolute_y(layer, y) - local center_point = multi_map.map_min + multi_map.layers_start + (multi_map.current_layer * multi_map.layer_height) + multi_map.half_layer_height - return y - center_point +-- current_layer = the layer we are in or if nil the current layer multi_map is processing +function multi_map.get_absolute_y(y, current_layer) + if current_layer then + local center_point = multi_map.map_min + multi_map.layers_start + (current_layer * multi_map.layer_height) + multi_map.half_layer_height + return y - center_point + else + local center_point = multi_map.map_min + multi_map.layers_start + (multi_map.current_layer * multi_map.layer_height) + multi_map.half_layer_height + return y - center_point + end end -- Register a fallback generator, which is called in case not suitable generators are found for a layer @@ -94,12 +102,21 @@ end local last_used_layer = -1 +-- Mmmmh, might make these local ... multi_map.global_2d_maps = {} multi_map.global_2d_params = {} multi_map.global_2d_map_arrays = {} local map_cache = {} +-- Register a named map for use as 2D map. A 3D map could potentially be +-- registered using this as well, but since this is specialized for +-- multiple different seeds per layer, multi_map provides this mechanism. +-- Note: The seed provided in the params is used to seed math.random +-- and each layer gets a randomized seed after that. As such, the noise +-- is still predictable/ reproducible +-- name = the name of the map +-- params = the noise parameters as per minetest standard function multi_map.register_global_2dmap(name, params) math.randomseed(params.seed) multi_map.global_2d_params[name] = {} @@ -118,6 +135,11 @@ function multi_map.register_global_2dmap(name, params) end end +-- Get the named 2D map as flat array +-- name = name of the noise map +-- chulenxz = chunk length in 2 dimensions (xz) +-- minposxz = minimum 2D position (xz) +-- current layer = the layer for which to retrieve the map or nil to use multi_map's current layer function multi_map.get_global_2dmap_flat(name, chulenxz, minposxz, current_layer) if not multi_map.global_2d_map_arrays[name] then minetest.log("error", "[multi_map] Trying to get an unregistered global 2D map") @@ -141,15 +163,26 @@ function multi_map.get_global_2dmap_flat(name, chulenxz, minposxz, current_layer return map_cache[name] end +-- Mmmmh, might make these local ... multi_map.global_3d_maps = {} multi_map.global_3d_params = {} multi_map.global_3d_map_arrays = {} +-- Register a named map for use as 3D map. It is separated from the 2D case as that one +-- retruires a layer to be specified in order to get differently seeded noise maps per +-- layer. For 3D this is not an issue as the abslute y can be used to retrieve different +-- values from layer to layer. Hence the 3D case is separate +-- name = the name of the map +-- params = the noise parameters as per minetest standard function multi_map.register_global_3dmap(name, params) multi_map.global_3d_params[name] = params multi_map.global_3d_map_arrays[name] = {} end +-- Get the named 2D map as flat array +-- name = name of the noise map +-- chulenxyz = chunk length in 3 dimensions (xyz) +-- minposxyz = minimum 3D position (xyz) function multi_map.get_global_3dmap_flat(name, chulenxyz, minposxyz) if not multi_map.global_3d_map_arrays[name] then minetest.log("error", "[multi_map] Trying to get an unregistered global 3D map") @@ -210,7 +243,12 @@ function multi_map.register_generator(...) end end --- Helper to fill a chunk with a single type of node +-- Helper to fill a map chunk with a single type of node +-- minp = minimum position vector, where to start filling +-- maxp = maximum position vector, where to end filling +-- area = voxel area +-- vm_data = the array with data for the voxel manipulator to fill +-- content_id = the content id of the node to use for filling the chunk function multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, content_id) for z = minp.z, maxp.z do for y = minp.y, maxp.y do @@ -224,6 +262,12 @@ function multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, content_ end -- Helper to create a 1 node high plane on the specified y +-- minp = minimum position vector, where to start filling +-- maxp = maximum position vector, where to end filling +-- area = voxel area +-- vm_data = the array with data for the voxel manipulator to fill +-- y = (absolute) y level to place the plane at +-- content_id = the content id of the node to use for filling the chunk 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) @@ -234,7 +278,8 @@ function multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, y, conte end end --- Inspired by duane's underworlds, to fetch the result of get_content_id once and cache it +-- Inspired by duane's underworlds, to fetch the result of get_content_id once and cache it. +-- Use: local c_air node["air"] -- get the content id for air multi_map.node = setmetatable({}, { __index = function(t, k) if not (t and k and type(t) == 'table') then @@ -246,6 +291,7 @@ multi_map.node = setmetatable({}, { end }) +-- Simple init, does a sanity check of the settings and sets the mapgen to singlenode minetest.register_on_mapgen_init(function(mapgen_params) if multi_map.layers_start + (multi_map.number_of_layers * multi_map.layer_height) > multi_map.map_height then minetest.log("error", "[multi_map] Number of layers for the given layer height exceeds map height!") @@ -253,6 +299,8 @@ minetest.register_on_mapgen_init(function(mapgen_params) minetest.set_mapgen_params({mgname="singlenode"}) end) +-- Dump the current state of the multiple map layer generator, i.e. settings, registered generators, +-- registered noises function multi_map.log_state() minetest.log("action", "[multi_map] Multiple map layer generator global settings") minetest.log("action", "[multi_map] - Number of layers: "..multi_map.number_of_layers) @@ -284,6 +332,7 @@ end local firstrun = true +-- Here all the magic (or should I say mess..) happens! minetest.register_on_generated(function(minp, maxp) if firstrun then minetest.log("action", "[multi_map]") @@ -378,6 +427,11 @@ minetest.register_on_generated(function(minp, maxp) map_cache = {} end) +-- Skyrock is an invisible/ airlike node that is fully lit and +-- blocks shadow propagation by allowing sunlight to propagate +-- to below layers. Though airlike, it blocks player movement +-- so that the underside of a layer (e.g. bedrock or any other +-- mechanism) is not seen when approaching a layer's y limit minetest.register_node("multi_map_core:skyrock", { description = "Multi Map Impenetrable Skyblock", drawtype = "airlike", @@ -390,6 +444,13 @@ minetest.register_node("multi_map_core:skyrock", { paramtype = "light", }) +-- The shadow caster is used underground to create dark caves +-- since multi_map requires water_level to be set to -31000. +-- This water level allows every layer's overworld to be lit +-- and shaded properly using the engine's light calculation +-- but causes caves to be lit as well. By placing this layer +-- above the chunk being generated and then removing it after, +-- the map chunk is darkened properly as if it was underground minetest.register_node("multi_map_core:shadow_caster", { description = "Multi Map Shadow Caster", drawtype = "airlike", @@ -401,6 +462,9 @@ minetest.register_node("multi_map_core:shadow_caster", { climbable = false, }) +-- Bedrock layer that can be used as the bottom of the layer +-- to avoid players moving from one layer to another outside +-- of other means such as teleporters minetest.register_node("multi_map_core:bedrock", { description = "Multi Map Impenetrable Bedrock", drawtype = "normal",