Merge pull request 'Fix #4189 - Make hoppers move items if there is space for one item' (#4190) from teknomunk/MineClone2:hopper-changes into master
Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/4190 Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>hammers_spears
commit
4e12c6747c
|
@ -257,12 +257,21 @@ end
|
|||
---@param dst_inventory InvRef Destination inventory to push to
|
||||
---@param dst_list string Name of destination inventory list to push to
|
||||
---@param condition? fun(stack: ItemStack) Condition which items are allowed to be transfered.
|
||||
---@param count? integer Number of items to try to transfer at once
|
||||
---@return integer Item stack number to be transfered
|
||||
function mcl_util.select_stack(src_inventory, src_list, dst_inventory, dst_list, condition)
|
||||
function mcl_util.select_stack(src_inventory, src_list, dst_inventory, dst_list, condition, count)
|
||||
local src_size = src_inventory:get_size(src_list)
|
||||
local stack
|
||||
for i = 1, src_size do
|
||||
stack = src_inventory:get_stack(src_list, i)
|
||||
|
||||
-- Allow for partial stack movement
|
||||
if count and stack:get_count() >= count then
|
||||
local new_stack = ItemStack(stack)
|
||||
new_stack:set_count(count)
|
||||
stack = new_stack
|
||||
end
|
||||
|
||||
if not stack:is_empty() and dst_inventory:room_for_item(dst_list, stack) and ((condition == nil or condition(stack))) then
|
||||
return i
|
||||
end
|
||||
|
@ -280,21 +289,22 @@ end
|
|||
-- Returns true on success and false on failure
|
||||
-- Possible failures: No item in source slot, destination inventory full
|
||||
function mcl_util.move_item(source_inventory, source_list, source_stack_id, destination_inventory, destination_list)
|
||||
if not source_inventory:is_empty(source_list) then
|
||||
local stack = source_inventory:get_stack(source_list, source_stack_id)
|
||||
if not stack:is_empty() then
|
||||
local new_stack = ItemStack(stack)
|
||||
new_stack:set_count(1)
|
||||
if not destination_inventory:room_for_item(destination_list, new_stack) then
|
||||
return false
|
||||
end
|
||||
stack:take_item()
|
||||
source_inventory:set_stack(source_list, source_stack_id, stack)
|
||||
destination_inventory:add_item(destination_list, new_stack)
|
||||
return true
|
||||
end
|
||||
-- Can't move items we don't have
|
||||
if source_inventory:is_empty(source_list) then return false end
|
||||
|
||||
-- Can't move from an empty stack
|
||||
local stack = source_inventory:get_stack(source_list, source_stack_id)
|
||||
if stack:is_empty() then return false end
|
||||
|
||||
local new_stack = ItemStack(stack)
|
||||
new_stack:set_count(1)
|
||||
if not destination_inventory:room_for_item(destination_list, new_stack) then
|
||||
return false
|
||||
end
|
||||
return false
|
||||
stack:take_item()
|
||||
source_inventory:set_stack(source_list, source_stack_id, stack)
|
||||
destination_inventory:add_item(destination_list, new_stack)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Try pushing item from hopper inventory to destination inventory
|
||||
|
@ -314,25 +324,23 @@ function mcl_util.hopper_push(pos, dst_pos)
|
|||
local dst_list = 'main'
|
||||
local dst_inv, stack_id
|
||||
|
||||
-- Find a inventory stack in the destination
|
||||
if dst_def._mcl_hoppers_on_try_push then
|
||||
dst_inv, dst_list, stack_id = dst_def._mcl_hoppers_on_try_push(dst_pos, pos, hop_inv, hop_list)
|
||||
else
|
||||
local dst_meta = minetest.get_meta(dst_pos)
|
||||
dst_inv = dst_meta:get_inventory()
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, dst_inv, dst_list)
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, dst_inv, dst_list, nil, 1)
|
||||
end
|
||||
if not stack_id then return false end
|
||||
|
||||
-- Move the item
|
||||
local ok = mcl_util.move_item(hop_inv, hop_list, stack_id, dst_inv, dst_list)
|
||||
if dst_def._mcl_hoppers_on_after_push then
|
||||
dst_def._mcl_hoppers_on_after_push(dst_pos)
|
||||
end
|
||||
|
||||
if stack_id ~= nil then
|
||||
local ok = mcl_util.move_item(hop_inv, hop_list, stack_id, dst_inv, dst_list)
|
||||
if dst_def._mcl_hoppers_on_after_push then
|
||||
dst_def._mcl_hoppers_on_after_push(dst_pos)
|
||||
end
|
||||
if ok then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
return ok
|
||||
end
|
||||
|
||||
-- Try pulling from source inventory to hopper inventory
|
||||
|
@ -357,7 +365,7 @@ function mcl_util.hopper_pull(pos, src_pos)
|
|||
else
|
||||
local src_meta = minetest.get_meta(src_pos)
|
||||
src_inv = src_meta:get_inventory()
|
||||
stack_id = mcl_util.select_stack(src_inv, src_list, hop_inv, hop_list)
|
||||
stack_id = mcl_util.select_stack(src_inv, src_list, hop_inv, hop_list, nil, 1)
|
||||
end
|
||||
|
||||
if stack_id ~= nil then
|
||||
|
|
|
@ -475,8 +475,11 @@ minetest.register_node("mcl_books:bookshelf", {
|
|||
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main",
|
||||
function(stack) return minetest.get_item_group(stack:get_name(), "book") == 1 or stack:get_name() == "mcl_enchanting:book_enchanted" end)
|
||||
local function filter(stack)
|
||||
return minetest.get_item_group(stack:get_name(), "book") == 1 or
|
||||
stack:get_name() == "mcl_enchanting:book_enchanted"
|
||||
end
|
||||
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", filter, 1)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -379,16 +379,27 @@ end
|
|||
local function hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then
|
||||
return inv, "input", mcl_util.select_stack(hop_inv, hop_list, inv, "input",
|
||||
function(stack) return minetest.get_item_group(stack:get_name(), "brewitem") == 1 and minetest.get_item_group(stack:get_name(), "bottle") == 0 end)
|
||||
|
||||
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z)
|
||||
then
|
||||
local function filter(stack)
|
||||
return minetest.get_item_group(stack:get_name(), "brewitem") == 1 and
|
||||
minetest.get_item_group(stack:get_name(), "bottle") == 0
|
||||
end
|
||||
|
||||
return inv, "input", mcl_util.select_stack(hop_inv, hop_list, inv, "input", filter, 1)
|
||||
else
|
||||
local stack = mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", function(stack) return stack:get_name() == "mcl_mobitems:blaze_powder" end)
|
||||
local filter = function(stack)
|
||||
return stack:get_name() == "mcl_mobitems:blaze_powder"
|
||||
end
|
||||
local stack = mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", filter, 1 )
|
||||
if stack then
|
||||
return inv, "fuel", stack
|
||||
else
|
||||
return inv, "stand", mcl_util.select_stack(hop_inv, hop_list, inv, "stand",
|
||||
function(stack) return minetest.get_item_group(stack:get_name(), "bottle") == 1 end)
|
||||
local function filter(stack)
|
||||
return minetest.get_item_group(stack:get_name(), "bottle") == 1
|
||||
end
|
||||
return inv, "stand", mcl_util.select_stack(hop_inv, hop_list, inv, "stand", filter, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -760,7 +760,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main")
|
||||
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main", nil, 1)
|
||||
if stack_id ~= nil then
|
||||
return inv, "main", stack_id
|
||||
end
|
||||
|
@ -768,7 +768,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
||||
local meta_other = minetest.get_meta(pos_other)
|
||||
local inv_other = meta_other:get_inventory()
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main")
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main", nil, 1)
|
||||
return inv_other, "main", stack_id
|
||||
end,
|
||||
})
|
||||
|
@ -955,13 +955,13 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
|
|||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
||||
local meta_other = minetest.get_meta(pos_other)
|
||||
local inv_other = meta_other:get_inventory()
|
||||
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main")
|
||||
local stack_id = mcl_util.select_stack(hop_inv, hop_list, inv_other, "main", nil, 1)
|
||||
if stack_id ~= nil then
|
||||
return inv_other, "main", stack_id
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main")
|
||||
stack_id = mcl_util.select_stack(hop_inv, hop_list, inv, "main", nil, 1)
|
||||
return inv, "main", stack_id
|
||||
end,
|
||||
})
|
||||
|
@ -1522,7 +1522,7 @@ for color, desc in pairs(boxtypes) do
|
|||
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box)
|
||||
return inv, "main", mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box, 1)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ minetest.register_node("mcl_composters:composter", {
|
|||
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition)
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition, 1)
|
||||
end,
|
||||
_mcl_hoppers_on_after_push = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
@ -293,7 +293,7 @@ local function register_filled_composter(level)
|
|||
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition)
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", hopper_push_condition, 1)
|
||||
end,
|
||||
_mcl_hoppers_on_after_push = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
|
|
@ -466,9 +466,9 @@ function mcl_furnaces.hoppers_on_try_push(pos, hop_pos, hop_inv, hop_list)
|
|||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
if math.abs(pos.y - hop_pos.y) > math.abs(pos.x - hop_pos.x) and math.abs(pos.y - hop_pos.y) > math.abs(pos.z - hop_pos.z) then
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src")
|
||||
return inv, "src", mcl_util.select_stack(hop_inv, hop_list, inv, "src", nil, 1)
|
||||
else
|
||||
return inv, "fuel", mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", mcl_util.is_fuel)
|
||||
return inv, "fuel", mcl_util.select_stack(hop_inv, hop_list, inv, "fuel", mcl_util.is_fuel, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -32,6 +32,68 @@ local mcl_hoppers_formspec = table.concat({
|
|||
"listring[current_player;main]",
|
||||
})
|
||||
|
||||
local function straight_hopper_act(pos, node, active_object_count, active_count_wider)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if timer:is_started() then
|
||||
--Pause if already recived item this tick
|
||||
return
|
||||
end
|
||||
timer:start(1.0)
|
||||
|
||||
-- Move from internal inventory to dst first
|
||||
local dst_pos = vector.offset(pos, 0, -1, 0)
|
||||
local dst_node = minetest.get_node(dst_pos)
|
||||
local dst_name = dst_node.name
|
||||
local dst_def = minetest.registered_nodes[dst_name]
|
||||
|
||||
if dst_def and dst_def._mcl_hopper_act then
|
||||
dst_def._mcl_hopper_act( dst_pos, dst_node, active_object_count, active_count_wider )
|
||||
end
|
||||
|
||||
mcl_util.hopper_push(pos, dst_pos)
|
||||
local src_pos = vector.offset(pos, 0, 1, 0)
|
||||
mcl_util.hopper_pull(pos, src_pos)
|
||||
end
|
||||
|
||||
local function bent_hopper_act(pos, node, active_object_count, active_object_count_wider)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if timer:is_started() then
|
||||
--Pause if already recived item this tick
|
||||
return
|
||||
end
|
||||
timer:start(1.0)
|
||||
|
||||
-- Check if we are empty
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local empty = inv:is_empty("main")
|
||||
|
||||
-- Determine to which side the hopper is facing, get nodes
|
||||
local face = minetest.get_node(pos).param2
|
||||
local dst_pos = {}
|
||||
if face == 0 then
|
||||
dst_pos = vector.offset(pos, -1, 0, 0)
|
||||
elseif face == 1 then
|
||||
dst_pos = vector.offset(pos, 0, 0, 1)
|
||||
elseif face == 2 then
|
||||
dst_pos = vector.offset(pos, 1, 0, 0)
|
||||
elseif face == 3 then
|
||||
dst_pos = vector.offset(pos, 0, 0, -1)
|
||||
end
|
||||
local dst_node = minetest.get_node(dst_pos)
|
||||
local dst_name = dst_node.name
|
||||
local dst_def = minetest.registered_nodes[dst_name]
|
||||
if dst_def and dst_def._mcl_hopper_act then
|
||||
dst_def._mcl_hopper_act( dst_pos, dst_node, active_object_count, active_object_count_wider )
|
||||
end
|
||||
if not empty then
|
||||
mcl_util.hopper_push(pos, dst_pos)
|
||||
end
|
||||
|
||||
local src_pos = vector.offset(pos, 0, 1, 0)
|
||||
mcl_util.hopper_pull(pos, src_pos)
|
||||
end
|
||||
|
||||
-- Downwards hopper (base definition)
|
||||
|
||||
---@type node_definition
|
||||
|
@ -206,6 +268,7 @@ def_hopper_enabled.mesecons = {
|
|||
end,
|
||||
},
|
||||
}
|
||||
def_hopper_enabled._mcl_hopper_act = straight_hopper_act
|
||||
|
||||
minetest.register_node("mcl_hoppers:hopper", def_hopper_enabled)
|
||||
|
||||
|
@ -355,6 +418,7 @@ def_hopper_side_enabled.mesecons = {
|
|||
end,
|
||||
},
|
||||
}
|
||||
def_hopper_side_enabled._mcl_hopper_act = bent_hopper_act
|
||||
minetest.register_node("mcl_hoppers:hopper_side", def_hopper_side_enabled)
|
||||
|
||||
---@type node_definition
|
||||
|
@ -559,24 +623,7 @@ minetest.register_abm({
|
|||
neighbors = { "group:container" },
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
if minetest.get_node_timer(pos):is_started() then
|
||||
return
|
||||
end
|
||||
|
||||
-- Move from internal inventory to dst first
|
||||
local dst_pos = vector.offset(pos, 0, -1, 0)
|
||||
local pushed = mcl_util.hopper_push(pos, dst_pos)
|
||||
|
||||
local src_pos = vector.offset(pos, 0, 1, 0)
|
||||
mcl_util.hopper_pull(pos, src_pos)
|
||||
|
||||
local dst_node = minetest.get_node(dst_pos)
|
||||
if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then
|
||||
--Pause destination hopper
|
||||
minetest.get_node_timer(dst_pos):start(1.0)
|
||||
end
|
||||
end,
|
||||
action = straight_hopper_act,
|
||||
})
|
||||
|
||||
-- Register push/pull for "bent" hopper
|
||||
|
@ -586,35 +633,7 @@ minetest.register_abm({
|
|||
neighbors = { "group:container" },
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
if minetest.get_node_timer(pos):is_started() then
|
||||
--Pause if already recived item this tick
|
||||
return
|
||||
end
|
||||
|
||||
-- Determine to which side the hopper is facing, get nodes
|
||||
local face = minetest.get_node(pos).param2
|
||||
local dst_pos = {}
|
||||
if face == 0 then
|
||||
dst_pos = vector.offset(pos, -1, 0, 0)
|
||||
elseif face == 1 then
|
||||
dst_pos = vector.offset(pos, 0, 0, 1)
|
||||
elseif face == 2 then
|
||||
dst_pos = vector.offset(pos, 1, 0, 0)
|
||||
elseif face == 3 then
|
||||
dst_pos = vector.offset(pos, 0, 0, -1)
|
||||
end
|
||||
local pushed = mcl_util.hopper_push(pos, dst_pos)
|
||||
|
||||
local src_pos = vector.offset(pos, 0, 1, 0)
|
||||
mcl_util.hopper_pull(pos, src_pos)
|
||||
|
||||
local dst_node = minetest.get_node(dst_pos)
|
||||
if pushed and (dst_node.name == "mcl_hoppers:hopper" or dst_node.name == "mcl_hoppers:hopper_side") then
|
||||
--Pause destination hopper
|
||||
minetest.get_node_timer(dst_pos):start(1.0)
|
||||
end
|
||||
end,
|
||||
action = bent_hopper_act,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
|
Loading…
Reference in New Issue