storage_interface = {} storage_interface.storage_nodes = { "default:chest", "default:chest_open", "default:chest_locked", "default:chest_locked_open" } storage_interface.connection_nodes = { "storage_interface:storage_interface", "storage_interface:storage_connector" } if minetest.get_modpath("technic_chests") then table.insert(storage_interface.storage_nodes, "technic:iron_chest") table.insert(storage_interface.storage_nodes, "technic:iron_locked_chest") table.insert(storage_interface.storage_nodes, "technic:copper_chest") table.insert(storage_interface.storage_nodes, "technic:copper_locked_chest") table.insert(storage_interface.storage_nodes, "technic:silver_chest") table.insert(storage_interface.storage_nodes, "technic:silver_locked_chest") table.insert(storage_interface.storage_nodes, "technic:gold_chest") table.insert(storage_interface.storage_nodes, "technic:gold_locked_chest") table.insert(storage_interface.storage_nodes, "technic:mithril_chest") table.insert(storage_interface.storage_nodes, "technic:mithril_locked_chest") end if minetest.get_modpath("connected_chests") then table.insert(storage_interface.storage_nodes, "default:chest_connected_left") table.insert(storage_interface.storage_nodes, "default:chest_locked_connected_left") table.insert(storage_interface.connection_nodes, "default:chest_connected_right") table.insert(storage_interface.connection_nodes, "default:chest_locked_connected_right") end -- helper functions local function table_contains(t, v) for _, i in ipairs(t) do if i == v then return true end end return false end local function table_contains_table(t, v) for _, i in ipairs(t) do local c = 0 local l = 0 for m, k in pairs(i) do l = l+1 if v[m] == k then c = c+1 end end if c == l then return true end end end local function pos_to_string(pos) return pos.x .. "," .. pos.y .. "," .. pos.z end local function create_changed_pos(pos, x, y, z) local new_pos = table.copy(pos) new_pos.x = new_pos.x + x new_pos.y = new_pos.y + y new_pos.z = new_pos.z + z return new_pos end local function get_connected_nodes(pos, player) local p1 = create_changed_pos(pos, 10, 10, 10) local p2 = create_changed_pos(pos, -10, -10, -10) local pos_table = {pos} for _, tpos in ipairs(pos_table) do local check_pos = { create_changed_pos(tpos, 1, 0, 0), create_changed_pos(tpos, -1, 0, 0), create_changed_pos(tpos, 0, 1, 0), create_changed_pos(tpos, 0, -1, 0), create_changed_pos(tpos, 0, 0, 1), create_changed_pos(tpos, 0, 0, -1) } for _, cpos in ipairs(check_pos) do local nodename = minetest.get_node(cpos).name if (table_contains(storage_interface.storage_nodes, nodename) or table_contains(storage_interface.connection_nodes, nodename)) and not table_contains_table(pos_table, cpos) then table.insert(pos_table, cpos) end end end local rc = 0 for k = 1, #pos_table do local kpos = pos_table[k - rc] local owner = minetest.get_meta(kpos):get_string("owner") if table_contains(storage_interface.connection_nodes, minetest.get_node(kpos).name) or (owner ~= "" and owner ~= player and player ~= ".ignore_player") then table.remove(pos_table, k - rc) rc = rc + 1 end end return pos_table end local function match_filter(item_name, filter) if filter == "" then return true end local filter_table = string.split(filter, ",", false, -1) for _, filter_string in ipairs(filter_table) do if filter_string ~= "" then if string.sub(filter_string, 1, 6) == "group:" then if minetest.get_item_group(item_name, string.sub(filter_string, 7)) > 0 then return true end else if string.find(item_name, filter_string) then return true end end end end return false end -- storage_inv functions local function storage_remove_item(pos, stack, match_meta_and_wear, player) local nodes = get_connected_nodes(pos, player) local take_count = stack:get_count(stack) local return_stack = ItemStack(nil) local ostack = stack:get_name() if match_meta_and_wear == true then ostack = stack:peek_item(1):to_string() end for _, tpos in ipairs(nodes) do local meta = minetest.get_meta(tpos) local inv = meta:get_inventory() for listname, list in pairs(inv:get_lists()) do for i, istack in pairs(list) do local oistack = istack:get_name() if match_meta_and_wear == true then oistack = istack:peek_item(1):to_string() end if ostack == oistack then local available_count = istack:get_count() if take_count <= available_count then return_stack:add_item(istack:take_item(take_count)) inv:set_stack(listname, i, istack) return return_stack else return_stack:add_item(istack:take_item(available_count)) inv:set_stack(listname, i, istack) take_count = take_count - available_count end end end end end if not return_stack:is_empty() then return return_stack end return false end -- not perfect local function storage_room_for_item(pos, stack, player) local nodes = get_connected_nodes(pos, player) for _, tpos in ipairs(nodes) do local meta = minetest.get_meta(tpos) local inv = meta:get_inventory() local filter = meta:get_string("storage_interface_filter_string") if match_filter(stack:get_name(), filter) then for listname, _ in pairs(inv:get_lists()) do if inv:room_for_item(listname, stack) then return true end end end end return false end -- not perfect local function storage_add_item(pos, stack, player) local nodes = get_connected_nodes(pos, player) local possible_destinations = {} for _, tpos in ipairs(nodes) do local meta = minetest.get_meta(tpos) local inv = meta:get_inventory() local filter = meta:get_string("storage_interface_filter_string") if match_filter(stack:get_name(), filter) then for listname, _ in pairs(inv:get_lists()) do if inv:room_for_item(listname, stack) then local priority = meta:get_int("storage_interface_priority") or 0 table.insert(possible_destinations, {pos = tpos, listname = listname, priority = priority}) end end end end if not possible_destinations[1] then return stack end table.sort(possible_destinations, function(e1, e2) return e1.priority > e2.priority end) local meta = minetest.get_meta(possible_destinations[1].pos) local inv = meta:get_inventory() return inv:add_item(possible_destinations[1].listname, stack) end -- storage_table functions local function get_storage_table(pos, player) local pos_table = get_connected_nodes(pos, player) local storage_table = {} for _, tpos in ipairs(pos_table) do local meta = minetest.get_meta(tpos) local inv = meta:get_inventory() for list, _ in pairs(inv:get_lists()) do for i = 1, inv:get_size(list), 1 do table.insert(storage_table, { pos = tpos, listname = list, index = i, itemstack = inv:get_stack(list, i), priority = meta:get_int("storage_interface_priority") or 0, filter = meta:get_string("storage_interface_filter_string") or "" }) end end end return storage_table end local function get_oikt_index(itemstack, ignore_wam) local index = "" if ignore_wam == "false" then local itemstack_table = itemstack:to_table() or {} itemstack_table.count = 1 index = ItemStack(itemstack_table):to_string() else index = itemstack:get_name() end return index end local function get_one_item_kind_table(storage_table, ignore_wam) local out_table = {} for _, entry in ipairs(storage_table) do local name = get_oikt_index(entry.itemstack, ignore_wam) out_table[name] = out_table[name] or {} local stack_count = entry.itemstack:get_count() local oikt_count = out_table[name].count or 0 local oc_stack_count = entry.count if oc_stack_count then out_table[name].count = oc_stack_count else out_table[name].count = stack_count + oikt_count end table.insert(out_table[name], entry) end for _, entry_table in pairs(out_table) do table.sort(entry_table, function(entry1, entry2) return entry1.itemstack:get_count() > entry2.itemstack:get_count() end) end return out_table end local function sort_storage_table(storage_table, mode, ignore_wam) if mode == "count" then local oikt = get_one_item_kind_table(storage_table, ignore_wam) for _, e in ipairs(storage_table) do local name = get_oikt_index(e.itemstack, ignore_wam) if not e.count then if oikt[name] then e.count = oikt[name].count else e.count = 0 end end end local ioikt = {} for _, ioikt_e in pairs(oikt) do table.insert(ioikt, ioikt_e) end table.sort(ioikt, function(entry1, entry2) local p1 = entry1.count local p2 = entry2.count if p1 == p2 then local itemstack1 = entry1[1].itemstack local itemstack2 = entry2[1].itemstack local name1 = itemstack1:get_name() local name2 = itemstack2:get_name() if name1 == name2 then p2 = itemstack1:get_wear() p1 = itemstack2:get_wear() else local nst = {} nst[1] = name1 nst[2] = name2 table.sort(nst) if nst[1] == name1 and nst[2] == name2 then return true else return false end end end return p1 > p2 end) storage_table = {} for _, entry_table in ipairs(ioikt) do for _, entry in ipairs(entry_table) do table.insert(storage_table, entry) end end else table.sort(storage_table, function(entry1, entry2) local p1 = 0 local p2 = 0 local itemstack1 = entry1.itemstack local itemstack2 = entry2.itemstack local name1 = itemstack1:get_name() local name2 = itemstack2:get_name() if name1 == name2 then p1 = itemstack2:get_count() p2 = itemstack1:get_count() if p1 == p2 then p1 = itemstack1:get_wear() p2 = itemstack2:get_wear() end else local nst = {} nst[1] = name1 nst[2] = name2 table.sort(nst) if nst[1] == name1 and nst[2] == name2 then return true else return false end end return p1 < p2 end) end return storage_table end -- storage_interface functions local function storage_table_to_formspec(storage_table, xpos, ypos, l, h, page) local d_table = {} local formspec = "" local lc = 0 local hc = 1 for i = 1, l * h, 1 do d_table[i] = storage_table[i + (page-1) * l * h] end for _, entry in ipairs(d_table) do lc = lc + 1 if lc > l then lc = 1 hc = hc + 1 if hc > h then break end end local string_pos = pos_to_string(entry.pos) formspec = formspec .. "list[nodemeta:".. string_pos ..";".. entry["listname"] ..";".. xpos + lc - 1 ..",".. hc + ypos - 1 ..";".. "1,1;".. entry.index -1 .."]" .. "listring[nodemeta:" .. string_pos .. ";".. entry["listname"] .."]" .. "listring[current_player;main]".. "listring[current_player;nothing]" end return formspec end local function set_fake_inv(oikt, xpos, ypos, l, h, page, pos, sorting_mode, ignore_wam) local storage_table = {} for i, en in pairs(oikt) do en[1].count = en.count table.insert(storage_table, en[1]) end storage_table = sort_storage_table(storage_table, sorting_mode, ignore_wam) local d_table = {} for i = 1, l * h, 1 do d_table[i] = storage_table[i + (page-1) * l * h] end local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local formspec = "" local lc = 0 local hc = 1 for i, entry in ipairs(d_table) do inv:set_stack("fake_inv", i, entry.itemstack) local count = entry.count local itemstack = inv:get_stack("fake_inv", i) local max_scount = itemstack:get_stack_max() if ignore_wam == "true" then itemstack:get_meta():from_table(nil) itemstack:set_wear(0) end if count > max_scount then itemstack:set_count(max_scount) else itemstack:set_count(count) end inv:set_stack("fake_inv", i, itemstack) lc = lc + 1 if lc > l then lc = 1 hc = hc + 1 if hc > h then break end end local string_pos = pos_to_string(pos) formspec = formspec .. "label[".. xpos + lc - 0.9 ..",".. (hc + ypos - 0.4) * 1.4 ..";".. entry.count .."]" .. "list[nodemeta:".. string_pos ..";".. "fake_inv;".. xpos + lc - 1 ..",".. (hc + ypos - 1) * 1.4 ..";".. "1,1;".. lc - 1 + (hc - 1) * l .."]" .. "listring[nodemeta:" .. string_pos .. ";fake_inv]" .. "listring[current_player;main]".. "listring[current_player;nothing]" end return formspec end local function get_buttons(oikt, xpos, ypos, l, h, page, pos, sorting_mode, ignore_wam) local ignore_wam = true local storage_table = {} for i, en in pairs(oikt) do en[1].count = en.count table.insert(storage_table, en[1]) end storage_table = sort_storage_table(storage_table, sorting_mode, ignore_wam) local d_table = {} for i = 1, l * h, 1 do d_table[i] = storage_table[i + (page-1) * l * h] end local formspec = "" local lc = 0 local hc = 1 for i, entry in ipairs(d_table) do lc = lc + 1 if lc > l then lc = 1 hc = hc + 1 if hc > h then break end end local itemstack_name = entry.itemstack:get_name() local string_pos = pos_to_string(pos) formspec = formspec .. "label[".. xpos + lc - 0.9 ..",".. (hc + ypos - 0.4) * 1.4 ..";".. entry.count .."]" .. "item_image_button[".. xpos + lc - 1 ..",".. (hc + ypos - 1) * 1.4 .. ";1,1;".. itemstack_name ..";".. "storage_button_" .. itemstack_name ..";]" end return formspec end local function update_formspec(player, pos) local meta = minetest.get_meta(pos) local storage_table = get_storage_table(pos, player) local page = meta:get_int("page") or 1 local max_page = 1 local mode = meta:get_string("mode") or "actual_inv" local capacity = #storage_table local empty_slots = 0 for i = 1, #storage_table, 1 do local stitemstack = storage_table[i - empty_slots].itemstack if stitemstack:is_empty() or stitemstack:get_name() == "" then table.remove(storage_table, i - empty_slots) empty_slots = empty_slots + 1 end end local sorting_mode = meta:get_string("sorting_mode") or "name" local sorting_modedis = "" if sorting_mode == "name" then sorting_modedis = "Name" elseif sorting_mode == "count" then sorting_modedis = "Count" end local ignore_wam = meta:get_string("ignore_wam") or "true" if mode == "buttons" then ignore_wam = "true" end local ignore_wamdis = "" if ignore_wam == "true" then ignore_wamdis = "True" elseif ignore_wam == "false" then ignore_wamdis = "False" end local search_field = meta:get_string("search_field") or "" do local kept_table = {} for si, se in ipairs(storage_table) do kept_table[si] = match_filter(se.itemstack:get_name(), search_field) end local rc = 0 for i = 1, #storage_table, 1 do if kept_table[i] ~= true then table.remove(storage_table, i - rc) rc = rc + 1 end end end storage_table = sort_storage_table(storage_table, sorting_mode, ignore_wam) local shown = meta:get_string("shown") or "everything" local showndis = shown if shown == "everything" then showndis = "Everything" elseif shown == "nodes" then showndis = "Nodes" local rc = 0 for i = 1, #storage_table, 1 do if not minetest.registered_nodes[storage_table[i - rc].itemstack:get_name()] then table.remove(storage_table, i - rc) rc = rc + 1 end end elseif shown == "craftitems" then showndis = "Craftitems" local rc = 0 for i = 1, #storage_table, 1 do if not minetest.registered_craftitems[storage_table[i - rc].itemstack:get_name()] then table.remove(storage_table, i - rc) rc = rc + 1 end end elseif shown == "tools" then showndis = "Tools" local rc = 0 for i = 1, #storage_table, 1 do if not minetest.registered_tools[storage_table[i - rc].itemstack:get_name()] then table.remove(storage_table, i - rc) rc = rc + 1 end end end local modedis = mode local st_form = "" if mode == "actual_inv" then modedis = "Actual Inventory" max_page = math.ceil(#storage_table/(15*7)) if max_page < 1 then max_page = 1 end if page > max_page then page = max_page meta:set_int("page", page) end if page < 1 then page = 1 meta:set_int("page", page) end st_form = storage_table_to_formspec(storage_table, 0, 0, 15, 7, page) elseif mode == "fake_inv" then modedis = "Fake Inventory" local oikt = get_one_item_kind_table(storage_table, ignore_wam) local oiktl = 0 for _, _ in pairs(oikt) do oiktl = oiktl + 1 end max_page = math.ceil(oiktl/(15*5)) if max_page < 1 then max_page = 1 end if page > max_page then page = max_page meta:set_int("page", page) end if page < 1 then page = 1 meta:set_int("page", page) end st_form = set_fake_inv(oikt, 0, 0, 15, 5, page, pos, sorting_mode, ignore_wam) elseif mode == "buttons" then modedis = "Buttons" local oikt = get_one_item_kind_table(storage_table, ignore_wam) local oiktl = 0 for _, _ in pairs(oikt) do oiktl = oiktl + 1 end max_page = math.ceil(oiktl/(15*5)) if max_page < 1 then max_page = 1 end if page > max_page then page = max_page meta:set_int("page", page) end if page < 1 then page = 1 meta:set_int("page", page) end st_form = get_buttons(oikt, 0, 0, 15, 5, page, pos, sorting_mode, ignore_wam) end local rb_mode = meta:get_string("rb_mode") or "settings" local rb_formspec = "" if rb_mode == "crafting" then rb_formspec = "label[13,7.2;Crafting]" .. "list[current_player;craft;12,9.2;3,3;]" .. "list[current_player;craftpreview;13,8;1,1;]" .. "listring[current_player;craft]" .. "listring[current_player;main]" elseif rb_mode == "settings" then local dbuttons = "label[11.6,10.3;Ignore meta and wear: ".. ignore_wamdis .."]" .. "button[14,10.1;1,1;change_ignore_wam;Change]" if mode == "buttons" then local items_on_click = meta:get_string("items_on_click") or "one_stack" local items_on_clickdis = items_on_click if items_on_click == "one_stack" then items_on_clickdis = "One stack" elseif items_on_click == "all" then items_on_clickdis = "All" elseif items_on_click == "one_item" then items_on_clickdis = "One item" end dbuttons = "label[11.6,10.3;Items on click: ".. items_on_clickdis .."]" .. "button[14,10.1;1,1;change_items_on_click;Change]" end rb_formspec = "label[13,7.2;Settings]" .. "label[11.6,8.2;Mode: ".. modedis .."]" .. "button[14,8;1,1;change_mode;Change]" .. "label[11.6,8.9;Shown: ".. showndis .."]" .. "button[14,8.7;1,1;change_shown;Change]" .. "label[11.6,9.6;Sorting Mode: ".. sorting_modedis .."]" .. "button[14,9.4;1,1;change_sorting_mode;Change]" .. dbuttons .. "field[11.9,11.4;2,1;infotext;Infotext;".. meta:get_string("infotext") .."]" .. "button[14,11.1;1,1;set_infotext;Set]" .. "field_close_on_enter[infotext;false]" end local spos = pos_to_string(pos) local formspec = "size[15,12]" .. default.gui_bg .. default.gui_bg_img .. default.gui_slots .. "list[nodemeta:" .. spos .. ";input;0,10.2;3,2;]" .. "label[0,9.7;Input:]" .. "listring[current_player;main]" .. "listring[nodemeta:" .. spos .. ";input]" .. "listring[current_player;nothing]" .. st_form .. "label[0,7.2;Page: ".. page .." of ".. max_page .."]" .. "label[0,7.9;Capacity: ".. capacity - empty_slots .." of ".. capacity .."]" .. "button[3.1,7;0.9,1;first;|<--]".. "button[3.8,7;0.9,1;threeback;<<--]".. "button[4.5,7;0.9,1;back;<--]".. "button[5.2,7;0.9,1;next;-->]".. "button[5.9,7;0.9,1;threenext;-->>]".. "button[6.6,7;0.9,1;last;-->|]".. "button[10.5,7;1,1;search;Search]".. "button[11.4,7;1,1;reset;Reset]".. "field[7.8,7.3;3,1;search_field;;".. search_field .."]" .. "field_close_on_enter[search_field;false]".. "button[0.5,8.6;2,1;sort_storage;Sort storage]".. "list[current_player;main;3.5,8;8,1;]" .. "list[current_player;main;3.5,9.2;8,3;8]" .. "button[14,7;1,1;change_rb_mode;Change]".. rb_formspec .. default.get_hotbar_bg(3.5,8) minetest.show_formspec(player, "storage_interface:storage_interface", formspec) end local function sort_storage(pos, player) local meta = minetest.get_meta(pos) local storage_table = get_storage_table(pos, player) local sorted_storage_table = {} for _, ste in ipairs(storage_table) do local itemstack = ste.itemstack local item_name = itemstack:get_name() for _, sste in ipairs(sorted_storage_table) do local new_itemstack = sste.itemstack if new_itemstack:get_name() == item_name then itemstack = new_itemstack:add_item(itemstack) end if itemstack:is_empty() then break end end if not itemstack:is_empty() then table.insert(sorted_storage_table, ste) end end sorted_storage_table = sort_storage_table(sorted_storage_table, meta:get_string("sorting_mode"), "false") for i, e in ipairs(sorted_storage_table) do for id, ed in ipairs(storage_table) do if match_filter(e.itemstack:get_name(), ed.filter) and not storage_table[id].used then sorted_storage_table[i].can_store = true storage_table[id].used = true break end end if not sorted_storage_table[i].can_store then minetest.chat_send_player(player, "Your storage is to small to sort it.") return end end for _, entry in ipairs(storage_table) do local inv = minetest.get_meta(entry.pos):get_inventory() inv:set_stack(entry.listname, entry.index, "") end for _, entry in ipairs(sorted_storage_table) do storage_add_item(pos, entry.itemstack, player) end end local formspec_pos_si = {} minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "storage_interface:storage_interface" then return end local name = player:get_player_name() local pos = formspec_pos_si[name] if not pos then return end local meta = minetest.get_meta(pos) local page = meta:get_int("page") if fields.first then meta:set_int("page", 1) elseif fields.last then meta:set_int("page", 1000) elseif fields.threenext then meta:set_int("page", page + 3) elseif fields.threeback then meta:set_int("page", page - 3) elseif fields.next then meta:set_int("page", page + 1) elseif fields.back then meta:set_int("page", page - 1) elseif fields.change_mode then local mode = meta:get_string("mode") if mode == "actual_inv" then meta:set_string("mode", "fake_inv") elseif mode == "fake_inv" then meta:set_string("mode", "buttons") elseif mode == "buttons" then meta:set_string("mode", "actual_inv") end elseif fields.change_shown then local shown = meta:get_string("shown") if shown == "everything" then meta:set_string("shown", "nodes") elseif shown == "nodes" then meta:set_string("shown", "craftitems") elseif shown == "craftitems" then meta:set_string("shown", "tools") elseif shown == "tools" then meta:set_string("shown", "everything") end elseif fields.change_rb_mode then local rb_mode = meta:get_string("rb_mode") if rb_mode == "crafting" then meta:set_string("rb_mode", "settings") elseif rb_mode == "settings" then meta:set_string("rb_mode", "crafting") end elseif fields.change_sorting_mode then local sorting_mode = meta:get_string("sorting_mode") if sorting_mode == "name" then meta:set_string("sorting_mode", "count") elseif sorting_mode == "count" then meta:set_string("sorting_mode", "name") end elseif fields.change_ignore_wam then local ignore_wam = meta:get_string("ignore_wam") if ignore_wam == "true" then meta:set_string("ignore_wam", "false") elseif ignore_wam == "false" then meta:set_string("ignore_wam", "true") end elseif fields.change_items_on_click then local items_on_click = meta:get_string("items_on_click") if items_on_click == "one_stack" then meta:set_string("items_on_click", "one_item") elseif items_on_click == "one_item" then meta:set_string("items_on_click", "all") elseif items_on_click == "all" then meta:set_string("items_on_click", "one_stack") end elseif fields.set_infotext or fields.key_enter_field == "infotext" then meta:set_string("infotext", fields.infotext) elseif fields.search or fields.key_enter_field == "search_field" then meta:set_string("search_field", fields.search_field) elseif fields.reset then meta:set_string("search_field", "") elseif fields.sort_storage then sort_storage(pos, name) elseif meta:get_string("mode") == "buttons" then for fieldname, b in pairs(fields) do if b and string.sub(fieldname, 1, 15) == "storage_button_" then local playerinv = player:get_inventory() local bitemstack = ItemStack(string.sub(fieldname, 16)) local items_on_click = meta:get_string("items_on_click") or "one_stack" if items_on_click == "one_stack" then bitemstack:set_count(bitemstack:get_stack_max()) if playerinv:room_for_item("main", bitemstack) then local re_stack = storage_remove_item(pos, bitemstack, false, name) if re_stack then playerinv:add_item("main", re_stack) end end elseif items_on_click == "one_item" then bitemstack:set_count(1) if playerinv:room_for_item("main", bitemstack) then local re_stack = storage_remove_item(pos, bitemstack, false, name) if re_stack then playerinv:add_item("main", re_stack) end end elseif items_on_click == "all" then bitemstack:set_count(bitemstack:get_stack_max()) for i = 1, 4*8 do local new_bitemstack = ItemStack(bitemstack:to_string()) if playerinv:room_for_item("main", bitemstack) then local re_stack = storage_remove_item(pos, bitemstack, false, name) if re_stack then playerinv:add_item("main", re_stack) else break end else break end end end break end end end if fields.quit then return true else update_formspec(name, pos) end end) local si_node_def = { description = "Storage Interface", tiles = {"default_chest_top.png", "default_chest_top.png", "default_chest_top.png","default_chest_top.png", "default_chest_top.png", "default_chest_top.png^storage_interface_front.png"}, paramtype2 = "facedir", groups = {choppy = 2, oddly_breakable_by_hand = 2}, legacy_facedir_simple = true, is_ground_content = false, sounds = default.node_sound_wood_defaults(), on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_int("page", 1) meta:set_string("mode", "actual_inv") meta:set_string("shown", "everything") meta:set_string("rb_mode", "settings") meta:set_string("sorting_mode", "name") meta:set_string("search_field", "") meta:set_string("ignore_wam", "false") meta:set_string("infotext", "Storage Interface") meta:set_string("items_on_click", "one_stack") local inv = meta:get_inventory() inv:set_size("input", 3*2) inv:set_size("fake_inv", 15*7) end, can_dig = function(pos,player) local meta = minetest.get_meta(pos); local inv = meta:get_inventory() return inv:is_empty("input") end, allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) return 0 end, allow_metadata_inventory_take = function(pos, listname, index, stack, player) if listname == "fake_inv" then -- trigger only one time local oldc_taken = player:get_attribute("storage_interface_taken") if oldc_taken then return oldc_taken end local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local match_meta_and_wear = true if meta:get_string("ignore_wam") == "true" then match_meta_and_wear = false end local taken_stack = storage_remove_item(pos, stack, match_meta_and_wear, player:get_player_name()) if not taken_stack then return 0 end local count = taken_stack:get_count() inv:set_stack("fake_inv", index, taken_stack) player:set_attribute("storage_interface_taken", count) return count elseif listname == "input" then return stack:get_count() end return 0 end, on_metadata_inventory_take = function(pos, listname, index, stack, player) if listname == "fake_inv" then player:set_attribute("storage_interface_taken", nil) -- Save items if a right-click swap has happened local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local new_stack = inv:get_stack(listname, index) if not new_stack:item_fits(stack) then local inv = player:get_inventory() local overflow = inv:add_item("main", new_stack) if overflow and not overflow:is_empty() then minetest.item_drop(overflow, player, player:getpos()) end end end update_formspec(player:get_player_name(), pos) end, allow_metadata_inventory_put = function(pos, listname, index, stack, player) if listname == "input" then if storage_add_item(pos, stack, player:get_player_name()):is_empty() then update_formspec(player:get_player_name(), pos) return(-1) end end return 0 end, on_rightclick = function(pos, node, clicker) local name = clicker:get_player_name() formspec_pos_si[name] = pos update_formspec(name, pos) end, on_blast = function(pos) local drops = {} default.get_inventory_drops(pos, "input", drops) drops[#drops+1] = "storage_interface:storage_interface" minetest.remove_node(pos) return drops end } if minetest.get_modpath("pipeworks") then local tube_entry = "^pipeworks_tube_connection_wooden.png" si_node_def.tiles[1] = si_node_def.tiles[1] .. tube_entry si_node_def.tiles[2] = si_node_def.tiles[2] .. tube_entry si_node_def.tiles[3] = si_node_def.tiles[3] .. tube_entry si_node_def.tiles[4] = si_node_def.tiles[4] .. tube_entry si_node_def.tiles[5] = si_node_def.tiles[5] .. tube_entry .. "^[transformFX" si_node_def.groups.tubedevice = 1 si_node_def.groups.tubedevice_receiver = 1 si_node_def.after_place_node = pipeworks.after_place si_node_def.after_dig_node = pipeworks.after_dig si_node_def.tube = { insert_object = function(pos, node, stack, direction) return storage_add_item(pos, stack, ".ignore_player") end, can_insert = function(pos, node, stack, direction) return storage_room_for_item(pos, stack, ".ignore_player") end, input_inventory = "input", connect_sides = {left = 1, right = 1, back = 1, bottom = 1, top = 1}, } end -- sfit functions local formspec_pos_sfit = {} local sfit_local_filter_string = {} local function use_sfit(player, pos) local player_name = player:get_player_name() local meta = minetest.get_meta(pos) local old_filter_string = sfit_local_filter_string[player_name] or meta:get_string("storage_interface_filter_string") or "" sfit_local_filter_string[player_name] = old_filter_string local old_priority = meta:get_int("storage_interface_priority") or 0 formspec_pos_sfit[player_name] = pos minetest.create_detached_inventory("storage_interface:sfit", { allow_put = function(inv, listname, index, stack, player) local player_name = player:get_player_name() local filter_string = sfit_local_filter_string[player_name] local stack_name = stack:get_name() if (not filter_string) or filter_string == "" then filter_string = stack_name else local filter_string_table = string.split(filter_string, ",", false, -1) for _, filter_stringi in ipairs(filter_string_table) do if filter_stringi == stack_name then use_sfit(player, formspec_pos_sfit[player_name]) return 0 end end filter_string = filter_string ..",".. stack:get_name() end sfit_local_filter_string[player_name] = filter_string use_sfit(player, formspec_pos_sfit[player_name]) return 0 end }, player_name) local inv = minetest.get_inventory({type="detached", name="storage_interface:sfit"}) inv:set_size("item_adder", 1) local formspec = "size[8,6]" .. default.gui_bg .. default.gui_bg_img .. default.gui_slots .. "list[detached:storage_interface:sfit;item_adder;0,0.5;1,1]" .. "list[current_player;main;0,1.85;8,1;]" .. "list[current_player;main;0,3.08;8,3;8]" .. "listring[detached:storage_interface:sfit;item_adder]" .. "listring[current_player;main]" .. "field[1.3,0.8;5,1;sorting_filter_string;Sorting Filter String ();".. old_filter_string .."]" .. "field[6.3,0.8;1,1;priority;Priority;".. old_priority .."]" .. "button[7,0.5;1,1;set_filter_string;Set]".. default.get_hotbar_bg(0,1.85) minetest.show_formspec(player_name, "storage_interface:sfit", formspec) end minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "storage_interface:sfit" then return end local player_name = player:get_player_name() local pos = formspec_pos_sfit[player_name] if not pos then return end local meta = minetest.get_meta(pos) if fields.set_filter_string or fields.key_enter_field == "sorting_filter_string" or fields.key_enter_field == "priority" then sfit_local_filter_string[player_name] = nil meta:set_string("storage_interface_filter_string", fields.sorting_filter_string) local priority = tonumber(fields.priority) or 0 meta:set_int("storage_interface_priority", priority) end if fields.quit then return true else use_sfit(player, pos) end end) -- item registration minetest.register_node("storage_interface:storage_interface", si_node_def) minetest.register_node("storage_interface:storage_connector", { description = "Storage Connector", tiles = {"default_chest_top.png^storage_interface_connector.png"}, groups = {choppy = 2, oddly_breakable_by_hand = 2, wood = 1}, is_ground_content = false, sounds = default.node_sound_wood_defaults(), }) minetest.register_craftitem("storage_interface:sfit", { description = "Sorting Filter Inscribing Tool", inventory_image = "storage_interface_sfit.png", stack_max = 1, on_use = function(itemstack, user, pointed_thing) if not (pointed_thing and pointed_thing.type == "node" and user) then return end local pos = pointed_thing.under local player_name = user:get_player_name() local node = minetest.get_node(pos).name local meta = minetest.get_meta(pos) local owner = meta:get_string("owner") or "" if (owner ~= "" and owner ~= player_name) or minetest.is_protected(pos, player_name) then minetest.chat_send_player(player_name, "You do not own this node.") return end if table_contains(storage_interface.storage_nodes, node) then sfit_local_filter_string[player_name] = nil use_sfit(user, pos) else minetest.chat_send_player(player_name, "You can't inscribe this node.") end return end, }) -- craft registration minetest.register_craft({ output = 'storage_interface:storage_interface', recipe = { {'default:steel_ingot', 'default:glass', 'default:steel_ingot'}, {'group:wood', 'default:mese', 'group:wood'}, {'group:wood', 'default:chest', 'group:wood'}, } }) minetest.register_craft({ output = 'storage_interface:storage_connector 18', recipe = { {'group:stick', '', 'group:stick'}, {'default:chest', 'group:wood', 'default:chest'}, {'group:stick', '', 'group:stick'}, } }) minetest.register_craft({ output = 'storage_interface:sfit', recipe = { {'', 'default:mese_crystal_fragment', 'group:dye'}, {'default:steel_ingot', 'default:chest', 'default:mese_crystal_fragment'}, {'group:stick', 'default:steel_ingot', ''}, } })