NodeCore mod that adds contraptions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.6 KiB

local util = {}
local AXES = {
x = vector.new(1, 0, 0),
y = vector.new(0, 1, 0),
z = vector.new(0, 0, 1),
}
util.AXES = AXES;
-- Gets an array of vectors relative to `pos` of neighbors that have the specified `match`.
local function find_neighbors_with_name(pos, match)
local result = {}
for _, v in pairs(AXES) do
if minetest.get_node(pos - v).name == match then
table.insert(result, -v)
end
end
for _, v in pairs(AXES) do
if minetest.get_node(pos + v).name == match then
table.insert(result, v)
end
end
return result
end
util.find_neighbors_with_name = find_neighbors_with_name;
-- Moves `pos` towards `dir` while node is still `match`.
-- returns (vector, array) or nil
local function move_until_corner(pos, match, dir)
repeat pos = pos + dir
until minetest.get_node(pos + dir).name ~= match
local neighbors = find_neighbors_with_name(pos, match)
if #neighbors == 2
then return pos, neighbors
else return nil
end
end
-- Moves `pos` towards `dir`, checking that each node has exactly two neighbors
-- that of type `match`, until a corner turning towards `expected_corner_dir` is hit.
-- returns vector or nil
local function move_until_corner_with_checks(pos, match, dir, expected_corner_dir)
while true do
pos = pos + dir
local neighbors = find_neighbors_with_name(pos, match)
if #neighbors ~= 2 then return nil end
-- Get the "next direction" the piece is going.
local next_dir = neighbors[1]
if next_dir == -dir then next_dir = neighbors[2] end
if next_dir ~= dir then
if next_dir == expected_corner_dir
then return pos
else return nil
end
end
end
end
-- Finds a rectangle structure made from the specified node `match`.
-- returns { min = vector, max = vector } or nil
local function find_rectangle(pos, match)
local neighbors = find_neighbors_with_name(pos, match)
if #neighbors ~= 2 then return nil end
-- If we found a line piece (neighbors are opposite) then move in the
-- direction of the smallest xyz coordinate.
if neighbors[1] == -neighbors[2] then
-- NOTE: Due to how `get_neighbors_with_name` is written, the first element
-- is guaranteed to contain the vector pointing towards negative.
pos, neighbors = move_until_corner(pos, match, neighbors[1])
if not pos then return nil end
end
-- We're now guaranteed to be at a corner piece.
-- Move to the corner piece with the smallest xyz coordinate.
while neighbors[1].x + neighbors[1].y + neighbors[1].z < 1 do
pos, neighbors = move_until_corner(pos, match, neighbors[1])
if not pos then return nil end
end
-- Find the neighboring corners of the starting corner.
local first_corner = move_until_corner_with_checks(pos, match, neighbors[1], neighbors[2])
if not first_corner then return nil end
local second_corner = move_until_corner_with_checks(pos, match, neighbors[2], neighbors[1])
if not second_corner then return nil end
-- Continue towards the final corner from the new corners.
first_corner = move_until_corner_with_checks(first_corner, match, neighbors[2], -neighbors[1])
if not first_corner then return nil end
second_corner = move_until_corner_with_checks(second_corner, match, neighbors[1], -neighbors[2])
if not second_corner then return nil end
-- Ensure that they have met up at the same location.
if first_corner ~= second_corner then return nil end
return { min = pos, max = second_corner }
end
util.find_rectangle = find_rectangle;
return util