commit dbb8cdf39d0f05bfbb0abe808a9daea2b1f2358e Author: Joachim Stolberg Date: Fri Oct 5 21:55:40 2018 +0200 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a54599 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Tube Library 2 [tubelib2] + +A library for mods which need connecting tubes / pipes / cables or similar. + +Browse on: ![GitHub](https://github.com/joe7575/tubelib2) + +Download: ![GitHub](https://github.com/joe7575/tubelib2/archive/master.zip) + + +## Dependencies +default + +# License +Copyright (C) 2017-2018 Joachim Stolberg +Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt +Textures: CC0 + +## Dependencies +default + diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +default diff --git a/description.txt b/description.txt new file mode 100644 index 0000000..ad31204 --- /dev/null +++ b/description.txt @@ -0,0 +1,2 @@ +A library for mods which need connecting tubes / pipes / cables or similar. + diff --git a/design.txt b/design.txt new file mode 100644 index 0000000..46de9b6 --- /dev/null +++ b/design.txt @@ -0,0 +1,57 @@ +View to the north + + + dir1/dir2: axis dir: + 6 + A 1 + | / 0 + +--|-----+ A 1 + / o /| | / + +--------+ | |/ + 4 <----| |o----> 2 4 <-------+-------> 3 + | o | | /| + | / | + / | + | / |/ 2 V + +-/------+ 5 + / | + 3 | + V + 5 + + +------+ + | | + +------+ +---+------+---+ +------+ + |XXXXXX| | | | | | | + |XXXXXX| | | | | | | + +------+ +---+------+---+ +------+ + | | + +------+ +dir1/dir2 1/3 2/4 5/6 +axis/rot 3/0 5/1 1/0 + + +------+ +---+------+ +------+ +------+---+ + |XXXXXX| | | | | | | | | + |XXXXXX| | | | | | | | | + +------+ +---+------+ +------+ +------+---+ + | | | | | | | | + +------+ +------+ +------+ +------+ +dir1/dir2 3/5 4/5 1/5 2/5 +axis/rot 0/0 3/3 2/0 0/3 + + +------+ +------+ +------+ +------+ + | | | | | | | | + +------+ +---+------+ +------+ +------+---+ + |XXXXXX| | | | | | | | | + |XXXXXX| | | | | | | | | + +------+ +---+------+ +------+ +------+---+ +axis/rot 3/6 4/6 1/6 2/6 +dir1/dir2 5/0 3/1 2/2 4/3 + + +------+---+ +---+------+ +------+---+ +---+------+ + | | | | | | |XXXXXX| | | |XXXXXX| + | | | | | | |XXXXXX| | | |XXXXXX| + +------+---+ +---+------+ +------+---+ +---+------+ +dir1/dir2 1/2 1/4 2/3 3/4 +axis/rot 2/3 3/2 1/3 1/1 + + diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..bdc5e4c --- /dev/null +++ b/init.lua @@ -0,0 +1,5 @@ +tubelib2 = {} + +dofile(minetest.get_modpath("tubelib2") .. "/tube_api.lua") +dofile(minetest.get_modpath("tubelib2") .. "/internal.lua") +dofile(minetest.get_modpath("tubelib2") .. "/tube_test.lua") diff --git a/internal.lua b/internal.lua new file mode 100644 index 0000000..3116e91 --- /dev/null +++ b/internal.lua @@ -0,0 +1,406 @@ +--[[ + + Tube Library 2 + ============== + + Copyright (C) 2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + internal.lua + +]]-- + +-- for lazy programmers +local P = minetest.pos_to_string +local S = minetest.string_to_pos +local M = minetest.get_meta + + +-- +-- Tubelib2 specific 6D directions (1 = North, 2 = East, 3 = South, 4 = West, 5 = Down, 6 = Up) +-- +-- All 6D dirs are the view from the node to the outer side +-- Tubes are based on two node types, "angled" and "straight" tubes. +-- +-- +-------+ +-- / /| +-------+ +-- +-------+ | / /| +-- | | | / / | +-- | | | +-------+ | +-- | | | | | | +-- | | | | |/ | +-- | | + +-------+| + +-- | |/ | |/ +-- +-------+ +------+ +-- +-- All other nodes are build by means of axis/rotation variants based on param2 +-- (paramtype2 == "facedir"). + + +local Turn180Deg = {3,4,1,2,6,5} + +-- To calculate param2 based on dir6d information +local DirToParam2 = { + -- dir1 / dir2 ==> param2 / type (Angled/Straight) + [12] = {11, "A"}, + [13] = {12, "S"}, + [14] = {14, "A"}, + [15] = { 8, "A"}, + [16] = {10, "A"}, + [23] = { 7, "A"}, + [24] = {21, "S"}, + [25] = { 3, "A"}, + [26] = {19, "A"}, + [34] = { 5, "A"}, + [35] = { 0, "A"}, + [36] = {20, "A"}, + [45] = {15, "A"}, + [46] = {13, "A"}, + [56] = { 4, "S"}, +} + +-- To retrieve dir6d values from the nodes param2 +local Param2ToDir = {} +for k,item in pairs(DirToParam2) do + Param2ToDir[item[1]] = k +end + +-- For neighbour position calculation +local Dir6dToVector = { + {x=0, y=0, z=1}, + {x=1, y=0, z=0}, + {x=0, y=0, z=-1}, + {x=-1, y=0, z=0}, + {x=0, y=-1, z=0}, + {x=0, y=1, z=0}, +} + +local VectorToDir6d = { + [{x=0, y=0, z=1}] = 1, + [{x=1, y=0, z=0}] = 2, + [{x=0, y=0, z=-1}] = 3, + [{x=-1, y=0, z=0}] = 4, + [{x=0, y=-1, z=0}] = 5, + [{x=0, y=1, z=0}] = 6, +} + + +-- +-- Local Functions +-- + +local function Tbl(list) + local tbl = {} + for _,item in ipairs(list) do + tbl[item] = true + end + return tbl +end + +local function range(val, min, max) + if val > max then return max end + if val < min then return min end + return val +end + +local function get_node_lvm(pos) + local node = minetest.get_node_or_nil(pos) + if node then + return node + end + local vm = minetest.get_voxel_manip() + local MinEdge, MaxEdge = vm:read_from_map(pos, pos) + local data = vm:get_data() + local param2_data = vm:get_param2_data() + local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge}) + local idx = area:index(pos.x, pos.y, pos.z) + node = { + name = minetest.get_name_from_content_id(data[idx]), + param2 = param2_data[idx] + } + return node +end + +-- Return node next to pos in direction 'dir' +local function get_next_node(pos, dir) + if dir and Dir6dToVector[dir] then + local npos = vector.add(pos, Dir6dToVector[dir]) + return npos, get_node_lvm(npos) + end + return pos, get_node_lvm(pos) +end + +-- +-- Tubelib2 Methods +-- + +local Tube = tubelib2.Tube + +-- check if node has a connection on the given dir +function Tube:connected(pos, dir) + local _, node = get_next_node(pos, dir) + return self.primary_node_names[node.name] or self.secondary_node_names[node.name] +end + +-- The 3 free bits or param2 are used to store the number of connections. +-- return param2 and tube type +function Tube:encode_param2(dir1, dir2, num_conn) + if dir1 > dir2 then + dir1, dir2 = dir2, dir1 + end + local param2, _type = unpack(DirToParam2[dir1 * 10 + dir2] or {0, "S"}) + return (num_conn * 32) + param2, _type +end + +-- return dir1, dir2, num_conn +function Tube:decode_param2(param2) + local val = Param2ToDir[param2 % 32] + if val then + local dir1, dir2 = math.floor(val / 10), val % 10 + local num_conn = math.floor(param2 / 32) + return dir1, dir2, num_conn + end + return nil +end + +-- return pos for a primary_node and true if num_conn < 2, else false +function Tube:friendly_primary_node(pos, dir) + -- read node + local npos, node = get_next_node(pos, dir) + -- tube node with max one connection? + local _,_,num_conn = self:decode_param2(node.param2) + if self.primary_node_names[node.name] then + return npos, num_conn < 2 + end + return nil +end + +function Tube:secondary_node(pos, dir) + -- read node + local npos, node = get_next_node(pos, dir) + if self.secondary_node_names[node.name] then + return npos + end + return nil +end + +function Tube:fdir(player) + local pitch = player:get_look_pitch() + if pitch > 1.1 then -- up? + return 6 + elseif pitch < -1.1 then -- down? + return 5 + else + return minetest.dir_to_facedir(player:get_look_dir()) + 1 + end +end + +function Tube:get_player_data(placer, pointed_thing) + if placer and pointed_thing and pointed_thing.type == "node" then + if placer:get_player_control().sneak then + return pointed_thing.under, Tube:fdir(placer) + else + return nil, Tube:fdir(placer) + end + end +end + + +-- Check all 6 possible positions for known nodes considering preferred_pos +-- and the players fdir and return dir1, dir2 and the number of tubes to connect to (0..2). +function Tube:determine_tube_dirs(pos, preferred_pos, fdir) + local tbl = {} + local allowed = table.copy(self.allowed_6d_dirs) + + -- Check for primary nodes (tubes) + for dir = 1,6 do + if allowed[dir] then + local npos, friendly = self:friendly_primary_node(pos, dir) + if npos then + if not friendly then + allowed[dir] = false + else + if preferred_pos and vector.equals(npos, preferred_pos) then + preferred_pos = nil + table.insert(tbl, 1, dir) + else + table.insert(tbl, dir) + end + end + end + end + end + + -- If no tube around the pointed pos and player prefers a position, + -- then the new tube shall point to the player. + if #tbl == 0 and preferred_pos and fdir and allowed[Turn180Deg[fdir]] then + tbl[1] = Turn180Deg[fdir] + -- Already 2 dirs found? + elseif #tbl >= 2 then + return tbl[1], tbl[2], 2 + end + + -- Check for secondary nodes (chests and so on) + for dir = 1,6 do + if allowed[dir] then + local npos = self: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) + else + table.insert(tbl, dir) + end + end + end + end + + -- player pointed to an unknown node to force the tube orientation? + if preferred_pos and fdir then + if tbl[1] == Turn180Deg[fdir] and allowed[fdir] then + tbl[2] = fdir + elseif allowed[Turn180Deg[fdir]] then + tbl[2] = Turn180Deg[fdir] + end + end + + -- dir1, dir2 still unknown? + if fdir then + if #tbl == 0 and allowed[Turn180Deg[fdir]] then + tbl[1] = Turn180Deg[fdir] + end + if #tbl == 1 and allowed[Turn180Deg[tbl[1]]] then + tbl[2] = Turn180Deg[tbl[1]] + elseif #tbl == 1 and tbl[1] ~= Turn180Deg[fdir] and allowed[Turn180Deg[fdir]] then + tbl[2] = Turn180Deg[fdir] + end + end + + if #tbl >= 2 and tbl[1] ~= tbl[2] then + local num_tubes = (self:connected(pos, tbl[1]) and 1 or 0) + + (self:connected(pos, tbl[2]) and 1 or 0) + return tbl[1], tbl[2], math.min(2, num_tubes) + end +end + + +function Tube:tube_data_to_table(pos, dir1, dir2, num_tubes) + local param2, ttype = self:encode_param2(dir1, dir2, num_tubes) + return {pos = pos, param2 = param2, type = ttype, num_tubes = num_tubes} +end + + +function Tube:add_tube_dir(pos, dir) + local npos, node = get_next_node(pos, dir) + if self.primary_node_names[node.name] then + local d1, d2, num = self:decode_param2(node.param2) + -- not already connected to the new tube? + dir = Turn180Deg[dir] + if d1 ~= dir and dir ~= d2 then + if num == 0 then + d1 = dir + elseif num == 1 then + -- determine, which of d1, d2 has already a connection + if self:connected(npos, d1) then + d2 = dir + else + d1 = dir + end + end + end + return npos, d1, d2, math.min(num + 1, 2) + end +end + + +function Tube:del_tube_dir(pos, dir) + local npos, node = get_next_node(pos, dir) + if self.primary_node_names[node.name] then + local d1, d2, num = self:decode_param2(node.param2) + return npos, d1, d2, math.max(num - 1, 0) + end +end + +function Tube:get_tube_dirs(pos) + local node = minetest.get_node(pos) + if self.primary_node_names[node.name] then + local d1, d2 = self:decode_param2(node.param2) + return d1, d2 + end +end + +function Tube:get_next_tube(pos, dir) + local npos, node = get_next_node(pos, dir) + local dir1, dir2, num = self:decode_param2(node.param2) + if self.primary_node_names[node.name] then + if Turn180Deg[dir] == dir1 then + return npos, dir2 + else + return npos, dir1 + end + end +end + +function Tube:find_tube_head(pos) + local cnt = 0 + local dir = nil + while cnt <= self.max_tube_length do + local new_pos, new_dir = self:get_next_tube(pos, dir) + if not new_dir then break end + pos, dir = new_pos, new_dir + cnt = cnt + 1 + end + return pos, dir +end + + +-- Do a correction of param2, delete meta data and +-- return the new pos, dir +function Tube:repair_next_tube(pos, dir) + local npos, node = get_next_node(pos, dir) + if self.primary_node_names[node.name] then + local dir1, dir2, num = self:decode_param2(node.param2) + if num ~= 2 then + node.param2 = self:encode_param2(dir1, dir2, 2) + minetest.set_node(npos, node) + end + M(npos):from_table(nil) + if Turn180Deg[dir] == dir1 then + return npos, dir2 + else + return npos, dir1 + end + end +end + +function Tube:repair_tube_line(pos, dir) + local cnt = 0 + if not dir then return pos, cnt end + while cnt <= self.max_tube_length do + local new_pos, new_dir = self:repair_next_tube(pos, dir) + if not new_dir then break end + pos, dir = new_pos, new_dir + cnt = cnt + 1 + end + return pos, cnt +end + +-- update meta data and set number of connections to 1 or 0 +function Tube:update_head_tube(pos1, pos2, num_tubes) + local _, node = get_next_node(pos1) + local dir1, dir2, num = self:decode_param2(node.param2) + num = (self:connected(pos1, dir1) and 1 or 0) + (self:connected(pos1, dir2) and 1 or 0) + node.param2 = self:encode_param2(dir1, dir2, num) + minetest.set_node(pos1, node) + if self.show_infotext then + M(pos1):set_string("infotext", P(pos2).." / "..num_tubes.." tubes") + end + M(pos1):set_string("peer_pos", P(pos2)) +end + +function Tube:add_meta(pos1, pos2, num_tubes) + self:update_head_tube(pos1, pos2, num_tubes) + self:update_head_tube(pos2, pos1, num_tubes) +end diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..a967bf9 --- /dev/null +++ b/mod.conf @@ -0,0 +1 @@ +name=tubelib2 diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..ed55d8a Binary files /dev/null and b/screenshot.png differ diff --git a/textures/tubelib2_hole.png b/textures/tubelib2_hole.png new file mode 100644 index 0000000..572754b Binary files /dev/null and b/textures/tubelib2_hole.png differ diff --git a/textures/tubelib2_tool.png b/textures/tubelib2_tool.png new file mode 100644 index 0000000..1bfeab9 Binary files /dev/null and b/textures/tubelib2_tool.png differ diff --git a/textures/tubelib2_tube.png b/textures/tubelib2_tube.png new file mode 100644 index 0000000..cdc5932 Binary files /dev/null and b/textures/tubelib2_tube.png differ diff --git a/tube_api.lua b/tube_api.lua new file mode 100644 index 0000000..bb0520c --- /dev/null +++ b/tube_api.lua @@ -0,0 +1,149 @@ +--[[ + + Tube Library 2 + ============== + + Copyright (C) 2017-2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + tube_api.lua + +]]-- + +-- for lazy programmers +local P = minetest.pos_to_string +local S = minetest.string_to_pos +local M = minetest.get_meta + + +local function Tbl(list) + local tbl = {} + for _,item in ipairs(list) do + tbl[item] = true + end + return tbl +end + +-- +-- API Functions +-- + +-- Tubelib2 Class +tubelib2.Tube = {} +local Tube = tubelib2.Tube + +function Tube:new(attr) + local o = { + allowed_6d_dirs = attr.allowed_6d_dirs or {true, true, true, true, true, true}, + 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 {}), + show_infotext = attr.show_infotext or false, + } + setmetatable(o, self) + self.__index = self + return o +end + +-- Register (foreign) tubelib compatible nodes +function Tube:add_secondary_node_names(names) + for _,name in ipairs(names) do + self.secondary_node_names[name] = true + end +end + +-- From node to node via tube +-- Used for item transportation via tubes +function Tube:get_connected_node_pos(pos, dir) + -- update_meta + return pos, dir +end + +-- From tube head to tube head +function Tube:get_tube_end_pos(pos) + local spos = M(pos):get_string("peer_pos") + if spos then + return S(spos) + end + local npos, num = self:find_tube_head(pos) + self:update_head_tube(pos, npos, num) + return pos +end + + +-- To be called after a tube node is placed +function Tube:update_tubes_after_place_node(pos, placer, pointed_thing) + local preferred_pos, fdir = self:get_player_data(placer, pointed_thing) + local dir1, dir2, num_tubes = self:determine_tube_dirs(pos, preferred_pos, fdir) + if dir1 == nil then + return {} + end + + local tbl = {self:tube_data_to_table(pos, dir1, dir2, num_tubes)} + + if num_tubes >= 1 then + local npos, d1, d2, num = self:add_tube_dir(pos, dir1) + if npos then + --print("update_tubes_after_place_node: d1, d2, num", d1, d2, num) + tbl[#tbl+1] = self:tube_data_to_table(npos, d1, d2, num) + end + end + + if num_tubes >= 2 then + local npos, d1, d2, num = self:add_tube_dir(pos, dir2) + if npos then + --print("update_tubes_after_place_node: d1, d2, num", d1, d2, num) + tbl[#tbl+1] = self:tube_data_to_table(npos, d1, d2, num) + end + end + + return tbl +end + + +-- To be called after a tube node is removed +function Tube:update_tubes_after_dig_node(pos, oldnode) + local dir1, dir2, num_tubes = self:decode_param2(oldnode.param2) + local tbl = {} + + local npos, d1, d2, num = self:del_tube_dir(pos, dir1) + if npos then + tbl[#tbl+1] = self:tube_data_to_table(npos, d1, d2, num) + end + + npos, d1, d2, num = self:del_tube_dir(pos, dir2) + if npos then + tbl[#tbl+1] = self:tube_data_to_table(npos, d1, d2, num) + end + + return tbl +end + +-- To be called from a repair tool +function Tube:repair_tubes(pos) + local dir1, dir2 = self:get_tube_dirs(pos) + self:repair_next_tube(pos) + local npos1, cnt1 = self:repair_tube_line(pos, dir1) + local npos2, cnt2 = self:repair_tube_line(pos, dir2) + self:add_meta(npos1, npos2, cnt1+cnt2+1) + return npos1, npos2, cnt1, cnt2 +end + +-- To be called from a repair tool +function Tube:remove_tube(pos, sound) + local dir1, dir2 = self:get_tube_dirs(pos) + if dir1 and dir2 then + minetest.sound_play({ + name=sound},{ + gain=1, + max_hear_distance=5, + loop=false}) + local npos1 = self:friendly_primary_node(pos, dir1) + local npos2 = self:friendly_primary_node(pos, dir2) + minetest.remove_node(pos) + if npos1 then self:repair_tubes(npos1) end + if npos2 then self:repair_tubes(npos2) end + end +end diff --git a/tube_test.lua b/tube_test.lua new file mode 100644 index 0000000..77d6c2a --- /dev/null +++ b/tube_test.lua @@ -0,0 +1,208 @@ +--[[ + + Tube Library 2 + ============== + + Copyright (C) 2017-2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + tube_test.lua + + THIS FILE IS ONLY FOR TESTING PURPOSES + +]]-- + +-- for lazy programmers +local P = minetest.pos_to_string +local S = minetest.string_to_pos +local M = minetest.get_meta + +-- Test tubes + +local Tube = tubelib2.Tube:new({ + max_tube_length = 1000, + show_infotext = true, + primary_node_names = {"tubelib2:tubeS", "tubelib2:tubeA"}, + secondary_node_names = {"default:chest", "default:chest_open"}, +}) + +minetest.register_node("tubelib2:tubeS", { + description = "Tubelib2 Test tube", + tiles = { -- Top, base, right, left, front, back + "tubelib2_tube.png", + "tubelib2_tube.png", + "tubelib2_tube.png", + "tubelib2_tube.png", + "tubelib2_hole.png", + "tubelib2_hole.png", + }, + + after_place_node = function(pos, placer, itemstack, pointed_thing) + local nodes = Tube:update_tubes_after_place_node(pos, placer, pointed_thing) + --print("nodes"..dump(nodes)) + if #nodes > 0 then + for _,item in ipairs(nodes) do + --print("after_place_node", item.type, item.param2) + minetest.set_node(item.pos, {name = "tubelib2:tube"..item.type, param2 = item.param2}) + end + return false + else + minetest.remove_node(pos) + return true + end + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + for _,item in ipairs(Tube:update_tubes_after_dig_node(pos, oldnode)) do + --print("after_dig_node", item.type, item.param2) + minetest.set_node(item.pos, {name = "tubelib2:tube"..item.type, param2 = item.param2}) + end + end, + + paramtype2 = "facedir", -- important! + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-2/8, -2/8, -4/8, 2/8, 2/8, 4/8}, + }, + }, + node_placement_prediction = "", -- important! + paramtype = "light", + sunlight_propagates = true, + is_ground_content = false, + groups = {crumbly = 3, cracky = 3, snappy = 3}, + sounds = default.node_sound_glass_defaults(), +}) + +minetest.register_node("tubelib2:tubeA", { + description = "Tubelib2 Test tube", + tiles = { -- Top, base, right, left, front, back + "tubelib2_tube.png", + "tubelib2_hole.png", + "tubelib2_tube.png", + "tubelib2_tube.png", + "tubelib2_tube.png", + "tubelib2_hole.png", + }, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + for _,item in ipairs(Tube:update_tubes_after_dig_node(pos, oldnode)) do + --print("after_dig_node", item.type, item.param2) + minetest.set_node(item.pos, {name = "tubelib2:tube"..item.type, param2 = item.param2}) + end + end, + + paramtype2 = "facedir", -- important! + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-2/8, -4/8, -2/8, 2/8, 2/8, 2/8}, + {-2/8, -2/8, -4/8, 2/8, 2/8, -2/8}, + }, + }, + paramtype = "light", + sunlight_propagates = true, + is_ground_content = false, + groups = {crumbly = 3, cracky = 3, snappy = 3, not_in_creative_inventory=1}, + sounds = default.node_sound_glass_defaults(), + drop = "tubelib2:tubeS", +}) + +local function read_test_type(itemstack, placer, pointed_thing) + local param2 + if pointed_thing.type == "node" then + local node = minetest.get_node(pointed_thing.under) + param2 = node.param2 + else + param2 = 0 + end + local num = math.floor(param2/32) + local axis = math.floor(param2/4) % 8 + local rot = param2 % 4 + minetest.chat_send_player(placer:get_player_name(), "[Tubelib2] param2 = "..param2.."/"..num.."/"..axis.."/"..rot) + + return itemstack +end + +local function TEST_determine_tube_dirs(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.above + local preferred_pos = pointed_thing.under + local fdir = Tube:fdir(placer) + local dir1, dir2, num_tubes = Tube:determine_tube_dirs(pos, preferred_pos, fdir) + print("num_tubes="..num_tubes.." dir1="..(dir1 or "nil").." dir2="..(dir2 or "nil")) + end +end + +local function TEST_update_tubes_after_place_node(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.above + local nodes = Tube:update_tubes_after_place_node(pos, placer, pointed_thing) + print("nodes"..dump(nodes)) + end +end + +local function TEST_add_tube_dir(itemstack, placer, pointed_thing) + read_test_type(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.above + local fdir = Tube:fdir(placer) + local npos, d1, d2, num = Tube:add_tube_dir(pos, fdir) + print("npos, d1, d2, num", npos and P(npos), d1, d2, num) + end +end + +local function TEST_del_tube_dir(itemstack, placer, pointed_thing) + read_test_type(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.above + local fdir = Tube:fdir(placer) + local npos, d1, d2, num = Tube:del_tube_dir(pos, fdir) + print("npos, d1, d2, num", npos and P(npos), d1, d2, num) + end +end + +local function read_param2(pos, player) + local node = minetest.get_node(pos) + local num = math.floor(node.param2/32) + local axis = math.floor(node.param2/4) % 8 + local rot = node.param2 % 4 + minetest.chat_send_player(player:get_player_name(), "[Tubelib2] param2 = "..node.param2.."/"..num.."/"..axis.."/"..rot) +end + +local function repair_tubes(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.under + local pos1, pos2, cnt1, cnt2 = Tube:repair_tubes(pos) + minetest.chat_send_player(placer:get_player_name(), "[Tubelib2] 1: "..P(pos1).." / "..cnt1.." tubes") + minetest.chat_send_player(placer:get_player_name(), "[Tubelib2] 2: "..P(pos2).." / "..cnt2.." tubes") + end +end + +local function remove_tube(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.under + if placer:get_player_control().sneak then + read_param2(pos, placer) + else + Tube:remove_tube(pos, "default_break_glass") + end + end +end + +-- Tool for tube workers to crack a tube line +minetest.register_node("tubelib2:tool", { + description = "Tubelib2 Tool", + inventory_image = "tubelib2_tool.png", + wield_image = "tubelib2_tool.png", + use_texture_alpha = true, + groups = {cracky=1, book=1}, + on_use = remove_tube, + on_place = repair_tubes, + node_placement_prediction = "", +}) +