2022-07-10 20:25:00 +02:00
local FS = hopper.translator_escaped
2017-03-31 08:58:28 +02:00
-- Target inventory retrieval
-- looks first for a registration matching the specific node name, then for a registration
-- matching group and value, then for a registration matching a group and *any* value
2024-07-21 03:16:35 +02:00
hopper.get_registered = function ( target_node_name )
2017-03-31 08:58:28 +02:00
local output = hopper.containers [ target_node_name ]
if output ~= nil then return output end
2017-09-02 04:53:03 +02:00
2017-03-31 08:58:28 +02:00
local target_def = minetest.registered_nodes [ target_node_name ]
2017-05-07 21:06:26 +02:00
if target_def == nil or target_def.groups == nil then return nil end
2017-09-02 04:53:03 +02:00
2017-03-31 08:58:28 +02:00
for group , value in pairs ( target_def.groups ) do
local registered_group = hopper.groups [ group ]
if registered_group ~= nil then
output = registered_group [ value ]
if output ~= nil then return output end
output = registered_group [ " all " ]
2017-09-02 04:53:03 +02:00
if output ~= nil then return output end
end
2017-03-31 08:58:28 +02:00
end
2017-09-02 04:53:03 +02:00
2017-03-31 08:58:28 +02:00
return nil
end
hopper.get_eject_button_texts = function ( pos , loc_X , loc_Y )
if not hopper.config . eject_button_enabled then return " " end
2022-07-10 20:25:00 +02:00
local texture , eject_button_tooltip
2017-03-31 08:58:28 +02:00
if minetest.get_meta ( pos ) : get_string ( " eject " ) == " true " then
2022-07-10 20:25:00 +02:00
texture = " hopper_mode_eject.png "
eject_button_tooltip = FS ( " This hopper is currently set to eject items from its output \n even if there isn't a compatible block positioned to receive it. \n Click this button to disable this feature. " )
2017-03-31 08:58:28 +02:00
else
2022-07-10 20:25:00 +02:00
texture = " hopper_mode_hold.png "
eject_button_tooltip = FS ( " This hopper is currently set to hold on to item if there \n isn't a compatible block positioned to receive it. \n Click this button to have it eject items instead. " )
2017-03-31 08:58:28 +02:00
end
2022-07-10 20:25:00 +02:00
return ( " image_button_exit[%g,%g;1,1;%s;eject;] " ) : format ( loc_X , loc_Y , texture ) ..
" tooltip[eject; " .. eject_button_tooltip .. " ] "
2017-03-31 08:58:28 +02:00
end
hopper.get_string_pos = function ( pos )
return pos.x .. " , " .. pos.y .. " , " .. pos.z
end
-- Apparently node_sound_metal_defaults is a newer thing, I ran into games using an older version of the default mod without it.
if default.node_sound_metal_defaults ~= nil then
hopper.metal_sounds = default.node_sound_metal_defaults ( )
else
hopper.metal_sounds = default.node_sound_stone_defaults ( )
end
-------------------------------------------------------------------------------------------
-- Inventory transfer functions
2017-04-02 06:39:31 +02:00
local delay = function ( x )
return ( function ( ) return x end )
end
local get_placer = function ( player_name )
if player_name ~= " " then
return minetest.get_player_by_name ( player_name ) or {
is_player = delay ( true ) ,
get_player_name = delay ( player_name ) ,
is_fake_player = " :hopper " ,
get_wielded_item = delay ( ItemStack ( nil ) )
}
end
return nil
end
2024-08-12 22:05:05 +02:00
local function get_container_inventory ( node_pos , inv_info )
local get_inventory_fn = inv_info.get_inventory
local inventory
if get_inventory_fn then
inventory = get_inventory_fn ( node_pos )
if not inventory then
2024-08-16 22:58:59 +02:00
local target_node = minetest.get_node ( node_pos )
2024-08-12 22:05:05 +02:00
minetest.log ( " error " , " No inventory from api get_inventory function: " ..
target_node.name .. " on " .. vector.to_string ( node_pos ) )
end
else
inventory = minetest.get_meta ( node_pos ) : get_inventory ( )
end
return inventory
end
2024-12-14 19:05:49 +01:00
--- @param Removes items from the target node and puts them into the hopper's inventory
--- @param target_inv_info : Inventory information where to take the ItemStacks
2024-07-21 03:16:35 +02:00
hopper.take_item_from = function ( hopper_pos , target_pos , target_node , target_inv_info )
2024-12-14 19:05:49 +01:00
if not target_inv_info then
return false -- Cannot move take from this direction
end
2017-05-07 21:06:26 +02:00
local target_def = minetest.registered_nodes [ target_node.name ]
if not target_def then
return
end
2017-03-31 08:58:28 +02:00
--hopper inventory
2024-07-21 03:16:35 +02:00
local hopper_meta = minetest.get_meta ( hopper_pos )
2017-03-31 08:58:28 +02:00
local hopper_inv = hopper_meta : get_inventory ( )
2017-04-02 06:39:31 +02:00
local placer = get_placer ( hopper_meta : get_string ( " placer " ) )
2017-09-02 04:53:03 +02:00
2017-03-31 08:58:28 +02:00
--source inventory
2024-08-12 22:05:05 +02:00
local target_inv_name = target_inv_info.inventory_name
local target_inv = get_container_inventory ( target_pos , target_inv_info )
if not target_inv then
return false
2024-07-21 03:16:35 +02:00
end
2024-08-12 22:05:05 +02:00
2024-07-21 03:16:35 +02:00
local target_inv_size = target_inv : get_size ( target_inv_name )
if target_inv : is_empty ( target_inv_name ) == false then
2017-03-31 08:58:28 +02:00
for i = 1 , target_inv_size do
2024-07-21 03:16:35 +02:00
local stack = target_inv : get_stack ( target_inv_name , i )
2024-09-25 20:41:03 +02:00
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 )
2017-03-31 08:58:28 +02:00
end
2024-09-25 20:41:03 +02:00
break
2017-03-31 08:58:28 +02:00
end
end
2024-09-25 20:41:03 +02:00
end -- for
2017-03-31 08:58:28 +02:00
end
end
2024-09-25 20:41:03 +02:00
local function try_send_item_to_air ( hopper_inv , target_pos )
2024-09-02 17:46:15 +02:00
local stack
local stack_num
for i = 1 , hopper_inv : get_size ( " main " ) do
stack = hopper_inv : get_stack ( " main " , i )
2024-09-25 20:41:03 +02:00
if not stack : is_empty ( ) then
2024-09-02 17:46:15 +02:00
stack_num = i
break
end
end
2024-09-25 20:41:03 +02:00
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
2024-09-02 17:46:15 +02:00
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 )
2024-09-25 20:41:03 +02:00
hopper.log_inventory ( " hopper ejecting " .. stack : get_name ( ) .. " as object to " .. target_pos : to_string ( ) )
2024-09-02 17:46:15 +02:00
return true
end
2024-12-14 19:05:49 +01:00
--- @brief Moves items from the hopper's inventory to the destination and triggers inventory actions
--- @param placer : (optional) PlayerRef
--- @param target_def : Target nodedef
2024-09-02 17:46:15 +02:00
local function send_item_to_inv ( hopper_inv , target_pos , filtered_items , placer , target_inv_info , target_def )
local target_inv_name = target_inv_info.inventory_name
local target_inv = get_container_inventory ( target_pos , target_inv_info )
if not target_inv then
return false
end
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 ] )
and target_inv : room_for_item ( target_inv_name , item ) then
stack_num = i
break
end
end
if not stack_num then
return false
end
local stack_to_put = stack : take_item ( 1 )
if target_def.allow_metadata_inventory_put and placer -- backwards compatibility, older versions of this mod didn't record who placed the hopper
and target_def.allow_metadata_inventory_put ( target_pos , target_inv_name , stack_num , stack_to_put , placer ) < 0 then
return false
end
hopper_inv : set_stack ( " main " , stack_num , stack )
target_inv : add_item ( target_inv_name , stack_to_put )
if target_def.on_metadata_inventory_put ~= nil and placer ~= nil then
target_def.on_metadata_inventory_put ( target_pos , target_inv_name , stack_num , stack_to_put , placer )
end
return true
end
2024-12-14 19:05:49 +01:00
--- @brief Used to put items from the hopper inventory into the target block
--- @param target_inv_info : Inventory information where to put the ItemStacks
--- @param filtered_items : (optional) whitelist of item names { ["modname:itemname"] = true, ... }
2024-07-21 03:16:35 +02:00
hopper.send_item_to = function ( hopper_pos , target_pos , target_node , target_inv_info , filtered_items )
2024-12-14 19:05:49 +01:00
if not target_inv_info then
return false -- Cannot move item into this direction
end
2017-03-31 08:58:28 +02:00
local target_def = minetest.registered_nodes [ target_node.name ]
2017-05-07 21:06:26 +02:00
if not target_def then
return false
end
2017-09-02 04:53:03 +02:00
2024-08-16 22:58:59 +02:00
local hopper_meta = minetest.get_meta ( hopper_pos )
2017-03-31 08:58:28 +02:00
local hopper_inv = hopper_meta : get_inventory ( )
if hopper_inv : is_empty ( " main " ) == true then
return false
end
2017-04-02 06:39:31 +02:00
2024-12-14 19:05:49 +01:00
local placer = get_placer ( hopper_meta : get_string ( " placer " ) )
return send_item_to_inv ( hopper_inv , target_pos , filtered_items , placer , target_inv_info , target_def )
2024-09-25 20:41:03 +02:00
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
2017-03-31 08:58:28 +02:00
end
2024-09-02 17:46:15 +02:00
2024-09-25 20:41:03 +02:00
return try_send_item_to_air ( hopper_inv , target_pos )
2017-03-31 08:58:28 +02:00
end
2024-09-25 20:41:03 +02:00