diff --git a/API.md b/API.md index a1056db..7c7538a 100644 --- a/API.md +++ b/API.md @@ -235,6 +235,40 @@ A map of search filters, indexed by name. --- +### Sorting methods + +Sorting methods are used to filter the player's main inventory. + +#### `i3.add_sorting_method(def)` + +Adds a player inventory sorting method. + +- `def` is the method definition. + +Example: + +```Lua +i3.add_sorting_method { + name = "test", + description = "Cool sorting method", + func = function(player, data) + local inv = player:get_inventory() + local list = inv:get_list("main") + table.sort(list) + + -- An array of items must be returned + return list + end, +} + +``` + +#### `i3.sorting_methods` + +A table containing all sorting methods. + +--- + ### Item list compression `i3` can reduce the item list size by compressing a group of items. diff --git a/README.md b/README.md index 409dfed..5f2f4f5 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ This mod requires **Minetest 5.4+** - Quick Crafting - Backpacks - 3D Player Model Preview - - Inventory Sorting (alphabetical + item stack compression) + - Inventory Sorting (with optional compression) - Item Bookmarks - Waypoints - - Item List Compression (**`moreblocks`** supported) + - Item List Compression (**`moreblocks`** is supported) **ยน** *This mode is a Terraria-like system that shows recipes you can craft from items you ever had in your inventory. To enable it: `i3_progressive_mode = true` in `minetest.conf`.* diff --git a/etc/api.lua b/etc/api.lua index 9749cf2..44e8af2 100644 --- a/etc/api.lua +++ b/etc/api.lua @@ -2,6 +2,7 @@ local make_fs = i3.files.gui() local gmatch, match, split = i3.get("gmatch", "match", "split") local S, err, fmt, reg_items = i3.get("S", "err", "fmt", "reg_items") +local name_sort, count_sort, sort_inventory = i3.get("name_sort", "count_sort", "sort_inventory") local sort, concat, copy, insert, remove = i3.get("sort", "concat", "copy", "insert", "remove") local true_str, true_table, is_str, is_func, is_table, clean_name = i3.get("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name") @@ -166,6 +167,10 @@ function i3.set_fs(player, _fs) local data = i3.data[name] if not data then return end + if data.auto_sorting then + sort_inventory(player, data) + end + local fs = fmt("%s%s", make_fs(player, data), _fs or "") player:set_inventory_formspec(fs) end @@ -289,3 +294,65 @@ function i3.compress(item, def) i3.compressed[it] = true end end + +function i3.add_sorting_method(def) + if not true_table(def) then + return err "i3.add_sorting_method: definition missing" + elseif not true_str(def.name) then + return err "i3.add_sorting_method: name missing" + elseif not is_func(def.func) then + return err "i3.add_sorting_method: function missing" + end + + insert(i3.sorting_methods, def) +end + +local function pre_sorting(player) + local inv = player:get_inventory() + local list = inv:get_list("main") + local size = inv:get_size("main") + local new_inv, stack_meta = {}, {} + + for i = 1, size do + local stack = list[i] + local name = stack:get_name() + local count = stack:get_count() + local empty = stack:is_empty() + local meta = stack:get_meta():to_table() + local wear = stack:get_wear() > 0 + + if not empty then + if next(meta.fields) or wear then + stack_meta[#stack_meta + 1] = stack + else + new_inv[#new_inv + 1] = ItemStack(fmt("%s %u", name, count)) + end + end + end + + for i = 1, #stack_meta do + new_inv[#new_inv + 1] = stack_meta[i] + end + + return new_inv +end + +i3.add_sorting_method { + name = "alphabetical", + description = S"Sort items by name (A-Z)", + func = function(player, data) + local new_inv = pre_sorting(player) + name_sort(new_inv, data.reverse_sorting) + return new_inv + end +} + +i3.add_sorting_method { + name = "numerical", + description = S"Sort items by number of items per stack", + func = function(player, data) + local new_inv = pre_sorting(player) + count_sort(new_inv, data.reverse_sorting) + return new_inv + end, +} diff --git a/etc/common.lua b/etc/common.lua index 52d69d4..ca8e4ea 100644 --- a/etc/common.lua +++ b/etc/common.lua @@ -1,6 +1,6 @@ local translate = core.get_translated_string -local insert, remove, floor, vec_add, vec_mul = - table.insert, table.remove, math.floor, vector.add, vector.mul +local insert, remove, sort, vec_add, vec_mul = + table.insert, table.remove, table.sort, vector.add, vector.mul local fmt, find, gmatch, match, sub, split, lower = string.format, string.find, string.gmatch, string.match, string.sub, string.split, string.lower local reg_items, reg_nodes, reg_craftitems, reg_tools = @@ -297,7 +297,7 @@ end local function round(num, decimal) local mul = 10 ^ decimal - return floor(num * mul + 0.5) / mul + return math.floor(num * mul + 0.5) / mul end local function is_fav(favs, query_item) @@ -351,9 +351,107 @@ local function spawn_item(player, stack) core.add_item(look_at, stack) end +local function name_sort(inv, reverse) + return sort(inv, function(a, b) + a, b = a:get_name(), b:get_name() + + if reverse then + return a > b + end + + return a < b + end) +end + +local function count_sort(inv, reverse) + return sort(inv, function(a, b) + a, b = a:get_count(), b:get_count() + + if reverse then + return a > b + end + + return a < b + end) +end + +local function get_sorting_idx(name) + local idx = 1 + + for i, def in ipairs(i3.sorting_methods) do + if name == def.name then + idx = i + end + end + + return idx +end + +local function compress_items(player) + local inv = player:get_inventory() + local list = inv:get_list("main") + local size = inv:get_size("main") + local new_inv, _new_inv, special = {}, {}, {} + + for i = 1, size do + local stack = list[i] + local name = stack:get_name() + local count = stack:get_count() + local stackmax = stack:get_stack_max() + local empty = stack:is_empty() + local meta = stack:get_meta():to_table() + local wear = stack:get_wear() > 0 + + if not empty then + if next(meta.fields) or wear or count >= stackmax then + special[#special + 1] = stack + else + new_inv[name] = new_inv[name] or 0 + new_inv[name] = new_inv[name] + count + end + end + end + + for name, count in pairs(new_inv) do + local stackmax = ItemStack(name):get_stack_max() + local iter = math.ceil(count / stackmax) + local leftover = count + + for _ = 1, iter do + _new_inv[#_new_inv + 1] = fmt("%s %u", name, math.min(stackmax, leftover)) + leftover = leftover - stackmax + end + end + + for i = 1, #special do + _new_inv[#_new_inv + 1] = special[i] + end + + inv:set_list("main", _new_inv) +end + +local function sort_inventory(player, data) + if data.inv_compress then + compress_items(player) + end + + local sorts = {} + + for _, def in ipairs(i3.sorting_methods) do + sorts[def.name] = def.func + end + + local new_inv = sorts[data.sort](player, data) + + if new_inv then + local inv = player:get_inventory() + inv:set_list("main", new_inv) + end +end + ------------------------------------------------------------------------------- -local registry = { +local _ = { -- Groups is_group = is_group, extract_groups = extract_groups, @@ -366,6 +464,10 @@ local registry = { -- Sorting search = search, + name_sort = name_sort, + count_sort = count_sort, + sort_inventory = sort_inventory, + get_sorting_idx = get_sorting_idx, sort_by_category = sort_by_category, apply_recipe_filters = apply_recipe_filters, @@ -446,7 +548,7 @@ function i3.get(...) local t = {} for i, var in ipairs{...} do - t[i] = registry[var] + t[i] = _[var] end return unpack(t) diff --git a/etc/gui.lua b/etc/gui.lua index 0bed973..da67edb 100644 --- a/etc/gui.lua +++ b/etc/gui.lua @@ -8,13 +8,14 @@ local clr, ESC, check_privs = i3.get("clr", "ESC", "check_privs") local min, max, floor, ceil, round = i3.get("min", "max", "floor", "ceil", "round") local sprintf, find, match, sub, upper = i3.get("fmt", "find", "match", "sub", "upper") local reg_items, reg_tools, reg_entities = i3.get("reg_items", "reg_tools", "reg_entities") -local maxn, sort, concat, copy, insert, remove = i3.get("maxn", "sort", "concat", "copy", "insert", "remove") +local maxn, sort, concat, copy, insert, remove = + i3.get("maxn", "sort", "concat", "copy", "insert", "remove") local true_str, is_fav, is_num = i3.get("true_str", "is_fav", "is_num") -local is_group, extract_groups, item_has_groups = - i3.get("is_group", "extract_groups", "item_has_groups") local groups_to_items, compression_active, compressible = i3.get("groups_to_items", "compression_active", "compressible") +local get_sorting_idx, is_group, extract_groups, item_has_groups = + i3.get("get_sorting_idx", "is_group", "extract_groups", "item_has_groups") local function fmt(elem, ...) if not fs_elements[elem] then @@ -404,6 +405,84 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa end end +local function show_popup(fs, data) + if data.confirm_trash then + fs("style_type[box;colors=#999,#999,#808080,#808080]") + + for _ = 1, 3 do + fs("box", 2.97, 10.75, 4.3, 0.5, "") + end + + fs("label", 3.12, 11, "Confirm trash?") + fs("image_button", 5.17, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes") + fs("image_button", 6.27, 10.75, 1, 0.5, "", "confirm_trash_no", "No") + + elseif data.show_settings then + fs("style_type[box;colors=#999,#999,#808080,#808080]") + + for _ = 1, 3 do + fs("box", 2.1, 9.25, 6, 2, "") + end + + for _ = 1, 3 do + fs("box", 2.1, 9.25, 6, 0.5, "#707070") + end + + fs("image_button", 7.75, 9.35, 0.25, 0.25, PNG.cancel_hover .. "^\\[brighten", "close_settings", "") + + local show_home = data.show_setting == "home" + local show_sorting = data.show_setting == "sorting" + local show_misc = data.show_setting == "misc" + + fs(fmt("style[setting_home;textcolor=%s;sound=i3_click]", show_home and "#ff0" or "#fff")) + fs(fmt("style[setting_sorting;textcolor=%s;sound=i3_click]", show_sorting and "#ff0" or "#fff")) + fs(fmt("style[setting_misc;textcolor=%s;sound=i3_click]", show_misc and "#ff0" or "#fff")) + + fs("button", 2.2, 9.25, 1.8, 0.55, "setting_home", "Home") + fs("button", 4, 9.25, 1.8, 0.55, "setting_sorting", "Sorting") + fs("button", 5.8, 9.25, 1.8, 0.55, "setting_misc", "Misc.") + + if show_home then + local home_pos = data.home or "" + home_pos = home_pos:gsub(",", ", "):gsub("%(", ""):gsub("%)", "") + local home_str = fmt("Home position: %s", home_pos) + home_str = data.home and home_str or ES"No home set" + + fs("button", 2.1, 9.7, 6, 0.8, "", home_str) + fs("image_button", 4.2, 10.4, 1.8, 0.7, "", "set_home", "Set home") + + elseif show_sorting then + fs("button", 2.1, 9.7, 6, 0.8, "", ES"Select the inventory sorting method:") + + fs(fmt("style[prev_sort;fgimg=%s;fgimg_hovered=%s]", PNG.prev, PNG.prev_hover)) + fs(fmt("style[next_sort;fgimg=%s;fgimg_hovered=%s]", PNG.next, PNG.next_hover)) + + fs("image_button", 2.2, 10.6, 0.35, 0.35, "", "prev_sort", "") + fs("image_button", 7.65, 10.6, 0.35, 0.35, "", "next_sort", "") + + fs("style[sort_method;font=bold;font_size=20]") + fs("button", 2.55, 10.35, 5.1, 0.8, "sort_method", data.sort:gsub("^%l", upper)) + + local idx = get_sorting_idx(data.sort) + local desc = i3.sorting_methods[idx].description + + if desc then + fs(fmt("tooltip[%s;%s]", "sort_method", desc)) + end + + elseif show_misc then + fs("checkbox", 2.4, 10.05, + "inv_compress", ES"Inventory compression", tostring(data.inv_compress)) + + fs("checkbox", 2.4, 10.5, + "auto_sorting", ES"Automatic sorting", tostring(data.auto_sorting)) + + fs("checkbox", 2.4, 10.95, + "reverse_sorting", ES"Reverse sorting", tostring(data.reverse_sorting)) + end + end +end + local function get_inventory_fs(player, data, fs) fs("listcolors[#bababa50;#bababa99]") @@ -481,10 +560,10 @@ local function get_inventory_fs(player, data, fs) fs("scroll_container_end[]") local btn = { - {"trash", ES"Clear inventory"}, - {"sort_az", ES"Sort items (A-Z)"}, - {"sort_za", ES"Sort items (Z-A)"}, - {"compress", ES"Compress items"}, + {"trash", ES"Clear inventory"}, + {"sort", ES"Sort items"}, + {"settings", ES"Settings"}, + {"home", ES"Go home"}, } for i, v in ipairs(btn) do @@ -493,21 +572,11 @@ local function get_inventory_fs(player, data, fs) fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])) - fs("image_button", i + 3.447 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "") + fs("image_button", i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "") fs(fmt("tooltip[%s;%s]", btn_name, tooltip)) end - if data.confirm_trash then - fs("style_type[box;colors=#999,#999,#808080,#808080]") - - for _ = 1, 3 do - fs("box", 2.97, 10.75, 4.3, 0.5, "") - end - - fs("label", 3.12, 11, "Confirm trash?") - fs("image_button", 5.17, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes") - fs("image_button", 6.27, 10.75, 1, 0.5, "", "confirm_trash_no", "No") - end + show_popup(fs, data) end local function get_tooltip(item, info, pos) diff --git a/etc/inventory.lua b/etc/inventory.lua index c9652a8..7452ae4 100644 --- a/etc/inventory.lua +++ b/etc/inventory.lua @@ -7,11 +7,11 @@ local fmt, find, match, sub, lower = i3.get("fmt", "find", "match", "sub", "lowe local vec_new, vec_mul, vec_eq, vec_round = i3.get("vec_new", "vec_mul", "vec_eq", "vec_round") local sort, copy, insert, remove, indexof = i3.get("sort", "copy", "insert", "remove", "indexof") -local msg, is_str, is_fav = i3.get("msg", "is_str", "is_fav") +local msg, is_fav = i3.get("msg", "is_fav") local is_group, extract_groups, groups_to_items = i3.get("is_group", "extract_groups", "groups_to_items") -local search, sort_by_category, apply_recipe_filters = - i3.get("search", "sort_by_category", "apply_recipe_filters") +local search, get_sorting_idx, sort_inventory, sort_by_category, apply_recipe_filters = + i3.get("search", "get_sorting_idx", "sort_inventory", "sort_by_category", "apply_recipe_filters") local show_item, spawn_item, clean_name, compressible, check_privs = i3.get("show_item", "spawn_item", "clean_name", "compressible", "check_privs") @@ -40,6 +40,8 @@ local function reset_data(data) data.export_usg = nil data.alt_items = nil data.confirm_trash = nil + data.show_settings = nil + data.show_setting = "home" data.items = data.items_raw if data.current_itab > 1 then @@ -66,104 +68,6 @@ local function get_recipes(player, item) not no_usages and usages or nil end -local function __sort(inv, reverse) - sort(inv, function(a, b) - if not is_str(a) then - a = a:get_name() - end - - if not is_str(b) then - b = b:get_name() - end - - if reverse then - return a > b - end - - return a < b - end) -end - -local function sort_itemlist(player, az) - local inv = player:get_inventory() - local list = inv:get_list("main") - local size = inv:get_size("main") - local new_inv, stack_meta = {}, {} - - for i = 1, size do - local stack = list[i] - local name = stack:get_name() - local count = stack:get_count() - local empty = stack:is_empty() - local meta = stack:get_meta():to_table() - local wear = stack:get_wear() > 0 - - if not empty then - if next(meta.fields) or wear then - stack_meta[#stack_meta + 1] = stack - else - new_inv[#new_inv + 1] = fmt("%s %u", name, count) - end - end - end - - for i = 1, #stack_meta do - new_inv[#new_inv + 1] = stack_meta[i] - end - - if az then - __sort(new_inv) - else - __sort(new_inv, true) - end - - inv:set_list("main", new_inv) -end - -local function compress_items(player) - local inv = player:get_inventory() - local list = inv:get_list("main") - local size = inv:get_size("main") - local new_inv, _new_inv, special = {}, {}, {} - - for i = 1, size do - local stack = list[i] - local name = stack:get_name() - local count = stack:get_count() - local stackmax = stack:get_stack_max() - local empty = stack:is_empty() - local meta = stack:get_meta():to_table() - local wear = stack:get_wear() > 0 - - if not empty then - if next(meta.fields) or wear or count >= stackmax then - special[#special + 1] = stack - else - new_inv[name] = new_inv[name] or 0 - new_inv[name] = new_inv[name] + count - end - end - end - - for name, count in pairs(new_inv) do - local stackmax = ItemStack(name):get_stack_max() - local iter = ceil(count / stackmax) - local leftover = count - - for _ = 1, iter do - _new_inv[#_new_inv + 1] = fmt("%s %u", name, min(stackmax, leftover)) - leftover = leftover - stackmax - end - end - - for i = 1, #special do - _new_inv[#_new_inv + 1] = special[i] - end - - __sort(_new_inv) - inv:set_list("main", _new_inv) -end - local function get_stack(player, stack) local inv = player:get_inventory() @@ -174,6 +78,13 @@ local function get_stack(player, stack) end end +local function safe_teleport(player, pos) + pos.y = pos.y + 0.5 + local vel = player:get_velocity() + player:add_velocity(vec_mul(vel, -1)) + player:set_pos(pos) +end + i3.new_tab { name = "inventory", description = S"Inventory", @@ -181,6 +92,7 @@ i3.new_tab { fields = function(player, data, fields) local name = player:get_player_name() + local inv = player:get_inventory() local sb_inv = fields.scrbar_inv if fields.skins then @@ -194,6 +106,9 @@ i3.new_tab { data.subcat = indexof(i3.SUBCAT, sub(field, 5)) break + elseif sub(field, 1, 8) == "setting_" then + data.show_setting = match(field, "_(%w+)$") + elseif find(field, "waypoint_%d+") then local id, action = match(field, "_(%d+)_(%w+)$") id = tonumber(id) @@ -206,12 +121,7 @@ i3.new_tab { elseif action == "teleport" then local pos = vec_new(waypoint.pos) - pos.y = pos.y + 0.5 - - local vel = player:get_velocity() - player:add_velocity(vec_mul(vel, -1)) - player:set_pos(pos) - + safe_teleport(player, pos) msg(name, fmt("Teleported to %s", clr("#ff0", waypoint.name))) elseif action == "refresh" then @@ -242,23 +152,79 @@ i3.new_tab { end end - if fields.trash then + if fields.quit then + data.confirm_trash = nil + data.show_settings = nil + + elseif fields.trash then + data.show_settings = nil data.confirm_trash = true + elseif fields.settings then + data.confirm_trash = nil + data.show_settings = true + elseif fields.confirm_trash_yes or fields.confirm_trash_no then if fields.confirm_trash_yes then - local inv = player:get_inventory() inv:set_list("main", {}) inv:set_list("craft", {}) end data.confirm_trash = nil - elseif fields.compress then - compress_items(player) + elseif fields.close_settings then + data.show_settings = nil - elseif fields.sort_az or fields.sort_za then - sort_itemlist(player, fields.sort_az) + elseif fields.sort then + sort_inventory(player, data) + + elseif fields.prev_sort or fields.next_sort then + local idx = get_sorting_idx(data.sort) + local tot = #i3.sorting_methods + + idx = idx - (fields.prev_sort and 1 or -1) + + if idx > tot then + idx = 1 + elseif idx == 0 then + idx = tot + end + + data.sort = i3.sorting_methods[idx].name + + elseif fields.inv_compress then + data.inv_compress = false + + if fields.inv_compress == "true" then + data.inv_compress = true + end + + elseif fields.auto_sorting then + data.auto_sorting = false + + if fields.auto_sorting == "true" then + data.auto_sorting = true + end + + elseif fields.reverse_sorting then + data.reverse_sorting = false + + if fields.reverse_sorting == "true" then + data.reverse_sorting = true + end + + elseif fields.home then + if not data.home then + return msg(name, "No home set") + elseif not check_privs(name, {home = true}) then + return msg(name, "'home' privilege missing") + end + + safe_teleport(player, core.string_to_pos(data.home)) + msg(name, S"Welcome back home!") + + elseif fields.set_home then + data.home = core.pos_to_string(player:get_pos(), 1) elseif sb_inv and sub(sb_inv, 1, 3) == "CHG" then data.scrbar_inv = tonumber(match(sb_inv, "%d+")) diff --git a/etc/styles.lua b/etc/styles.lua index a083afc..dc56d92 100644 --- a/etc/styles.lua +++ b/etc/styles.lua @@ -11,8 +11,8 @@ local PNG = { next = "i3_next.png", arrow = "i3_arrow.png", trash = "i3_trash.png", - sort_az = "i3_sort_az.png", - sort_za = "i3_sort_za.png", + sort = "i3_sort.png", + settings = "i3_settings.png", compress = "i3_compress.png", fire = "i3_fire.png", fire_anim = "i3_fire_anim.png", @@ -36,14 +36,15 @@ local PNG = { visible = "i3_visible.png^\\[brighten", nonvisible = "i3_non_visible.png", exit = "i3_exit.png", + home = "i3_home.png", cancel_hover = "i3_cancel.png^\\[brighten", search_hover = "i3_search.png^\\[brighten", export_hover = "i3_export.png^\\[brighten", trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100", compress_hover = "i3_compress.png^\\[brighten", - sort_az_hover = "i3_sort_az.png^\\[brighten", - sort_za_hover = "i3_sort_za.png^\\[brighten", + sort_hover = "i3_sort.png^\\[brighten", + settings_hover = "i3_settings.png^\\[brighten", prev_hover = "i3_next_hover.png^\\[transformFX", next_hover = "i3_next_hover.png", tab_hover = "i3_tab_hover.png", @@ -58,13 +59,14 @@ local PNG = { add_hover = "i3_add.png^\\[brighten", refresh_hover = "i3_refresh.png^\\[brighten", exit_hover = "i3_exit.png^\\[brighten", + home_hover = "i3_home.png^\\[brighten", } local styles = string.format([[ style_type[field;border=false;bgcolor=transparent] style_type[label,field;font_size=16] style_type[button;border=false;content_offset=0] - style_type[image_button,item_image_button;border=false;sound=i3_click] + style_type[image_button,item_image_button,checkbox;border=false;sound=i3_click] style_type[item_image_button;bgimg_hovered=%s] style[pagenum,no_item,no_rcp;font=bold;font_size=18] @@ -82,7 +84,7 @@ local styles = string.format([[ style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft; bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png; bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6] - style[confirm_trash_yes,confirm_trash_no;noclip=true;font_size=16; + style[confirm_trash_yes,confirm_trash_no,set_home;noclip=true;font_size=16; bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png; bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6] ]], @@ -104,6 +106,7 @@ local fs_elements = { image = "image[%f,%f;%f,%f;%s]", tooltip = "tooltip[%f,%f;%f,%f;%s]", button = "button[%f,%f;%f,%f;%s;%s]", + checkbox = "checkbox[%f,%f;%s;%s;%s]", item_image = "item_image[%f,%f;%f,%f;%s]", hypertext = "hypertext[%f,%f;%f,%f;%s;%s]", bg9 = "background9[%f,%f;%f,%f;%s;false;%u]", diff --git a/init.lua b/init.lua index 99ace14..aec119a 100644 --- a/init.lua +++ b/init.lua @@ -30,6 +30,7 @@ i3 = { }, META_SAVES = { + home = true, bag_item = true, bag_size = true, waypoints = true, @@ -38,14 +39,17 @@ i3 = { }, -- Caches - init_items = {}, - recipes_cache = {}, - usages_cache = {}, - fuel_cache = {}, + init_items = {}, + fuel_cache = {}, + usages_cache = {}, + recipes_cache = {}, + + tabs = {}, + craft_types = {}, + recipe_filters = {}, search_filters = {}, - craft_types = {}, - tabs = {}, + sorting_methods = {}, files = { api = lf("/etc/api.lua"), @@ -140,18 +144,24 @@ local function init_data(player, info) i3.data[name] = i3.data[name] or {} local data = i3.data[name] - data.filter = "" - data.pagenum = 1 - data.items = i3.init_items - data.items_raw = i3.init_items - data.favs = {} - data.export_counts = {} - data.current_tab = 1 - data.current_itab = 1 - data.subcat = 1 - data.scrbar_inv = 0 - data.lang_code = get_lang_code(info) - data.fs_version = info.formspec_version + data.filter = "" + data.pagenum = 1 + data.items = i3.init_items + data.items_raw = i3.init_items + data.favs = {} + data.sort = "alphabetical" + data.show_setting = "home" + data.auto_sorting = false + data.reverse_sorting = false + data.inv_compress = true + data.export_counts = {} + data.current_tab = 1 + data.current_itab = 1 + data.subcat = 1 + data.scrbar_inv = 0 + data.compress = true + data.lang_code = get_lang_code(info) + data.fs_version = info.formspec_version core.after(0, i3.set_fs, player) end diff --git a/textures/i3_home.png b/textures/i3_home.png new file mode 100644 index 0000000..a8d49a7 Binary files /dev/null and b/textures/i3_home.png differ diff --git a/textures/i3_settings.png b/textures/i3_settings.png new file mode 100644 index 0000000..3c87ac9 Binary files /dev/null and b/textures/i3_settings.png differ diff --git a/textures/i3_sort.png b/textures/i3_sort.png new file mode 100644 index 0000000..767a10a Binary files /dev/null and b/textures/i3_sort.png differ diff --git a/textures/i3_sort_az.png b/textures/i3_sort_az.png deleted file mode 100644 index 54d5197..0000000 Binary files a/textures/i3_sort_az.png and /dev/null differ diff --git a/textures/i3_sort_za.png b/textures/i3_sort_za.png deleted file mode 100644 index e4c3fc6..0000000 Binary files a/textures/i3_sort_za.png and /dev/null differ