mods that hopefully work for a TechAge-based pack
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
--[[
|
||||
|
||||
Tube Library 2
|
||||
==============
|
||||
|
||||
Copyright (C) 2018-2021 Joachim Stolberg
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
internal.lua
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local S2P = minetest.string_to_pos
|
||||
local M = minetest.get_meta
|
||||
|
||||
-- Load support for I18n.
|
||||
local S = tubelib2.S
|
||||
|
||||
local Tube = {}
|
||||
|
||||
local Turn180Deg = {[0]=0,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 = {[0] =
|
||||
{x=0, y=0, z=0},
|
||||
{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},
|
||||
}
|
||||
|
||||
tubelib2.Tube = Tube
|
||||
tubelib2.Turn180Deg = Turn180Deg
|
||||
tubelib2.DirToParam2 = DirToParam2
|
||||
tubelib2.Param2ToDir = Param2ToDir
|
||||
tubelib2.Dir6dToVector = Dir6dToVector
|
||||
|
||||
|
||||
--
|
||||
-- Tubelib2 Methods
|
||||
--
|
||||
|
||||
function Tube: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
|
||||
|
||||
-- Read param2 from a primary node at the given position.
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns param2, new_pos or nil
|
||||
function Tube:get_primary_node_param2(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
self.node = self:get_node_lvm(npos)
|
||||
if self.primary_node_names[self.node.name] then
|
||||
return self.node.param2, npos
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if node at given position is a tube node
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns true/false
|
||||
function Tube:is_primary_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
local node = self:get_node_lvm(npos)
|
||||
return self.primary_node_names[node.name]
|
||||
end
|
||||
|
||||
-- Get secondary node at given position
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns node and new_pos or nil
|
||||
function Tube:get_secondary_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
local node = self:get_node_lvm(npos)
|
||||
if self.secondary_node_names[node.name] then
|
||||
return node, npos
|
||||
end
|
||||
end
|
||||
|
||||
-- Get special registered nodes at given position
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns node and new_pos or nil
|
||||
function Tube:get_special_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
local node = self:get_node_lvm(npos)
|
||||
if self.special_node_names[node.name] then
|
||||
return node, npos
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if node at given position is a secondary node
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns true/false
|
||||
function Tube:is_secondary_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
local node = self:get_node_lvm(npos)
|
||||
return self.secondary_node_names[node.name]
|
||||
end
|
||||
|
||||
-- Check if node at given position is a special node
|
||||
-- If dir == nil then node_pos = pos
|
||||
-- Function returns true/false
|
||||
function Tube:is_special_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
local node = self:get_node_lvm(npos)
|
||||
return self.special_node_names[node.name]
|
||||
end
|
||||
|
||||
-- Check if node has a connection on the given dir
|
||||
function Tube:connected(pos, dir)
|
||||
return self:is_primary_node(pos, dir) or self:is_secondary_node(pos, dir)
|
||||
end
|
||||
|
||||
function Tube:get_next_tube(pos, dir)
|
||||
local param2, npos = self:get_primary_node_param2(pos, dir)
|
||||
if param2 then
|
||||
local val = Param2ToDir[param2 % 32] or 0
|
||||
local dir1, dir2 = math.floor(val / 10), val % 10
|
||||
local num_conn = math.floor(param2 / 32) or 0
|
||||
local odir = Turn180Deg[dir]
|
||||
if odir == dir1 then
|
||||
return npos, dir2, num_conn
|
||||
elseif odir == dir2 then
|
||||
return npos, dir1, num_conn
|
||||
end
|
||||
return
|
||||
end
|
||||
return self:get_next_teleport_node(pos, dir)
|
||||
end
|
||||
|
||||
-- Return param2 and tube type ("A"/"S")
|
||||
function Tube:encode_param2(dir1, dir2, num_conn)
|
||||
if dir1 and dir2 and num_conn then
|
||||
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 0, "S"
|
||||
end
|
||||
|
||||
|
||||
-- Return dir1, dir2, num_conn
|
||||
function Tube:decode_param2(pos, 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
|
||||
end
|
||||
|
||||
function Tube:repair_tube(pos, dir)
|
||||
local param2, npos = self:get_primary_node_param2(pos, dir)
|
||||
if param2 then
|
||||
local dir1, dir2 = self:decode_param2(npos, param2)
|
||||
local param2, tube_type = self:encode_param2(dir1, dir2, 2)
|
||||
self.clbk_after_place_tube(npos, param2, tube_type, 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Return node next to pos in direction 'dir'
|
||||
function Tube:get_node(pos, dir)
|
||||
local npos = vector.add(pos, Dir6dToVector[dir or 0])
|
||||
return npos, self:get_node_lvm(npos)
|
||||
end
|
||||
|
||||
-- format and return given data as table
|
||||
function Tube:get_tube_data(pos, dir1, dir2, num_tubes, state)
|
||||
local param2, tube_type = self:encode_param2(dir1, dir2, num_tubes)
|
||||
return pos, param2, tube_type, num_tubes, state
|
||||
end
|
||||
|
||||
-- Return pos for a primary_node and true if num_conn < 2, else false
|
||||
function Tube:friendly_primary_node(pos, dir)
|
||||
local param2, npos = self:get_primary_node_param2(pos, dir)
|
||||
if param2 then
|
||||
local _,_,num_conn = self:decode_param2(npos, param2)
|
||||
-- tube node with max one connection?
|
||||
return npos, (num_conn or 2) < 2
|
||||
end
|
||||
end
|
||||
|
||||
function Tube:vector_to_dir(v)
|
||||
if v.y > 0 then
|
||||
return 6
|
||||
elseif v.y < 0 then
|
||||
return 5
|
||||
else
|
||||
return minetest.dir_to_facedir(v) + 1
|
||||
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.valid_dirs)
|
||||
|
||||
-- If the node at players "prefered position" is a tube,
|
||||
-- then the other side of the new tube shall point to the player.
|
||||
if preferred_pos then
|
||||
local _, friendly = self:friendly_primary_node(preferred_pos)
|
||||
if friendly then
|
||||
local v = vector.direction(pos, preferred_pos)
|
||||
local dir1 = self:vector_to_dir(v)
|
||||
local dir2 = fdir < 5 and Turn180Deg[fdir] or fdir
|
||||
return dir1, dir2, 1
|
||||
end
|
||||
end
|
||||
-- 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 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
|
||||
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
|
||||
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
|
||||
|
||||
-- dir1, dir2 still unknown?
|
||||
if fdir and #tbl < 2 then
|
||||
-- Try to turn the node by 90 degrees
|
||||
local dir1 = fdir < 5 and (fdir + 1) % 4 or fdir
|
||||
local dir2 = dir1 < 5 and Turn180Deg[dir1] or dir1
|
||||
if dir1 ~= dir2 and allowed[dir1] and allowed[dir2] then
|
||||
return dir1, dir2, 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Determine a tube side without connection, increment the number of connections
|
||||
-- and return the new data to be able to update the node:
|
||||
-- new_pos, dir1, dir2, num_connections (1, 2)
|
||||
function Tube:add_tube_dir(pos, dir)
|
||||
local param2, npos = self:get_primary_node_param2(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
|
||||
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, num
|
||||
end
|
||||
end
|
||||
|
||||
-- Decrement the number of tube connections
|
||||
-- and return the new data to be able to update the node:
|
||||
-- new_pos, dir1, dir2, num_connections (0, 1)
|
||||
function Tube:del_tube_dir(pos, dir)
|
||||
local param2, npos = self:get_primary_node_param2(pos, dir)
|
||||
if param2 then
|
||||
local d1, d2, num = self:decode_param2(npos, param2)
|
||||
-- check if node is connected to the given pos
|
||||
dir = Turn180Deg[dir]
|
||||
if d1 == dir or dir == d2 then
|
||||
return npos, d1, d2, math.max((num or 1) - 1, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Pairing helper function
|
||||
function Tube:store_teleport_data(pos, peer_pos)
|
||||
local meta = M(pos)
|
||||
meta:set_string("tele_pos", P2S(peer_pos))
|
||||
meta:set_string("channel", "")
|
||||
meta:set_string("formspec", "")
|
||||
meta:set_string("infotext", S("Connected to @1", P2S(peer_pos)))
|
||||
return meta:get_int("tube_dir")
|
||||
end
|
||||
|
||||
-- Jump over the teleport nodes to the next tube node
|
||||
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
|
||||
local tele_pos = S2P(s)
|
||||
local tube_dir = M(tele_pos):get_int("tube_dir")
|
||||
if tube_dir ~= 0 then
|
||||
return tele_pos, tube_dir
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Tube:dbg_out()
|
||||
for pos1,item1 in pairs(self.connCache) do
|
||||
for dir1,item2 in pairs(item1) do
|
||||
print("pos1="..pos1..", dir1="..dir1..", pos2="..P2S(item2.pos2)..", dir2="..item2.dir2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Walk to the end of the tube line and return pos and outdir of both head tube nodes.
|
||||
-- If no tube is available, return nil
|
||||
function Tube:walk_tube_line(pos, dir)
|
||||
local cnt = 0
|
||||
if dir then
|
||||
while cnt <= self.max_tube_length do
|
||||
local new_pos, new_dir, num = self:get_next_tube(pos, dir)
|
||||
if not new_pos then break end
|
||||
if cnt > 0 and num ~= 2 and self:is_primary_node(new_pos, new_dir) then
|
||||
self:repair_tube(new_pos, new_dir)
|
||||
end
|
||||
pos, dir = new_pos, new_dir
|
||||
cnt = cnt + 1
|
||||
end
|
||||
if cnt > 0 then
|
||||
return pos, dir, cnt
|
||||
end
|
||||
end
|
||||
return table.copy(pos), dir, 0
|
||||
end
|
||||
Reference in New Issue
Block a user