diff --git a/.luacheckrc b/.luacheckrc index ceef878..1ef8d39 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -13,6 +13,8 @@ read_globals = { "string", "table", "ItemStack", + "VoxelArea", + "VoxelManip", } globals = { diff --git a/README.md b/README.md index 10aebf6..c691510 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This mod requires **Minetest 5.4+** - Progressive ModeĀ¹ - Quick Crafting - 3D Player Model Real-Time Preview + - Isometric Area Preview - Inventory Sorting (+ options: compression, reverse mode, automation, etc.) - Item List Compression (**`moreblocks`** is supported) - Item Bookmarks diff --git a/init.lua b/init.lua index b5158c5..d290f27 100644 --- a/init.lua +++ b/init.lua @@ -38,6 +38,8 @@ i3 = { fuel_cache = {}, usages_cache = {}, recipes_cache = {}, + content_ids = {}, + cubes = {}, tabs = {}, craft_types = {}, @@ -49,6 +51,7 @@ i3 = { files = { api = lf("/src/api.lua"), bags = lf("/src/bags.lua"), + caches = lf("/src/caches.lua"), callbacks = lf("/src/callbacks.lua"), common = lf("/src/common.lua"), compress = lf("/src/compress.lua"), @@ -57,7 +60,6 @@ i3 = { gui = lf("/src/gui.lua"), model_alias = lf("/src/model_aliases.lua"), progressive = lf("/src/progressive.lua"), - recipes = lf("/src/recipes.lua"), styles = lf("/src/styles.lua"), }, @@ -80,7 +82,7 @@ i3.data = dslz(storage:get_string"data") or {} local init_bags = i3.files.bags() local init_inventories = i3.files.detached() -local init_recipes = i3.files.recipes() +local fill_caches = i3.files.caches() local function get_lang_code(info) return info and info.lang_code @@ -208,7 +210,7 @@ local function save_data(player_name) end core.register_on_mods_loaded(function() - init_recipes() + fill_caches() disable_inventories() end) diff --git a/src/recipes.lua b/src/caches.lua similarity index 90% rename from src/recipes.lua rename to src/caches.lua index 6d9b75f..e75c631 100644 --- a/src/recipes.lua +++ b/src/caches.lua @@ -1,8 +1,8 @@ local replacements = {fuel = {}} local ItemStack = ItemStack -local fmt, reg_items, reg_aliases = i3.get("fmt", "reg_items", "reg_aliases") -local maxn, copy, insert, sort, match = i3.get("maxn", "copy", "insert", "sort", "match") +local fmt, reg_items, reg_aliases, reg_nodes = i3.get("fmt", "reg_items", "reg_aliases", "reg_nodes") +local maxn, copy, insert, sort, match, sub = i3.get("maxn", "copy", "insert", "sort", "match", "sub") local is_group, extract_groups, item_has_groups, groups_to_items = i3.get("is_group", "extract_groups", "item_has_groups", "groups_to_items") @@ -286,4 +286,23 @@ local function init_recipes() end end -return init_recipes +local function init_cubes() + for name, def in pairs(reg_nodes) do + if def and def.drawtype == "normal" or def.drawtype == "liquid" or + sub(def.drawtype, 1, 9) == "glasslike" or + sub(def.drawtype, 1, 8) == "allfaces" then + local id = core.get_content_id(name) + i3.content_ids[id] = name + + local tile = def.tiles[1].name or def.tiles[1] + local cube = core.inventorycube(tile, tile, tile) + + i3.cubes[name] = cube + end + end +end + +return function() + init_recipes() + init_cubes() +end diff --git a/src/callbacks.lua b/src/callbacks.lua index b2306c8..71b845b 100644 --- a/src/callbacks.lua +++ b/src/callbacks.lua @@ -2,8 +2,7 @@ local _, get_inventory_fs = i3.files.gui() local set_fs = i3.set_fs local ItemStack = ItemStack -local S, clr = i3.get("S", "clr") -local min, random = i3.get("min", "random") +local S, min, random = i3.get("S", "min", "random") local reg_items, reg_aliases = i3.get("reg_items", "reg_aliases") local fmt, find, match, sub, lower, split = i3.get("fmt", "find", "match", "sub", "lower", "split") local vec_new, vec_eq, vec_round = i3.get("vec_new", "vec_eq", "vec_round") @@ -78,18 +77,25 @@ i3.new_tab("inventory", { elseif find(field, "waypoint_%d+") then local id, action = match(field, "_(%d+)_(%w+)$") - id = tonumber(id) + id = tonumber(id) local waypoint = data.waypoints[id] if not waypoint then return end - if action == "delete" then + if action == "see" then + if data.waypoint_see and data.waypoint_see == id then + data.waypoint_see = nil + else + data.waypoint_see = id + end + + elseif action == "delete" then player:hud_remove(waypoint.id) remove(data.waypoints, id) elseif action == "teleport" then local pos = vec_new(str_to_pos(waypoint.pos)) safe_teleport(player, pos) - msg(name, fmt("Teleported to %s", clr("#ff0", waypoint.name))) + msg(name, S("Teleported to: @1", waypoint.name)) elseif action == "refresh" then local color = random(0xffffff) @@ -116,6 +122,7 @@ i3.new_tab("inventory", { if fields.quit then data.confirm_trash = nil data.show_settings = nil + data.waypoint_see = nil elseif fields.trash then data.show_settings = nil @@ -140,6 +147,9 @@ i3.new_tab("inventory", { elseif fields.close_settings then data.show_settings = nil + elseif fields.close_preview then + data.waypoint_see = nil + elseif fields.sort then sort_inventory(player, data) diff --git a/src/common.lua b/src/common.lua index dd6c0d2..2a6993f 100644 --- a/src/common.lua +++ b/src/common.lua @@ -1,5 +1,7 @@ local ItemStack = ItemStack local loadstring = loadstring + +local vec_add, vec_mul = vector.add, vector.multiply local sort, concat, insert = table.sort, table.concat, table.insert local min, floor, ceil = math.min, math.floor, math.ceil local fmt, find, match, gmatch, sub, split, lower = @@ -319,7 +321,7 @@ local function spawn_item(player, stack) local dir = player:get_look_dir() local ppos = player:get_pos() ppos.y = ppos.y + player:get_properties().eye_height - local look_at = vector.add(ppos, vector.multiply(dir, 1)) + local look_at = vec_add(ppos, vec_mul(dir, 1)) core.add_item(look_at, stack) end @@ -410,7 +412,7 @@ local function safe_teleport(player, pos) pos.y = pos.y + 0.5 local vel = player:get_velocity() - player:add_velocity(vector.multiply(vel, -1)) + player:add_velocity(vec_mul(vel, -1)) player:set_pos(pos) end @@ -691,6 +693,8 @@ local _ = { -- Vectors vec_new = vector.new, vec_add = vector.add, + vec_sub = vector.subtract, + vec_mul = vector.multiply, vec_round = vector.round, vec_eq = vector.equals, } diff --git a/src/gui.lua b/src/gui.lua index 88aafe8..2ca2356 100644 --- a/src/gui.lua +++ b/src/gui.lua @@ -4,16 +4,19 @@ local model_aliases = i3.files.model_alias() local PNG, styles, fs_elements, colors = i3.files.styles() local ItemStack = ItemStack +local VoxelArea, VoxelManip = VoxelArea, VoxelManip + local S, ES, translate = i3.get("S", "ES", "translate") local clr, ESC, check_privs = i3.get("clr", "ESC", "check_privs") +local vec_new, vec_sub, vec_round = i3.get("vec_new", "vec_sub", "vec_round") 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, unpack = i3.get("maxn", "sort", "concat", "copy", "insert", "remove", "unpack") -local true_str, is_fav, is_num, get_group = - i3.get("true_str", "is_fav", "is_num", "get_group") +local true_str, is_fav, is_num, get_group, str_to_pos = + i3.get("true_str", "is_fav", "is_num", "get_group", "str_to_pos") 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 = @@ -224,6 +227,45 @@ local function get_award_list(data, fs, ctn_len, yextra, award_list, awards_unlo end end +local function get_isometric_view(fs, pos, X, Y) + pos = vec_round(pos) + local size = 0.25 + local width = 8 + + local pos1 = vec_new(pos.x - width, pos.y - 1, pos.z - width) + local pos2 = vec_new(pos.x + width, pos.y + 3, pos.z + width) + core.emerge_area(pos1, pos2) + + local vm = VoxelManip(pos1, pos2) + local emin, emax = vm:read_from_map(pos1, pos2) + local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} + local data = vm:get_data() + + local t = {} + data[0] = #data + + for i = 1, data[0] do + local id = data[i] + t[i] = i3.content_ids[id] + end + + for idx in area:iterp(pos1, pos2) do + local name = t[idx] + local cube = i3.cubes[name] + + if cube then + local p = area:position(idx) + p = vec_sub(p, pos) + + local x = 2 + (size / 2 * (p.z - p.x)) + local y = 1.15 + (size / 4 * (p.x + p.z - 2 * p.y)) + local elem = fmt("image[%f,%f;%.1f,%.1f;%s]", x + X, y + Y, size, size, cube) + + insert(fs, elem) + end + end +end + local function get_waypoint_fs(fs, data, player, yextra, ctn_len) fs(fmt("box[0,%f;4.9,0.6;#bababa25]", yextra + 1.1)) fs("label", 0, yextra + 0.85, ES"Waypoint name:") @@ -254,10 +296,19 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len) hex = "0" .. hex end + local teleport_priv = check_privs(player, {teleport = true}) + local waypoint_preview = data.waypoint_see and data.waypoint_see == i + fs("label", 0.15, y + 0.33, clr(fmt("#%s", hex), waypoint_name)) - fs("tooltip", 0, y, ctn_len - 2.5, 0.65, - fmt("Name: %s\nPosition:%s", clr("#dbeeff", v.name), - v.pos:sub(2,-2):gsub("(%-*%d*%.?%d+)", clr("#dbeeff", " %1")))) + + local tooltip = fmt("Name: %s\nPosition:%s", clr("#dbeeff", v.name), + v.pos:sub(2,-2):gsub("(%-*%d*%.?%d+)", clr("#dbeeff", " %1"))) + + if teleport_priv then + tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]")) + end + + fs("tooltip", 0, y, ctn_len - 2.1, 0.65, tooltip) local del = fmt("waypoint_%u_delete", i) fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover)) @@ -269,17 +320,31 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len) fs("image_button", ctn_len - 1, yi, icon_size, icon_size, "", rfs, "") fs(fmt("tooltip[%s;%s]", rfs, ES"Change color")) + local see = fmt("waypoint_%u_see", i) + fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", + see, waypoint_preview and PNG.search_hover or PNG.search, PNG.search, PNG.search_hover)) + fs("image_button", ctn_len - 1.5, yi, icon_size, icon_size, "", see, "") + fs(fmt("tooltip[%s;%s]", see, ES"Preview the waypoint area")) + local vsb = fmt("waypoint_%u_hide", i) fs(fmt("style[%s;fgimg=%s;content_offset=0]", vsb, v.hide and PNG.nonvisible or PNG.visible)) - fs("image_button", ctn_len - 1.5, yi, icon_size, icon_size, "", vsb, "") + fs("image_button", ctn_len - 2, yi, icon_size, icon_size, "", vsb, "") fs(fmt("tooltip[%s;%s]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint")) - if check_privs(player, {teleport = true}) then + if teleport_priv then local tp = fmt("waypoint_%u_teleport", i) - fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", - tp, PNG.teleport, PNG.teleport_hover)) - fs("image_button", ctn_len - 2, yi, icon_size, icon_size, "", tp, "") - fs(fmt("tooltip[%s;%s]", tp, ES"Teleport to waypoint")) + fs("button", 0, y, ctn_len - 2.1, 0.6, tp, "") + end + + if waypoint_preview then + fs("image", 0.25, y - 3.5, 5, 4, PNG.bg_content) + fs("button", 0.25, y - 3.35, 5, 0.55, "area_preview", v.name) + fs("image_button", 4.65, y - 3.25, 0.25, 0.25, + PNG.cancel_hover .. "^\\[brighten", "close_preview", "") + + local pos = vec_new(str_to_pos(data.waypoints[i].pos)) + get_isometric_view(fs, pos, 0.6, y - 2.5) + fs("image", 2.7, y - 1.5, 0.3, 0.3, PNG.flag) end end diff --git a/src/styles.lua b/src/styles.lua index 7fc0cb4..1b61899 100644 --- a/src/styles.lua +++ b/src/styles.lua @@ -32,13 +32,13 @@ local PNG = { awards = "i3_award.png", skins = "i3_skin.png", waypoints = "i3_waypoint.png", - teleport = "i3_teleport.png", add = "i3_add.png", refresh = "i3_refresh.png", visible = "i3_visible.png^\\[brighten", nonvisible = "i3_non_visible.png", exit = "i3_exit.png", home = "i3_home.png", + flag = "i3_flag.png", cancel_hover = "i3_cancel.png^\\[brighten", search_hover = "i3_search.png^\\[brighten", @@ -57,7 +57,6 @@ local PNG = { awards_hover = "i3_award_hover.png", skins_hover = "i3_skin_hover.png", waypoints_hover = "i3_waypoint_hover.png", - teleport_hover = "i3_teleport.png^\\[brighten", add_hover = "i3_add.png^\\[brighten", refresh_hover = "i3_refresh.png^\\[brighten", exit_hover = "i3_exit.png^\\[brighten", diff --git a/textures/i3_flag.png b/textures/i3_flag.png new file mode 100644 index 0000000..06f21e1 Binary files /dev/null and b/textures/i3_flag.png differ diff --git a/textures/i3_teleport.png b/textures/i3_teleport.png deleted file mode 100644 index 5b911fa..0000000 Binary files a/textures/i3_teleport.png and /dev/null differ