Compare commits
	
		
			No commits in common. "851cb19cd296b1a0cafe13e12e166cd48e98b613" and "7b29f68ffa41e6907b99e380f867b54ef66bf113" have entirely different histories. 
		
	
	
		
			851cb19cd2
			...
			7b29f68ffa
		
	
		
							
								
								
									
										222
									
								
								init.lua
								
								
								
								
							
							
						
						
									
										222
									
								
								init.lua
								
								
								
								
							| 
						 | 
				
			
			@ -1,13 +1,6 @@
 | 
			
		|||
-- DEVELOPMENT ONLY: Timer module for debugging performance
 | 
			
		||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
 | 
			
		||||
 | 
			
		||||
dofile(modpath.."/lua/timer.lua")
 | 
			
		||||
 | 
			
		||||
-- DEVELOPMENT ONLY: End of timer module
 | 
			
		||||
 | 
			
		||||
-- Local variables used for programming
 | 
			
		||||
local internal =
 | 
			
		||||
    { a = nil
 | 
			
		||||
    { a = 0
 | 
			
		||||
 | 
			
		||||
    -- Average size of a cave biome
 | 
			
		||||
    , biome_size  = { x =   50, y =   50, z =   50 }
 | 
			
		||||
| 
						 | 
				
			
			@ -18,18 +11,6 @@ local internal =
 | 
			
		|||
    -- The margin that a voxelmanip gives around the chunk being generated
 | 
			
		||||
    , mapgen_buffer = 16
 | 
			
		||||
 | 
			
		||||
    -- Enum type used during cave generation for classifying different types
 | 
			
		||||
    -- of cave nodes. Do not touch unless you're changing the code
 | 
			
		||||
    , node_types =
 | 
			
		||||
        { stick_edge = 0
 | 
			
		||||
        , air = 1
 | 
			
		||||
        , stone = 2
 | 
			
		||||
        , floor = 3
 | 
			
		||||
        , wall = 4
 | 
			
		||||
        , ceiling = 5
 | 
			
		||||
        , floor_deco = 6
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    -- Point that can be used for generating Voronoi graphs
 | 
			
		||||
    -- The number can be anything, as long as it reasonably far away from
 | 
			
		||||
    -- the range 0 - 100
 | 
			
		||||
| 
						 | 
				
			
			@ -76,15 +57,14 @@ Flat3dArray.__index = Flat3dArray
 | 
			
		|||
-- Please see API.md for reference
 | 
			
		||||
noordstar_caves =
 | 
			
		||||
    { a = nil
 | 
			
		||||
 | 
			
		||||
    -- The `cave_vastness` is a variable that determines the size of caves.
 | 
			
		||||
    -- The function takes in an x, y and z variable, and returns a number
 | 
			
		||||
    -- between 0 and 1.
 | 
			
		||||
    -- Low numbers mean very rare and tiny caves, while high numbers mean
 | 
			
		||||
    -- massive caves, with massive open spaces.
 | 
			
		||||
    -- If you wish to overwrite this function, it is good to keep in mind to:
 | 
			
		||||
    --  - Make sure that the output changes VERY SLOWLY over time
 | 
			
		||||
    --  - Keep the function performant as it will be executed many, many times
 | 
			
		||||
        -- The `cave_vastness` is a variable that determines the size of caves.
 | 
			
		||||
        -- The function takes in an x, y and z variable, and returns a number between
 | 
			
		||||
        -- 0 and 1.
 | 
			
		||||
        -- Low numbers mean very rare and tiny caves, while high numbers mean massive
 | 
			
		||||
        -- caves, with massive open spaces.
 | 
			
		||||
        -- If you wish to overwrite this function, it is good to keep in mind to:
 | 
			
		||||
        --  - Make sure that the output changes VERY SLOWLY over time
 | 
			
		||||
        --  - Keep the function performant as it will be executed many, many times
 | 
			
		||||
    , cave_vastness = function(pos)
 | 
			
		||||
        return pos.y / internal.world_depth
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +121,6 @@ function noordstar_caves.unregister_shape(name)
 | 
			
		|||
    noordstar_caves.registered_shapes[name] = nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- Calculate the distance of a given biome to a given point
 | 
			
		||||
function internal.biome_def_distance(def, heat, humidity)
 | 
			
		||||
    local dx = math.abs(humidity - def.humidity_point)
 | 
			
		||||
| 
						 | 
				
			
			@ -466,64 +445,6 @@ function internal.flat_from_cave_bools(minp, maxp)
 | 
			
		|||
    return bools
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function internal.flat_from_node_types(bools, minp, maxp)
 | 
			
		||||
    local nt = internal.node_types
 | 
			
		||||
 | 
			
		||||
    -- local bools = internal.flat_from_cave_bools(minp, maxp)
 | 
			
		||||
 | 
			
		||||
    local node_types = Flat3dArray:from_func(minp, maxp, function (i, pos)
 | 
			
		||||
        -- Simplify calculation by ignoring edges
 | 
			
		||||
        if pos.x == minp.x or pos.x == maxp.x then
 | 
			
		||||
            return nt.stick_edge
 | 
			
		||||
        elseif pos.y == minp.y or pos.y == maxp.y then
 | 
			
		||||
            return nt.stick_edge
 | 
			
		||||
        elseif pos.z == maxp.z or pos.z == minp.z then
 | 
			
		||||
            return nt.stick_edge
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        if bools:get_index(i) then
 | 
			
		||||
            -- PART OF CAVE
 | 
			
		||||
 | 
			
		||||
            if bools:get_index(i + bools.down) == false then
 | 
			
		||||
                -- Block is right on the floor
 | 
			
		||||
                return nt.floor_deco
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            return nt.air
 | 
			
		||||
        else
 | 
			
		||||
            -- NOT PART OF CAVE
 | 
			
		||||
 | 
			
		||||
            -- Floor
 | 
			
		||||
            if bools:get_index(i + bools.up) then
 | 
			
		||||
                return nt.floor
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            -- Ceiling
 | 
			
		||||
            if bools:get_index(i + bools.down) then
 | 
			
		||||
                return nt.ceiling
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            -- Walls
 | 
			
		||||
            if bools:get_index(i + bools.north) then
 | 
			
		||||
                return nt.wall
 | 
			
		||||
            end
 | 
			
		||||
            if bools:get_index(i + bools.east) then
 | 
			
		||||
                return nt.wall
 | 
			
		||||
            end
 | 
			
		||||
            if bools:get_index(i + bools.south) then
 | 
			
		||||
                return nt.wall
 | 
			
		||||
            end
 | 
			
		||||
            if bools:get_index(i + bools.west) then
 | 
			
		||||
                return nt.wall
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            return nt.stone
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    return node_types
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get a Flat3dArray using noise_params
 | 
			
		||||
function internal.flat_from_noise_params(noise_params, minp, maxp)
 | 
			
		||||
    local nx = maxp.x - minp.x + 1
 | 
			
		||||
| 
						 | 
				
			
			@ -573,105 +494,6 @@ function internal.from_3d_to_flat(dx, dy, dz, nx, ny)
 | 
			
		|||
    return (nx * ny * dz) + (nx * dy) + dx + 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Generate caves given a voxelmanip array
 | 
			
		||||
function internal.generate_caves(data, minp, maxp)
 | 
			
		||||
    -- Increased voxelmanip size
 | 
			
		||||
    local vminp =
 | 
			
		||||
        { x = minp.x - internal.mapgen_buffer
 | 
			
		||||
        , y = minp.y - internal.mapgen_buffer
 | 
			
		||||
        , z = minp.z - internal.mapgen_buffer
 | 
			
		||||
        }
 | 
			
		||||
    local vmaxp =
 | 
			
		||||
        { x = maxp.x + internal.mapgen_buffer
 | 
			
		||||
        , y = maxp.y + internal.mapgen_buffer
 | 
			
		||||
        , z = maxp.z + internal.mapgen_buffer
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    -- Increased node type size to account for unknown edges
 | 
			
		||||
    local bminp =
 | 
			
		||||
        { x = minp.x - 1
 | 
			
		||||
        , y = minp.y - 1
 | 
			
		||||
        , z = minp.z - 1
 | 
			
		||||
        }
 | 
			
		||||
    local bmaxp =
 | 
			
		||||
        { x = maxp.x + 1
 | 
			
		||||
        , y = maxp.y + 1
 | 
			
		||||
        , z = maxp.z + 1
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    -- Load data
 | 
			
		||||
    local vmanip = Flat3dArray:new(vminp, vmaxp, data)
 | 
			
		||||
    
 | 
			
		||||
    -- Get cave bools
 | 
			
		||||
    local bools = internal.flat_from_cave_bools(bminp, bmaxp)
 | 
			
		||||
 | 
			
		||||
    -- Get node types
 | 
			
		||||
    local nts = internal.flat_from_node_types(bools, bminp, bmaxp)
 | 
			
		||||
 | 
			
		||||
    -- Calculate biome heat & humidity
 | 
			
		||||
    local heat_points = internal.flat_from_noise_params(
 | 
			
		||||
        internal.heat_noise_params(), bminp, bmaxp
 | 
			
		||||
    )
 | 
			
		||||
    local humidity_points = internal.flat_from_noise_params(
 | 
			
		||||
        internal.humidity_noise_params(), bminp, bmaxp
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    -- Place blocks where necessary
 | 
			
		||||
    internal.iter_3d_area(bminp, bmaxp, function (i, pos)
 | 
			
		||||
        local function place(name)
 | 
			
		||||
            if type(name) == "string" then
 | 
			
		||||
                vmanip:set_index(
 | 
			
		||||
                    vmanip:pos_to_index(pos),
 | 
			
		||||
                    minetest.get_content_id(name)
 | 
			
		||||
                )
 | 
			
		||||
            elseif type(name) == "nil" then
 | 
			
		||||
            else
 | 
			
		||||
                error("Inserted invalid type " .. type(name) .. " into voxelmanip array")
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local nt = nts:get_index(i)
 | 
			
		||||
 | 
			
		||||
        if nt == internal.node_types.stone then
 | 
			
		||||
        elseif nt == internal.node_types.stick_edge then
 | 
			
		||||
        elseif nt == internal.node_types.air then
 | 
			
		||||
            place("air")
 | 
			
		||||
        elseif nt == internal.node_types.floor_deco then
 | 
			
		||||
            -- TODO: Place registered decoration
 | 
			
		||||
        else
 | 
			
		||||
            -- Find appropriate biome
 | 
			
		||||
            local heat = heat_points:get_index(i)
 | 
			
		||||
            local humidity = humidity_points:get_index(i)
 | 
			
		||||
 | 
			
		||||
            local name = internal.closest_cave_biome(heat, humidity)
 | 
			
		||||
 | 
			
		||||
            local def = noordstar_caves.registered_biomes[name] or internal.default_biome()
 | 
			
		||||
 | 
			
		||||
            if nt == internal.node_types.floor then
 | 
			
		||||
                place(def.node_floor)
 | 
			
		||||
            elseif nt == internal.node_types.wall then
 | 
			
		||||
                place(def.node_wall)
 | 
			
		||||
            elseif nt == internal.node_types.ceiling then
 | 
			
		||||
                place(def.node_roof)
 | 
			
		||||
            else
 | 
			
		||||
                error(
 | 
			
		||||
                    table.concat(
 | 
			
		||||
                        { "Found unknown node type "
 | 
			
		||||
                        , nt
 | 
			
		||||
                        , " (type "
 | 
			
		||||
                        , type(nt)
 | 
			
		||||
                        , ")"
 | 
			
		||||
                        }
 | 
			
		||||
                        , ""
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    return vmanip.arr
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get the noise params for the cave biome temperature.
 | 
			
		||||
function internal.heat_noise_params()
 | 
			
		||||
    return { 
 | 
			
		||||
| 
						 | 
				
			
			@ -770,11 +592,6 @@ function internal.iter_3d_area(minp, maxp, callback)
 | 
			
		|||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- -- Log text to the Minetest chat
 | 
			
		||||
-- function internal.log(text)
 | 
			
		||||
--     minetest.chat_send_all(os.time() .. " - " .. text)
 | 
			
		||||
-- end
 | 
			
		||||
 | 
			
		||||
-- Helper function to convert a set of coordinates to a readable string
 | 
			
		||||
function internal.pos_to_str(pos)
 | 
			
		||||
    return "(" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. " )"
 | 
			
		||||
| 
						 | 
				
			
			@ -874,7 +691,6 @@ function internal.within_bounds(pos, minp, maxp)
 | 
			
		|||
    return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- Create a new flat 3d array based on a function callback that gets the index
 | 
			
		||||
-- and position as inputs
 | 
			
		||||
function Flat3dArray:from_func(minp, maxp, callback)
 | 
			
		||||
| 
						 | 
				
			
			@ -990,26 +806,6 @@ function Flat3dArray:validate_pos(pos)
 | 
			
		|||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
minetest.register_on_generated(function(minp, maxp, blockseed)
 | 
			
		||||
    local vm = minetest.get_mapgen_object("voxelmanip")
 | 
			
		||||
    local data = vm:get_data()
 | 
			
		||||
 | 
			
		||||
    data = internal.generate_caves(data, minp, maxp)
 | 
			
		||||
 | 
			
		||||
    vm:set_data(data)
 | 
			
		||||
    vm:write_to_map()
 | 
			
		||||
end)
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,578 @@
 | 
			
		|||
 | 
			
		||||
-- Constants and magic numbers
 | 
			
		||||
local mapgen_buffer = 16
 | 
			
		||||
 | 
			
		||||
-- Cave biome range
 | 
			
		||||
local biome_spread_range = 50
 | 
			
		||||
 | 
			
		||||
-- Noise params for heat_point
 | 
			
		||||
local heat_noise_params =
 | 
			
		||||
    { offset = 50
 | 
			
		||||
    , scale = 50
 | 
			
		||||
    , spread = { x = biome_spread_range, y = biome_spread_range, z = biome_spread_range }
 | 
			
		||||
    , seed = 320523
 | 
			
		||||
    , octaves = 2
 | 
			
		||||
    , persistence = 0.1
 | 
			
		||||
    , lacunarity = 2.0
 | 
			
		||||
    , flags = ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
-- Noise params for humidity_point
 | 
			
		||||
local humidity_noise_params =
 | 
			
		||||
    { offset = 50
 | 
			
		||||
    , scale = 50
 | 
			
		||||
    , spread = { x = biome_spread_range, y = biome_spread_range, z = biome_spread_range }
 | 
			
		||||
    , seed = 9923473
 | 
			
		||||
    , octaves = 2
 | 
			
		||||
    , persistence = 0.1
 | 
			
		||||
    , lacunarity = 2.0
 | 
			
		||||
    , flags = ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
local default_biome =
 | 
			
		||||
    { name = "noordstar_caves:none"
 | 
			
		||||
    , heat_point = -1e6
 | 
			
		||||
    , humidity_point = -1e6
 | 
			
		||||
    , minp = { x = -1e5, y = -1e5, z = -1e5 }
 | 
			
		||||
    , maxp = { x =  1e5, y =  1e5, z =  1e5 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
local cave_shape_chunk_size = 8
 | 
			
		||||
 | 
			
		||||
local cluster_shape_chunks_x = 4
 | 
			
		||||
local cluster_shape_chunks_y = 6
 | 
			
		||||
local cluster_shape_chunks_z = 4
 | 
			
		||||
 | 
			
		||||
local function reduced_pos(pos)
 | 
			
		||||
    return
 | 
			
		||||
        { x = math.floor(pos.x / (cave_shape_chunk_size * cluster_shape_chunks_x))
 | 
			
		||||
        , y = math.floor(pos.y / (cave_shape_chunk_size * cluster_shape_chunks_y))
 | 
			
		||||
        , z = math.floor(pos.z / (cave_shape_chunk_size * cluster_shape_chunks_z))
 | 
			
		||||
        }
 | 
			
		||||
end
 | 
			
		||||
-- Convert 3d relative coordinates to an index on a flat array
 | 
			
		||||
local function from_3d_to_flat(dx, dy, dz, nx, ny)
 | 
			
		||||
    return (nx * ny * dz) + (nx * dy) + dx + 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Convert an index on a flat array to 3d relative coordinates
 | 
			
		||||
local function from_flat_to_3d(i, nx, ny)
 | 
			
		||||
    return {
 | 
			
		||||
        dx = (i - 1) % nx,
 | 
			
		||||
        dy = math.floor((i - 1) / nx) % ny,
 | 
			
		||||
        dz = math.floor((i - 1) / (nx * ny))
 | 
			
		||||
    }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Iterate over a 3d area, both indexing by the index and the ansolute position
 | 
			
		||||
local function iter_3d_area(minp, maxp, callback)
 | 
			
		||||
    local nx = maxp.x - minp.x + 1
 | 
			
		||||
    local ny = maxp.y - minp.y + 1
 | 
			
		||||
    local nz = maxp.z - minp.z + 1
 | 
			
		||||
 | 
			
		||||
    for i = 1, nx * ny * nz do
 | 
			
		||||
        local dpos = from_flat_to_3d(i, nx, ny)
 | 
			
		||||
        local pos = {
 | 
			
		||||
            x = minp.x + dpos.dx,
 | 
			
		||||
            y = minp.y + dpos.dy,
 | 
			
		||||
            z = minp.z + dpos.dz,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        callback(i, pos)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Helper function to convert a set of coordinates to a readable string
 | 
			
		||||
local function pos_to_str(pos)
 | 
			
		||||
    return "(" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. " )"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local Flat3dArray = {}
 | 
			
		||||
Flat3dArray.__index = Flat3dArray
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:new(minp, maxp, arr)
 | 
			
		||||
    local instance = {}
 | 
			
		||||
    setmetatable(instance, Flat3dArray)
 | 
			
		||||
 | 
			
		||||
    local nx = maxp.x - minp.x + 1
 | 
			
		||||
    local ny = maxp.y - minp.y + 1
 | 
			
		||||
    local nz = maxp.z - minp.z + 1
 | 
			
		||||
 | 
			
		||||
    if #arr ~= nx * ny * nz then
 | 
			
		||||
        error(
 | 
			
		||||
            "Input array doesn't match dimension lengths: " .. nx .. " x " ..
 | 
			
		||||
            ny .. " x " .. nz .. " = " .. (nx*ny*nz) .. ", but found " .. #arr
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    instance.nx = nx
 | 
			
		||||
    instance.ny = ny
 | 
			
		||||
    instance.nz = nz
 | 
			
		||||
    instance.minp = minp
 | 
			
		||||
    instance.maxp = maxp
 | 
			
		||||
    instance.arr = arr
 | 
			
		||||
 | 
			
		||||
    return instance
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:from_func(minp, maxp, callback)
 | 
			
		||||
    local arr = {}
 | 
			
		||||
 | 
			
		||||
    iter_3d_area(minp, maxp, function (i, pos)
 | 
			
		||||
        arr[i] = callback(i, pos)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    return self:new(minp, maxp, arr)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:get_index(i)
 | 
			
		||||
    local out = self.arr[i]
 | 
			
		||||
    if out == nil then
 | 
			
		||||
        error(
 | 
			
		||||
            "Index " .. i .. " not found in array of length " .. #self.arr
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
    return out
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:get_pos(pos)
 | 
			
		||||
    self:validate_pos(pos)
 | 
			
		||||
 | 
			
		||||
    local dx = pos.x - self.minp.x
 | 
			
		||||
    local dy = pos.y - self.minp.y
 | 
			
		||||
    local dz = pos.z - self.minp.z
 | 
			
		||||
 | 
			
		||||
    return self:get_index(from_3d_to_flat(dx, dy, dz, self.nx, self.ny))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function is_valid_pos(pos, minp, maxp)
 | 
			
		||||
    if pos.x < minp.x then
 | 
			
		||||
        return false
 | 
			
		||||
    elseif pos.x > maxp.x then
 | 
			
		||||
        return false
 | 
			
		||||
    elseif pos.y < minp.y then
 | 
			
		||||
        return false
 | 
			
		||||
    elseif pos.y > maxp.y then
 | 
			
		||||
        return false
 | 
			
		||||
    elseif pos.z < minp.z then
 | 
			
		||||
        return false
 | 
			
		||||
    elseif pos.z > maxp.z then
 | 
			
		||||
        return false
 | 
			
		||||
    else
 | 
			
		||||
        return true
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:valid_pos(pos)
 | 
			
		||||
    return is_valid_pos(pos, self.minp, self.maxp)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function Flat3dArray:validate_pos(pos)
 | 
			
		||||
    if not self:valid_pos(pos) then
 | 
			
		||||
        error(
 | 
			
		||||
            table.concat(
 | 
			
		||||
                { "Position "
 | 
			
		||||
                , pos_to_str(pos)
 | 
			
		||||
                , " out of bounds from minp = "
 | 
			
		||||
                , pos_to_str(self.minp)
 | 
			
		||||
                , ", maxp = "
 | 
			
		||||
                , pos_to_str(self.maxp)
 | 
			
		||||
                },
 | 
			
		||||
                ""
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get an enhanced function from the def function that warns us when the
 | 
			
		||||
-- function does not behave properly
 | 
			
		||||
local function enhanced_func(def)
 | 
			
		||||
    if type(def.name) ~= "string" then
 | 
			
		||||
        error("Invalid nameless shape definition")
 | 
			
		||||
    elseif type(def.func) ~= "function" then
 | 
			
		||||
        error(
 | 
			
		||||
            "Invalid shape definition misses an adjustment function"
 | 
			
		||||
        )
 | 
			
		||||
    else
 | 
			
		||||
        return function(pos, n)
 | 
			
		||||
            local out = def.func(pos, n)
 | 
			
		||||
 | 
			
		||||
            if type(out) == "number" then
 | 
			
		||||
                return out
 | 
			
		||||
            elseif n == nil then
 | 
			
		||||
                error(
 | 
			
		||||
                    "Shape " .. def.name .. " function must return a number. The input `n` was nil. Perhaps your `noise_params` field is invalid?"
 | 
			
		||||
                )
 | 
			
		||||
            else
 | 
			
		||||
                error("Shape " .. def.name .. " function must return a number.")
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get a flat array of cave shape noise values from a given cave shape def
 | 
			
		||||
local function get_flat_from_shape_def(def, minp, maxp)
 | 
			
		||||
    local f = enhanced_func(def)
 | 
			
		||||
 | 
			
		||||
    local nx = maxp.x - minp.x + 1
 | 
			
		||||
    local ny = maxp.y - minp.y + 1
 | 
			
		||||
    local nz = maxp.z - minp.z + 1
 | 
			
		||||
 | 
			
		||||
    local noise_flat_map = {}
 | 
			
		||||
 | 
			
		||||
    -- If noise parameters have been defined, fill the table with noise
 | 
			
		||||
    -- If not, all values remain nil
 | 
			
		||||
    if def.noise_params ~= nil then
 | 
			
		||||
        local p = PerlinNoiseMap(def.noise_params, { x = nx, y = ny, z = nz })
 | 
			
		||||
        
 | 
			
		||||
        if nz == 1 then
 | 
			
		||||
            p:get_2d_map_flat(minp, noise_flat_map)
 | 
			
		||||
        else
 | 
			
		||||
            p:get_3d_map_flat(minp, noise_flat_map)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    iter_3d_area(minp, maxp, function(i, pos)
 | 
			
		||||
        noise_flat_map[i] = f(pos, noise_flat_map[i])
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    return Flat3dArray:new(minp, maxp, noise_flat_map)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function get_flat_from_noise_params(minp, maxp, noise_params)
 | 
			
		||||
    local nx = maxp.x - minp.x + 1
 | 
			
		||||
    local ny = maxp.y - minp.y + 1
 | 
			
		||||
    local nz = maxp.z - minp.z + 1
 | 
			
		||||
 | 
			
		||||
    local buffer = {}
 | 
			
		||||
 | 
			
		||||
    local p = PerlinNoiseMap(noise_params, { x = nx, y = ny, z = nz })
 | 
			
		||||
 | 
			
		||||
    if nz == 1 then
 | 
			
		||||
        p:get_2d_map_flat(minp, buffer)
 | 
			
		||||
    else
 | 
			
		||||
        p:get_3d_map_flat(minp, buffer)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return Flat3dArray:new(minp, maxp, buffer)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Based on the number of cave shapes, calculate how quickly connectivity is
 | 
			
		||||
-- meant to change
 | 
			
		||||
local function get_connectivity_noise_params(shape_size)
 | 
			
		||||
    local factor = math.max(math.abs(shape_size) ^ 0.5, 1)
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        offset = 50,
 | 
			
		||||
        scale = 50,
 | 
			
		||||
        spread =
 | 
			
		||||
            reduced_pos(
 | 
			
		||||
                { x = factor * 250
 | 
			
		||||
                , y = factor * 100
 | 
			
		||||
                , z = factor * 250
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
        seed = 297948,
 | 
			
		||||
        octaves = 2,
 | 
			
		||||
        persistence = 0.2,
 | 
			
		||||
        lacunarity = 2.0,
 | 
			
		||||
        flags = "eased"
 | 
			
		||||
    }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Based on the number of cave shapes, calculate how quickly verticality is
 | 
			
		||||
-- meant to change
 | 
			
		||||
local function get_verticality_noise_params(shape_size)
 | 
			
		||||
    local factor = math.max(math.abs(shape_size) ^ 0.5, 1)
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        offset = 50,
 | 
			
		||||
        scale = 50,
 | 
			
		||||
        spread =
 | 
			
		||||
            reduced_pos(
 | 
			
		||||
                { x = factor * 100
 | 
			
		||||
                , y = factor * 250
 | 
			
		||||
                , z = factor * 100
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
        seed = 35644,
 | 
			
		||||
        octaves = 2,
 | 
			
		||||
        persistence = 0.2,
 | 
			
		||||
        lacunarity = 2.0,
 | 
			
		||||
        flags = "eased"
 | 
			
		||||
    }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get whether a cave shape is within distance.
 | 
			
		||||
local function shape_within_distance(shape_size, dx, dy)
 | 
			
		||||
    local factor = math.max(math.abs(shape_size) ^ 0.5, 1)
 | 
			
		||||
    local max_distance = 30 / factor
 | 
			
		||||
 | 
			
		||||
    return dx^2 + dy^2 <= max_distance^2
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function shape_def_distance(def, x, y)
 | 
			
		||||
    local dx = math.abs(x - def.connectivity_point)
 | 
			
		||||
    local dy = math.abs(y - def.verticality_point)
 | 
			
		||||
 | 
			
		||||
    return dx^2 + dy^2
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get a flat map containing all flat threshold values
 | 
			
		||||
local function get_threshold_flat(minp, maxp)
 | 
			
		||||
    local connectivity = get_flat_from_noise_params(
 | 
			
		||||
        reduced_pos(minp), reduced_pos(maxp),
 | 
			
		||||
        get_connectivity_noise_params(#noordstar_caves.registered_shapes)
 | 
			
		||||
    )
 | 
			
		||||
    
 | 
			
		||||
    local verticality = get_flat_from_noise_params(
 | 
			
		||||
        reduced_pos(minp), reduced_pos(maxp),
 | 
			
		||||
        get_verticality_noise_params(#noordstar_caves.registered_shapes)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    local noise = {}
 | 
			
		||||
 | 
			
		||||
    -- Get noise for all cave shapes
 | 
			
		||||
    for key, def in pairs(noordstar_caves.registered_shapes) do
 | 
			
		||||
        noise[key] = get_flat_from_shape_def(def, reduced_pos(minp), reduced_pos(maxp))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Create a (reduced) flat array
 | 
			
		||||
    local reduced = Flat3dArray:from_func(
 | 
			
		||||
        reduced_pos(minp), reduced_pos(maxp),
 | 
			
		||||
        function(i, pos)
 | 
			
		||||
            local x = connectivity:get_pos(pos)
 | 
			
		||||
            local y = verticality:get_pos(pos)
 | 
			
		||||
 | 
			
		||||
            local value = 0
 | 
			
		||||
        
 | 
			
		||||
            for key, def in pairs(noordstar_caves.registered_shapes) do
 | 
			
		||||
                local dx = math.abs(x - def.connectivity_point)
 | 
			
		||||
                local dy = math.abs(y - def.verticality_point)
 | 
			
		||||
 | 
			
		||||
                if shape_within_distance(#noordstar_caves.registered_shapes, dx, dy) then
 | 
			
		||||
                    value = math.max(value, noise[key]:get_pos(pos))
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            return value
 | 
			
		||||
        end
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    -- Create the flat array
 | 
			
		||||
    local x = Flat3dArray:from_func(minp, maxp, function(i, pos)
 | 
			
		||||
        return reduced:get_pos(reduced_pos(pos))
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    return x
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- Old minimum height for the overworld
 | 
			
		||||
local old_overworld_min = mcl_vars.mg_overworld_min
 | 
			
		||||
 | 
			
		||||
-- If another mod doesn't override the maximum world depth, we will assume that
 | 
			
		||||
-- the world depth is the following value.
 | 
			
		||||
local world_depth = -60
 | 
			
		||||
 | 
			
		||||
-- Otherwise, this variable can be changed using the following function,
 | 
			
		||||
-- which will also update all the other necessary variables
 | 
			
		||||
function noordstar_caves.set_world_depth(h)
 | 
			
		||||
    -- Set world depth variable
 | 
			
		||||
    world_depth = h
 | 
			
		||||
end
 | 
			
		||||
noordstar_caves.set_world_depth(world_depth)
 | 
			
		||||
 | 
			
		||||
-- The `cave_vastness` is a variable that determines the size of caves.
 | 
			
		||||
-- The function takes in an x, y and z variable, and returns a number between
 | 
			
		||||
-- 0 and 1.
 | 
			
		||||
-- Low numbers mean very rare and tiny caves, while high numbers mean massive
 | 
			
		||||
-- caves, with massive open spaces.
 | 
			
		||||
-- If you wish to overwrite this function, it is good to keep in mind to:
 | 
			
		||||
--  - Make sure that the output changes VERY SLOWLY over time
 | 
			
		||||
--  - This function will be run a LOT so it is very performance sensitive
 | 
			
		||||
noordstar_caves.cave_vastness = function(pos)
 | 
			
		||||
    return pos.y / world_depth
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Secretly, we're using an internal function that also adds a safe layer for
 | 
			
		||||
-- when we're approaching bedrock levels
 | 
			
		||||
local function cave_vastness(pos)
 | 
			
		||||
    if world_depth + 20 < pos.y then
 | 
			
		||||
        return noordstar_caves.cave_vastness(pos)
 | 
			
		||||
    elseif world_depth + 5 < pos.y then
 | 
			
		||||
        return noordstar_caves.cave_vastness(pos) * math.abs(pos.y - world_depth - 5) / 15
 | 
			
		||||
    else
 | 
			
		||||
        return 0
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Get a flat array of nodes that are either in caves or not in caves
 | 
			
		||||
local function get_flat_cave_bools(minp, maxp)
 | 
			
		||||
    local thresholds = get_threshold_flat(minp, maxp)
 | 
			
		||||
 | 
			
		||||
    return Flat3dArray:from_func(minp, maxp, function(i, pos)
 | 
			
		||||
        return thresholds:get_pos(pos) >= 1 - cave_vastness(pos)
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local node_type =
 | 
			
		||||
    { unknown = 1  -- Edge of a chunk
 | 
			
		||||
    , floor = 2    -- Floor of a cave
 | 
			
		||||
    , wall = 3     -- Side wall of a cave
 | 
			
		||||
    , roof = 4     -- Roof of a cave
 | 
			
		||||
    , content = 5  -- Air in the cave not adjacent to a wall, floor or roof
 | 
			
		||||
    , stone = 6    -- Underground node not adjacent to a cave
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
local function get_flat_cave_node_types(minp, maxp)
 | 
			
		||||
    local bools = get_flat_cave_bools(minp, maxp)
 | 
			
		||||
 | 
			
		||||
    return Flat3dArray:from_func(minp, maxp, function (i, pos)
 | 
			
		||||
        if bools:get_pos(pos) then
 | 
			
		||||
            return node_type.content
 | 
			
		||||
        -- Floor takes precedence
 | 
			
		||||
        elseif pos.y == maxp.y then -- Could be floor
 | 
			
		||||
            return node_type.unknown
 | 
			
		||||
        elseif bools:get_pos({ x = pos.x, y = pos.y + 1, z = pos.z }) then
 | 
			
		||||
            return node_type.floor
 | 
			
		||||
        -- Then roof takes precedence
 | 
			
		||||
        elseif pos.y == minp.y then -- Could be roof
 | 
			
		||||
            return node_type.unknown
 | 
			
		||||
        elseif bools:get_pos({ x = pos.x, y = pos.y - 1, z = pos.z }) then
 | 
			
		||||
            return node_type.roof
 | 
			
		||||
        else
 | 
			
		||||
            -- Check for walls
 | 
			
		||||
            local left  = { x = pos.x - 1, y = pos.y, z = pos.z }
 | 
			
		||||
            local right = { x = pos.x + 1, y = pos.y, z = pos.z }
 | 
			
		||||
            local front = { x = pos.x, y = pos.y, z = pos.z - 1 }
 | 
			
		||||
            local back  = { x = pos.x, y = pos.y, z = pos.z + 1 }
 | 
			
		||||
 | 
			
		||||
            -- Check if the value is near the edge
 | 
			
		||||
            local on_edge = false
 | 
			
		||||
 | 
			
		||||
            if left.x < minp.x then
 | 
			
		||||
                on_edge = true
 | 
			
		||||
            elseif bools:get_pos(left) then
 | 
			
		||||
                return node_type.wall
 | 
			
		||||
            end
 | 
			
		||||
            if right.x > maxp.x then
 | 
			
		||||
                on_edge = true
 | 
			
		||||
            elseif bools:get_pos(right) then
 | 
			
		||||
                return node_type.wall
 | 
			
		||||
            end
 | 
			
		||||
            if front.z < minp.z then
 | 
			
		||||
                on_edge = true
 | 
			
		||||
            elseif bools:get_pos(front) then
 | 
			
		||||
                return node_type.wall
 | 
			
		||||
            end
 | 
			
		||||
            if back.z > maxp.z then
 | 
			
		||||
                on_edge = true
 | 
			
		||||
            elseif bools:get_pos(back) then
 | 
			
		||||
                return node_type.wall
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            if on_edge then
 | 
			
		||||
                return node_type.unknown
 | 
			
		||||
            else
 | 
			
		||||
                return node_type.stone
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Transform categorized blocks into 
 | 
			
		||||
local function biome_def_to_content_id(def, nt, original_block)
 | 
			
		||||
    local function get_node(name, alt)
 | 
			
		||||
        return function()
 | 
			
		||||
            if name == nil then
 | 
			
		||||
                return alt
 | 
			
		||||
            else
 | 
			
		||||
                return minetest.get_content_id(name)
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local node_air     = get_node(def.node_air, minetest.get_content_id("air"))
 | 
			
		||||
    local node_floor   = get_node(def.node_floor, original_block)
 | 
			
		||||
    local node_stone   = get_node(nil,           original_block)
 | 
			
		||||
    local node_roof    = get_node(def.node_roof, original_block)
 | 
			
		||||
    local node_unknown = get_node(nil,           original_block)
 | 
			
		||||
    local node_wall    = get_node(def.node_wall, original_block)
 | 
			
		||||
 | 
			
		||||
    if nt == node_type.unknown then
 | 
			
		||||
        return node_unknown()
 | 
			
		||||
    elseif nt == node_type.floor then
 | 
			
		||||
        return node_floor()
 | 
			
		||||
    elseif nt == node_type.wall then
 | 
			
		||||
        return node_wall()
 | 
			
		||||
    elseif nt == node_type.roof then
 | 
			
		||||
        return node_roof()
 | 
			
		||||
    elseif nt == node_type.content then
 | 
			
		||||
        return node_air()
 | 
			
		||||
    elseif nt == node_type.stone then
 | 
			
		||||
        return node_stone()
 | 
			
		||||
    else
 | 
			
		||||
        return original_block
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function biome_distance(def, heat, humidity)
 | 
			
		||||
    return (def.heat_point - heat)^2 + (def.humidity_point - humidity)^2
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
minetest.register_on_generated(function(minp, maxp, blockseed)
 | 
			
		||||
    local vminp =
 | 
			
		||||
        { x = minp.x - mapgen_buffer
 | 
			
		||||
        , y = minp.y - mapgen_buffer
 | 
			
		||||
        , z = minp.z - mapgen_buffer
 | 
			
		||||
        }
 | 
			
		||||
    local vmaxp =
 | 
			
		||||
        { x = maxp.x + mapgen_buffer
 | 
			
		||||
        , y = maxp.y + mapgen_buffer
 | 
			
		||||
        , z = maxp.z + mapgen_buffer
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    -- Get voxelmanip
 | 
			
		||||
    local vm = minetest.get_mapgen_object("voxelmanip")
 | 
			
		||||
    local flat_data = Flat3dArray:new(vminp, vmaxp, vm:get_data())
 | 
			
		||||
    
 | 
			
		||||
    -- Get threshold values
 | 
			
		||||
    local node_types = get_flat_cave_node_types(vminp, vmaxp)
 | 
			
		||||
    
 | 
			
		||||
    local heat_points = get_flat_from_noise_params(minp, maxp, heat_noise_params)
 | 
			
		||||
    local humidity_points = get_flat_from_noise_params(minp, maxp, humidity_noise_params)
 | 
			
		||||
 | 
			
		||||
    -- Map block values
 | 
			
		||||
    local nids = Flat3dArray:from_func(vminp, vmaxp, function(i, pos)
 | 
			
		||||
        local nt = node_types:get_pos(pos)
 | 
			
		||||
 | 
			
		||||
        if not is_valid_pos(pos, minp, maxp) then
 | 
			
		||||
            return flat_data:get_pos(pos)
 | 
			
		||||
        else
 | 
			
		||||
            local biome = default_biome
 | 
			
		||||
 | 
			
		||||
            local heat = heat_points:get_pos(pos)
 | 
			
		||||
            local humidity = humidity_points:get_pos(pos)
 | 
			
		||||
 | 
			
		||||
            for _, def in pairs(noordstar_caves.registered_biomes) do
 | 
			
		||||
                if pos.x < def.minp.x then
 | 
			
		||||
                elseif pos.y < def.minp.y then
 | 
			
		||||
                elseif pos.z < def.minp.z then
 | 
			
		||||
                elseif pos.x > def.maxp.x then
 | 
			
		||||
                elseif pos.y > def.maxp.y then
 | 
			
		||||
                elseif pos.z > def.maxp.z then
 | 
			
		||||
                elseif biome_distance(def, heat, humidity) > biome_distance(biome, heat, humidity) then
 | 
			
		||||
                else
 | 
			
		||||
                    biome = def
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            return biome_def_to_content_id(biome, nt, flat_data:get_pos(pos))
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    -- Write all changes to the Minetest world
 | 
			
		||||
    vm:set_data(nids.arr)
 | 
			
		||||
    vm:write_to_map()
 | 
			
		||||
end)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,97 +0,0 @@
 | 
			
		|||
local internal = {
 | 
			
		||||
    waypoints = {},
 | 
			
		||||
    stats = {},
 | 
			
		||||
    sessions = 0,
 | 
			
		||||
    last = os.clock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
timer = {}
 | 
			
		||||
 | 
			
		||||
function timer.start()
 | 
			
		||||
    internal.waypoints = {}
 | 
			
		||||
 | 
			
		||||
    internal.now()
 | 
			
		||||
 | 
			
		||||
    internal.sessions = internal.sessions + 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function timer.checkpoint(name)
 | 
			
		||||
    local now = os.clock()
 | 
			
		||||
 | 
			
		||||
    table.insert(internal.waypoints, { name, internal.last, now })
 | 
			
		||||
 | 
			
		||||
    internal.now()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function timer.stop()
 | 
			
		||||
    local name_len = 0
 | 
			
		||||
 | 
			
		||||
    for _, t in ipairs(internal.waypoints) do
 | 
			
		||||
        local name  = t[1]
 | 
			
		||||
        local start = t[2]
 | 
			
		||||
        local stop  = t[3]
 | 
			
		||||
 | 
			
		||||
        local stat = internal.stats[name]
 | 
			
		||||
 | 
			
		||||
        if stat then
 | 
			
		||||
            internal.stats[name] = stat + (stop - start)
 | 
			
		||||
        else
 | 
			
		||||
            internal.stats[name] = stop - start
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        name_len = math.max(name_len, name)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local h1 = "Task"
 | 
			
		||||
    local h2 = "Time"
 | 
			
		||||
    local h3 = "Time (avg)"
 | 
			
		||||
    
 | 
			
		||||
    internal.log(
 | 
			
		||||
        table.concat(
 | 
			
		||||
            { h1
 | 
			
		||||
            , string.rep(" ", name_len - string.len(h1))
 | 
			
		||||
            , " | "
 | 
			
		||||
            , h2
 | 
			
		||||
            , string.rep(" ", 8 - string.len(h2))
 | 
			
		||||
            , " | "
 | 
			
		||||
            , h3
 | 
			
		||||
            }
 | 
			
		||||
            , ""
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    internal.log(string.rep("-", name_len + 3 + 8 + 3 + 8))
 | 
			
		||||
 | 
			
		||||
    for _, t in ipairs(internal.waypoints) do
 | 
			
		||||
        local name = t[1]
 | 
			
		||||
        local duration = tostring(math.round(1e3 * (t[3] - t[2])))
 | 
			
		||||
        local avg_duration = tostring(math.round(1e3 * internal.stats[name] / internal.sessions))
 | 
			
		||||
 | 
			
		||||
        internal.log(
 | 
			
		||||
            table.concat(
 | 
			
		||||
                { name
 | 
			
		||||
                , string.rep(" ", name_len - string.len(name))
 | 
			
		||||
                , " | "
 | 
			
		||||
                , string.rep(" ", 5 - string.len(duration))
 | 
			
		||||
                , duration
 | 
			
		||||
                , " ms | "
 | 
			
		||||
                , string.rep(" ", 5 - string.len(avg_duration))
 | 
			
		||||
                , avg_duration
 | 
			
		||||
                , " ms"
 | 
			
		||||
                }
 | 
			
		||||
                , ""
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Log text to the Minetest chat
 | 
			
		||||
function internal.log(text)
 | 
			
		||||
    minetest.chat_send_all(os.time() .. " - " .. text)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function internal.now()
 | 
			
		||||
    internal.last = os.clock()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
internal.now()
 | 
			
		||||
		Loading…
	
		Reference in New Issue