Compare commits

..

2 Commits

Author SHA1 Message Date
RealBadAngel
763eca424e Waypoints update 2014-01-31 00:14:18 +01:00
RealBadAngel
3306676910 Initial waypoints tab upload 2014-01-27 12:15:25 +01:00
96 changed files with 966 additions and 3978 deletions

@ -1,11 +0,0 @@
on: [push, pull_request]
name: Check & Release
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: lint
uses: Roang-zero1/factorio-mod-luacheck@master
with:
luacheckrc_url: https://raw.githubusercontent.com/minetest-mods/unified_inventory/master/.luacheckrc

2
.gitignore vendored

@ -1,2 +0,0 @@
*~

@ -1,21 +0,0 @@
unused_args = false
allow_defined_top = true
max_line_length = 999
globals = {
"unified_inventory",
}
read_globals = {
string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn"}},
"minetest", "vector",
"ItemStack", "datastorage",
"hb",
"doors",
}
files["callbacks.lua"].ignore = { "player", "draw_lite_mode" }
files["bags.lua"].ignore = { "player" }

@ -1,19 +0,0 @@
Unified Inventory for Minetest
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Contact information:
Examine a git patch to get the contributor's email address.

106
README.md

@ -1,104 +1,6 @@
# Unified Inventory
unified_inventory
=================
[![](https://github.com/minetest-mods/unified_inventory/workflows/Check%20&%20Release/badge.svg)](https://github.com/minetest-mods/unified_inventory/actions)
Replacement for Minetest creative inventory.
![Screenshot](screenshot.png)
Unified Inventory replaces the default survival and creative inventory.
## Features
* Node, item and tool browser
* Crafting guide
* Can copy the recipe to the crafting grid
* Recipe search function by ingredients
* Up to four bags with up to 24 slots each
* Home function to teleport
* Trash slot and refill slot for creative
* Waypoints to keep track of important locations
* Lite mode: reduces the item browser width
* `minetest.conf` setting `unified_inventory_lite = true`
* Mod API for modders: see [mod_api.txt](doc/mod_api.txt)
* Setting-determinated features: see [settingtypes.txt](settingtypes.txt)
## Requirements
* Minetest 5.4.0+
* Mod `default` for category filters (contained in Minetest Game)
* Mod `farming` for craftable bags (contained in Minetest Game)
* For waypoint migration: `datastorage`
# Licenses
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
Copyright (C) 2012-? Various minetest-mods contributors
## Code
GNU LGPLv2+, see [license notice](LICENSE.txt)
## Textures
VanessaE: (CC-BY-4.0)
* `ui_group.png`
Tango Project: (Public Domain, CC-BY-4.0)
* [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg)
* [`ui_doubleleft_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg)
* [`ui_doubleright_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg)
* [`ui_left_icon.png` / `ui_right_icon.png`](http://commons.wikimedia.org/wiki/File:Media-playback-start.svg)
* [`ui_skip_backward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg)
* [`ui_skip_forward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg)
From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html)
* [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.html)
* [`bags_large.png` / `ui_bags_icon.png`](http://www.clker.com/clipart-backpack-green-brown.html)
* `ui_trash_icon.png`: <http://www.clker.com/clipart-29090.html> and <http://www.clker.com/clipart-trash.html>
* [`ui_search_icon.png`](http://www.clker.com/clipart-24887.html)
* [`ui_off_icon.png` / `ui_on_icon.png`](http://www.clker.com/clipart-on-off-switches.html)
* [`ui_waypoints_icon.png`](http://www.clker.com/clipart-map-pin-red.html)
* [`ui_circular_arrows_icon.png`](http://www.clker.com/clipart-circular-arrow-pattern.html)
* [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.html)
* [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html)
Everaldo Coelho (YellowIcon) (LGPL v2.1+):
* [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png)
Gregory H. Revera: (CC-BY-SA 3.0)
* [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg)
Thomas Bresson: (CC-BY 3.0)
* [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg)
Fibonacci: (Public domain, CC-BY 4.0)
* [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg)
Gregory Maxwell: (Public domain, CC-BY 4.0)
* [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg)
Adrien Facélina: (LGPL v2.1+)
* [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg)
Other files from Wikimedia Commons:
* [`ui_gohome_icon.png` / `ui_home_icon.png` / `ui_sethome_icon.png`](http://commons.wikimedia.org/wiki/File:Home_256x256.png) (GPL v2+)
RealBadAngel: (CC-BY-4.0)
* Everything else.
Unified Inventory replaces the survival and creative inventory; it also functions as a crafting guide.

419
api.lua

@ -1,417 +1,102 @@
local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
local ui = unified_inventory
-- Create detached creative inventory after loading all mods
minetest.after(0.01, function()
local rev_aliases = {}
for source, target in pairs(minetest.registered_aliases) do
if not rev_aliases[target] then rev_aliases[target] = {} end
table.insert(rev_aliases[target], source)
end
ui.items_list = {}
unified_inventory.items_list = {}
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or
def.groups.not_in_creative_inventory == 0) and
def.description and def.description ~= "" then
table.insert(ui.items_list, name)
local all_names = rev_aliases[name] or {}
table.insert(all_names, name)
for _, player_name in ipairs(all_names) do
local recipes = minetest.get_all_craft_recipes(player_name)
if recipes then
for _, recipe in ipairs(recipes) do
local unknowns
for _,chk in pairs(recipe.items) do
local groupchk = string.find(chk, "group:")
if (not groupchk and not minetest.registered_items[chk])
or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item)
or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then
unknowns = true
end
end
if not unknowns then
ui.register_craft(recipe)
end
end
end
end
end
end
table.sort(ui.items_list)
ui.items_list_size = #ui.items_list
print("Unified Inventory. Inventory size: "..ui.items_list_size)
for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name]
-- Simple drops
if type(def.drop) == "string" then
local dstack = ItemStack(def.drop)
if not dstack:is_empty() and dstack:get_name() ~= name then
ui.register_craft({
type = "digging",
items = {name},
output = def.drop,
width = 0,
})
end
-- Complex drops. Yes, it's really complex!
elseif type(def.drop) == "table" then
--[[ Extract single items from the table and save them into dedicated tables
to register them later, in order to avoid duplicates. These tables counts
the total number of guaranteed drops and drops by chance (maybes) for each item.
For maybes, the final count is the theoretical maximum number of items, not
neccessarily the actual drop count. ]]
local drop_guaranteed = {}
local drop_maybe = {}
-- This is for catching an obscure corner case: If the top items table has
-- only items with rarity = 1, but max_items is set, then only the first
-- max_items will be part of the drop, any later entries are logically
-- impossible, so this variable is for keeping track of this
local max_items_left = def.drop.max_items
-- For checking whether we still encountered only guaranteed only so far;
-- for the first “maybe” item it will become false which will cause ALL
-- later items to be considered “maybes”.
-- A common idiom is:
-- { max_items 1, { items = {
-- { items={"example:1"}, rarity = 5 },
-- { items={"example:2"}, rarity = 1 }, }}}
-- example:2 must be considered a “maybe” because max_items is set and it
-- appears after a “maybe”
local max_start = true
-- Let's iterate through the items madness!
-- Handle invalid drop entries gracefully.
local drop_items = def.drop.items or { }
for i=1,#drop_items do
if max_items_left ~= nil and max_items_left <= 0 then break end
local itit = drop_items[i]
for j=1,#itit.items do
local dstack = ItemStack(itit.items[j])
if not dstack:is_empty() and dstack:get_name() ~= name then
local dname = dstack:get_name()
local dcount = dstack:get_count()
-- Guaranteed drops AND we are not yet in “maybe mode”
if #itit.items == 1 and itit.rarity == 1 and max_start then
if drop_guaranteed[dname] == nil then
drop_guaranteed[dname] = 0
end
drop_guaranteed[dname] = drop_guaranteed[dname] + dcount
if max_items_left ~= nil then
max_items_left = max_items_left - 1
if max_items_left <= 0 then break end
end
-- Drop was a “maybe”
else
if max_items_left ~= nil then max_start = false end
if drop_maybe[dname] == nil then
drop_maybe[dname] = 0
end
drop_maybe[dname] = drop_maybe[dname] + dcount
end
end
end
end
for itemstring, count in pairs(drop_guaranteed) do
ui.register_craft({
type = "digging",
items = {name},
output = itemstring .. " " .. count,
width = 0,
})
end
for itemstring, count in pairs(drop_maybe) do
ui.register_craft({
type = "digging_chance",
items = {name},
output = itemstring .. " " .. count,
width = 0,
})
end
end
end
-- Step 1: group-indexed lookup table for items
local spec_matcher = {}
for _, name in ipairs(ui.items_list) do
-- we only need to care about groups, exact items are handled separately
for group, value in pairs(minetest.registered_items[name].groups) do
if value and value ~= 0 then
if not spec_matcher[group] then
spec_matcher[group] = {}
end
spec_matcher[group][name] = true
end
end
end
-- Step 2: Find all matching items for the given spec (groups)
local function get_matching_spec_items(specname)
if specname:sub(1,6) ~= "group:" then
return { [specname] = true }
end
local accepted = {}
for i, group in ipairs(specname:sub(7):split(",")) do
if i == 1 then
-- First step: Copy all possible item names in this group
for name, _ in pairs(spec_matcher[group] or {}) do
accepted[name] = true
end
table.insert(unified_inventory.items_list, name)
local recipes = minetest.get_all_craft_recipes(name)
if recipes then
unified_inventory.crafts_table[name] = recipes
else
-- Perform filtering
if spec_matcher[group] then
for name, _ in pairs(accepted) do
accepted[name] = spec_matcher[group][name]
end
else
-- No matching items
return {}
end
end
end
return accepted
end
for _, recipes in pairs(ui.crafts_for.recipe) do
-- List of crafts that return this item string (variable "_")
for _, recipe in ipairs(recipes) do
local ingredient_items = {}
for _, spec in pairs(recipe.items) do
-- Get items that fit into this spec (group or item name)
local specname = ItemStack(spec):get_name()
for item_name, _ in pairs(get_matching_spec_items(specname)) do
ingredient_items[item_name] = true
end
end
for name, _ in pairs(ingredient_items) do
if not ui.crafts_for.usage[name] then
ui.crafts_for.usage[name] = {}
end
table.insert(ui.crafts_for.usage[name], recipe)
unified_inventory.crafts_table[name] = {}
end
end
end
for _, callback in ipairs(ui.initialized_callbacks) do
callback()
end
table.sort(unified_inventory.items_list)
unified_inventory.items_list_size = #unified_inventory.items_list
print("Unified Inventory. inventory size: "..unified_inventory.items_list_size)
end)
-- load_home
local function load_home()
local input = io.open(ui.home_filename, "r")
if not input then
ui.home_pos = {}
return
local input = io.open(unified_inventory.home_filename, "r")
if input then
while true do
local x = input:read("*n")
if x == nil then
break
end
local y = input:read("*n")
local z = input:read("*n")
local name = input:read("*l")
unified_inventory.home_pos[name:sub(2)] = {x = x, y = y, z = z}
end
io.close(input)
else
unified_inventory.home_pos = {}
end
while true do
local x = input:read("*n")
if not x then break end
local y = input:read("*n")
local z = input:read("*n")
local name = input:read("*l")
ui.home_pos[name:sub(2)] = {x = x, y = y, z = z}
end
io.close(input)
end
load_home()
function ui.set_home(player, pos)
function unified_inventory.set_home(player, pos)
local player_name = player:get_player_name()
ui.home_pos[player_name] = vector.round(pos)
unified_inventory.home_pos[player_name] = pos
-- save the home data from the table to the file
local output = io.open(ui.home_filename, "w")
if not output then
minetest.log("warning", "[unified_inventory] Failed to save file: "
.. ui.home_filename)
return
end
for k, v in pairs(ui.home_pos) do
output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n")
local output = io.open(unified_inventory.home_filename, "w")
for k, v in pairs(unified_inventory.home_pos) do
if v ~= nil then
output:write(math.floor(v.x).." "
..math.floor(v.y).." "
..math.floor(v.z).." "
..k.."\n")
end
end
io.close(output)
end
function ui.go_home(player)
local pos = ui.home_pos[player:get_player_name()]
if pos then
player:set_pos(pos)
return true
function unified_inventory.go_home(player)
local pos = unified_inventory.home_pos[player:get_player_name()]
if pos ~= nil then
player:setpos(pos)
end
return false
end
-- register_craft
function ui.register_craft(options)
if not options.output then
function unified_inventory.register_craft(options)
if options.output == nil then
return
end
local itemstack = ItemStack(options.output)
if itemstack:is_empty() then
return
end
if options.type == "normal" and options.width == 0 then
options = { type = "shapeless", items = options.items, output = options.output, width = 0 }
end
local item_name = itemstack:get_name()
if not ui.crafts_for.recipe[item_name] then
ui.crafts_for.recipe[item_name] = {}
end
table.insert(ui.crafts_for.recipe[item_name],options)
for _, callback in ipairs(ui.craft_registered_callbacks) do
callback(item_name, options)
if unified_inventory.crafts_table[itemstack:get_name()] == nil then
unified_inventory.crafts_table[itemstack:get_name()] = {}
end
table.insert(unified_inventory.crafts_table[itemstack:get_name()],options)
end
local craft_type_defaults = {
width = 3,
height = 3,
uses_crafting_grid = false,
}
function ui.craft_type_defaults(name, options)
if not options.description then
options.description = name
end
setmetatable(options, {__index = craft_type_defaults})
return options
function unified_inventory.register_page(name, def)
unified_inventory.pages[name] = def
end
function ui.register_craft_type(name, options)
ui.registered_craft_types[name] =
ui.craft_type_defaults(name, options)
end
ui.register_craft_type("normal", {
description = F(S("Crafting")),
icon = "ui_craftgrid_icon.png",
width = 3,
height = 3,
get_shaped_craft_width = function (craft) return craft.width end,
dynamic_display_size = function (craft)
local w = craft.width
local h = math.ceil(table.maxn(craft.items) / craft.width)
local g = w < h and h or w
return { width = g, height = g }
end,
uses_crafting_grid = true,
})
ui.register_craft_type("shapeless", {
description = F(S("Mixing")),
icon = "ui_craftgrid_icon.png",
width = 3,
height = 3,
dynamic_display_size = function (craft)
local maxn = table.maxn(craft.items)
local g = 1
while g*g < maxn do g = g + 1 end
return { width = g, height = g }
end,
uses_crafting_grid = true,
})
ui.register_craft_type("cooking", {
description = F(S("Cooking")),
icon = "default_furnace_front.png",
width = 1,
height = 1,
})
ui.register_craft_type("digging", {
description = F(S("Digging")),
icon = "default_tool_steelpick.png",
width = 1,
height = 1,
})
ui.register_craft_type("digging_chance", {
description = "Digging (by chance)",
icon = "default_tool_steelpick.png^[transformFY.png",
width = 1,
height = 1,
})
function ui.register_page(name, def)
ui.pages[name] = def
end
function ui.register_button(name, def)
function unified_inventory.register_button(name, def)
if not def.action then
def.action = function(player)
ui.set_inventory_formspec(player, name)
unified_inventory.set_inventory_formspec(player, name)
end
end
def.name = name
table.insert(ui.buttons, def)
table.insert(unified_inventory.buttons, def)
end
function ui.register_on_initialized(callback)
if type(callback) ~= "function" then
error(("Initialized callback must be a function, %s given."):format(type(callback)))
function unified_inventory.is_creative(playername)
if minetest.check_player_privs(playername, {creative=true}) or
minetest.setting_getbool("creative_mode") then
return true
end
table.insert(ui.initialized_callbacks, callback)
end
function ui.register_on_craft_registered(callback)
if type(callback) ~= "function" then
error(("Craft registered callback must be a function, %s given."):format(type(callback)))
end
table.insert(ui.craft_registered_callbacks, callback)
end
function ui.get_recipe_list(output)
return ui.crafts_for.recipe[output]
end
function ui.get_registered_outputs()
local outputs = {}
for item_name, _ in pairs(ui.crafts_for.recipe) do
table.insert(outputs, item_name)
end
return outputs
end
function ui.is_creative(playername)
return minetest.check_player_privs(playername, {creative=true})
or minetest.settings:get_bool("creative_mode")
end
function ui.single_slot(xpos, ypos, bright)
return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]",
xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") )
end
function ui.make_trash_slot(xpos, ypos)
return
ui.single_slot(xpos, ypos)..
"image["..xpos..","..ypos..";1.25,1.25;ui_trash_slot_icon.png]"..
"list[detached:trash;main;"..(xpos + ui.list_img_offset)..","..(ypos + ui.list_img_offset)..";1,1;]"
end
function ui.make_inv_img_grid(xpos, ypos, width, height, bright)
local tiled = {}
local n=1
for y = 0, (height - 1) do
for x = 0, (width -1) do
tiled[n] = ui.single_slot(xpos + (ui.imgscale * x), ypos + (ui.imgscale * y), bright)
n = n + 1
end
end
return table.concat(tiled)
end

150
bags.lua Normal file

@ -0,0 +1,150 @@
-- Bags for Minetest
-- Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
-- License: GPLv3
unified_inventory.register_page("bags", {
get_formspec = function(player)
local player_name = player:get_player_name()
local formspec = "background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]"
formspec = formspec.."image[0,0;1,1;ui_bags_icon.png]"
formspec = formspec.."label[1,0;Bags]"
formspec = formspec.."button[0,2;2,0.5;bag1;Bag 1]"
formspec = formspec.."button[2,2;2,0.5;bag2;Bag 2]"
formspec = formspec.."button[4,2;2,0.5;bag3;Bag 3]"
formspec = formspec.."button[6,2;2,0.5;bag4;Bag 4]"
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec.."list[detached:"..player_name.."_bags;bag1;0.5,1;1,1;]"
formspec = formspec.."list[detached:"..player_name.."_bags;bag2;2.5,1;1,1;]"
formspec = formspec.."list[detached:"..player_name.."_bags;bag3;4.5,1;1,1;]"
formspec = formspec.."list[detached:"..player_name.."_bags;bag4;6.5,1;1,1;]"
return {formspec=formspec}
end,
})
unified_inventory.register_button("bags", {
type = "image",
image = "ui_bags_icon.png",
})
for i = 1, 4 do
unified_inventory.register_page("bag"..i, {
get_formspec = function(player)
local stack = player:get_inventory():get_stack("bag"..i, 1)
local image = stack:get_definition().inventory_image
local formspec = "image[7,0;1,1;"..image.."]"
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec.."list[current_player;bag"..i.."contents;0,1;8,3;]"
local slots = stack:get_definition().groups.bagslots
if slots == 8 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_sm_form.png]"
elseif slots == 16 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_med_form.png]"
elseif slots == 24 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_lg_form.png]"
end
return {formspec=formspec}
end,
})
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
end
for i = 1, 4 do
if fields["bag"..i] then
local stack = player:get_inventory():get_stack("bag"..i, 1)
if not stack:get_definition().groups.bagslots then
return
end
unified_inventory.set_inventory_formspec(player, "bag"..i)
return
end
end
end)
minetest.register_on_joinplayer(function(player)
local player_inv = player:get_inventory()
local bags_inv = minetest.create_detached_inventory(player:get_player_name().."_bags",{
on_put = function(inv, listname, index, stack, player)
player:get_inventory():set_stack(listname, index, stack)
player:get_inventory():set_size(listname.."contents",
stack:get_definition().groups.bagslots)
end,
on_take = function(inv, listname, index, stack, player)
player:get_inventory():set_stack(listname, index, nil)
end,
allow_put = function(inv, listname, index, stack, player)
if stack:get_definition().groups.bagslots then
return 1
else
return 0
end
end,
allow_take = function(inv, listname, index, stack, player)
if player:get_inventory():is_empty(listname.."contents") then
return stack:get_count()
else
return 0
end
end,
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return 0
end,
})
for i=1,4 do
local bag = "bag"..i
player_inv:set_size(bag, 1)
bags_inv:set_size(bag, 1)
bags_inv:set_stack(bag, 1, player_inv:get_stack(bag, 1))
end
end)
-- register bag tools
minetest.register_tool("unified_inventory:bag_small", {
description = "Small Bag",
inventory_image = "bags_small.png",
groups = {bagslots=8},
})
minetest.register_tool("unified_inventory:bag_medium", {
description = "Medium Bag",
inventory_image = "bags_medium.png",
groups = {bagslots=16},
})
minetest.register_tool("unified_inventory:bag_large", {
description = "Large Bag",
inventory_image = "bags_large.png",
groups = {bagslots=24},
})
-- register bag crafts
minetest.register_craft({
output = "unified_inventory:bag_small",
recipe = {
{"", "default:stick", ""},
{"group:wood", "group:wood", "group:wood"},
{"group:wood", "group:wood", "group:wood"},
},
})
minetest.register_craft({
output = "unified_inventory:bag_medium",
recipe = {
{"", "", ""},
{"default:stick", "unified_inventory:bag_small", "default:stick"},
{"default:stick", "unified_inventory:bag_small", "default:stick"},
},
})
minetest.register_craft({
output = "unified_inventory:bag_large",
recipe = {
{"", "", ""},
{"default:stick", "unified_inventory:bag_medium", "default:stick"},
{"default:stick", "unified_inventory:bag_medium", "default:stick"},
},
})

