Files
lwcomponents/storage.lua
2022-02-24 08:28:38 +10:00

1448 lines
31 KiB
Lua

local utils = ...
local S = utils.S
local function unit_after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]"..
"size[11.75,12.25,false]"..
"list[context;main;1.0,1.0;8,4;]"..
"list[current_player;main;1.0,6.5;8,4;]"..
"listring[]"
meta:set_string ("inventory", "{ main = { } }")
meta:set_string ("formspec", spec)
local inv = meta:get_inventory ()
inv:set_size ("main", 32)
inv:set_width ("main", 8)
-- If return true no item is taken from itemstack
return false
end
local function unit_after_place_node_locked (pos, placer, itemstack, pointed_thing)
unit_after_place_node (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Storage Unit (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
return false
end
local function unit_can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if not inv:is_empty ("main") then
return false
end
end
end
return true
end
local function unit_on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("main")
for slot = 1, slots do
local stack = inv:get_stack ("main", slot)
if stack and not stack:is_empty () then
if math.floor (math.random (0, 5)) == 3 then
utils.item_drop (stack, nil, pos)
else
utils.on_destroy (stack)
end
end
end
end
on_destruct (pos)
minetest.remove_node (pos)
else -- intensity < 1.0
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("main")
for slot = 1, slots do
local stack = inv:get_stack ("main", slot)
if stack and not stack:is_empty () then
utils.item_drop (stack, nil, pos)
end
end
end
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
on_destruct (pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function unit_on_rightclick (pos, node, clicker, itemstack, pointed_thing)
if not utils.can_interact_with_node (pos, clicker) then
if clicker and clicker:is_player () then
local owner = "<unknown>"
local meta = minetest.get_meta (pos)
if meta then
owner = meta:get_string ("owner")
end
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (clicker:get_player_name (),
"lwcomponents:component_privately_owned",
spec)
end
end
return itemstack
end
minetest.register_node("lwcomponents:storage_unit", {
description = S("Storage Unit"),
drawtype = "glasslike_framed",
tiles = { "lwcomponents_storage_framed.png", "lwcomponents_storage.png" },
is_ground_content = false,
groups = { choppy = 2 },
sounds = default.node_sound_wood_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
after_place_node = unit_after_place_node,
can_dig = unit_can_dig,
on_blast = unit_on_blast,
on_rightclick = unit_on_rightclick
})
minetest.register_node("lwcomponents:storage_unit_locked", {
description = S("Storage Unit (locked)"),
drawtype = "glasslike_framed",
tiles = { "lwcomponents_storage_framed.png", "lwcomponents_storage.png" },
is_ground_content = false,
groups = { choppy = 2 },
sounds = default.node_sound_wood_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
after_place_node = unit_after_place_node_locked,
can_dig = unit_can_dig,
on_blast = unit_on_blast,
on_rightclick = unit_on_rightclick
})
local consolidation_interval = 20
local function unescape_description (description)
if description:sub (1, 4) == string.char (27, 40, 84, 64) then
local last = description:find (")", 5, true)
if last then
description = description:sub (last + 1, -1)
end
end
return description:gsub (string.char (27, 70), ""):gsub (string.char (27, 69), "")
end
local function unit_inventory (pos, owner, inv_list)
local node = utils.get_far_node (pos)
if node and (node.name == "lwcomponents:storage_unit" or
node.name == "lwcomponents:storage_unit_locked") then
local meta = minetest.get_meta (pos)
local uowner = meta:get_string ("owner")
if meta and (owner == uowner or uowner == "") then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("main")
for slot = 1, slots, 1 do
local stack = inv:get_stack ("main", slot)
if stack and not stack:is_empty () then
local copy = ItemStack (stack)
copy:set_count (1)
local name = copy:to_string ()
local item = inv_list[name]
if not item then
inv_list[name] = { count = 0 }
item = inv_list[name]
end
item[#item + 1] =
{
pos = vector.new (pos),
count = stack:get_count (),
slot = slot
}
item.count = item.count + stack:get_count ()
end
end
end
return true
end
end
return false
end
local function inventory_searcher (pos, owner, coords, inv_list, check_list)
local spos = minetest.pos_to_string (pos, 0)
if not check_list[spos] then
check_list[spos] = true
if unit_inventory (pos, owner, inv_list) then
for _, c in ipairs (coords) do
inventory_searcher (vector.add (pos, c), owner, coords, inv_list, check_list)
end
end
end
end
local function get_inventory_list (pos)
local inv_list = { }
local meta = minetest.get_meta (pos)
if meta then
local owner = meta:get_string ("owner")
local check_list = { [minetest.pos_to_string (pos, 0)] = true }
local coords =
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 }
}
for _, c in ipairs (coords) do
inventory_searcher (vector.add (pos, c), owner, coords, inv_list, check_list)
end
end
return inv_list
end
local function count_table_keys (t)
local count = 0
for k, v in pairs (t) do
count = count + 1
end
return count
end
local function get_stock_list (pos)
local inv_list = get_inventory_list (pos)
local list = { }
for k, v in pairs (inv_list) do
local stack = ItemStack (k)
local name = stack:get_name ()
local description = nil
local custom = false
local pallet_index = nil
local tstack = stack:to_table ()
if tstack and tstack.meta and count_table_keys (tstack.meta) > 0 then
custom = true
if stack:get_meta ():get_string ("description") ~= "" then
description = stack:get_meta ():get_string ("description")
end
pallet_index = tstack.meta.palette_index
end
if not description then
description = name
local def = utils.find_item_def (name)
if def then
if def.short_description then
description = def.short_description
elseif def.description then
description = def.description
end
end
end
list[#list + 1] =
{
name = stack:get_name (),
description = unescape_description (description),
id = k,
count = v.count,
custom = custom,
pallet_index = pallet_index,
}
end
return list
end
local function output_items (pos, name, count)
if count < 1 then
return 0
end
local meta = minetest.get_meta (pos)
if not meta then
return 0
end
local inv = meta:get_inventory ()
if not inv then
return 0
end
local stack = ItemStack (name)
stack:set_count (count)
while stack:get_count () > 0 do
if inv:room_for_item ("output", stack) then
break
else
stack:set_count (stack:get_count () - 1)
end
end
if stack:get_count () < 1 then
return 0
end
local inv_list = get_inventory_list (pos)
local item = inv_list[name]
local left = stack:get_count ()
if item then
for i = #item, 1, -1 do
local tmeta = minetest.get_meta (item[i].pos)
local tinv = (tmeta and tmeta:get_inventory ()) or nil
if tinv then
local s = tinv:get_stack ("main", item[i].slot)
if utils.is_same_item (name, s) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
tinv:set_stack ("main", item[i].slot, s)
left = 0
else
tinv:set_stack ("main", item[i].slot, nil)
left = left - s:get_count ()
end
end
if left == 0 then
break
end
end
end
end
if left < count then
local output = ItemStack (name)
output:set_count (count - left)
inv:add_item ("output", output)
return count - left
end
return 0
end
local function consolidate_itemstacks (item1, item2)
local copy1 = ItemStack (item1)
local copy2 = ItemStack (item2)
if utils.is_same_item (copy1, copy2) then
local count = copy1:get_stack_max () - copy1:get_count ()
if count > copy2:get_count () then
count = copy2:get_count ()
end
if count > 0 then
copy1:set_count (copy1:get_count () + count)
copy2:set_count (copy2:get_count () - count)
if copy2:get_count () < 1 then
copy2 = nil
end
end
end
return copy1, copy2
end
local function consolidate_stock (pos)
local inv_list = get_inventory_list (pos)
for k, v in pairs (inv_list) do
if #v > 1 then
for i = #v, 2, -1 do
local smeta = minetest.get_meta (v[i].pos)
local sinv = (smeta and smeta:get_inventory ()) or nil
if sinv then
local src = sinv:get_stack ("main", v[i].slot)
if src and not src:is_empty () then
for j = 1, i - 1, 1 do
local dmeta = minetest.get_meta (v[j].pos)
local dinv = (dmeta and dmeta:get_inventory ()) or nil
if dinv then
local dest = dinv:get_stack ("main", v[j].slot)
dest, src = consolidate_itemstacks (dest, src)
dinv:set_stack ("main", v[j].slot, dest)
end
if not src or src:is_empty () then
break
end
end
end
sinv:set_stack ("main", v[i].slot, src)
end
end
end
end
end
local function check_consolidation (pos)
local meta = minetest.get_meta (pos)
if meta then
local count = meta:get_int ("input_count") + 1
if count >= consolidation_interval then
meta:set_int ("input_count", 0)
minetest.after (0.1, consolidate_stock, vector.new (pos))
else
meta:set_int ("input_count", count)
end
end
end
local function check_filter (pos, itemstack)
local stack = ItemStack (itemstack)
if stack and not stack:is_empty () then
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if inv:is_empty ("filter") then
return true
end
local slots = inv:get_size ("filter")
for i = 1, slots, 1 do
local s = inv:get_stack ("filter", i)
if s and not s:is_empty () and
s:get_name () == stack:get_name () then
return true
end
end
end
end
end
return false
end
local function unit_placer (pos, owner, stack)
local node = utils.get_far_node (pos)
if node and (node.name == "lwcomponents:storage_unit" or
node.name == "lwcomponents:storage_unit_locked") then
local meta = minetest.get_meta (pos)
local uowner = meta:get_string ("owner")
if meta and (owner == uowner or uowner == "") then
local inv = meta:get_inventory ()
if inv then
local left = inv:add_item ("main", stack)
if not left or left:is_empty () or left:get_count () == 0 then
return false, nil
end
return true, left
end
end
end
return false, stack
end
local function inventory_placer (pos, owner, coords, stack, check_list)
local spos = minetest.pos_to_string (pos, 0)
if not check_list[spos] then
check_list[spos] = true
local continue, left = unit_placer (pos, owner, stack)
if continue and left then
for _, c in ipairs (coords) do
left = inventory_placer (vector.add (pos, c), owner, coords, left, check_list)
if not left then
break
end
end
end
return left
end
return stack
end
local function input_item (pos, itemstack)
local stack = ItemStack (itemstack)
if stack and not stack:is_empty () and
check_filter (pos, itemstack) then
local meta = minetest.get_meta (pos)
if meta then
local owner = meta:get_string ("owner")
local check_list = { [minetest.pos_to_string (pos, 0)] = true }
local coords =
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 }
}
for _, c in ipairs (coords) do
stack = inventory_placer (vector.add (pos, c), owner, coords, stack, check_list)
if not stack then
break
end
end
end
check_consolidation (pos)
end
return stack
end
local function store_input (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("input")
for slot = 1, slots, 1 do
local stack = inv:get_stack ("input", slot)
if stack and not stack:is_empty () then
local left = input_item (pos, stack)
if left then
left = inv:add_item ("output", left)
end
inv:set_stack ("input", slot, left)
end
end
end
end
end
local function store_input_delayed (pos)
minetest.after (0.1, store_input, pos)
end
local function search_filter (name, terms)
if terms then
for _, t in ipairs (terms) do
if (name:lower ():find (t, 1, true)) then
return true
end
end
return false
end
return true
end
local function get_formspec_list (pos)
local inv_list = get_inventory_list (pos)
local list = { }
for k, v in pairs (inv_list) do
local description = k
local stack = ItemStack (k)
local smeta = stack:get_meta ()
if smeta and smeta:get_string ("description") ~= "" then
description = smeta:get_string ("description")
else
local def = utils.find_item_def (stack:get_name ())
if def then
if def.short_description then
description = def.short_description
elseif def.description then
description = def.description
end
end
end
list[#list + 1] =
{
item = k,
description = unescape_description (description),
count = v.count
}
end
local foo = table.sort (list , function (e1, e2)
return (e1.description:lower () < e2.description:lower ())
end)
return list
end
local function indexer_get_formspec (pos, search)
local inv_list = get_formspec_list (pos)
search = search or ""
local terms = { }
for w in string.gmatch(search, "[^%s]+") do
terms[#terms + 1] = string.lower (w)
end
if #terms < 1 then
terms = nil
end
local index = ""
local count = 0
local top = 0
for _, v in ipairs (inv_list) do
if search_filter (v.description, terms) then
local stack = ItemStack (v.item)
local max_stack = stack:get_stack_max ()
local descr_esc = minetest.formspec_escape (v.description)
local item =
string.format ("item_image_button[0.0,%0.2f;1.0,1.0;%s;01_%s;]",
top, v.item, v.item)
if max_stack >= 10 then
item = item..
string.format ("button[1.0,%0.2f;1.0,1.0;10_%s;10]",
top, v.item)
end
if max_stack > 1 then
item = item..
string.format ("button[2.0,%0.2f;1.0,1.0;ST_%d_%s;%d]",
top, max_stack, v.item, max_stack)
end
item = item..
string.format ("label[3.1,%0.2f;%d]"..
"label[4.4,%0.2f;%s]",
top + 0.5, v.count,
top + 0.5, descr_esc)
index = index..item
top = top + 1.0
count = count + 1
end
end
local scroll_height = ((count < 12 and 0) or (count - 11)) * 10
local thumb_size = (count < 12 and 11) or (scroll_height * (11 / count))
if thumb_size < (scroll_height / 10) then
thumb_size = scroll_height / 10
end
local spec =
string.format ("formspec_version[3]"..
"size[21.75,14.5,false]"..
"field[1.0,1.21;7.5,0.8;search_field;;%s]\n"..
"field_close_on_enter[search_field;false]"..
"button[8.5,1.21;2.0,0.8;search;Search]\n"..
"scrollbaroptions[min=0;max=%d;smallstep=10;largestep=100;thumbsize=%d;arrows=default]"..
"scrollbar[10.0,2.5;0.5,11.0;vertical;index_scrollbar;0-%d]"..
"scroll_container[1.0,2.5;9.0,11.0;index_scrollbar;vertical;0.1]"..
"%s"..
"scroll_container_end[]"..
"field[11.0,1.21;3.0,0.8;channel;Channel;${channel}]\n"..
"field_close_on_enter[channel;false]"..
"button[14.0,1.21;1.5,0.8;setchannel;Set]\n"..
"label[11.0,3.6;Input]"..
"list[context;input;11.0,3.8;2,2;]"..
"listring[context;output]"..
"label[16.0,1.0;Output]"..
"list[context;output;16.0,1.25;4,4;]"..
"listring[current_player;main]"..
"label[11.0,6.75;Filter]"..
"list[context;filter;11.0,7.0;8,1;]"..
"list[current_player;main;11.0,8.75;8,4;]"..
"listring[context;input]",
search,
scroll_height,
thumb_size,
scroll_height,
index)
return spec
end
local function indexer_after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
meta:set_string ("inventory", "{ input = { }, output = { }, filter = { } }")
meta:set_string ("formspec", indexer_get_formspec (pos))
local inv = meta:get_inventory ()
inv:set_size ("input", 4)
inv:set_width ("input", 2)
inv:set_size ("output", 16)
inv:set_width ("output", 4)
inv:set_size ("filter", 8)
inv:set_width ("filter", 2)
end
local function indexer_after_place_node (pos, placer, itemstack, pointed_thing)
indexer_after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function indexer_after_place_node_locked (pos, placer, itemstack, pointed_thing)
indexer_after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Storage Indexer (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function indexer_can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if not inv:is_empty ("input") then
return false
end
if not inv:is_empty ("output") then
return false
end
end
end
return true
end
local function indexer_on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("input")
for slot = 1, slots do
local stack = inv:get_stack ("input", slot)
if stack and not stack:is_empty () then
if math.floor (math.random (0, 5)) == 3 then
utils.item_drop (stack, nil, pos)
else
utils.on_destroy (stack)
end
end
end
slots = inv:get_size ("output")
for slot = 1, slots do
local stack = inv:get_stack ("output", slot)
if stack and not stack:is_empty () then
if math.floor (math.random (0, 5)) == 3 then
utils.item_drop (stack, nil, pos)
else
utils.on_destroy (stack)
end
end
end
end
on_destruct (pos)
minetest.remove_node (pos)
else -- intensity < 1.0
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("input")
for slot = 1, slots do
local stack = inv:get_stack ("input", slot)
if stack and not stack:is_empty () then
utils.item_drop (stack, nil, pos)
end
end
slots = inv:get_size ("output")
for slot = 1, slots do
local stack = inv:get_stack ("output", slot)
if stack and not stack:is_empty () then
utils.item_drop (stack, nil, pos)
end
end
end
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
on_destruct (pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function indexer_on_rightclick (pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
if meta then
if not utils.can_interact_with_node (pos, clicker) then
if clicker and clicker:is_player () then
local owner = meta:get_string ("owner")
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (clicker:get_player_name (),
"lwcomponents:component_privately_owned",
spec)
end
return itemstack
end
meta:set_string ("formspec", indexer_get_formspec (pos))
end
return itemstack
end
local function indexer_on_receive_fields (pos, formname, fields, sender)
if not utils.can_interact_with_node (pos, sender) then
return
end
if fields.setchannel or (fields.key_enter_field and
fields.key_enter_field == "channel") then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel)
end
elseif fields.search or (fields.key_enter_field and
fields.key_enter_field == "search_field") then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("formspec", indexer_get_formspec (pos, fields.search_field))
end
else
for k, v in pairs (fields) do
if k:sub (1, 3) == "01_" then
local item = k:sub (4, -1)
output_items (pos, item, 1)
break
elseif k:sub (1, 3) == "10_" then
local item = k:sub (4, -1)
output_items (pos, item, 10)
break
elseif k:sub (1, 3) == "ST_" then
local marker = k:find ("_", 4, true)
if marker then
local qty = tonumber (k:sub (4, marker - 1) or 1)
local item = k:sub (marker + 1, -1)
output_items (pos, item, qty)
end
end
end
end
end
local function indexer_on_metadata_inventory_put (pos, listname, index, stack, player)
if listname == "input" then
store_input_delayed (pos)
end
end
local function indexer_on_metadata_inventory_move (pos, from_list, from_index,
to_list, to_index, count, player)
if from_list == "output" and to_list == "input" then
store_input_delayed (pos)
end
end
local function indexer_allow_metadata_inventory_put (pos, listname, index, stack, player)
if listname == "filter" then
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
inv:set_stack ("filter", index, ItemStack (stack:get_name ()))
end
end
return 0
end
return stack:get_stack_max ()
end
local function indexer_allow_metadata_inventory_take (pos, listname, index, stack, player)
if listname == "filter" then
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
inv:set_stack ("filter", index, nil)
end
end
return 0
end
return stack:get_stack_max ()
end
local function indexer_allow_metadata_inventory_move (pos, from_list, from_index,
to_list, to_index, count, player)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if from_list == "filter" then
if to_list == "filter" then
return 1
end
inv:set_stack ("filter", from_index, nil)
return 0
elseif to_list == "filter" then
local stack = inv:get_stack (from_list, from_index)
if stack and not stack:is_empty () then
inv:set_stack ("filter", to_index, ItemStack (stack:get_name ()))
end
return 0
else
local stack = inv:get_stack (from_list, from_index)
if stack and not stack:is_empty () then
return stack:get_stack_max ()
end
end
end
end
return utils.settings.default_stack_max
end
local function send_stock_message (pos)
if utils.digilines_supported then
local meta = minetest.get_meta (pos)
if meta then
local channel = meta:get_string ("channel")
if channel:len () > 0 then
local msg =
{
action = "inventory",
inventory = get_stock_list (pos)
}
utils.digilines_receptor_send (pos,
utils.digilines_default_rules,
channel,
msg)
end
end
end
end
local function digilines_support ()
if utils.digilines_supported then
return
{
wire =
{
rules = utils.digilines_default_rules,
},
effector =
{
action = function (pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if meta then
local this_channel = meta:get_string ("channel")
if this_channel ~= "" then
if type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if this_channel == channel then
if m[1] == "output" then
if m[2] then
output_items (pos, m[2], tonumber (m[3] or 1) or 1)
end
elseif m[1] == "inventory" then
send_stock_message (pos)
end
end
elseif type (msg) == "table" then
if this_channel == channel then
if msg.action and msg.action == "output" and
type (msg.item) == "string" then
output_items (pos, msg.item, tonumber (msg.count or 1) or 1)
end
end
end
end
end
end,
}
}
end
return nil
end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "output",
connect_sides = { left = 1, right = 1, front = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
store_input_delayed (pos)
return inv:add_item ("input", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("input", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("output")
for i = 1, slots, 1 do
local s = inv:get_stack ("output", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("output")
for i = 1, slots, 1 do
local s = inv:get_stack ("output", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("output", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("output", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local indexer_groups = { choppy = 2 }
if utils.pipeworks_supported then
indexer_groups.tubedevice = 1
indexer_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:storage_indexer", {
description = S("Storage Indexer"),
drawtype = "normal",
tiles = { "lwcomponents_storage_framed.png", "lwcomponents_storage_framed.png",
"lwcomponents_storage_indexer.png", "lwcomponents_storage_indexer.png",
"lwcomponents_storage_indexer.png", "lwcomponents_storage_indexer.png",},
is_ground_content = false,
groups = table.copy (indexer_groups),
sounds = default.node_sound_wood_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = indexer_on_receive_fields,
after_place_node = indexer_after_place_node,
can_dig = indexer_can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = indexer_on_blast,
on_rightclick = indexer_on_rightclick,
on_metadata_inventory_put = indexer_on_metadata_inventory_put,
on_metadata_inventory_move = indexer_on_metadata_inventory_move,
allow_metadata_inventory_take = indexer_allow_metadata_inventory_take,
allow_metadata_inventory_put = indexer_allow_metadata_inventory_put,
allow_metadata_inventory_move = indexer_allow_metadata_inventory_move
})
minetest.register_node("lwcomponents:storage_indexer_locked", {
description = S("Storage Indexer (locked)"),
drawtype = "normal",
tiles = { "lwcomponents_storage_framed.png", "lwcomponents_storage_framed.png",
"lwcomponents_storage_indexer.png", "lwcomponents_storage_indexer.png",
"lwcomponents_storage_indexer.png", "lwcomponents_storage_indexer.png",},
is_ground_content = false,
groups = table.copy (indexer_groups),
sounds = default.node_sound_wood_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = indexer_on_receive_fields,
after_place_node = indexer_after_place_node_locked,
can_dig = indexer_can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = indexer_on_blast,
on_rightclick = indexer_on_rightclick,
on_metadata_inventory_put = indexer_on_metadata_inventory_put,
on_metadata_inventory_move = indexer_on_metadata_inventory_move,
allow_metadata_inventory_take = indexer_allow_metadata_inventory_take,
allow_metadata_inventory_put = indexer_allow_metadata_inventory_put,
allow_metadata_inventory_move = indexer_allow_metadata_inventory_move
})
utils.hopper_add_container({
{"top", "lwcomponents:storage_indexer", "output"}, -- take items from above into hopper below
{"bottom", "lwcomponents:storage_indexer", "input"}, -- insert items below from hopper above
{"side", "lwcomponents:storage_indexer", "input"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:storage_indexer_locked", "output"}, -- take items from above into hopper below
{"bottom", "lwcomponents:storage_indexer_locked", "input"}, -- insert items below from hopper above
{"side", "lwcomponents:storage_indexer_locked", "input"}, -- insert items from hopper at side
})
--