54 Commits

Author SHA1 Message Date
99bdfe9e14 Merge remote-tracking branch 'upstream/master' 2025-03-20 12:54:30 +01:00
43cf0d8e7e Fix error when clicking unknown item in the recipe (#255) 2024-12-09 17:40:40 +01:00
e132a17523 Russian locale update (#253) 2024-11-26 17:49:43 +01:00
6f132186ab Merge remote-tracking branch 'upstream/master' 2024-09-15 12:57:15 +02:00
e071a01372 Giveme form: Respect stack_max (#250) 2024-08-25 13:36:13 +02:00
1547ebcdd4 Make waypoints usable from lite mode (#251) 2024-08-13 20:00:49 +02:00
16265dca2d Item names: fix HUD deprecation warning 2024-07-18 20:45:24 +02:00
235fa841dd Replace deprecated meta:set_string(*, nil) call 2024-06-29 16:52:32 +02:00
2c9449b6e7 Categories: Remove not_in_creative_inventory items
`unified_inventory.is_itemdef_listable` already prevents such items
being listed. They are not needed, thus removing them from the
categories in the first place does make sense.

Co-authored-by: SmallJoker <mk939@ymail.com>
2024-03-23 12:31:04 +01:00
b5de18b196 Categories: remove unknown items after start
This avoids runtime errors caused by removed items
or such that were not registered at all but listed
by default in a pre-defined category.
2024-03-17 16:54:21 +01:00
921a6d76ee Add dump function to luacheck 2024-01-13 10:47:05 +01:00
004a39aaf7 Categories: Improve automatic ore categorization
This function is now executed after registering all recipes
within unified_inventory to properly register all item drops
as ores.
2024-01-13 10:40:25 +01:00
eb3bb03ebf Option to hide uncraftable items (#240)
This setting only applies to non-creative players.
2024-01-06 12:35:54 +01:00
e7d03626b4 Categories: fix error caused by inexistent ore names 2023-12-24 12:18:40 +01:00
cb6e602497 Merge remote-tracking branch 'github/master' 2023-11-25 15:40:23 +01:00
693ca112b8 Add setting to disable waypoints 2023-11-20 17:54:44 +01:00
380b77d0fb Improve settings descriptions 2023-11-20 17:51:34 +01:00
43c9b50800 Add unified_inventory_enable_item_names setting (#235)
Show only names settings: in case of multi-line descriptions, only the first line is shown
Shorten long descriptions: Removes all characters after x index, and add `[...]`
Max length before truncation: x for Shorten long descriptions
Notes: If Max length == 0, then item names won't be displayed
2023-10-15 21:02:35 +02:00
5d233a0f0a Clean itemname before checking existence (#234)
important when the item string contains metadata
2023-07-11 18:12:35 +02:00
2426b6c912 Full polish translation (#231) 2023-06-24 08:43:04 +02:00
d6d4bea819 Bags: Prevent error caused by moving the opened bag 2023-06-18 18:48:15 +02:00
aa04d4539f Merge remote-tracking branch 'github/master' 2023-06-07 22:58:05 +02:00
15d729c351 Waypoints: Add teleportation button
This also adds button click sounds and makes use of the teleport sound for consistency.
2023-06-06 19:41:03 +02:00
b2cc3d1532 Fix search not working after page flip 2023-01-27 15:57:28 +01:00
37969b2a1b Make bags support lite mode 2023-01-12 22:16:06 +01:00
1b074828a6 Document and replace sounds
A few sounds were replaced because I could not find them on freesound.org
2023-01-10 21:27:56 +01:00
de0063835c Purge recipes with invalid ingredients 2023-01-09 17:42:41 +01:00
bda9f2598f Improve group matching for 'copy to craft' 2023-01-09 17:42:41 +01:00
b590764026 Centre page number label and move refill/trash labels (#221)
* Centre page number label

* Move refill and trash labels
2023-01-04 14:35:46 +01:00
82cdf24045 Improve scroll height calculation (#220) 2022-12-30 21:43:46 +01:00
31c35dcd59 Remove dependency on farming (#219)
Avoids circular dependencies of 3rd party mods with unified_inventory -> farming -> stairs.
2022-12-12 17:45:53 +01:00
826d5f4683 Add setting to hide disabled buttons (#217) 2022-10-26 10:05:03 +02:00
db1c3c10b8 API doc: use Minetest style 2022-10-05 21:07:41 +02:00
9533200e25 Tidy and comment filtering functions 2022-10-05 21:07:11 +02:00
177debd13c Bags: Disallow moving bags into themselves
Previously, the bag and its list would disappear immediately.
2022-09-15 12:53:41 +02:00
8e9ea34ae8 Elaborate the use of NS() 2022-09-15 10:56:01 +02:00
574de91971 Craft guide: Add support for colored items (#213) 2022-09-15 10:48:29 +02:00
fc562ecaa0 Update German translation (#211)
Added categories, waypoint etc. translations updated, inventory trashing button still missing
2022-09-04 18:35:00 +02:00
a977ec47fd Merge remote-tracking branch 'upstream/master' 2022-08-26 15:24:41 +02:00
182ab493c3 Update CN translation 2022-07-29 21:42:59 +02:00
8c56e27c94 Merge remote-tracking branch 'github/master' 2022-05-27 18:54:23 +02:00
14da1a3dd0 Fix reverse item lookup ("usage") broken by 5ac2558
> return { specname }

This returned a number-indexed table whereas the code expects a name-indexed table
2022-04-22 22:01:15 +02:00
fa079c31b6 Obligatory screenshot update 2022-04-11 20:11:31 +02:00
c1fef26c87 Fix error caused by slow starts and mod dependencies 2022-04-11 19:42:06 +02:00
477acd2f89 Change background to rounded corners (#200)
This change is supposed to match the rounded inventory slot design.
2022-04-03 22:30:21 +02:00
19efce45ed Revert "Remove mod name from tooltips"
This reverts commit 64b0248c77.

The mod name may differ from the item name, in which cases it is
helpful to have this information contained in the tooltip.
No information is shown in case the mod name is missing.
2022-03-20 13:45:59 +01:00
6da71e1819 Merge remote-tracking branch 'upstream/master' 2022-03-05 11:37:32 +01:00
dbe06be68b Add scroll bar for overflowing tab buttons (#195) 2022-02-26 11:41:15 +01:00
3074d625e2 Version 4: Feature checks and deprecate internal functions 2022-02-26 11:38:45 +01:00
5ac2558da4 Speed up group filtering code
This improves the startup time dramatically by lowering the algorithm complexity.
Mainly noticeable with large inventory sizes.

Written by Test_User, post-edited by SmallJoker
2022-02-26 11:03:21 +01:00
25c40fea6c Fix filter reset for empty search boxes 2022-01-24 15:20:57 +01:00
23a45b8131 Only update formspec on search filter changes 2022-01-23 18:15:17 +01:00
9649c0ed0e Merge remote-tracking branch 'github/master' 2022-01-22 20:08:35 +01:00
d6688872c8 Fix two occasional runtime errors (#191) 2021-12-25 17:31:18 +01:00
32 changed files with 928 additions and 595 deletions

View File

@ -10,6 +10,7 @@ read_globals = {
string = {fields = {"split", "trim"}}, string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn"}}, table = {fields = {"copy", "getn"}},
"dump",
"minetest", "vector", "minetest", "vector",
"ItemStack", "datastorage", "ItemStack", "datastorage",

View File

@ -71,6 +71,9 @@ From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.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_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html)
From https://www.svgrepo.com (CC-BY)
* [`ui_teleport.png`](https://www.svgrepo.com/svg/321565/teleport)
Everaldo Coelho (YellowIcon) (LGPL v2.1+): Everaldo Coelho (YellowIcon) (LGPL v2.1+):
* [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png) * [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png)
@ -102,3 +105,16 @@ Other files from Wikimedia Commons:
RealBadAngel: (CC-BY-4.0) RealBadAngel: (CC-BY-4.0)
* Everything else. * Everything else.
## Sounds
* [`bell.ogg`](https://freesound.org/people/bennstir/sounds/81072/) by bennstir, CC 4.0
* [`electricity.ogg`](https://freesound.org/people/Halleck/sounds/19486/) by Halleck, CC 4.0 (cut)
* [`pageflip1.ogg`](https://freesound.org/people/themfish/sounds/45823/) by themfish, CC 4.0 (cut, slowed down)
* `pageflip2.ogg` (derived from `pageflip1.ogg`)
* [`trash.ogg`](https://freesound.org/people/OwlStorm/sounds/151231/) by OwlStorm, CC 0 (speed up)
* [`trash_all.ogg`](https://freesound.org/people/abel_K/sounds/68280/) by abel_K, Sampling Plus 1.0 (speed up)
* [`ui_click.ogg`](https://freesound.org/people/lartti/sounds/527569/) by lartti, CC 0 (cut)
* [`ui_morning.ogg`](https://freesound.org/people/InspectorJ/sounds/439472/) by InspectorJ, CC 4.0
* [`ui_owl.ogg`](https://freesound.org/people/manda_g/sounds/54987/) by manda_g, Sampling Plus 1.0 (cut)

147
api.lua
View File

@ -2,48 +2,61 @@ local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory local ui = unified_inventory
local function is_recipe_craftable(recipe)
-- Ensure the ingedients exist
for _, itemname in pairs(recipe.items) do
local groups = string.find(itemname, "group:")
if groups then
if not ui.get_group_item(string.sub(groups, 8)).item then
return false
end
else
-- Possibly an item
local itemname_cleaned = ItemStack(itemname):get_name()
if not minetest.registered_items[itemname_cleaned]
or minetest.get_item_group(itemname_cleaned, "not_in_craft_guide") ~= 0 then
return false
end
end
end
return true
end
-- Create detached creative inventory after loading all mods -- Create detached creative inventory after loading all mods
minetest.after(0.01, function() minetest.after(0.01, function()
local rev_aliases = {} local rev_aliases = {}
for source, target in pairs(minetest.registered_aliases) do for original, newname in pairs(minetest.registered_aliases) do
if not rev_aliases[target] then rev_aliases[target] = {} end if not rev_aliases[newname] then
table.insert(rev_aliases[target], source) rev_aliases[newname] = {}
end end
table.insert(rev_aliases[newname], original)
end
-- Filtered item list
ui.items_list = {} ui.items_list = {}
for name, def in pairs(minetest.registered_items) do for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or if ui.is_itemdef_listable(def) then
def.groups.not_in_creative_inventory == 0) and
def.description and def.description ~= "" then
table.insert(ui.items_list, name) table.insert(ui.items_list, name)
-- Alias processing: Find recipes that belong to the current item name
local all_names = rev_aliases[name] or {} local all_names = rev_aliases[name] or {}
table.insert(all_names, name) table.insert(all_names, name)
for _, player_name in ipairs(all_names) do for _, itemname in ipairs(all_names) do
local recipes = minetest.get_all_craft_recipes(player_name) local recipes = minetest.get_all_craft_recipes(itemname)
if recipes then for _, recipe in ipairs(recipes or {}) do
for _, recipe in ipairs(recipes) do if is_recipe_craftable(recipe) then
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) ui.register_craft(recipe)
end end
end end
end end
end end
end end
end
table.sort(ui.items_list) table.sort(ui.items_list)
ui.items_list_size = #ui.items_list ui.items_list_size = #ui.items_list
print("Unified Inventory. inventory size: "..ui.items_list_size) print("Unified Inventory. Inventory size: "..ui.items_list_size)
-- Analyse dropped items -> custom "digging" recipes
for _, name in ipairs(ui.items_list) do for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name] local def = minetest.registered_items[name]
-- Simple drops -- Simple drops
@ -133,33 +146,82 @@ minetest.after(0.01, function()
end end
end end
end end
for _, recipes in pairs(ui.crafts_for.recipe) do
-- Step 1: Initialize cache for looking up groups
unified_inventory.init_matching_cache()
-- Step 2: Find all matching items for the given spec (groups)
local get_matching_spec_items = unified_inventory.get_matching_items
for outputitemname, recipes in pairs(ui.crafts_for.recipe) do
-- List of crafts that return this item string (variable "_")
-- Problem: The group cache must be initialized after all mods finished loading
-- thus, invalid recipes might be indexed. Hence perform filtering with `new_recipe_list`
local new_recipe_list = {}
for _, recipe in ipairs(recipes) do for _, recipe in ipairs(recipes) do
local ingredient_items = {} local ingredient_items = {}
for _, spec in pairs(recipe.items) do for _, spec in pairs(recipe.items) do
local matches_spec = ui.canonical_item_spec_matcher(spec) -- Get items that fit into this spec (group or item name)
for _, name in ipairs(ui.items_list) do local specname = ItemStack(spec):get_name()
if matches_spec(name) then for item_name, _ in pairs(get_matching_spec_items(specname)) do
ingredient_items[name] = true ingredient_items[item_name] = true
end
end end
end end
for name, _ in pairs(ingredient_items) do for name, _ in pairs(ingredient_items) do
if ui.crafts_for.usage[name] == nil then if not ui.crafts_for.usage[name] then
ui.crafts_for.usage[name] = {} ui.crafts_for.usage[name] = {}
end end
table.insert(ui.crafts_for.usage[name], recipe) table.insert(ui.crafts_for.usage[name], recipe)
end end
if next(ingredient_items) then
-- There's at least one known ingredient: mark as good recipe
-- PS: What whatll be done about partially incomplete recipes?
table.insert(new_recipe_list, recipe)
end end
end end
ui.crafts_for.recipe[outputitemname] = new_recipe_list
end
-- Remove unknown items from all categories
local total_removed = 0
for cat_name, cat_def in pairs(ui.registered_category_items) do
for itemname, _ in pairs(cat_def) do
local idef = minetest.registered_items[itemname]
if not idef then
total_removed = total_removed + 1
--[[
-- For analysis
minetest.log("warning", "[unified_inventory] Removed item '"
.. itemname .. "' from category '" .. cat_name
.. "'. Reason: item not registered")
]]
cat_def[itemname] = nil
elseif not ui.is_itemdef_listable(idef) then
total_removed = total_removed + 1
--[[
-- For analysis
minetest.log("warning", "[unified_inventory] Removed item '"
.. itemname .. "' from category '" .. cat_name
.. "'. Reason: item is in 'not_in_creative_inventory' group")
]]
cat_def[itemname] = nil
end
end
end
if total_removed > 0 then
minetest.log("info", "[unified_inventory] Removed " .. total_removed ..
" items from the categories.")
end
for _, callback in ipairs(ui.initialized_callbacks) do for _, callback in ipairs(ui.initialized_callbacks) do
callback() callback()
end end
end) end)
---------------- Home API ----------------
-- load_home
local function load_home() local function load_home()
local input = io.open(ui.home_filename, "r") local input = io.open(ui.home_filename, "r")
if not input then if not input then
@ -176,6 +238,7 @@ local function load_home()
end end
io.close(input) io.close(input)
end end
load_home() load_home()
function ui.set_home(player, pos) function ui.set_home(player, pos)
@ -204,7 +267,8 @@ function ui.go_home(player)
return false return false
end end
-- register_craft ---------------- Crafting API ----------------
function ui.register_craft(options) function ui.register_craft(options)
if not options.output then if not options.output then
return return
@ -227,14 +291,12 @@ function ui.register_craft(options)
end end
end end
local craft_type_defaults = { local craft_type_defaults = {
width = 3, width = 3,
height = 3, height = 3,
uses_crafting_grid = false, uses_crafting_grid = false,
} }
function ui.craft_type_defaults(name, options) function ui.craft_type_defaults(name, options)
if not options.description then if not options.description then
options.description = name options.description = name
@ -245,8 +307,7 @@ end
function ui.register_craft_type(name, options) function ui.register_craft_type(name, options)
ui.registered_craft_types[name] = ui.registered_craft_types[name] = ui.craft_type_defaults(name, options)
ui.craft_type_defaults(name, options)
end end
@ -303,6 +364,8 @@ ui.register_craft_type("digging_chance", {
height = 1, height = 1,
}) })
---------------- GUI registrations ----------------
function ui.register_page(name, def) function ui.register_page(name, def)
ui.pages[name] = def ui.pages[name] = def
end end
@ -318,6 +381,8 @@ function ui.register_button(name, def)
table.insert(ui.buttons, def) table.insert(ui.buttons, def)
end end
---------------- Callback registrations ----------------
function ui.register_on_initialized(callback) function ui.register_on_initialized(callback)
if type(callback) ~= "function" then if type(callback) ~= "function" then
error(("Initialized callback must be a function, %s given."):format(type(callback))) error(("Initialized callback must be a function, %s given."):format(type(callback)))
@ -332,6 +397,8 @@ function ui.register_on_craft_registered(callback)
table.insert(ui.craft_registered_callbacks, callback) table.insert(ui.craft_registered_callbacks, callback)
end end
---------------- List getters ----------------
function ui.get_recipe_list(output) function ui.get_recipe_list(output)
return ui.crafts_for.recipe[output] return ui.crafts_for.recipe[output]
end end
@ -344,11 +411,15 @@ function ui.get_registered_outputs()
return outputs return outputs
end end
---------------- Player utilities ----------------
function ui.is_creative(playername) function ui.is_creative(playername)
return minetest.check_player_privs(playername, {creative=true}) return minetest.check_player_privs(playername, {creative=true})
or minetest.settings:get_bool("creative_mode") or minetest.settings:get_bool("creative_mode")
end end
---------------- Formspec helpers ----------------
function ui.single_slot(xpos, ypos, bright) function ui.single_slot(xpos, ypos, bright)
return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]", 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 "") ) xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") )

141
bags.lua
View File

@ -10,25 +10,26 @@ local F = minetest.formspec_escape
local ui = unified_inventory local ui = unified_inventory
ui.register_page("bags", { ui.register_page("bags", {
get_formspec = function(player) get_formspec = function(player, perplayer_formspec)
local player_name = player:get_player_name() local player_name = player:get_player_name()
return { formspec = table.concat({ local std_inv_x = perplayer_formspec.std_inv_x
ui.style_full.standard_inv_bg, local formspec = {
ui.single_slot(0.925, 1.5), perplayer_formspec.standard_inv_bg,
ui.single_slot(3.425, 1.5), "label[", perplayer_formspec.form_header_x, ",",
ui.single_slot(5.925, 1.5), perplayer_formspec.form_header_y, ";", F(S("Bags")), "]",
ui.single_slot(8.425, 1.5),
"label["..ui.style_full.form_header_x..","..ui.style_full.form_header_y..";" .. F(S("Bags")) .. "]",
"button[0.6125,2.75;1.875,0.75;bag1;" .. F(S("Bag @1", 1)) .. "]",
"button[3.1125,2.75;1.875,0.75;bag2;" .. F(S("Bag @1", 2)) .. "]",
"button[5.6125,2.75;1.875,0.75;bag3;" .. F(S("Bag @1", 3)) .. "]",
"button[8.1125,2.75;1.875,0.75;bag4;" .. F(S("Bag @1", 4)) .. "]",
"listcolors[#00000000;#00000000]", "listcolors[#00000000;#00000000]",
"list[detached:" .. F(player_name) .. "_bags;bag1;1.075,1.65;1,1;]", }
"list[detached:" .. F(player_name) .. "_bags;bag2;3.575,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag3;6.075,1.65;1,1;]", for i = 1, 4 do
"list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]" local x = std_inv_x + i * 2.5
}) } formspec[#formspec + 1] = ui.single_slot(x - 1.875, 1.5)
formspec[#formspec + 1] = string.format("list[detached:%s_bags;bag%i;%.3f,1.65;1,1;]",
F(player_name), i, x - 1.725)
formspec[#formspec + 1] = string.format("button[%.4f,2.75;1.875,0.75;bag%i;%s]",
x - 2.1875, i, F(S("Bag @1", i)))
end
return { formspec = table.concat(formspec) }
end, end,
}) })
@ -36,7 +37,6 @@ ui.register_button("bags", {
type = "image", type = "image",
image = "ui_bags_icon.png", image = "ui_bags_icon.png",
tooltip = S("Bags"), tooltip = S("Bags"),
hide_lite=true
}) })
local function get_player_bag_stack(player, i) local function get_player_bag_stack(player, i)
@ -48,23 +48,38 @@ end
for bag_i = 1, 4 do for bag_i = 1, 4 do
ui.register_page("bag" .. bag_i, { ui.register_page("bag" .. bag_i, {
get_formspec = function(player) get_formspec = function(player, perplayer_formspec)
local stack = get_player_bag_stack(player, bag_i) local stack = get_player_bag_stack(player, bag_i)
local image = stack:get_definition().inventory_image local image = stack:get_definition().inventory_image
local slots = stack:get_definition().groups.bagslots local slots = stack:get_definition().groups.bagslots
local std_inv_x = perplayer_formspec.std_inv_x
local lite_mode = perplayer_formspec.is_lite_mode
local bag_inv_y, header_x, header_y = 1.5, 0.3, 0.65
if lite_mode then
bag_inv_y = 0.5
header_x = perplayer_formspec.form_header_x
header_y = perplayer_formspec.form_header_y
end
local formspec = { local formspec = {
ui.style_full.standard_inv_bg, perplayer_formspec.standard_inv_bg,
ui.make_inv_img_grid(0.3, 1.5, 8, slots/8), ui.make_inv_img_grid(std_inv_x, bag_inv_y, 8, slots/8),
"image[9.2,0.4;1,1;" .. image .. "]", "label[", header_x, ",", header_y, ";", F(S("Bag @1", bag_i)), "]",
"label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
"listcolors[#00000000;#00000000]", "listcolors[#00000000;#00000000]",
"listring[current_player;main]", "listring[current_player;main]",
string.format("list[current_player;bag%icontents;%f,%f;8,3;]", string.format("list[current_player;bag%icontents;%f,%f;8,3;]",
bag_i, 0.3 + ui.list_img_offset, 1.5 + ui.list_img_offset), bag_i, std_inv_x + ui.list_img_offset, bag_inv_y + ui.list_img_offset),
"listring[current_name;bag" .. bag_i .. "contents]", "listring[current_name;bag", bag_i, "contents]",
} }
if lite_mode then
return { formspec = table.concat(formspec) }
end
local n = #formspec + 1 local n = #formspec + 1
formspec[n] = "image[" .. std_inv_x + 8.9 .. ",0.4;1,1;" .. image .. "]"
n = n + 1
local player_name = player:get_player_name() -- For if statement. local player_name = player:get_player_name() -- For if statement.
if ui.trash_enabled if ui.trash_enabled
@ -114,6 +129,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
end) end)
-- Player slots are preserved when unified_inventory is disabled. Do not allow modification.
-- Fix: use a detached inventory and store the data separately.
local function save_bags_metadata(player, bags_inv) local function save_bags_metadata(player, bags_inv)
local is_empty = true local is_empty = true
local bags = {} local bags = {}
@ -127,7 +144,7 @@ local function save_bags_metadata(player, bags_inv)
end end
local meta = player:get_meta() local meta = player:get_meta()
if is_empty then if is_empty then
meta:set_string("unified_inventory:bags", nil) meta:set_string("unified_inventory:bags", "")
else else
meta:set_string("unified_inventory:bags", meta:set_string("unified_inventory:bags",
minetest.serialize(bags)) minetest.serialize(bags))
@ -163,7 +180,7 @@ local function load_bags_metadata(player, bags_inv)
save_bags_metadata(player, bags_inv) save_bags_metadata(player, bags_inv)
end end
-- Clean up deprecated garbage after saving -- Legacy: Clean up old player lists
for i = 1, 4 do for i = 1, 4 do
local bag = "bag" .. i local bag = "bag" .. i
player_inv:set_size(bag, 0) player_inv:set_size(bag, 0)
@ -173,45 +190,28 @@ end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local bags_inv = minetest.create_detached_inventory(player_name .. "_bags", { local bags_inv = minetest.create_detached_inventory(player_name .. "_bags", {
allow_put = function(inv, listname, index, stack, player)
local new_slots = stack:get_definition().groups.bagslots
if not new_slots then
return 0 -- ItemStack is not a bag.
end
-- The execution order of `allow_put`/`allow_take` is not defined.
-- We do not know the replacement ItemStack if the items are swapped.
-- Hence, bag slot upgrades and downgrades are not possible with the
-- current API.
if not player:get_inventory():is_empty(listname .. "contents") then
-- Legacy: in case `allow_take` is not executed on old Minetest versions.
return 0
end
return 1
end,
on_put = function(inv, listname, index, stack, player) on_put = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname .. "contents", player:get_inventory():set_size(listname .. "contents",
stack:get_definition().groups.bagslots) stack:get_definition().groups.bagslots)
save_bags_metadata(player, inv) save_bags_metadata(player, inv)
end, end,
allow_put = function(inv, listname, index, stack, player)
local new_slots = stack:get_definition().groups.bagslots
if not new_slots then
return 0
end
local player_inv = player:get_inventory()
local old_slots = player_inv:get_size(listname .. "contents")
if new_slots >= old_slots then
return 1
end
-- using a smaller bag, make sure it fits
local old_list = player_inv:get_list(listname .. "contents")
local new_list = {}
local slots_used = 0
local use_new_list = false
for i, v in ipairs(old_list) do
if v and not v:is_empty() then
slots_used = slots_used + 1
use_new_list = i > new_slots
new_list[slots_used] = v
end
end
if new_slots >= slots_used then
if use_new_list then
player_inv:set_list(listname .. "contents", new_list)
end
return 1
end
-- New bag is smaller: Disallow inserting
return 0
end,
allow_take = function(inv, listname, index, stack, player) allow_take = function(inv, listname, index, stack, player)
if player:get_inventory():is_empty(listname .. "contents") then if player:get_inventory():is_empty(listname .. "contents") then
return stack:get_count() return stack:get_count()
@ -221,6 +221,11 @@ minetest.register_on_joinplayer(function(player)
on_take = function(inv, listname, index, stack, player) on_take = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname .. "contents", 0) player:get_inventory():set_size(listname .. "contents", 0)
save_bags_metadata(player, inv) save_bags_metadata(player, inv)
if listname == ui.current_page[player:get_player_name()] then
-- Bag is currently open: avoid follow-up issues by navigating back
-- Trick: the list name is the same as the registered page name
ui.set_inventory_formspec(player, "bags")
end
end, end,
allow_move = function() allow_move = function()
return 0 return 0
@ -230,6 +235,20 @@ minetest.register_on_joinplayer(function(player)
load_bags_metadata(player, bags_inv) load_bags_metadata(player, bags_inv)
end) end)
minetest.register_allow_player_inventory_action(function(player, action, inventory, info)
-- From detached inventory -> player inventory: put & take callbacks
if action ~= "put" or not info.listname:find("bag%dcontents") then
return
end
if info.stack:get_definition().groups.bagslots then
-- Problem 1: empty bags could be moved into their own slots
-- Problem 2: cannot reliably keep track of ItemStack ownership due to
--> Disallow all external bag movements into this list
return 0
end
end)
-- register bag tools -- register bag tools
minetest.register_tool("unified_inventory:bag_small", { minetest.register_tool("unified_inventory:bag_small", {
description = S("Small Bag"), description = S("Small Bag"),

View File

@ -1,3 +1,5 @@
local ui = unified_inventory
local function default_refill(stack) local function default_refill(stack)
stack:set_count(stack:get_stack_max()) stack:set_count(stack:get_stack_max())
local itemdef = minetest.registered_items[stack:get_name()] local itemdef = minetest.registered_items[stack:get_name()]
@ -12,19 +14,17 @@ end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
unified_inventory.players[player_name] = {} unified_inventory.players[player_name] = {}
unified_inventory.current_index[player_name] = 1 unified_inventory.current_index[player_name] = 1 -- Item (~page) index
unified_inventory.filtered_items_list[player_name] = unified_inventory.filtered_items_list[player_name] =
unified_inventory.items_list unified_inventory.items_list
unified_inventory.activefilter[player_name] = "" unified_inventory.activefilter[player_name] = ""
unified_inventory.active_search_direction[player_name] = "nochange" unified_inventory.active_search_direction[player_name] = "nochange"
unified_inventory.apply_filter(player, "", "nochange")
unified_inventory.current_searchbox[player_name] = "" unified_inventory.current_searchbox[player_name] = ""
unified_inventory.current_category[player_name] = "all" unified_inventory.current_category[player_name] = "all"
unified_inventory.current_category_scroll[player_name] = 0 unified_inventory.current_category_scroll[player_name] = 0
unified_inventory.alternate[player_name] = 1 unified_inventory.alternate[player_name] = 1
unified_inventory.current_item[player_name] = nil unified_inventory.current_item[player_name] = nil
unified_inventory.current_craft_direction[player_name] = "recipe" unified_inventory.current_craft_direction[player_name] = "recipe"
unified_inventory.set_inventory_formspec(player, unified_inventory.default)
-- Refill slot -- Refill slot
local refill = minetest.create_detached_inventory(player_name.."refill", { local refill = minetest.create_detached_inventory(player_name.."refill", {
@ -46,30 +46,58 @@ minetest.register_on_joinplayer(function(player)
refill:set_size("main", 1) refill:set_size("main", 1)
end) 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 function apply_new_filter(player, search_text, new_dir)
local player_name = player:get_player_name() local player_name = player:get_player_name()
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, search_text, new_dir) minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1})
unified_inventory.current_searchbox[player_name] = search_text ui.apply_filter(player, search_text, new_dir)
unified_inventory.set_inventory_formspec(player, ui.current_searchbox[player_name] = search_text
unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end
-- Search box handling
local function receive_fields_searchbox(player, formname, fields)
local player_name = player:get_player_name()
-- always take new search text, even if not searching on it yet
if fields.searchbox and fields.searchbox ~= ui.current_searchbox[player_name] then
ui.current_searchbox[player_name] = fields.searchbox
end
if fields.searchbutton
or fields.key_enter_field == "searchbox" then
if ui.current_searchbox[player_name] ~= ui.activefilter[player_name] 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
end
end end
minetest.register_on_player_receive_fields(function(player, formname, fields) 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 if formname ~= "" then
return return
end end
-- always take new search text, even if not searching on it yet receive_fields_searchbox(player, formname, fields)
if fields.searchbox
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
unified_inventory.current_searchbox[player_name] = fields.searchbox
end
local player_name = player:get_player_name()
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name)
local clicked_category local clicked_category
for name, value in pairs(fields) do for name, value in pairs(fields) do
@ -88,19 +116,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_page[player_name]) unified_inventory.current_page[player_name])
end end
if fields.next_category then if fields.next_category or fields.prev_category then
local scroll = math.min(#unified_inventory.category_list-ui_peruser.pagecols, unified_inventory.current_category_scroll[player_name] + 1) local step = fields.next_category and 1 or -1
if scroll ~= unified_inventory.current_category_scroll[player_name] then local scroll_old = ui.current_category_scroll[player_name]
unified_inventory.current_category_scroll[player_name] = scroll local scroll_new = math.max(0, math.min(#ui.category_list - ui_peruser.pagecols, scroll_old + step))
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name]) if scroll_old ~= scroll_new then
end ui.current_category_scroll[player_name] = scroll_new
end ui.set_inventory_formspec(player,
if fields.prev_category then
local scroll = math.max(0, unified_inventory.current_category_scroll[player_name] - 1)
if scroll ~= unified_inventory.current_category_scroll[player_name] then
unified_inventory.current_category_scroll[player_name] = scroll
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name]) unified_inventory.current_page[player_name])
end end
end end
@ -108,7 +131,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
for i, def in pairs(unified_inventory.buttons) do for i, def in pairs(unified_inventory.buttons) do
if fields[def.name] then if fields[def.name] then
def.action(player) def.action(player)
minetest.sound_play("click", minetest.sound_play("ui_click",
{to_player=player_name, gain = 0.1}) {to_player=player_name, gain = 0.1})
return return
end end
@ -173,7 +196,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
end end
if clicked_item then if clicked_item then
minetest.sound_play("click", minetest.sound_play("ui_click",
{to_player=player_name, gain = 0.1}) {to_player=player_name, gain = 0.1})
local page = unified_inventory.current_page[player_name] local page = unified_inventory.current_page[player_name]
local player_creative = unified_inventory.is_creative(player_name) local player_creative = unified_inventory.is_creative(player_name)
@ -195,22 +218,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
end end
if fields.searchbutton
or fields.key_enter_field == "searchbox" then
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0})
elseif fields.searchresetbutton then
apply_new_filter(player, "", "nochange")
end
-- alternate buttons -- alternate buttons
if not (fields.alternate or fields.alternate_prev) then if not (fields.alternate or fields.alternate_prev) then
return return
end end
minetest.sound_play("click", minetest.sound_play("ui_click",
{to_player=player_name, gain = 0.1}) {to_player=player_name, gain = 0.1})
local item_name = unified_inventory.current_item[player_name] local item_name = unified_inventory.current_item[player_name]
if not item_name then if not item_name then
@ -241,11 +253,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_page[player_name]) unified_inventory.current_page[player_name])
end) end)
if minetest.delete_detached_inventory then
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
minetest.delete_detached_inventory(player_name.."_bags") minetest.remove_detached_inventory(player_name.."_bags")
minetest.delete_detached_inventory(player_name.."craftrecipe") minetest.remove_detached_inventory(player_name.."refill")
minetest.delete_detached_inventory(player_name.."refill")
end) end)
end

View File

@ -96,6 +96,9 @@ function unified_inventory.register_category(category_name, config)
end end
update_category_list() update_category_list()
end end
-- TODO: Mark these for removal. They are pretty much useless
function unified_inventory.set_category_symbol(category_name, symbol) function unified_inventory.set_category_symbol(category_name, symbol)
ensure_category_exists(category_name) ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].symbol = symbol unified_inventory.registered_categories[category_name].symbol = symbol
@ -112,6 +115,11 @@ function unified_inventory.set_category_index(category_name, index)
update_category_list() update_category_list()
end end
function unified_inventory.add_category_item(category_name, item) function unified_inventory.add_category_item(category_name, item)
if type(item) ~= "string" then
minetest.log("warning", "[unified_inventory] Cannot register category item: " .. dump(item))
return
end
ensure_category_exists(category_name) ensure_category_exists(category_name)
unified_inventory.registered_category_items[category_name][item] = true unified_inventory.registered_category_items[category_name][item] = true
end end

View File

@ -1,4 +1,5 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local ui = unified_inventory
unified_inventory.register_category('plants', { unified_inventory.register_category('plants', {
symbol = "flowers:tulip", symbol = "flowers:tulip",
@ -25,10 +26,7 @@ unified_inventory.register_category('lighting', {
label = S("Lighting") label = S("Lighting")
}) })
local function register_automatic_categorization()
if unified_inventory.automatic_categorization then
minetest.register_on_mods_loaded(function()
-- Add biome nodes to environment category -- Add biome nodes to environment category
for _,def in pairs(minetest.registered_biomes) do for _,def in pairs(minetest.registered_biomes) do
local env_nodes = { local env_nodes = {
@ -41,18 +39,33 @@ if unified_inventory.automatic_categorization then
end end
end end
-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment -- Preparation for ore registration: find all possible drops (digging)
for _,item in pairs(minetest.registered_ores) do local possible_node_dig_drops = {
if item.ore_type == "scatter" then -- ["default:stone_with_coal"] = { "default:coal_lump", "mymod:raregem" }
local drop = minetest.registered_nodes[item.ore].drop -- Ores may be contained multiple times, depending on drop chances.
if drop and drop ~= "" then }
unified_inventory.add_category_item('minerals', item.ore) for itemname, recipes in pairs(ui.crafts_for.usage) do
unified_inventory.add_category_item('minerals', drop) for _, recipe in ipairs(recipes) do
else if recipe.type == "digging" or recipe.type == "digging_chance" then
unified_inventory.add_category_item('environment', item.ore) if not possible_node_dig_drops[itemname] then
possible_node_dig_drops[itemname] = {}
end end
local stack = ItemStack(recipe.output)
table.insert(possible_node_dig_drops[itemname], stack:get_name())
end
end
end
-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment
for _, odef in pairs(minetest.registered_ores) do
local drops = possible_node_dig_drops[odef.ore]
if drops and odef.ore_type == "scatter" then
ui.add_category_item('minerals', odef.ore)
-- Register all possible drops as "minerals"
ui.add_category_items('minerals', drops)
possible_node_dig_drops[odef.ore] = {} -- mask as handled
else else
unified_inventory.add_category_item('environment', item.ore) ui.add_category_item('environment', odef.ore)
end end
end end
@ -87,9 +100,13 @@ if unified_inventory.automatic_categorization then
end end
end end
end end
end)
end end
if ui.automatic_categorization then
ui.register_on_initialized(register_automatic_categorization)
end
-- [[ -- [[
unified_inventory.add_category_items('plants', { unified_inventory.add_category_items('plants', {
"default:dry_grass_5", "default:dry_grass_5",
@ -256,23 +273,6 @@ unified_inventory.add_category_items('minerals', {
"default:coal_lump", "default:coal_lump",
"default:bronzeblock", "default:bronzeblock",
"default:goldblock", "default:goldblock",
"stairs:slab_bronzeblock",
"stairs:slab_copperblock",
"stairs:slab_steelblock",
"stairs:slab_tinblock",
"stairs:stair_bronzeblock",
"stairs:stair_copperblock",
"stairs:stair_inner_bronzeblock",
"stairs:stair_inner_copperblock",
"stairs:stair_inner_steelblock",
"stairs:stair_inner_tinblock",
"stairs:stair_outer_bronzeblock",
"stairs:stair_outer_copperblock",
"stairs:stair_outer_steelblock",
"stairs:stair_outer_tinblock",
"stairs:stair_steelblock",
"stairs:stair_tinblock",
}) })
unified_inventory.add_category_items('building', { unified_inventory.add_category_items('building', {

View File

@ -1,7 +1,8 @@
unified_inventory API unified_inventory API
===================== =====================
This file provides information about the API of unified_inventory. This file provides information about the API of unified_inventory
and can be viewed in Markdown readers.
API revisions within unified_inventory can be checked using: API revisions within unified_inventory can be checked using:
@ -23,7 +24,9 @@ Grouped by use-case, afterwards sorted alphabetically.
Callbacks Callbacks
--------- ---------
Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft: Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft.
This callback is run before any recipe ingredients checks, hence it is also executed on recipes that are
purged after all mods finished loading.
unified_inventory.register_on_craft_registered( unified_inventory.register_on_craft_registered(
function (item_name, options) function (item_name, options)
@ -163,68 +166,57 @@ Register a non-standard craft recipe:
Categories Categories
---------- ----------
Register a new category: * `unified_inventory.register_category(name, def)`
The config table (second argument) is optional, and all its members are optional * Registers a new category
See the unified_inventory.set_category_* functions for more details on the members of the config table * `name` (string): internal category name
* `def` (optional, table): also its fields are optional
unified_inventory.register_category("category_name", { unified_inventory.register_category("category_name", {
symbol = "mod_name:item_name" or "texture.png", symbol = source,
-- ^ Can be in the format "mod_name:item_name" or "texture.png",
label = "Human Readable Label", label = "Human Readable Label",
index = 5, index = 5,
-- ^ Categories are sorted by index. Lower numbers appear before higher ones.
-- By default, the name is translated to a number: AA -> 0.0101, ZZ -> 0.2626
--- Predefined category indices: "all" = -2, "uncategorized" = -1
items = { items = {
"mod_name:item_name", "mod_name:item_name",
"another_mod:different_item" "another_mod:different_item"
} }
-- ^ List of items within this category
}) })
* `unified_inventory.remove_category(name)`
* Removes an entire category
Add / override the symbol for a category: Modifier functions (to be removed)
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") * `unified_inventory.set_category_symbol(name, source)`
* Changes the symbol of the category. The category does not need to exist yet.
* `name` (string): internal category name
* `source` (string, optional): `"mod_name:item_name"` or `"texture.png"`.
Defaults to `"default:stick"` if not specified.
* `unified_inventory.set_category_label(name, label)`
* Changes the human readable label of the category.
* `name` (string): internal category name
* `label` (string): human readable label. Defaults to the category name.
* `unified_inventory.set_category_index(name, index)`
* Changes the sorting index of the category.
* `name` (string): internal category name
* `index` (numeric): any real number
Add / override the human readable label for a category: Item management
If unset this will default to the category name
unified_inventory.set_category_label("category_name", "Human Readable Label") * ` unified_inventory.add_category_item(name, itemname)`
* Adds a single item to the category
* `itemname` (string): self-explanatory
* `unified_inventory.add_category_items(name, { itemname1, itemname2, ... }`
* Same as above but with multiple items
* `unified_inventory.remove_category_item(name, itemname)`
* Removes an item from the category
* `unified_inventory.find_category(itemname)`
* Looks up the first category containing this item
* Returns: category name (string) or nil
* `unified_inventory.find_categories(itemname)`
* Looks up the item name within all registered categories
* Returns: array of category names (table)
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")

101
group.lua
View File

@ -1,29 +1,5 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local ui = unified_inventory
function unified_inventory.canonical_item_spec_matcher(spec)
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)
local itemname = ItemStack(item):get_name()
return unified_inventory.canonical_item_spec_matcher(spec)(itemname)
end
function unified_inventory.extract_groupnames(groupname) function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name() local specname = ItemStack(groupname):get_name()
@ -34,22 +10,6 @@ function unified_inventory.extract_groupnames(groupname)
return table.concat(group_names, S(" and ")), #group_names return table.concat(group_names, S(" and ")), #group_names
end 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)
unified_inventory.registered_group_items[groupname] = itemname
end
-- This is used when displaying craft recipes, where an ingredient is -- This is used when displaying craft recipes, where an ingredient is
-- specified by group rather than as a specific item. A single-item group -- specified by group rather than as a specific item. A single-item group
@ -67,6 +27,7 @@ end
-- It may be a comma-separated list of group names. This is really a -- It may be a comma-separated list of group names. This is really a
-- "group:..." ingredient specification, minus the "group:" prefix. -- "group:..." ingredient specification, minus the "group:" prefix.
-- TODO Replace this with the more efficient spec matcher (below)
local function compute_group_item(group_name_list) local function compute_group_item(group_name_list)
local group_names = group_name_list:split(",") local group_names = group_name_list:split(",")
local candidate_items = {} local candidate_items = {}
@ -125,3 +86,61 @@ function unified_inventory.get_group_item(group_name)
return group_item_cache[group_name] return group_item_cache[group_name]
end end
--[[
This is for filtering known items by groups
e.g. find all items that match "group:flower,yellow" (flower AND yellow groups)
]]
local spec_matcher = {}
function unified_inventory.init_matching_cache()
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
end
--[[
Retrieves all matching items
Arguments:
specname (string): Item name or group(s) to filter
Output:
{
matchingitem1 = true,
...
}
]]
function unified_inventory.get_matching_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
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

View File

@ -1,5 +1,11 @@
-- Unified Inventory -- 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
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modpath = minetest.get_modpath(minetest.get_current_modname())
local worldpath = minetest.get_worldpath() local worldpath = minetest.get_worldpath()
@ -44,9 +50,12 @@ unified_inventory = {
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false), trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25, imgscale = 1.25,
list_img_offset = 0.13, list_img_offset = 0.13,
standard_background = "background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]", standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
version = 3 hide_disabled_buttons = minetest.settings:get_bool("unified_inventory_hide_disabled_buttons", false),
hide_uncraftable_items = minetest.settings:get_bool("unified_inventory_hide_uncraftable_items", false),
version = 5
} }
local ui = unified_inventory local ui = unified_inventory
@ -59,10 +68,16 @@ ui.style_full = {
formspec_y = 1, formspec_y = 1,
formw = 17.75, formw = 17.75,
formh = 12.25, formh = 12.25,
-- Item browser size, pos
pagecols = 8, pagecols = 8,
pagerows = 9, pagerows = 9,
page_x = 10.75, page_x = 10.75,
page_y = 2.30, page_y = 2.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_x = 2.8,
craft_y = 1.15, craft_y = 1.15,
craftresult_x = 7.8, craftresult_x = 7.8,
@ -74,13 +89,15 @@ ui.style_full = {
craft_guide_resultstr_x = 0.3, craft_guide_resultstr_x = 0.3,
craft_guide_resultstr_y = 0.6, craft_guide_resultstr_y = 0.6,
give_btn_x = 0.25, give_btn_x = 0.25,
-- Tab switching buttons
main_button_x = 0.4, main_button_x = 0.4,
main_button_y = 11.0, main_button_y = 11.0,
page_buttons_x = 11.60, main_button_cols = 12,
page_buttons_y = 10.15, main_button_rows = 1,
searchwidth = 3.4, -- Tab title position
form_header_x = 0.4, form_header_x = 0.4,
form_header_y = 0.4, form_header_y = 0.4,
-- Generic sizes
btn_spc = 0.85, btn_spc = 0.85,
btn_size = 0.75, btn_size = 0.75,
std_inv_x = 0.3, std_inv_x = 0.3,
@ -92,10 +109,16 @@ ui.style_lite = {
formspec_y = 0.6, formspec_y = 0.6,
formw = 14, formw = 14,
formh = 9.75, formh = 9.75,
-- Item browser size, pos
pagecols = 4, pagecols = 4,
pagerows = 5, pagerows = 5,
page_x = 10.5, page_x = 10.5,
page_y = 2.15, page_y = 2.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_x = 2.6,
craft_y = 0.75, craft_y = 0.75,
craftresult_x = 5.75, craftresult_x = 5.75,
@ -107,13 +130,15 @@ ui.style_lite = {
craft_guide_resultstr_x = 0.15, craft_guide_resultstr_x = 0.15,
craft_guide_resultstr_y = 0.35, craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15, give_btn_x = 0.15,
-- Tab switching buttons
main_button_x = 10.5, main_button_x = 10.5,
main_button_y = 8.15, main_button_y = 8.15,
page_buttons_x = 10.5, main_button_cols = 4,
page_buttons_y = 6.15, main_button_rows = 2,
searchwidth = 1.6, -- Tab title position
form_header_x = 0.2, form_header_x = 0.2,
form_header_y = 0.2, form_header_y = 0.2,
-- Generic sizes
btn_spc = 0.8, btn_spc = 0.8,
btn_size = 0.7, btn_size = 0.7,
std_inv_x = 0.1, std_inv_x = 0.1,
@ -167,7 +192,12 @@ dofile(modpath.."/register.lua")
if minetest.settings:get_bool("unified_inventory_bags") ~= false then if minetest.settings:get_bool("unified_inventory_bags") ~= false then
dofile(modpath.."/bags.lua") dofile(modpath.."/bags.lua")
end end
if minetest.settings:get_bool("unified_inventory_item_names") ~= false then
dofile(modpath.."/item_names.lua") dofile(modpath.."/item_names.lua")
end
if minetest.settings:get_bool("unified_inventory_waypoints") ~= false then
dofile(modpath.."/waypoints.lua") dofile(modpath.."/waypoints.lua")
end
dofile(modpath.."/legacy.lua") -- mod compatibility
minetest.log("action", "[unified_inventory] loaded.") minetest.log("action", "[unified_inventory] loaded.")

View File

@ -18,7 +18,7 @@ function ui.demangle_for_formspec(str)
return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end)
end end
-- Get the player-specific unified_inventory style
function ui.get_per_player_formspec(player_name) 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 draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
@ -27,6 +27,7 @@ function ui.get_per_player_formspec(player_name)
return style return style
end 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 function formspec_button(ui_peruser, name, image, offset, pos, scale, label)
local element = 'image_button' local element = 'image_button'
if minetest.registered_items[image] then if minetest.registered_items[image] then
@ -43,52 +44,68 @@ local function formspec_button(ui_peruser, name, image, offset, pos, scale, labe
string.format("tooltip[%s;%s]", name, F(label or name)) string.format("tooltip[%s;%s]", name, F(label or name))
end end
local function formspec_add_filters(player, formspec, style) -- Add registered buttons (tabs)
local button_row = 0 local function formspec_tab_buttons(player, formspec, style)
local button_col = 0
local n = #formspec + 1 local n = #formspec + 1
-- Main buttons -- Main buttons
local filtered_inv_buttons = {} local filtered_inv_buttons = {}
for i, def in pairs(ui.buttons) do for _, def in pairs(ui.buttons) do
if not (style.is_lite_mode and def.hide_lite) then if not (style.is_lite_mode and def.hide_lite) then
if def.condition == nil or def.condition(player) or not ui.hide_disabled_buttons then
table.insert(filtered_inv_buttons, def) table.insert(filtered_inv_buttons, def)
end end
end end
local j = 1 --Modif NALC (sys4 20/11/2018) 12 buttons max by row
for i, def in pairs(filtered_inv_buttons) do
if style.is_lite_mode and i > 4 then
button_row = 1
button_col = 1
elseif not draw_lite_mode and j > 12 then
button_row = 1
j = 1
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.type == "image" then
local pos_x = style.main_button_x + style.btn_spc * (j - 1) - button_col * style.btn_spc * 4 if (def.condition == nil or def.condition(player)) then
local pos_y = style.main_button_y + button_row * style.btn_spc formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]",
if (def.condition == nil or def.condition(player) == true) then
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
pos_x, pos_y, style.btn_size, style.btn_size, pos_x, pos_y, style.btn_size, style.btn_size,
F(def.image), F(def.image),
F(def.name)) F(def.name))
formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]" formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]"
n = n+2 n = n+2
else else
formspec[n] = string.format("image[%f,%f;%f,%f;%s^[colorize:#808080:alpha]", formspec[n] = string.format("image[%g,%g;%g,%g;%s^[colorize:#808080:alpha]",
pos_x, pos_y, style.btn_size, style.btn_size, pos_x, pos_y, style.btn_size, style.btn_size,
def.image) def.image)
n = n+1 n = n+1
end end
end end
j = j + 1 -- Modif NALC end
formspec[n] = "scroll_container_end[]"
if needs_scrollbar then
local total_rows = math.ceil(#filtered_inv_buttons / style.main_button_cols)
formspec[n+1] = ("scrollbaroptions[max=%i;arrows=hide]"):format(
-- This calculation is not 100% accurate but "good enough"
(total_rows - style.main_button_rows) * style.btn_spc * 10
)
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
end end
-- Add category GUI elements (top right)
local function formspec_add_categories(player, formspec, ui_peruser) local function formspec_add_categories(player, formspec, ui_peruser)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local n = #formspec + 1 local n = #formspec + 1
@ -102,9 +119,9 @@ local function formspec_add_categories(player, formspec, ui_peruser)
ui_peruser.form_header_y - (ui_peruser.is_lite_mode and 0 or 0.2) ui_peruser.form_header_y - (ui_peruser.is_lite_mode and 0 or 0.2)
} }
formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;3]", formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;16]",
ui_peruser.page_x-0.1, categories_scroll_pos[2], ui_peruser.page_x-0.15, categories_scroll_pos[2],
(ui_peruser.btn_spc * ui_peruser.pagecols) + 0.13, 1.4 + (ui_peruser.is_lite_mode and 0 or 0.2), (ui_peruser.btn_spc * ui_peruser.pagecols) + 0.2, 1.4 + (ui_peruser.is_lite_mode and 0 or 0.2),
"ui_smallbg_9_sliced.png") "ui_smallbg_9_sliced.png")
n = n + 1 n = n + 1
@ -243,17 +260,25 @@ local function formspec_add_item_browser(player, formspec, ui_peruser)
ui_peruser.btn_size, ui_peruser.btn_size, ui_peruser.btn_size, ui_peruser.btn_size,
name, button_name 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( formspec[n + 1] = ("tooltip[%s;%s]"):format(
button_name, minetest.formspec_escape(item.description) button_name, minetest.formspec_escape(tooltip)
) )
n = n + 2 n = n + 2
end
list_index = list_index + 1 list_index = list_index + 1
end end
end end
end formspec[n] = "style[page_number;content_offset=0]"
formspec[n] = string.format("label[%f,%f;%s: %s]", formspec[n + 1] = string.format("image_button[%f,%f;%f,0.4;;page_number;%s: %s;false;false;]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc * (ui_peruser.is_lite_mode and 1 or 2), ui_peruser.page_buttons_x,
ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2, ui_peruser.page_buttons_y + ui_peruser.btn_spc * 2 - 0.1,
ui_peruser.btn_spc * (bn - 1) + ui_peruser.btn_size,
F(S("Page")), S("@1 of @2",page2,pagemax)) F(S("Page")), S("@1 of @2",page2,pagemax))
end end
@ -285,7 +310,7 @@ function ui.get_formspec(player, page)
fs[#fs + 1] = fsdata.formspec fs[#fs + 1] = fsdata.formspec
formspec_add_filters(player, fs, ui_peruser) formspec_tab_buttons(player, fs, ui_peruser)
if fsdata.draw_inventory ~= false then if fsdata.draw_inventory ~= false then
-- Player inventory -- Player inventory
@ -310,7 +335,7 @@ function ui.set_inventory_formspec(player, page)
end end
end end
local function valid_def(def) function ui.is_itemdef_listable(def)
return (not def.groups.not_in_creative_inventory return (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0) or def.groups.not_in_creative_inventory == 0)
and def.description and def.description
@ -323,11 +348,30 @@ function ui.apply_filter(player, filter, search_dir)
return false return false
end end
local player_name = player:get_player_name() local player_name = player:get_player_name()
-- Whether to show uncraftable items
local fprefilter = function(_)
return true
end
if ui.hide_uncraftable_items and not ui.is_creative(player_name) then
fprefilter = function(name)
return ui.get_recipe_list(name)
end
end
local registered_items = minetest.registered_items
local lfilter = string.lower(filter) local lfilter = string.lower(filter)
local ffilter local ffilter
if lfilter:sub(1, 6) == "group:" then if lfilter:sub(1, 6) == "group:" then
-- Group filter: all groups of the item must match
local groups = lfilter:sub(7):split(",") local groups = lfilter:sub(7):split(",")
ffilter = function(name, def) ffilter = function(name)
local def = registered_items[name]
if not def then
return false
end
for _, group in ipairs(groups) do for _, group in ipairs(groups) do
if not def.groups[group] if not def.groups[group]
or def.groups[group] <= 0 then or def.groups[group] <= 0 then
@ -337,8 +381,16 @@ function ui.apply_filter(player, filter, search_dir)
return true return true
end end
else else
local lang = minetest.get_player_information(player_name).lang_code -- Name filter: fuzzy match item names and descriptions
ffilter = function(name, def) local player_info = minetest.get_player_information(player_name)
local lang = player_info and player_info.lang_code or ""
ffilter = function(name)
local def = registered_items[name]
if not def then
return false
end
local lname = string.lower(name) local lname = string.lower(name)
local ldesc = string.lower(def.description) local ldesc = string.lower(def.description)
local llocaldesc = minetest.get_translated_string local llocaldesc = minetest.get_translated_string
@ -347,37 +399,50 @@ function ui.apply_filter(player, filter, search_dir)
or llocaldesc and string.find(llocaldesc, lfilter, 1, true) or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
end end
end end
ui.filtered_items_list[player_name]={}
local filtered_items = {}
local category = ui.current_category[player_name] or 'all' local category = ui.current_category[player_name] or 'all'
if category == 'all' then if category == 'all' then
for name, def in pairs(minetest.registered_items) do for _, name in ipairs(ui.items_list) do
if valid_def(def) if fprefilter(name) and ffilter(name) then
and ffilter(name, def) then table.insert(filtered_items, name)
table.insert(ui.filtered_items_list[player_name], name)
end end
end end
elseif category == 'uncategorized' then elseif category == 'uncategorized' then
for name, def in pairs(minetest.registered_items) do for _, name in ipairs(ui.items_list) do
if (not ui.find_category(name)) if not ui.find_category(name)
and valid_def(def) and fprefilter(name)
and ffilter(name, def) then and ffilter(name) then
table.insert(ui.filtered_items_list[player_name], name) table.insert(filtered_items, name)
end end
end end
else else
-- Any other category is selected
for name, exists in pairs(ui.registered_category_items[category]) do for name, exists in pairs(ui.registered_category_items[category]) do
local def = minetest.registered_items[name] if exists
if exists and def and fprefilter(name)
and valid_def(def) and ffilter(name) then
and ffilter(name, def) then table.insert(filtered_items, name)
table.insert(ui.filtered_items_list[player_name], name)
end end
end end
end end
table.sort(ui.filtered_items_list[player_name]) table.sort(filtered_items)
ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
ui.filtered_items_list_size[player_name] = #filtered_items
ui.filtered_items_list[player_name] = filtered_items
ui.current_index[player_name] = 1 ui.current_index[player_name] = 1
ui.activefilter[player_name] = filter ui.activefilter[player_name] = filter
ui.active_search_direction[player_name] = search_dir ui.active_search_direction[player_name] = search_dir
ui.set_inventory_formspec(player, ui.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end 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."))
end
end)

View File

@ -3,6 +3,8 @@
local item_names = {} -- [player_name] = { hud, dtime, itemname } local item_names = {} -- [player_name] = { hud, dtime, itemname }
local dlimit = 3 -- HUD element will be hidden after this many seconds local dlimit = 3 -- HUD element will be hidden after this many seconds
local hudbars_mod = minetest.get_modpath("hudbars") local hudbars_mod = minetest.get_modpath("hudbars")
local only_names = minetest.settings:get_bool("unified_inventory_only_names", true)
local max_length = tonumber(minetest.settings:get("unified_inventory_max_item_name_length")) or 80
local function set_hud(player) local function set_hud(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
@ -16,7 +18,8 @@ local function set_hud(player)
item_names[player_name] = { item_names[player_name] = {
hud = player:hud_add({ hud = player:hud_add({
hud_elem_type = "text", -- TODO: remove compatibility code when 5.8.0 is no longer used
[minetest.features.hud_def_type_field and "type" or "hud_elem_type"] = "text",
position = {x=0.5, y=1}, position = {x=0.5, y=1},
offset = off, offset = off,
alignment = {x=0, y=-1}, alignment = {x=0, y=-1},
@ -60,6 +63,7 @@ minetest.register_globalstep(function(dtime)
data.itemname = itemname data.itemname = itemname
data.index = index data.index = index
data.dtime = 0 data.dtime = 0
local lang_code = minetest.get_player_information(player:get_player_name()).lang_code
local desc = stack.get_meta local desc = stack.get_meta
and stack:get_meta():get_string("description") and stack:get_meta():get_string("description")
@ -69,6 +73,14 @@ minetest.register_globalstep(function(dtime)
local def = minetest.registered_items[itemname] local def = minetest.registered_items[itemname]
desc = def and def.description or "" desc = def and def.description or ""
end end
if only_names and desc and string.find(desc, "\n") then
desc = string.match(desc, "([^\n]*)")
end
desc = minetest.get_translated_string(lang_code, desc)
desc = minetest.strip_colors(desc)
if string.len(desc) > max_length and max_length > 0 then
desc = string.sub(desc, 1, max_length) .. " [...]"
end
player:hud_change(data.hud, 'text', desc) player:hud_change(data.hud, 'text', desc)
end end
end end

55
legacy.lua Normal file
View File

@ -0,0 +1,55 @@
-- 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

View File

@ -7,17 +7,17 @@ Bag @1=Tasche @1
Small Bag=Kleine Tasche Small Bag=Kleine Tasche
Medium Bag=Mittelgroße Tasche Medium Bag=Mittelgroße Tasche
Large Bag=Große Tasche Large Bag=Große Tasche
All Items= All Items=Alle Gegenstände
Misc. Items= Misc. Items=Sonstige Gegenstände
Plant Life= Plant Life=Pfanzenwelt
Building Materials= Building Materials=Baumaterialien
Tools= Tools=Werkzeuge
Minerals and Metals= Minerals and Metals=Minerale und Metalle
Environment and Worldgen= Environment and Worldgen=Umwelt und Welterstellung
Lighting= Lighting=Beleuchtung
and = und and = und
Scroll categories left= Scroll categories left=Kategorien nach links blättern
Scroll categories right= Scroll categories right=Kategorien nach rechts blättern
Search=Suchen Search=Suchen
Reset search and display everything=Suche zurücksetzen und alles anzeigen Reset search and display everything=Suche zurücksetzen und alles anzeigen
First page=Erste Seite First page=Erste Seite
@ -76,10 +76,10 @@ Waypoints=Wegpunkte
Select Waypoint #@1=Wegpunkt Nr. @1 auswählen Select Waypoint #@1=Wegpunkt Nr. @1 auswählen
Waypoint @1=Wegpunkt Nr. @1 Waypoint @1=Wegpunkt Nr. @1
Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position
Hide waypoint= Hide waypoint=Wegpunkt verstecken
Show waypoint= Show waypoint=Wegpunkt zeigen
Hide coordinates= Hide coordinates=Koordinaten verstecken
Show coordinates= Show coordinates=Koordinaten zeigen
Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern
Edit waypoint name=Name des Wegpunkts ändern Edit waypoint name=Name des Wegpunkts ändern
Waypoint active=Wegpunkt aktiv Waypoint active=Wegpunkt aktiv

View File

@ -1,98 +1,91 @@
# textdomain: unified_inventory # textdomain: unified_inventory
Mixing= Category:=Kategorie:
Cooking= Mixing=Miksowanie
Digging= Cooking=Gotowanie
Digging=Kopanie
Bags=Plecaki Bags=Plecaki
Bag @1=Plecak @1 Bag @1=Plecak @1
Small Bag=Maly plecak Small Bag=Mały plecak
Medium Bag=Sredni plecak Medium Bag=Średni plecak
Large Bag=Duzy plecak Large Bag=Duży plecak
All Items= All Items=Wszystkie przedmioty
Misc. Items= Misc. Items=Różne przedmioty
Plant Life= Plant Life=Życie roślin
Building Materials= Building Materials=Materiały budowlane
Tools= Tools=Narzędzia
Minerals and Metals= Minerals and Metals=Minerały i metale
Environment and Worldgen= Environment and Worldgen=Otoczenie i generowanie świata
Lighting= Lighting=Oświetlenie
and = i and = i
Scroll categories left= Scroll categories left=Przewiń kategorię w lewo
Scroll categories right= Scroll categories right=Przewiń kategorię w prawo
Search=Szukaj Search=Szukaj
Reset search and display everything= Reset search and display everything=Zresetuj wyszukiwanie i pokaż wszystko
First page=Pierwsza strona First page=Pierwsza strona
Back three pages=3 strony w tyl Back three pages=Trzy strony do tyłu
Back one page=1 strona w tyl Back one page=Stronę do tyłu
Forward one page=1 strona do przodu Forward one page=Stronę do przodu
Forward three pages=3 strony do przodu Forward three pages=Trzy strony do przodu
Last page=Ostatnia strona Last page=Ostatnia strona
No matching items=Brak pasujacych przedmiotow No matching items=Brak pasujących przedmiotów
No matches.=Brak wyników No matches.=Brak wyników
Page=Strona Page=Strona
@1 of @2=@1 z @2 @1 of @2=@1 z @2
Filter=Filtr Filter=Filtr
Can use the creative inventory= Can use the creative inventory=Może używać kreatywnego ekwipunku
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Wymusza wyświetlanie Unified Inventory w trybie Full jeżeli tryb Lite jest skonfigurowany globalnie
Crafting Grid= Crafting Grid=Siatka craftingu
Crafting Guide= Crafting Guide=Przewodnik craftingu
Set home position=Ustaw pozycję wyjściową Set home position=Ustaw pozycję domu
Home position set to: @1=Pozycja domowa ustawiona na: @1 Home position set to: @1=Pozycja domu ustawiona na: @1
You don't have the "home" privilege!=Nie masz uprawnien do zmiany czasu "home"! You don't have the "home" privilege!=Brak uprawnień "home"!
Go home=Idź do domu Go home=Idź do domu
Set time to day=Ustaw czas na dzień Set time to day=Ustaw czas na dzień
Time of day set to 6am=Czas ustawiony na 6:00 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"! You don't have the settime privilege!=Brak uprawnień "settime"!
Set time to night=Ustaw czas na noc Set time to night=Ustaw czas na noc
Time of day set to 9pm=Czas ustawiony na 21:00 Time of day set to 9pm=Czas ustawiony na 21:00
Clear inventory=Wyczyść zapasy Clear inventory=Wyczyść ekwipunek
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=Aby zapobiec przypadkowemu skasowaniu ekwipunku, ten przycisk został wyłączony poza trybem kreatywnym.@nUżyj zamiast tego ikony śmietnika.
Inventory cleared!=Zapasy zostały wyczyszczone! Inventory cleared!=Ekwipunek został wyczyszczony!
Trash:=Smietnik: Trash:=Śmietnik:
Refill:=Uzupelnianie: Refill:=Uzupełnianie:
Any item belonging to the @1 group= Any item belonging to the @1 group=Każdy przedmiot należący do @1 grupy
Any item belonging to the groups @1= Any item belonging to the groups @1=Każdy przedmiot należacy do grup @1
Recipe @1 of @2=Recepta @1 z @2 Recipe @1 of @2=Recepta @1 z @2
Usage @1 of @2=Użycie @1 z @2 Usage @1 of @2=Użycie @1 z @2
No recipes=Brak recepty No recipes=Brak recepty
No usages=Bez użycia No usages=Bez użycia
Result=Wynik Result=Wynik
Ingredient=Składnik Ingredient=Składnik
Show next recipe= Show next recipe=Pokaż nastepną recepturę
Show next usage= Show next usage=Pokaż następne użycie
Show previous recipe= Show previous recipe=Pokaż poprzednią recepturę
Show previous usage= Show previous usage=Pokaż poprzednie użycie
@1 (@2)= @1 (@2)=@1 (@2)
Give me:=Daj mi: Give me:=Daj mi:
This recipe is too@@large to be displayed.= This recipe is too@@large to be displayed.=Receptura jest zbyt@@duża aby ją wyświetlić.
To craft grid:= To craft grid:=Do siatki craftingu.
All=Wszystko All=Wszystko
Crafting= Crafting=Crafting
White=Bialy White=Biały
Yellow=Zolty Yellow=Zółty
Red=Czerwony Red=Czerwony
Green=Zielony Green=Zielony
Blue=Niebieski Blue=Niebieski
Waypoints=Punkty orientacyjne Waypoints=Punkty orientacyjne
Select Waypoint #@1=Wybierz punkt #@1 Select Waypoint #@1=Wybierz punkt #@1
Waypoint @1=Punkty orientacyjne @1 Waypoint @1=Punkty orientacyjne @1
Set waypoint to current location=Ustaw punkt orientacyjny na biezacej pozycji Set waypoint to current location=Ustaw punkt orientacyjny na bieżacej pozycji
Hide waypoint= Hide waypoint=Ukryj punkt orientacyjny
Show waypoint= Show waypoint=Pokaż punkt orientacyjny
Hide coordinates= Hide coordinates=Ukryj koordynaty
Show coordinates= Show coordinates=Pokaż koordynaty
Change color of waypoint display=Zmien kolor punktu Change color of waypoint display=Zmień kolor punktu
Edit waypoint name=Edytuj nazwe punktu Edit waypoint name=Edytuj nazwę punktu
Waypoint active=Punkt wlaczony Waypoint active=Punkt włączony
Waypoint inactive=Punkt wylaczony Waypoint inactive=Punkt wyłączony
Finish editing=Zakoncz edycje Finish editing=Zakończ edycję
World position=Pozycja World position=Pozycja
Name=Nazwa Name=Nazwa
HUD text color=Kolor tekstu HUD 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

View File

@ -1,23 +1,23 @@
# textdomain: unified_inventory # textdomain: unified_inventory
Mixing=Мешать Mixing=Мешать
Cooking=Варить Cooking=Готовить
Digging=Копать Digging=Копать
Bags=Сумки Bags=Сумки
Bag @1=Сумка @1 Bag @1=Сумка @1
Small Bag=Малая сумка Small Bag=Малая сумка
Medium Bag=Средняя сумка Medium Bag=Средняя сумка
Large Bag=Большая сумка Large Bag=Большая сумка
All Items= All Items=Все предметы
Misc. Items= Misc. Items=Разн. предметы
Plant Life= Plant Life=Растения
Building Materials= Building Materials=Стройматериалы
Tools= Tools=Инструменты
Minerals and Metals= Minerals and Metals=Металлы и минералы
Environment and Worldgen= Environment and Worldgen=Окружение и генер.мира
Lighting= Lighting=Освещение
and = и and = и
Scroll categories left= Scroll categories left=Листать влево
Scroll categories right= Scroll categories right=Листать вправо
Search=Поиск Search=Поиск
Reset search and display everything=Сброс поиска, показать всё Reset search and display everything=Сброс поиска, показать всё
First page=Первая страница First page=Первая страница
@ -32,7 +32,7 @@ Page=Страница
@1 of @2=@1 из @2 @1 of @2=@1 из @2
Filter=Фильтр Filter=Фильтр
Can use the creative inventory=Можно использовать инвентарь творческого режима Can use the creative inventory=Можно использовать инвентарь творческого режима
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Отображает инвентарь в полном режиме, если простой режим установлен глобально
Crafting Grid=Решетка крафта Crafting Grid=Решетка крафта
Crafting Guide=Книга рецептов Crafting Guide=Книга рецептов
Set home position=Установить позицию дома Set home position=Установить позицию дома
@ -59,11 +59,11 @@ Result=Результат
Ingredient=Состав Ingredient=Состав
Show next recipe=Следующий рецепт Show next recipe=Следующий рецепт
Show next usage=Следующее использование Show next usage=Следующее использование
Show previous recipe=Прошлый рецепт Show previous recipe=Предыдущий рецепт
Show previous usage=Прошлая страница Show previous usage=Предыдущая страница
@1 (@2)= @1 (@2)=
Give me:=Дай мне: Give me:=Дай мне:
This recipe is too@@large to be displayed.= This recipe is too@@large to be displayed.=Этот рецепт слишком большой
To craft grid:=На решeтку крафта: To craft grid:=На решeтку крафта:
All=Все All=Все
Crafting=Крафт Crafting=Крафт
@ -76,10 +76,10 @@ Waypoints=Путевые точки
Select Waypoint #@1=Выбрать путевую точку №@1 Select Waypoint #@1=Выбрать путевую точку №@1
Waypoint @1=Путевая точка @1 Waypoint @1=Путевая точка @1
Set waypoint to current location=Установить путевую точку по текущей позиции Set waypoint to current location=Установить путевую точку по текущей позиции
Hide waypoint= Hide waypoint=Скрыть точку
Show waypoint= Show waypoint=Показать точку
Hide coordinates= Hide coordinates=Скрыть координаты
Show coordinates= Show coordinates=Показать координаты
Change color of waypoint display=Поменять цвет путевой точки Change color of waypoint display=Поменять цвет путевой точки
Edit waypoint name=Переименовать путевую точку Edit waypoint name=Переименовать путевую точку
Waypoint active=Путевая точка включена Waypoint active=Путевая точка включена
@ -88,13 +88,4 @@ Finish editing=Закончить редакцию
World position=Позиция мира World position=Позиция мира
Name=Имя Name=Имя
HUD text color=Цвет текста HUDа HUD text color=Цвет текста HUDа
Category:=Категории:
##### not used anymore #####
invisible=невидимой
visible=видимой
Make waypoint @1=Сделать путевую точку @1
Disable=Выключить
Enable=Включить
@1 display of waypoint coordinates=@1 показ координат путевых точек

View File

@ -7,17 +7,17 @@ Bag @1=背包@1
Small Bag=小背包 Small Bag=小背包
Medium Bag=中背包 Medium Bag=中背包
Large Bag=大背包 Large Bag=大背包
All Items= All Items=所有物品
Misc. Items= Misc. Items=杂项
Plant Life= Plant Life=植物
Building Materials= Building Materials=建材
Tools= Tools=工具
Minerals and Metals= Minerals and Metals=矿物与金属
Environment and Worldgen= Environment and Worldgen=自然环境
Lighting= Lighting=光源
and = 和 and = 和
Scroll categories left= Scroll categories left=向左滚动分类栏
Scroll categories right= Scroll categories right=向右滚动分类栏
Search=搜索 Search=搜索
Reset search and display everything=重置搜索并显示所有物品 Reset search and display everything=重置搜索并显示所有物品
First page=第一页 First page=第一页
@ -32,7 +32,7 @@ Page=页面
@1 of @2=第@1页共@2页 @1 of @2=第@1页共@2页
Filter=过滤器 Filter=过滤器
Can use the creative inventory=可以使用创造背包 Can use the creative inventory=可以使用创造背包
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果轻量模式被全局配置强迫Unified Inventory以完全模式展现。
Crafting Grid=合成表 Crafting Grid=合成表
Crafting Guide=合成指南 Crafting Guide=合成指南
Set home position=设置家的位置 Set home position=设置家的位置
@ -45,7 +45,7 @@ You don't have the settime privilege!=你没有“settime”权限
Set time to night=设置时间到晚上 Set time to night=设置时间到晚上
Time of day set to 9pm=时间设置到晚上9点 Time of day set to 9pm=时间设置到晚上9点
Clear inventory=清空背包 Clear inventory=清空背包
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按钮已在非创造模式中禁用以防止意外的背包清空。@n请使用垃圾桶栏。
Inventory cleared!=清空背包 Inventory cleared!=清空背包
Trash:=丢弃: Trash:=丢弃:
Refill:=填满: Refill:=填满:
@ -57,13 +57,13 @@ No recipes=没有配方
No usages=没有用法 No usages=没有用法
Result=结果 Result=结果
Ingredient=原料 Ingredient=原料
Show next recipe= Show next recipe=显示下一个配方
Show next usage= Show next usage=显示下一个用法
Show previous recipe= Show previous recipe=显示前一个配方
Show previous usage= Show previous usage=显示前一个用法
@1 (@2)= @1 (@2)=@1 (@2)
Give me:=给予: Give me:=给予:
This recipe is too@@large to be displayed.= This recipe is too@@large to be displayed.=该配方太@@大,不能显示。
To craft grid:=填充物品到合成表 To craft grid:=填充物品到合成表
All=全部 All=全部
Crafting=合成 Crafting=合成
@ -76,10 +76,10 @@ Waypoints=航路点
Select Waypoint #@1=查询航路点 #@1 Select Waypoint #@1=查询航路点 #@1
Waypoint @1=航路点 @1 Waypoint @1=航路点 @1
Set waypoint to current location=将航路点设置到当前位置 Set waypoint to current location=将航路点设置到当前位置
Hide waypoint= Hide waypoint=隐藏航路点
Show waypoint= Show waypoint=显示航路点
Hide coordinates= Hide coordinates=隐藏坐标
Show coordinates= Show coordinates=显示坐标
Change color of waypoint display=改变航路点显示的颜色 Change color of waypoint display=改变航路点显示的颜色
Edit waypoint name=编辑航路点名称 Edit waypoint name=编辑航路点名称
Waypoint active=航路点已激活 Waypoint active=航路点已激活

View File

@ -7,17 +7,17 @@ Bag @1=揹包@1
Small Bag=小揹包 Small Bag=小揹包
Medium Bag=中揹包 Medium Bag=中揹包
Large Bag=大揹包 Large Bag=大揹包
All Items= All Items=所有物品
Misc. Items= Misc. Items=雜項
Plant Life= Plant Life=植物
Building Materials= Building Materials=建材
Tools= Tools=工具
Minerals and Metals= Minerals and Metals=礦物與金屬
Environment and Worldgen= Environment and Worldgen=自然環境
Lighting= Lighting=光源
and = 和 and = 和
Scroll categories left= Scroll categories left=向左滾動分類欄
Scroll categories right= Scroll categories right=向右滾動分類欄
Search=搜索 Search=搜索
Reset search and display everything=重置搜索並顯示所有物品 Reset search and display everything=重置搜索並顯示所有物品
First page=第一頁 First page=第一頁
@ -32,7 +32,7 @@ Page=頁面
@1 of @2=第@1頁共@2頁 @1 of @2=第@1頁共@2頁
Filter=過濾器 Filter=過濾器
Can use the creative inventory=可以使用創造揹包 Can use the creative inventory=可以使用創造揹包
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果輕量模式被全局配置強迫Unified Inventory以完全模式展現。
Crafting Grid=合成表 Crafting Grid=合成表
Crafting Guide=合成指南 Crafting Guide=合成指南
Set home position=設置家的位置 Set home position=設置家的位置
@ -45,7 +45,7 @@ You don't have the settime privilege!=你沒有“settime”權限
Set time to night=設置時間到晚上 Set time to night=設置時間到晚上
Time of day set to 9pm=時間設置到晚上9點 Time of day set to 9pm=時間設置到晚上9點
Clear inventory=清空揹包 Clear inventory=清空揹包
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按鈕已在非創造模式中禁用以防止意外的背包清空。@n請使用垃圾桶欄。
Inventory cleared!=清空揹包 Inventory cleared!=清空揹包
Trash:=丟棄: Trash:=丟棄:
Refill:=填滿: Refill:=填滿:
@ -57,13 +57,13 @@ No recipes=沒有配方
No usages=沒有用法 No usages=沒有用法
Result=結果 Result=結果
Ingredient=原料 Ingredient=原料
Show next recipe= Show next recipe=顯示下一個配方
Show next usage= Show next usage=顯示下一個用法
Show previous recipe= Show previous recipe=顯示上一個配方
Show previous usage= Show previous usage=顯示上一個用法
@1 (@2)= @1 (@2)=@1 (@2)
Give me:=給予: Give me:=給予:
This recipe is too@@large to be displayed.= This recipe is too@@large to be displayed.=該配方太@@大,不能顯示。
To craft grid:=填充物品到合成表 To craft grid:=填充物品到合成表
All=全部 All=全部
Crafting=合成 Crafting=合成
@ -76,10 +76,10 @@ Waypoints=航路點
Select Waypoint #@1=查詢航路點 #@1 Select Waypoint #@1=查詢航路點 #@1
Waypoint @1=航路點 @1 Waypoint @1=航路點 @1
Set waypoint to current location=將航路點設置到當前位置 Set waypoint to current location=將航路點設置到當前位置
Hide waypoint= Hide waypoint=隱藏航路點
Show waypoint= Show waypoint=顯示航路點
Hide coordinates= Hide coordinates=隱藏坐標
Show coordinates= Show coordinates=顯示坐標
Change color of waypoint display=改變航路點顯示的顏色 Change color of waypoint display=改變航路點顯示的顏色
Edit waypoint name=編輯航路點名稱 Edit waypoint name=編輯航路點名稱
Waypoint active=航路點已激活 Waypoint active=航路點已激活

View File

@ -126,25 +126,18 @@ Example output:
} }
--]] --]]
function unified_inventory.find_usable_items(inv_items, craft_items) function unified_inventory.find_usable_items(inv_items, craft_items)
local get_group = minetest.get_item_group
local result = {} local result = {}
for craft_item in pairs(craft_items) do for craft_item in pairs(craft_items) do
local group = craft_item:match("^group:(.+)") -- may specify group:type1,type2
local items = unified_inventory.get_matching_items(craft_item)
local found = {} local found = {}
for itemname, _ in pairs(items) do
if group ~= nil then if inv_items[itemname] then
for inv_item in pairs(inv_items) do found[itemname] = true
if get_group(inv_item, group) > 0 then
found[inv_item] = true
end end
end end
else
if inv_items[craft_item] ~= nil then
found[craft_item] = true
end
end
result[craft_item] = found result[craft_item] = found
end end

View File

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

View File

@ -49,7 +49,7 @@ ui.register_button("misc_set_day", {
action = function(player) action = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("birds", minetest.sound_play("ui_morning",
{to_player=player_name, gain = 1.0}) {to_player=player_name, gain = 1.0})
minetest.set_timeofday((6000 % 24000) / 24000) minetest.set_timeofday((6000 % 24000) / 24000)
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
@ -73,7 +73,7 @@ ui.register_button("misc_set_night", {
action = function(player) action = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {settime=true}) then if minetest.check_player_privs(player_name, {settime=true}) then
minetest.sound_play("owl", minetest.sound_play("ui_owl",
{to_player=player_name, gain = 1.0}) {to_player=player_name, gain = 1.0})
minetest.set_timeofday((21000 % 24000) / 24000) minetest.set_timeofday((21000 % 24000) / 24000)
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
@ -134,14 +134,14 @@ ui.register_page("craft", {
local n=#formspec+1 local n=#formspec+1
if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then
formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.45, crafty + 2.4, F(S("Trash:"))) formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.35, crafty + 2.3, F(S("Trash:")))
formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5) formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5)
n=n + 2 n=n + 2
end end
if ui.is_creative(player_name) then if ui.is_creative(player_name) then
formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5) formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5)
formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.3, crafty + 2.4,F(S("Refill:"))) formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.4, crafty + 2.3, F(S("Refill:")))
formspec[n+2] = string.format("list[detached:%srefill;main;%f,%f;1,1;]", formspec[n+2] = 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) F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset)
end end
@ -158,17 +158,15 @@ ui.register_page("craft", {
local function stack_image_button(x, y, w, h, buttonname_prefix, item) local function stack_image_button(x, y, w, h, buttonname_prefix, item)
local name = item:get_name() local name = item:get_name()
local count = item:get_count()
local wear = item:get_wear()
local description = item:get_meta():get_string("description") local description = item:get_meta():get_string("description")
local show_is_group = false local show_is_group = false
local displayitem = name.." "..count.." "..wear local displayitem = item:to_string()
local selectitem = name local selectitem = name
if name:sub(1, 6) == "group:" then if name:sub(1, 6) == "group:" then
local group_name = name:sub(7) local group_name = name:sub(7)
local group_item = ui.get_group_item(group_name) local group_item = ui.get_group_item(group_name)
show_is_group = not group_item.sole show_is_group = not group_item.sole
displayitem = group_item.item or "unknown" displayitem = group_item.item or name
selectitem = group_item.sole and displayitem or name selectitem = group_item.sole and displayitem or name
end end
local label = show_is_group and "G" or "" local label = show_is_group and "G" or ""
@ -196,6 +194,9 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
return button return button
end end
-- The recipe text contains parameters, hence they can yet not be translated.
-- Instead, use a dummy translation call so that it can be picked up by the
-- static parsing of the translation string update script
local recipe_text = { local recipe_text = {
recipe = NS("Recipe @1 of @2"), recipe = NS("Recipe @1 of @2"),
usage = NS("Usage @1 of @2"), usage = NS("Usage @1 of @2"),
@ -248,11 +249,10 @@ ui.register_page("craftguide", {
local n = 4 local n = 4
local item_def = minetest.registered_items[item_name]
local item_name_shown local item_name_shown
if minetest.registered_items[item_name] if item_def and item_def.description then
and minetest.registered_items[item_name].description then item_name_shown = S("@1 (@2)", item_def.description, item_name)
item_name_shown = S("@1 (@2)",
minetest.registered_items[item_name].description, item_name)
else else
item_name_shown = item_name item_name_shown = item_name
end end
@ -277,12 +277,14 @@ ui.register_page("craftguide", {
F(role_text[dir]), item_name_shown) F(role_text[dir]), item_name_shown)
n = n + 2 n = n + 2
local giveme_form = table.concat({ local giveme_form =
"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]", "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) .. "," .. (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]", if item_def and item_def.type ~= "tool" then
giveme_form = giveme_form ..
"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]" "button[" .. (give_x + 1.6) .. "," .. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]"
}) end
if not craft then if not craft then
-- No craft recipes available for this item. -- No craft recipes available for this item.
@ -450,6 +452,14 @@ local function craftguide_craft(player, formname, fields)
local alternate = ui.alternate[player_name] local alternate = ui.alternate[player_name]
local craft = crafts[alternate] 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 if craft.width > 3 then return end
ui.craftguide_match_craft(player, "main", "craft", craft, amount) ui.craftguide_match_craft(player, "main", "craft", craft, amount)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -1,14 +1,36 @@
#Enabling lite mode enables a smaller and simpler version of the Unified # Reduced formspec layout, optimized for smaller displays.
#Inventory, optimized for small displays. # Note: This may also disable some features to free up visual space.
unified_inventory_lite (Lite mode) bool false unified_inventory_lite (Lite mode) bool false
#If enabled, bags will be made available which can be used to extend # Provides craftable bag items to extend the inventory space.
#inventory storage size.
unified_inventory_bags (Enable bags) bool true unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative # Shows the trash slot to everyone.
#and the give privilege. # When disabled, only players with the privilege "creative" or "give" will
# have this slot shown in their inventory.
unified_inventory_trash (Enable trash) bool true unified_inventory_trash (Enable trash) bool true
# Provides waypoints on a per-player basis to remember positions on the map.
unified_inventory_waypoints (Enable waypoints) bool true
unified_inventory_automatic_categorization (Items automatically added to categories) bool true # If enabled, disabled buttons will be hidden instead of grayed out.
unified_inventory_hide_disabled_buttons (Hide disabled buttons) bool false
# Hides items with no known craft recipe from the category "all" (default).
# This setting has no effect on players in creative mode.
unified_inventory_hide_uncraftable_items (Hide uncraftable items) bool false
# Automatically categorizes registered items based on their
# groups. This is based on a fuzzy match, thus is not 100% accurate.
unified_inventory_automatic_categorization (Categories: add items automatically) bool true
# Shows the selected wielded item description in the HUD for a few seconds.
unified_inventory_item_names (Enable HUD item names) bool true
# Trims the shown wielded item description to the first line.
unified_inventory_only_names (HUD item name: first line only) bool true
# Hard character limit of the wielded item description.
# Crops the shown description to the specified length.
# 0 disables this functionality.
unified_inventory_max_item_name_length (HUD item names: character limit) int 80

Binary file not shown.

Binary file not shown.

BIN
sounds/ui_click.ogg Normal file

Binary file not shown.

BIN
sounds/ui_morning.ogg Normal file

Binary file not shown.

BIN
sounds/ui_owl.ogg Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 551 B

BIN
textures/ui_teleport.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -103,7 +103,7 @@ local function get_waypoint_data(player)
end end
ui.register_page("waypoints", { ui.register_page("waypoints", {
get_formspec = function(player) get_formspec = function(player, perplayer_formspec)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local wp_info_x = ui.style_full.form_header_x + 1.25 local wp_info_x = ui.style_full.form_header_x + 1.25
local wp_info_y = ui.style_full.form_header_y + 0.5 local wp_info_y = ui.style_full.form_header_y + 0.5
@ -115,12 +115,16 @@ ui.register_page("waypoints", {
local sel = waypoints.selected or 1 local sel = waypoints.selected or 1
local formspec = { local formspec = {
ui.style_full.standard_inv_bg,
string.format("label[%f,%f;%s]", string.format("label[%f,%f;%s]",
ui.style_full.form_header_x, ui.style_full.form_header_y, F(S("Waypoints"))), ui.style_full.form_header_x, ui.style_full.form_header_y, F(S("Waypoints"))),
"image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]" "image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]"
} }
local n=4 local n=3
if not perplayer_formspec.is_lite_mode then
formspec[n] = ui.style_full.standard_inv_bg
n = n + 1
end
-- Tabs buttons: -- Tabs buttons:
for i = 1, COUNT do for i = 1, COUNT do
@ -140,36 +144,49 @@ ui.register_page("waypoints", {
-- Main buttons: -- Main buttons:
local btnlist = { local btnlist = {
set_waypoint = { -- 1. formspec name
"ui_waypoint_set_icon.png", -- 2. button image
S("Set waypoint to current location") -- 3. translation text
}, {
toggle_waypoint = { "toggle_waypoint",
waypoint.active and "ui_on_icon.png" or "ui_off_icon.png", waypoint.active and "ui_on_icon.png" or "ui_off_icon.png",
waypoint.active and S("Hide waypoint") or S("Show waypoint") waypoint.active and S("Hide waypoint") or S("Show waypoint")
}, },
toggle_display_pos = { {
"rename_waypoint",
"ui_pencil_icon.png",
S("Edit waypoint name")
},
{
"set_waypoint",
"ui_waypoint_set_icon.png",
S("Set waypoint to current location")
},
{
"toggle_display_pos",
waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)", waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)",
waypoint.display_pos and S("Hide coordinates") or S("Show coordinates") waypoint.display_pos and S("Hide coordinates") or S("Show coordinates")
}, },
toggle_color = { {
"toggle_color",
"ui_circular_arrows_icon.png", "ui_circular_arrows_icon.png",
S("Change color of waypoint display") S("Change color of waypoint display")
}, },
rename_waypoint = {
"ui_pencil_icon.png",
S("Edit waypoint name")
}
} }
if minetest.get_player_privs(player_name).teleport then
table.insert(btnlist, {
"teleport_waypoint",
"ui_teleport.png",
S("Teleport to waypoint")
})
end
local x = 4 for i, def in pairs(btnlist) do
for name, def in pairs(btnlist) do
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]", formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]",
wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row, wp_buttons_rj + ui.style_full.btn_spc * (i - #btnlist), wp_bottom_row,
ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size,
def[1], name, sel) def[2], def[1], sel)
formspec[n+1] = "tooltip["..name..sel..";"..F(def[2]).."]" formspec[n+1] = "tooltip["..def[1]..sel..";"..F(def[3]).."]"
x = x - 1
n = n + 2 n = n + 2
end end
@ -199,7 +216,10 @@ ui.register_page("waypoints", {
formspec[n+2] = string.format("label[%f,%f;%s: %s]", formspec[n+2] = string.format("label[%f,%f;%s: %s]",
wp_info_x, wp_info_y+2.60, F(S("HUD text color")), hud_colors[waypoint.color or 1][3]) wp_info_x, wp_info_y+2.60, F(S("HUD text color")), hud_colors[waypoint.color or 1][3])
return {formspec=table.concat(formspec)} return {
formspec = table.concat(formspec),
draw_inventory = not perplayer_formspec.is_lite_mode,
}
end, end,
}) })
@ -207,7 +227,6 @@ ui.register_button("waypoints", {
type = "image", type = "image",
image = "ui_waypoints_icon.png", image = "ui_waypoints_icon.png",
tooltip = S("Waypoints"), tooltip = S("Waypoints"),
hide_lite=true
}) })
local function update_hud(player, waypoints, temp, i) local function update_hud(player, waypoints, temp, i)
@ -313,6 +332,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
update_formspec = true update_formspec = true
end end
if fields["teleport_waypoint" .. i] and waypoint.world_pos then
if minetest.get_player_privs(player_name).teleport then
minetest.sound_play("teleport", {to_player = player_name})
player:set_pos(waypoint.world_pos)
end
end
if hit then if hit then
-- Save first -- Save first
waypoints.data[i] = waypoint waypoints.data[i] = waypoint
@ -323,6 +349,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
update_hud(player, waypoints, temp, i) update_hud(player, waypoints, temp, i)
end end
if update_formspec then if update_formspec then
minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1})
ui.set_inventory_formspec(player, "waypoints") ui.set_inventory_formspec(player, "waypoints")
end end