@ -1,34 +1,36 @@
local ui = unified_inventory
local function default_refill(stack)
stack:set_count(stack:get_stack_max())
local itemdef = minetest.registered_items[stack:get_name()]
if itemdef
and (itemdef.wear_represents or "mechanical_wear") == "mechanical_wear"
and stack:get_wear() ~= 0 then
stack:set_wear(0)
end
return stack
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
unified_inventory.players[player_name] = {}
unified_inventory.current_index[player_name] = 1 -- Item (~page) index
unified_inventory.current_index[player_name] = 1
unified_inventory.filtered_items_list[player_name] =
unified_inventory.items_list
unified_inventory.items_list
unified_inventory.activefilter[player_name] = ""
unified_inventory.active_search_direction[player_name] = "nochange"
unified_inventory.current_searchbox[player_name] = ""
unified_inventory.current_category[player_name] = "all"
unified_inventory.current_category_scroll[player_name] = 0
unified_inventory.apply_filter(player, "")
unified_inventory.alternate[player_name] = 1
unified_inventory.current_item[player_name] = nil
unified_inventory.current_craft_direction[player_name] = "recipe"
unified_inventory.set_inventory_formspec(player,
unified_inventory.default)
-- Crafting guide inventories
local inv = minetest.create_detached_inventory(player_name.."craftrecipe", {
allow_put = function(inv, listname, index, stack, player)
return 0
end,
allow_take = function(inv, listname, index, stack, player)
return 0
end,
allow_move = function(inv, from_list, from_index, to_list,
to_index, count, player)
return 0
end,
})
inv:set_size("output", 1)
-- Refill slot
local refill = minetest.create_detached_inventory(player_name.."refill", {
allow_put = function(inv, listname, index, stack, player)
local player_name = player:get_player_name()
if unified_inventory.is_creative(player_name) then
return stack:get_count()
else
@ -36,80 +38,21 @@ minetest.register_on_joinplayer(function(player)
end
end,
on_put = function(inv, listname, index, stack, player)
local handle_refill = (minetest.registered_items[stack:get_name()] or {}).on_refill or default_refill
stack = handle_refill(stack)
local player_name = player:get_player_name()
stack:set_count(stack:get_stack_max())
inv:set_stack(listname, index, stack)
minetest.sound_play("electricity",
{to_player=player_name, gain = 1.0})
end,
}, player_name)
})
refill:set_size("main", 1)
end)
minetest.register_on_mods_loaded(function()
minetest.register_on_joinplayer(function(player)
-- After everything is initialized, set up the formspec
ui.apply_filter(player, "", "nochange")
ui.set_inventory_formspec(player, unified_inventory.default)
end)
end)
local function apply_new_filter(player, search_text, new_dir)
local player_name = player:get_player_name()
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
ui.apply_filter(player, search_text, new_dir)
ui.current_searchbox[player_name] = search_text
ui.set_inventory_formspec(player, ui.current_page[player_name])
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local player_name = player:get_player_name()
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name)
if formname ~= "" then
return
end
-- always take new search text, even if not searching on it yet
local dirty_search_filter = false
if fields.searchbox
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
unified_inventory.current_searchbox[player_name] = fields.searchbox
dirty_search_filter = true
end
local clicked_category
for name, value in pairs(fields) do
local category_name = string.match(name, "^category_(.+)$")
if category_name then
clicked_category = category_name
break
end
end
if clicked_category
and clicked_category ~= unified_inventory.current_category[player_name] then
unified_inventory.current_category[player_name] = clicked_category
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
if fields.next_category or fields.prev_category then
local step = fields.next_category and 1 or -1
local scroll_old = ui.current_category_scroll[player_name]
local scroll_new = math.max(0, math.min(#ui.category_list - ui_peruser.pagecols, scroll_old + step))
if scroll_old ~= scroll_new then
ui.current_category_scroll[player_name] = scroll_new
ui.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
local player_name = player:get_player_name()
for i, def in pairs(unified_inventory.buttons) do
if fields[def.name] then
@ -122,124 +65,120 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- Inventory page controls
local start = math.floor(
unified_inventory.current_index[player_name] / ui_peruser.items_per_page + 1)
unified_inventory.current_index[player_name] / 80 + 1)
local start_i = start
local pagemax = math.floor(
(#unified_inventory.filtered_items_list[player_name] - 1)
/ (ui_peruser.items_per_page) + 1)
/ (80) + 1)
if fields.start_list then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = 1
end
if fields.rewind1 then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = start_i - 1
end
if fields.forward1 then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = start_i + 1
end
if fields.rewind3 then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = start_i - 3
end
if fields.forward3 then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = start_i + 3
end
if fields.end_list then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
start_i = pagemax
end
if start_i < 1 then
start_i = 1
end
if start_i > pagemax then
start_i = pagemax
end
if start_i ~= start then
minetest.sound_play("paperflip1",
{to_player=player_name, gain = 1.0})
unified_inventory.current_index[player_name] = (start_i - 1) * ui_peruser.items_per_page + 1
if not (start_i == start) then
unified_inventory.current_index[player_name] = (start_i - 1) * 80 + 1
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
-- Check clicked item image button
local clicked_item
local clicked_item = nil
for name, value in pairs(fields) do
local new_dir, mangled_item = string.match(name, "^[0-9]*_?item_button_([a-z]+)_(.*)$")
if new_dir and mangled_item then
clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
if string.sub(clicked_item, 1, 6) == "group:" then
-- Change search filter to this group
unified_inventory.current_category[player_name] = "all"
apply_new_filter(player, clicked_item, new_dir)
return
end
if new_dir == "recipe" or new_dir == "usage" then
unified_inventory.current_craft_direction[player_name] = new_dir
end
if string.sub(name, 1, 12) == "item_button_" then
clicked_item = string.sub(name, 13)
break
elseif string.sub(name, 1, 11) == "item_group_" then
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, "group:"..string.sub(name, 12))
return
end
end
if clicked_item then
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
local page = unified_inventory.current_page[player_name]
local player_creative = unified_inventory.is_creative(player_name)
if not player_creative then
if not unified_inventory.is_creative(player_name) then
page = "craftguide"
end
if page == "craftguide" then
unified_inventory.current_item[player_name] = clicked_item
unified_inventory.alternate[player_name] = 1
unified_inventory.set_inventory_formspec(player, "craftguide")
elseif player_creative then
-- Creative page: Add entire stack to inventory
local inv = player:get_inventory()
local stack = ItemStack(clicked_item)
stack:set_count(stack:get_stack_max())
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
unified_inventory.set_inventory_formspec(player,
"craftguide")
else
if unified_inventory.is_creative(player_name) then
local inv = player:get_inventory()
local stack = ItemStack(clicked_item)
stack:set_count(stack:get_stack_max())
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
end
end
end
end
if fields.searchbutton
or fields.key_enter_field == "searchbox" then
if dirty_search_filter then
ui.apply_filter(player, ui.current_searchbox[player_name], "nochange")
ui.set_inventory_formspec(player, ui.current_page[player_name])
minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0})
end
elseif fields.searchresetbutton then
if ui.activefilter[player_name] ~= "" then
apply_new_filter(player, "", "nochange")
end
if fields.searchbutton then
unified_inventory.apply_filter(player, fields.searchbox)
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0})
end
-- alternate buttons
if not (fields.alternate or fields.alternate_prev) then
return
end
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
local item_name = unified_inventory.current_item[player_name]
if not item_name then
return
end
local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][item_name]
if not crafts then
return
end
local alternates = #crafts
if alternates <= 1 then
return
end
local alternate
-- alternate button
if fields.alternate then
alternate = unified_inventory.alternate[player_name] + 1
if alternate > alternates then
alternate = 1
end
elseif fields.alternate_prev then
alternate = unified_inventory.alternate[player_name] - 1
if alternate < 1 then
alternate = alternates
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
local item_name = unified_inventory.current_item[player_name]
if item_name then
local alternates = 0
local alternate = unified_inventory.alternate[player_name]
local crafts = unified_inventory.crafts_table[item_name]
if crafts ~= nil then
alternates = #crafts
end
if alternates > 1 then
alternate = alternate + 1
if alternate > alternates then
alternate = 1
end
unified_inventory.alternate[player_name] = alternate
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
end
unified_inventory.alternate[player_name] = alternate
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
minetest.remove_detached_inventory(player_name.."_bags")
minetest.remove_detached_inventory(player_name.."refill")
end)

83
datastorage.lua Normal file

@ -0,0 +1,83 @@
datastorage={}
datastorage["!registered_players"]={}
datastorage.save_data = function(table_pointer)
local data = minetest.serialize( datastorage[table_pointer] )
local path = minetest.get_worldpath().."/datastorage_"..table_pointer..".data"
local file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
return true
else return nil
end
end
datastorage.load_data = function(table_pointer)
local path = minetest.get_worldpath().."/datastorage_"..table_pointer..".data"
local file = io.open( path, "r" )
if( file ) then
local data = file:read("*all")
datastorage[table_pointer] = minetest.deserialize( data )
file:close()
return true
else return nil
end
end
datastorage.get_container = function (player, key)
local player_name = player:get_player_name()
local container = datastorage[player_name]
if container[key] == nil then
container[key] = {}
end
datastorage.save_data(player_name)
return container[key]
end
-- forced save of all player's data
datastorage.save_container = function (player)
local player_name = player:get_player_name()
datastorage.save_data(player_name)
end
-- Init
if datastorage.load_data("!registered_players") == nil then
datastorage["!registered_players"]={}
datastorage.save_data("!registered_players")
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local registered = nil
for __,tab in ipairs(datastorage["!registered_players"]) do
if tab["player_name"] == player_name then registered = true break end
end
if registered == nil then
local new={}
new["player_name"]=player_name
table.insert(datastorage["!registered_players"],new)
datastorage[player_name]={}
datastorage.save_data("!registered_players")
datastorage.save_data(player_name)
else
datastorage.load_data(player_name)
end
end
)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
datastorage.save_data(player_name)
datastorage[player_name] = nil
end
)
minetest.register_on_shutdown(function()
for __,tab in ipairs(datastorage["!registered_players"]) do
if datastorage[tab["player_name"]] == nil then break end
datastorage.save_data(tab["player_name"])
end
end
)

1
depends.txt Normal file

@ -0,0 +1 @@
creative?

@ -1,230 +0,0 @@
unified_inventory API
=====================
This file provides information about the API of unified_inventory.
API revisions within unified_inventory can be checked using:
(unified_inventory.version or 1)
**Revision history**
* Version `1`: Classic formspec layout (no real_coordinates)
* Version `2`: Force formspec version 4 (includes real_coordinates)
Misc functions
--------------
Grouped by use-case, afterwards sorted alphabetically.
* `unified_inventory.is_creative(name)`
* Checks whether creative is enabled or the player has `creative`
Callbacks
---------
Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft:
unified_inventory.register_on_craft_registered(
function (item_name, options)
-- item_name (string): name of the output item, equivalent to `ItemStack:get_name()`
-- options (table): definition table of crafts registered by `unified_inventory.register_craft`
end
)
Register a callback that will be run after all mods have loaded and after the unified_inventory mod has initialised all its internal structures:
unified_inventory.register_on_initialized(callback)
-- The callback is passed no arguments
Accessing Data
--------------
These methods should be used instead of accessing the unified_inventory data structures directly - this will ensure your code survives any potential restructuring of the mod.
Get a list of recipes for a particular output item:
unified_inventory.get_recipe_list(output_item)
Returns a list of tables, each holding a recipe definition, like:
{
{
type = "normal",
items = { "default:stick", "default:stick", "default:stick", "default:stick" },
output = "default:wood",
width = 2
},
{
type = "shapeless",
items = { "default:tree" },
output = "default:wood 4",
width = 0
},
...
}
Get a list of all the output items crafts have been registered for:
unified_inventory.get_registered_outputs()
Returns a list of item names, like:
{
"default:stone",
"default:chest",
"default:brick",
"doors:door_wood",
...
}
Pages
-----
Register a new page: The callback inside this function is called on user input.
unified_inventory.register_page("pagename", {
get_formspec = function(player)
-- ^ `player` is an `ObjectRef`
-- Compute the formspec string here
return {
formspec = "button[2,2;2,1;mybutton;Press me]",
-- ^ Final form of the formspec to display
draw_inventory = false, -- default `true`
-- ^ Optional. Hides the player's `main` inventory list
draw_item_list = false, -- default `true`
-- ^ Optional. Hides the item list on the right side
formspec_prepend = false, -- default `false`
-- ^ Optional. When `false`: Disables the formspec prepend
}
end,
})
Buttons
-------
Register a new button for the bottom row:
unified_inventory.register_button("skins", {
type = "image",
image = "skins_skin_button.png",
tooltip = "Skins",
hide_lite = true
-- ^ Button is hidden when following two conditions are met:
-- Configuration line `unified_inventory_lite = true`
-- Player does not have the privilege `ui_full`
})
Crafting
--------
The code blocks below document each possible parameter using exemplary values.
Provide information to display custom craft types:
unified_inventory.register_craft_type("mytype", {
-- ^ Unique identifier for `register_craft`
description = "Sample Craft",
-- ^ Text shown below the crafting arrow
icon = "dummy.png",
-- ^ Image shown above the crafting arrow
width = 3,
height = 3,
-- ^ Maximal input dimensions of the recipes
dynamic_display_size = function(craft)
-- ^ `craft` is the definition from `register_craft`
return {
width = 2,
height = 3
}
end,
-- ^ Optional callback to change the displayed recipe size
uses_crafting_grid = true,
})
Register a non-standard craft recipe:
unified_inventory.register_craft({
output = "default:foobar",
type = "mytype",
-- ^ Standard craft type or custom (see `register_craft_type`)
items = {
{ "default:foo" },
{ "default:bar" }
},
width = 3,
-- ^ Same as `minetest.register_recipe`
})
Categories
----------
Register a new category:
The config table (second argument) is optional, and all its members are optional
See the unified_inventory.set_category_* functions for more details on the members of the config table
unified_inventory.register_category("category_name", {
symbol = "mod_name:item_name" or "texture.png",
label = "Human Readable Label",
index = 5,
items = {
"mod_name:item_name",
"another_mod:different_item"
}
})
Add / override the symbol for a category:
The category does not need to exist first
The symbol can be an item name or a texture image
If unset this will default to "default:stick"
unified_inventory.set_category_symbol("category_name", "mod_name:item_name" or "texture.png")
Add / override the human readable label for a category:
If unset this will default to the category name
unified_inventory.set_category_label("category_name", "Human Readable Label")
Add / override the sorting index of the category:
Must be a number, can also be negative (-5) or fractional (2.345)
This determines the position the category appears in the list of categories
The "all" meta-category has index -2, the "misc"/"uncategorized" meta-category has index -1, use a negative number smaller than these to make a category appear before these in the list
By default categories are sorted alphabetically with an index between 0.0101(AA) and 0.2626(ZZ)
unified_inventory.set_category_index("category_name", 5)
Add a single item to a category:
unified_inventory.add_category_item("category_name", "mod_name:item_name")
Add multiple items to a category:
unified_inventory.add_category_items("category_name", {
"mod_name:item_name",
"another_mod:different_item"
})
Remove an item from a category:
unified_inventory.remove_category_item("category_name", "mod_name:item_name")
Remove a category entirely:
unified_inventory.remove_category("category_name")
Finding existing items in categories:
This will find the first category an item exists in
It should be used for checking if an item is catgorised
Returns "category_name" or nil
unified_inventory.find_category("mod_name:item_name")
This will find all the categories an item exists in
Returns a number indexed table (list) of category names
unified_inventory.find_categories("mod_name:item_name")

