Correctly display multi-group ingredients

Extend the representative-item logic to handle ingredients specified
as the intersection of multiple groups.  Also add mangling of item
button content, because comma for a multi-group ingredient is getting
formspec-escaped and then not de-escaped.
This commit is contained in:
Zefram 2014-06-13 10:40:52 +01:00 committed by Diego Martinez
parent dbf98cb694
commit a8c8ef0890
4 changed files with 41 additions and 10 deletions

@ -122,7 +122,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local clicked_item = nil
for name, value in pairs(fields) do
if string.sub(name, 1, 12) == "item_button_" then
clicked_item = string.sub(name, 13)
clicked_item = unified_inventory.demangle_for_formspec(string.sub(name, 13))
if string.sub(clicked_item, 1, 6) == "group:" then
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, clicked_item)

@ -21,13 +21,23 @@ end
-- those items we prefer the one registered for the group by a mod.
-- Among equally-preferred items, we just pick the one with the
-- lexicographically earliest name.
--
-- The parameter to this function isn't just a single group name.
-- It may be a comma-separated list of group names. This is really a
-- "group:..." ingredient specification, minus the "group:" prefix.
local function compute_group_item(group_name)
local function compute_group_item(group_name_list)
local group_names = group_name_list:split(",")
local candidate_items = {}
for itemname, itemdef in pairs(minetest.registered_items) do
if (itemdef.groups.not_in_creative_inventory or 0) == 0 and
(itemdef.groups[group_name] or 0) ~= 0 then
table.insert(candidate_items, itemname)
if (itemdef.groups.not_in_creative_inventory or 0) == 0 then
local all = true
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
all = false
end
end
if all then table.insert(candidate_items, itemname) end
end
end
local num_candidates = #candidate_items
@ -36,15 +46,22 @@ local function compute_group_item(group_name)
elseif num_candidates == 1 then
return {item = candidate_items[1], sole = true}
end
local is_group = {}
local registered_rep = {}
for _, group_name in ipairs(group_names) do
is_group[group_name] = true
local rep = unified_inventory.registered_group_items[group_name]
if rep then registered_rep[rep] = true end
end
local bestitem = ""
local bestpref = 0
for _, item in ipairs(candidate_items) do
local pref
if item == unified_inventory.registered_group_items[group_name] then
if registered_rep[item] then
pref = 4
elseif item == "default:"..group_name then
elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then
pref = 3
elseif item:gsub("^[^:]*:", "") == group_name then
elseif is_group[item:gsub("^[^:]*:", "")] then
pref = 2
else
pref = 1

@ -1,3 +1,17 @@
-- This pair of encoding functions is used where variable text must go in
-- button names, where the text might contain formspec metacharacters.
-- We can escape button names for the formspec, to avoid screwing up
-- form structure overall, but they then don't get de-escaped, and so
-- the input we get back from the button contains the formspec escaping.
-- This is a game engine bug, and in the anticipation that it might be
-- fixed some day we don't want to rely on it. So for safety we apply
-- an encoding that avoids all formspec metacharacters.
function unified_inventory.mangle_for_formspec(str)
return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end)
end
function unified_inventory.demangle_for_formspec(str)
return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end)
end
function unified_inventory.get_formspec(player, page)
if not player then
@ -71,7 +85,7 @@ function unified_inventory.get_formspec(player, page)
..(8.2 + x * 0.7)..","
..(1 + y * 0.7)..";.81,.81;"
..name..";item_button_"
..name..";]"
..unified_inventory.mangle_for_formspec(name)..";]"
list_index = list_index + 1
end
end

@ -165,7 +165,7 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
return string.format("item_image_button[%u,%u;%u,%u;%s;%s;%s]",
x, y, w, h,
minetest.formspec_escape(displayitem),
minetest.formspec_escape(buttonname_prefix..selectitem),
minetest.formspec_escape(buttonname_prefix..unified_inventory.mangle_for_formspec(selectitem)),
label)
end