Multiple updates:

1)  Refactor autoplace,

There was a lot of redundant code and like a dozen unneccessary string
scans for every node next to every tube placed! I put it all into
indexed tables and loops instead of bizarre and unexplainable variable
names and copy and pasted code. There was also no support for notifying
a chest when an item has been taken from it by a filter, so I added
something for that.

I also thought it prudent to fall back on the
allow_metadata_inventory_take function should a special can_remove not
exist. In fact if can_insert doesn't exist, it calls
allow_metadata_inventory_put instead.

I also added a thing for allowing pipes to attach to nodes of other
modules, without having to hard code type all those node names into
autoplace.lua.  Basically node.tube.collects(i,param2) and i is the
direction from the pipe and param2 is the param2 of what it's pointing
at.

I also abstracted the inscrutable correlation between i and
param2 by trial and error (and the paramwand mod) into understandable
functions. There was no pipeworks namespace so I created it, and put
these functions into pipeworks.collects (as distinguished from a
        node.tube.collects function, which uses those functions)

And now it's too late to cart my old clothes to the thrift store,
dangit.

2)  My "node.tube.collects" idea might be redundant with the
node.tube.connect_sides thing, though possibly more versatile so I'll
leave it in.

3) I was using node.tube.connects and fancy functions for checking if it's
the sides or top or whatnot, and this connect_side thing came in. This
should make both my way and the way using connect_side work.

Also removed some debugging cruft
This commit is contained in:
Cy 2013-10-14 23:45:07 -04:00 committed by Vanessa Ezekowitz
parent 79897c8fe6
commit 28328d975c
2 changed files with 284 additions and 152 deletions

View File

