Refactor deployer and dispenser
authorZefram <zefram@fysh.org>
Tue, 22 Jul 2014 14:33:16 +0000 (15:33 +0100)
committerVanessa Ezekowitz <vanessaezekowitz@gmail.com>
Wed, 23 Jul 2014 13:50:50 +0000 (09:50 -0400)
Merge implementations into a single "wielder" mechanism.  Clean up the
code a bit.  Fix get_player_control_bits for the dispenser (it wasn't
indicating the sneak setting).  Fix drops for dispenser (dispenser_on was
dropping as itself).  Show item image, as well as name, at head of form.

deployer.lua [deleted file]
dispenser.lua [deleted file]
init.lua
wielder.lua [new file with mode: 0644]

diff --git a/deployer.lua b/deployer.lua
deleted file mode 100644 (file)
index 360a0c5..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-
---register aliases for when someone had technic installed, but then uninstalled it but not pipeworks
-minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off")
-minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on")
-
-minetest.register_craft({
-       output = 'pipeworks:deployer_off 1',
-       recipe = {
-               {'group:wood', 'default:chest','group:wood'},
-               {'default:stone', 'mesecons:piston','default:stone'},
-               {'default:stone', 'mesecons:mesecon','default:stone'},
-       }
-})
-
-local function swap_node(pos, name)
-    local node = minetest.get_node(pos)
-    if node.name == name then
-        return
-    end
-    node.name = name
-    minetest.swap_node(pos, node)
-end
-
-local function delay(x)
-       return (function() return x end)
-end
-
-local function deployer_on(pos, node)
-       if node.name ~= "pipeworks:deployer_off" then
-               return
-       end
-       
-       --locate the above and under positions
-       local dir = minetest.facedir_to_dir(node.param2)
-       local pos_under, pos_above = {x = pos.x - dir.x, y = pos.y - dir.y, z = pos.z - dir.z}, {x = pos.x - 2*dir.x, y = pos.y - 2*dir.y, z = pos.z - 2*dir.z}
-       
-       swap_node(pos, "pipeworks:deployer_on")
-       nodeupdate(pos)
-       
-       local meta = minetest.get_meta(pos)
-       local inv = meta:get_inventory()
-       local invlist = inv:get_list("main")
-       for i, stack in ipairs(invlist) do
-               if stack:get_name() ~= nil and stack:get_name() ~= "" then--and minetest.get_node(pos_under).name == "air" then --obtain the first non-empty item slot
-                       local pitch
-                       local yaw
-                       if dir.z < 0 then
-                               yaw = 0
-                               pitch = 0
-                       elseif dir.z > 0 then
-                               yaw = math.pi
-                               pitch = 0
-                       elseif dir.x < 0 then
-                               yaw = 3*math.pi/2
-                               pitch = 0
-                       elseif dir.x > 0 then
-                               yaw = math.pi/2
-                               pitch = 0
-                       elseif dir.y > 0 then
-                               yaw = 0
-                               pitch = -math.pi/2
-                       else
-                               yaw = 0
-                               pitch = math.pi/2
-                       end
-                       local placer = {
-                               get_inventory_formspec = delay(meta:get_string("formspec")),
-                               get_look_dir = delay({x = -dir.x, y = -dir.y, z = -dir.z}),
-                               get_look_pitch = delay(pitch),
-                               get_look_yaw = delay(yaw),
-                               get_player_control = delay({jump=false, right=false, left=false, LMB=false, RMB=false, sneak=false, aux1=false, down=false, up=false}),
-                               get_player_control_bits = delay(0),
-                               get_player_name = delay(meta:get_string("owner")),
-                               is_player = delay(true),
-                               is_fake_player = true,
-                               set_inventory_formspec = delay(),
-                               getpos = delay({x = pos.x, y = pos.y - 1.5, z = pos.z}), -- Player height
-                               get_hp = delay(20),
-                               get_inventory = delay(inv),
-                               get_wielded_item = delay(stack),
-                               get_wield_index = delay(i),
-                               get_wield_list = delay("main"),
-                               moveto = delay(),
-                               punch = delay(),
-                               remove = delay(),
-                               right_click = delay(),
-                               setpos = delay(),
-                               set_hp = delay(),
-                               set_properties = delay(),
-                               set_wielded_item = function(self, item) inv:set_stack("main", i, item) end,
-                               set_animation = delay(),
-                               set_attach = delay(),
-                               set_detach = delay(),
-                               set_bone_position = delay(),
-                       }
-                       local pointed_thing = {type="node", under=pos_under, above=pos_above}
-                       local stack2
-                       if minetest.registered_items[stack:get_name()] then
-                               stack2 = minetest.registered_items[stack:get_name()].on_place(stack, placer, pointed_thing) or stack
-                       end
-                       --if minetest.setting_getbool("creative_mode") and not minetest.get_modpath("unified_inventory") then --infinite stacks ahoy!
-                       --      stack2:take_item()
-                       --end
-                       inv:set_stack("main", i, stack2)
-                       return
-               end
-       end
-end
-
-local deployer_off = function(pos, node)
-       if node.name == "pipeworks:deployer_on" then
-               swap_node(pos, "pipeworks:deployer_off")
-               nodeupdate(pos)
-       end
-end
-
-minetest.register_node("pipeworks:deployer_off", {
-       description = "Deployer",
-       tile_images = {"pipeworks_deployer_top.png","pipeworks_deployer_bottom.png","pipeworks_deployer_side2.png","pipeworks_deployer_side1.png",
-                       "pipeworks_deployer_back.png","pipeworks_deployer_front_off.png"},
-       mesecons = {effector={rules=pipeworks.rules_all,action_on=deployer_on,action_off=deployer_off}},
-       tube={insert_object=function(pos,node,stack,direction)
-                       local meta=minetest.get_meta(pos)
-                       local inv=meta:get_inventory()
-                       return inv:add_item("main",stack)
-               end,
-               can_insert=function(pos,node,stack,direction)
-                       local meta=minetest.get_meta(pos)
-                       local inv=meta:get_inventory()
-                       return inv:room_for_item("main",stack)
-               end,
-               input_inventory="main",
-               connect_sides={back=1},
-               can_remove = function(pos, node, stack, dir)
-                       return stack:get_count()
-               end},
-       is_ground_content = true,
-       paramtype2 = "facedir",
-       groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2, mesecon = 2,tubedevice=1, tubedevice_receiver=1},
-       sounds = default.node_sound_stone_defaults(),
-       on_construct = function(pos)
-               local meta = minetest.get_meta(pos)
-               meta:set_string("formspec",
-                               "invsize[8,9;]"..
-                               "label[0,0;Deployer]"..
-                               "list[current_name;main;4,1;3,3;]"..
-                               "list[current_player;main;0,5;8,4;]")
-               meta:set_string("infotext", "Deployer")
-               local inv = meta:get_inventory()
-               inv:set_size("main", 3*3)
-       end,
-       can_dig = function(pos,player)
-               local meta = minetest.get_meta(pos);
-               local inv = meta:get_inventory()
-               return inv:is_empty("main")
-       end,
-       after_place_node = function (pos, placer)
-               pipeworks.scan_for_tube_objects(pos, placer)
-               local placer_pos = placer:getpos()
-               
-               --correct for the player's height
-               if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
-               
-               --correct for 6d facedir
-               if placer_pos then
-                       local dir = {
-                               x = pos.x - placer_pos.x,
-                               y = pos.y - placer_pos.y,
-                               z = pos.z - placer_pos.z
-                       }
-                       local node = minetest.get_node(pos)
-                       node.param2 = minetest.dir_to_facedir(dir, true)
-                       minetest.set_node(pos, node)
-                       minetest.log("action", "real (6d) facedir: " .. node.param2)
-               end
-               
-               minetest.get_meta(pos):set_string("owner", placer:get_player_name())
-       end,
-       after_dig_node = pipeworks.scan_for_tube_objects,
-       allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return count
-       end,
-       allow_metadata_inventory_put = function(pos, listname, index, stack, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return stack:get_count()
-       end,
-       allow_metadata_inventory_take = function(pos, listname, index, stack, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return stack:get_count()
-       end
-})
-
-minetest.register_node("pipeworks:deployer_on", {
-       description = "Deployer",
-       tile_images = {"pipeworks_deployer_top.png","pipeworks_deployer_bottom.png","pipeworks_deployer_side2.png","pipeworks_deployer_side1.png",
-                       "pipeworks_deployer_back.png","pipeworks_deployer_front_on.png"},
-       mesecons = {effector={rules=pipeworks.rules_all,action_on=deployer_on,action_off=deployer_off}},
-       tube={insert_object=function(pos,node,stack,direction)
-                       local meta=minetest.get_meta(pos)
-                       local inv=meta:get_inventory()
-                       return inv:add_item("main",stack)
-               end,
-               can_insert=function(pos,node,stack,direction)
-                       local meta=minetest.get_meta(pos)
-                       local inv=meta:get_inventory()
-                       return inv:room_for_item("main",stack)
-               end,
-               input_inventory="main",
-               connect_sides={back=1},
-               can_remove = function(pos, node, stack, dir)
-                       return stack:get_count()
-               end},
-       is_ground_content = true,
-       paramtype2 = "facedir",
-       tubelike=1,
-       drop = "pipeworks:deployer_off",
-       groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2, mesecon = 2,tubedevice=1, tubedevice_receiver=1,not_in_creative_inventory=1},
-       sounds = default.node_sound_stone_defaults(),
-       on_construct = function(pos)
-               local meta = minetest.get_meta(pos)
-               meta:set_string("formspec",
-                               "invsize[8,9;]"..
-                               "label[0,0;Deployer]"..
-                               "list[current_name;main;4,1;3,3;]"..
-                               "list[current_player;main;0,5;8,4;]")
-               meta:set_string("infotext", "Deployer")
-               local inv = meta:get_inventory()
-               inv:set_size("main", 3*3)
-       end,
-       can_dig = function(pos,player)
-               local meta = minetest.get_meta(pos);
-               local inv = meta:get_inventory()
-               return inv:is_empty("main")
-       end,
-       after_place_node = function (pos, placer)
-               pipeworks.scan_for_tube_objects(pos, placer)
-               local placer_pos = placer:getpos()
-               
-               --correct for the player's height
-               if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
-               
-               --correct for 6d facedir
-               if placer_pos then
-                       local dir = {
-                               x = pos.x - placer_pos.x,
-                               y = pos.y - placer_pos.y,
-                               z = pos.z - placer_pos.z
-                       }
-                       local node = minetest.get_node(pos)
-                       node.param2 = minetest.dir_to_facedir(dir, true)
-                       minetest.set_node(pos, node)
-                       minetest.log("action", "real (6d) facedir: " .. node.param2)
-               end
-               
-               minetest.get_meta(pos):set_string("owner", placer:get_player_name())
-       end,
-       after_dig_node = pipeworks.scan_for_tube_objects,
-       allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return count
-       end,
-       allow_metadata_inventory_put = function(pos, listname, index, stack, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return stack:get_count()
-       end,
-       allow_metadata_inventory_take = function(pos, listname, index, stack, player)
-               local meta = minetest.get_meta(pos)
-               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                       return 0
-               end
-               return stack:get_count()
-       end
-})
diff --git a/dispenser.lua b/dispenser.lua
deleted file mode 100644 (file)
index de78348..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-minetest.register_craft({
-       output = "pipeworks:dispenser_off",
-       recipe = {
-               { "default:desert_sand", "default:chest",    "default:desert_sand" },
-               { "default:stone",       "mesecons:piston",  "default:stone"       },
-               { "default:stone",       "mesecons:mesecon", "default:stone"       },
-       }
-})
-
-local function delay(x)
-       return (function() return x end)
-end
-
-local function dispenser_on(pos, node)
-       if node.name ~= "pipeworks:dispenser_off" then
-               return
-       end
-
-       node.name = "pipeworks:dispenser_on"
-       minetest.swap_node(pos, node)
-       nodeupdate(pos)
-
-       local meta = minetest.get_meta(pos)
-       local inv = meta:get_inventory()
-       local invlist = inv:get_list("main")
-       for i, stack in ipairs(invlist) do
-               if stack:get_name() ~= nil and stack:get_name() ~= "" then
-                       local dir = minetest.facedir_to_dir(node.param2)
-                       local pitch
-                       local yaw
-                       if dir.z < 0 then
-                               yaw = 0
-                               pitch = 0
-                       elseif dir.z > 0 then
-                               yaw = math.pi
-                               pitch = 0
-                       elseif dir.x < 0 then
-                               yaw = 3*math.pi/2
-                               pitch = 0
-                       elseif dir.x > 0 then
-                               yaw = math.pi/2
-                               pitch = 0
-                       elseif dir.y > 0 then
-                               yaw = 0
-                               pitch = -math.pi/2
-                       else
-                               yaw = 0
-                               pitch = math.pi/2
-                       end
-                       local dropper_pos = {x = pos.x, y = pos.y - 1.5, z = pos.z} -- Player height
-                       local dropper = {
-                               get_inventory_formspec = delay(meta:get_string("formspec")),
-                               get_look_dir = delay({x = -dir.x, y = -dir.y, z = -dir.z}),
-                               get_look_pitch = delay(pitch),
-                               get_look_yaw = delay(yaw),
-                               get_player_control = delay({jump=false, right=false, left=false, LMB=false, RMB=false, sneak=true, aux1=false, down=false, up=false}),
-                               get_player_control_bits = delay(0),
-                               get_player_name = delay(":pipeworks:"..minetest.pos_to_string(pos)),
-                               is_player = delay(true),
-                               is_fake_player = true,
-                               set_inventory_formspec = delay(),
-                               getpos = delay(dropper_pos),
-                               get_hp = delay(20),
-                               get_inventory = delay(inv),
-                               get_wielded_item = delay(stack),
-                               get_wield_index = delay(i),
-                               get_wield_list = delay("main"),
-                               moveto = delay(),
-                               punch = delay(),
-                               remove = delay(),
-                               right_click = delay(),
-                               setpos = delay(),
-                               set_hp = delay(),
-                               set_properties = delay(),
-                               set_wielded_item = function(self, item) inv:set_stack("main", i, item) end,
-                               set_animation = delay(),
-                               set_attach = delay(),
-                               set_detach = delay(),
-                               set_bone_position = delay(),
-                       }
-                       local stack2
-                       if minetest.registered_items[stack:get_name()] then
-                               stack2 = minetest.registered_items[stack:get_name()].on_drop(stack, dropper, dropper_pos) or stack
-                       end
-                       inv:set_stack("main", i, stack2)
-                       return
-               end
-       end
-end
-
-local dispenser_off = function(pos, node)
-       if node.name == "pipeworks:dispenser_on" then
-               node.name = "pipeworks:dispenser_off"
-               minetest.swap_node(pos, node)
-               nodeupdate(pos)
-       end
-end
-
-for _, state in ipairs({ "off", "on" }) do
-       local grps = { snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon=2, tubedevice=1, tubedevice_receiver=1 }
-       if state == "on" then grps.not_in_creative_inventory = 1 end
-       minetest.register_node("pipeworks:dispenser_"..state, {
-               description = "Dispenser",
-               tile_images = {
-                       "pipeworks_dispenser_top.png",
-                       "pipeworks_dispenser_bottom.png",
-                       "pipeworks_dispenser_side2.png",
-                       "pipeworks_dispenser_side1.png",
-                       "pipeworks_dispenser_back.png",
-                       "pipeworks_dispenser_front_"..state..".png",
-               },
-               mesecons = {
-                       effector = {
-                               rules = pipeworks.rules_all,
-                               action_on = dispenser_on,
-                               action_off = dispenser_off,
-                       },
-               },
-               tube={insert_object=function(pos,node,stack,direction)
-                               local meta=minetest.get_meta(pos)
-                               local inv=meta:get_inventory()
-                               return inv:add_item("main",stack)
-                       end,
-                       can_insert=function(pos,node,stack,direction)
-                               local meta=minetest.get_meta(pos)
-                               local inv=meta:get_inventory()
-                               return inv:room_for_item("main",stack)
-                       end,
-                       input_inventory="main",
-                       connect_sides={back=1},
-                       can_remove = function(pos, node, stack, dir)
-                               return stack:get_count()
-                       end},
-               is_ground_content = true,
-               paramtype2 = "facedir",
-               tubelike = 1,
-               groups = grps,
-               sounds = default.node_sound_stone_defaults(),
-               on_construct = function(pos)
-                       local meta = minetest.get_meta(pos)
-                       meta:set_string("formspec",
-                                       "invsize[8,9;]"..
-                                       "label[0,0;Dispenser]"..
-                                       "list[current_name;main;4,1;3,3;]"..
-                                       "list[current_player;main;0,5;8,4;]")
-                       meta:set_string("infotext", "Dispenser")
-                       local inv = meta:get_inventory()
-                       inv:set_size("main", 3*3)
-               end,
-               can_dig = function(pos,player)
-                       local meta = minetest.get_meta(pos)
-                       local inv = meta:get_inventory()
-                       return inv:is_empty("main")
-               end,
-               after_place_node = function (pos, placer)
-                       pipeworks.scan_for_tube_objects(pos, placer)
-                       local placer_pos = placer:getpos()
-
-                       --correct for the player's height
-                       if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
-
-                       --correct for 6d facedir
-                       if placer_pos then
-                               local dir = {
-                                       x = pos.x - placer_pos.x,
-                                       y = pos.y - placer_pos.y,
-                                       z = pos.z - placer_pos.z
-                               }
-                               local node = minetest.get_node(pos)
-                               node.param2 = minetest.dir_to_facedir(dir, true)
-                               minetest.set_node(pos, node)
-                               minetest.log("action", "real (6d) facedir: " .. node.param2)
-                       end
-
-                       minetest.get_meta(pos):set_string("owner", placer:get_player_name())
-               end,
-               after_dig_node = pipeworks.scan_for_tube_objects,
-               allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-                       local meta = minetest.get_meta(pos)
-                       if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                               return 0
-                       end
-                       return count
-               end,
-               allow_metadata_inventory_put = function(pos, listname, index, stack, player)
-                       local meta = minetest.get_meta(pos)
-                       if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                               return 0
-                       end
-                       return stack:get_count()
-               end,
-               allow_metadata_inventory_take = function(pos, listname, index, stack, player)
-                       local meta = minetest.get_meta(pos)
-                       if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
-                               return 0
-                       end
-                       return stack:get_count()
-               end,
-       })
-end
index 265ae1d50d9ebe4c08722b393eace9b917af9df2..625a99c9386e687edff5c907a4768a0d1b0ad636 100644 (file)
--- a/init.lua
+++ b/init.lua
@@ -114,14 +114,13 @@ dofile(pipeworks.modpath.."/flowing_logic.lua")
 dofile(pipeworks.modpath.."/crafts.lua")
 dofile(pipeworks.modpath.."/tubes.lua")
 dofile(pipeworks.modpath.."/trashcan.lua")
+dofile(pipeworks.modpath.."/wielder.lua")
 
 if pipeworks.enable_pipes then dofile(pipeworks.modpath.."/pipes.lua") end
 if pipeworks.enable_teleport_tube then dofile(pipeworks.modpath.."/teleport_tube.lua") end
 if pipeworks.enable_pipe_devices then dofile(pipeworks.modpath.."/devices.lua") end
 if pipeworks.enable_redefines then dofile(pipeworks.modpath.."/compat.lua") end
 if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.lua") end
-if pipeworks.enable_deployer then dofile(pipeworks.modpath.."/deployer.lua") end
-if pipeworks.enable_dispenser then dofile(pipeworks.modpath.."/dispenser.lua") end
 
 if pipeworks.enable_node_breaker then
        dofile(pipeworks.modpath.."/node_breaker.lua")
diff --git a/wielder.lua b/wielder.lua
new file mode 100644 (file)
index 0000000..8c4cff9
--- /dev/null
@@ -0,0 +1,238 @@
+local assumed_eye_pos = vector.new(0, 1.5, 0)
+
+local function delay(x)
+       return (function() return x end)
+end
+
+local function wielder_on(data, wielder_pos, wielder_node)
+       if wielder_node.name ~= data.name_base.."_off" then return end
+       wielder_node.name = data.name_base.."_on"
+       minetest.swap_node(wielder_pos, wielder_node)
+       nodeupdate(wielder_pos)
+       local wielder_meta = minetest.get_meta(wielder_pos)
+       local inv = wielder_meta:get_inventory()
+       local invlist = inv:get_list("main")
+       local wieldindex, wieldstack
+       for i, stack in ipairs(invlist) do
+               if not stack:is_empty() then
+                       wieldindex = i
+                       wieldstack = stack
+                       break
+               end
+       end
+       if not wieldindex then return end
+       local dir = minetest.facedir_to_dir(wielder_node.param2)
+       local under_pos = vector.subtract(wielder_pos, dir)
+       local above_pos = vector.subtract(under_pos, dir)
+       local pitch
+       local yaw
+       if dir.z < 0 then
+               yaw = 0
+               pitch = 0
+       elseif dir.z > 0 then
+               yaw = math.pi
+               pitch = 0
+       elseif dir.x < 0 then
+               yaw = 3*math.pi/2
+               pitch = 0
+       elseif dir.x > 0 then
+               yaw = math.pi/2
+               pitch = 0
+       elseif dir.y > 0 then
+               yaw = 0
+               pitch = -math.pi/2
+       else
+               yaw = 0
+               pitch = math.pi/2
+       end
+       local virtplayer = {
+               get_inventory_formspec = delay(wielder_meta:get_string("formspec")),
+               get_look_dir = delay(vector.multiply(dir, -1)),
+               get_look_pitch = delay(pitch),
+               get_look_yaw = delay(yaw),
+               get_player_control = delay({ jump=false, right=false, left=false, LMB=false, RMB=false, sneak=data.sneak, aux1=false, down=false, up=false }),
+               get_player_control_bits = delay(data.sneak and 64 or 0),
+               get_player_name = delay(data.masquerade_as_owner and wielder_meta:get_string("owner") or ":pipeworks:"..minetest.pos_to_string(wielder_pos)),
+               is_player = delay(true),
+               is_fake_player = true,
+               set_inventory_formspec = delay(),
+               getpos = delay(vector.subtract(wielder_pos, assumed_eye_pos)),
+               get_hp = delay(20),
+               get_inventory = delay(inv),
+               get_wielded_item = delay(wieldstack),
+               get_wield_index = delay(wieldindex),
+               get_wield_list = delay("main"),
+               moveto = delay(),
+               punch = delay(),
+               remove = delay(),
+               right_click = delay(),
+               setpos = delay(),
+               set_hp = delay(),
+               set_properties = delay(),
+               set_wielded_item = function(self, item) inv:set_stack("main", wieldindex, item) end,
+               set_animation = delay(),
+               set_attach = delay(),
+               set_detach = delay(),
+               set_bone_position = delay(),
+       }
+       local pointed_thing = { type="node", under=under_pos, above=above_pos }
+       virtplayer:set_wielded_item(data.on_act(virtplayer, pointed_thing) or wieldstack)
+end
+
+local function wielder_off(data, pos, node)
+       if node.name == data.name_base.."_on" then
+               node.name = data.name_base.."_off"
+               minetest.swap_node(pos, node)
+               nodeupdate(pos)
+       end
+end
+
+local function register_wielder(data)
+       for _, state in ipairs({ "off", "on" }) do
+               local groups = { snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon=2, tubedevice=1, tubedevice_receiver=1 }
+               if state == "on" then groups.not_in_creative_inventory = 1 end
+               local tile_images = {}
+               for _, face in ipairs({ "top", "bottom", "side2", "side1", "back", "front" }) do
+                       table.insert(tile_images, data.texture_base.."_"..face..(data.texture_stateful[face] and "_"..state or "")..".png")
+               end
+               minetest.register_node(data.name_base.."_"..state, {
+                       description = data.description,
+                       tile_images = tile_images,
+                       mesecons = {
+                               effector = {
+                                       rules = pipeworks.rules_all,
+                                       action_on = function (pos, node)
+                                               wielder_on(data, pos, node)
+                                       end,
+                                       action_off = function (pos, node)
+                                               wielder_off(data, pos, node)
+                                       end,
+                               },
+                       },
+                       tube = {
+                               insert_object = function(pos,node,stack,direction)
+                                       local meta = minetest.get_meta(pos)
+                                       local inv = meta:get_inventory()
+                                       return inv:add_item("main",stack)
+                               end,
+                               can_insert = function(pos,node,stack,direction)
+                                       local meta = minetest.get_meta(pos)
+                                       local inv = meta:get_inventory()
+                                       return inv:room_for_item("main",stack)
+                               end,
+                               input_inventory = "main",
+                               connect_sides = {back=1},
+                               can_remove = function(pos, node, stack, dir)
+                                       return stack:get_count()
+                               end,
+                       },
+                       is_ground_content = true,
+                       paramtype2 = "facedir",
+                       tubelike = 1,
+                       groups = groups,
+                       sounds = default.node_sound_stone_defaults(),
+                       drop = data.name_base.."_off",
+                       on_construct = function(pos)
+                               local meta = minetest.get_meta(pos)
+                               meta:set_string("formspec",
+                                               "invsize[8,9;]"..
+                                               "item_image[0,0;1,1;"..data.name_base.."_off]"..
+                                               "label[1,0;"..minetest.formspec_escape(data.description).."]"..
+                                               "list[current_name;main;4,1;3,3;]"..
+                                               "list[current_player;main;0,5;8,4;]")
+                               meta:set_string("infotext", data.description)
+                               local inv = meta:get_inventory()
+                               inv:set_size("main", 3*3)
+                       end,
+                       can_dig = function(pos,player)
+                               local meta = minetest.get_meta(pos)
+                               local inv = meta:get_inventory()
+                               return inv:is_empty("main")
+                       end,
+                       after_place_node = function (pos, placer)
+                               pipeworks.scan_for_tube_objects(pos, placer)
+                               local placer_pos = placer:getpos()
+                               if placer_pos and placer:is_player() then placer_pos = vector.add(placer_pos, assumed_eye_pos) end
+                               if placer_pos then
+                                       local dir = vector.subtract(pos, placer_pos)
+                                       local node = minetest.get_node(pos)
+                                       node.param2 = minetest.dir_to_facedir(dir, true)
+                                       minetest.set_node(pos, node)
+                                       minetest.log("action", "real (6d) facedir: " .. node.param2)
+                               end
+                               minetest.get_meta(pos):set_string("owner", placer:get_player_name())
+                       end,
+                       after_dig_node = pipeworks.scan_for_tube_objects,
+                       allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
+                               local meta = minetest.get_meta(pos)
+                               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
+                                       return 0
+                               end
+                               return count
+                       end,
+                       allow_metadata_inventory_put = function(pos, listname, index, stack, player)
+                               local meta = minetest.get_meta(pos)
+                               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
+                                       return 0
+                               end
+                               return stack:get_count()
+                       end,
+                       allow_metadata_inventory_take = function(pos, listname, index, stack, player)
+                               local meta = minetest.get_meta(pos)
+                               if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then
+                                       return 0
+                               end
+                               return stack:get_count()
+                       end,
+               })
+       end
+end
+
+if pipeworks.enable_deployer then
+       register_wielder({
+               name_base = "pipeworks:deployer",
+               description = "Deployer",
+               texture_base = "pipeworks_deployer",
+               texture_stateful = { front = true },
+               masquerade_as_owner = true,
+               sneak = false,
+               on_act = function(virtplayer, pointed_thing)
+                       local wieldstack = virtplayer:get_wielded_item()
+                       return (minetest.registered_items[wieldstack:get_name()] or {on_place=minetest.item_place}).on_place(wieldstack, virtplayer, pointed_thing)
+               end,
+       })
+       minetest.register_craft({
+               output = "pipeworks:deployer_off",
+               recipe = {
+                       { "group:wood",    "default:chest",    "group:wood"    },
+                       { "default:stone", "mesecons:piston",  "default:stone" },
+                       { "default:stone", "mesecons:mesecon", "default:stone" },
+               }
+       })
+       -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks
+       minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off")
+       minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on")
+end
+
+if pipeworks.enable_dispenser then
+       register_wielder({
+               name_base = "pipeworks:dispenser",
+               description = "Dispenser",
+               texture_base = "pipeworks_dispenser",
+               texture_stateful = { front = true },
+               masquerade_as_owner = false,
+               sneak = true,
+               on_act = function(virtplayer, pointed_thing)
+                       local wieldstack = virtplayer:get_wielded_item()
+                       return (minetest.registered_items[wieldstack:get_name()] or {on_drop=minetest.item_drop}).on_drop(wieldstack, virtplayer, virtplayer:getpos())
+               end,
+       })
+       minetest.register_craft({
+               output = "pipeworks:dispenser_off",
+               recipe = {
+                       { "default:desert_sand", "default:chest",    "default:desert_sand" },
+                       { "default:stone",       "mesecons:piston",  "default:stone"       },
+                       { "default:stone",       "mesecons:mesecon", "default:stone"       },
+               }
+       })
+end