diff --git a/internal2.lua b/internal2.lua index acee684..e1de6a6 100644 --- a/internal2.lua +++ b/internal2.lua @@ -284,13 +284,17 @@ function Tube:determine_tube_dirs(pos, preferred_pos, fdir) -- Check for secondary nodes (chests and so on) for dir = 1,6 do if allowed[dir] then - local _,npos = self:get_secondary_node(pos, dir) - if npos then - if preferred_pos and vector.equals(npos, preferred_pos) then - preferred_pos = nil - table.insert(tbl, 2, dir) + local node,npos = self:get_secondary_node(pos, dir) + if npos then + if self:is_valid_dir(node, Turn180Deg[dir]) == false then + allowed[dir] = false else - table.insert(tbl, dir) + if preferred_pos and vector.equals(npos, preferred_pos) then + preferred_pos = nil + table.insert(tbl, 2, dir) + else + table.insert(tbl, dir) + end end end end @@ -332,6 +336,8 @@ function Tube:add_tube_dir(pos, dir) if param2 then local d1, d2, num = self:decode_param2(npos, param2) if not num then return end + -- if invalid face, do nothing + if self:is_valid_dir_pos(pos, dir) == false then return end -- not already connected to the new tube? dir = Turn180Deg[dir] if d1 ~= dir and dir ~= d2 then @@ -379,6 +385,9 @@ end function Tube:get_next_teleport_node(pos, dir) if pos then local npos = vector.add(pos, Dir6dToVector[dir or 0]) + if self:is_valid_dir_pos(npos, Turn180Deg[dir]) == false then + return + end local meta = M(npos) local s = meta:get_string("tele_pos") if s ~= "" then diff --git a/tube_api.lua b/tube_api.lua index 62326a3..fdc8b1f 100644 --- a/tube_api.lua +++ b/tube_api.lua @@ -23,12 +23,34 @@ local M = minetest.get_meta local MP = minetest.get_modpath("tubelib2") local I,_ = dofile(MP.."/intllib.lua") +-- Cardinal directions, regardless of orientation local Dir2Str = {"north", "east", "south", "west", "down", "up"} function tubelib2.dir_to_string(dir) return Dir2Str[dir] end +-- Relative directions, dependant on orientation (param2) +local DirToSide = {"B", "R", "F", "L", "D", "U"} + +function tubelib2.dir_to_side(dir, param2) + if dir < 5 then + dir = (((dir - 1) - (param2 % 4)) % 4) + 1 + end + return DirToSide[dir] +end + +local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6} + +function tubelib2.side_to_dir(side, param2) + local dir = SideToDir[side] + if dir < 5 then + dir = (((dir - 1) + (param2 % 4)) % 4) + 1 + end + return dir +end + + local function Tbl(list) local tbl = {} for _,item in ipairs(list) do @@ -159,6 +181,8 @@ local function update_secondary_nodes_after_node_dug(self, pos, dirs) tmp, npos = self:get_secondary_node(pos, dir) end if npos then + self:del_from_cache(npos, Turn180Deg[dir]) + self:del_from_cache(pos, dir) self:update_secondary_node(npos, Turn180Deg[dir]) self:update_secondary_node(pos, dir) end @@ -175,6 +199,7 @@ function Tube:new(attr) max_tube_length = attr.max_tube_length or 1000, primary_node_names = Tbl(attr.primary_node_names or {}), secondary_node_names = Tbl(attr.secondary_node_names or {}), + valid_node_contact_sides = {}, show_infotext = attr.show_infotext or false, force_to_use_tubes = attr.force_to_use_tubes or false, clbk_after_place_tube = attr.after_place_tube, @@ -187,6 +212,9 @@ function Tube:new(attr) o.valid_dirs = Tbl(o.dirs_to_check) setmetatable(o, self) self.__index = self + if attr.valid_node_contact_sides then + o:set_valid_sides_multiple(attr.valid_node_contact_sides) + end return o end @@ -197,6 +225,87 @@ function Tube:add_secondary_node_names(names) end end + +-- Defaults for valid sides configuration +local function invert_booleans(tab) + local inversion = {} + for key, value in pairs(tab) do + inversion[key] = not value + end + return inversion +end +local valid_sides_default_true = Tbl(DirToSide) +local valid_sides_default_false = invert_booleans(valid_sides_default_true) +local function complete_valid_sides(valid_sides, existing_defaults) + local valid_sides_complete = {} + for side, default_value in pairs(existing_defaults) do + local new_value = valid_sides[side] + if new_value == nil then + valid_sides_complete[side] = default_value + else + valid_sides_complete[side] = new_value + end + end + return valid_sides_complete +end + +-- Set sides which are valid +-- with a table of name = valid_sides pairs +function Tube:set_valid_sides_multiple(names) + for name, valid_sides in pairs(names) do + self:set_valid_sides(name, valid_sides) + end +end + +-- Set sides which are invalid +-- with a table of name = valid_sides pairs +function Tube:set_invalid_sides_multiple(names) + for name, invalid_sides in pairs(names) do + self:set_invalid_sides(name, invalid_sides) + end +end + +-- Set sides which are valid +-- will assume all sides not given are invalid +-- Only sets new sides, existing sides will remain +function Tube:set_valid_sides(name, valid_sides) + local existing_defaults = self.valid_node_contact_sides[name] or valid_sides_default_false + self.valid_node_contact_sides[name] = complete_valid_sides(Tbl(valid_sides), existing_defaults) +end + +-- Set sides which are invalid +-- will assume all sides not given are valid +-- Only sets new sides, existing sides will remain +function Tube:set_invalid_sides(name, invalid_sides) + local existing_defaults = self.valid_node_contact_sides[name] or valid_sides_default_true + self.valid_node_contact_sides[name] = complete_valid_sides(invert_booleans(Tbl(invalid_sides)), existing_defaults) +end + +-- Checks the list of valid node connection sides to +-- see if a given side can be connected to +function Tube:is_valid_side(name, side) + local valid_sides = self.valid_node_contact_sides[name] + if valid_sides then + return valid_sides[side] or false + end +end + +-- Checks if a particular node can be connected to +-- from a particular direction, taking into account orientation +function Tube:is_valid_dir(node, dir) + if node and dir ~= nil and self.valid_node_contact_sides[node.name] then + local side = tubelib2.dir_to_side(dir, node.param2) + return self:is_valid_side(node.name, side) + end +end + +-- Checks if a node at a particular position can be connected to +-- from a particular direction, taking into account orientation +function Tube:is_valid_dir_pos(pos, dir) + local node = self:get_node_lvm(pos) + return self:is_valid_dir(node, dir) +end + -- Register further nodes, which should be updated after -- a node/tube is placed/dug function Tube:add_special_node_names(names)