electricity/internal.lua

360 lines
14 KiB
Lua
Executable File

-- cache node conn data to use it when unloaded?
electricity.conn_cache = {}
-- Can i make "electricity" code simplier?
-- Get node face direction
function electricity.get_node_face_direction(pos)
local node = minetest.get_node(pos)
local node_reg = minetest.registered_nodes[node.name]
local face_vector = nil
if node_reg.paramtype2 == "wallmounted" then
-- face_vector = vector.multiply(minetest.wallmounted_to_dir(node.param2), -1)
local param2_n = node.param2 % 8
face_vector = ({[0]={x=0, y=-1, z=0}, [1]={x=0, y=1, z=0}, [2]={x=-1, y=0, z=0}, [3]={x=1, y=0, z=0}, [4]={x=0, y=0, z=-1}, [5]={x=0, y=0, z=1}, [6]={x=0, y=-1, z=0}, [7]={x=0, y=-1, z=0}})[param2_n]
elseif node_reg.paramtype2 == "facedir" then
-- face_vector = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local param2_n = math.floor((node.param2 % 24)/4)
local param2_m = node.param2 % 4 -- division remainder
face_vector = ({
[0] = {[0]={x=0, y=0, z=-1}, [1]={x=0, y=1, z=0}, [2]={x=0, y=-1, z=0}, [3]={x=0, y=0, z=-1}, [4]={x=0, y=0, z=-1}, [5]={x=0, y=0, z=-1}},
[1] = {[0]={x=-1, y=0, z=0}, [1]={x=-1, y=0, z=0}, [2]={x=-1, y=0, z=0}, [3]={x=0, y=1, z=0}, [4]={x=0, y=-1, z=0}, [5]={x=1, y=0, z=0}},
[2] = {[0]={x=0, y=0, z=1}, [1]={x=0, y=-1, z=0}, [2]={x=0, y=1, z=0}, [3]={x=0, y=0, z=1}, [4]={x=0, y=0, z=1}, [5]={x=0, y=0, z=1}},
[3] = {[0]={x=1, y=0, z=0}, [1]={x=1, y=0, z=0}, [2]={x=1, y=0, z=0}, [3]={x=0, y=-1, z=0}, [4]={x=0, y=1, z=0}, [5]={x=-1, y=0, z=0}},
})[param2_m][param2_n]
else
face_vector = vector.new(1,0,0)
end
return face_vector
end
-- Get node down direction, DEBUG - from face vector
function electricity.get_node_down_direction(pos, face_vector)
local node = minetest.get_node(pos)
local node_reg = minetest.registered_nodes[node.name]
local down_vector = nil
if node_reg.paramtype2 == "wallmounted" then
local param2_n = node.param2 % 8
local top_vector = ({[0]={x=0, y=0, z=-1}, [1]={x=0, y=0, z=-1}, [2]={x=0, y=-1, z=0}, [3]={x=0, y=-1, z=0}, [4]={x=0, y=-1, z=0}, [5]={x=0, y=-1, z=0}, [6]={x=0, y=0, z=1}, [7]={x=0, y=0, z=1}})[param2_n]
down_vector = vector.multiply(top_vector, -1)
elseif node_reg.paramtype2 == "facedir" then
local param2_n = math.floor((node.param2 % 24)/4)
local top_vector = ({[0]={x=0, y=1, z=0}, [1]={x=0, y=0, z=1}, [2]={x=0, y=0, z=-1}, [3]={x=1, y=0, z=0}, [4]={x=-1, y=0, z=0}, [5]={x=0, y=-1, z=0}})[param2_n]
down_vector = vector.multiply(top_vector, -1)
else
down_vector = vector.new(0,-1,0)
end
local facedir = node.param2
return down_vector
end
-- check if first rule connects to pos
function electricity.check_relative_rule(self_pos, to_pos)
local node = minetest.get_node(self_pos)
local node_reg = minetest.registered_nodes[node.name]
if node_reg and
node_reg.electricity and
node_reg.electricity.rules
then
local allrules = node_reg.electricity.rules
local face_vector = electricity.get_node_face_direction(self_pos)
local down_vector = electricity.get_node_down_direction(self_pos, face_vector)
if allrules[1] and allrules[1].x then
for _, rule in ipairs(allrules) do
if vector.equals(electricity.get_pos_relative(self_pos, rule, face_vector, down_vector), to_pos) then
return true
end
end
elseif allrules[1] then
metarule = allrules[1]
for _, rule in ipairs(metarule) do
if vector.equals(electricity.get_pos_relative(self_pos, rule, face_vector, down_vector), to_pos) then
return true
end
end
end
end
return false
end
-- get list of all connected positions for first rule
function electricity.get_connected_pos(self_pos)
local h = minetest.hash_node_position(self_pos)
local node = minetest.get_node_or_nil(self_pos)
-- return from cache when not loaded or has not loaded neighbor
if electricity.conn_cache[h] then
if not node then
return electricity.conn_cache[h]
end
local n1 = minetest.get_node_or_nil({x=self_pos.x+1, y=self_pos.y, z=self_pos.z})
local n2 = minetest.get_node_or_nil({x=self_pos.x-1, y=self_pos.y, z=self_pos.z})
local n3 = minetest.get_node_or_nil({x=self_pos.x, y=self_pos.y, z=self_pos.z+1})
local n4 = minetest.get_node_or_nil({x=self_pos.x, y=self_pos.y, z=self_pos.z-1})
local n5 = minetest.get_node_or_nil({x=self_pos.x, y=self_pos.y+1, z=self_pos.z})
local n6 = minetest.get_node_or_nil({x=self_pos.x, y=self_pos.y-1, z=self_pos.z})
if not n1 or not n2 or not n3 or not n4 or not n5 or not n6 then
return electricity.conn_cache[h]
end
end
local node_reg = minetest.registered_nodes[node.name]
if node_reg and
node_reg.electricity and
node_reg.electricity.rules
then
local allrules = node_reg.electricity.rules
local face_vector = electricity.get_node_face_direction(self_pos)
local down_vector = electricity.get_node_down_direction(self_pos, face_vector)
local connected_pos_list = {}
if allrules[1] and allrules[1].x then
for _, rule in ipairs(allrules) do
local to_pos = electricity.get_pos_relative(self_pos, rule, face_vector, down_vector)
-- minetest.chat_send_all(minetest.serialize(rule))
-- minetest.chat_send_all(minetest.serialize(face_vector))
-- minetest.chat_send_all(minetest.serialize(to_pos))
-- minetest.chat_send_all(minetest.serialize("-"))
if electricity.check_relative_rule(to_pos, self_pos) then
table.insert(connected_pos_list, to_pos)
end
end
elseif allrules[1] then
metarule = allrules[1]
for _, rule in ipairs(metarule) do
local to_pos = electricity.get_pos_relative(self_pos, rule, face_vector, down_vector)
if electricity.check_relative_rule(to_pos, self_pos) then
table.insert(connected_pos_list, to_pos)
end
end
end
electricity.conn_cache[h] = connected_pos_list
return connected_pos_list
end
return {}
end
-- tests if the node can be pushed into, e.g. air, water, grass
function electricity.node_replaceable(name)
if name == "ignore" then return true end
if minetest.registered_nodes[name] then
return minetest.registered_nodes[name].buildable_to or false
end
return false
end
-- Trying optimize mesecons object move function
-- Move all objects in one node position to nev position
function electricity.get_move_objects(pos1, objects_near)
if objects_near == nil then
objects_near = minetest.get_objects_inside_radius(pos1, 2)
end
local objects_to_move = {}
-- function from mesecoins
-- I forgot adding direction part, but oh well it is working...
for id, obj in pairs(objects_near) do
local obj_pos = obj:get_pos()
local cbox = obj:get_properties().collisionbox
local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3]))
local max_pos = vector.add(obj_pos, vector.new(cbox[4], cbox[5], cbox[6]))
local ok = true
for k, v in pairs(pos1) do
local edge1, edge2
if k ~= nil then
edge1 = v - 0.51 -- More than 0.5 to move objects near to the stack.
edge2 = v + 0.51
else
edge1 = v - 0.5 * dir_l
edge2 = v + (#nodestack + 0.5 * movefactor) * dir_l
-- Make sure, edge1 is bigger than edge2:
if edge1 > edge2 then
edge1, edge2 = edge2, edge1
end
end
if min_pos[k] > edge2 or max_pos[k] < edge1 then
ok = false
break
end
end
if ok then
objects_to_move[id] = obj
end
end
return objects_to_move
end
function electricity.move_objects(objects_to_move, pos1, pos2)
local dir = vector.subtract(pos2, pos1)
if dir.y == 1 then
-- Fix for player foot falling inside node
dir.y = 1.1
end
for id, obj in pairs(objects_to_move) do
local obj_pos = obj:get_pos()
local np = vector.add(obj_pos, dir)
obj:move_to(np)
end
end
-- this function is available separatelly in coordinate_helper mod
-- x-FRONT/BACK, z-LEFT/RIGHT, y-UP/DOWN
function electricity.get_pos_relative(position, rel_pos, face_vector, down_vector)
local pos = {x=position.x,y=position.y,z=position.z}
assert(vector.length(face_vector) == 1, "Incorrect face vector")
-- oh no! "wallmounted" and "facedir" cannot store down vector. i choose defaults.
if not down_vector then
down_vector = {x=0, y=0, z=0}
if face_vector.y == 1 then
down_vector.x = 1
elseif face_vector.y == -1 then
down_vector.x = -1
else
down_vector.y = -1
end
end
local node = minetest.get_node(position)
assert(vector.length(down_vector) == 1, "Incorrect down vector")
assert(vector.length(vector.multiply(face_vector, down_vector)) == 0, "Down vector ".."x"..down_vector.x.."y"..down_vector.y.."z"..down_vector.z.." incompatible with face vector ".."x"..face_vector.x.."y"..face_vector.y.."z"..face_vector.z.." "..node.name.." "..node.param2)
if rel_pos.x == 0 and rel_pos.y == 0 and rel_pos.z == 0 then
return {x=pos.x, y=pos.y, z=pos.z}
end
local fdir = face_vector
local ddir = down_vector
if fdir.x == 1 then -- NORD
pos.x = pos.x + rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.x == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == 1 then
pos.y = pos.y + rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.y = pos.y - rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.z = pos.z - rel_pos.z
end
elseif fdir.z == -1 then -- EAST
pos.z = pos.z - rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.x = pos.x + rel_pos.z
elseif ddir.x == 1 then
pos.y = pos.y + rel_pos.z
pos.x = pos.x - rel_pos.y
elseif ddir.x == -1 then
pos.y = pos.y - rel_pos.z
pos.x = pos.x + rel_pos.y
elseif ddir.z == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.x = pos.x - rel_pos.z
end
elseif fdir.x == -1 then -- SOUTH
pos.x = pos.x - rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.x == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == 1 then
pos.y = pos.y - rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.y = pos.y + rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.z = pos.z + rel_pos.z
end
elseif fdir.z == 1 then -- WEST
pos.z = pos.z + rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.x = pos.x - rel_pos.z
elseif ddir.x == 1 then
pos.y = pos.y - rel_pos.z
pos.x = pos.x - rel_pos.y
elseif ddir.x == -1 then
pos.y = pos.y + rel_pos.z
pos.x = pos.x + rel_pos.y
elseif ddir.z == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.x = pos.x + rel_pos.z
end
elseif fdir.y == 1 then -- UP
pos.y = pos.y + rel_pos.x
if ddir.y == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == 1 then
pos.x = pos.x - rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.x == -1 then
pos.x = pos.x + rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.z == 1 then
pos.x = pos.x - rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.x = pos.x + rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
assert(false, "Impossible vector combination!")
end
elseif fdir.y == -1 then -- DOWN
pos.y = pos.y - rel_pos.x
if ddir.y == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == 1 then
pos.x = pos.x - rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.x == -1 then
pos.x = pos.x + rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.z == 1 then
pos.x = pos.x + rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.x = pos.x - rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
assert(false, "Impossible vector combination!")
end
end
return pos
end