875 lines
22 KiB
Lua
875 lines
22 KiB
Lua
|
|
-- define global
|
|
hopper = {version = "20230815"}
|
|
|
|
-- Translation support
|
|
local S = minetest.get_translator("hopper")
|
|
|
|
-- creative check
|
|
local creative_mode_cache = minetest.settings:get_bool("creative_mode")
|
|
local function check_creative(name)
|
|
return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
|
|
end
|
|
|
|
-- screwdriver mod
|
|
local mod_screwdriver = minetest.get_modpath("screwdriver")
|
|
|
|
-- containers ( { where, node, inventory, run_callbacks })
|
|
-- run_callbacks is false to suppress logging during transfer. (be quiet like pipeworks)
|
|
local containers = {
|
|
{"top", "hopper:hopper", "main", true},
|
|
{"bottom", "hopper:hopper", "main", true},
|
|
{"side", "hopper:hopper", "main", true},
|
|
{"side", "hopper:hopper_side", "main", true},
|
|
|
|
{"void", "hopper:hopper", "main", true},
|
|
{"void", "hopper:hopper_side", "main", true},
|
|
{"void", "hopper:hopper_void", "main", true},
|
|
}
|
|
|
|
-- default behavior for *_metadata_inventory_* callbacks
|
|
-- useful to prevent logging during transfer between nodes
|
|
-- cb_default: { true | false }
|
|
-- true: runs callbacks, except the nodes from the blacklist
|
|
-- false: only performs callbacks for the nodes in the whitelist
|
|
local cb_default = true
|
|
local cb_nodes = {}
|
|
|
|
if cb_default == false then
|
|
|
|
-- a whitelist follows
|
|
-- *_metadata_inventory_* or timer:start may be necessary to start processing
|
|
cb_nodes = {
|
|
-- callbacks without transfer logging
|
|
"^bones:bones", -- drop empty bones
|
|
"^default:furnace", -- start timer
|
|
"^wine:wine_barrel", -- start timer
|
|
-- crazy autocrafter:
|
|
-- allow_metadata_inventory_* is needed to start processing,
|
|
-- when 'main' was empty before.
|
|
-- But don't call get_node_timer(pos):start(1) when disabled.
|
|
"^pipeworks:autocrafter",
|
|
--[[ notes
|
|
-- no prozessing, no transfer logging
|
|
"^pipeworks:deployer_",
|
|
"^pipeworks:dispenser_",
|
|
"^pipeworks:nodebreaker_",
|
|
|
|
-- checks upgrade slots, no transfer logging
|
|
"^technic:[lmh]v_",
|
|
"^technic:coal_alloy_furnace", -- abm driven
|
|
"^technic:constructor_mk",
|
|
"^technic:injector",
|
|
"^technic:tool_workshop",
|
|
|
|
-- fixed: no transfer logging of fake players
|
|
"^hopper:hopper",
|
|
--]]
|
|
}
|
|
|
|
elseif cb_default == true then
|
|
|
|
-- a blacklist follows
|
|
-- *_metadata_inventory_* or timer:start is not needed to start processing
|
|
cb_nodes = {
|
|
-- callbacks opens the formspec
|
|
"^df_underworld_items:puzzle_seal",
|
|
|
|
-- callbacks disabled to prevent logging during transfer between nodes
|
|
"[:_]chest",
|
|
"^castle_storage:",
|
|
"^crafting_bench:workbench",
|
|
"^darkage:box",
|
|
"^darkage:wood_shelves",
|
|
"^homedecor:",
|
|
--[[ notes
|
|
-- no prozessing, logs action in on_metadata_inventory_*
|
|
"^digilines:chest",
|
|
"^homedecor:nightstand_",
|
|
"^homedecor:kitchen_cabinet_",
|
|
"^homedecor:refrigerator_",
|
|
"^homedecor:cardboard_box",
|
|
"^homedecor:desk",
|
|
"^homedecor:filing_cabine",
|
|
"^homedecor:wardrobe",
|
|
"^more_chests:",
|
|
"^nanotech:carbon_chest",
|
|
"^protector:chest",
|
|
"^technic:.*_chest",
|
|
|
|
-- abm driven, logs action in on_metadata_inventory_*
|
|
"^homedecor:microwave_oven",
|
|
"^homedecor:oven",
|
|
--]]
|
|
}
|
|
end
|
|
|
|
|
|
-- global function to add new containers
|
|
function hopper:add_container(list)
|
|
|
|
for n = 1, #list do
|
|
|
|
local cols = table.copy(list[n])
|
|
|
|
cols[4] = cb_default
|
|
|
|
for _, p in pairs(cb_nodes) do
|
|
|
|
if string.find(cols[2], p) then
|
|
|
|
cols[4] = not cb_nodes
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
table.insert(containers, cols)
|
|
end
|
|
end
|
|
|
|
|
|
-- default containers
|
|
hopper:add_container({
|
|
{"top", "default:chest", "main"},
|
|
{"bottom", "default:chest", "main"},
|
|
{"side", "default:chest", "main"},
|
|
|
|
{"top", "default:furnace", "dst"},
|
|
{"bottom", "default:furnace", "src"},
|
|
{"side", "default:furnace", "fuel"},
|
|
|
|
{"top", "default:furnace_active", "dst"},
|
|
{"bottom", "default:furnace_active", "src"},
|
|
{"side", "default:furnace_active", "fuel"},
|
|
|
|
{"top", "default:chest_locked", "main"}, -- checks owner before taking items
|
|
{"bottom", "default:chest_locked", "main"},
|
|
{"side", "default:chest_locked", "main"},
|
|
|
|
{"top", "default:chest_open", "main"}, -- new animated chests
|
|
{"bottom", "default:chest_open", "main"},
|
|
{"side", "default:chest_open", "main"},
|
|
|
|
{"top", "default:chest_locked_open", "main"}, -- checks owner before taking items
|
|
{"bottom", "default:chest_locked_open", "main"},
|
|
{"side", "default:chest_locked_open", "main"},
|
|
|
|
{"void", "default:chest", "main"},
|
|
{"void", "default:chest_open", "main"},
|
|
{"void", "default:furnace", "src"},
|
|
{"void", "default:furnace_active", "src"}
|
|
})
|
|
|
|
|
|
-- protector redo mod support
|
|
if minetest.get_modpath("protector") then
|
|
|
|
hopper:add_container({
|
|
{"top", "protector:chest", "main"},
|
|
{"bottom", "protector:chest", "main"},
|
|
{"side", "protector:chest", "main"},
|
|
{"void", "protector:chest", "main"}
|
|
})
|
|
end
|
|
|
|
|
|
-- wine mod support
|
|
if minetest.get_modpath("wine") then
|
|
|
|
hopper:add_container({
|
|
{"top", "wine:wine_barrel", "dst"},
|
|
{"bottom", "wine:wine_barrel", "src"},
|
|
{"side", "wine:wine_barrel", "src"},
|
|
{"void", "wine:wine_barrel", "src"}
|
|
})
|
|
end
|
|
|
|
|
|
-- formspec
|
|
local function get_hopper_formspec(pos)
|
|
|
|
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
|
|
local formspec =
|
|
"size[8,9]"
|
|
.. default.gui_bg
|
|
.. default.gui_bg_img
|
|
.. default.gui_slots
|
|
.. "list[nodemeta:" .. spos .. ";main;0,0.3;8,4;]"
|
|
.. "list[current_player;main;0,4.85;8,1;]"
|
|
.. "list[current_player;main;0,6.08;8,3;8]"
|
|
.. "listring[nodemeta:" .. spos .. ";main]"
|
|
.. "listring[current_player;main]"
|
|
|
|
return formspec
|
|
end
|
|
|
|
|
|
-- only log actions of real players
|
|
local function log_action(player, pos, message)
|
|
|
|
if player and not player.is_fake_player and player:is_player() then
|
|
|
|
minetest.log("action", player:get_player_name() .. " "
|
|
.. message .. " at " .. minetest.pos_to_string(pos))
|
|
end
|
|
end
|
|
|
|
|
|
-- check where pointing and set normal or side-hopper
|
|
local hopper_place = function(itemstack, placer, pointed_thing)
|
|
|
|
local pos = pointed_thing.above
|
|
local x = pointed_thing.under.x - pos.x
|
|
local z = pointed_thing.under.z - pos.z
|
|
local name = placer:get_player_name() or ""
|
|
|
|
if minetest.is_protected(pos, name) then
|
|
minetest.record_protection_violation(pos, name)
|
|
return itemstack
|
|
end
|
|
|
|
-- make sure we aren't replacing something we shouldnt
|
|
local node = minetest.get_node_or_nil(pos)
|
|
local def = node and minetest.registered_nodes[node.name]
|
|
if def and not def.buildable_to then
|
|
return itemstack
|
|
end
|
|
|
|
if pointed_thing.type == "node"
|
|
and placer and not placer:get_player_control().sneak then
|
|
|
|
local nn = minetest.get_node(pointed_thing.under).name
|
|
|
|
if minetest.registered_nodes[nn]
|
|
and minetest.registered_nodes[nn].on_rightclick then
|
|
return minetest.item_place(itemstack, placer, pointed_thing)
|
|
end
|
|
end
|
|
|
|
if x == -1 then
|
|
minetest.set_node(pos, {name = "hopper:hopper_side", param2 = 0})
|
|
|
|
elseif x == 1 then
|
|
minetest.set_node(pos, {name = "hopper:hopper_side", param2 = 2})
|
|
|
|
elseif z == -1 then
|
|
minetest.set_node(pos, {name = "hopper:hopper_side", param2 = 3})
|
|
|
|
elseif z == 1 then
|
|
minetest.set_node(pos, {name = "hopper:hopper_side", param2 = 1})
|
|
|
|
else
|
|
minetest.set_node(pos, {name = "hopper:hopper"})
|
|
end
|
|
|
|
if not check_creative(placer:get_player_name()) then
|
|
itemstack:take_item()
|
|
end
|
|
|
|
-- set metadata
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
|
|
inv:set_size("main", 4*4)
|
|
|
|
meta:set_string("owner", name)
|
|
|
|
return itemstack
|
|
end
|
|
|
|
|
|
-- hopper
|
|
minetest.register_node("hopper:hopper", {
|
|
description = S("Hopper (Place onto sides for side-hopper)"),
|
|
groups = {cracky = 3},
|
|
drawtype = "nodebox",
|
|
paramtype = "light",
|
|
use_texture_alpha = "clip",
|
|
tiles = {"hopper_top.png", "hopper_top.png", "hopper_front.png"},
|
|
inventory_image = "hopper_inv.png",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
--funnel walls
|
|
{-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
|
|
{0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
|
|
--funnel base
|
|
{-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
|
|
--spout
|
|
{-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
|
|
{-0.15, -0.3, -0.15, 0.15, -0.5, 0.15}
|
|
}
|
|
},
|
|
|
|
on_place = hopper_place,
|
|
|
|
can_dig = function(pos, player)
|
|
|
|
local inv = minetest.get_meta(pos):get_inventory()
|
|
|
|
return inv:is_empty("main")
|
|
end,
|
|
|
|
on_rightclick = function(pos, node, clicker, itemstack)
|
|
|
|
if not minetest.get_meta(pos)
|
|
or minetest.is_protected(pos, clicker:get_player_name()) then
|
|
return itemstack
|
|
end
|
|
|
|
minetest.show_formspec(clicker:get_player_name(),
|
|
"hopper:hopper", get_hopper_formspec(pos))
|
|
end,
|
|
|
|
on_metadata_inventory_move = function(
|
|
pos, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
log_action(player, pos, "moves stuff in hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff to hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff from hopper")
|
|
end,
|
|
|
|
on_rotate = mod_screwdriver and screwdriver.disallow,
|
|
on_blast = function() end
|
|
})
|
|
|
|
|
|
-- side hopper
|
|
minetest.register_node("hopper:hopper_side", {
|
|
description = S("Side Hopper (Place into crafting to return normal Hopper)"),
|
|
groups = {cracky = 3, not_in_creative_inventory = 1},
|
|
drawtype = "nodebox",
|
|
paramtype = "light",
|
|
use_texture_alpha = "clip",
|
|
paramtype2 = "facedir",
|
|
tiles = {
|
|
"hopper_top.png", "hopper_top.png", "hopper_back.png",
|
|
"hopper_side.png", "hopper_back.png", "hopper_back.png"
|
|
},
|
|
inventory_image = "hopper_side_inv.png",
|
|
drop = "hopper:hopper",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
--funnel walls
|
|
{-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
|
|
{0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
|
|
--funnel base
|
|
{-0.5, 0.0, -0.5, 0.5, 0.1, 0.5},
|
|
--spout
|
|
{-0.3, -0.3, -0.3, 0.3, 0.0, 0.3},
|
|
{-0.7, -0.3, -0.15, 0.15, 0.0, 0.15}
|
|
}
|
|
},
|
|
|
|
on_place = hopper_place,
|
|
|
|
can_dig = function(pos, player)
|
|
|
|
local inv = minetest.get_meta(pos):get_inventory()
|
|
|
|
return inv:is_empty("main")
|
|
end,
|
|
|
|
on_rightclick = function(pos, node, clicker, itemstack)
|
|
|
|
if not minetest.get_meta(pos)
|
|
or minetest.is_protected(pos, clicker:get_player_name()) then
|
|
return itemstack
|
|
end
|
|
|
|
minetest.show_formspec(clicker:get_player_name(),
|
|
"hopper:hopper_side", get_hopper_formspec(pos))
|
|
end,
|
|
|
|
on_metadata_inventory_move = function(
|
|
pos, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
log_action(player, pos, "moves stuff in side hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff to side hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff from side hopper")
|
|
end,
|
|
|
|
on_rotate = mod_screwdriver and screwdriver.rotate_simple,
|
|
on_blast = function() end
|
|
})
|
|
|
|
|
|
local player_void = {}
|
|
|
|
-- void hopper
|
|
minetest.register_node("hopper:hopper_void", {
|
|
description = S("Void Hopper (Use first to set destination container)"),
|
|
groups = {cracky = 3},
|
|
drawtype = "nodebox",
|
|
paramtype = "light",
|
|
use_texture_alpha = "clip",
|
|
tiles = {"hopper_top.png", "hopper_top.png", "hopper_front.png"},
|
|
inventory_image = "default_obsidian.png^hopper_inv.png",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
--funnel walls
|
|
{-0.5, 0.0, 0.4, 0.5, 0.5, 0.5},
|
|
{0.4, 0.0, -0.5, 0.5, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, -0.4, 0.5, 0.5},
|
|
{-0.5, 0.0, -0.5, 0.5, 0.5, -0.4},
|
|
--funnel base
|
|
{-0.5, 0.0, -0.5, 0.5, 0.1, 0.5}
|
|
}
|
|
},
|
|
|
|
on_use = function(itemstack, player, pointed_thing)
|
|
|
|
if pointed_thing.type ~= "node" then
|
|
return
|
|
end
|
|
|
|
local pos = pointed_thing.under
|
|
local name = player:get_player_name()
|
|
local node = minetest.get_node(pos).name
|
|
local ok
|
|
|
|
if minetest.is_protected(pos, name) then
|
|
minetest.record_protection_violation(pos, name)
|
|
return itemstack
|
|
end
|
|
|
|
for _ = 1, #containers do
|
|
if node == containers[_][2] then
|
|
ok = true
|
|
end
|
|
end
|
|
|
|
if ok then
|
|
minetest.chat_send_player(name, S("Output container set")
|
|
.. " " .. minetest.pos_to_string(pos))
|
|
player_void[name] = pos
|
|
else
|
|
minetest.chat_send_player(name, S("Not a registered container!"))
|
|
player_void[name] = nil
|
|
end
|
|
end,
|
|
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
|
|
local pos = pointed_thing.above
|
|
local name = placer:get_player_name() or ""
|
|
|
|
if pointed_thing.type == "node"
|
|
and placer and not placer:get_player_control().sneak then
|
|
|
|
local nn = minetest.get_node(pointed_thing.under).name
|
|
|
|
if minetest.registered_nodes[nn]
|
|
and minetest.registered_nodes[nn].on_rightclick then
|
|
return minetest.item_place(itemstack, placer, pointed_thing)
|
|
end
|
|
end
|
|
|
|
if not player_void[name] then
|
|
minetest.chat_send_player(name, S("No container position set!"))
|
|
return itemstack
|
|
end
|
|
|
|
if minetest.is_protected(pos, name) then
|
|
minetest.record_protection_violation(pos, name)
|
|
return itemstack
|
|
end
|
|
|
|
-- make sure we aren't replacing something we shouldnt
|
|
local node = minetest.get_node_or_nil(pos)
|
|
local def = node and minetest.registered_nodes[node.name]
|
|
if def and not def.buildable_to then
|
|
return itemstack
|
|
end
|
|
|
|
if not check_creative(placer:get_player_name()) then
|
|
itemstack:take_item()
|
|
end
|
|
|
|
minetest.set_node(pos, {name = "hopper:hopper_void", param2 = 0})
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
|
|
inv:set_size("main", 4*4)
|
|
|
|
meta:set_string("owner", name)
|
|
meta:set_string("void", minetest.pos_to_string(player_void[name]))
|
|
meta:set_string("infotext", "Void Hopper\nConnected to " ..
|
|
minetest.pos_to_string(player_void[name]))
|
|
|
|
return itemstack
|
|
end,
|
|
|
|
can_dig = function(pos, player)
|
|
|
|
local inv = minetest.get_meta(pos):get_inventory()
|
|
|
|
return inv:is_empty("main")
|
|
end,
|
|
|
|
on_rightclick = function(pos, node, clicker, itemstack)
|
|
|
|
if not minetest.get_meta(pos)
|
|
or minetest.is_protected(pos, clicker:get_player_name()) then
|
|
return itemstack
|
|
end
|
|
|
|
minetest.show_formspec(clicker:get_player_name(),
|
|
"hopper:hopper", get_hopper_formspec(pos))
|
|
end,
|
|
|
|
on_metadata_inventory_move = function(
|
|
pos, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
log_action(player, pos, "moves stuff in void hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff into void hopper")
|
|
end,
|
|
|
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
|
|
log_action(player, pos, "moves stuff from void hopper")
|
|
end,
|
|
|
|
on_rotate = mod_screwdriver and screwdriver.disallow,
|
|
on_blast = function() end
|
|
})
|
|
|
|
|
|
-- transfer function
|
|
local transfer = function(src, srcpos, dst, dstpos, allowed, finished)
|
|
|
|
-- source inventory
|
|
local inv = minetest.get_meta(srcpos):get_inventory()
|
|
|
|
-- destination inventory
|
|
local inv2 = minetest.get_meta(dstpos):get_inventory()
|
|
|
|
-- check for empty source or no inventory
|
|
if not inv or not inv2 or inv:is_empty(src) == true then
|
|
return
|
|
end
|
|
|
|
local stack, item, max
|
|
|
|
-- transfer item
|
|
for i = 1, inv:get_size(src) do
|
|
|
|
stack = inv:get_stack(src, i)
|
|
item = stack:get_name()
|
|
|
|
-- if slot not empty and room for item in destination
|
|
if item ~= ""
|
|
and inv2:room_for_item(dst, item) then
|
|
|
|
local take = stack:take_item(1)
|
|
|
|
if allowed(i, take) then
|
|
|
|
inv2:add_item(dst, take)
|
|
inv:set_stack(src, i, stack)
|
|
|
|
finished(i, take)
|
|
end
|
|
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local lazy = minetest.settings:get_bool("lazy_container_support")
|
|
|
|
local function add_container_lazy(meta, where, node_name, inv_names)
|
|
|
|
if not meta then return end
|
|
|
|
local inv = meta:get_inventory()
|
|
|
|
for _, inv_name in pairs(inv_names) do
|
|
|
|
if inv:get_size(inv_name) > 0 then
|
|
|
|
hopper:add_container({{where, node_name, inv_name}})
|
|
|
|
--print("hopper: add_container_lazy ["..#containers.."] "..where.." '"..node_name.."' "..inv_name .. " " .. (containers[#containers][4] and "true" or "false"))
|
|
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- hopper workings
|
|
minetest.register_abm({
|
|
|
|
label = "Hopper suction and transfer",
|
|
nodenames = {"hopper:hopper", "hopper:hopper_side", "hopper:hopper_void"},
|
|
interval = 1,
|
|
chance = 1,
|
|
catch_up = false,
|
|
|
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
|
|
local inv = minetest.get_meta(pos):get_inventory()
|
|
|
|
for _,object in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
|
|
|
if not object:is_player()
|
|
and object:get_luaentity()
|
|
and object:get_luaentity().name == "__builtin:item"
|
|
and inv
|
|
and inv:room_for_item("main",
|
|
ItemStack(object:get_luaentity().itemstring)) then
|
|
|
|
if object:get_pos().y - pos.y > 0.25 then
|
|
|
|
inv:add_item("main",
|
|
ItemStack(object:get_luaentity().itemstring))
|
|
|
|
object:get_luaentity().itemstring = ""
|
|
object:remove()
|
|
end
|
|
end
|
|
end
|
|
|
|
local dst_pos
|
|
|
|
-- if side hopper check which way spout is facing
|
|
if node.name == "hopper:hopper_side" then
|
|
|
|
local face = node.param2
|
|
|
|
if face == 0 then
|
|
dst_pos = {x = pos.x - 1, y = pos.y, z = pos.z}
|
|
|
|
elseif face == 1 then
|
|
dst_pos = {x = pos.x, y = pos.y, z = pos.z + 1}
|
|
|
|
elseif face == 2 then
|
|
dst_pos = {x = pos.x + 1, y = pos.y, z = pos.z}
|
|
|
|
elseif face == 3 then
|
|
dst_pos = {x = pos.x, y = pos.y, z = pos.z - 1}
|
|
else
|
|
return
|
|
end
|
|
|
|
elseif node.name == "hopper:hopper_void" then
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
if not meta then return end
|
|
|
|
dst_pos = minetest.string_to_pos(meta:get_string("void"))
|
|
|
|
elseif node.name == "hopper:hopper" then
|
|
-- otherwise normal hopper, output downwards
|
|
dst_pos = {x = pos.x, y = pos.y - 1, z = pos.z}
|
|
else
|
|
return
|
|
end
|
|
|
|
-- get node above hopper
|
|
local src_pos = {x = pos.x, y = pos.y + 1, z = pos.z}
|
|
local src_name = minetest.get_node(src_pos).name
|
|
|
|
-- get node at other end of spout
|
|
local dst_name = minetest.get_node(dst_pos).name
|
|
|
|
-- hopper owner
|
|
local owner = minetest.get_meta(pos):get_string("owner")
|
|
|
|
-- the hopper itself interacts as fake player
|
|
local player = {
|
|
is_player = function() return false end,
|
|
get_player_name = function() return owner end,
|
|
is_fake_player = ":hopper",
|
|
get_wielded_item = function() return ItemStack(nil) end
|
|
}
|
|
|
|
if minetest.check_player_privs(owner, "protection_bypass") then
|
|
owner = ""
|
|
end
|
|
|
|
local to
|
|
if node.name == "hopper:hopper" then
|
|
to = "bottom"
|
|
elseif node.name == "hopper:hopper_side" then
|
|
to = "side"
|
|
elseif node.name == "hopper:hopper_void" then
|
|
to = "void"
|
|
end
|
|
|
|
local where, name, inv, run_cb, src_inv, dst_inv, src_cb, dst_cb
|
|
|
|
-- do for loop here for api check
|
|
for n = 1, #containers do
|
|
|
|
where = containers[n][1]
|
|
name = containers[n][2]
|
|
inv = containers[n][3]
|
|
run_cb = containers[n][4]
|
|
|
|
if where == "top" and src_name == name then
|
|
src_inv = inv -- from hopper into destionation container
|
|
src_cb = run_cb
|
|
elseif where == to and dst_name == name then
|
|
dst_inv = inv
|
|
dst_cb = run_cb
|
|
end
|
|
end
|
|
|
|
-- get container owner
|
|
local c_owner = minetest.get_meta(src_pos):get_string("owner") or ""
|
|
|
|
-- if protection_bypass or actual owner or container not owned
|
|
if owner == "" or owner == c_owner or c_owner == "" then
|
|
|
|
if src_inv then
|
|
|
|
-- run callbacks from source node or not
|
|
local src_def = src_cb and minetest.registered_nodes[src_name]
|
|
local allowed = function(i, stack)
|
|
|
|
return not src_def
|
|
or not src_def.allow_metadata_inventory_take
|
|
or src_def.allow_metadata_inventory_take(src_pos, src_inv, i,
|
|
stack, player) > 0
|
|
end
|
|
|
|
local finished = function(i, stack)
|
|
|
|
return not src_def
|
|
or not src_def.on_metadata_inventory_take
|
|
or src_def.on_metadata_inventory_take(src_pos, src_inv, i, stack,
|
|
player)
|
|
end
|
|
|
|
transfer(src_inv, src_pos, "main", pos, allowed, finished)
|
|
|
|
elseif src_name ~= "ignore"
|
|
and lazy and not string.find(src_name, "^hopper:") then
|
|
|
|
local meta = minetest.get_meta(src_pos)
|
|
|
|
add_container_lazy(meta, "top", src_name, {"main", "dst", "out"})
|
|
end
|
|
end
|
|
|
|
c_owner = minetest.get_meta(dst_pos):get_string("owner") or ""
|
|
|
|
if owner == "" or owner == c_owner or c_owner == "" then
|
|
|
|
if dst_inv then
|
|
|
|
-- run callbacks from destionation node or not
|
|
local dst_def = dst_cb and minetest.registered_nodes[dst_name]
|
|
local allowed = function(i, stack)
|
|
|
|
return not dst_def
|
|
or not dst_def.allow_metadata_inventory_put
|
|
or dst_def.allow_metadata_inventory_put(dst_pos, dst_inv, i, stack,
|
|
player) > 0
|
|
end
|
|
|
|
local finished = function(i, stack)
|
|
|
|
return not dst_def
|
|
or not dst_def.on_metadata_inventory_put
|
|
or dst_def.on_metadata_inventory_put(dst_pos, dst_inv, i, stack,
|
|
player)
|
|
end
|
|
|
|
transfer("main", pos, dst_inv, dst_pos, allowed, finished)
|
|
|
|
elseif dst_name ~= "ignore" and lazy
|
|
and not string.find(dst_name, "^hopper:") then
|
|
|
|
local meta = minetest.get_meta(dst_pos)
|
|
|
|
if to == "side" then
|
|
add_container_lazy(meta, to, dst_name, {"fuel", "main", "src", "in"})
|
|
else
|
|
add_container_lazy(meta, to, dst_name, {"main", "src", "in"})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
|
|
-- hopper recipe
|
|
minetest.register_craft({
|
|
output = "hopper:hopper",
|
|
recipe = {
|
|
{"default:steel_ingot", "default:chest", "default:steel_ingot"},
|
|
{"", "default:steel_ingot", ""}
|
|
}
|
|
})
|
|
|
|
-- side hopper to hopper recipe
|
|
minetest.register_craft({
|
|
output = "hopper:hopper",
|
|
recipe = {{"hopper:hopper_side"}}
|
|
})
|
|
|
|
-- void hopper recipe
|
|
if minetest.get_modpath("teleport_potion") then
|
|
minetest.register_craft({
|
|
output = "hopper:hopper_void",
|
|
recipe = {
|
|
{"default:steel_ingot", "default:chest", "default:steel_ingot"},
|
|
{"teleport_potion:potion", "default:steel_ingot", "teleport_potion:potion"}
|
|
}
|
|
})
|
|
else
|
|
minetest.register_craft({
|
|
output = "hopper:hopper_void",
|
|
recipe = {
|
|
{"default:steel_ingot", "default:chest", "default:steel_ingot"},
|
|
{"default:diamondblock", "default:steel_ingot", "default:mese"}
|
|
}
|
|
})
|
|
end
|
|
|
|
|
|
-- add lucky blocks
|
|
if minetest.get_modpath("lucky_block") then
|
|
|
|
lucky_block:add_blocks({
|
|
{"dro", {"hopper:hopper"}, 3},
|
|
{"nod", "default:lava_source", 1}
|
|
})
|
|
end
|
|
|
|
|
|
print ("[MOD] Hopper loaded")
|