group.lua 3.8 KB

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