diff --git a/callbacks.lua b/callbacks.lua index f1646ed..ad7c1ed 100644 --- a/callbacks.lua +++ b/callbacks.lua @@ -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) diff --git a/group.lua b/group.lua index 594bed2..e509006 100644 --- a/group.lua +++ b/group.lua @@ -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 diff --git a/internal.lua b/internal.lua index 7724c9d..2323e07 100644 --- a/internal.lua +++ b/internal.lua @@ -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 diff --git a/register.lua b/register.lua index 131cbe2..aac5342 100644 --- a/register.lua +++ b/register.lua @@ -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