48 Commits

Author SHA1 Message Date
dd17b6ce17 Fix deprecated field 'hud_elem_type' and limit line length 2025-06-15 15:28:18 +02:00
240e6cc68a Add Ukrainian localization (#258) 2025-03-25 21:59:11 +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
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
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
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
182ab493c3 Update CN translation 2022-07-29 21:42:59 +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
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
d6688872c8 Fix two occasional runtime errors (#191) 2021-12-25 17:31:18 +01:00
33 changed files with 1032 additions and 598 deletions

View File

@ -1,6 +1,6 @@
unused_args = false
allow_defined_top = true
max_line_length = 999
max_line_length = 131
globals = {
"unified_inventory",
@ -10,8 +10,10 @@ read_globals = {
string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn"}},
"minetest", "vector",
"dump",
"core", "minetest",
"ItemStack", "datastorage",
"vector",
"hb",
"doors",

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_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+):
* [`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)
* 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)

149
api.lua
View File

@ -2,48 +2,61 @@ local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape
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
minetest.after(0.01, function()
local rev_aliases = {}
for source, target in pairs(minetest.registered_aliases) do
if not rev_aliases[target] then rev_aliases[target] = {} end
table.insert(rev_aliases[target], source)
for original, newname in pairs(minetest.registered_aliases) do
if not rev_aliases[newname] then
rev_aliases[newname] = {}
end
table.insert(rev_aliases[newname], original)
end
-- Filtered item list
ui.items_list = {}
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or
def.groups.not_in_creative_inventory == 0) and
def.description and def.description ~= "" then
if ui.is_itemdef_listable(def) then
table.insert(ui.items_list, name)
-- Alias processing: Find recipes that belong to the current item name
local all_names = rev_aliases[name] or {}
table.insert(all_names, name)
for _, player_name in ipairs(all_names) do
local recipes = minetest.get_all_craft_recipes(player_name)
if recipes then
for _, recipe in ipairs(recipes) do
local unknowns
for _,chk in pairs(recipe.items) do
local groupchk = string.find(chk, "group:")
if (not groupchk and not minetest.registered_items[chk])
or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item)
or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then
unknowns = true
end
end
if not unknowns then
ui.register_craft(recipe)
end
for _, itemname in ipairs(all_names) do
local recipes = minetest.get_all_craft_recipes(itemname)
for _, recipe in ipairs(recipes or {}) do
if is_recipe_craftable(recipe) then
ui.register_craft(recipe)
end
end
end
end
end
table.sort(ui.items_list)
ui.items_list_size = #ui.items_list
print("Unified Inventory. inventory size: "..ui.items_list_size)
print("Unified Inventory. Inventory size: "..ui.items_list_size)
-- Analyse dropped items -> custom "digging" recipes
for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name]
-- Simple drops
@ -133,24 +146,73 @@ minetest.after(0.01, function()
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
local ingredient_items = {}
for _, spec in pairs(recipe.items) do
local matches_spec = ui.canonical_item_spec_matcher(spec)
for _, name in ipairs(ui.items_list) do
if matches_spec(name) then
ingredient_items[name] = true
end
-- Get items that fit into this spec (group or item name)
local specname = ItemStack(spec):get_name()
for item_name, _ in pairs(get_matching_spec_items(specname)) do
ingredient_items[item_name] = true
end
end
for name, _ in pairs(ingredient_items) do
if ui.crafts_for.usage[name] == nil then
if not ui.crafts_for.usage[name] then
ui.crafts_for.usage[name] = {}
end
table.insert(ui.crafts_for.usage[name], recipe)
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
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
@ -158,8 +220,8 @@ minetest.after(0.01, function()
end
end)
---------------- Home API ----------------
-- load_home
local function load_home()
local input = io.open(ui.home_filename, "r")
if not input then
@ -176,6 +238,7 @@ local function load_home()
end
io.close(input)
end
load_home()
function ui.set_home(player, pos)
@ -204,7 +267,8 @@ function ui.go_home(player)
return false
end
-- register_craft
---------------- Crafting API ----------------
function ui.register_craft(options)
if not options.output then
return
@ -227,14 +291,12 @@ function ui.register_craft(options)
end
end
local craft_type_defaults = {
width = 3,
height = 3,
uses_crafting_grid = false,
}
function ui.craft_type_defaults(name, options)
if not options.description then
options.description = name
@ -245,8 +307,7 @@ end
function ui.register_craft_type(name, options)
ui.registered_craft_types[name] =
ui.craft_type_defaults(name, options)
ui.registered_craft_types[name] = ui.craft_type_defaults(name, options)
end
@ -303,6 +364,8 @@ ui.register_craft_type("digging_chance", {
height = 1,
})
---------------- GUI registrations ----------------
function ui.register_page(name, def)
ui.pages[name] = def
end
@ -318,6 +381,8 @@ function ui.register_button(name, def)
table.insert(ui.buttons, def)
end
---------------- Callback registrations ----------------
function ui.register_on_initialized(callback)
if type(callback) ~= "function" then
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)
end
---------------- List getters ----------------
function ui.get_recipe_list(output)
return ui.crafts_for.recipe[output]
end
@ -344,11 +411,15 @@ function ui.get_registered_outputs()
return outputs
end
---------------- Player utilities ----------------
function ui.is_creative(playername)
return minetest.check_player_privs(playername, {creative=true})
or minetest.settings:get_bool("creative_mode")
end
---------------- Formspec helpers ----------------
function ui.single_slot(xpos, ypos, bright)
return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]",
xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") )

143
bags.lua
View File

@ -10,25 +10,26 @@ local F = minetest.formspec_escape
local ui = unified_inventory
ui.register_page("bags", {
get_formspec = function(player)
get_formspec = function(player, perplayer_formspec)
local player_name = player:get_player_name()
return { formspec = table.concat({
ui.style_full.standard_inv_bg,
ui.single_slot(0.925, 1.5),
ui.single_slot(3.425, 1.5),
ui.single_slot(5.925, 1.5),
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)) .. "]",
local std_inv_x = perplayer_formspec.std_inv_x
local formspec = {
perplayer_formspec.standard_inv_bg,
"label[", perplayer_formspec.form_header_x, ",",
perplayer_formspec.form_header_y, ";", F(S("Bags")), "]",
"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;]",
"list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]"
}) }
}
for i = 1, 4 do
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,
})
@ -36,7 +37,6 @@ ui.register_button("bags", {
type = "image",
image = "ui_bags_icon.png",
tooltip = S("Bags"),
hide_lite=true
})
local function get_player_bag_stack(player, i)
@ -48,23 +48,38 @@ end
for bag_i = 1, 4 do
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 image = stack:get_definition().inventory_image
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 = {
ui.style_full.standard_inv_bg,
ui.make_inv_img_grid(0.3, 1.5, 8, slots/8),
"image[9.2,0.4;1,1;" .. image .. "]",
"label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
perplayer_formspec.standard_inv_bg,
ui.make_inv_img_grid(std_inv_x, bag_inv_y, 8, slots/8),
"label[", header_x, ",", header_y, ";", F(S("Bag @1", bag_i)), "]",
"listcolors[#00000000;#00000000]",
"listring[current_player;main]",
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),
"listring[current_name;bag" .. bag_i .. "contents]",
bag_i, std_inv_x + ui.list_img_offset, bag_inv_y + ui.list_img_offset),
"listring[current_name;bag", bag_i, "contents]",
}
if lite_mode then
return { formspec = table.concat(formspec) }
end
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.
if ui.trash_enabled
@ -114,6 +129,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
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 is_empty = true
local bags = {}
@ -127,7 +144,7 @@ local function save_bags_metadata(player, bags_inv)
end
local meta = player:get_meta()
if is_empty then
meta:set_string("unified_inventory:bags", nil)
meta:set_string("unified_inventory:bags", "")
else
meta:set_string("unified_inventory:bags",
minetest.serialize(bags))
@ -163,7 +180,7 @@ local function load_bags_metadata(player, bags_inv)
save_bags_metadata(player, bags_inv)
end
-- Clean up deprecated garbage after saving
-- Legacy: Clean up old player lists
for i = 1, 4 do
local bag = "bag" .. i
player_inv:set_size(bag, 0)
@ -172,46 +189,29 @@ end
minetest.register_on_joinplayer(function(player)
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)
player:get_inventory():set_size(listname .. "contents",
stack:get_definition().groups.bagslots)
save_bags_metadata(player, inv)
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)
if player:get_inventory():is_empty(listname .. "contents") then
return stack:get_count()
@ -221,6 +221,11 @@ minetest.register_on_joinplayer(function(player)
on_take = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname .. "contents", 0)
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,
allow_move = function()
return 0
@ -230,6 +235,20 @@ minetest.register_on_joinplayer(function(player)
load_bags_metadata(player, bags_inv)
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
minetest.register_tool("unified_inventory:bag_small", {
description = S("Small Bag"),

View File

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

View File

@ -96,6 +96,9 @@ function unified_inventory.register_category(category_name, config)
end
update_category_list()
end
-- TODO: Mark these for removal. They are pretty much useless
function unified_inventory.set_category_symbol(category_name, symbol)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].symbol = symbol
@ -112,6 +115,11 @@ function unified_inventory.set_category_index(category_name, index)
update_category_list()
end
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)
unified_inventory.registered_category_items[category_name][item] = true
end

View File

@ -1,4 +1,5 @@
local S = minetest.get_translator("unified_inventory")
local ui = unified_inventory
unified_inventory.register_category('plants', {
symbol = "flowers:tulip",
@ -25,71 +26,87 @@ unified_inventory.register_category('lighting', {
label = S("Lighting")
})
if unified_inventory.automatic_categorization then
minetest.register_on_mods_loaded(function()
-- Add biome nodes to environment category
for _,def in pairs(minetest.registered_biomes) do
local env_nodes = {
def.node_riverbed, def.node_top, def.node_filler, def.node_dust,
}
for i,node in pairs(env_nodes) do
if node then
unified_inventory.add_category_item('environment', node)
end
local function register_automatic_categorization()
-- Add biome nodes to environment category
for _,def in pairs(minetest.registered_biomes) do
local env_nodes = {
def.node_riverbed, def.node_top, def.node_filler, def.node_dust,
}
for i,node in pairs(env_nodes) do
if node then
unified_inventory.add_category_item('environment', node)
end
end
end
-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment
for _,item in pairs(minetest.registered_ores) do
if item.ore_type == "scatter" then
local drop = minetest.registered_nodes[item.ore].drop
if drop and drop ~= "" then
unified_inventory.add_category_item('minerals', item.ore)
unified_inventory.add_category_item('minerals', drop)
else
unified_inventory.add_category_item('environment', item.ore)
-- Preparation for ore registration: find all possible drops (digging)
local possible_node_dig_drops = {
-- ["default:stone_with_coal"] = { "default:coal_lump", "mymod:raregem" }
-- Ores may be contained multiple times, depending on drop chances.
}
for itemname, recipes in pairs(ui.crafts_for.usage) do
for _, recipe in ipairs(recipes) do
if recipe.type == "digging" or recipe.type == "digging_chance" then
if not possible_node_dig_drops[itemname] then
possible_node_dig_drops[itemname] = {}
end
else
unified_inventory.add_category_item('environment', item.ore)
local stack = ItemStack(recipe.output)
table.insert(possible_node_dig_drops[itemname], stack:get_name())
end
end
end
-- Add items by item definition
for name, def in pairs(minetest.registered_items) do
local group = def.groups or {}
if not group.not_in_creative_inventory then
if group.stair or
group.slab or
group.wall or
group.fence then
unified_inventory.add_category_item('building', name)
elseif group.flora or
group.flower or
group.seed or
group.leaves or
group.sapling or
group.tree then
unified_inventory.add_category_item('plants', name)
elseif def.type == 'tool' then
unified_inventory.add_category_item('tools', name)
elseif def.liquidtype == 'source' then
unified_inventory.add_category_item('environment', name)
elseif def.light_source and def.light_source > 0 then
unified_inventory.add_category_item('lighting', name)
elseif group.door or
minetest.global_exists("doors") and (
doors.registered_doors and doors.registered_doors[name..'_a'] or
doors.registered_trapdoors and doors.registered_trapdoors[name]
) then
unified_inventory.add_category_item('building', name)
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
ui.add_category_item('environment', odef.ore)
end
end
-- Add items by item definition
for name, def in pairs(minetest.registered_items) do
local group = def.groups or {}
if not group.not_in_creative_inventory then
if group.stair or
group.slab or
group.wall or
group.fence then
unified_inventory.add_category_item('building', name)
elseif group.flora or
group.flower or
group.seed or
group.leaves or
group.sapling or
group.tree then
unified_inventory.add_category_item('plants', name)
elseif def.type == 'tool' then
unified_inventory.add_category_item('tools', name)
elseif def.liquidtype == 'source' then
unified_inventory.add_category_item('environment', name)
elseif def.light_source and def.light_source > 0 then
unified_inventory.add_category_item('lighting', name)
elseif group.door or
minetest.global_exists("doors") and (
doors.registered_doors and doors.registered_doors[name..'_a'] or
doors.registered_trapdoors and doors.registered_trapdoors[name]
) then
unified_inventory.add_category_item('building', name)
end
end
end)
end
end
if ui.automatic_categorization then
ui.register_on_initialized(register_automatic_categorization)
end
-- [[
unified_inventory.add_category_items('plants', {
"default:dry_grass_5",
@ -256,23 +273,6 @@ unified_inventory.add_category_items('minerals', {
"default:coal_lump",
"default:bronzeblock",
"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', {

View File

@ -1,7 +1,8 @@
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:
@ -23,7 +24,9 @@ Grouped by use-case, afterwards sorted alphabetically.
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(
function (item_name, options)
@ -163,68 +166,57 @@ Register a non-standard craft recipe:
Categories
----------
Register a new category:
The config table (second argument) is optional, and all its members are optional
See the unified_inventory.set_category_* functions for more details on the members of the config table
* `unified_inventory.register_category(name, def)`
* Registers a new category
* `name` (string): internal category name
* `def` (optional, table): also its fields are optional
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",
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 = {
"mod_name:item_name",
"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:
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"
Modifier functions (to be removed)
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:
If unset this will default to the category name
Item management
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")
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
local ui = unified_inventory
function unified_inventory.extract_groupnames(groupname)
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
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
-- 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
-- "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 group_names = group_name_list:split(",")
local candidate_items = {}
@ -125,3 +86,61 @@ function unified_inventory.get_group_item(group_name)
return group_item_cache[group_name]
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
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 worldpath = minetest.get_worldpath()
@ -44,9 +50,12 @@ unified_inventory = {
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25,
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
@ -59,10 +68,16 @@ ui.style_full = {
formspec_y = 1,
formw = 17.75,
formh = 12.25,
-- Item browser size, pos
pagecols = 8,
pagerows = 9,
page_x = 10.75,
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_y = 1.15,
craftresult_x = 7.8,
@ -74,13 +89,15 @@ ui.style_full = {
craft_guide_resultstr_x = 0.3,
craft_guide_resultstr_y = 0.6,
give_btn_x = 0.25,
-- Tab switching buttons
main_button_x = 0.4,
main_button_y = 11.0,
page_buttons_x = 11.60,
page_buttons_y = 10.15,
searchwidth = 3.4,
main_button_cols = 12,
main_button_rows = 1,
-- Tab title position
form_header_x = 0.4,
form_header_y = 0.4,
-- Generic sizes
btn_spc = 0.85,
btn_size = 0.75,
std_inv_x = 0.3,
@ -92,10 +109,16 @@ ui.style_lite = {
formspec_y = 0.6,
formw = 14,
formh = 9.75,
-- Item browser size, pos
pagecols = 4,
pagerows = 5,
page_x = 10.5,
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_y = 0.75,
craftresult_x = 5.75,
@ -107,13 +130,15 @@ ui.style_lite = {
craft_guide_resultstr_x = 0.15,
craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15,
-- Tab switching buttons
main_button_x = 10.5,
main_button_y = 8.15,
page_buttons_x = 10.5,
page_buttons_y = 6.15,
searchwidth = 1.6,
main_button_cols = 4,
main_button_rows = 2,
-- Tab title position
form_header_x = 0.2,
form_header_y = 0.2,
-- Generic sizes
btn_spc = 0.8,
btn_size = 0.7,
std_inv_x = 0.1,
@ -167,6 +192,10 @@ dofile(modpath.."/register.lua")
if minetest.settings:get_bool("unified_inventory_bags") ~= false then
dofile(modpath.."/bags.lua")
end
dofile(modpath.."/item_names.lua")
dofile(modpath.."/waypoints.lua")
if minetest.settings:get_bool("unified_inventory_item_names") ~= false then
dofile(modpath.."/item_names.lua")
end
if minetest.settings:get_bool("unified_inventory_waypoints") ~= false then
dofile(modpath.."/waypoints.lua")
end
dofile(modpath.."/legacy.lua") -- mod compatibility

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)
end
-- Get the player-specific unified_inventory style
function ui.get_per_player_formspec(player_name)
local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
@ -27,6 +27,7 @@ function ui.get_per_player_formspec(player_name)
return style
end
-- Creates an item image or regular image button with a tooltip
local function formspec_button(ui_peruser, name, image, offset, pos, scale, label)
local element = 'image_button'
if minetest.registered_items[image] then
@ -43,47 +44,68 @@ local function formspec_button(ui_peruser, name, image, offset, pos, scale, labe
string.format("tooltip[%s;%s]", name, F(label or name))
end
local function formspec_add_filters(player, formspec, style)
local button_row = 0
local button_col = 0
-- Add registered buttons (tabs)
local function formspec_tab_buttons(player, formspec, style)
local n = #formspec + 1
-- Main buttons
local filtered_inv_buttons = {}
for i, def in pairs(ui.buttons) do
for _, def in pairs(ui.buttons) do
if not (style.is_lite_mode and def.hide_lite) then
table.insert(filtered_inv_buttons, def)
if def.condition == nil or def.condition(player) or not ui.hide_disabled_buttons then
table.insert(filtered_inv_buttons, def)
end
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
if style.is_lite_mode and i > 4 then
button_row = 1
button_col = 1
end
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
local pos_x = style.main_button_x + style.btn_spc * (i - 1) - button_col * style.btn_spc * 4
local pos_y = style.main_button_y + button_row * style.btn_spc
if (def.condition == nil or def.condition(player) == true) then
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
if (def.condition == nil or def.condition(player)) then
formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]",
pos_x, pos_y, style.btn_size, style.btn_size,
F(def.image),
F(def.name))
formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]"
n = n+2
else
formspec[n] = string.format("image[%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,
def.image)
n = n+1
end
end
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
-- Add category GUI elements (top right)
local function formspec_add_categories(player, formspec, ui_peruser)
local player_name = player:get_player_name()
local n = #formspec + 1
@ -97,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)
}
formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;3]",
ui_peruser.page_x-0.1, 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),
formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;16]",
ui_peruser.page_x-0.15, categories_scroll_pos[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")
n = n + 1
@ -121,18 +143,21 @@ local function formspec_add_categories(player, formspec, ui_peruser)
if ui.current_category[player_name] == category.name then
scale = 1
end
formspec[n] = formspec_button(ui_peruser, "category_"..category.name, category.symbol, categories_pos, {column-1, 0}, scale, category.label)
formspec[n] = formspec_button(ui_peruser, "category_"..category.name, category.symbol, categories_pos,
{column-1, 0}, scale, category.label)
n = n + 1
end
end
if category_count > ui_peruser.pagecols and scroll_offset > 0 then
-- prev
formspec[n] = formspec_button(ui_peruser, "prev_category", "ui_left_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 2, 0}, 0.8, S("Scroll categories left"))
formspec[n] = formspec_button(ui_peruser, "prev_category", "ui_left_icon.png", categories_scroll_pos,
{ui_peruser.pagecols - 2, 0}, 0.8, S("Scroll categories left"))
n = n + 1
end
if category_count > ui_peruser.pagecols and category_count - scroll_offset > ui_peruser.pagecols then
-- next
formspec[n] = formspec_button(ui_peruser, "next_category", "ui_right_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 1, 0}, 0.8, S("Scroll categories right"))
formspec[n] = formspec_button(ui_peruser, "next_category", "ui_right_icon.png", categories_scroll_pos,
{ui_peruser.pagecols - 1, 0}, 0.8, S("Scroll categories right"))
end
end
@ -238,17 +263,25 @@ local function formspec_add_item_browser(player, formspec, ui_peruser)
ui_peruser.btn_size, ui_peruser.btn_size,
name, button_name
)
local tooltip = item.description
if item.mod_origin then
-- "mod_origin" may not be specified for items that were
-- registered in a callback (during or before ServerEnv init)
tooltip = tooltip .. " [" .. item.mod_origin .. "]"
end
formspec[n + 1] = ("tooltip[%s;%s]"):format(
button_name, minetest.formspec_escape(item.description)
button_name, minetest.formspec_escape(tooltip)
)
n = n + 2
list_index = list_index + 1
end
list_index = list_index + 1
end
end
formspec[n] = string.format("label[%f,%f;%s: %s]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc * (ui_peruser.is_lite_mode and 1 or 2),
ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2,
formspec[n] = "style[page_number;content_offset=0]"
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.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))
end
@ -280,7 +313,7 @@ function ui.get_formspec(player, page)
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
-- Player inventory
@ -305,7 +338,7 @@ function ui.set_inventory_formspec(player, page)
end
end
local function valid_def(def)
function ui.is_itemdef_listable(def)
return (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
@ -318,11 +351,30 @@ function ui.apply_filter(player, filter, search_dir)
return false
end
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 ffilter
if lfilter:sub(1, 6) == "group:" then
-- Group filter: all groups of the item must match
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
if not def.groups[group]
or def.groups[group] <= 0 then
@ -332,8 +384,16 @@ function ui.apply_filter(player, filter, search_dir)
return true
end
else
local lang = minetest.get_player_information(player_name).lang_code
ffilter = function(name, def)
-- Name filter: fuzzy match item names and descriptions
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 ldesc = string.lower(def.description)
local llocaldesc = minetest.get_translated_string
@ -342,37 +402,50 @@ function ui.apply_filter(player, filter, search_dir)
or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
end
end
ui.filtered_items_list[player_name]={}
local filtered_items = {}
local category = ui.current_category[player_name] or 'all'
if category == 'all' then
for name, def in pairs(minetest.registered_items) do
if valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
for _, name in ipairs(ui.items_list) do
if fprefilter(name) and ffilter(name) then
table.insert(filtered_items, name)
end
end
elseif category == 'uncategorized' then
for name, def in pairs(minetest.registered_items) do
if (not ui.find_category(name))
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
for _, name in ipairs(ui.items_list) do
if not ui.find_category(name)
and fprefilter(name)
and ffilter(name) then
table.insert(filtered_items, name)
end
end
else
for name,exists in pairs(ui.registered_category_items[category]) do
local def = minetest.registered_items[name]
if exists and def
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
-- Any other category is selected
for name, exists in pairs(ui.registered_category_items[category]) do
if exists
and fprefilter(name)
and ffilter(name) then
table.insert(filtered_items, name)
end
end
end
table.sort(ui.filtered_items_list[player_name])
ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
table.sort(filtered_items)
ui.filtered_items_list_size[player_name] = #filtered_items
ui.filtered_items_list[player_name] = filtered_items
ui.current_index[player_name] = 1
ui.activefilter[player_name] = filter
ui.active_search_direction[player_name] = search_dir
ui.set_inventory_formspec(player, ui.current_page[player_name])
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 dlimit = 3 -- HUD element will be hidden after this many seconds
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 player_name = player:get_player_name()
@ -16,7 +18,8 @@ local function set_hud(player)
item_names[player_name] = {
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},
offset = off,
alignment = {x=0, y=-1},
@ -60,6 +63,7 @@ minetest.register_globalstep(function(dtime)
data.itemname = itemname
data.index = index
data.dtime = 0
local lang_code = minetest.get_player_information(player:get_player_name()).lang_code
local desc = stack.get_meta
and stack:get_meta():get_string("description")
@ -69,6 +73,14 @@ minetest.register_globalstep(function(dtime)
local def = minetest.registered_items[itemname]
desc = def and def.description or ""
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)
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
Medium Bag=Mittelgroße Tasche
Large Bag=Große Tasche
All Items=
Misc. Items=
Plant Life=
Building Materials=
Tools=
Minerals and Metals=
Environment and Worldgen=
Lighting=
All Items=Alle Gegenstände
Misc. Items=Sonstige Gegenstände
Plant Life=Pfanzenwelt
Building Materials=Baumaterialien
Tools=Werkzeuge
Minerals and Metals=Minerale und Metalle
Environment and Worldgen=Umwelt und Welterstellung
Lighting=Beleuchtung
and = und
Scroll categories left=
Scroll categories right=
Scroll categories left=Kategorien nach links blättern
Scroll categories right=Kategorien nach rechts blättern
Search=Suchen
Reset search and display everything=Suche zurücksetzen und alles anzeigen
First page=Erste Seite
@ -76,10 +76,10 @@ Waypoints=Wegpunkte
Select Waypoint #@1=Wegpunkt Nr. @1 auswählen
Waypoint @1=Wegpunkt Nr. @1
Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position
Hide waypoint=
Show waypoint=
Hide coordinates=
Show coordinates=
Hide waypoint=Wegpunkt verstecken
Show waypoint=Wegpunkt zeigen
Hide coordinates=Koordinaten verstecken
Show coordinates=Koordinaten zeigen
Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern
Edit waypoint name=Name des Wegpunkts ändern
Waypoint active=Wegpunkt aktiv

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -98,7 +98,7 @@ ui.register_button("misc_set_day", {
action = function(player)
local player_name = player:get_player_name()
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})
minetest.set_timeofday((6000 % 24000) / 24000)
minetest.chat_send_player(player_name,
@ -122,7 +122,7 @@ ui.register_button("misc_set_night", {
action = function(player)
local player_name = player:get_player_name()
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})
minetest.set_timeofday((21000 % 24000) / 24000)
minetest.chat_send_player(player_name,
@ -183,14 +183,14 @@ ui.register_page("craft", {
local n=#formspec+1
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)
n=n + 2
end
if ui.is_creative(player_name) then
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;]",
F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset)
end
@ -207,17 +207,15 @@ ui.register_page("craft", {
local function stack_image_button(x, y, w, h, buttonname_prefix, item)
local name = item:get_name()
local count = item:get_count()
local wear = item:get_wear()
local description = item:get_meta():get_string("description")
local show_is_group = false
local displayitem = name.." "..count.." "..wear
local displayitem = item:to_string()
local selectitem = name
if name:sub(1, 6) == "group:" then
local group_name = name:sub(7)
local group_item = ui.get_group_item(group_name)
show_is_group = not group_item.sole
displayitem = group_item.item or "unknown"
displayitem = group_item.item or name
selectitem = group_item.sole and displayitem or name
end
local label = show_is_group and "G" or ""
@ -245,6 +243,9 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
return button
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 = {
recipe = NS("Recipe @1 of @2"),
usage = NS("Usage @1 of @2"),
@ -297,11 +298,10 @@ ui.register_page("craftguide", {
local n = 4
local item_def = minetest.registered_items[item_name]
local item_name_shown
if minetest.registered_items[item_name]
and minetest.registered_items[item_name].description then
item_name_shown = S("@1 (@2)",
minetest.registered_items[item_name].description, item_name)
if item_def and item_def.description then
item_name_shown = S("@1 (@2)", item_def.description, item_name)
else
item_name_shown = item_name
end
@ -326,12 +326,14 @@ ui.register_page("craftguide", {
F(role_text[dir]), item_name_shown)
n = n + 2
local giveme_form = table.concat({
"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]",
"button["..(give_x)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_1;1]",
"button["..(give_x+0.8)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_10;10]",
"button["..(give_x+1.6)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]"
})
local giveme_form =
"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]"
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]"
end
if not craft then
-- No craft recipes available for this item.
@ -499,6 +501,14 @@ local function craftguide_craft(player, formname, fields)
local alternate = ui.alternate[player_name]
local craft = crafts[alternate]
if not craft.width then
if not craft.output then
minetest.log("warning", "[unified_inventory] Craft has no output.")
else
minetest.log("warning", ("[unified_inventory] Craft for '%s' has no width."):format(craft.output))
end
return
end
if craft.width > 3 then return end
ui.craftguide_match_craft(player, "main", "craft", craft, amount)

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
#Inventory, optimized for small displays.
# Reduced formspec layout, optimized for smaller displays.
# Note: This may also disable some features to free up visual space.
unified_inventory_lite (Lite mode) bool false
#If enabled, bags will be made available which can be used to extend
#inventory storage size.
# Provides craftable bag items to extend the inventory space.
unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative
#and the give privilege.
# Shows the trash slot to everyone.
# 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
# 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
ui.register_page("waypoints", {
get_formspec = function(player)
get_formspec = function(player, perplayer_formspec)
local player_name = player:get_player_name()
local wp_info_x = ui.style_full.form_header_x + 1.25
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 formspec = {
ui.style_full.standard_inv_bg,
string.format("label[%f,%f;%s]",
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]"
}
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:
for i = 1, COUNT do
@ -140,36 +144,50 @@ ui.register_page("waypoints", {
-- Main buttons:
local btnlist = {
set_waypoint = {
"ui_waypoint_set_icon.png",
S("Set waypoint to current location")
},
toggle_waypoint = {
-- 1. formspec name
-- 2. button image
-- 3. translation text
{
"toggle_waypoint",
waypoint.active and "ui_on_icon.png" or "ui_off_icon.png",
waypoint.active and S("Hide waypoint") or S("Show waypoint")
},
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)",
{
"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 S("Hide coordinates") or S("Show coordinates")
},
toggle_color = {
{
"toggle_color",
"ui_circular_arrows_icon.png",
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 name, def in pairs(btnlist) do
for i, def in pairs(btnlist) do
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,
def[1], name, sel)
formspec[n+1] = "tooltip["..name..sel..";"..F(def[2]).."]"
x = x - 1
def[2], def[1], sel)
formspec[n+1] = "tooltip["..def[1]..sel..";"..F(def[3]).."]"
n = n + 2
end
@ -199,7 +217,10 @@ ui.register_page("waypoints", {
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])
return {formspec=table.concat(formspec)}
return {
formspec = table.concat(formspec),
draw_inventory = not perplayer_formspec.is_lite_mode,
}
end,
})
@ -207,7 +228,6 @@ ui.register_button("waypoints", {
type = "image",
image = "ui_waypoints_icon.png",
tooltip = S("Waypoints"),
hide_lite=true
})
local function update_hud(player, waypoints, temp, i)
@ -235,7 +255,7 @@ local function update_hud(player, waypoints, temp, i)
end
if waypoint.active then
temp.hud = player:hud_add({
hud_elem_type = "waypoint",
[core.features.hud_def_type_field and "type" or "hud_elem_type"] = "waypoint",
number = hud_colors[waypoint.color or 1][2] ,
name = name,
text = "m",
@ -313,6 +333,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
update_formspec = true
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
-- Save first
waypoints.data[i] = waypoint
@ -323,6 +350,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
update_hud(player, waypoints, temp, i)
end
if update_formspec then
minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1})
ui.set_inventory_formspec(player, "waypoints")
end