Mods update

master
Daretmavi 2021-07-07 17:02:36 +02:00
parent f11ec46f3f
commit ed2630c292
15 changed files with 632 additions and 112 deletions

View File

@ -78,7 +78,7 @@ Mod: flora/farming
origin https://github.com/daretmavi/i3.git (fetch) origin https://github.com/daretmavi/i3.git (fetch)
upstream https://github.com/minetest-mods/i3.git (fetch) upstream https://github.com/minetest-mods/i3.git (fetch)
* main 7bd3e5d [origin/main] New Variable i3_no_trash_in_survival Better bool reading from settings * main 4e39096 [origin/main] Merge pull request #4 from daretmavi/devtest
Mod: gui/i3 Mod: gui/i3
origin https://repo.or.cz/minetest_hbarmor.git (fetch) origin https://repo.or.cz/minetest_hbarmor.git (fetch)
@ -118,7 +118,7 @@ origin https://notabug.org/tenplus1/mobs_redo (fetch)
Mod: lib_api/mobs_redo Mod: lib_api/mobs_redo
origin https://github.com/appgurueu/modlib (fetch) origin https://github.com/appgurueu/modlib (fetch)
* master abced34 [origin/master] Deal with Lua log file memory leak * master 35081f3 [origin/master] Localize global fields
Mod: lib_api/modlib Mod: lib_api/modlib
origin git@github.com:runsy/rcbows.git (fetch) origin git@github.com:runsy/rcbows.git (fetch)

View File

@ -0,0 +1,9 @@
[*]
end_of_line = lf
[*.{lua,txt,md,json}]
charset = utf8
indent_size = 8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -84,6 +84,9 @@ local styles = fmt([[
style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft; style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft;
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png; bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6] bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
style[confirm_trash_yes,confirm_trash_no;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]
]], ]],
PNG.slot, PNG.slot,
PNG.exit, PNG.exit_hover, PNG.exit, PNG.exit_hover,

View File

