578 lines
22 KiB
Lua
578 lines
22 KiB
Lua
--[[
|
|
Describes the falling/eroding effect for slopes
|
|
--]]
|
|
|
|
--[[
|
|
Pick replacement, node and area
|
|
--]]
|
|
|
|
-- Manage color for param2
|
|
-- @param replacement the replacement table
|
|
-- @param source the name or id of the node being transformed
|
|
-- @param dest the name or id of the new shape
|
|
-- @param param2_source the param2 value before transformation
|
|
-- @param param2_dest the param2 value for facedir (if any) after transformation
|
|
-- @return a new param2 value for dest node with color if necessary
|
|
local function manage_param2_color(replacement, source, dest, param2_source, param2_dest)
|
|
if not replacement._colored_source then
|
|
return param2_dest
|
|
end
|
|
if dest == replacement.source then
|
|
-- param2_source will hold a 'color' value
|
|
if source == replacement.source then
|
|
-- from 'color' to 'color'
|
|
return param2_source
|
|
else
|
|
-- from 'color' to 'colorfacedir'
|
|
local new_color_index = replacement._color_convert(param2_source, true) % 8
|
|
return param2_dest + (new_color_index * 32)
|
|
end
|
|
else
|
|
-- param2_source will hold a 'colorfacedir' value
|
|
if dest == replacement.source then
|
|
-- from 'colorfacedir' to 'color'
|
|
local old_color = math.floor(param2_source / 32)
|
|
return replacement._color_convert(old_color, false) % 256
|
|
else
|
|
-- from 'colorfacedir' to an other 'colorfacedir'
|
|
local color = math.floor(param2_source / 32)
|
|
return param2_dest + (color * 32)
|
|
end
|
|
end
|
|
end
|
|
|
|
--- {Private} Pick a replacement node.
|
|
-- @param type The replacement shape. Either 'block', 'straight', 'ic' or 'oc'
|
|
-- @param name The name (or id for area) of the node to replace.
|
|
-- @param old_param2 The current value of param2 for the node to replace
|
|
-- @param param2 Facedir value to orient the new node.
|
|
-- @param for_area True when picking for an area, changes the parameter types
|
|
-- @return node {name=new_name, param2=new_param2} or area data {id=new_id, param2_data=new_param2}
|
|
-- or nil if dest node is not found.
|
|
local function pick_replacement(slope_type, name, old_param2, param2, for_area)
|
|
local replacement
|
|
if for_area then
|
|
replacement = naturalslopeslib.get_replacement_id(name)
|
|
else
|
|
replacement = naturalslopeslib.get_replacement(name)
|
|
end
|
|
if not replacement then return nil end
|
|
local dest_node_name = nil
|
|
if slope_type == 'block' and replacement.source then
|
|
dest_node_name = replacement.source
|
|
elseif slope_type == 'pike' and replacement.pike then
|
|
dest_node_name = replacement.pike
|
|
elseif slope_type == 'straight' and replacement.straight then
|
|
dest_node_name = replacement.straight
|
|
elseif slope_type == 'ic' and replacement.inner then
|
|
dest_node_name = replacement.inner
|
|
elseif slope_type == 'oc' and replacement.outer then
|
|
dest_node_name = replacement.outer
|
|
end
|
|
if dest_node_name then
|
|
if param2 == nil then param2 = 0 end
|
|
local color_param2 = manage_param2_color(replacement, name, dest_node_name, old_param2, param2)
|
|
if for_area then
|
|
return {id = dest_node_name, param2_data = color_param2}
|
|
else
|
|
return {name = dest_node_name, param2 = color_param2}
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
|
|
--[[
|
|
Surrounding checks and get replacement
|
|
--]]
|
|
|
|
--- Check if a node is considered empty to switch shape.
|
|
-- @param pos The position to check
|
|
function naturalslopeslib.is_free_for_shape_update(pos)
|
|
if not pos then return nil end
|
|
local node = minetest.get_node_or_nil(pos)
|
|
if node == nil then
|
|
return nil
|
|
end
|
|
return node.name == 'air'
|
|
end
|
|
|
|
local air_id = minetest.get_content_id('air')
|
|
function naturalslopeslib.area_is_free_for_shape_update(area, data, index)
|
|
if not area:containsi(index) then
|
|
return nil
|
|
end
|
|
return data[index] == air_id
|
|
end
|
|
-- Deprecated name
|
|
naturalslopeslib.area_is_free_for_erosion = naturalslopeslib.area_is_free_for_shape_update
|
|
|
|
--- Get the replacement node according to it's surroundings.
|
|
-- @param pos The position of the node or index with VoxelArea.
|
|
-- @param node The node at that position or content id with VoxelArea.
|
|
-- @param area The VoxelArea, nil for single position update.
|
|
-- @param data Data from VoxelManip, nil for single position update.
|
|
-- @param param2_data Param2 data from VoxelManip, nil for single position update.
|
|
-- @return A node to use with minetest.set_node
|
|
-- or a table with id and param2_data if called with an area.
|
|
-- Nil if no replacement is found or a neighbour cannot be read.
|
|
function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_data)
|
|
-- Set functions and data according to update mode: single or VoxelManip
|
|
local is_free = nil
|
|
local new_pos = nil
|
|
local replacement = nil
|
|
local node_name = nil -- Either name or id
|
|
local for_area = false
|
|
local old_param2 = 0
|
|
if area then
|
|
for_area = true
|
|
is_free = function (at_index) -- always use with new_pos
|
|
return naturalslopeslib.area_is_free_for_shape_update(area, data, at_index)
|
|
end
|
|
new_pos = function(add) -- Get new index from current with add position
|
|
local area_pos = area:position(pos)
|
|
return area:indexp(vector.add(area_pos, add))
|
|
end
|
|
node_name = node
|
|
old_param2 = param2_data[pos]
|
|
else
|
|
is_free = naturalslopeslib.is_free_for_shape_update
|
|
new_pos = function(add) return vector.add(pos, add) end
|
|
node_name = node.name
|
|
old_param2 = node.param2
|
|
end
|
|
local is_ground -- ground or ceiling node
|
|
local pointing_y = -1
|
|
-- If there's something above and below, get back to full block
|
|
local above_free = is_free(new_pos({x=0, y=1, z=0}))
|
|
local below_free = is_free(new_pos({x=0, y=-1, z=0}))
|
|
if above_free == nil or below_free == nil then
|
|
return nil
|
|
end
|
|
if above_free and not below_free then
|
|
is_ground = true
|
|
pointing_y = 1
|
|
elseif below_free and not above_free then
|
|
is_ground = false
|
|
pointing_y = 5
|
|
else -- nothing below and above
|
|
return pick_replacement("block", node_name, old_param2, 0, for_area)
|
|
end
|
|
-- Check blocks around
|
|
local airXP = is_free(new_pos({x=1, y=0, z=0}))
|
|
if airXP == nil then return nil end
|
|
local airXM = is_free(new_pos({x=-1, y=0, z=0}))
|
|
if airXM == nil then return nil end
|
|
local airZP = is_free(new_pos({x=0, y=0, z=1}))
|
|
if airZP == nil then return nil end
|
|
local airZM = is_free(new_pos({x=0, y=0, z=-1}))
|
|
if airZM == nil then return nil end
|
|
local free_neighbors = 0
|
|
for index, free in next, {airXP, airXM, airZP, airZM} do
|
|
if free then free_neighbors = free_neighbors + 1 end
|
|
end
|
|
-- For four or three free neighbors, pike (slab)
|
|
if free_neighbors == 4 or free_neighbors == 3 then
|
|
local param2 = 0
|
|
if is_ground == false then param2 = 20 end
|
|
return pick_replacement("pike", node_name, old_param2, param2, for_area)
|
|
-- For two free neighbors
|
|
elseif free_neighbors == 2 then
|
|
-- at opposite sides, block
|
|
local param2
|
|
if (airXP and airXM) or (airZP and airZM) then
|
|
return pick_replacement('block', node_name, old_param2, 0, for_area)
|
|
-- side by side, outer corner
|
|
elseif (airXP and airZP) then
|
|
if is_ground then param2 = 3 else param2 = 22 end
|
|
return pick_replacement("oc", node_name, old_param2, param2, for_area)
|
|
elseif (airXP and airZM) then
|
|
if is_ground then param2 = 0 else param2 = 21 end
|
|
return pick_replacement("oc", node_name, old_param2, param2, for_area)
|
|
elseif (airXM and airZP) then
|
|
if is_ground then param2 = 2 else param2 = 23 end
|
|
return pick_replacement("oc", node_name, old_param2, param2, for_area)
|
|
elseif (airXM and airZM) then
|
|
if is_ground then param2 = 1 else param2 = 20 end
|
|
return pick_replacement("oc", node_name, old_param2, param2, for_area)
|
|
end
|
|
-- For one free neighbor, straight slope
|
|
elseif free_neighbors == 1 then
|
|
local param2 = 0
|
|
if airXP then if is_ground then param2 = 3 else param2 = 15 end
|
|
elseif airXM then if is_ground then param2 = 1 else param2 = 17 end
|
|
elseif airZP then if is_ground then param2 = 2 else param2 = 6 end
|
|
elseif airZM then if is_ground then param2 = 0 else param2 = 8 end
|
|
end
|
|
return pick_replacement("straight", node_name, old_param2, param2, for_area)
|
|
-- For no free neighbor check for a free diagonal for an inner corner
|
|
-- or fully surrounded for a rebuild
|
|
else
|
|
local airXPZP = is_free(new_pos({x=1, y=0, z=1}))
|
|
local airXPZM = is_free(new_pos({x=1, y=0, z=-1}))
|
|
local airXMZP = is_free(new_pos({x=-1, y=0, z=1}))
|
|
local airXMZM = is_free(new_pos({x=-1, y=0, z=-1}))
|
|
local param2
|
|
if airXPZP and not airXPZM and not airXMZP and not airXMZM then
|
|
if is_ground then param2 = 3 else param2 = 15 end
|
|
return pick_replacement("ic", node_name, old_param2, param2, for_area)
|
|
elseif not airXPZP and airXPZM and not airXMZP and not airXMZM then
|
|
if is_ground then param2 = 0 else param2 = 8 end
|
|
return pick_replacement("ic", node_name, old_param2, param2, for_area)
|
|
elseif not airXPZP and not airXPZM and airXMZP and not airXMZM then
|
|
if is_ground then param2 = 2 else param2 = 23 end
|
|
return pick_replacement("ic", node_name, old_param2, param2, for_area)
|
|
elseif not airXPZP and not airXPZM and not airXMZP and airXMZM then
|
|
if is_ground then param2 = 1 else param2 = 17 end
|
|
return pick_replacement("ic", node_name, old_param2, param2, for_area)
|
|
else
|
|
return pick_replacement('block', node_name, old_param2, 0, for_area)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--[[
|
|
Do the replacement
|
|
--]]
|
|
|
|
-- Do shape update when random roll passes on a single node.
|
|
function naturalslopeslib.chance_update_shape(pos, node, factor, type)
|
|
if factor == nil then factor = 1 end
|
|
local replacement = naturalslopeslib.get_replacement(node.name)
|
|
if not replacement then return false end
|
|
local chance_factor = 1
|
|
if type == "mapgen" or type == "stomp" or type == "place" or type == "time" then
|
|
chance_factor = replacement.chance_factors[type]
|
|
end
|
|
if (math.random() * (replacement.chance * factor * chance_factor)) < 1.0 then
|
|
return naturalslopeslib.update_shape(pos, node)
|
|
end
|
|
return false
|
|
end
|
|
|
|
--- Try to update the shape of a node according to it's surroundings.
|
|
-- @param pos The position of the node.
|
|
-- @param node The node at that position.
|
|
-- @return True if the node was updated, false otherwise.
|
|
function naturalslopeslib.update_shape(pos, node)
|
|
local replacement = naturalslopeslib.get_replacement_node(pos, node)
|
|
if replacement and (replacement.name ~= node.name or node.param2 ~= replacement.param2) then
|
|
minetest.set_node(pos, replacement)
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local function get_edges(minp, maxp)
|
|
-- corner000 = minp
|
|
local corner001 = {x = minp.x, y = minp.y, z = maxp.z}
|
|
local corner010 = {x = minp.x, y = maxp.y, z = minp.z}
|
|
local corner011 = {x = minp.x, y = maxp.y, z = maxp.z}
|
|
local corner100 = {x = maxp.x, y = minp.y, z = minp.z}
|
|
local corner101 = {x = maxp.x, y = minp.y, z = maxp.z}
|
|
local corner110 = {x = maxp.x, y = maxp.y, z = minp.z}
|
|
-- corner111 = maxp
|
|
return { -- min pos, max pos, normal[x, y ,z]
|
|
-- The 8 corners
|
|
{minp, minp, {-1, -1, -1}},
|
|
{corner001, corner001, {-1, -1, 1}},
|
|
{corner010, corner010, {-1, 1, -1}},
|
|
{corner011, corner011, {-1, 1, 1}},
|
|
{corner100, corner100, { 1, -1, -1}},
|
|
{corner101, corner101, { 1, -1, 1}},
|
|
{corner110, corner110, { 1, 1, -1}},
|
|
{maxp, maxp, { 1, 1, 1}},
|
|
-- The 8 segments
|
|
{{x = minp.x + 1, y = minp.y, z = minp.z}, {x = maxp.x - 1, y = minp.y, z = minp.z}, { 0, -1, -1}},
|
|
{{x = minp.x + 1, y = maxp.y, z = minp.z}, {x = maxp.x - 1, y = maxp.y, z = minp.z}, { 0, 1, -1}},
|
|
{{x = minp.x, y = minp.y + 1, z = minp.z}, {x = minp.x, y = maxp.y - 1, z = minp.z}, {-1, 0, -1}},
|
|
{{x = maxp.x, y = minp.y + 1, z = minp.z}, {x = maxp.x, y = maxp.y - 1, z = minp.z}, { 1, 0, -1}},
|
|
{{x = minp.x + 1, y = minp.y, z = maxp.z}, {x = maxp.x - 1, y = minp.y, z = maxp.z}, { 0, -1, 1}},
|
|
{{x = minp.x + 1, y = maxp.y, z = maxp.z}, {x = maxp.x - 1, y = maxp.y, z = maxp.z}, { 0, 1, 1}},
|
|
{{x = minp.x, y = minp.y + 1, z = maxp.z}, {x = minp.x, y = maxp.y - 1, z = maxp.z}, { -1, 0, 1}},
|
|
{{x = maxp.x, y = minp.y + 1, z = maxp.z}, {x = maxp.x, y = maxp.y - 1, z = maxp.z}, { 1, 0, 1}},
|
|
-- The 6 faces
|
|
{{x = minp.x + 1, y = minp.y, z = minp.z + 1}, {x = maxp.x - 1, y = minp.y, z = maxp.z - 1}, { 0, -1, 0}},
|
|
{{x = minp.x + 1, y = maxp.y, z = minp.z + 1}, {x = maxp.x - 1, y = maxp.y, z = maxp.z - 1}, { 0, 1, 0}},
|
|
{{x = minp.x, y = minp.y + 1, z = minp.z + 1}, {x = minp.x, y = maxp.y - 1, z = maxp.z - 1}, { -1, 0, 0}},
|
|
{{x = maxp.x, y = minp.y + 1, z = minp.z + 1}, {x = maxp.x, y = maxp.y - 1, z = maxp.z - 1}, { 1, 0, 0}},
|
|
{{x = minp.x + 1, y = minp.y + 1, z = minp.z}, {x = maxp.x - 1, y = maxp.y - 1, z = minp.z}, { 0, 0, -1}},
|
|
{{x = minp.x + 1, y = minp.y + 1, z = maxp.z}, {x = maxp.x - 1, y = maxp.y - 1, z = maxp.z}, { 0, 0, 1}}
|
|
}
|
|
end
|
|
|
|
--- Massive shape update with VoxelManip.
|
|
-- @param minp Lower boundary of area.
|
|
-- @param mapx Higher boundary of area.
|
|
-- @param factor Factor for chance (0.1 means 10 times more likely to update)
|
|
-- @param skip (optional) Don't parse all nodes, skip randomly skip/2 to skip nodes
|
|
-- @param progressive_edges (optional) When true, edges are generated progressively (default)
|
|
-- @param type (optional) Transformation type for chance factor.
|
|
-- at every loop.
|
|
function naturalslopeslib.area_chance_update_shape(minp, maxp, factor, skip, progressive_edges, type)
|
|
if not skip then skip = 0 end
|
|
if progressive_edges == nil then progressive_edges = true end
|
|
-- Run on every block
|
|
local vm, emin, emax = minetest.get_voxel_manip()
|
|
local e1, e2 = vm:read_from_map(minp, maxp)
|
|
local area = VoxelArea:new{MinEdge = e1, MaxEdge = e2}
|
|
local data = vm:get_data()
|
|
local param2_data = vm:get_param2_data()
|
|
local i = area:indexp(e1)
|
|
local imax = area:indexp(e2)
|
|
if progressive_edges then
|
|
local edges = get_edges(minp, maxp)
|
|
for _, edge in ipairs(edges) do
|
|
naturalslopeslib.register_progressive_area_update(edge[1], edge[2], factor, skip, type, {x = edge[3][1], y = edge[3][2], z = edge[3][3]})
|
|
end
|
|
end
|
|
while i <= imax do
|
|
local x = (i-1) % area.ystride
|
|
local y = (i-1) % area.zstride
|
|
if x == 0 or x == area.ystride - 1
|
|
or y == 0 or y == area.zstride - 1 then
|
|
-- Skip edges
|
|
else
|
|
local replacement = naturalslopeslib.get_replacement_id(data[i])
|
|
if replacement ~= nil then
|
|
local chance_factor = 1
|
|
if type == "mapgen" or type == "stomp" or type == "place" or type == "time" then
|
|
chance_factor = replacement.chance_factors[type]
|
|
end
|
|
if math.random() * (replacement.chance * factor * chance_factor) < 1.0 then
|
|
local new_data = naturalslopeslib.get_replacement_node(i, data[i], area, data, param2_data)
|
|
if new_data then
|
|
data[i] = new_data.id
|
|
if new_data.param2_data then
|
|
param2_data[i] = new_data.param2_data
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
i = i + 1 + math.random(skip / 2, skip)
|
|
end
|
|
vm:set_data(data)
|
|
vm:set_param2_data(param2_data)
|
|
vm:write_to_map()
|
|
end
|
|
|
|
naturalslopeslib.progressive_area_updates = {}
|
|
|
|
function naturalslopeslib.register_progressive_area_update(minp, maxp, factor, skip, type, edge_normal)
|
|
if edge_normal ~= nil or minp.x == maxp.x or minp.y == maxp.y or minp.z == maxp.z then
|
|
-- Explicit edge or ignored
|
|
table.insert(naturalslopeslib.progressive_area_updates, {minp = minp, maxp = maxp,
|
|
factor = factor, skip = skip, i = 1, edge_normal = edge_normal})
|
|
return
|
|
end
|
|
-- else register the inner cube and all edges
|
|
-- The inner cube
|
|
table.insert(naturalslopeslib.progressive_area_updates, {
|
|
minp = vector.add(minp, 1),
|
|
maxp = vector.add(maxp, -1),
|
|
factor = factor, skip = skip, i = 1, edge_normal = nil})
|
|
local edges = get_edges(minp, maxp)
|
|
-- Register
|
|
for _, edge in ipairs(edges) do
|
|
table.insert(naturalslopeslib.progressive_area_updates, {
|
|
minp = edge[1], maxp = edge[2],
|
|
factor = factor, type = type, skip = skip, i = 1,
|
|
edge_normal = {x = edge[3][1], y = edge[3][2], z = edge[3][3]}
|
|
})
|
|
end
|
|
end
|
|
|
|
|
|
local function check_area_edges(area)
|
|
if area.edge_normal == nil then
|
|
return true
|
|
end
|
|
local edge = area.edge_normal
|
|
local pos = area.minp
|
|
local requirements = math.abs(edge.x) + math.abs(edge.y) + math.abs(edge.z)
|
|
local found = 0
|
|
if edge.x ~= 0 then
|
|
if minetest.get_node_or_nil(vector.add(pos, {x = edge.x, y = 0, z = 0})) ~= nil then
|
|
found = found + 1
|
|
end
|
|
end
|
|
if edge.y ~= 0 then
|
|
if minetest.get_node_or_nil(vector.add(pos, {x = 0, y = edge.y, z = 0})) ~= nil then
|
|
found = found + 1
|
|
end
|
|
end
|
|
if edge.z ~= 0 then
|
|
if minetest.get_node_or_nil(vector.add(pos, {x = 0, y = 0, z = edge.z})) ~= nil then
|
|
found = found + 1
|
|
end
|
|
end
|
|
return found == requirements
|
|
end
|
|
|
|
local function progressive_area_update(start_time)
|
|
if #naturalslopeslib.progressive_area_updates == 0 then
|
|
return true
|
|
end
|
|
if start_time == nil then
|
|
start_time = os.clock()
|
|
end
|
|
-- pick an area around a player at random and process it
|
|
local players = minetest.get_connected_players()
|
|
local processed_area_index = nil
|
|
local alt_processed_area_index = nil
|
|
for area_index, area in ipairs(naturalslopeslib.progressive_area_updates) do
|
|
for _, p in ipairs(players) do
|
|
local minp = area.minp
|
|
local maxp = area.maxp
|
|
local ppos = p:get_pos()
|
|
if ppos.x >= minp.x and ppos.x <= maxp.x and ppos.y >= minp.y and ppos.y <= maxp.y and ppos.z >= minp.z and ppos.z <= maxp.z then
|
|
-- Prefer an area in which a player is
|
|
if (check_area_edges(area)) then
|
|
processed_area_index = area_index
|
|
break
|
|
end
|
|
elseif alt_processed_area_index == nil and ppos.x + 16 >= minp.x and ppos.x - 16 <= maxp.x and ppos.y + 16 >= minp.y and ppos.y - 16 <= maxp.y and ppos.z + 16 >= minp.z and ppos.z - 16 <= maxp.z then
|
|
-- Else pick an area near a player
|
|
if (check_area_edges(area)) then
|
|
alt_processed_area_index = area_index
|
|
end
|
|
end
|
|
end
|
|
if processed_area_index ~= nil then
|
|
local area = naturalslopeslib.progressive_area_updates[processed_area_index]
|
|
end
|
|
end
|
|
if processed_area_index == nil then
|
|
if alt_processed_area_index ~= nil then
|
|
processed_area_index = alt_processed_area_index
|
|
else
|
|
processed_area_index = 1 -- try to reduce the queue as fast as possible
|
|
end
|
|
end
|
|
local area = naturalslopeslib.progressive_area_updates[processed_area_index]
|
|
local i = area.i
|
|
local y_size = area.maxp.y - area.minp.y + 1
|
|
local z_size = area.maxp.z - area.minp.z + 1
|
|
local imax = y_size * z_size * (area.maxp.x - area.minp.x + 1)
|
|
while i <= imax do
|
|
local x = math.floor((i - 1) / (y_size * z_size))
|
|
local y = math.floor((i - 1) / z_size) % y_size
|
|
local z = (i - 1) % (z_size)
|
|
local pos = {x = area.minp.x + x, y = area.minp.y + y, z = area.minp.z + z}
|
|
local node = minetest.get_node(pos)
|
|
naturalslopeslib.chance_update_shape(pos, node, area.factor, area.type)
|
|
i = i + 1 + math.random(area.skip / 2, area.skip)
|
|
if (os.clock() - start_time) > 0.1 and i <= imax then
|
|
area.i = i
|
|
return false
|
|
end
|
|
end
|
|
table.remove(naturalslopeslib.progressive_area_updates, processed_area_index)
|
|
if os.clock() - start_time < 0.1 then
|
|
progressive_area_update(start_time)
|
|
end
|
|
return true
|
|
end
|
|
|
|
local generation_dtime = 0
|
|
local function generation_globalstep(dtime)
|
|
generation_dtime = generation_dtime + dtime
|
|
if generation_dtime > 0.1 then
|
|
progressive_area_update()
|
|
generation_dtime = 0
|
|
end
|
|
end
|
|
minetest.register_globalstep(generation_globalstep)
|
|
|
|
minetest.register_on_shutdown(function()
|
|
if #naturalslopeslib.progressive_area_updates > 0 then
|
|
minetest.log("info", "Processing slope generation for queued areas")
|
|
for i, area in ipairs(naturalslopeslib.progressive_area_updates) do
|
|
minetest.log("info", (#naturalslopeslib.progressive_area_updates - i + 1) .. " remaining area(s)")
|
|
naturalslopeslib.area_chance_update_shape(area.minp, area.maxp, area.factor, area.skip, false, area.type)
|
|
end
|
|
end
|
|
end)
|
|
|
|
--[[
|
|
Triggers registration
|
|
--]]
|
|
|
|
-- Stomp function to get the replacement node name
|
|
function naturalslopeslib.update_shape_on_walk(player, pos, node, desc, trigger_meta)
|
|
return naturalslopeslib.get_replacement_node(pos, node)
|
|
end
|
|
|
|
-- Chat command
|
|
minetest.register_chatcommand('updshape', {
|
|
func = function(name, param)
|
|
local player = minetest.get_player_by_name(name)
|
|
if not player then return false, 'Player not found' end
|
|
if not minetest.check_player_privs(player, {server=true}) then return false, 'Update shape requires server privileges' end
|
|
local pos = player:get_pos()
|
|
local node_pos = {['x'] = pos.x, ['y'] = pos.y - 1, ['z'] = pos.z}
|
|
local node = minetest.get_node(node_pos)
|
|
if naturalslopeslib.update_shape(node_pos, node) then
|
|
return true, 'Shape updated.'
|
|
end
|
|
return false, node.name .. " cannot have it's shape updated."
|
|
end,
|
|
})
|
|
|
|
-- On generation big update
|
|
local function register_on_generation()
|
|
if not naturalslopeslib._register_on_generated then
|
|
return
|
|
end
|
|
if naturalslopeslib.setting_enable_shape_on_generation() then
|
|
if naturalslopeslib.setting_generation_method() == "Progressive" then
|
|
minetest.register_on_generated(function(minp, maxp, seed)
|
|
naturalslopeslib.register_progressive_area_update(minp, maxp, naturalslopeslib.setting_generation_factor(), naturalslopeslib.setting_generation_skip(), "mapgen")
|
|
end)
|
|
else
|
|
minetest.register_on_generated(function(minp, maxp, seed)
|
|
naturalslopeslib.area_chance_update_shape(minp, maxp, naturalslopeslib.setting_generation_factor(), naturalslopeslib.setting_generation_skip(), true, "mapgen")
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
if not naturalslopeslib.setting_revert() then
|
|
minetest.register_on_mods_loaded(register_on_generation)
|
|
end
|
|
|
|
--- On place neighbor update
|
|
local function on_place_or_dig(pos, force_below)
|
|
local function update(pos, x, y, z, factor)
|
|
local new_pos = vector.add(pos, vector.new(x, y, z))
|
|
naturalslopeslib.chance_update_shape(new_pos, minetest.get_node(new_pos), factor, "place")
|
|
end
|
|
-- Update 8 neighbors plus above and below
|
|
local place_factor = naturalslopeslib.setting_dig_place_factor()
|
|
update(pos, 0, 0, 0, place_factor)
|
|
update(pos, 1, 0, 0, place_factor)
|
|
update(pos, 0, 0, 1, place_factor)
|
|
update(pos, -1, 0, 0, place_factor)
|
|
update(pos, 0, 0, -1, place_factor)
|
|
update(pos, 1, 0, 1, place_factor)
|
|
update(pos, 1, 0, -1, place_factor)
|
|
update(pos, -1, 0, 1, place_factor)
|
|
update(pos, -1, 0, -1, place_factor)
|
|
if force_below then update(pos, 0, -1, 0, 0)
|
|
else update(pos, 0, -1, 0, place_factor)
|
|
end
|
|
update(pos, 0, 1, 0, place_factor)
|
|
end
|
|
|
|
if naturalslopeslib.setting_enable_shape_on_dig_place() and not naturalslopeslib.setting_revert() then
|
|
minetest.register_on_placenode(function(pos, new_node, placer, old_node, item_stack, pointed_thing)
|
|
on_place_or_dig(pos, true)
|
|
end)
|
|
minetest.register_on_dignode(function(pos, old_node, digger)
|
|
on_place_or_dig(pos)
|
|
end)
|
|
end
|
|
|