tubelib2/internal1.lua
Joachim Stolberg fd2599f676 v0.4 - bugfixes
2018-11-13 21:09:05 +01:00

279 lines
8.4 KiB
Lua

--[[
Tube Library 2
==============
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
internal1.lua
First level functions behind the API
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local Tube = tubelib2.Tube
local Turn180Deg = tubelib2.Turn180Deg
local Dir6dToVector = tubelib2.Dir6dToVector
local tValidNum = {[0] = true, true, true} -- 0..2 are valid
--------------------------------------------------------------------------------------
-- node get/test functions
--------------------------------------------------------------------------------------
-- Check if node at given position is a tube node
-- If dir == nil then node_pos = pos
-- Function returns the new pos or nil
function Tube:primary_node(pos, dir)
local npos, node = self:get_node(pos, dir)
if self.primary_node_names[node.name] then
return npos
end
end
-- Check if node at given position is a secondary node
-- If dir == nil then node_pos = pos
-- Function returns the new pos or nil
function Tube:secondary_node(pos, dir)
local npos, node = self:get_node(pos, dir)
if self.secondary_node_names[node.name] then
return npos
end
end
-- Used to determine the node side to the tube connection.
-- Function returns the first found dir value
-- to a primary node.
-- Only used by convert.set_pairing()
function Tube:get_primary_dir(pos)
-- Check all valid positions
for dir = 1,6 do
if self:primary_node(pos, dir) then
return dir
end
end
end
-- Return the new pos behind pos/dir and the dir our of the node.
function Tube:get_pos(pos, dir)
return vector.add(pos, Dir6dToVector[dir or 0]), Turn180Deg[dir]
end
--------------------------------------------------------------------------------------
-- get/del/add meta data functions
--------------------------------------------------------------------------------------
function Tube:del_meta(pos, dir)
local npos, node = self:get_node(pos, dir)
if self.primary_node_names[node.name] then
local meta = M(npos)
local peer_pos = meta:get_string("peer_pos")
local peer_dir = meta:get_int("peer_dir")
meta:from_table(nil)
if peer_pos ~= "" then
return P(peer_pos), peer_dir
end
end
return self:repair_tube_line(pos, dir)
end
function Tube:get_meta(pos, dir)
local npos = vector.add(pos, Dir6dToVector[dir or 0])
local meta = M(npos)
local peer_pos = meta:get_string("peer_pos")
local peer_dir = meta:get_int("peer_dir")
if peer_pos ~= "" then
return P(peer_pos), peer_dir
end
return self:repair_tube_line(pos, dir)
end
-- Like get_meta(), but repair data if necessary
function Tube:repair_meta(pos, dir)
local npos = vector.add(pos, Dir6dToVector[dir or 0])
local meta = M(npos)
local peer_pos = meta:get_string("peer_pos")
local peer_dir = meta:get_int("peer_dir")
if peer_pos ~= "" then
return P(peer_pos), peer_dir
end
peer_pos, peer_dir = self:repair_tube_line(pos, dir)
self:add_meta(npos, peer_pos, peer_dir)
return peer_pos, peer_dir
end
function Tube:get_oldmeta(pos, dir, oldmetadata)
if oldmetadata.fields and oldmetadata.fields.peer_pos then
return P(oldmetadata.fields.peer_pos), tonumber(oldmetadata.fields.peer_dir)
end
return self:repair_tube_line(pos, dir)
end
-- Add meta data from the other tube head node
function Tube:add_meta(pos, peer_pos, peer_dir)
local _, node = self:get_node(pos)
if self.primary_node_names[node.name] then
if self.show_infotext then
M(pos):set_string("infotext", S(peer_pos))
end
M(pos):set_string("peer_pos", S(peer_pos))
M(pos):set_int("peer_dir", peer_dir)
end
end
--------------------------------------------------------------------------------------
-- Further helper functions
--------------------------------------------------------------------------------------
-- Do a correction of param2, delete meta data of all 2-conn-tubes,
-- and return peer_pos, peer_dir, and number of tube nodes.
function Tube:repair_tube_line(pos, dir)
local repair_next_tube = function(self, pos, dir)
local npos, dir1, dir2 = self:determine_next_node(pos, dir)
if dir1 then
M(npos):from_table(nil)
if Turn180Deg[dir] == dir1 then
return npos, dir2
else
return npos, dir1
end
end
return self:get_next_teleport_node(pos, dir)
end
print("repair_tube_line")
local cnt = 0
if not dir then return pos, dir, cnt end
while cnt <= self.max_tube_length do
local new_pos, new_dir = repair_next_tube(self, pos, dir)
if not new_dir then break end
pos, dir = new_pos, new_dir
cnt = cnt + 1
end
return pos, dir, cnt
end
-- fpos,fdir points to the secondary node to be updated.
-- npos,ndir are used to calculate the connection data to be written.
function Tube:update_secondary_node(fpos,fdir, npos,ndir)
-- [s]<-[n]----[f]->[s]
local fpos2, node = self:get_node(fpos, fdir)
if minetest.registered_nodes[node.name].tubelib2_on_update then
local npos2 = self:get_pos(npos, ndir)
if vector.equals(npos2, fpos2) then -- last tube removed?
npos2,ndir = nil,nil -- used to delete the data base
end
minetest.registered_nodes[node.name].tubelib2_on_update(fpos2, Turn180Deg[fdir], npos2, ndir)
end
end
--------------------------------------------------------------------------------------
-- pairing functions
--------------------------------------------------------------------------------------
-- Pairing helper function
function Tube:store_teleport_data(pos, peer_pos)
local meta = M(pos)
meta:set_string("tele_pos", S(peer_pos))
meta:set_string("channel", nil)
meta:set_string("formspec", nil)
meta:set_string("infotext", "Connected with "..S(peer_pos))
return meta:get_int("tube_dir")
end
-------------------------------------------------------------------------------
-- update-after/get-dir functions
-------------------------------------------------------------------------------
function Tube:update_after_place_node(pos, dirs)
-- Check all valid positions
local lRes= {}
dirs = dirs or self.dirs_to_check
for _,dir in ipairs(dirs) do
local npos, d1, d2, num = self:add_tube_dir(pos, dir)
if npos and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(self:tube_data_to_table(npos, d1, d2, num))
lRes[#lRes+1] = dir
end
end
return lRes
end
function Tube:update_after_dig_node(pos, dirs)
-- Check all valid positions
local lRes= {}
dirs = dirs or self.dirs_to_check
for _,dir in ipairs(dirs) do
local npos, d1, d2, num = self:del_tube_dir(pos, dir)
if npos and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(self:tube_data_to_table(npos, d1, d2, num))
lRes[#lRes+1] = dir
end
end
return lRes
end
function Tube:update_after_place_tube(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 false
end
if self.valid_dirs[dir1] and self.valid_dirs[dir2] and tValidNum[num_tubes]then
self.clbk_after_place_tube(self:tube_data_to_table(pos, dir1, dir2, num_tubes))
end
if num_tubes >= 1 then
local npos, d1, d2, num = self:add_tube_dir(pos, dir1)
if npos and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(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 and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(self:tube_data_to_table(npos, d1, d2, num))
end
end
return true, dir1, dir2, num_tubes
end
function Tube:update_after_dig_tube(pos, param2)
local dir1, dir2, num_tubes = self:decode_param2(pos, param2)
local lRes = {}
local npos, d1, d2, num = self:del_tube_dir(pos, dir1)
if npos and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(self:tube_data_to_table(npos, d1, d2, num))
lRes[#lRes+1] = dir1
end
npos, d1, d2, num = self:del_tube_dir(pos, dir2)
if npos and self.valid_dirs[d1] and self.valid_dirs[d2] and tValidNum[num]then
self.clbk_after_place_tube(self:tube_data_to_table(npos, d1, d2, num))
lRes[#lRes+1] = dir2
end
return lRes
end
function Tube:update_secondary_nodes_after_dig_tube(pos)
local d1, d2 = self:determine_dir1_dir2_and_num_conn(pos)
if d1 then
self:update_secondary_node(pos,d1, pos,d1)
end
if d2 then
self:update_secondary_node(pos,d2, pos,d2)
end
end