@ -1,86 +0,0 @@
local S = minetest.get_translator("unified_inventory")
function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name()
if specname:sub(1, 6) ~= "group:" then
return nil, 0
end
local group_names = specname:sub(7):split(",")
return table.concat(group_names, S(" and ")), #group_names
end
-- This is used when displaying craft recipes, where an ingredient is
-- specified by group rather than as a specific item. A single-item group
-- is represented by that item, with the single-item status signalled
-- in the "sole" field. If the group contains no items at all, the item
-- field will be nil.
--
-- Within a multiple-item group, we prefer to use an item that has the
-- same specific name as the group, and if there are more than one of
-- those items we prefer the one registered for the group by a mod.
-- Among equally-preferred items, we just pick the one with the
-- lexicographically earliest name.
--
-- The parameter to this function isn't just a single group name.
-- It may be a comma-separated list of group names. This is really a
-- "group:..." ingredient specification, minus the "group:" prefix.
local function compute_group_item(group_name_list)
local group_names = group_name_list:split(",")
local candidate_items = {}
for itemname, itemdef in pairs(minetest.registered_items) do
if (itemdef.groups.not_in_creative_inventory or 0) == 0 then
local all = true
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
all = false
end
end
if all then table.insert(candidate_items, itemname) end
end
end
local num_candidates = #candidate_items
if num_candidates == 0 then
return {sole = true}
elseif num_candidates == 1 then
return {item = candidate_items[1], sole = true}
end
local is_group = {}
local registered_rep = {}
for _, group_name in ipairs(group_names) do
is_group[group_name] = true
local rep = unified_inventory.registered_group_items[group_name]
if rep then registered_rep[rep] = true end
end
local bestitem = ""
local bestpref = 0
for _, item in ipairs(candidate_items) do
local pref
if registered_rep[item] then
pref = 4
elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then
pref = 3
elseif is_group[item:gsub("^[^:]*:", "")] then
pref = 2
else
pref = 1
end
if pref > bestpref or (pref == bestpref and item < bestitem) then
bestitem = item
bestpref = pref
end
end
return {item = bestitem, sole = false}
end
local group_item_cache = {}
function unified_inventory.get_group_item(group_name)
if not group_item_cache[group_name] then
group_item_cache[group_name] = compute_group_item(group_name)
end
return group_item_cache[group_name]
end

@ -1,69 +0,0 @@
bags_small.png:
http://www.clker.com/clipart-moneybag-empty.html
bags_medium.png:
http://www.clker.com/clipart-backpack-1.html
bags_large.png / ui_bags_icon.png:
http://www.clker.com/clipart-backpack-green-brown.html
ui_craftguide_icon.png / ui_craft_icon.png
http://commons.wikimedia.org/wiki/File:Advancedsettings.png
ui_doubleleft_icon.png
http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg
ui_doubleright_icon.png
http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg
ui_left_icon.png / ui_right_icon.png
http://commons.wikimedia.org/wiki/File:Media-playback-start.svg
ui_skip_backward_icon.png
http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg
ui_skip_forward_icon.png
http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg
ui_reset_icon.png
https://commons.wikimedia.org/wiki/File:Edit-clear.svg
ui_gohome_icon.png / ui_home_icon.png / ui_sethome_icon.png
http://commons.wikimedia.org/wiki/File:Home_256x256.png
ui_moon_icon.png
http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg
ui_sun_icon.png
http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg
ui_trash_icon.png
http://www.clker.com/clipart-29090.html
http://www.clker.com/clipart-trash.html
ui_search_icon.png
http://www.clker.com/clipart-24887.html
ui_off_icon.png / ui_on_icon.png
http://www.clker.com/clipart-on-off-switches.html
ui_waypoints_icon.png
http://www.clker.com/clipart-map-pin-red.html
ui_circular_arrows_icon.png
http://www.clker.com/clipart-circular-arrow-pattern.html
ui_pencil_icon.pnc
http://www.clker.com/clipart-2256.html
ui_waypoint_set_icon.png
http://www.clker.com/clipart-larger-flag.html
ui_xyz_off_icon.png
http://commons.wikimedia.org/wiki/File:No_sign.svg
ui_ok_icon.png
http://commons.wikimedia.org/wiki/File:Yes_check.svg
inventory_plus_worldedit_gui.png
http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg

199
init.lua

@ -1,187 +1,44 @@
-- Unified Inventory
if not minetest.features.formspec_version_element then
-- At least formspec_version[] is the minimal feature requirement
error("Unified Inventory requires Minetest version 5.4.0 or newer.\n" ..
" Please update Minetest or use an older version of Unified Inventory.")
end
-- Unified Inventory for Minetest 0.4.8+
local modpath = minetest.get_modpath(minetest.get_current_modname())
local worldpath = minetest.get_worldpath()
-- Data tables definitions
unified_inventory = {
activefilter = {},
active_search_direction = {},
alternate = {},
current_page = {},
current_searchbox = {},
current_category = {},
current_category_scroll = {},
current_index = {},
current_item = {},
current_craft_direction = {},
registered_craft_types = {},
crafts_for = {usage = {}, recipe = {} },
players = {},
items_list_size = 0,
items_list = {},
filtered_items_list_size = {},
filtered_items_list = {},
pages = {},
buttons = {},
initialized_callbacks = {},
craft_registered_callbacks = {},
unified_inventory = {}
unified_inventory.activefilter = {}
unified_inventory.alternate = {}
unified_inventory.current_page = {}
unified_inventory.current_index = {}
unified_inventory.current_item = {}
unified_inventory.crafts_table = {}
unified_inventory.crafts_table_count = 0
unified_inventory.players = {}
unified_inventory.items_list_size = 0
unified_inventory.items_list = {}
unified_inventory.filtered_items_list_size = {}
unified_inventory.filtered_items_list = {}
unified_inventory.pages = {}
unified_inventory.buttons = {}
-- Homepos stuff
home_pos = {},
home_filename = worldpath.."/unified_inventory_home.home",
-- Homepos stuff
unified_inventory.home_pos = {}
unified_inventory.home_filename =
worldpath.."/unified_inventory_home.home"
-- Default inventory page
default = "craft",
-- "Lite" mode
lite_mode = minetest.settings:get_bool("unified_inventory_lite"),
-- Items automatically added to categories based on item definitions
automatic_categorization = (minetest.settings:get_bool("unified_inventory_automatic_categorization") ~= false),
-- Trash enabled
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25,
list_img_offset = 0.13,
standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
version = 4
}
local ui = unified_inventory
-- These tables establish position and layout for the two UI styles.
-- UI doesn't use formspec_[xy] anymore, but other mods may need them.
ui.style_full = {
formspec_x = 1,
formspec_y = 1,
formw = 17.75,
formh = 12.25,
-- Item browser size, pos
pagecols = 8,
pagerows = 11,
page_x = 10.75,
page_y = 0.30,
-- Item browser controls
page_buttons_x = 11.60,
page_buttons_y = 10.15,
searchwidth = 3.4,
-- Crafting grid positions
craft_x = 2.8,
craft_y = 1.15,
craftresult_x = 7.8,
craft_arrow_x = 6.55,
craft_guide_x = 3.3,
craft_guide_y = 1.15,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.3,
craft_guide_resultstr_y = 0.6,
give_btn_x = 0.25,
-- Tab switching buttons
main_button_x = 0.4,
main_button_y = 11.0,
main_button_cols = 12,
main_button_rows = 1,
-- Tab title position
form_header_x = 0.4,
form_header_y = 0.4,
-- Generic sizes
btn_spc = 0.85,
btn_size = 0.75,
std_inv_x = 0.3,
std_inv_y = 5.75,
}
ui.style_lite = {
formspec_x = 0.6,
formspec_y = 0.6,
formw = 14,
formh = 9.75,
-- Item browser size, pos
pagecols = 4,
pagerows = 7,
page_x = 10.5,
page_y = 0.15,
-- Item browser controls
page_buttons_x = 10.5,
page_buttons_y = 6.15,
searchwidth = 1.6,
-- Crafting grid positions
craft_x = 2.6,
craft_y = 0.75,
craftresult_x = 5.75,
craft_arrow_x = 6.35,
craft_guide_x = 3.1,
craft_guide_y = 0.75,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.15,
craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15,
-- Tab switching buttons
main_button_x = 10.5,
main_button_y = 8.15,
main_button_cols = 4,
main_button_rows = 2,
-- Tab title position
form_header_x = 0.2,
form_header_y = 0.2,
-- Generic sizes
btn_spc = 0.8,
btn_size = 0.7,
std_inv_x = 0.1,
std_inv_y = 4.6,
}
dofile(modpath.."/api.lua")
for _, style in ipairs({ui.style_full, ui.style_lite}) do
style.items_per_page = style.pagecols * style.pagerows
style.standard_inv = string.format("list[current_player;main;%f,%f;8,4;]",
style.std_inv_x + ui.list_img_offset, style.std_inv_y + ui.list_img_offset)
style.standard_inv_bg = ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y, 8, 1, true)..
ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y + ui.imgscale, 8, 3)
style.craft_grid = table.concat({
ui.make_inv_img_grid(style.craft_x, style.craft_y, 3, 3),
ui.single_slot(style.craft_x + ui.imgscale*4, style.craft_y), -- the craft result slot
string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
style.craft_arrow_x, style.craft_y, ui.imgscale, ui.imgscale),
string.format("list[current_player;craft;%f,%f;3,3;]",
style.craft_x + ui.list_img_offset, style.craft_y + ui.list_img_offset),
string.format("list[current_player;craftpreview;%f,%f;1,1;]",
style.craftresult_x + ui.list_img_offset, style.craft_y + ui.list_img_offset)
})
end
-- Default inventory page
unified_inventory.default = "craft"
-- Disable default creative inventory
local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory")
if creative then
function creative.set_creative_formspec(player, start_i, pagenum)
if creative_inventory then
function creative_inventory.set_creative_formspec(player, start_i, pagenum)
return
end
end
-- Disable sfinv inventory
local sfinv = rawget(_G, "sfinv")
if sfinv then
sfinv.enabled = false
end
dofile(modpath.."/group.lua")
dofile(modpath.."/datastorage.lua")
dofile(modpath.."/api.lua")
dofile(modpath.."/internal.lua")
dofile(modpath.."/callbacks.lua")
dofile(modpath.."/register.lua")
dofile(modpath.."/item_names.lua")
dofile(modpath.."/legacy.lua") -- mod compatibility
dofile(modpath.."/bags.lua")
dofile(modpath.."/waypoints.lua")