@ -0,0 +1,251 @@
-- ****************************************************************************
-- Funnctions and Variables from i3 init.lua
local modpath = core.get_modpath "i3"
local maxn, sort, concat, copy, insert, remove, indexof =
table.maxn, table.sort, table.concat, table.copy,
table.insert, table.remove, table.indexof
local sprintf, find, gmatch, match, sub, split, upper, lower =
string.format, string.find, string.gmatch, string.match,
string.sub, string.split, string.upper, string.lower
local PNG, styles, fs_elements = loadfile(modpath .. "/etc/styles.lua")()
local ESC = core.formspec_escape
local S = core.get_translator "i3"
local ES = function(...)
return ESC(S(...))
end
local function fmt(elem, ...)
if not fs_elements[elem] then
return sprintf(elem, ...)
end
return sprintf(fs_elements[elem], ...)
end
local function add_subtitle(fs, name, y, ctn_len, font_size, sep, label)
fs(fmt("style[%s;font=bold;font_size=%u]", name, font_size))
fs("button", 0, y, ctn_len, 0.5, name, ESC(label))
if sep then
fs("image", 0, y + 0.55, ctn_len, 0.035, PNG.bar)
end
end
-- ****************************************************************************
-- Function to get detail info aout texture
-- Forked from skinsdb mod
local function get_skin_info_formspec(skin, xoffset, yoffset)
local texture = skin:get_texture()
local m_name = skin:get_meta_string("name")
local m_author = skin:get_meta_string("author")
local m_license = skin:get_meta_string("license")
local m_format = skin:get_meta("format")
-- overview page
local raw_size = m_format == "1.8" and "2,2" or "2,1"
--local lxoffs = 0.8 + xoffset
local cxoffs = 2 + xoffset
local rxoffs = 2 + xoffset
local formspec = "" -- = "image["..lxoffs..","..0.6 + yoffset..";1,2;"..minetest.formspec_escape(skin:get_preview()).."]"
if texture then
formspec = formspec.."label["..rxoffs..","..2 + yoffset..";"..S("Raw texture")..":]"
.."image["..1 + rxoffs..","..2.5 + yoffset..";"..raw_size..";"..texture.."]"
end
if m_name ~= "" then
formspec = formspec.."label["..cxoffs..","..0.5 + yoffset..";"..S("Name")..": "..minetest.formspec_escape(m_name).."]"
end
if m_author ~= "" then
formspec = formspec.."label["..cxoffs..","..1 + yoffset..";"..S("Author")..": "..minetest.formspec_escape(m_author).."]"
end
if m_license ~= "" then
formspec = formspec.."label["..cxoffs..","..1.5 + yoffset..";"..S("License")..": "..minetest.formspec_escape(m_license).."]"
end
return formspec
end
-- skin images and pages
local function get_skin_selection_formspec(player, context)
context.skins_list = skins.get_skinlist_for_player(player:get_player_name())
context.total_pages = 1
local xoffs = 0.8
local yoffs = 6.5
local xspc = 1.1
local yspc = 2.1
local skinwidth = 1
local skinheight = 2
local xscale = 1
local btn_y = yoffs + 4.5
local drop_y = yoffs + 4.5
local btn_width = 0.35
local btn_heigh = 0.35
local droppos = xoffs + 1.3
local droplen = 6.2
local btn_left = droppos - btn_width
local btn_right = droppos + droplen
local maxdisp = 16
local ctrls_height = 0.4
for i, skin in ipairs(context.skins_list ) do
local page = math.floor((i-1) / maxdisp)+1
skin:set_meta("inv_page", page)
skin:set_meta("inv_page_index", (i-1)%maxdisp+1)
context.total_pages = page
end
context.skins_page = context.skins_page or skins.get_player_skin(player):get_meta("inv_page") or 1
context.dropdown_values = nil
local page = context.skins_page
local formspec = ""
for i = (page-1)*maxdisp+1, page*maxdisp do
local skin = context.skins_list[i]
if not skin then
break
end
local index_p = skin:get_meta("inv_page_index")
local x = ((index_p-1) % 8) * xspc + xoffs
local y
if index_p > 8 then
y = yoffs + yspc
else
y = yoffs
end
formspec = formspec..
string.format("image_button[%f,%f;%f,%f;%s;skins_set$%i;]",
x, y, skinwidth, skinheight,
minetest.formspec_escape(skin:get_preview()), i)..
"tooltip[skins_set$"..i..";"..minetest.formspec_escape(skin:get_meta_string("name")).."]"
end
if context.total_pages > 1 then
local page_prev = page - 1
local page_next = page + 1
if page_prev < 1 then
page_prev = context.total_pages
end
if page_next > context.total_pages then
page_next = 1
end
local page_list = ""
context.dropdown_values = {}
for pg=1, context.total_pages do
local pagename = S("Page").." "..pg.."/"..context.total_pages
context.dropdown_values[pagename] = pg
if pg > 1 then page_list = page_list.."," end
page_list = page_list..pagename
end
formspec = formspec..
string.format("image_button[%f,%f;%f,%f;%s;skins_page$%i;]",
btn_left, btn_y, btn_width, btn_heigh, PNG.prev, page_prev)..
string.format("image_button[%f,%f;%f,%f;%s;skins_page$%i;]",
btn_right, btn_y, btn_width, btn_heigh, PNG.next, page_next)..
string.format("dropdown[%f,%f;%f,%f;skins_selpg;%s;%i]",
droppos, drop_y, droplen, ctrls_height, page_list, page)
end
return formspec
end
-- ****************************************************************************
-- i3 Tab definition
i3.new_tab {
name = "Skins",
description = "Skins",
image = "i3_skin.png",
formspec = function(player, data, fs)
--fs("label[3,1;Test 1]")
local name = player:get_player_name()
local ctn_len, ctn_hgt = 5.7, 6.3
local yextra = 1
local yoffset = 0
local xpos = 5
local _skins = skins.get_skinlist_for_player(name)
local skin_name = skins.get_player_skin(player).name
local sks, id = {}, 1
local props = player:get_properties()
for i, skin in ipairs(_skins) do
if skin.name == skin_name then
id = i
end
sks[#sks + 1] = skin.name
end
sks = concat(sks, ","):gsub(";", "")
add_subtitle(fs, "player_name", 0, ctn_len + 4.5, 22, true, ESC(name))
if props.mesh ~= "" then
local anim = player:get_local_animation()
local armor_skin = __3darmor or __skinsdb
local t = {}
for _, v in ipairs(props.textures) do
t[#t + 1] = ESC(v):gsub(",", "!")
end
local textures = concat(t, ","):gsub("!", ",")
local skinxoffset = 1.3
--fs("style[player_model;bgcolor=black]")
fs("model", skinxoffset, 0.2, armor_skin and 4 or 3.4, ctn_hgt,
"player_model", props.mesh, textures, "0,-150", "false", "false",
fmt("%u,%u%s", anim.x, anim.y, data.fs_version >= 5 and ";30" or ""))
else
local size = 2.5
fs("image", 0.7, 0.2, size, size * props.visual_size.y, props.textures[1])
end
fs("label", xpos, yextra, fmt("%s:", ES"Select a skin"))
fs(fmt("dropdown[%f,%f;4,0.6;skins;%s;%u;true]", xpos, yextra + 0.2, sks, id))
local skin = skins.get_player_skin(player)
local formspec = get_skin_info_formspec(skin, 3, 2)
fs(formspec)
--core.log("fs skins: "..dump(formspec))
local context = skins.get_formspec_context(player)
local formspec = get_skin_selection_formspec(player, context)
--core.log("skins context: "..dump(context))
--core.log("fs skins: "..dump(formspec))
fs(formspec)
end,
-- click button handlers - giving fields
fields = function(player, data, fields)
local name = player:get_player_name()
local sb_inv = fields.scrbar_inv
--core.log("fields: "..dump(fields))
-- set skin with dropdown from original i3 inventory
if fields.skins then
local id = tonumber(fields.skins)
local _skins = skins.get_skinlist_for_player(name)
skins.set_player_skin(player, _skins[id])
end
-- set skin with skinddb image an page change
local context = skins.get_formspec_context(player)
local action = skins.on_skin_selection_receive_fields(player, context, fields)
-- update formspec
return i3.set_fs(player)
end,
}
-- ****************************************************************************

View File

@ -20,13 +20,17 @@ local PNG, styles, fs_elements = loadfile(modpath .. "/etc/styles.lua")()
local compress_groups, compressed = loadfile(modpath .. "/etc/compress.lua")() local compress_groups, compressed = loadfile(modpath .. "/etc/compress.lua")()
local group_stereotypes, group_names = loadfile(modpath .. "/etc/groups.lua")() local group_stereotypes, group_names = loadfile(modpath .. "/etc/groups.lua")()
local progressive_mode = core.settings:get_bool("i3_progressive_mode", false) local progressive_mode = core.settings:get_bool("i3_progressive_mode", true)
local item_compression = core.settings:get_bool("i3_item_compression", true) local item_compression = core.settings:get_bool("i3_item_compression", true)
local damage_enabled = core.settings:get_bool "enable_damage" local damage_enabled = core.settings:get_bool "enable_damage"
-- new settings
local creative_trash_only = core.settings:get_bool("i3_no_trash_in_survival", true)
local use_skinsdb_tab = core.settings:get_bool("i3_skinsdb_tab", true)
-- ************
local __3darmor, __skinsdb, __awards local __3darmor, __skinsdb, __awards
local __sfinv, old_sfinv_fn
local __unified_inventory, old_unified_inventory_fn
local http = core.request_http_api() local http = core.request_http_api()
local singleplayer = core.is_singleplayer() local singleplayer = core.is_singleplayer()
@ -107,11 +111,11 @@ local function get_formspec_version(info)
end end
local function outdated(name) local function outdated(name)
local fs = sprintf("size[5.8,1.3]image[0,0;1,1;%s]label[1,0;%s]button_exit[2.4,0.8;1,1;;OK]", local fs = sprintf("size[6.3,1.3]image[0,0;1,1;%s]label[1,0;%s]button_exit[2.6,0.8;1,1;;OK]",
PNG.book, PNG.book,
"Your Minetest client is outdated.\nGet the latest version on minetest.net to use i3") "Your Minetest client is outdated.\nGet the latest version on minetest.net to play the game.")
core.show_formspec(name, "i3", fs) core.show_formspec(name, "i3_outdated", fs)
end end
local old_is_creative_enabled = core.is_creative_enabled local old_is_creative_enabled = core.is_creative_enabled
@ -2011,7 +2015,6 @@ local function get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, a
-- fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75)) -- fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75))
--fs("image", 4.45, yoffset + 3.75, 1, 1, PNG.trash) --fs("image", 4.45, yoffset + 3.75, 1, 1, PNG.trash)
local creative_trash_only = core.settings:get_bool("i3_no_trash_in_survival", true)
if core.is_creative_enabled(name) or not creative_trash_only then if core.is_creative_enabled(name) or not creative_trash_only then
fs(fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75)) fs(fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75))
fs("image", 4.45, yoffset + 3.75, 1, 1, PNG.trash) fs("image", 4.45, yoffset + 3.75, 1, 1, PNG.trash)
@ -2020,6 +2023,8 @@ local function get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, a
local yextra = damage_enabled and 5.5 or 5 local yextra = damage_enabled and 5.5 or 5
for i, title in ipairs(SUBCAT) do for i, title in ipairs(SUBCAT) do
if title ~= "skins" or not use_skinsdb_tab then
local btn_name = fmt("btn_%s", title) local btn_name = fmt("btn_%s", title)
fs(fmt("style[btn_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", title, fs(fmt("style[btn_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", title,
@ -2028,6 +2033,8 @@ local function get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, a
fs("image_button", 0.25 + ((i - 1) * 1.18), yextra - 0.2, 0.5, 0.5, "", btn_name, "") fs("image_button", 0.25 + ((i - 1) * 1.18), yextra - 0.2, 0.5, 0.5, "", btn_name, "")
fs(fmt("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper))) fs(fmt("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper)))
end
end end
fs("box", 0, yextra + 0.45, ctn_len, 0.045, "#bababa50") fs("box", 0, yextra + 0.45, ctn_len, 0.045, "#bababa50")
@ -2059,19 +2066,24 @@ local function get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, a
end end
elseif data.subcat == 3 then elseif data.subcat == 3 then
if __skinsdb then if __skinsdb and not use_skinsdb_tab then
local _skins = skins.get_skinlist_for_player(name) local _skins = skins.get_skinlist_for_player(name)
local sks = {} local skin_name = skins.get_player_skin(player).name
local sks, id = {}, 1
for i, skin in ipairs(_skins) do
if skin.name == skin_name then
id = i
end
for _, skin in ipairs(_skins) do
sks[#sks + 1] = skin.name sks[#sks + 1] = skin.name
end end
sks = concat(sks, ","):gsub(";", "") sks = concat(sks, ","):gsub(";", "")
fs("label", 0, yextra + 0.85, fmt("%s:", ES"Select a skin")) fs("label", 0, yextra + 0.85, fmt("%s:", ES"Select a skin"))
fs(fmt("dropdown[0,%f;4,0.6;skins;%s;%u;true]", yextra + 1.1, sks, data.skin_id or 1)) fs(fmt("dropdown[0,%f;4,0.6;skins;%s;%u;true]", yextra + 1.1, sks, id))
else elseif not use_skinsdb_tab then
not_installed("skinsdb") not_installed("skinsdb")
end end
@ -2138,18 +2150,26 @@ local function get_tabs_fs(player, data, fs, full_height)
end end
local function get_debug_grid(data, fs, full_height) local function get_debug_grid(data, fs, full_height)
local spacing = 0.2 fs("style_type[label;font_size=8;noclip=true]")
local spacing, i = 0.2, 1
for x = 0, data.inv_width + 8, spacing do for x = 0, data.inv_width + 8, spacing do
fs("box", x, 0, 0.01, full_height, "#ff0") fs("box", x, 0, 0.01, full_height, "#ff0")
fs("label", x, full_height + 0.1, tostring(i))
i = i + 1
end end
i = 61
for y = 0, full_height, spacing do for y = 0, full_height, spacing do
fs("box", 0, y, data.inv_width + 8, 0.01, "#ff0") fs("box", 0, y, data.inv_width + 8, 0.01, "#ff0")
fs("label", -0.15, y, tostring(i))
i = i - 1
end end
fs("box", data.inv_width / 2, 0, 0.01, full_height, "#f00") fs("box", data.inv_width / 2, 0, 0.01, full_height, "#f00")
fs("box", 0, full_height / 2, data.inv_width, 0.01, "#f00") fs("box", 0, full_height / 2, data.inv_width, 0.01, "#f00")
fs("style_type[label;font_size=16]")
end end
local function make_fs(player, data) local function make_fs(player, data)
@ -2309,20 +2329,21 @@ local function init_data(player, info)
end end
local function reset_data(data) local function reset_data(data)
data.filter = "" data.filter = ""
data.expand = "" data.expand = ""
data.pagenum = 1 data.pagenum = 1
data.rnum = 1 data.rnum = 1
data.unum = 1 data.unum = 1
data.scrbar_rcp = 1 data.scrbar_rcp = 1
data.scrbar_usg = 1 data.scrbar_usg = 1
data.query_item = nil data.query_item = nil
data.recipes = nil data.recipes = nil
data.usages = nil data.usages = nil
data.export_rcp = nil data.export_rcp = nil
data.export_usg = nil data.export_usg = nil
data.alt_items = nil data.alt_items = nil
data.items = data.items_raw data.confirm_trash = nil
data.items = data.items_raw
if data.current_itab > 1 then if data.current_itab > 1 then
sort_by_category(data) sort_by_category(data)
@ -2524,12 +2545,12 @@ local function get_inventory_fs(player, data, fs)
fs("scroll_container_end[]") fs("scroll_container_end[]")
local btn = { local btn = {
--{"trash", ES"Trash all items"}, --{"trash", ES"Clear inventory"},
{"sort_az", ES"Sort items (A-Z)"}, {"sort_az", ES"Sort items (A-Z)"},
{"sort_za", ES"Sort items (Z-A)"}, {"sort_za", ES"Sort items (Z-A)"},
{"compress", ES"Compress items"}, {"compress", ES"Compress items"},
} }
if core.is_creative_enabled(name) then table.insert(btn, 1, {"trash", ES"Trash all items"}) end if core.is_creative_enabled(name) then table.insert(btn, 1, {"trash", ES"Clear inventory"}) end
for i, v in ipairs(btn) do for i, v in ipairs(btn) do
local btn_name, tooltip = unpack(v) local btn_name, tooltip = unpack(v)
@ -2540,6 +2561,18 @@ local function get_inventory_fs(player, data, fs)
fs("image_button", i + 3.447 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "") fs("image_button", i + 3.447 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
fs(fmt("tooltip[%s;%s]", btn_name, tooltip)) fs(fmt("tooltip[%s;%s]", btn_name, tooltip))
end 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
end end
i3.new_tab { i3.new_tab {
@ -2551,10 +2584,10 @@ i3.new_tab {
local name = player:get_player_name() local name = player:get_player_name()
local sb_inv = fields.scrbar_inv local sb_inv = fields.scrbar_inv
if fields.skins and data.skin_id ~= tonum(fields.skins) then if fields.skins then
data.skin_id = tonum(fields.skins) local id = tonum(fields.skins)
local _skins = skins.get_skinlist_for_player(name) local _skins = skins.get_skinlist_for_player(name)
skins.set_player_skin(player, _skins[data.skin_id]) skins.set_player_skin(player, _skins[id])
end end
for field in pairs(fields) do for field in pairs(fields) do
@ -2611,9 +2644,16 @@ i3.new_tab {
end end
if fields.trash then if fields.trash then
local inv = player:get_inventory() data.confirm_trash = true
inv:set_list("main", {})
inv:set_list("craft", {}) 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 elseif fields.compress then
compress_items(player) compress_items(player)
@ -2900,18 +2940,12 @@ end
core.register_on_mods_loaded(function() core.register_on_mods_loaded(function()
get_init_items() get_init_items()
__sfinv = rawget(_G, "sfinv") if rawget(_G, "sfinv") then
if __sfinv then
old_sfinv_fn = sfinv.set_player_inventory_formspec
function sfinv.set_player_inventory_formspec() return end function sfinv.set_player_inventory_formspec() return end
sfinv.enabled = false sfinv.enabled = false
end end
__unified_inventory = rawget(_G, "unified_inventory") if rawget(_G, "unified_inventory") then
if __unified_inventory then
old_unified_inventory_fn = unified_inventory.set_inventory_formspec
function unified_inventory.set_inventory_formspec() return end function unified_inventory.set_inventory_formspec() return end
end end
end) end)
@ -2991,21 +3025,7 @@ core.register_on_joinplayer(function(player)
local info = core.get_player_information and core.get_player_information(name) local info = core.get_player_information and core.get_player_information(name)
if not info or get_formspec_version(info) < MIN_FORMSPEC_VERSION then if not info or get_formspec_version(info) < MIN_FORMSPEC_VERSION then
if __sfinv then
sfinv.set_player_inventory_formspec = old_sfinv_fn
sfinv.enabled = true
end
if __unified_inventory then
unified_inventory.set_inventory_formspec = old_unified_inventory_fn
if __sfinv then
sfinv.enabled = false
end
end
pdata[name] = nil pdata[name] = nil
return outdated(name) return outdated(name)
end end
@ -3036,7 +3056,6 @@ end)
local META_SAVES = { local META_SAVES = {
bag_size = true, bag_size = true,
waypoints = true, waypoints = true,
skin_id = true,
inv_items = true, inv_items = true,
known_recipes = true, known_recipes = true,
} }
@ -3074,11 +3093,14 @@ end
after(SAVE_INTERVAL, routine) after(SAVE_INTERVAL, routine)
core.register_on_player_receive_fields(function(player, formname, fields) core.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then local name = player:get_player_name()
if formname == "i3_outdated" then
return false, core.kick_player(name, "Come back when your client is up-to-date.")
elseif formname ~= "" then
return false return false
end end
local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
if not data then return end if not data then return end
@ -3286,6 +3308,7 @@ if progressive_mode then
local player = players[i] local player = players[i]
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
if not data then return end
local inv_items = get_inv_items(player) local inv_items = get_inv_items(player)
local diff = array_diff(inv_items, data.inv_items) local diff = array_diff(inv_items, data.inv_items)
@ -3321,7 +3344,7 @@ if progressive_mode then
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
if data.show_hud ~= nil and singleplayer then if data and data.show_hud ~= nil and singleplayer then
show_hud_success(player, data) show_hud_success(player, data)
end end
end end
@ -3362,6 +3385,7 @@ if progressive_mode then
core.register_on_joinplayer(function(player) core.register_on_joinplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
if not data then return end
-- remove recipe filter to suppress progressive_mode in creative -- remove recipe filter to suppress progressive_mode in creative
-- on player join -- on player join
@ -3413,3 +3437,7 @@ end
--dofile(modpath .. "/tests/test_tabs.lua") --dofile(modpath .. "/tests/test_tabs.lua")
--dofile(modpath .. "/tests/test_custom_recipes.lua") --dofile(modpath .. "/tests/test_custom_recipes.lua")
if __skinsdb and use_skinsdb_tab then
dofile(modpath .. "/i3_mods_tabs.lua")
end

View File

@ -1,8 +1,15 @@
# The progressive mode shows recipes you can craft from items you ever had in your inventory. # The progressive mode shows recipes you can craft from items you ever had in your inventory.
i3_progressive_mode (Learn crafting recipes progressively) bool false i3_progressive_mode (Learn crafting recipes progressively) bool true
# Regroup the items of the same type in the item list. # Regroup the items of the same type in the item list.
i3_item_compression (Regroup items of the same type) bool true i3_item_compression (Regroup items of the same type) bool true
# ------------ NEW SETTINGS ------------ # ------------ NEW SETTINGS ------------
# not in original i3 available
# Show trash only in creative mode, or with creative privileges
i3_no_trash_in_survival (Trash is available only in creative) bool true i3_no_trash_in_survival (Trash is available only in creative) bool true
# For skin choice use tab instead of inventory dropdown only
i3_skinsdb_tab (Use tab for skins) bool true

View File

@ -0,0 +1,7 @@
Copyright 2019 - 2021 Lars Mueller alias LMD or appguru(eu)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,5 +1,6 @@
-- Localize globals -- Localize globals
local assert, math = assert, math local assert, math_huge, math_frexp, math_floor
= assert, math.huge, math.frexp, math.floor
-- Set environment -- Set environment
local _ENV = {} local _ENV = {}
@ -30,7 +31,7 @@ function read_float(read_byte, double)
mantissa = (mantissa + byte_2) / 0x80 mantissa = (mantissa + byte_2) / 0x80
if exponent == 0xFF then if exponent == 0xFF then
if mantissa == 0 then if mantissa == 0 then
return sign * math.huge return sign * math_huge
end end
-- Differentiating quiet and signalling nan is not possible in Lua, hence we don't have to do it -- Differentiating quiet and signalling nan is not possible in Lua, hence we don't have to do it
-- HACK ((0/0)^1) yields nan, 0/0 yields -nan -- HACK ((0/0)^1) yields nan, 0/0 yields -nan
@ -67,7 +68,7 @@ end
function write_uint(write_byte, uint, bytes) function write_uint(write_byte, uint, bytes)
for _ = 1, bytes do for _ = 1, bytes do
write_byte(uint % 0x100) write_byte(uint % 0x100)
uint = math.floor(uint / 0x100) uint = math_floor(uint / 0x100)
end end
assert(uint == 0) assert(uint == 0)
end end
@ -80,16 +81,16 @@ function write_float(write_byte, number, on_write, double)
number = -number number = -number
sign = 0x80 sign = 0x80
end end
local mantissa, exponent = math.frexp(number) local mantissa, exponent = math_frexp(number)
exponent = exponent + 127 exponent = exponent + 127
if exponent > 1 then if exponent > 1 then
-- TODO ensure this deals properly with subnormal numbers -- TODO ensure this deals properly with subnormal numbers
mantissa = mantissa * 2 - 1 mantissa = mantissa * 2 - 1
exponent = exponent - 1 exponent = exponent - 1
end end
local sign_byte = sign + math.floor(exponent / 2) local sign_byte = sign + math_floor(exponent / 2)
mantissa = mantissa * 0x80 mantissa = mantissa * 0x80
local exponent_byte = (exponent % 2) * 0x80 + math.floor(mantissa) local exponent_byte = (exponent % 2) * 0x80 + math_floor(mantissa)
mantissa = mantissa % 1 mantissa = mantissa % 1
local mantissa_bytes = {} local mantissa_bytes = {}
-- TODO ensure this check is proper -- TODO ensure this check is proper
@ -102,7 +103,7 @@ function write_float(write_byte, number, on_write, double)
local len = double and 6 or 2 local len = double and 6 or 2
for index = len, 1, -1 do for index = len, 1, -1 do
mantissa = mantissa * 0x100 mantissa = mantissa * 0x100
mantissa_bytes[index] = math.floor(mantissa) mantissa_bytes[index] = math_floor(mantissa)
mantissa = mantissa % 1 mantissa = mantissa % 1
end end
assert(mantissa == 0) assert(mantissa == 0)

View File

@ -1,5 +1,6 @@
-- Localize globals -- Localize globals
local assert, error, ipairs, math, modlib, next, pairs, setmetatable, string, table, type, unpack = assert, error, ipairs, math, modlib, next, pairs, setmetatable, string, table, type, unpack local assert, error, ipairs, math_floor, math_huge, modlib, next, pairs, setmetatable, string, table_insert, type, unpack
= assert, error, ipairs, math.floor, math.huge, modlib, next, pairs, setmetatable, string, table.insert, type, unpack
-- Set environment -- Set environment
local _ENV = {} local _ENV = {}
@ -61,8 +62,8 @@ local constants = {
[0] = "\2", [0] = "\2",
-- not possible as table entry as Lua doesn't allow +/-nan as table key -- not possible as table entry as Lua doesn't allow +/-nan as table key
-- [0/0] = "\3", -- [0/0] = "\3",
[math.huge] = "\4", [math_huge] = "\4",
[-math.huge] = "\5", [-math_huge] = "\5",
[""] = "\20" [""] = "\20"
} }
@ -297,18 +298,18 @@ function read(self, stream)
end end
if type <= type_ranges.string then if type <= type_ranges.string then
local string = stream_read(uint(type - type_ranges.number)) local string = stream_read(uint(type - type_ranges.number))
table.insert(references, string) table_insert(references, string)
return string return string
end end
if type <= type_ranges.table then if type <= type_ranges.table then
type = type - type_ranges.string - 1 type = type - type_ranges.string - 1
local tab = {} local tab = {}
table.insert(references, tab) table_insert(references, tab)
if type == 0 then if type == 0 then
return tab return tab
end end
local list_len = uint(type % 5) local list_len = uint(type % 5)
local kv_len = uint(math.floor(type / 5)) local kv_len = uint(math_floor(type / 5))
for index = 1, list_len do for index = 1, list_len do
tab[index] = _read(stream_read(1)) tab[index] = _read(stream_read(1))
end end

View File

@ -50,6 +50,7 @@ for _, file in pairs{
"ranked_set", "ranked_set",
"binary", "binary",
"b3d", "b3d",
"luon",
"bluon", "bluon",
"persistence", "persistence",
"debug" "debug"

View File

@ -0,0 +1,165 @@
local assert, next, pairs, pcall, error, type, table_insert, table_concat, string_format, string_match, setfenv, math_huge, loadfile, loadstring
= assert, next, pairs, pcall, error, type, table.insert, table.concat, string.format, string.match, setfenv, math.huge, loadfile, loadstring
local count_values = modlib.table.count_values
-- Build a table with the succeeding character from A-Z
local succ = {}
for char = ("A"):byte(), ("Z"):byte() - 1 do
succ[string.char(char)] = string.char(char + 1)
end
local function quote(string)
return string_format("%q", string)
end
local _ENV = {}
setfenv(1, _ENV)
function write(object, write)
local reference = {"A"}
local function increment_reference(place)
if not reference[place] then
reference[place] = "B"
elseif reference[place] == "Z" then
reference[place] = "A"
return increment_reference(place + 1)
else
reference[place] = succ[reference[place]]
end
end
local references = {}
local to_fill = {}
for value, count in pairs(count_values(object)) do
local type_ = type(value)
if count >= 2 and ((type_ == "string" and #reference + 2 >= #value) or type_ == "table") then
local ref = table_concat(reference)
write(ref)
write"="
write(type_ == "table" and "{}" or quote(value))
write";"
references[value] = ref
if type_ == "table" then
to_fill[value] = true
end
increment_reference(1)
end
end
local function is_short_key(key)
return not references[key] and type(key) == "string" and string_match(key, "^[%a_][%a%d_]*$")
end
local function dump(value)
-- Primitive types
if value == nil then
return write"nil"
end
if value == true then
return write"true"
end
if value == false then
return write"false"
end
local type_ = type(value)
if type_ == "number" then
return write(string_format("%.17g", value))
end
-- Reference types: table and string
local ref = references[value]
if ref then
-- Referenced
if not to_fill[value] then
return write(ref)
end
-- Fill table
to_fill[value] = false
for k, v in pairs(value) do
write(ref)
if is_short_key(k) then
write"."
write(k)
else
write"["
dump(k)
write"]"
end
write"="
dump(v)
write";"
end
elseif type_ == "string" then
return write(quote(value))
elseif type_ == "table" then
local first = true
write"{"
local len = #value
for i = 1, len do
if not first then write";" end
dump(value[i])
first = false
end
for k, v in next, value do
if type(k) ~= "number" or k % 1 ~= 0 or k < 1 or k > len then
if not first then write";" end
if is_short_key(k) then
write(k)
else
write"["
dump(k)
write"]"
end
write"="
dump(v)
first = false
end
end
write"}"
else
error("unsupported type: " .. type_)
end
end
local fill_root = to_fill[object]
if fill_root then
-- Root table is circular, must return by named reference
dump(object)
write"return "
write(references[object])
else
-- Root table is not circular, can directly start writing
write"return "
dump(object)
end
end
function write_file(object, file)
return write(object, function(text)
file:write(text)
end)
end
function write_string(object)
local rope = {}
write(object, function(text)
table_insert(rope, text)
end)
return table_concat(rope)
end
function read(...)
local read = assert(...)
-- math.huge is serialized to inf, 0/0 is serialized to -nan
setfenv(read, {inf = math_huge, nan = 0/0})
local success, value_or_err = pcall(read)
if success then
return value_or_err
end
return nil, value_or_err
end
function read_file(path)
return read(loadfile(path))
end
function read_string(string)
return read(loadstring(string))
end
return _ENV

View File

@ -185,7 +185,7 @@ function colorspec.from_string(string)
if number then if number then
return colorspec.from_number(number * 0x100 + alpha) return colorspec.from_number(number * 0x100 + alpha)
end end
local hex_text = string:match(hex) local hex_text = string:match("^" .. hex .. "$")
local len, num = hex_text:len(), tonumber(hex_text, 16) local len, num = hex_text:len(), tonumber(hex_text, 16)
if len == 8 then if len == 8 then
return colorspec.from_number(num) return colorspec.from_number(num)

View File

@ -106,43 +106,39 @@ function lua_log_file:_dump(value, is_key)
end end
reference = self.reference_count + 1 reference = self.reference_count + 1
local key = "R[" .. reference .."]" local key = "R[" .. reference .."]"
local formatted
local function create_reference() local function create_reference()
self.reference_count = reference self.reference_count = reference
self.references[value] = reference self.references[value] = reference
end end
if _type == "string" then if _type == "string" then
local reference_strings = self.reference_strings local reference_strings = self.reference_strings
if is_key and ((not reference_strings) or value:len() <= key:len()) and value:match"[%a_][%a%d_]*" then if is_key and ((not reference_strings) or value:len() <= key:len()) and value:match"^[%a_][%a%d_]*$" then
-- Short key -- Short key
return value, true return value, true
end end
formatted = ("%q"):format(value) local formatted = ("%q"):format(value)
if (not reference_strings) or formatted:len() <= key:len() then if (not reference_strings) or formatted:len() <= key:len() then
-- Short string -- Short string
return formatted return formatted
end end
-- Use reference -- Use reference
create_reference() create_reference()
self:log(key .. "=" .. formatted)
elseif _type == "table" then elseif _type == "table" then
-- Tables always need a reference before they are traversed to prevent infinite recursion -- Tables always need a reference before they are traversed to prevent infinite recursion
create_reference() create_reference()
local entries = {} -- TODO traverse tables to determine whether this is actually needed
for _, value in ipairs(value) do self:log(key .. "={}")
table.insert(entries, self:_dump(value))
end
local tablelen = #value local tablelen = #value
for key, value in pairs(value) do for k, v in pairs(value) do
if type(key) ~= "number" or key % 1 ~= 0 or key < 1 or key > tablelen then if type(k) ~= "number" or k % 1 ~= 0 or k < 1 or k > tablelen then
local dumped, short = self:_dump(key, true) local dumped, short = self:_dump(k, true)
table.insert(entries, (short and dumped or ("[" .. dumped .. "]")) .. "=" .. self:_dump(value)) self:log(key .. (short and ("." .. dumped) or ("[" .. dumped .. "]")) .. "=" .. self:_dump(v))
end end
end end
formatted = "{" .. table.concat(entries, ";") .. "}"
else else
error("unsupported type: " .. _type) error("unsupported type: " .. _type)
end end
self:log(key .. "=" .. formatted)
return key return key
end end

View File

@ -337,6 +337,27 @@ function deep_foreach_any(table, func)
visit(table) visit(table)
end end
-- Recursively counts occurences of values in a table
-- Also counts primitive values like boolean and number
-- Does not count NaN, because that doesn't work as a table index
function count_values(value)
local counts = {}
local function count_values_(value)
-- Ignore NaN
if value ~= value then return end
local count = counts[value]
counts[value] = (count or 0) + 1
if not count and type(value) == "table" then
for k, v in pairs(value) do
count_values_(k)
count_values_(v)
end
end
end
count_values_(value)
return counts
end
function foreach_value(table, func) function foreach_value(table, func)
for _, v in pairs(table) do for _, v in pairs(table) do
func(v) func(v)

View File

@ -166,10 +166,41 @@ for _ = 1, 1000 do
assert(distance == min_distance) assert(distance == min_distance)
end end
local function serializer_test(assert_preserves)
-- TODO nan
for _, constant in pairs{true, false, huge, -huge} do
assert_preserves(constant)
end
-- Strings
for i = 1, 1000 do
assert_preserves(_G.table.concat(table.repetition(_G.string.char(i % 256), i)))
end
-- Numbers
for _ = 1, 1000 do
local int = random(-2^50, 2^50)
assert(int % 1 == 0)
assert_preserves(int)
assert_preserves((random() - 0.5) * 2^random(-20, 20))
end
-- Simple tables
assert_preserves{hello = "world", welt = "hallo"}
assert_preserves{"hello", "hello", "hello"}
local circular = {}
circular[circular] = circular
circular[1] = circular
assert_preserves(circular)
local mixed = {1, 2, 3}
mixed[mixed] = mixed
mixed.vec = {x = 1, y = 2, z = 3}
mixed.vec2 = modlib.table.copy(mixed.vec)
mixed.blah = "blah"
assert_preserves(mixed)
end
-- bluon -- bluon
do do
local bluon = bluon local bluon = bluon
local function assert_preserves(object) serializer_test(function(object)
local rope = table.rope{} local rope = table.rope{}
local written, read, input local written, read, input
local _, err = pcall(function() local _, err = pcall(function()
@ -186,25 +217,17 @@ do
written = written and text.hexdump(written), written = written and text.hexdump(written),
err = err err = err
}) })
end end)
for _, constant in pairs{true, false, huge, -huge} do end
assert_preserves(constant)
end -- luon
for i = 1, 1000 do do
assert_preserves(_G.table.concat(table.repetition(_G.string.char(i % 256), i))) serializer_test(function(object)
end local serialized = luon.write_string(object)
for _ = 1, 1000 do assert(table.equals_references(object, luon.read_string(serialized)), serialized)
local int = random(-2^50, 2^50) end)
assert(int % 1 == 0) local nan = luon.read_string(luon.write_string(0/0))
assert_preserves(int) assert(nan ~= nan)
assert_preserves((random() - 0.5) * 2^random(-20, 20))
end
assert_preserves{hello = "world", welt = "hallo"}
assert_preserves{"hello", "hello", "hello"}
local a = {}
a[a] = a
a[1] = a
assert_preserves(a)
end end
if not _G.minetest then return end if not _G.minetest then return end
@ -230,9 +253,16 @@ local function test_logfile(reference_strings)
logfile.root = {a_longer_string = "test"} logfile.root = {a_longer_string = "test"}
logfile:rewrite() logfile:rewrite()
logfile:set_root({a = 1}, {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge}) logfile:set_root({a = 1}, {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge})
local circular = {}
circular[circular] = circular
logfile:set_root(circular, circular)
logfile:close() logfile:close()
logfile:init() logfile:init()
assert(table.equals(logfile.root, {a_longer_string = "test", [{a = 1}] = {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge}})) assert(table.equals_references(logfile.root, {
a_longer_string = "test",
[{a = 1}] = {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge},
[circular] = circular,
}))
if not reference_strings then if not reference_strings then
for key in pairs(logfile.references) do for key in pairs(logfile.references) do
assert(type(key) ~= "string") assert(type(key) ~= "string")