1-- creative/inventory.lua 2 3-- support for MT game translation. 4local S = creative.get_translator 5 6local player_inventory = {} 7local inventory_cache = {} 8 9local function init_creative_cache(items) 10 inventory_cache[items] = {} 11 local i_cache = inventory_cache[items] 12 13 for name, def in pairs(items) do 14 if def.groups.not_in_creative_inventory ~= 1 and 15 def.description and def.description ~= "" then 16 i_cache[name] = def 17 end 18 end 19 table.sort(i_cache) 20 return i_cache 21end 22 23function creative.init_creative_inventory(player) 24 local player_name = player:get_player_name() 25 player_inventory[player_name] = { 26 size = 0, 27 filter = "", 28 start_i = 0, 29 old_filter = nil, -- use only for caching in update_creative_inventory 30 old_content = nil 31 } 32 33 minetest.create_detached_inventory("creative_" .. player_name, { 34 allow_move = function(inv, from_list, from_index, to_list, to_index, count, player2) 35 local name = player2 and player2:get_player_name() or "" 36 if not minetest.is_creative_enabled(name) or 37 to_list == "main" then 38 return 0 39 end 40 return count 41 end, 42 allow_put = function(inv, listname, index, stack, player2) 43 return 0 44 end, 45 allow_take = function(inv, listname, index, stack, player2) 46 local name = player2 and player2:get_player_name() or "" 47 if not minetest.is_creative_enabled(name) then 48 return 0 49 end 50 return -1 51 end, 52 on_move = function(inv, from_list, from_index, to_list, to_index, count, player2) 53 end, 54 on_take = function(inv, listname, index, stack, player2) 55 if stack and stack:get_count() > 0 then 56 minetest.log("action", player_name .. " takes " .. stack:get_name().. " from creative inventory") 57 end 58 end, 59 }, player_name) 60 61 return player_inventory[player_name] 62end 63 64local NO_MATCH = 999 65local function match(s, filter) 66 if filter == "" then 67 return 0 68 end 69 if s:lower():find(filter, 1, true) then 70 return #s - #filter 71 end 72 return NO_MATCH 73end 74 75local function description(def, lang_code) 76 local s = def.description 77 if lang_code then 78 s = minetest.get_translated_string(lang_code, s) 79 end 80 return s:gsub("\n.*", "") -- First line only 81end 82 83function creative.update_creative_inventory(player_name, tab_content) 84 local inv = player_inventory[player_name] or 85 creative.init_creative_inventory(minetest.get_player_by_name(player_name)) 86 local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name}) 87 88 if inv.filter == inv.old_filter and tab_content == inv.old_content then 89 return 90 end 91 inv.old_filter = inv.filter 92 inv.old_content = tab_content 93 94 local items = inventory_cache[tab_content] or init_creative_cache(tab_content) 95 96 local lang 97 local player_info = minetest.get_player_information(player_name) 98 if player_info and player_info.lang_code ~= "" then 99 lang = player_info.lang_code 100 end 101 102 local creative_list = {} 103 local order = {} 104 for name, def in pairs(items) do 105 local m = match(description(def), inv.filter) 106 if m > 0 then 107 m = math.min(m, match(description(def, lang), inv.filter)) 108 end 109 if m > 0 then 110 m = math.min(m, match(name, inv.filter)) 111 end 112 113 if m < NO_MATCH then 114 creative_list[#creative_list+1] = name 115 -- Sort by match value first so closer matches appear earlier 116 order[name] = string.format("%02d", m) .. name 117 end 118 end 119 120 table.sort(creative_list, function(a, b) return order[a] < order[b] end) 121 122 player_inv:set_size("main", #creative_list) 123 player_inv:set_list("main", creative_list) 124 inv.size = #creative_list 125end 126 127-- Create the trash field 128local trash = minetest.create_detached_inventory("creative_trash", { 129 -- Allow the stack to be placed and remove it in on_put() 130 -- This allows the creative inventory to restore the stack 131 allow_put = function(inv, listname, index, stack, player) 132 return stack:get_count() 133 end, 134 on_put = function(inv, listname) 135 inv:set_list(listname, {}) 136 end, 137}) 138trash:set_size("main", 1) 139 140creative.formspec_add = "" 141 142function creative.register_tab(name, title, items) 143 sfinv.register_page("creative:" .. name, { 144 title = title, 145 is_in_nav = function(self, player, context) 146 return minetest.is_creative_enabled(player:get_player_name()) 147 end, 148 get = function(self, player, context) 149 local player_name = player:get_player_name() 150 creative.update_creative_inventory(player_name, items) 151 local inv = player_inventory[player_name] 152 local pagenum = math.floor(inv.start_i / (4*8) + 1) 153 local pagemax = math.ceil(inv.size / (4*8)) 154 local esc = minetest.formspec_escape 155 return sfinv.make_formspec(player, context, 156 "label[5.8,4.15;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" .. 157 [[ 158 image[4.08,4.2;0.8,0.8;creative_trash_icon.png] 159 listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF] 160 list[detached:creative_trash;main;4.02,4.1;1,1;] 161 listring[] 162 image_button[5,4.05;0.8,0.8;creative_prev_icon.png;creative_prev;] 163 image_button[7.2,4.05;0.8,0.8;creative_next_icon.png;creative_next;] 164 image_button[2.63,4.05;0.8,0.8;creative_search_icon.png;creative_search;] 165 image_button[3.25,4.05;0.8,0.8;creative_clear_icon.png;creative_clear;] 166 ]] .. 167 "tooltip[creative_search;" .. esc(S("Search")) .. "]" .. 168 "tooltip[creative_clear;" .. esc(S("Reset")) .. "]" .. 169 "tooltip[creative_prev;" .. esc(S("Previous page")) .. "]" .. 170 "tooltip[creative_next;" .. esc(S("Next page")) .. "]" .. 171 "listring[current_player;main]" .. 172 "field_close_on_enter[creative_filter;false]" .. 173 "field[0.3,4.2;2.8,1.2;creative_filter;;" .. esc(inv.filter) .. "]" .. 174 "listring[detached:creative_" .. player_name .. ";main]" .. 175 "list[detached:creative_" .. player_name .. ";main;0,0;8,4;" .. tostring(inv.start_i) .. "]" .. 176 creative.formspec_add, true) 177 end, 178 on_enter = function(self, player, context) 179 local player_name = player:get_player_name() 180 local inv = player_inventory[player_name] 181 if inv then 182 inv.start_i = 0 183 end 184 end, 185 on_player_receive_fields = function(self, player, context, fields) 186 local player_name = player:get_player_name() 187 local inv = player_inventory[player_name] 188 assert(inv) 189 190 if fields.creative_clear then 191 inv.start_i = 0 192 inv.filter = "" 193 sfinv.set_player_inventory_formspec(player, context) 194 elseif fields.creative_search or 195 fields.key_enter_field == "creative_filter" then 196 inv.start_i = 0 197 inv.filter = fields.creative_filter:lower() 198 sfinv.set_player_inventory_formspec(player, context) 199 elseif not fields.quit then 200 local start_i = inv.start_i or 0 201 202 if fields.creative_prev then 203 start_i = start_i - 4*8 204 if start_i < 0 then 205 start_i = inv.size - (inv.size % (4*8)) 206 if inv.size == start_i then 207 start_i = math.max(0, inv.size - (4*8)) 208 end 209 end 210 elseif fields.creative_next then 211 start_i = start_i + 4*8 212 if start_i >= inv.size then 213 start_i = 0 214 end 215 end 216 217 inv.start_i = start_i 218 sfinv.set_player_inventory_formspec(player, context) 219 end 220 end 221 }) 222end 223 224-- Sort registered items 225local registered_nodes = {} 226local registered_tools = {} 227local registered_craftitems = {} 228 229minetest.register_on_mods_loaded(function() 230 for name, def in pairs(minetest.registered_items) do 231 local group = def.groups or {} 232 233 local nogroup = not (group.node or group.tool or group.craftitem) 234 if group.node or (nogroup and minetest.registered_nodes[name]) then 235 registered_nodes[name] = def 236 elseif group.tool or (nogroup and minetest.registered_tools[name]) then 237 registered_tools[name] = def 238 elseif group.craftitem or (nogroup and minetest.registered_craftitems[name]) then 239 registered_craftitems[name] = def 240 end 241 end 242end) 243 244creative.register_tab("all", S("All"), minetest.registered_items) 245creative.register_tab("nodes", S("Nodes"), registered_nodes) 246creative.register_tab("tools", S("Tools"), registered_tools) 247creative.register_tab("craftitems", S("Items"), registered_craftitems) 248 249local old_homepage_name = sfinv.get_homepage_name 250function sfinv.get_homepage_name(player) 251 if minetest.is_creative_enabled(player:get_player_name()) then 252 return "creative:all" 253 else 254 return old_homepage_name(player) 255 end 256end 257