@ -1,321 +1,149 @@
local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
local ui = unified_inventory
-- This pair of encoding functions is used where variable text must go in
-- button names, where the text might contain formspec metacharacters.
-- We can escape button names for the formspec, to avoid screwing up
-- form structure overall, but they then don't get de-escaped, and so
-- the input we get back from the button contains the formspec escaping.
-- This is a game engine bug, and in the anticipation that it might be
-- fixed some day we don't want to rely on it. So for safety we apply
-- an encoding that avoids all formspec metacharacters.
function ui.mangle_for_formspec(str)
return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end)
end
function ui.demangle_for_formspec(str)
return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end)
end
-- Get the player-specific unified_inventory style
function ui.get_per_player_formspec(player_name)
local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
local style = table.copy(draw_lite_mode and ui.style_lite or ui.style_full)
style.is_lite_mode = draw_lite_mode
return style
end
-- Creates an item image or regular image button with a tooltip
local function formspec_button(ui_peruser, name, image, offset, pos, scale, label)
local element = 'image_button'
if minetest.registered_items[image] then
element = 'item_image_button'
elseif image:find(":", 1, true) then
image = "unknown_item.png"
end
local spc = (1-scale)*ui_peruser.btn_size/2
local size = ui_peruser.btn_size*scale
return string.format("%s[%f,%f;%f,%f;%s;%s;]", element,
(offset.x or offset[1]) + ( ui_peruser.btn_spc * (pos.x or pos[1]) ) + spc,
(offset.y or offset[2]) + ( ui_peruser.btn_spc * (pos.y or pos[2]) ) + spc,
size, size, image, name) ..
string.format("tooltip[%s;%s]", name, F(label or name))
end
-- Add registered buttons (tabs)
local function formspec_tab_buttons(player, formspec, style)
local n = #formspec + 1
-- Main buttons
local filtered_inv_buttons = {}
for i, def in pairs(ui.buttons) do
if not (style.is_lite_mode and def.hide_lite) then
table.insert(filtered_inv_buttons, def)
end
end
local needs_scrollbar = #filtered_inv_buttons > style.main_button_cols * style.main_button_rows
formspec[n] = ("scroll_container[%g,%g;%g,%g;tabbtnscroll;vertical]"):format(
style.main_button_x, style.main_button_y, -- position
style.main_button_cols * style.btn_spc, style.main_button_rows -- size
)
n = n + 1
for i, def in pairs(filtered_inv_buttons) do
local pos_x = ((i - 1) % style.main_button_cols) * style.btn_spc
local pos_y = math.floor((i - 1) / style.main_button_cols) * style.btn_spc
if def.type == "image" then
if (def.condition == nil or def.condition(player) == true) then
formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]",
pos_x, pos_y, style.btn_size, style.btn_size,
F(def.image),
F(def.name))
formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]"
n = n+2
else
-- formspec[n] = string.format("image[%g,%g;%g,%g;%s^[colorize:#808080:alpha]",
-- pos_x, pos_y, style.btn_size, style.btn_size,
-- def.image)
-- n = n+1
end
end
end
formspec[n] = "scroll_container_end[]"
if needs_scrollbar then
formspec[n+1] = ("scrollbaroptions[max=%i;arrows=hide]"):format(
-- This calculation is not 100% accurate but "good enough"
math.ceil((#filtered_inv_buttons - 1) / style.main_button_cols) * style.btn_spc * 5
)
formspec[n+2] = ("scrollbar[%g,%g;0.4,%g;vertical;tabbtnscroll;0]"):format(
style.main_button_x + style.main_button_cols * style.btn_spc - 0.1, -- x pos
style.main_button_y, -- y pos
style.main_button_rows * style.btn_spc -- height
)
formspec[n+3] = "scrollbaroptions[max=1000;arrows=default]"
end
end
local function formspec_add_search_box(player, formspec, ui_peruser)
local player_name = player:get_player_name()
local n = #formspec + 1
formspec[n] = "field_close_on_enter[searchbox;false]"
formspec[n+1] = string.format("field[%f,%f;%f,%f;searchbox;;%s]",
ui_peruser.page_buttons_x, ui_peruser.page_buttons_y,
ui_peruser.searchwidth - 0.1, ui_peruser.btn_size,
F(ui.current_searchbox[player_name]))
formspec[n+2] = string.format("image_button[%f,%f;%f,%f;ui_search_icon.png;searchbutton;]",
ui_peruser.page_buttons_x + ui_peruser.searchwidth, ui_peruser.page_buttons_y,
ui_peruser.btn_size,ui_peruser.btn_size)
formspec[n+3] = "tooltip[searchbutton;" ..F(S("Search")) .. "]"
formspec[n+4] = string.format("image_button[%f,%f;%f,%f;ui_reset_icon.png;searchresetbutton;]",
ui_peruser.page_buttons_x + ui_peruser.searchwidth + ui_peruser.btn_spc,
ui_peruser.page_buttons_y,
ui_peruser.btn_size, ui_peruser.btn_size)
formspec[n+5] = "tooltip[searchresetbutton;"..F(S("Reset search and display everything")).."]"
if ui.activefilter[player_name] ~= "" then
formspec[n+6] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_x, ui_peruser.page_y - 0.25,
F(S("Filter")), F(ui.activefilter[player_name]))
end
end
local function formspec_add_item_browser(player, formspec, ui_peruser)
local player_name = player:get_player_name()
local n = #formspec + 1
formspec[n] = string.format("image_button[%f,%f;%f,%f;ui_left_icon.png;rewind1;]",
ui_peruser.page_buttons_x,
ui_peruser.page_buttons_y + 1,
ui_peruser.btn_size, ui_peruser.btn_size)
formspec[n+1] = "tooltip[rewind1;"..F(S("Back one page")).."]"
formspec[n+2] = string.format("image_button[%f,%f;%f,%f;ui_right_icon.png;forward1;]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc * 5,
ui_peruser.page_buttons_y + 1,
ui_peruser.btn_size, ui_peruser.btn_size)
formspec[n+3] = "tooltip[forward1;"..F(S("Forward one page")).."]"
n = n + 4
-- Items list
if #ui.filtered_items_list[player_name] == 0 then
local no_matches = S("No matching items")
if ui_peruser.is_lite_mode then
no_matches = S("No matches.")
end
formspec[n] = "label["..ui_peruser.page_x..","..(ui_peruser.page_y+0.15)..";" .. F(no_matches) .. "]"
return
end
local dir = ui.active_search_direction[player_name]
local list_index = ui.current_index[player_name]
local page2 = math.floor(list_index / (ui_peruser.items_per_page) + 1)
local pagemax = math.floor(
(#ui.filtered_items_list[player_name] - 1)
/ (ui_peruser.items_per_page) + 1)
for y = 0, ui_peruser.pagerows - 1 do
for x = 0, ui_peruser.pagecols - 1 do
local name = ui.filtered_items_list[player_name][list_index]
local item = minetest.registered_items[name]
if item then
-- Clicked on current item: Flip crafting direction
if name == ui.current_item[player_name] then
local cdir = ui.current_craft_direction[player_name]
if cdir == "recipe" then
dir = "usage"
elseif cdir == "usage" then
dir = "recipe"
end
else
-- Default: use active search direction by default
dir = ui.active_search_direction[player_name]
end
local button_name = "item_button_" .. dir .. "_"
.. ui.mangle_for_formspec(name)
formspec[n] = ("item_image_button[%f,%f;%f,%f;%s;%s;]"):format(
ui_peruser.page_x + x * ui_peruser.btn_spc,
ui_peruser.page_y + y * ui_peruser.btn_spc,
ui_peruser.btn_size, ui_peruser.btn_size,
name, button_name
)
local tooltip = item.description
if item.mod_origin then
-- "mod_origin" may not be specified for items that were
-- registered in a callback (during or before ServerEnv init)
tooltip = tooltip .. " [" .. item.mod_origin .. "]"
end
formspec[n + 1] = ("tooltip[%s;%s]"):format(
button_name, minetest.formspec_escape(tooltip)
)
n = n + 2
list_index = list_index + 1
end
end
end
formspec[n] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc * (ui_peruser.is_lite_mode and 1 or 2),
ui_peruser.page_buttons_y - 0.3 + ui_peruser.btn_spc * 2,
F(S("Page")), S("@1 of @2",page2,pagemax))
end
function ui.get_formspec(player, page)
function unified_inventory.get_formspec(player, page)
if not player then
return ""
end
local player_name = player:get_player_name()
local ui_peruser = ui.get_per_player_formspec(player_name)
unified_inventory.current_page[player_name] = page
local pagedef = unified_inventory.pages[page]
ui.current_page[player_name] = page
local pagedef = ui.pages[page]
local formspec = "size[14,10]"
local fsdata = nil
if not pagedef then
-- Background
formspec = formspec .. "background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]"
-- Current page
if unified_inventory.pages[page] then
fsdata = pagedef.get_formspec(player)
formspec = formspec .. fsdata.formspec
else
return "" -- Invalid page name
end
local fs = {
"formspec_version[4]",
"size["..ui_peruser.formw..","..ui_peruser.formh.."]",
pagedef.formspec_prepend and "" or "no_prepend[]",
ui.standard_background
}
local perplayer_formspec = ui.get_per_player_formspec(player_name)
local fsdata = pagedef.get_formspec(player, perplayer_formspec)
fs[#fs + 1] = fsdata.formspec
formspec_tab_buttons(player, fs, ui_peruser)
-- Main buttons
for i, def in pairs(unified_inventory.buttons) do
if def.type == "image" then
formspec = formspec.."image_button["
..(0.65 * (i - 1))..",9;0.8,0.8;"
..minetest.formspec_escape(def.image)..";"
..minetest.formspec_escape(def.name)..";]"
end
end
if fsdata.draw_inventory ~= false then
-- Player inventory
fs[#fs + 1] = "listcolors[#00000000;#00000000]"
fs[#fs + 1] = ui_peruser.standard_inv
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec .. "list[current_player;main;0,4.5;8,4;]"
end
if fsdata.draw_item_list == false then
return table.concat(fs, "")
return formspec
end
formspec_add_search_box(player, fs, ui_peruser)
formspec_add_item_browser(player, fs, ui_peruser)
-- Controls to flip items pages
local start_x = 9.2
formspec = formspec .. "image_button["..(start_x + 0.6 * 0)..",9;.8,.8;ui_skip_backward_icon.png;start_list;]"
formspec = formspec .. "image_button["..(start_x + 0.6 * 1)..",9;.8,.8;ui_doubleleft_icon.png;rewind3;]"
formspec = formspec .. "image_button["..(start_x + 0.6 * 2)..",9;.8,.8;ui_left_icon.png;rewind1;]"
formspec = formspec .. "image_button["..(start_x + 0.6 * 3)..",9;.8,.8;ui_right_icon.png;forward1;]"
formspec = formspec .. "image_button["..(start_x + 0.6 * 4)..",9;.8,.8;ui_doubleright_icon.png;forward3;]"
formspec = formspec .. "image_button["..(start_x + 0.6 * 5)..",9;.8,.8;ui_skip_forward_icon.png;end_list;]"
return table.concat(fs)
-- Search box
formspec = formspec .. "field[9.5,8.325;3,1;searchbox;;]"
formspec = formspec .. "image_button[12.2,8.1;.8,.8;ui_search_icon.png;searchbutton;]"
-- Items list
local list_index = unified_inventory.current_index[player_name]
local page = math.floor(list_index / (80) + 1)
local pagemax = math.floor(
(#unified_inventory.filtered_items_list[player_name] - 1)
/ (80) + 1)
local item = {}
for y = 0, 9 do
for x = 0, 7 do
local name = unified_inventory.filtered_items_list[player_name][list_index]
if minetest.registered_items[name] then
formspec = formspec.."item_image_button["
..(8.2 + x * 0.7)..","
..(1 + y * 0.7)..";.81,.81;"
..name..";item_button_"
..name..";]"
list_index = list_index + 1
end
end
end
formspec = formspec.."label[8.2,0;Page:]"
formspec = formspec.."label[9,0;"..page.." of "..pagemax.."]"
formspec = formspec.."label[8.2,0.4;Filter:]"
formspec = formspec.."label[9,0.4;"..unified_inventory.activefilter[player_name].."]"
return formspec
end
function ui.set_inventory_formspec(player, page)
function unified_inventory.set_inventory_formspec(player, page)
if player then
player:set_inventory_formspec(ui.get_formspec(player, page))
local formspec = unified_inventory.get_formspec(player, page)
player:set_inventory_formspec(formspec)
end
end
local function valid_def(def)
return (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
end
--apply filter to the inventory list (create filtered copy of full one)
function ui.apply_filter(player, filter, search_dir)
if not player then
return false
end
function unified_inventory.apply_filter(player, filter)
local player_name = player:get_player_name()
local size = 0
local lfilter = string.lower(filter)
local ffilter
if not pcall(function() ("technic:test"):find(lfilter) end) then
-- Filter is invalid
lfilter = ""
end
unified_inventory.filtered_items_list[player_name]={}
if lfilter:sub(1, 6) == "group:" then
local groups = lfilter:sub(7):split(",")
ffilter = function(name, def)
for _, group in ipairs(groups) do
if not def.groups[group]
or def.groups[group] <= 0 then
return false
for name, def in pairs(minetest.registered_items) do
if def.groups then
local all = true
for _, group in ipairs(groups) do
if not (def.groups[group] and (def.groups[group] > 0)) then
all = false
break
end
end
if all then
table.insert(unified_inventory.filtered_items_list[player_name], name)
size = size + 1
end
end
return true
end
else
local player_info = minetest.get_player_information(player_name)
local lang = player_info and player_info.lang_code or ""
ffilter = function(name, def)
local lname = string.lower(name)
local ldesc = string.lower(def.description)
local llocaldesc = minetest.get_translated_string
and string.lower(minetest.get_translated_string(lang, def.description))
return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true)
or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or
def.groups.not_in_creative_inventory == 0)
and def.description and def.description ~= "" then
local lname = string.lower(name)
local ldesc = string.lower(def.description)
if string.find(lname, lfilter) or string.find(ldesc, lfilter) then
table.insert(unified_inventory.filtered_items_list[player_name], name)
size = size + 1
end
end
end
end
ui.filtered_items_list[player_name]={}
for name, def in pairs(minetest.registered_items) do
if valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end
table.sort(ui.filtered_items_list[player_name])
ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
ui.current_index[player_name] = 1
ui.activefilter[player_name] = filter
ui.active_search_direction[player_name] = search_dir
ui.set_inventory_formspec(player, ui.current_page[player_name])
table.sort(unified_inventory.filtered_items_list[player_name])
unified_inventory.filtered_items_list_size[player_name] = size
unified_inventory.current_index[player_name] = 1
unified_inventory.activefilter[player_name] = filter
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
-- Inform players about potential visual issues
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local info = minetest.get_player_information(player_name)
if info and (info.formspec_version or 0) < 4 then
minetest.chat_send_player(player_name, S("Unified Inventory: Your game version is too old"
.. " and does not support the GUI requirements. You might experience visual issues."))
function unified_inventory.items_in_group(groups)
local items = {}
for name, item in pairs(minetest.registered_items) do
for _, group in pairs(groups:split(',')) do
if item.groups[group] then
table.insert(items, name)
end
end
end
end)
return items
end

@ -1,76 +0,0 @@
-- Based on 4itemnames mod by 4aiman
local item_names = {} -- [player_name] = { hud, dtime, itemname }
local dlimit = 3 -- HUD element will be hidden after this many seconds
local hudbars_mod = minetest.get_modpath("hudbars")
local function set_hud(player)
local player_name = player:get_player_name()
local off = {x=0, y=-65}
if hudbars_mod then
-- Assume no alignment (2 per line)
off.y = off.y - math.ceil(hb.hudbars_count / 2) * 25
else
off.y = off.y - 25
end
item_names[player_name] = {
hud = player:hud_add({
hud_elem_type = "text",
position = {x=0.5, y=1},
offset = off,
alignment = {x=0, y=-1},
number = 0xFFFFFF,
text = "",
}),
dtime = dlimit,
index = 1,
itemname = ""
}
end
minetest.register_on_joinplayer(function(player)
minetest.after(0, set_hud, player)
end)
minetest.register_on_leaveplayer(function(player)
item_names[player:get_player_name()] = nil
end)
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
local data = item_names[player:get_player_name()]
if not data or not data.hud then
data = {} -- Update on next step
set_hud(player)
end
local index = player:get_wield_index()
local stack = player:get_wielded_item()
local itemname = stack:get_name()
if data.hud and data.dtime < dlimit then
data.dtime = data.dtime + dtime
if data.dtime > dlimit then
player:hud_change(data.hud, 'text', "")
end
end
if data.hud and (itemname ~= data.itemname or index ~= data.index) then
data.itemname = itemname
data.index = index
data.dtime = 0
local desc = stack.get_meta
and stack:get_meta():get_string("description")
if not desc or desc == "" then
-- Try to use default description when none is set in the meta
local def = minetest.registered_items[itemname]
desc = def and def.description or ""
end
player:hud_change(data.hud, 'text', desc)
end
end
end)

@ -1,55 +0,0 @@
-- Inefficient pattern matching
local warned_funcs = {}
local function LOG_ONCE(funcname)
if warned_funcs[funcname] then return end
warned_funcs[funcname] = true
minetest.log("error", "Call to undocumented, deprecated API '" .. funcname .. "'."
.. " In a future version of Unified Inventory this will result in a real error.")
end
function unified_inventory.canonical_item_spec_matcher(spec)
LOG_ONCE("canonical_item_spec_matcher")
local specname = ItemStack(spec):get_name()
if specname:sub(1, 6) ~= "group:" then
return function (itemname)
return itemname == specname
end
end
local group_names = specname:sub(7):split(",")
return function (itemname)
local itemdef = minetest.registered_items[itemname]
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
return false
end
end
return true
end
end
function unified_inventory.item_matches_spec(item, spec)
LOG_ONCE("item_matches_spec")
local itemname = ItemStack(item):get_name()
return unified_inventory.canonical_item_spec_matcher(spec)(itemname)
end
unified_inventory.registered_group_items = {
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
stone = "default:cobble",
wood = "default:wood",
book = "default:book",
sand = "default:sand",
leaves = "default:leaves",
tree = "default:tree",
vessel = "vessels:glass_bottle",
wool = "wool:white",
}
function unified_inventory.register_group_item(groupname, itemname)
LOG_ONCE("register_group_item")
unified_inventory.registered_group_items[groupname] = itemname
end

@ -1,358 +0,0 @@
# LANGUAGE translation for the unified_inventory mod.
# Copyright (C) 2018 Maciej Kasatkin (RealBadAngel)
# This file is distributed under the same license as the unified_inventory package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: unified_inventory\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-02 03:34+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: api.lua register.lua
msgid "Crafting"
msgstr ""
#: api.lua
msgid "Mixing"
msgstr ""
#: api.lua
msgid "Cooking"
msgstr ""
#: api.lua
msgid "Digging"
msgstr ""
#: bags.lua
msgid "Bags"
msgstr ""
#: bags.lua
msgid "Bag @1"
msgstr ""
#: bags.lua
msgid "Small Bag"
msgstr ""
#: bags.lua
msgid "Medium Bag"
msgstr ""
#: bags.lua
msgid "Large Bag"
msgstr ""
#: group.lua
msgid " and "
msgstr ""
#: internal.lua
msgid "First page"
msgstr ""
#: internal.lua
msgid "Back three pages"
msgstr ""
#: internal.lua
msgid "Back one page"
msgstr ""
#: internal.lua
msgid "Forward one page"
msgstr ""
#: internal.lua
msgid "Forward three pages"
msgstr ""
#: internal.lua
msgid "Last page"
msgstr ""
#: internal.lua
msgid "Search"
msgstr ""
#: internal.lua
msgid "Reset search and display everything"
msgstr ""
#: internal.lua
msgid "No matching items"
msgstr ""
#: internal.lua
msgid "No matches."
msgstr ""
#: internal.lua
msgid "Page"
msgstr ""
#: internal.lua
#, lua-format
msgid "%s of %s"
msgstr ""
#: internal.lua
msgid "Filter"
msgstr ""
#: register.lua
msgid "Can use the creative inventory"
msgstr ""
#: register.lua
msgid ""
"Forces Unified Inventory to be displayed in Full mode if Lite mode is "
"configured globally"
msgstr ""
#: register.lua
msgid "Crafting Grid"
msgstr ""
#: register.lua
msgid "Crafting Guide"
msgstr ""
#: register.lua
msgid "Set home position"
msgstr ""
#: register.lua
#, lua-format
msgid "Home position set to: %s"
msgstr ""
#: register.lua
msgid "You don't have the \"home\" privilege!"
msgstr ""
#: register.lua
msgid "Go home"
msgstr ""
#: register.lua
msgid "Set time to day"
msgstr ""
#: register.lua
msgid "Time of day set to 6am"
msgstr ""
#: register.lua
msgid "You don't have the settime privilege!"
msgstr ""
#: register.lua
msgid "Set time to night"
msgstr ""
#: register.lua
msgid "Time of day set to 9pm"
msgstr ""
#: register.lua
msgid "Clear inventory"
msgstr ""
#: register.lua
msgid ""
"This button has been disabled outside of creative mode to prevent accidental "
"inventory trashing.\n"
"Use the trash slot instead."
msgstr ""
#: register.lua
msgid "Inventory cleared!"
msgstr ""
#: register.lua
msgid "Trash:"
msgstr ""
#: register.lua
msgid "Refill:"
msgstr ""
#: register.lua
#, lua-format
msgid "Any item belonging to the %s group"
msgstr ""
#: register.lua
#, lua-format
msgid "Any item belonging to the groups %s"
msgstr ""
#: register.lua
#, lua-format
msgid "Recipe %d of %d"
msgstr ""
#: register.lua
#, lua-format
msgid "Usage %d of %d"
msgstr ""
#: register.lua
msgid "No recipes"
msgstr ""
#: register.lua
msgid "No usages"
msgstr ""
#: register.lua
msgid "Result"
msgstr ""
#: register.lua
msgid "Ingredient"
msgstr ""
#: register.lua
msgid "Show next recipe"
msgstr ""
#: register.lua
msgid "Show next usage"
msgstr ""
#: register.lua
msgid "Show previous recipe"
msgstr ""
#: register.lua
msgid "Show previous usage"
msgstr ""
#: register.lua
#, lua-format
msgid "%s (%s)"
msgstr ""
#: register.lua
msgid "Give me:"
msgstr ""
#: register.lua
msgid ""
"This recipe is too\n"
"large to be displayed."
msgstr ""
#: register.lua
msgid "To craft grid:"
msgstr ""
#: register.lua
msgid "All"
msgstr ""
#: waypoints.lua
msgid "White"
msgstr ""
#: waypoints.lua
msgid "Yellow"
msgstr ""
#: waypoints.lua
msgid "Red"
msgstr ""
#: waypoints.lua
msgid "Green"
msgstr ""
#: waypoints.lua
msgid "Blue"
msgstr ""
#: waypoints.lua
msgid "Waypoints"
msgstr ""
#: waypoints.lua
#, lua-format
msgid "Select Waypoint #%d"
msgstr ""
#: waypoints.lua
#, lua-format
msgid "Waypoint %d"
msgstr ""
#: waypoints.lua
msgid "Set waypoint to current location"
msgstr ""
#: waypoints.lua
msgid "invisible"
msgstr ""
#: waypoints.lua
msgid "visible"
msgstr ""
#: waypoints.lua
msgid "Make waypoint @1"
msgstr ""
#: waypoints.lua
msgid "Disable"
msgstr ""
#: waypoints.lua
msgid "Enable"
msgstr ""
#: waypoints.lua
msgid "@1 display of waypoint coordinates"
msgstr ""
#: waypoints.lua
msgid "Change color of waypoint display"
msgstr ""
#: waypoints.lua
msgid "Edit waypoint name"
msgstr ""
#: waypoints.lua
msgid "Waypoint active"
msgstr ""
#: waypoints.lua
msgid "Waypoint inactive"
msgstr ""
#: waypoints.lua
msgid "Finish editing"
msgstr ""
#: waypoints.lua
msgid "World position"
msgstr ""
#: waypoints.lua
msgid "Name"
msgstr ""
#: waypoints.lua
msgid "HUD text color"
msgstr ""

@ -1,90 +0,0 @@
# textdomain: unified_inventory
Mixing=
Cooking=
Digging=
Bags=
Bag @1=
Small Bag=
Medium Bag=
Large Bag=
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and =
Scroll categories left=
Scroll categories right=
Search=
Reset search and display everything=
First page=
Back three pages=
Back one page=
Forward one page=
Forward three pages=
Last page=
No matching items=
No matches.=
Page=
@1 of @2=
Filter=
Can use the creative inventory=
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=
Crafting Guide=
Set home position=
Home position set to: @1=
You don't have the "home" privilege!=
Go home=
Set time to day=
Time of day set to 6am=
You don't have the settime privilege!=
Set time to night=
Time of day set to 9pm=
Clear inventory=
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=
Trash:=
Refill:=
Any item belonging to the @1 group=
Any item belonging to the groups @1=
Recipe @1 of @2=
Usage @1 of @2=
No recipes=
No usages=
Result=
Ingredient=
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=
This recipe is too@@large to be displayed.=
To craft grid:=
All=
Crafting=
White=
Yellow=
Red=
Green=
Blue=
Waypoints=
Select Waypoint #@1=
Waypoint @1=
Set waypoint to current location=
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=
Edit waypoint name=
Waypoint active=
Waypoint inactive=
Finish editing=
World position=
Name=
HUD text color=

@ -1,100 +0,0 @@
# textdomain: unified_inventory
Mixing=Mischen
Cooking=Kochen
Digging=Graben
Bags=Taschen
Bag @1=Tasche @1
Small Bag=Kleine Tasche
Medium Bag=Mittelgroße Tasche
Large Bag=Große Tasche
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = und
Scroll categories left=
Scroll categories right=
Search=Suchen
Reset search and display everything=Suche zurücksetzen und alles anzeigen
First page=Erste Seite
Back three pages=3 Seiten zurückblättern
Back one page=1 Seite zurückblättern
Forward one page=1 Seite vorblättern
Forward three pages=3 Seiten vorblättern
Last page=Letzte Seite
No matching items=Keine passenden Gegenstände
No matches.=Keine Treffer
Page=Seite
@1 of @2=@1 von @2
Filter=Filter
Can use the creative inventory=Kann das Kreativinventar nutzen
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Zwingt Unified Inventory, im Vollmodus angezeigt zu werden, wenn der Minimalmodus global eingestellt ist
Crafting Grid=Fertigungsraster
Crafting Guide=Fertigungsführer
Set home position=Heimatposition setzen
Home position set to: @1=Heimatposition nach @1 gesetzt
You don't have the "home" privilege!=Du hast das „home“-Privileg nicht!
Go home=Nach Hause gehen
Set time to day=Zur Tageszeit wechseln
Time of day set to 6am=Tageszeit auf 6 Uhr gesetzt
You don't have the settime privilege!=Du hast das „settime“-Privileg nicht!
Set time to night=Zur Nachtzeit wechseln
Time of day set to 9pm=Tageszeit auf 21 Uhr gesetzt
Clear inventory=Inventar leeren
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Inventar geleert!
Trash:=Müll:
Refill:=Nachfüllen:
Any item belonging to the @1 group=Irgendein Gegenstand, der zur Gruppe @1 gehört
Any item belonging to the groups @1=Irgendein Gegenstand, der zu den Gruppen @1 gehört
Recipe @1 of @2=Rezept @1 von @2
Usage @1 of @2=Verwendung @1 von @2
No recipes=Keine Rezepte
No usages=Keine Verwendungen
Result=Ergebnis
Ingredient=Zutat
Show next recipe=Nächstes Rezept zeigen
Show next usage=Nächste Verwendung zeigen
Show previous recipe=Vorheriges Rezept zeigen
Show previous usage=Vorherige Verwendung zeigen
@1 (@2)=
Give me:=Gib mir:
This recipe is too@@large to be displayed.=
To craft grid:=Ins Fertigungsraster:
All=Alles
Crafting=Fertigung
White=Weiß
Yellow=Gelb
Red=Rot
Green=Grün
Blue=Blau
Waypoints=Wegpunkte
Select Waypoint #@1=Wegpunkt Nr. @1 auswählen
Waypoint @1=Wegpunkt Nr. @1
Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern
Edit waypoint name=Name des Wegpunkts ändern
Waypoint active=Wegpunkt aktiv
Waypoint inactive=Wegpunkt inaktiv
Finish editing=Bearbeitung abschließen
World position=Weltposition
Name=Name
HUD text color=HUD-Textfarbe
##### not used anymore #####
invisible=unsichtbar
visible=sichtbar
Make waypoint @1=Wegpunkt @1 machen
Disable=ausschalten
Enable=einschalten
@1 display of waypoint coordinates=Anzeige der Wegpunktkoordinaten @1

@ -1,108 +0,0 @@
# textdomain: unified_inventory
# api.lua
Mixing=Mezclar
Cooking=Hornear
Digging=Recoger
# bags.lua
Bags=Bolsos
Bag @1=Bolso @1
Small Bag=Bolso Pequeño
Medium Bag=Bolso Mediano
Large Bag=Bolso Grande
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
# group.lua
and = y
Scroll categories left=
Scroll categories right=
Search=Buscar
Reset search and display everything=Limpiar la busqueda y mostrar todo
# internal.lua
First page=Primera página
Back three pages=Volver tres páginas
Back one page=Volver una página
Forward one page=Avanzar una página
Forward three pages=Avanzar tres páginas
Last page=Ultima Pagina
No matching items=No se encontraron elementos
No matches.=No hay resultados.
Page=Página
@1 of @2=@1 de @2
Filter=Filtro
# register.lua
Can use the creative inventory=Puede usar el inventario creativo
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Obliga al Inventario Unificado a mostrarse en modo Completo si el modo Simple está configurado globalmente
Crafting Grid=Cuadricula de Elaboración
Crafting Guide=Guía de Elaboración
Set home position=Establecer posición de la casa
Home position set to: @1=Posición de la casa cambiada a: @1
You don't have the "home" privilege!=
Go home=Ir a casa
Set time to day=Cambiar a dia
Time of day set to 6am=Hora del día cambiada a 6 AM
You don't have the settime privilege!=¡No tienes el privilegio "settime"!
Set time to night=Cambiar a noche
Time of day set to 9pm=Hora del día cambiada a 9 PM
Clear inventory=Limpiar inventario
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=¡Inventario limpio!
Trash:=Basura:
Refill:=Rellenar:
Any item belonging to the @1 group=Cualquier elemento que pertenezca al grupo @1
Any item belonging to the groups @1=Cualquier elemento perteneciente a los grupos @1
Recipe @1 of @2=Receta @1 de @2
Usage @1 of @2=Uso @1 de @2
No recipes=No tiene receta
No usages=No tiene uso
Result=Resultado
Ingredient=Ingrediente
Show next recipe=Mostrar la siguiente receta
Show next usage=Mostrar el siguiente uso
Show previous recipe=Mostrar la receta anterior
Show previous usage=Mostrar el uso anterior
@1 (@2)=@1 (@2)
Give me:=Dame:
This recipe is too@@large to be displayed.=
To craft grid:=Construir:
All=Todos
Crafting=Elaboración
White=Blanco
Yellow=Amarillo
Red=Rojo
Green=Verde
Blue=Azul
Waypoints=Puntos
Select Waypoint #@1=Seleccionar Punto #@1
Waypoint @1=Punto @1
Set waypoint to current location=Establecer el punto a la ubicación actual
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Cambiar el color del punto
Edit waypoint name=Editar nombre del punto
Waypoint active=Punto activo
Waypoint inactive=Punto inactivo
Finish editing=Terminar edición
World position=Posición en el mundo
Name=Nombre
HUD text color=Color del texto de la Interfaz
##### not used anymore #####
Make waypoint @1=Hacer punto @1
invisible=invisible
visible=visible
@1 display of waypoint coordinates=Visualizar coordenadas del punto @1
Disable=Deshabilitado
Enable=Habilitado
You don't have the \"home\" privilege!=¡No tienes el privilegio \"home\"!
This button has been disabled outside=Este botón ha sido deshabilitado
This recipe is too@nlarge to be displayed.=Esta receta es demasiado@ngrande para ser mostrada.

@ -1,96 +0,0 @@
# textdomain: unified_inventory
Mixing=
Cooking=Cuisson
Digging=Creuser
Bags=Sacs
Bag @1=Sac @1
Small Bag=Petit sac
Medium Bag=Sac moyen
Large Bag=Grand sac
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = et
Scroll categories left=
Scroll categories right=
Search=Rechercher
Reset search and display everything=
First page=1ère page
Back three pages=3 pages en arrière
Back one page=Page précédente
Forward one page=Page suivante
Forward three pages=3 pages en avant
Last page=Dernière page
No matching items=Aucun élément correspondant
No matches.=Aucun match
Page=Page
@1 of @2=@1 de @2
Filter=Filtre
Can use the creative inventory=Vous pouvez utiliser l'inventaire créatif
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=Grille de création
Crafting Guide=Guide de création
Set home position=Position dans le monde
Home position set to: @1=Position de votre base fixée à: @1
You don't have the "home" privilege!=Vous n'avez pas le privilège "home"!
Go home=
Set time to day=
Time of day set to 6am=Heure fixée à 6h
You don't have the settime privilege!=Vous n'avez pas le privilège "settime"!
Set time to night=
Time of day set to 9pm=Heure fixée à 21h
Clear inventory=
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Inventaire vidé !
Trash:=Poubelle :
Refill:=Remplir :
Any item belonging to the @1 group=
Any item belonging to the groups @1=
Recipe @1 of @2=Recette @1 de @2
Usage @1 of @2=
No recipes=
No usages=
Result=Résultat
Ingredient=
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=
This recipe is too@@large to be displayed.=
To craft grid:=Sur de création:
All=Tout
Crafting=Création
White=Blanc
Yellow=Jaune
Red=Rouge
Green=Vert
Blue=Bleu
Waypoints=Point de passage
Select Waypoint #@1=Choisir un point de passage #@1
Waypoint @1=Point de passage @1
Set waypoint to current location=Marquer un point de passage à la position actuelle
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Changer la couleur du point de passage
Edit waypoint name=Editer le nom du point de passage
Waypoint active=Point de passage actif
Waypoint inactive=Point de passage inactif
Finish editing=Terminer l'édition
World position=Position dans le monde
Name=Nom
HUD text color=Couleur de texte du HUD
##### not used anymore #####
Make waypoint @1=Rendre @1 le point de passage
@1 display of waypoint coordinates=@1 montrer les coordonnées des points de passages

@ -1,100 +0,0 @@
# textdomain: unified_inventory
Mixing=Unione
Cooking=Cottura
Digging=Scavo
Bags=Borse
Bag @1=Borsa @1
Small Bag=Borsa piccola
Medium Bag=Borsa media
Large Bag=Borsa grande
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = e
Scroll categories left=
Scroll categories right=
Search=Cerca
Reset search and display everything=Azzera la ricerca e mostra tutto
First page=Prima pagina
Back three pages=Indietro di tre pagine
Back one page=Indietro di una pagina
Forward one page=Avanti di una pagina
Forward three pages=Avanti di tre pagine
Last page=Ultima pagina
No matching items=Nessun oggetto corrispondente
No matches.=Nessuna corrispondenza.
Page=Pagina
@1 of @2=@1 di @2
Filter=Filtro
Can use the creative inventory=Può usare l'inventario creativo
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Forza la visualizzazione di Unified Inventory in modalità completa se è configurata globalmente la visualizzazione semplice
Crafting Grid=Griglia di assemblaggio
Crafting Guide=Guida di assemblaggio
Set home position=Imposta la residenza
Home position set to: @1=Residenza impostata su: @1
You don't have the "home" privilege!=Non hai il privilegio "home"!
Go home=Torna a casa
Set time to day=Imposta l'orario sul giorno
Time of day set to 6am=Orario impostato sulle 6am
You don't have the settime privilege!=Non hai il privilegio "time"!
Set time to night=Imposta l'orario sulla notte
Time of day set to 9pm=Orario impostato sulle 9am
Clear inventory=Ripulisci l'inventario
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Inventario ripulito!
Trash:=Butta:
Refill:=Riempi:
Any item belonging to the @1 group=Qualunque oggetto appartenente al gruppo @1
Any item belonging to the groups @1=Qualunque oggetto appartenente ai gruppi @1
Recipe @1 of @2=Ricetta @1 di @2
Usage @1 of @2=Uso @1 di @2
No recipes=Nessuna ricetta
No usages=Nessun utilizzo
Result=Risultato
Ingredient=Ingrediente
Show next recipe=Mostra la prossima ricetta
Show next usage=Mostra il prossimo utilizzo
Show previous recipe=Mostra la ricetta precedente
Show previous usage=Mostra l'utilizzo precedente
@1 (@2)=
Give me:=Dammi:
This recipe is too@@large to be displayed.=
To craft grid:=Alla griglia di assemblaggio:
All=Tutto
Crafting=Assemblaggio
White=Bianco
Yellow=Giallo
Red=Rosso
Green=Verde
Blue=Blu
Waypoints=Tappe
Select Waypoint #@1=Seleziona tappa n°@1
Waypoint @1=Tappa @1
Set waypoint to current location=Imposta tappa alla posizione attuale
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Modifica il colore della visualizzazione della tappa
Edit waypoint name=Modifica il nome della tappa
Waypoint active=Tappa attiva
Waypoint inactive=Tappa inattiva
Finish editing=Termina la modifica
World position=Posizione del mondo
Name=Nome
HUD text color=Colore del testo del visore
##### not used anymore #####
invisible=invisibile
visible=visibile
Make waypoint @1=Crea tappa @1
Disable=Disabilita
Enable=Abilita
@1 display of waypoint coordinates=@1 la visualizzazione delle coordinate della tappa

@ -1,100 +0,0 @@
# textdomain: unified_inventory
Mixing=Pencampuran
Cooking=Pemasakan
Digging=Penggalian
Bags=Beg
Bag @1=Beg @1
Small Bag=Beg Kecil
Medium Bag=Beg Sederhana
Large Bag=Beg Besar
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = dan
Scroll categories left=
Scroll categories right=
Search=Cari
Reset search and display everything=Set semula carian dan tunjukkan semua benda
First page=Halaman pertama
Back three pages=Tiga halaman sebelumnya
Back one page=Halaman sebelumnya
Forward one page=Halaman seterusnya
Forward three pages=Tiga halaman seterusnya
Last page=Halaman terakhir
No matching items=Tiada item sepadan
No matches.=Tiada padanan.
Page=Halaman
@1 of @2=@1 drpd @2
Filter=Tapis
Can use the creative inventory=Boleh guna inventori kreatif
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=Grid Pertukangan
Crafting Guide=Panduan Pertukangan
Set home position=Tetapkan kedudukan rumah
Home position set to: @1=Kedudukan rumah ditetapkan ke: @1
You don't have the "home" privilege!=Anda tidak ada keistimewaan "home"!
Go home=Balik rumah
Set time to day=Tetapkan masa jadi siang
Time of day set to 6am=Masa ditetapkan ke 6 pagi
You don't have the settime privilege!=Anda tidak ada keistimewaan settime!
Set time to night=Tetapkan masa jadi malam
Time of day set to 9pm=Masa ditetapkan ke 9 malam
Clear inventory=Kosongkan inventori
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Inventori dikosongkan!
Trash:=Buang:
Refill:=Isi balik:
Any item belonging to the @1 group=Sebarang item dari kumpulan @1
Any item belonging to the groups @1=Sebarang item dari kumpulan @1
Recipe @1 of @2=Resipi @1 drpd @2
Usage @1 of @2=Kegunaan @1 drpd @2
No recipes=Tiada resipi
No usages=Tiada kegunaan
Result=Hasil
Ingredient=Bahan
Show next recipe=Tunjuk resipi seterusnya
Show next usage=Tunjuk kegunaan seterusnya
Show previous recipe=Tunjuk resipi sebelumnya
Show previous usage=Tunjuk kegunaan sebelumnya
@1 (@2)=@1 (@2)
Give me:=Beri saya:
This recipe is too@@large to be displayed.=
To craft grid:=Ke grid pertukangan:
All=
Crafting=Pertukangan
White=Putih
Yellow=Kuning
Red=Merah
Green=Hijau
Blue=Biru
Waypoints=Titik Arah
Select Waypoint #@1=Pilih Titik Arah #@1
Waypoint @1=Titik Arah @1
Set waypoint to current location=Tetapkan titik arah ke lokasi semasa
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Tukar warna paparan titik arah
Edit waypoint name=Edit nama titik arah
Waypoint active=Titik arah aktif
Waypoint inactive=Titik arah tidak aktif
Finish editing=Selesai edit
World position=Kedudukan dunia
Name=Nama
HUD text color=Warna tulisan HUD
##### not used anymore #####
invisible=Sembunyikan
visible=Paparkan
Make waypoint @1=@1 titik arah
Disable=Sembunyikan
Enable=Paparkan
@1 display of waypoint coordinates=@1 koordinat untuk titik arah

@ -1,98 +0,0 @@
# textdomain: unified_inventory
Mixing=
Cooking=
Digging=
Bags=Plecaki
Bag @1=Plecak @1
Small Bag=Maly plecak
Medium Bag=Sredni plecak
Large Bag=Duzy plecak
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = i
Scroll categories left=
Scroll categories right=
Search=Szukaj
Reset search and display everything=
First page=Pierwsza strona
Back three pages=3 strony w tyl
Back one page=1 strona w tyl
Forward one page=1 strona do przodu
Forward three pages=3 strony do przodu
Last page=Ostatnia strona
No matching items=Brak pasujacych przedmiotow
No matches.=Brak wyników
Page=Strona
@1 of @2=@1 z @2
Filter=Filtr
Can use the creative inventory=
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=
Crafting Guide=
Set home position=Ustaw pozycję wyjściową
Home position set to: @1=Pozycja domowa ustawiona na: @1
You don't have the "home" privilege!=Nie masz uprawnien do zmiany czasu "home"!
Go home=Idź do domu
Set time to day=Ustaw czas na dzień
Time of day set to 6am=Czas ustawiony na 6:00
You don't have the settime privilege!=Nie masz uprawnien do zmiany czasu "settime"!
Set time to night=Ustaw czas na noc
Time of day set to 9pm=Czas ustawiony na 21:00
Clear inventory=Wyczyść zapasy
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Zapasy zostały wyczyszczone!
Trash:=Smietnik:
Refill:=Uzupelnianie:
Any item belonging to the @1 group=
Any item belonging to the groups @1=
Recipe @1 of @2=Recepta @1 z @2
Usage @1 of @2=Użycie @1 z @2
No recipes=Brak recepty
No usages=Bez użycia
Result=Wynik
Ingredient=Składnik
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=Daj mi:
This recipe is too@@large to be displayed.=
To craft grid:=
All=Wszystko
Crafting=
White=Bialy
Yellow=Zolty
Red=Czerwony
Green=Zielony
Blue=Niebieski
Waypoints=Punkty orientacyjne
Select Waypoint #@1=Wybierz punkt #@1
Waypoint @1=Punkty orientacyjne @1
Set waypoint to current location=Ustaw punkt orientacyjny na biezacej pozycji
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Zmien kolor punktu
Edit waypoint name=Edytuj nazwe punktu
Waypoint active=Punkt wlaczony
Waypoint inactive=Punkt wylaczony
Finish editing=Zakoncz edycje
World position=Pozycja
Name=Nazwa
HUD text color=Kolor tekstu HUD
##### not used anymore #####
invisible=niewidzialny
visible=widomy
Make waypoint @1=Robić punkt @1
@1 display of waypoint coordinates=@1 koordynatow punktu

@ -1,98 +0,0 @@
# textdomain: unified_inventory
Mixing=Muistura
Cooking=Cozimento
Digging=Escavação
Bags=Bolsas
Bag @1=Bolsa @1
Small Bag=Bolsa Pequena
Medium Bag=Bolsa Média
Large Bag=Bolsa Grande
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = e
Scroll categories left=
Scroll categories right=
Search=Pesquisar
Reset search and display everything=Redefinir pesquisa e exibir tudo
First page=Primeira Página
Back three pages=Voltar 3 Páginas
Back one page=Voltar 1 Página
Forward one page=Avançar 1 Página
Forward three pages=Avançar 3 Páginas
Last page=Ultima Página
No matching items=Nenhum item correspondente
No matches.=Sem correspondências
Page=Página
@1 of @2=@1 de @2
Filter=Filtro
Can use the creative inventory=Pode usar o inventário do criativo
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=Grade de Artesanato
Crafting Guide=Guia de Artesanato
Set home position=Definir posição de casa
Home position set to: @1=Posição inicial definida para: @1
You don't have the "home" privilege!=Você não tem o privilégio de "home"!
Go home=Transportar para Casa
Set time to day=Definir turno para dia
Time of day set to 6am=Hora do dia definida para 06h
You don't have the settime privilege!=Você não tem o privilégio de "settime"!
Set time to night=Definir turno para noite
Time of day set to 9pm=Hora do dia ajustada para 21h
Clear inventory=Limpar Inventário
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Inventário Apagado!
Trash:=Lixo:
Refill:=Recarga:
Any item belonging to the @1 group=Qualquer item pertencente ao grupo '@1'.
Any item belonging to the groups @1=Qualquer item pertencente aos grupos '@1'.
Recipe @1 of @2=Receita @1 de @2
Usage @1 of @2=Utilização @1 de @2
No recipes=Sem Receita
No usages=Sem Utilização
Result=Resultado
Ingredient=Ingrediente
Show next recipe=Exibir Próxima Receita
Show next usage=Mostrar Próxima Utilização
Show previous recipe=Exibir Receita Anterior
Show previous usage=Exibir Utilização Anterior
@1 (@2)=
Give me:=Gerado:
This recipe is too@@large to be displayed.=
To craft grid:=Para Grade de Artesanato
All=MAX
Crafting=Artesanato
White=Branco
Yellow=Amarelo
Red=Vermelho
Green=Verde
Blue=Azul
Waypoints=Apontador de Direção
Select Waypoint #@1=Seleção de Apontador de Direção #@1
Waypoint @1=Apontador de Direção @1
Set waypoint to current location=Configurar localização atual do Apontador de Direção
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Mudar cor exibida do Apontador de Direção
Edit waypoint name=Editar Nome de Apontador de Direção
Waypoint active=Apontador de Direção Ativo
Waypoint inactive=Apontador de Direção Inativo
Finish editing=Edição Finalizada
World position=Posição Mundial
Name=Nome
HUD text color=Cor de HUD
##### not used anymore #####
invisible=invisível
visible=visível
Make waypoint @1=Fazer Apontador de Direção @1
@1 display of waypoint coordinates=@1 exibição de coordenadas de Fazer Apontador de Direção

@ -1,100 +0,0 @@
# textdomain: unified_inventory
Mixing=Мешать
Cooking=Варить
Digging=Копать
Bags=Сумки
Bag @1=Сумка @1
Small Bag=Малая сумка
Medium Bag=Средняя сумка
Large Bag=Большая сумка
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = и
Scroll categories left=
Scroll categories right=
Search=Поиск
Reset search and display everything=Сброс поиска, показать всё
First page=Первая страница
Back three pages=3 страницы назад
Back one page=1 страницу назад
Forward one page=1 страницу вперёд
Forward three pages=3 страницы вперёд
Last page=Последняя страница
No matching items=Нет подходящих элементов
No matches.=Ничего не найдено
Page=Страница
@1 of @2=@1 из @2
Filter=Фильтр
Can use the creative inventory=Можно использовать инвентарь творческого режима
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=Решетка крафта
Crafting Guide=Книга рецептов
Set home position=Установить позицию дома
Home position set to: @1=Дом теперь расположен по коодинатам: @1
You don't have the "home" privilege!=У вас нет привилегии "home"!
Go home=Отправиться домой
Set time to day=День
Time of day set to 6am=Установлено время 6 утра
You don't have the settime privilege!=Вам не разрешено устанавливать время! (нет привилегии "settime")
Set time to night=Ночь
Time of day set to 9pm=Установлено время 9 вечера
Clear inventory=Очистить инвентарь
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Инвентарь очищен!
Trash:=Мусор:
Refill:=Наполнить:
Any item belonging to the @1 group=Любой элемент из группы: @1
Any item belonging to the groups @1=Любой элемент из группы: @1
Recipe @1 of @2=Рецепт @1 из @2
Usage @1 of @2=Вариант @1 of @2
No recipes=Рецептов нет
No usages=Не используется
Result=Результат
Ingredient=Состав
Show next recipe=Следующий рецепт
Show next usage=Следующее использование
Show previous recipe=Прошлый рецепт
Show previous usage=Прошлая страница
@1 (@2)=
Give me:=Дай мне:
This recipe is too@@large to be displayed.=
To craft grid:=На решeтку крафта:
All=Все
Crafting=Крафт
White=Белый
Yellow=Желтый
Red=Красный
Green=Зелёный
Blue=Синий
Waypoints=Путевые точки
Select Waypoint #@1=Выбрать путевую точку №@1
Waypoint @1=Путевая точка @1
Set waypoint to current location=Установить путевую точку по текущей позиции
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Поменять цвет путевой точки
Edit waypoint name=Переименовать путевую точку
Waypoint active=Путевая точка включена
Waypoint inactive=Путевая точка выключена
Finish editing=Закончить редакцию
World position=Позиция мира
Name=Имя
HUD text color=Цвет текста HUDа
##### not used anymore #####
invisible=невидимой
visible=видимой
Make waypoint @1=Сделать путевую точку @1
Disable=Выключить
Enable=Включить
@1 display of waypoint coordinates=@1 показ координат путевых точек

@ -1,99 +0,0 @@
# textdomain: unified_inventory
Mixing=Karıştırma
Cooking=Pişirme
Digging=Kazma
Bags=Çantalarım
Bag @1=@1. Çanta
Small Bag=Küçük Çanta
Medium Bag=Çanta
Large Bag=Büyük Çanta
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = ve
Scroll categories left=
Scroll categories right=
Search=Ara
Reset search and display everything=
First page=İlk Sayfa
Back three pages=3 Sayfa Gerile
Back one page=Geri
Forward one page=İleri
Forward three pages=3 Sayfa İlerile
Last page=Son Sayfa
No matching items=Eşleşme yok
No matches.=Eşleşme yok
Page=Sayfa
@1 of @2=@1 dan @2
Filter=Süzgeç
Can use the creative inventory=Yaratıcı envanteri kullanabilir
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=Üretim tablosu
Crafting Guide=Kılavuz
Set home position=Set ev pozisyon
Home position set to: @1=Yeni eviniz: @1
You don't have the "home" privilege!="home" yetkiniz yok!
Go home=Eve git
Set time to day=Güne zaman ayarla
Time of day set to 6am=Saat 06:00 olarak ayarlandı
You don't have the settime privilege!="settime" yetkiniz yok!
Set time to night=Geceye zaman ayarla
Time of day set to 9pm=Saat 19:00 olarak ayarlandı
Clear inventory=
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=Envanter temizlendi!
Trash:=Çöp
Refill:=Doldur
Any item belonging to the @1 group=
Any item belonging to the groups @1=
Recipe @1 of @2=@1 dan @2 tarifi
Usage @1 of @2=Kullanım @1/@2
No recipes=Tarifi yok
No usages=Kullanım yok
Result=Çıktı
Ingredient=Bileşen
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=Ver bana:
This recipe is too@@large to be displayed.=
To craft grid:=Üretim tablosuna kopyala
All=Tümü
Crafting=Üretim
White=Beyaz
Yellow=Sarı
Red=Kırmızı
Green=Yeşil
Blue=Mavi
Waypoints=Konum Noktaları
Select Waypoint #@1=#@1 konum noktası seç
Waypoint @1=@1 Konum Noktaları
Set waypoint to current location=Bulunduğun noktayı işaretle
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=Konum Gösterge Rengi
Edit waypoint name=Konum Noktasını Düzenle
Waypoint active=Konum Etkin
Waypoint inactive=Konum Devredışı
Finish editing=Düzenleme bitti
World position=Dünya konumu
Name=İsim
HUD text color=Metin rengi
##### not used anymore #####
msgid ""=Yaratıcı modu dışında iken bu tuş kullanılamaz.
invisible=görünmez
visible=görünür
Make waypoint @1=Yol noktası @1
@1 display of waypoint coordinates=Yol noktası koordinatlarının görüntülenmesini @1

@ -1,98 +0,0 @@
# textdomain: unified_inventory
Mixing=混合
Cooking=烹饪
Digging=挖出
Bags=背包
Bag @1=背包@1
Small Bag=小背包
Medium Bag=中背包
Large Bag=大背包
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = 和
Scroll categories left=
Scroll categories right=
Search=搜索
Reset search and display everything=重置搜索并显示所有物品
First page=第一页
Back three pages=后退三页
Back one page=后退一页
Forward one page=前进一页
Forward three pages=前进三页
Last page=最后一页
No matching items=没有匹配物品
No matches.=没有匹配
Page=页面
@1 of @2=第@1页共@2页
Filter=过滤器
Can use the creative inventory=可以使用创造背包
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=合成表
Crafting Guide=合成指南
Set home position=设置家的位置
Home position set to: @1=家的位置设置到: @1
You don't have the "home" privilege!=你没有“home”权限
Go home=回家
Set time to day=设置时间到白天
Time of day set to 6am=时间设置到早晨6点
You don't have the settime privilege!=你没有“settime”权限
Set time to night=设置时间到晚上
Time of day set to 9pm=时间设置到晚上9点
Clear inventory=清空背包
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=清空背包
Trash:=丢弃:
Refill:=填满:
Any item belonging to the @1 group=属于@1组的任何项目
Any item belonging to the groups @1=属于组@1的任何项目
Recipe @1 of @2=第@1配方共@2个
Usage @1 of @2=第@1用法共@2个
No recipes=没有配方
No usages=没有用法
Result=结果
Ingredient=原料
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=给予:
This recipe is too@@large to be displayed.=
To craft grid:=填充物品到合成表
All=全部
Crafting=合成
White=白
Yellow=黄
Red=红
Green=绿
Blue=蓝
Waypoints=航路点
Select Waypoint #@1=查询航路点 #@1
Waypoint @1=航路点 @1
Set waypoint to current location=将航路点设置到当前位置
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=改变航路点显示的颜色
Edit waypoint name=编辑航路点名称
Waypoint active=航路点已激活
Waypoint inactive=航路点未激活
Finish editing=完成编辑
World position=世界位置
Name=名称
HUD text color=HUD文本颜色
##### not used anymore #####
invisible=不可见的
visible=可见的
Make waypoint @1=设置航路点 @1
@1 display of waypoint coordinates=显示航路点@1坐标

@ -1,98 +0,0 @@
# textdomain: unified_inventory
Mixing=混合
Cooking=烹飪
Digging=挖出
Bags=揹包
Bag @1=揹包@1
Small Bag=小揹包
Medium Bag=中揹包
Large Bag=大揹包
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
and = 和
Scroll categories left=
Scroll categories right=
Search=搜索
Reset search and display everything=重置搜索並顯示所有物品
First page=第一頁
Back three pages=後退三頁
Back one page=後退一頁
Forward one page=前進一頁
Forward three pages=前進三頁
Last page=最後一頁
No matching items=沒有匹配物品
No matches.=沒有匹配
Page=頁面
@1 of @2=第@1頁共@2頁
Filter=過濾器
Can use the creative inventory=可以使用創造揹包
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
Crafting Grid=合成表
Crafting Guide=合成指南
Set home position=設置家的位置
Home position set to: @1=家的位置設置到: @1
You don't have the "home" privilege!=你沒有“home”權限
Go home=回家
Set time to day=設置時間到白天
Time of day set to 6am=時間設置到早晨6點
You don't have the settime privilege!=你沒有“settime”權限
Set time to night=設置時間到晚上
Time of day set to 9pm=時間設置到晚上9點
Clear inventory=清空揹包
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
Inventory cleared!=清空揹包
Trash:=丟棄:
Refill:=填滿:
Any item belonging to the @1 group=屬於@1組的任何項目
Any item belonging to the groups @1=屬於組@1的任何項目
Recipe @1 of @2=第@1配方共@2個
Usage @1 of @2=第@1用法共@2個
No recipes=沒有配方
No usages=沒有用法
Result=結果
Ingredient=原料
Show next recipe=
Show next usage=
Show previous recipe=
Show previous usage=
@1 (@2)=
Give me:=給予:
This recipe is too@@large to be displayed.=
To craft grid:=填充物品到合成表
All=全部
Crafting=合成
White=白
Yellow=黃
Red=紅
Green=綠
Blue=藍
Waypoints=航路點
Select Waypoint #@1=查詢航路點 #@1
Waypoint @1=航路點 @1
Set waypoint to current location=將航路點設置到當前位置
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Change color of waypoint display=改變航路點顯示的顏色
Edit waypoint name=編輯航路點名稱
Waypoint active=航路點已激活
Waypoint inactive=航路點未激活
Finish editing=完成編輯
World position=世界位置
Name=名稱
HUD text color=HUD文本顏色
##### not used anymore #####
invisible=不可見的
visible=可見的
Make waypoint @1=設置航路點 @1
@1 display of waypoint coordinates=顯示航路點@1座標

@ -1,409 +0,0 @@
-- match_craft.lua
-- Find and automatically move inventory items to the crafting grid
-- according to the recipe.
--[[
Retrieve items from inventory lists and calculate their total count.
Return a table of "item name" - "total count" pairs.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists to use
Example usage:
-- Count items in "main" and "craft" lists of player inventory
unified_inventory.count_items(player_inv_ref, {"main", "craft"})
Example output:
{
["default:pine_wood"] = 2,
["default:acacia_wood"] = 4,
["default:chest"] = 3,
["default:axe_diamond"] = 2, -- unstackable item are counted too
["wool:white"] = 6
}
]]--
function unified_inventory.count_items(inv, lists)
local counts = {}
for i = 1, #lists do
local name = lists[i]
local size = inv:get_size(name)
local list = inv:get_list(name)
for j = 1, size do
local stack = list[j]
if not stack:is_empty() then
local item = stack:get_name()
local count = stack:get_count()
counts[item] = (counts[item] or 0) + count
end
end
end
return counts
end
--[[
Retrieve craft recipe items and their positions in the crafting grid.
Return a table of "craft item name" - "set of positions" pairs.
Note that if craft width is not 3 then positions are recalculated as
if items were placed on a 3x3 grid. Also note that craft can contain
groups of items with "group:" prefix.
Arguments:
craft: minetest craft recipe
Example output:
-- Bed recipe
{
["wool:white"] = {[1] = true, [2] = true, [3] = true}
["group:wood"] = {[4] = true, [5] = true, [6] = true}
}
--]]
function unified_inventory.count_craft_positions(craft)
local positions = {}
local craft_items = craft.items
local craft_type = unified_inventory.registered_craft_types[craft.type]
or unified_inventory.craft_type_defaults(craft.type, {})
local display_width = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft).width
or craft_type.width
local craft_width = craft_type.get_shaped_craft_width
and craft_type.get_shaped_craft_width(craft)
or display_width
local i = 0
for y = 1, 3 do
for x = 1, craft_width do
i = i + 1
local item = craft_items[i]
if item ~= nil then
local pos = 3 * (y - 1) + x
local set = positions[item]
if set ~= nil then
set[pos] = true
else
positions[item] = {[pos] = true}
end
end
end
end
return positions
end
--[[
For every craft item find all matching inventory items.
- If craft item is a group then find all inventory items that matches
this group.
- If craft item is not a group (regular item) then find only this item.
If inventory doesn't contain needed item then found set is empty for
this item.
Return a table of "craft item name" - "set of matching inventory items"
pairs.
Arguments:
inv_items: table with items names as keys
craft_items: table with items names or groups as keys
Example output:
{
["group:wood"] = {
["default:pine_wood"] = true,
["default:acacia_wood"] = true
},
["wool:white"] = {
["wool:white"] = true
}
}
--]]
function unified_inventory.find_usable_items(inv_items, craft_items)
local get_group = minetest.get_item_group
local result = {}
for craft_item in pairs(craft_items) do
local group = craft_item:match("^group:(.+)")
local found = {}
if group ~= nil then
for inv_item in pairs(inv_items) do
if get_group(inv_item, group) > 0 then
found[inv_item] = true
end
end
else
if inv_items[craft_item] ~= nil then
found[craft_item] = true
end
end
result[craft_item] = found
end
return result
end
--[[
Match inventory items with craft grid positions.
For every position select the matching inventory item with maximum
(total_count / (times_matched + 1)) value.
If for some position matching item cannot be found or match count is 0
then return nil.
Return a table of "matched item name" - "set of craft positions" pairs
and overall match count.
Arguments:
inv_counts: table of inventory items counts from "count_items"
craft_positions: table of craft positions from "count_craft_positions"
Example output:
match_table = {
["wool:white"] = {[1] = true, [2] = true, [3] = true}
["default:acacia_wood"] = {[4] = true, [6] = true}
["default:pine_wood"] = {[5] = true}
}
match_count = 2
--]]
function unified_inventory.match_items(inv_counts, craft_positions)
local usable = unified_inventory.find_usable_items(inv_counts, craft_positions)
local match_table = {}
local match_count
local matches = {}
for craft_item, pos_set in pairs(craft_positions) do
local use_set = usable[craft_item]
for pos in pairs(pos_set) do
local pos_item
local pos_count
for use_item in pairs(use_set) do
local count = inv_counts[use_item]
local times_matched = matches[use_item] or 0
local new_pos_count = math.floor(count / (times_matched + 1))
if pos_count == nil or pos_count < new_pos_count then
pos_item = use_item
pos_count = new_pos_count
end
end
if pos_item == nil or pos_count == 0 then
return nil
end
local set = match_table[pos_item]
if set ~= nil then
set[pos] = true
else
match_table[pos_item] = {[pos] = true}
end
matches[pos_item] = (matches[pos_item] or 0) + 1
end
end
for match_item, times_matched in pairs(matches) do
local count = inv_counts[match_item]
local item_count = math.floor(count / times_matched)
if match_count == nil or item_count < match_count then
match_count = item_count
end
end
return match_table, match_count
end
--[[
Remove item from inventory lists.
Return stack of actually removed items.
This function replicates the inv:remove_item function but can accept
multiple lists.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists
stack: minetest item stack
--]]
function unified_inventory.remove_item(inv, lists, stack)
local removed = ItemStack(nil)
local leftover = ItemStack(stack)
for i = 1, #lists do
if leftover:is_empty() then
break
end
local cur_removed = inv:remove_item(lists[i], leftover)
removed:add_item(cur_removed)
leftover:take_item(cur_removed:get_count())
end
return removed
end
--[[
Add item to inventory lists.
Return leftover stack.
This function replicates the inv:add_item function but can accept
multiple lists.
Arguments:
inv: minetest inventory reference
lists: names of inventory lists
stack: minetest item stack
--]]
function unified_inventory.add_item(inv, lists, stack)
local leftover = ItemStack(stack)
for i = 1, #lists do
if leftover:is_empty() then
break
end
leftover = inv:add_item(lists[i], leftover)
end
return leftover
end
--[[
Move items from source list to destination list if possible.
Skip positions specified in exclude set.
Arguments:
inv: minetest inventory reference
src_list: name of source list
dst_list: name of destination list
exclude: set of positions to skip
--]]
function unified_inventory.swap_items(inv, src_list, dst_list, exclude)
local size = inv:get_size(src_list)
local empty = ItemStack(nil)
for i = 1, size do
if exclude == nil or exclude[i] == nil then
local stack = inv:get_stack(src_list, i)
if not stack:is_empty() then
inv:set_stack(src_list, i, empty)
local leftover = inv:add_item(dst_list, stack)
if not leftover:is_empty() then
inv:set_stack(src_list, i, leftover)
end
end
end
end
end
--[[
Move matched items to the destination list.
If destination list position is already occupied with some other item
then function tries to (in that order):
1. Move it to the source list
2. Move it to some other unused position in destination list itself
3. Drop it to the ground if nothing else is possible.
Arguments:
player: minetest player object
src_list: name of source list
dst_list: name of destination list
match_table: table of matched items
amount: amount of items per every position
--]]
function unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
local inv = player:get_inventory()
local item_drop = minetest.item_drop
local src_dst_list = {src_list, dst_list}
local dst_src_list = {dst_list, src_list}
local needed = {}
local moved = {}
-- Remove stacks needed for craft
for item, pos_set in pairs(match_table) do
local stack = ItemStack(item)
local stack_max = stack:get_stack_max()
local bounded_amount = math.min(stack_max, amount)
stack:set_count(bounded_amount)
for pos in pairs(pos_set) do
needed[pos] = unified_inventory.remove_item(inv, dst_src_list, stack)
end
end
-- Add already removed stacks
for pos, stack in pairs(needed) do
local occupied = inv:get_stack(dst_list, pos)
inv:set_stack(dst_list, pos, stack)
if not occupied:is_empty() then
local leftover = unified_inventory.add_item(inv, src_dst_list, occupied)
if not leftover:is_empty() then
inv:set_stack(dst_list, pos, leftover)
local oversize = unified_inventory.add_item(inv, src_dst_list, stack)
if not oversize:is_empty() then
item_drop(oversize, player, player:get_pos())
end
end
end
moved[pos] = true
end
-- Swap items from unused positions to src (moved positions excluded)
unified_inventory.swap_items(inv, dst_list, src_list, moved)
end
--[[
Find craft match and move matched items to the destination list.
If match cannot be found or match count is smaller than the desired
amount then do nothing.
If amount passed is -1 then amount is defined by match count itself.
This is used to indicate "craft All" case.
Arguments:
player: minetest player object
src_list: name of source list
dst_list: name of destination list
craft: minetest craft recipe
amount: desired amount of output items
--]]
function unified_inventory.craftguide_match_craft(player, src_list, dst_list, craft, amount)
local inv = player:get_inventory()
local src_dst_list = {src_list, dst_list}
local counts = unified_inventory.count_items(inv, src_dst_list)
local positions = unified_inventory.count_craft_positions(craft)
local match_table, match_count = unified_inventory.match_items(counts, positions)
if match_table == nil or match_count < amount then
return
end
if amount == -1 then
amount = match_count
end
unified_inventory.move_match(player, src_list, dst_list, match_table, amount)
end

@ -1,6 +0,0 @@
name = unified_inventory
description = """
Unified Inventory replaces the default survival and creative inventory.
It adds a nicer interface and a number of features, such as a crafting guide.
"""
min_minetest_version = 5.4.0

@ -1,21 +1,12 @@
local S = minetest.get_translator("unified_inventory")
local NS = function(s) return s end
local F = minetest.formspec_escape
local ui = unified_inventory
minetest.register_privilege("creative", {
description = S("Can use the creative inventory"),
give_to_singleplayer = false,
})
minetest.register_privilege("ui_full", {
description = S("Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally"),
description = "Can use the creative inventory",
give_to_singleplayer = false,
})
local trash = minetest.create_detached_inventory("trash", {
--allow_put = function(inv, listname, index, stack, player)
-- if ui.is_creative(player:get_player_name()) then
-- if unified_inventory.is_creative(player:get_player_name()) then
-- return stack:get_count()
-- else
-- return 0
@ -29,403 +20,288 @@ local trash = minetest.create_detached_inventory("trash", {
})
trash:set_size("main", 1)
-- ui.register_button("craft", {
-- type = "image",
-- image = "ui_craft_icon.png",
-- tooltip = S("Crafting Grid")
-- })
ui.register_button("clear_inv", {
unified_inventory.register_button("craft", {
type = "image",
image = "ui_trash_icon.png",
tooltip = S("Clear inventory"),
image = "ui_craft_icon.png",
})
unified_inventory.register_button("craftguide", {
type = "image",
image = "ui_craftguide_icon.png",
})
unified_inventory.register_button("home_gui_set", {
type = "image",
image = "ui_sethome_icon.png",
action = function(player)
local player_name = player:get_player_name()
if not ui.is_creative(player_name) then
unified_inventory.set_home(player, player:getpos())
local home = unified_inventory.home_pos[player_name]
if home ~= nil then
minetest.sound_play("dingdong",
{to_player=player_name, gain = 1.0})
minetest.chat_send_player(player_name,
S("This button has been disabled outside"
"Home position set to: "
..minetest.pos_to_string(home))
end
end,
})
unified_inventory.register_button("home_gui_go", {
type = "image",
image = "ui_gohome_icon.png",
action = function(player)
minetest.sound_play("teleport",
{to_player=player:get_player_name(), gain = 1.0})
unified_inventory.go_home(player)
end,
})
unified_inventory.register_button("misc_set_day", {
type = "image",
image = "ui_sun_icon.png",
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("birds",
{to_player=player_name, gain = 1.0})
minetest.set_timeofday((6000 % 24000) / 24000)
minetest.chat_send_player(player_name,
"Time of day set to 6am")
else
minetest.chat_send_player(player_name,
"You don't have the"
.." settime priviledge!")
end
end,
})
unified_inventory.register_button("misc_set_night", {
type = "image",
image = "ui_moon_icon.png",
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("owl",
{to_player=player_name, gain = 1.0})
minetest.set_timeofday((21000 % 24000) / 24000)
minetest.chat_send_player(player_name,
"Time of day set to 9pm")
else
minetest.chat_send_player(player_name,
"You don't have the"
.." settime priviledge!")
end
end,
})
unified_inventory.register_button("clear_inv", {
type = "image",
image = "ui_trash_icon.png",
action = function(player)
local player_name = player:get_player_name()
if not unified_inventory.is_creative(player_name) then
minetest.chat_send_player(player_name,
"This button has been disabled outside"
.." of creative mode to prevent"
.." accidental inventory trashing."
.."\nUse the trash slot instead."))
ui.set_inventory_formspec(player, ui.current_page[player_name])
.." Use the trash slot instead.")
return
end
player:get_inventory():set_list("main", {})
minetest.chat_send_player(player_name, S('Inventory cleared!'))
minetest.chat_send_player(player_name, 'Inventory Cleared!')
minetest.sound_play("trash_all",
{to_player=player_name, gain = 1.0})
end,
condition = function(player)
return ui.is_creative(player:get_player_name())
})
unified_inventory.register_page("craft", {
get_formspec = function(player, formspec)
local player_name = player:get_player_name()
local formspec = "background[0,1;8,3;ui_crafting_form.png]"
formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]"
formspec = formspec.."image[0,0;1,1;ui_craft_icon.png]"
formspec = formspec.."label[1,0;Crafting]"
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec.."list[current_player;craftpreview;6,1;1,1;]"
formspec = formspec.."list[current_player;craft;2,1;3,3;]"
formspec = formspec.."label[7,2.5;Trash:]"
formspec = formspec.."list[detached:trash;main;7,3;1,1;]"
if unified_inventory.is_creative(player_name) then
formspec = formspec.."label[0,2.5;Refill:]"
formspec = formspec.."list[detached:"..player_name.."refill;main;0,3;1,1;]"
end
return {formspec=formspec}
end,
})
ui.register_page("craft", {
get_formspec = function(player, perplayer_formspec)
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y
local craftx = perplayer_formspec.craft_x
local crafty = perplayer_formspec.craft_y
unified_inventory.register_page("craftguide", {
get_formspec = function(player)
local player_name = player:get_player_name()
local formspec = {
perplayer_formspec.standard_inv_bg,
}
local formspec2 = {
perplayer_formspec.craft_grid,
"label["..formheaderx..","..formheadery..";" ..F(S("Crafting")).."]",
"listcolors[#00000000;#00000000]",
"listring[current_name;craft]",
"listring[current_player;main]",
string.format("label[%f,%f;%s]", craftx + 6.45, crafty + 2.4, F(S("Trash:"))),
ui.make_trash_slot(craftx + 6.25, crafty + 2.5),
ui.single_slot(craftx - 2.5, crafty + 2.5),
string.format("label[%f,%f;%s]", craftx - 2.3, crafty + 2.4,F(S("Refill:"))),
string.format("list[detached:%srefill;main;%f,%f;1,1;]", F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset),
}
local n=#formspec+1
if ui.is_creative(player_name) then
--copy formspec2 to formspec
for i=1,#formspec2 do
formspec[n]=formspec2[i]
n = n+1
local formspec = "background[0,1;8,3;ui_craftguide_form.png]"
formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]"
formspec = formspec.."image[0,0;1,1;ui_craftguide_icon.png]"
formspec = formspec.."label[1,0;Crafting Guide]"
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec.."list[detached:"..player_name.."craftrecipe;output;6,1;1,1;]"
formspec = formspec.."label[6,3.35;Method:]"
local item_name = unified_inventory.current_item[player_name]
local craft = nil
if item_name then
formspec = formspec.."textarea[1.3,0.6;10,1;;Result: "..item_name..";]"
local alternates = 0
local alternate = unified_inventory.alternate[player_name]
local crafts = unified_inventory.crafts_table[item_name]
if crafts ~= nil and #crafts > 0 then
alternates = #crafts
craft = crafts[alternate]
local method = craft.type
local allow_auto_craft = ((method == "normal") or (method == "shapeless"))
if craft.type == "normal" then
method = "crafting"
elseif craft.type == "shapeless" then
method = "shapeless crafting"
elseif craft.type == "alloy" then
method = "alloy cooking"
end
formspec = formspec.."label[6,3.75;"..method.."]"
if allow_auto_craft then
formspec = formspec.."label[6,1.95;Copy to craft grid:]"
.."button[6,2.5;0.6,0.5;craftguide_craft_1;1]"
.."button[6.6,2.5;0.6,0.5;craftguide_craft_10;10]"
.."button[7.2,2.5;0.6,0.5;craftguide_craft_max;All]"
end
end
if alternates > 1 then
formspec = formspec.."label[0,2.6;Recipe "
..tostring(alternate).." of "
..tostring(alternates).."]"
.."button[0,3.15;2,1;alternate;Alternate]"
end
end
return {formspec=table.concat(formspec)}
end,
})
-- stack_image_button(): generate a form button displaying a stack of items
--
-- The specified item may be a group. In that case, the group will be
-- represented by some item in the group, along with a flag indicating
-- that it's a group. If the group contains only one item, it will be
-- treated as if that item had been specified directly.
local function stack_image_button(x, y, w, h, buttonname_prefix, item)
local name = item:get_name()
local count = item:get_count()
local wear = item:get_wear()
local description = item:get_meta():get_string("description")
local show_is_group = false
local displayitem = name.." "..count.." "..wear
local selectitem = name
if name:sub(1, 6) == "group:" then
local group_name = name:sub(7)
local group_item = ui.get_group_item(group_name)
show_is_group = not group_item.sole
displayitem = group_item.item or "unknown"
selectitem = group_item.sole and displayitem or name
end
local label = show_is_group and "G" or ""
-- Unique id to prevent tooltip being overridden
local id = string.format("%i%i_", x*10, y*10)
local buttonname = F(id..buttonname_prefix..ui.mangle_for_formspec(selectitem))
local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]",
x, y, w, h,
F(displayitem), buttonname, label)
if show_is_group then
local groupstring, andcount = ui.extract_groupnames(name)
local grouptip
if andcount == 1 then
grouptip = S("Any item belonging to the @1 group", groupstring)
elseif andcount > 1 then
grouptip = S("Any item belonging to the groups @1", groupstring)
end
grouptip = F(grouptip)
if andcount >= 1 then
button = button .. string.format("tooltip[%s;%s]", buttonname, grouptip)
end
elseif description ~= "" then
button = button .. string.format("tooltip[%s;%s]", buttonname, F(description))
end
return button
end
local recipe_text = {
recipe = NS("Recipe @1 of @2"),
usage = NS("Usage @1 of @2"),
}
local no_recipe_text = {
recipe = S("No recipes"),
usage = S("No usages"),
}
local role_text = {
recipe = S("Result"),
usage = S("Ingredient"),
}
local next_alt_text = {
recipe = S("Show next recipe"),
usage = S("Show next usage"),
}
local prev_alt_text = {
recipe = S("Show previous recipe"),
usage = S("Show previous usage"),
}
local other_dir = {
recipe = "usage",
usage = "recipe",
}
ui.register_page("craftguide", {
get_formspec = function(player, perplayer_formspec)
local craftguidex = perplayer_formspec.craft_guide_x
local craftguidey = perplayer_formspec.craft_guide_y
local craftguidearrowx = perplayer_formspec.craft_guide_arrow_x
local craftguideresultx = perplayer_formspec.craft_guide_result_x
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y
local give_x = perplayer_formspec.give_btn_x
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
local formspec = {
perplayer_formspec.standard_inv_bg,
"label["..formheaderx..","..formheadery..";" .. F(S("Crafting Guide")) .. "]",
"listcolors[#00000000;#00000000]"
}
local item_name = ui.current_item[player_name]
if not item_name then
return { formspec = table.concat(formspec) }
end
local n = 4
local item_name_shown
if minetest.registered_items[item_name]
and minetest.registered_items[item_name].description then
item_name_shown = S("@1 (@2)",
minetest.registered_items[item_name].description, item_name)
else
item_name_shown = item_name
end
local dir = ui.current_craft_direction[player_name]
local rdir = dir == "recipe" and "usage" or "recipe"
local crafts = ui.crafts_for[dir][item_name]
local alternate = ui.alternate[player_name]
local alternates, craft
if crafts and #crafts > 0 then
alternates = #crafts
craft = crafts[alternate]
end
local has_give = player_privs.give or ui.is_creative(player_name)
formspec[n] = string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
craftguidearrowx, craftguidey, ui.imgscale, ui.imgscale)
formspec[n+1] = string.format("textarea[%f,%f;10,1;;%s: %s;]",
perplayer_formspec.craft_guide_resultstr_x, perplayer_formspec.craft_guide_resultstr_y,
F(role_text[dir]), item_name_shown)
n = n + 2
local giveme_form = table.concat({
"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]",
"button["..(give_x)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_1;1]",
"button["..(give_x+0.8)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_10;10]",
"button["..(give_x+1.6)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]"
local craftinv = minetest.get_inventory({
type = "detached",
name = player_name.."craftrecipe"
})
-- fake buttons just to make 3x3 grid
for y = 1, 3 do
for x = 1, 3 do
formspec = formspec.."image_button["
..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;ui_blank_image.png;;]"
end
end
if not craft then
-- No craft recipes available for this item.
formspec[n] = string.format("label[%f,%f;%s]", craftguidex+2.5, craftguidey+1.5, F(no_recipe_text[dir]))
local no_pos = dir == "recipe" and (craftguidex+2.5) or craftguideresultx
local item_pos = dir == "recipe" and craftguideresultx or (craftguidex+2.5)
formspec[n+1] = "image["..no_pos..","..craftguidey..";1.2,1.2;ui_no.png]"
formspec[n+2] = stack_image_button(item_pos, craftguidey, 1.2, 1.2,
"item_button_" .. other_dir[dir] .. "_", ItemStack(item_name))
if has_give then
formspec[n+3] = giveme_form
end
return { formspec = table.concat(formspec) }
else
formspec[n] = stack_image_button(craftguideresultx, craftguidey, 1.2, 1.2,
"item_button_" .. rdir .. "_", ItemStack(craft.output))
n = n + 1
craftinv:set_stack("output", 1, nil)
return {formspec=formspec}
end
local craft_type = ui.registered_craft_types[craft.type] or
ui.craft_type_defaults(craft.type, {})
if craft_type.icon then
formspec[n] = string.format("image[%f,%f;%f,%f;%s]",
craftguidearrowx+0.35, craftguidey, 0.5, 0.5, craft_type.icon)
n = n + 1
end
formspec[n] = string.format("label[%f,%f;%s]", craftguidearrowx + 0.15, craftguidey + 1.4, F(craft_type.description))
n = n + 1
craftinv:set_stack("output", 1, craft.output)
local display_size = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft)
or { width = craft_type.width, height = craft_type.height }
local craft_width = craft_type.get_shaped_craft_width
and craft_type.get_shaped_craft_width(craft)
or display_size.width
-- This keeps recipes aligned to the right,
-- so that they're close to the arrow.
local xoffset = craftguidex+3.75
local bspc = 1.25
-- Offset factor for crafting grids with side length > 4
local of = (3/math.max(3, math.max(display_size.width, display_size.height)))
local od = 0
-- Minimum grid size at which size optimization measures kick in
local mini_craft_size = 6
if display_size.width >= mini_craft_size then
od = math.max(1, display_size.width - 2)
xoffset = xoffset - 0.1
local width = craft.width
if width == 0 then
-- Shapeless recipe
width = 3
end
-- Size modifier factor
local sf = math.min(1, of * (1.05 + 0.05*od))
-- Button size
local bsize = 1.2 * sf
if display_size.width >= mini_craft_size then -- it's not a normal 3x3 grid
bsize = 0.8 * sf
end
if (bsize > 0.35 and display_size.width) then
for y = 1, display_size.height do
for x = 1, display_size.width do
local item
if craft and x <= craft_width then
item = craft.items[(y-1) * craft_width + x]
end
-- Flipped x, used to build formspec buttons from right to left
local fx = display_size.width - (x-1)
-- x offset, y offset
local xof = ((fx-1) * of + of) * bspc
local yof = ((y-1) * of + 1) * bspc
local i = 1
for y = 1, 3 do
for x = 1, width do
local item = craft.items[i]
if item then
formspec[n] = stack_image_button(
xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize,
"item_button_recipe_",
ItemStack(item))
else
-- Fake buttons just to make grid
formspec[n] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]",
xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize)
if string.sub(item, 1, 6) == "group:" then
local group = string.sub(item, 7)
formspec = formspec.."image_button["
..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;"
.."ui_group.png;"
.."item_group_"..minetest.formspec_escape(group)..";"
..minetest.formspec_escape(group).."]"
else
formspec = formspec.."item_image_button["
..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;"
..minetest.formspec_escape(item)..";"
.."item_button_"
..minetest.formspec_escape(item)..";]"
end
end
n = n + 1
i = i + 1
end
end
else
-- Error
formspec[n] = string.format("label[2,%f;%s]",
craftguidey, F(S("This recipe is too@nlarge to be displayed.")))
n = n + 1
end
if craft_type.uses_crafting_grid and display_size.width <= 3 then
formspec[n] = "label["..(give_x+0.1)..",".. (craftguidey + 1.7) .. ";" .. F(S("To craft grid:")) .. "]"
formspec[n+1] = "button[".. (give_x)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_1;1]"
formspec[n+2] = "button[".. (give_x+0.8)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_10;10]"
formspec[n+3] = "button[".. (give_x+1.6)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_max;" .. F(S("All")) .. "]"
n = n + 4
end
if has_give then
formspec[n] = giveme_form
n = n + 1
end
if alternates and alternates > 1 then
formspec[n] = string.format("label[%f,%f;%s]",
craftguidex+4, craftguidey + 2.3, F(S(recipe_text[dir], alternate, alternates)))
formspec[n+1] = string.format("image_button[%f,%f;1.1,1.1;ui_left_icon.png;alternate_prev;]",
craftguidearrowx+0.2, craftguidey + 2.6)
formspec[n+2] = string.format("image_button[%f,%f;1.1,1.1;ui_right_icon.png;alternate;]",
craftguidearrowx+1.35, craftguidey + 2.6)
formspec[n+3] = "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]"
formspec[n+4] = "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]"
end
return { formspec = table.concat(formspec) }
return {formspec=formspec}
end,
})
local function craftguide_giveme(player, formname, fields)
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
if not player_privs.give and
not ui.is_creative(player_name) then
minetest.log("action", "[unified_inventory] Denied give action to player " ..
player_name)
return
end
local amount
for k, v in pairs(fields) do
amount = k:match("craftguide_giveme_(.*)")
if amount then break end
end
amount = tonumber(amount) or 0
if amount == 0 then return end
local output = ui.current_item[player_name]
if (not output) or (output == "") then return end
local player_inv = player:get_inventory()
player_inv:add_item("main", {name = output, count = amount})
end
local function craftguide_craft(player, formname, fields)
minetest.register_on_player_receive_fields(function(player, formname, fields)
local amount
for k, v in pairs(fields) do
amount = k:match("craftguide_craft_(.*)")
if amount then break end
end
if not amount then return end
amount = tonumber(amount) or -1 -- fallback for "all"
if amount == 0 or amount < -1 or amount > 99 then return end
local player_name = player:get_player_name()
local recipe_inv = minetest.get_inventory({
type="detached",
name=player_name.."craftrecipe",
})
local output = ui.current_item[player_name] or ""
if output == "" then return end
local output = unified_inventory.current_item[player_name]
if (not output) or (output == "") then return end
local crafts = ui.crafts_for[
ui.current_craft_direction[player_name]][output] or {}
if #crafts == 0 then return end
local player_inv = player:get_inventory()
local alternate = ui.alternate[player_name]
local crafts = unified_inventory.crafts_table[output]
if (not crafts) or (#crafts == 0) then return end
local alternate = unified_inventory.alternate[player_name]
local craft = crafts[alternate]
if not craft.width then
if not craft.output then
minetest.log("warning", "[unified_inventory] Craft has no output.")
else
minetest.log("warning", ("[unified_inventory] Craft for '%s' has no width."):format(craft.output))
end
return
end
if craft.width > 3 then return end
ui.craftguide_match_craft(player, "main", "craft", craft, amount)
local needed = craft.items
ui.set_inventory_formspec(player, "craft")
end
local craft_list = player_inv:get_list("craft")
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
local width = craft.width
if width == 0 then
-- Shapeless recipe
width = 3
end
for k, v in pairs(fields) do
if k:match("craftguide_craft_") then
craftguide_craft(player, formname, fields)
return
end
if k:match("craftguide_giveme_") then
craftguide_giveme(player, formname, fields)
return
if amount == "max" then
amount = 99 -- Arbitrary; need better way to do this.
else
amount = tonumber(amount)
end
for iter = 1, amount do
local index = 1
for y = 1, 3 do
for x = 1, width do
local needed_item = needed[index]
if needed_item then
local craft_index = ((y - 1) * 3) + x
local craft_item = craft_list[craft_index]
if (not craft_item) or (craft_item:is_empty()) or (craft_item:get_name() == needed_item) then
itemname = craft_item and craft_item:get_name() or needed_item
local needed_stack = ItemStack(needed_item)
if player_inv:contains_item("main", needed_stack) then
local count = (craft_item and craft_item:get_count() or 0) + 1
if count <= needed_stack:get_definition().stack_max then
local stack = ItemStack({name=needed_item, count=count})
craft_list[craft_index] = stack
player_inv:remove_item("main", needed_stack)
end
end
end
end
index = index + 1
end
end
end
player_inv:set_list("craft", craft_list)
unified_inventory.set_inventory_formspec(player, "craft")
end)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

@ -1,14 +0,0 @@
#Enabling lite mode enables a smaller and simpler version of the Unified
#Inventory, optimized for small displays.
unified_inventory_lite (Lite mode) bool false
#If enabled, bags will be made available which can be used to extend
#inventory storage size.
unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative
#and the give privilege.
unified_inventory_trash (Enable trash) bool true
unified_inventory_automatic_categorization (Items automatically added to categories) bool true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 B

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 928 B

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 B

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
textures/ui_cancel_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
textures/ui_form_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
textures/ui_misc_form.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
textures/ui_xyz_on_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

208
waypoints.lua Normal file

@ -0,0 +1,208 @@
unified_inventory.hud_colors = {
{"#FFFFFF", 0xFFFFFF, "White"},
{"#DBBB00", 0xf1d32c, "Yellow"},
{"#DD0000", 0xDD0000, "Red"},
{"#2cf136", 0x2cf136, "Green"},
{"#2c4df1", 0x2c4df1, "Blue"},
}
unified_inventory.hud_colors_max = #unified_inventory.hud_colors
unified_inventory.register_page("waypoints", {
get_formspec = function(player)
local waypoints = datastorage.get_container (player, "waypoints")
local formspec = "background[0,4.5;8,4;ui_main_inventory.png]"..
"image[0,0;1,1;ui_waypoints_icon.png]"..
"label[1,0;Waypoints]"
-- Tabs buttons:
local i
for i = 1, 5, 1 do
if i == waypoints.selected then
formspec = formspec ..
"image_button[0.0,".. 0.2 + i*0.7 ..";.8,.8;ui_blue_icon_background.png^ui_"..
i .."_icon.png;select_waypoint".. i .. ";]"
else
formspec = formspec ..
"image_button[0.0,".. 0.2 + i*0.7 ..";.8,.8;ui_"..
i .."_icon.png;select_waypoint".. i .. ";]"
end
end
i = waypoints.selected
-- Main buttons:
formspec = formspec ..
"image_button[4.5,3.7;.8,.8;ui_waypoint_set_icon.png;set_waypoint".. i .. ";]"
if waypoints[i].active then
formspec = formspec ..
"image_button[5.2,3.7;.8,.8;ui_on_icon.png;toggle_waypoint".. i .. ";]"
else
formspec = formspec ..
"image_button[5.2,3.7;.8,.8;ui_off_icon.png;toggle_waypoint".. i .. ";]"
end
if waypoints[i].display_pos then
formspec = formspec ..
"image_button[5.9,3.7;.8,.8;ui_green_icon_background.png^ui_xyz_icon.png;toggle_display_pos".. i .. ";]"
else
formspec = formspec ..
"image_button[5.9,3.7;.8,.8;ui_red_icon_background.png^ui_xyz_icon.png;toggle_display_pos".. i .. ";]"
end
formspec = formspec ..
"image_button[6.6,3.7;.8,.8;ui_circular_arrows_icon.png;toggle_color".. i .. ";]"..
"image_button[7.3,3.7;.8,.8;ui_pencil_icon.png;rename_waypoint".. i .. ";]"
-- Waypoint's info:
if waypoints[i].active then
formspec = formspec .. "label[1,0.8;Waypoint active]"
else
formspec = formspec .. "label[1,0.8;Waypoint inactive]"
end
formspec = formspec .. "label[1,1.3;World position: " ..
minetest.pos_to_string(waypoints[i].world_pos) .. "]" ..
"label[1,1.8;Name: ]".. waypoints[i].name .. "]" ..
"label[1,2.3;Hud text color: " ..
unified_inventory.hud_colors[waypoints[i].color][3] .. "]"
return {formspec=formspec}
end,
})
unified_inventory.register_button("waypoints", {
type = "image",
image = "ui_waypoints_icon.png",
})
unified_inventory.update_hud = function (player, waypoint)
local name
if waypoint.display_pos then
name = "("..
waypoint.world_pos.x .. "," ..
waypoint.world_pos.y .. "," ..
waypoint.world_pos.z .. ")"
if waypoint.name ~= "" then
name = name .. ", " ..
waypoint.name
end
else
name = waypoint.name
end
if waypoint.active then
player:hud_remove(waypoint.hud)
waypoint.hud = player:hud_add({
hud_elem_type = "waypoint",
number = unified_inventory.hud_colors[waypoint.color][2] ,
name = name,
text = "m",
world_pos = waypoint.world_pos
})
else
if waypoint.hud ~= nil then
player:hud_remove(waypoint.hud)
waypoint.hud = nil
end
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
end
local update_formspec = false
local update_hud = false
local waypoints = datastorage.get_container (player, "waypoints")
for i = 1, 5, 1 do
if fields["select_waypoint"..i] then
waypoints.selected = i
update_formspec = true
end
if fields["toggle_waypoint"..i] then
waypoints[i].active = not (waypoints[i].active)
update_hud = true
update_formspec = true
end
if fields["set_waypoint"..i] then
local pos = player:getpos()
pos.x = math.floor(pos.x)
pos.y = math.floor(pos.y)
pos.z = math.floor(pos.z)
waypoints[i].world_pos = pos
update_hud = true
update_formspec = true
end
if fields["rename_waypoint"..i] then
waypoints[i].edit = true
update_formspec = true
end
if fields["toggle_display_pos"..i] then
waypoints[i].display_pos = not waypoints[i].display_pos
update_hud = true
update_formspec = true
end
if fields["toggle_color"..i] then
local color = waypoints[i].color
color = color + 1
if color > unified_inventory.hud_colors_max then
color = 1
end
waypoints[i].color = color
update_hud = true
update_formspec = true
end
if fields["confirm_rename"..i] then
waypoints[i].edit = false
waypoints[i].name = fields["rename_box"..i]
update_hud = true
update_formspec = true
end
if update_hud then
unified_inventory.update_hud (player, waypoints[i])
end
if update_formspec then
unified_inventory.set_inventory_formspec(player, "waypoints")
end
end
end)
minetest.register_on_joinplayer(function(player)
local waypoints = datastorage.get_container (player, "waypoints")
-- Create new waypoints data
if waypoints[1] == nil then
for i = 1, 5, 1 do
waypoints[i] = {
edit = false,
active = false,
display_pos = true,
color = 2,
name = "Waypoint ".. i,
world_pos = {x = 0, y = 0, z = 0},
}
end
datastorage.save_container(player)
end
-- Initialize waypoints
minetest.after(0.5, function()
waypoints.selected = 1
for i = 1, 5, 1 do
waypoints[i].edit = false
unified_inventory.update_hud (player, waypoints[i])
end
end)
end)