Minetest-WorldEditAdditions/worldeditadditions/utils/nodes.lua

83 lines
2.8 KiB
Lua

--- Makes an associative table of node_name => weight into a list of node ids.
-- Node names with a heigher weight are repeated more times.
function worldeditadditions.make_weighted(tbl)
local result = {}
for node_name, weight in pairs(tbl) do
local next_id = minetest.get_content_id(node_name)
print("[make_weighted] seen "..node_name.." @ weight "..weight.." → id "..next_id)
for i = 1, weight do
table.insert(
result,
next_id
)
end
end
return result, #result
end
local node_id_air = minetest.get_content_id("air")
local node_id_ignore = minetest.get_content_id("ignore")
--- Determines whether the given node/content id is an airlike node or not.
-- @param id number The content/node id to check.
-- @return bool Whether the given node/content id is an airlike node or not.
function worldeditadditions.is_airlike(id)
-- Do a fast check against air and ignore
if id == node_id_air then
return true
elseif id == node_id_ignore then -- ignore = not loaded yet IIRC (so it could be anything)
return false
end
local name = minetest.get_name_from_content_id(id)
-- If the node isn't registered, then it might not be an air node
if not minetest.registered_nodes[id] then return false end
if minetest.registered_nodes[id].sunlight_propagates == true then
return true
end
-- Check for membership of the airlike group
local airlike_value = minetest.get_item_group(name, "airlike")
if airlike_value ~= nil and airlike_value > 0 then
return true
end
-- Just in case
return false
end
--- Given a manip object and associates, generates a 2D x/z heightmap.
-- Note that pos1 and pos2 should have already been pushed through
-- worldedit.sort_pos(pos1, pos2) before passing them to this function.
-- @param pos1 Vector Position 1 of the region to operate on
-- @param pos2 Vector Position 2 of the region to operate on
-- @param manip VoxelManip The VoxelManip object.
-- @param area area The associated area object.
-- @param data table The associated data object.
-- @return table The ZERO-indexed heightmap data (as 1 single flat array).
function worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
-- z y x (in reverse for little-endian machines) is the preferred loop order, but that isn't really possible here
local heightmap = {}
local hi = 0
local changes = { updated = 0, skipped_columns = 0 }
for z = pos1.z, pos2.z, 1 do
for x = pos1.x, pos2.x, 1 do
local found_node = false
-- Scan each column top to bottom
for y = pos2.y, pos1.y, -1 do
local i = area:index(x, y, z)
if not worldeditadditions.is_airlike(data[i]) then
-- It's the first non-airlike node in this column
heightmap[hi] = pos1.y - y
found_node = true
break
end
end
if not found_node then heightmap[hi] = -1 end
i = i + 1
end
end
return heightmap
end