@ -108,7 +108,6 @@ end
function tube_scanforobjects(pos) function tube_scanforobjects(pos)
if pos == nil then return end if pos == nil then return end
print("tubes_scanforobjects called at pos "..dump(pos))
tube_autoroute({ x=pos.x-1, y=pos.y , z=pos.z }) tube_autoroute({ x=pos.x-1, y=pos.y , z=pos.z })
tube_autoroute({ x=pos.x+1, y=pos.y , z=pos.z }) tube_autoroute({ x=pos.x+1, y=pos.y , z=pos.z })
tube_autoroute({ x=pos.x , y=pos.y-1, z=pos.z }) tube_autoroute({ x=pos.x , y=pos.y-1, z=pos.z })
@ -129,104 +128,225 @@ function is_tube(nodename)
return in_table(tubenodes,nodename) return in_table(tubenodes,nodename)
end end
function tube_autoroute(pos) if pipeworks == nil then
local nctr = minetest.get_node(pos) pipeworks = {}
end
-- this was tested experimentally, because I can't the whole bit arithematic
-- with these facingRight means "We're facing the right side of whatever it is"
pipeworks.connects = {
-- a filter's output is on the right, input on the left
facingLeft = function (i,param2)
-- measured with a mese filter
if i == 1 then
return param2 == 2 or param2 == 6 or param2 == 10 or param2 == 20
elseif i == 2 then
return param2 == 0 or param2 == 4 or param2 == 8 or param2 == 22
elseif i == 3 then
return param2 == 7 or param2 == 9 or param2 == 12 or param2 == 18
elseif i == 4 then
return param2 == 5 or param2 == 11 or param2 == 14 or param2 == 16
elseif i == 5 then
return param2 == 1 or param2 == 13 or param2 == 17 or param2 == 21
elseif i == 6 then
return param2 == 3 or param2 == 15 or param2 == 19
end
end,
facingRight = function (i,param2)
-- measured with a mese filter
if i == 1 then
return param2 == 0 or param2 == 4 or param2 == 8 or param2 == 22
elseif i == 2 then
return param2 == 2 or param2 == 6 or param2 == 10 or param2 == 20
elseif i == 3 then
return param2 == 5 or param2 == 11 or param2 == 14 or param2 == 16
elseif i == 4 then
return param2 == 7 or param2 == 9 or param2 == 12 or param2 == 18
elseif i == 5 then
return param2 == 3 or param2 == 15 or param2 == 19
elseif i == 6 then
return param2 == 1 or param2 == 13 or param2 == 17 or param2 == 21
end
end,
facingFront = function (i,param2)
-- measured with a chest and a technic:nodebreaker
if i == 1 then
return param2 == 3 or param2 == 7 or param2 == 11 or param2 == 21
elseif i == 2 then
return param2 == 1 or param2 == 5 or param2 == 9
elseif i == 3 then
return param2 == 4 or param2 == 10 or param2 == 14 or param2 == 19
elseif i == 4 then
return param2 == 6 or param2 == 8 or param2 == 15 or param2 == 17
elseif i == 5 then
return param2 == 14 or param2 == 18 or param2 == 22 or param2 == 2
elseif i == 6 then
return param2 == 12 or param2 == 16 or param2 == 20 or param2 == 0
end
end,
facingSide = function (i,param2)
-- aka not top or bottom
-- measured with a chair
if i == 1 or i == 2 then
return not (param2 >= 12 and param2 <= 19)
elseif i == 3 or i == 4 then
return not ((param2 >= 0 and param2 < 4) or (param2 >= 20 and param2 <= 22))
elseif i == 5 or i == 6 then
return not (param2 >= 4 and param2 <= 11)
end
end,
facingTop = function(i,param2)
-- measured with a chair
if i == 1 then
return param2 >= 16 and param2 <= 20
elseif i == 2 then
return param2 >= 12 and param2 < 16
elseif i == 3 then
return param2 >= 0 and param2 < 4
elseif i == 4 then
return param2 >= 21 and param2 < 23
elseif i == 5 then
return param2 >= 4 and param2 < 8
elseif i == 6 then
return param2 >= 8 and param2 < 12
-- else error bad value for i
end
end
}
--a function for determining which side of the node we are on --a function for determining which side of the node we are on
local function nodeside(node, tubedir) local function nodeside(node, tubedir)
--get a vector pointing back
local backdir = facedir_to_dir(node.param2)
--get a vector pointing back --check whether the vector is equivalent to the tube direction; if it is, the tube's on the backside
local backdir = facedir_to_dir(node.param2) if backdir.x == tubedir.x and backdir.y == tubedir.y and backdir.z == tubedir.z then
return "back"
end
--check whether the vector is equivalent to the tube direction; if it is, the tube's on the backside --check whether the vector is antiparallel with the tube direction; that indicates the front
if backdir.x == tubedir.x and backdir.y == tubedir.y and backdir.z == tubedir.z then if backdir.x == -tubedir.x and backdir.y == -tubedir.y and backdir.z == -tubedir.z then
return "back" return "front"
end end
--check whether the vector is antiparallel with the tube direction; that indicates the front --facedir is defined in terms of the top-bottom axis of the node; we'll take advantage of that
if backdir.x == -tubedir.x and backdir.y == -tubedir.y and backdir.z == -tubedir.z then local topdir = ({[0]={x=0, y=1, z=0},
return "front" {x=0, y=0, z=1},
end {x=0, y=0, z=-1},
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0}})[math.floor(node.param2/4)]
--facedir is defined in terms of the top-bottom axis of the node; we'll take advantage of that --is this the top?
local topdir = ({[0]={x=0, y=1, z=0}, if topdir.x == tubedir.x and topdir.y == tubedir.y and topdir.z == tubedir.z then
{x=0, y=0, z=1}, return "top"
{x=0, y=0, z=-1}, end
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=-1, z=0}})[math.floor(node.param2/4)]
--is this the top? --or the bottom?
if topdir.x == tubedir.x and topdir.y == tubedir.y and topdir.z == tubedir.z then if topdir.x == -tubedir.x and topdir.y == -tubedir.y and topdir.z == -tubedir.z then
return "top" return "bottom"
end end
--or the bottom? --we shall apply some maths to obtain the right-facing vector
if topdir.x == -tubedir.x and topdir.y == -tubedir.y and topdir.z == -tubedir.z then local rightdir = {x=topdir.y*backdir.z - backdir.y*topdir.z,
return "bottom" y=topdir.z*backdir.x - backdir.z*topdir.x,
end z=topdir.x*backdir.y - backdir.x*topdir.y}
--we shall apply some maths to obtain the right-facing vector --is this the right side?
local rightdir = {x=topdir.y*backdir.z - backdir.y*topdir.z, if rightdir.x == tubedir.x and rightdir.y == tubedir.y and rightdir.z == tubedir.z then
y=topdir.z*backdir.x - backdir.z*topdir.x, return "right"
z=topdir.x*backdir.y - backdir.x*topdir.y} end
--is this the right side? --or the left?
if rightdir.x == tubedir.x and rightdir.y == tubedir.y and rightdir.z == tubedir.z then if rightdir.x == -tubedir.x and rightdir.y == -tubedir.y and rightdir.z == -tubedir.z then
return "right" return "left"
end end
--or the left? --we should be done by now; initiate panic mode
if rightdir.x == -tubedir.x and rightdir.y == -tubedir.y and rightdir.z == -tubedir.z then minetest.log("error", "nodeside has been confused by its parameters; see pipeworks autoplace.lua, line 382")
return "left" end
end
--we should be done by now; initiate panic mode function tube_autoroute(pos)
minetest.log("error", "nodeside has been confused by its parameters; see pipeworks autoplace.lua, line 382") local active = {0, 0, 0, 0, 0, 0}
local nctr = minetest.get_node(pos)
if not is_tube(nctr.name) then return end
end local adjustments = {
{ x=-1, y=0, z=0 },
{ x=1, y=0, z=0 },
{ x=0, y=-1, z=0 },
{ x=0, y=1, z=0 },
{ x=0, y=0, z=-1 },
{ x=0, y=0, z=1 }
}
-- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6
--a further function for determining whether we should extend a tube in a certain direction local positions = {}
local function surchar(dir) local nodes = {}
for i,adj in ipairs(adjustments) do
positions[i] = {x=pos.x+adj.x, y=pos.y+adj.y, z=pos.z+adj.z}
nodes[i] = minetest.get_node(positions[i])
end
--get the node in that direction for i,node in ipairs(nodes) do
local node = minetest.get_node{x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} local idef = minetest.registered_nodes[node.name]
-- handle the tubes themselves
if is_tube(node.name) then
active[i] = 1
-- handle new style connectors
elseif idef.tube and idef.tube.connects then
-- connects returns true if self can connect w/ neighboring position
-- it uses facesFront, facesTop etc to determine this
-- pipeworks.connects.facingFront...
if idef.tube.connects(i,param2) then active[i] = 1 end
-- oops, handle the *other* newstyle connectors
elseif idef.tube and idef.tube.connect_side then
local dir = adjustments[i]
if idef.connect_sides[nodeside(node, {x=-dir.x, y=-dir.y, z=-dir.z})] then active[i] = 1 end
--and its tube table -- legacy stuff follows
local nodetube = minetest.registered_nodes[node.name].tube elseif string.find(node.name, "pipeworks:filter") ~= nil or string.find(node.name, "pipeworks:mese_filter") ~= nil then
-- filters only connect to pipes on their output (despite appearances)
-- input has to be a chest or furnace or something
if pipeworks.connects.facingRight(i,node.param2)
then
active[i] = 1
end
elseif
-- not the front
string.find(node.name, "pipeworks:deployer_") ~= nil or
string.find(node.name, "pipeworks:nodebreaker_") ~= nil or
string.find(node.name, "technic:nodebreaker_") ~= nil
then
if not pipeworks.connects.facingFront(i,node.param2) then active[i] = 1 end
elseif
string.find(node.name, "default:furnace") ~= nil or
string.find(node.name, "default:chest") or
string.find(node.name, "default:chest_locked")
then
if not pipeworks.connects.facingFront(i,node.param2) or
pipeworks.connects.facingTop(i,node.param2) then active[i] = 1 end
elseif string.find(node.name, "pipeworks:autocrafter") ~= nil then
active[i] = 1
end
end
--choose a surround character -- all sides checked, now figure which tube to use.
if nodetube and nodetube.connect_sides
and nodetube.connect_sides[nodeside(node, {x=-dir.x, y=-dir.y, z=-dir.z})] then
return '1'
else
return '0'
end
end
--keep track of the tube surroundings
local nsurround = ""
--look in each direction
nsurround = nsurround..surchar{x=-1, y=0, z=0}
nsurround = nsurround..surchar{x=1, y=0, z=0}
nsurround = nsurround..surchar{x=0, y=-1, z=0}
nsurround = nsurround..surchar{x=0, y=1, z=0}
nsurround = nsurround..surchar{x=0, y=0, z=-1}
nsurround = nsurround..surchar{x=0, y=0, z=1}
-- Apply the final routing decisions to the existing tube (if any)
if is_tube(nctr.name) then
local meta=minetest.get_meta(pos)
local meta0=meta:to_table()
nctr.name=string.sub(nctr.name,1,-7)..nsurround
minetest.add_node(pos, nctr)
local meta=minetest.get_meta(pos)
meta:from_table(meta0)
end
nsurround = ""
for i,n in ipairs(active) do
nsurround = nsurround .. n
end
local newname=string.sub(nctr.name,1,-7)..nsurround
if newname == nctr.name then return end
local meta=minetest.get_meta(pos)
local meta0=meta:to_table() -- XXX: hacky_swap_node
nctr.name = newname
minetest.add_node(pos, nctr)
local meta=minetest.get_meta(pos)
meta:from_table(meta0)
local nctr = minetest.get_node(pos)
end end
-- auto-rotation code for various devices the tubes attach to -- auto-rotation code for various devices the tubes attach to

