From b2a9fb7b994eb6c70babd2114e35378fc74fd8f7 Mon Sep 17 00:00:00 2001 From: mckaygerhard Date: Fri, 16 Jun 2023 00:42:58 -0400 Subject: [PATCH] creative - upgraded simplified and provide privilegie feature * register privilegie of creative for older or newer engines * enhanced the formspec of the creative player to 4 rows * try to upgrade most close to track upstream original * return back text button, remove extra media check https://notabug.org/TenPlus1/creative/issues/2 * update readme information to diference features --- mods/creative/README.txt | 39 ++++- mods/creative/depends.txt | 1 - mods/creative/description.txt | 1 + mods/creative/init.lua | 297 ++++++++++++++++++++++++++-------- mods/creative/mod.conf | 3 + 5 files changed, 264 insertions(+), 77 deletions(-) create mode 100644 mods/creative/description.txt create mode 100644 mods/creative/mod.conf diff --git a/mods/creative/README.txt b/mods/creative/README.txt index 82357f3..ec7e6ed 100644 --- a/mods/creative/README.txt +++ b/mods/creative/README.txt @@ -1,12 +1,41 @@ Minetest Game mod: creative =========================== -See license.txt for license information. -Authors of source code +Simplified creative for more accurate on mobile or small screens + +Information +------------ + +This mod is named `creative` and is a replacement for default "creative" mod +of orginal game, with reduced tabs, also minenux fork it uses a cached memory +to faster lodaing respect settings. + +![screenshot.png](screenshot.png) + +Technical Information ---------------------- + +This mod fork used as base the commit `72acd4db9cc676f9e0ae1435e371adb2b10cdbe8`, +for backguard compatibility with 5.2 and 0.4.16, with minimal backports, you +can download from https://codeberg.org/minenux/minetest-mod-creative and after +clone or downloaded renamed to `creative` (obviously replace the current one if any) + +Modified by TenPlus1 (added creative privilege, reduced tab count, tweaked code), +original work is at https://notabug.org/TenPlus1/creative + +The minenux fork cut down images to use only text so media download is not a hit! + +### Authors of source code + Originally by Perttu Ahola (celeron55) (MIT) Jean-Patrick G. (kilbith) (MIT) -Author of media (textures) --------------------------- -Jean-Patrick G. (kilbith) (CC BY-SA 3.0) +### Author of media (textures) + +Jean-Patrick G. (kilbith) (CC-BY-SA 3.0) + +LICENSE +------- + +See [license.txt](license.txt) for license information. + diff --git a/mods/creative/depends.txt b/mods/creative/depends.txt index 975e652..e354eb3 100644 --- a/mods/creative/depends.txt +++ b/mods/creative/depends.txt @@ -1,2 +1 @@ -default sfinv diff --git a/mods/creative/description.txt b/mods/creative/description.txt new file mode 100644 index 0000000..5dfff03 --- /dev/null +++ b/mods/creative/description.txt @@ -0,0 +1 @@ +Simplified creative for more accurate on mobile or small screens diff --git a/mods/creative/init.lua b/mods/creative/init.lua index 576e325..fba4ecb 100644 --- a/mods/creative/init.lua +++ b/mods/creative/init.lua @@ -1,20 +1,81 @@ -creative = {} +-- creative/init.lua -minetest.register_privilege("creative", { - description = "Allow player to use creative inventory", - give_to_singleplayer = false, - give_to_admin = false, - on_grant = update_sfinv, - on_revoke = update_sfinv, -}) +-- Load support for MT game translation. +local S + +if minetest.get_translator ~= nil then + S = minetest.get_translator("creative") -- 5.x translation function +else + if minetest.get_modpath("intllib") then + dofile(minetest.get_modpath("intllib") .. "/init.lua") + if intllib.make_gettext_pair then + S = intllib.make_gettext_pair() -- new gettext method + else + S = intllib.Getter() -- old text file method + end + else -- boilerplate function + S = function(str, ...) + local args = {...} + return str:gsub("@%d+", function(match) + return args[tonumber(match:sub(2))] + end) + end + end +end + +local is_50 = minetest.has_feature("object_use_texture_alpha") +local is_53 = minetest.has_feature("object_step_has_moveresult") +local is_54 = minetest.has_feature("direct_velocity_on_players") + +creative = {} +creative.get_translator = S +creative.is_50 = is_50 +creative.is_53 = is_53 +creative.is_54 = is_54 + +local privs_description = "Allow player to use creative inventory" +local privs_definition = {} + +local function update_sfinv(name) + minetest.after(0, function() + local player = minetest.get_player_by_name(name) + if player then + if sfinv.get_page(player):sub(1, 9) == "creative:" then + sfinv.set_page(player, sfinv.get_homepage_name(player)) + else + sfinv.set_player_inventory_formspec(player) + end + end + end) +end + +if is_50 then + privs_definition = { + description = privs_description, + give_to_singleplayer = false, + give_to_admin = false, + on_grant = update_sfinv, + on_revoke = update_sfinv + } +else + privs_definition = { + description = privs_description, + give_to_singleplayer = false + } +end + +minetest.register_privilege("creative", privs_definition) local creative_mode_cache = minetest.settings:get_bool("creative_mode") -local is_53 = minetest.has_feature("object_step_has_moveresult") - +-- backguard compatibility function creative.is_creative(name) - if is_53 then - return minetest.is_creative_enabled(name) + if creative.is_53 then + if name == "" then + return minetest.is_creative_enabled(name) + else + return minetest.check_player_privs(name, {creative = true}) or creative_mode_cache + end else return minetest.check_player_privs(name, {creative = true}) or creative_mode_cache end @@ -26,12 +87,12 @@ function minetest.is_creative_enabled(name) if name == "" then return old_is_creative_enabled(name) end - return minetest.check_player_privs(name, {creative = true}) or old_is_creative_enabled(name) + return minetest.check_player_privs(name, {creative = true}) or old_is_creative_enabled(name) end -- For backwards compatibility: function creative.is_enabled_for(name) - return minetest.is_creative_enabled(name) + return creative.is_creative(name) end local player_inventory = {} @@ -56,7 +117,9 @@ function creative.init_creative_inventory(player) player_inventory[player_name] = { size = 0, filter = "", - start_i = 0 + start_i = 0, + old_filter = nil, -- use only for caching in update_creative_inventory + old_content = nil } minetest.create_detached_inventory("creative_" .. player_name, { @@ -90,29 +153,76 @@ function creative.init_creative_inventory(player) return player_inventory[player_name] end +local NO_MATCH = 999 +local function match(s, filter) + if filter == "" then + return 0 + end + if s:lower():find(filter, 1, true) then + return #s - #filter + end + return NO_MATCH +end + +local function description(def, lang_code) + local s = def.description + if creative.is_53 then + if lang_code then + s = minetest.get_translated_string(lang_code, s) + end + end + return s:gsub("\n.*", "") -- First line only +end + function creative.update_creative_inventory(player_name, tab_content) - local creative_list = {} local inv = player_inventory[player_name] or creative.init_creative_inventory(minetest.get_player_by_name(player_name)) local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name}) + if inv.filter == inv.old_filter and tab_content == inv.old_content then + return + end + inv.old_filter = inv.filter + inv.old_content = tab_content + local items = inventory_cache[tab_content] or init_creative_cache(tab_content) - for name, def in pairs(items) do - if def.name:find(inv.filter, 1, true) or - def.description:lower():find(inv.filter, 1, true) then - creative_list[#creative_list+1] = name + local lang = minetest.settings:get("language") or "en" + local player_info = minetest.get_player_information(player_name) + + if is_53 then + if player_info and player_info.lang_code ~= "" then + lang = player_info.lang_code end end - table.sort(creative_list) + local creative_list = {} + local order = {} + for name, def in pairs(items) do + local m = match(description(def), inv.filter) + if m > 0 then + m = math.min(m, match(description(def, lang), inv.filter)) + end + if m > 0 then + m = math.min(m, match(name, inv.filter)) + end + + if m < NO_MATCH then + creative_list[#creative_list+1] = name + -- Sort by match value first so closer matches appear earlier + order[name] = string.format("%02d", m) .. name + end + end + + table.sort(creative_list, function(a, b) return order[a] < order[b] end) + player_inv:set_size("main", #creative_list) player_inv:set_list("main", creative_list) inv.size = #creative_list end -- Create the trash field -local trash = minetest.create_detached_inventory("creative_trash", { +local trash = minetest.create_detached_inventory("trash", { -- Allow the stack to be placed and remove it in on_put() -- This allows the creative inventory to restore the stack allow_put = function(inv, listname, index, stack, player) @@ -137,31 +247,29 @@ function creative.register_tab(name, title, items) creative.update_creative_inventory(player_name, items) local inv = player_inventory[player_name] local start_i = inv.start_i or 0 - local pagenum = math.floor(start_i / (3*8) + 1) - local pagemax = math.ceil(inv.size / (3*8)) + local pagenum = math.floor(inv.start_i / (4*8) + 1) + local pagemax = math.max(math.ceil(inv.size / (4*8)), 1) + local esc = minetest.formspec_escape return sfinv.make_formspec(player, context, - "label[6.2,3.35;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" .. + (inv.size == 0 and ("label[3,2;>_<]") or "") .. + "label[5.8,4.15;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" .. [[ - image[4.06,3.4;0.8,0.8;creative_trash_icon.png] + image[4,3.9;0.8,0.8;creative_trash_icon.png] listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF] list[current_player;main;0,4.7;8,1;] list[current_player;main;0,5.85;8,3;8] - list[detached:creative_trash;main;4,3.3;1,1;] + list[detached:trash;main;4,3.9;1,1;] listring[] - button[5.4,3.2;0.8,0.9;creative_prev;<] - button[7.25,3.2;0.8,0.9;creative_next;>] - button[2.1,3.4;0.8,0.5;creative_search;?] - button[2.75,3.4;0.8,0.5;creative_clear;X] - tooltip[creative_search;Search] - tooltip[creative_clear;Reset] - tooltip[creative_prev;Previous page] - tooltip[creative_next;Next page] - listring[current_player;main] - field_close_on_enter[creative_filter;false] + button[5,4.05;0.8,0.8;creative_prev;<] + button[7.25,4.05;0.8,0.8;creative_next;>] + button[2.63,4.05;0.8,0.8;creative_search;?] + button[3.25,4.05;0.8,0.8;creative_clear;X] ]] .. - "field[0.3,3.5;2.2,1;creative_filter;;" .. minetest.formspec_escape(inv.filter) .. "]" .. + "listring[current_player;main]" .. + "field_close_on_enter[creative_filter;false]" .. + "field[0.3,4.2;2.8,1.2;creative_filter;;" .. esc(inv.filter) .. "]" .. "listring[detached:creative_" .. player_name .. ";main]" .. - "list[detached:creative_" .. player_name .. ";main;0,0;8,3;" .. tostring(start_i) .. "]" .. + "list[detached:creative_" .. player_name .. ";main;0,0;8,4;" .. tostring(inv.start_i) .. "]" .. default.get_hotbar_bg(0,4.7) .. default.gui_bg .. default.gui_bg_img .. default.gui_slots .. creative.formspec_add, false) @@ -181,27 +289,30 @@ function creative.register_tab(name, title, items) if fields.creative_clear then inv.start_i = 0 inv.filter = "" - creative.update_creative_inventory(player_name, items) + --creative.update_creative_inventory(player_name, items) sfinv.set_player_inventory_formspec(player, context) - elseif fields.creative_search or - fields.key_enter_field == "creative_filter" then + elseif (fields.creative_search or + fields.key_enter_field == "creative_filter") + and fields.creative_filter then inv.start_i = 0 - inv.filter = fields.creative_filter:lower() - creative.update_creative_inventory(player_name, items) + inv.filter = fields.creative_filter:sub(1, 128) -- truncate to a sane length + :gsub("[%z\1-\8\11-\31\127]", "") -- strip naughty control characters (keeps \t and \n) + :lower() -- search is case insensitive + --creative.update_creative_inventory(player_name, items) sfinv.set_player_inventory_formspec(player, context) elseif not fields.quit then local start_i = inv.start_i or 0 if fields.creative_prev then - start_i = start_i - 3*8 + start_i = start_i - 4*8 if start_i < 0 then - start_i = inv.size - (inv.size % (3*8)) + start_i = inv.size - (inv.size % (4*8)) if inv.size == start_i then - start_i = math.max(0, inv.size - (3*8)) + start_i = math.max(0, inv.size - (4*8)) end end elseif fields.creative_next then - start_i = start_i + 3*8 + start_i = start_i + 4*8 if start_i >= inv.size then start_i = 0 end @@ -214,11 +325,37 @@ function creative.register_tab(name, title, items) }) end +-- Sort registered items +local registered_nodes = {} +local registered_tools = {} +local registered_craftitems = {} + +local tab_items = function() + for name, def in pairs(minetest.registered_items) do + local group = def.groups or {} + + local nogroup = not (group.node or group.tool or group.craftitem) + if group.node or (nogroup and minetest.registered_nodes[name]) then + registered_nodes[name] = def + elseif group.tool or (nogroup and minetest.registered_tools[name]) then + registered_tools[name] = def + elseif group.craftitem or (nogroup and minetest.registered_craftitems[name]) then + registered_craftitems[name] = def + end + end +end + +if minetest.register_on_mods_loaded then + minetest.register_on_mods_loaded(tab_items) +else + minetest.after(0.1, tab_items) +end + +creative.register_tab("all", "Creative", minetest.registered_items) --creative.register_tab("all", "All", minetest.registered_items) --creative.register_tab("nodes", "Nodes", minetest.registered_nodes) --creative.register_tab("tools", "Tools", minetest.registered_tools) --creative.register_tab("craftitems", "Items", minetest.registered_craftitems) -creative.register_tab("all", "Creative", minetest.registered_items) local old_homepage_name = sfinv.get_homepage_name function sfinv.get_homepage_name(player) @@ -230,13 +367,14 @@ function sfinv.get_homepage_name(player) end -if creative_mode_cache then - -- Dig time is modified according to difference (leveldiff) between tool - -- 'maxlevel' and node 'level'. Digtime is divided by the larger of - -- leveldiff and 1. - -- To speed up digging in creative, hand 'maxlevel' and 'digtime' have been - -- increased such that nodes of differing levels have an insignificant - -- effect on digtime. +if minetest.is_creative_enabled("") then + local hand_hack = function() + -- Dig time is modified according to difference (leveldiff) between tool + -- 'maxlevel' and node 'level'. Digtime is divided by the larger of + -- leveldiff and 1. + -- To speed up digging in creative, hand 'maxlevel' and 'digtime' have been + -- increased such that nodes of differing levels have an insignificant + -- effect on digtime. local digtime = 42 local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 256} @@ -254,33 +392,50 @@ if creative_mode_cache then snappy = caps, choppy = caps, oddly_breakable_by_hand = caps, + -- dig_immediate group doesn't use value 1. Value 3 is instant dig + dig_immediate = {times = {[2] = digtime, [3] = 0}, uses = 0, maxlevel = 256}, }, damage_groups = {fleshy = 10}, } }) + end + if minetest.register_on_mods_loaded then + minetest.register_on_mods_loaded(hand_hack) + else + minetest.after(0, hand_hack) + end end -- Unlimited node placement minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack) - if placer and placer:is_player() then - return creative.is_enabled_for(placer:get_player_name()) + if placer then + if placer:is_player() then + return creative.is_creative(placer:get_player_name()) + end end end) --- Don't pick up if the item is already in the inventory -local old_handle_node_drops = minetest.handle_node_drops -function minetest.handle_node_drops(pos, drops, digger) - if not digger or not digger:is_player() or --- not creative.is_enabled_for(digger:get_player_name()) then - not creative_mode_cache then - return old_handle_node_drops(pos, drops, digger) - end - local inv = digger:get_inventory() - if inv then - for _, item in ipairs(drops) do - if not inv:contains_item("main", item, true) then - inv:add_item("main", item) +-- Don't pick up if the item is already in the inventory only in hard creative single +if creative_mode_cache then + local old_handle_node_drops = minetest.handle_node_drops + function minetest.handle_node_drops(pos, drops, digger) + if not digger then + if not digger:is_player() then + if not creative.is_creative(digger:get_player_name()) then + return old_handle_node_drops(pos, drops, digger) + end + end + end + local inv = digger:get_inventory() + if inv then + for _, item in ipairs(drops) do + if not inv:contains_item("main", item, true) then + inv:add_item("main", item) + end end end end end + +print("[creative] mod loaded") + diff --git a/mods/creative/mod.conf b/mods/creative/mod.conf new file mode 100644 index 0000000..198455a --- /dev/null +++ b/mods/creative/mod.conf @@ -0,0 +1,3 @@ +name = creative +depends = sfinv +description = Simplified creative for more accurate on mobiles or small screens