group.lua 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. function unified_inventory.canonical_item_spec_matcher(spec)
  2. local specname = ItemStack(spec):get_name()
  3. if specname:sub(1, 6) == "group:" then
  4. local group_names = specname:sub(7):split(",")
  5. return function (itemname)
  6. local itemdef = minetest.registered_items[itemname]
  7. for _, group_name in ipairs(group_names) do
  8. if (itemdef.groups[group_name] or 0) == 0 then
  9. return false
  10. end
  11. end
  12. return true
  13. end
  14. else
  15. return function (itemname) return itemname == specname end
  16. end
  17. end
  18. function unified_inventory.item_matches_spec(item, spec)
  19. local itemname = ItemStack(item):get_name()
  20. return unified_inventory.canonical_item_spec_matcher(spec)(itemname)
  21. end
  22. unified_inventory.registered_group_items = {
  23. mesecon_conductor_craftable = "mesecons:wire_00000000_off",
  24. stone = "default:cobble",
  25. wool = "wool:white",
  26. }
  27. function unified_inventory.register_group_item(groupname, itemname)
  28. unified_inventory.registered_group_items[groupname] = itemname
  29. end
  30. -- This is used when displaying craft recipes, where an ingredient is
  31. -- specified by group rather than as a specific item. A single-item group
  32. -- is represented by that item, with the single-item status signalled
  33. -- in the "sole" field. If the group contains no items at all, the item
  34. -- field will be nil.
  35. --
  36. -- Within a multiple-item group, we prefer to use an item that has the
  37. -- same specific name as the group, and if there are more than one of
  38. -- those items we prefer the one registered for the group by a mod.
  39. -- Among equally-preferred items, we just pick the one with the
  40. -- lexicographically earliest name.
  41. --
  42. -- The parameter to this function isn't just a single group name.
  43. -- It may be a comma-separated list of group names. This is really a
  44. -- "group:..." ingredient specification, minus the "group:" prefix.
  45. local function compute_group_item(group_name_list)
  46. local group_names = group_name_list:split(",")
  47. local candidate_items = {}
  48. for itemname, itemdef in pairs(minetest.registered_items) do
  49. if (itemdef.groups.not_in_creative_inventory or 0) == 0 then
  50. local all = true
  51. for _, group_name in ipairs(group_names) do
  52. if (itemdef.groups[group_name] or 0) == 0 then
  53. all = false
  54. end
  55. end
  56. if all then table.insert(candidate_items, itemname) end
  57. end
  58. end
  59. local num_candidates = #candidate_items
  60. if num_candidates == 0 then
  61. return {sole = true}
  62. elseif num_candidates == 1 then
  63. return {item = candidate_items[1], sole = true}
  64. end
  65. local is_group = {}
  66. local registered_rep = {}
  67. for _, group_name in ipairs(group_names) do
  68. is_group[group_name] = true
  69. local rep = unified_inventory.registered_group_items[group_name]
  70. if rep then registered_rep[rep] = true end
  71. end
  72. local bestitem = ""
  73. local bestpref = 0
  74. for _, item in ipairs(candidate_items) do
  75. local pref
  76. if registered_rep[item] then
  77. pref = 4
  78. elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then
  79. pref = 3
  80. elseif is_group[item:gsub("^[^:]*:", "")] then
  81. pref = 2
  82. else
  83. pref = 1
  84. end
  85. if pref > bestpref or (pref == bestpref and item < bestitem) then
  86. bestitem = item
  87. bestpref = pref
  88. end
  89. end
  90. return {item = bestitem, sole = false}
  91. end
  92. local group_item_cache = {}
  93. function unified_inventory.get_group_item(group_name)
  94. if not group_item_cache[group_name] then
  95. group_item_cache[group_name] = compute_group_item(group_name)
  96. end
  97. return group_item_cache[group_name]
  98. end