View File

@ -100,6 +100,56 @@ minetest.register_craftitem("pipeworks:filter", {
stack_max = 99, stack_max = 99,
}) })
local fakePlayer = {
get_player_name = function() return ":pipeworks" end,
-- any other player functions called by allow_metadata_inventory_take anywhere...
-- perhaps a custom metaclass that errors specially when fakePlayer.<property> is not found?
}
-- adding two tube functions
-- can_remove(pos,node,stack,dir) returns true if an item can be removed from that stack on that node
-- remove_items(pos,node,stack,dir,count) removes count items and returns them
-- both optional w/ sensible defaults and fallback to normal allow_* function
-- XXX: possibly change insert_object to insert_item
-- sname = the current name to allow for, or nil if it allows anything
function grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir,all)
for spos,stack in ipairs(frominv:get_list(frominvname)) do
if ( sname == nil and stack:get_name() ~= "") or stack:get_name()==sname then
local doRemove = true
if tube.can_remove then
doRemove = tube.can_remove(frompos, fromnode, stack, dir)
elseif idef.allow_metadata_inventory_take then
doRemove = idef.allow_metadata_inventory_take(frompos,"main",spos, stack, fakePlayer)
end
-- stupid lack of continue statements grumble
if doRemove then
local item
local count
if all then
count = stack:get_count()
else
count = 1
end
if tube.remove_items then
-- it could be the entire stack...
item=tube.remove_items(frompos,fromnode,stack,dir,count)
else
item=stack:take_item(count)
frominv:set_stack(frominvname,spos,stack)
idef.on_metadata_inventory_take(frompos, "main", spos, item, fakePlayer)
end
item1=tube_item(frompos,item)
item1:get_luaentity().start_pos = frompos
item1:setvelocity(dir)
item1:setacceleration({x=0, y=0, z=0})
return -- only fire one item, please
end
end
end
end
minetest.register_node("pipeworks:filter", { minetest.register_node("pipeworks:filter", {
description = "Filter", description = "Filter",
tiles = {"pipeworks_filter_top.png", "pipeworks_filter_top.png", "pipeworks_filter_output.png", tiles = {"pipeworks_filter_top.png", "pipeworks_filter_top.png", "pipeworks_filter_output.png",
@ -139,44 +189,26 @@ minetest.register_node("pipeworks:filter", {
local dir = facedir_to_right_dir(node.param2) local dir = facedir_to_right_dir(node.param2)
local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z} local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z}
local fromnode=minetest.get_node(frompos) local fromnode=minetest.get_node(frompos)
if not fromnode then return end
local frominv local frominv
if (not fromnode) or (not minetest.registered_nodes[fromnode.name]) or (not (minetest.registered_nodes[fromnode.name].tube and local idef = minetest.registered_nodes[fromnode.name]
minetest.registered_nodes[fromnode.name].tube.input_inventory)) then -- assert(idef)
return local tube = idef.tube
end if not (tube and tube.input_inventory) then
return
end
local frommeta=minetest.get_meta(frompos) local frommeta=minetest.get_meta(frompos)
local frominvname=minetest.registered_nodes[fromnode.name].tube.input_inventory local frominvname=tube.input_inventory
local frominv=frommeta:get_inventory() local frominv=frommeta:get_inventory()
for _,filter in ipairs(inv:get_list("main")) do for _,filter in ipairs(inv:get_list("main")) do
local sname=filter:get_name() local sname=filter:get_name()
if sname ~="" then if sname ~="" then
for spos,stack in ipairs(frominv:get_list(frominvname)) do -- XXX: that's a lot of parameters
if stack:get_name()==sname then grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir)
item=stack:take_item()
frominv:set_stack(frominvname,spos,stack)
pos1=pos
item1=tube_item({x=pos1.x,y=pos1.y,z=pos1.z},item)
item1:get_luaentity().start_pos = {x=pos1.x,y=pos1.y,z=pos1.z}
item1:setvelocity(dir)
item1:setacceleration({x=0, y=0, z=0})
return
end
end
end end
end end
if inv:is_empty("main") then if inv:is_empty("main") then
for spos,stack in ipairs(frominv:get_list(frominvname)) do grabAndFire(frominv,frominvname,frompos,fromnode,nil,tube,idef,dir)
if stack:get_name()~="" then
item=stack:take_item()
frominv:set_stack(frominvname,spos,stack)
pos1=pos
item1=tube_item({x=pos1.x,y=pos1.y,z=pos1.z},item)
item1:get_luaentity().start_pos = {x=pos1.x,y=pos1.y,z=pos1.z}
item1:setvelocity(dir)
item1:setacceleration({x=0, y=0, z=0})
return
end
end
end end
end, end,
}) })
@ -226,43 +258,23 @@ minetest.register_node("pipeworks:mese_filter", {
local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z} local frompos = {x=pos.x - dir.x, y=pos.y - dir.y, z=pos.z - dir.z}
local fromnode=minetest.get_node(frompos) local fromnode=minetest.get_node(frompos)
local frominv local frominv
if not (minetest.registered_nodes[fromnode.name].tube and local idef = minetest.registered_nodes[fromnode.name]
minetest.registered_nodes[fromnode.name].tube.input_inventory) then -- assert(idef)
return local tube = idef.tube
end if not (tube and tube.input_inventory) then
return
end
local frommeta=minetest.get_meta(frompos) local frommeta=minetest.get_meta(frompos)
local frominvname=minetest.registered_nodes[fromnode.name].tube.input_inventory local frominvname=minetest.registered_nodes[fromnode.name].tube.input_inventory
local frominv=frommeta:get_inventory() local frominv=frommeta:get_inventory()
for _,filter in ipairs(inv:get_list("main")) do for _,filter in ipairs(inv:get_list("main")) do
local sname=filter:get_name() local sname=filter:get_name()
if sname ~="" then if sname ~="" then
for spos,stack in ipairs(frominv:get_list(frominvname)) do grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir,true)
if stack:get_name()==sname then
item=stack:take_item(stack:get_count())
frominv:set_stack(frominvname,spos,stack)
pos1=pos
item1=tube_item({x=pos1.x,y=pos1.y,z=pos1.z},item)
item1:get_luaentity().start_pos = {x=pos1.x,y=pos1.y,z=pos1.z}
item1:setvelocity(dir)
item1:setacceleration({x=0, y=0, z=0})
return
end
end
end end
end end
if inv:is_empty("main") then if inv:is_empty("main") then
for spos,stack in ipairs(frominv:get_list(frominvname)) do grabAndFire(frominv,frominvname,frompos,fromnode,sname,tube,idef,dir,true)
if stack:get_name()~="" then
item=stack:take_item(stack:get_count())
frominv:set_stack(frominvname,spos,stack)
pos1=pos
item1=tube_item({x=pos1.x,y=pos1.y,z=pos1.z},item)
item1:get_luaentity().start_pos = {x=pos1.x,y=pos1.y,z=pos1.z}
item1:setvelocity(dir)
item1:setacceleration({x=0, y=0, z=0})
return
end
end
end end
end, end,
}) })