-
Notifications
You must be signed in to change notification settings - Fork 10
/
utility.lua
238 lines (201 loc) · 7.88 KB
/
utility.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
local FS = hopper.translator_escaped
-- 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
hopper.get_registered = function(target_node_name)
local output = hopper.containers[target_node_name]
if output ~= nil then return output end
local target_def = minetest.registered_nodes[target_node_name]
if target_def == nil or target_def.groups == nil then return nil end
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"]
if output ~= nil then return output end
end
end
return nil
end
hopper.get_eject_button_texts = function(pos, loc_X, loc_Y)
if not hopper.config.eject_button_enabled then return "" end
local texture, eject_button_tooltip
if minetest.get_meta(pos):get_string("eject") == "true" then
texture = "hopper_mode_eject.png"
eject_button_tooltip = FS("This hopper is currently set to eject items from its output\neven if there isn't a compatible block positioned to receive it.\nClick this button to disable this feature.")
else
texture = "hopper_mode_hold.png"
eject_button_tooltip = FS("This hopper is currently set to hold on to item if there\nisn't a compatible block positioned to receive it.\nClick this button to have it eject items instead.")
end
return ("image_button_exit[%g,%g;1,1;%s;eject;]"):format(loc_X, loc_Y, texture) ..
"tooltip[eject;"..eject_button_tooltip.."]"
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
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
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
local target_node = minetest.get_node(node_pos)
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
-- Used to remove items from the target block and put it into the hopper's inventory
hopper.take_item_from = function(hopper_pos, target_pos, target_node, target_inv_info)
local target_def = minetest.registered_nodes[target_node.name]
if not target_def then
return
end
--hopper inventory
local hopper_meta = minetest.get_meta(hopper_pos)
local hopper_inv = hopper_meta:get_inventory()
local placer = get_placer(hopper_meta:get_string("placer"))
--source inventory
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 target_inv_size = target_inv:get_size(target_inv_name)
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)
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 -- for
end
end
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)
if not stack:is_empty() then
stack_num = i
break
end
end
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
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
-- Used to put items from the hopper inventory into the target block
hopper.send_item_to = function(hopper_pos, target_pos, target_node, target_inv_info, filtered_items)
local target_def = minetest.registered_nodes[target_node.name]
if not target_def then
return false
end
local hopper_meta = minetest.get_meta(hopper_pos)
local hopper_inv = hopper_meta:get_inventory()
if hopper_inv:is_empty("main") == true then
return false
end
if target_inv_info then
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)
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