diff --git a/abms.lua b/abms.lua index 3eaf0d2..d4b724e 100644 --- a/abms.lua +++ b/abms.lua @@ -97,9 +97,9 @@ minetest.register_abm({ destination_pos = vector.add(pos, destination_dir) end - local output_direction + local output_direction = "bottom" if destination_dir.y == 0 then - output_direction = "horizontal" + output_direction = "side" end local source_node = minetest.get_node(source_pos) @@ -112,13 +112,11 @@ minetest.register_abm({ local registered_destination_inventories = hopper.get_registered(destination_node.name) if registered_destination_inventories ~= nil then - if output_direction == "horizontal" then - hopper.send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["side"]) - else - hopper.send_item_to(pos, destination_pos, destination_node, registered_destination_inventories["bottom"]) + if not hopper.send_item_to(pos, destination_pos, destination_node, registered_destination_inventories[output_direction]) then + hopper.try_eject_item(pos, destination_pos) end else - hopper.send_item_to(pos, destination_pos, destination_node) -- for handling ejection + hopper.try_eject_item(pos, destination_pos) end end, }) diff --git a/nodes/chute.lua b/nodes/chute.lua index 1d0ca71..23a1fec 100644 --- a/nodes/chute.lua +++ b/nodes/chute.lua @@ -88,21 +88,19 @@ minetest.register_node("hopper:chute", { local node = minetest.get_node(pos) local dir = minetest.facedir_to_dir(node.param2) local destination_pos = vector.add(pos, dir) - local output_direction + local output_direction = "bottom" if dir.y == 0 then - output_direction = "horizontal" + output_direction = "side" end local destination_node = minetest.get_node(destination_pos) local registered_inventories = hopper.get_registered(destination_node.name) if registered_inventories ~= nil then - if output_direction == "horizontal" then - hopper.send_item_to(pos, destination_pos, destination_node, registered_inventories["side"]) - else - hopper.send_item_to(pos, destination_pos, destination_node, registered_inventories["bottom"]) + if not hopper.send_item_to(pos, destination_pos, destination_node, registered_inventories[output_direction]) then + hopper.try_eject_item(pos, destination_pos) end else - hopper.send_item_to(pos, destination_pos, destination_node) + hopper.try_eject_item(pos, destination_pos) end if not inv:is_empty("main") then diff --git a/nodes/sorter.lua b/nodes/sorter.lua index 0c8c54a..3493f6a 100644 --- a/nodes/sorter.lua +++ b/nodes/sorter.lua @@ -175,21 +175,23 @@ minetest.register_node("hopper:sorter", { local filter_output_direction = (dir.y == 0) and "side" or "bottom" --- returns success? = true/false - local function try_send_item(output_dir, dst_pos) + local function try_send_item(output_dir, dst_pos, filter_items_map) local dst_node = minetest.get_node(dst_pos) local registered_inventories = hopper.get_registered(dst_node.name) if registered_inventories ~= nil then - return hopper.send_item_to(pos, dst_pos, dst_node, registered_inventories[output_dir], filter_items) + return hopper.send_item_to(pos, dst_pos, dst_node, registered_inventories[output_dir], filter_items_map) end - return hopper.send_item_to(pos, dst_pos, dst_node, nil, filter_items) + return false end - if not try_send_item(filter_output_direction, filter_destination_pos) then + if not try_send_item(filter_output_direction, filter_destination_pos, filter_items) then -- weren't able to put something in the filter destination, for whatever reason. -- Now we can start moving stuff forward to the default. - try_send_item(default_output_direction, default_destination_pos) + if not try_send_item(default_output_direction, default_destination_pos) then + hopper.try_eject_item(pos, default_destination_pos) + end end if not inv:is_empty("main") then diff --git a/utility.lua b/utility.lua index c09a1df..2789b1d 100644 --- a/utility.lua +++ b/utility.lua @@ -108,45 +108,56 @@ hopper.take_item_from = function(hopper_pos, target_pos, target_node, target_inv if target_inv:is_empty(target_inv_name) == false then for i = 1,target_inv_size do local stack = target_inv:get_stack(target_inv_name, i) - local item = stack:get_name() - if item ~= "" then - if hopper_inv:room_for_item("main", item) then - local stack_to_take = stack:take_item(1) - if target_def.allow_metadata_inventory_take == nil - or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper - or target_def.allow_metadata_inventory_take(target_pos, target_inv_name, i, stack_to_take, placer) > 0 then - target_inv:set_stack(target_inv_name, i, stack) - --add to hopper - hopper_inv:add_item("main", stack_to_take) - if target_def.on_metadata_inventory_take ~= nil and placer ~= nil then - target_def.on_metadata_inventory_take(target_pos, target_inv_name, i, stack_to_take, placer) - end - break + + if not stack:is_empty() and hopper_inv:room_for_item("main", stack:get_name()) then + local stack_to_take = stack:take_item(1) + + if target_def.allow_metadata_inventory_take == nil + or placer == nil -- backwards compatibility, older versions of this mod didn't record who placed the hopper + or target_def.allow_metadata_inventory_take(target_pos, target_inv_name, i, stack_to_take, placer) > 0 then + + target_inv:set_stack(target_inv_name, i, stack) + --add to hopper + hopper_inv:add_item("main", stack_to_take) + if target_def.on_metadata_inventory_take ~= nil and placer ~= nil then + target_def.on_metadata_inventory_take(target_pos, target_inv_name, i, stack_to_take, placer) end + break end end - end + + end -- for end end -local function send_item_to_air(hopper_inv, target_pos, filtered_items) +local function try_send_item_to_air(hopper_inv, target_pos) local stack local stack_num for i = 1, hopper_inv:get_size("main") do stack = hopper_inv:get_stack("main", i) - local item = stack:get_name() - if item ~= "" and (filtered_items == nil or filtered_items[item]) then + if not stack:is_empty() then stack_num = i break end end - if not stack_num then - return false + + local eject_node = minetest.get_node(target_pos) + local ndef = minetest.registered_nodes[eject_node.name] + if not ndef or not ndef.buildable_to then + minetest.log("verbose", "hopper.try_send_item_to_air: eject direction not buildable (" + ..eject_node.name.." at "..target_pos:to_string().."). Looking for alternate.") + local air_pos = minetest.find_node_near(target_pos, 2, {"air"}) + if not air_pos then + minetest.log("warning", "hopper.try_send_item_to_air: could not find an air node nearby") + return false + end + target_pos = air_pos end local stack_to_put = stack:take_item(1) minetest.add_item(target_pos, stack_to_put) hopper_inv:set_stack("main", stack_num, stack) + hopper.log_inventory("hopper ejecting "..stack:get_name().." as object to "..target_pos:to_string()) return true end @@ -204,10 +215,24 @@ hopper.send_item_to = function(hopper_pos, target_pos, target_node, target_inv_i return send_item_to_inv(hopper_inv, target_pos, filtered_items, placer, target_inv_info, target_def) end - if hopper.config.eject_button_enabled and target_def.buildable_to - and hopper_meta:get_string("eject") == "true" then - return send_item_to_air(hopper_inv, target_pos, filtered_items) - end - return false end + +hopper.try_eject_item = function(hopper_pos, target_pos) + if not hopper.config.eject_button_enabled then + return false + end + + local hopper_meta = minetest.get_meta(hopper_pos) + if hopper_meta:get_string("eject") ~= "true" then + return false + end + + local hopper_inv = hopper_meta:get_inventory() + if hopper_inv:is_empty("main") then + return false + end + + return try_send_item_to_air(hopper_inv, target_pos) +end +