This commit is contained in:
Jean-Patrick Guerrero 2021-10-25 05:31:58 +02:00
parent 9e50f58f5b
commit 6d2682b8d9
9 changed files with 285 additions and 276 deletions

View File

@ -23,6 +23,7 @@ globals = {
}
exclude_files = {
"tests/test_compression.lua",
"tests/test_custom_recipes.lua",
"tests/test_tabs.lua",
}

8
API.md
View File

@ -196,8 +196,8 @@ They can be used like so: `<optional_name> +<filter name>=<value1>,<value2>,<...
Example usages:
- `+groups=cracky,crumbly`: search for groups `cracky` and `crumbly` in all items.
- `wood +groups=flammable`: search for group `flammable` amongst items which contain
- `+groups=cracky,crumbly` -> search for groups `cracky` and `crumbly` in all items.
- `wood +groups=flammable` -> search for group `flammable` amongst items which contain
`wood` in their names.
Notes:
@ -252,9 +252,9 @@ i3.compress("default:diamondblock", {
```
#### `i3.get_compress_groups()`
#### `i3.compress_groups`
Returns a map of all compressed item groups, indexed by stereotypes.
A map of all compressed item groups, indexed by stereotypes.
---

View File

@ -1,17 +1,10 @@
local make_fs = i3.files.gui()
local S, fmt, reg_items = i3.need("S", "fmt", "reg_items")
local gmatch, match, split = i3.need("gmatch", "match", "split")
local S, err, fmt, reg_items = i3.need("S", "err", "fmt", "reg_items")
local sort, concat, copy, insert, remove = i3.need("sort", "concat", "copy", "insert", "remove")
local true_str, is_str, is_table, clean_name = i3.need("true_str", "is_str", "is_table", "clean_name")
local function err(str)
return core.log("error", str)
end
local function is_func(x)
return type(x) == "function"
end
local true_str, true_table, is_str, is_func, is_table, clean_name =
i3.need("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name")
function i3.register_craft_type(name, def)
if not true_str(name) then
@ -47,7 +40,7 @@ function i3.register_craft(def)
return
end
if not is_table(def) or not next(def) then
if not true_table(def) then
return err "i3.register_craft: craft definition missing"
end
@ -180,7 +173,7 @@ end
local set_fs = i3.set_fs
function i3.new_tab(def)
if not is_table(def) or not next(def) then
if not true_table(def) then
return err "i3.new_tab: tab definition missing"
end
@ -242,7 +235,7 @@ function i3.set_tab(player, tabname)
end
function i3.override_tab(tabname, newdef)
if not is_table(newdef) or not next(newdef) then
if not true_table(newdef) then
return err "i3.override_tab: tab definition missing"
end
@ -290,7 +283,7 @@ function i3.compress(item, def)
return err "i3.compress: item name missing"
end
if not is_table(def) then
if not true_table(def) then
return err "i3.compress: replace definition missing"
end
@ -315,8 +308,4 @@ function i3.compress(item, def)
end
end
function i3.get_compress_groups()
return i3.compress_groups
end
return set_fs, i3.set_tab

View File

@ -1,9 +1,38 @@
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 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 =
core.registered_items, core.registered_nodes, core.registered_craftitems, core.registered_tools
local S = core.get_translator "i3"
local ES = function(...) return core.formspec_escape(S(...)) end
local function is_num(x)
return type(x) == "number"
end
local function is_str(x)
return type(x) == "string"
end
local function is_table(x)
return type(x) == "table"
end
local function is_func(x)
return type(x) == "function"
end
local function true_str(str)
return is_str(str) and str ~= ""
end
local function true_table(x)
return is_table(x) and next(x)
end
local function reset_compression(data)
data.alt_items = nil
data.expand = ""
@ -76,6 +105,14 @@ local function search(data)
data.items = filtered_list
end
local function table_replace(t, val, new)
for k, v in pairs(t) do
if v == val then
t[k] = new
end
end
end
local function table_merge(t1, t2, hash)
t1 = t1 or {}
t2 = t2 or {}
@ -96,6 +133,86 @@ local function table_merge(t1, t2, hash)
return t1
end
local function array_diff(t1, t2)
local hash = {}
for i = 1, #t1 do
local v = t1[i]
hash[v] = true
end
for i = 1, #t2 do
local v = t2[i]
hash[v] = nil
end
local diff, c = {}, 0
for i = 1, #t1 do
local v = t1[i]
if hash[v] then
c = c + 1
diff[c] = v
end
end
return diff
end
local function table_eq(T1, T2)
local avoid_loops = {}
local function recurse(t1, t2)
if type(t1) ~= type(t2) then return end
if not is_table(t1) then
return t1 == t2
end
if avoid_loops[t1] then
return avoid_loops[t1] == t2
end
avoid_loops[t1] = t2
local t2k, t2kv = {}, {}
for k in pairs(t2) do
if is_table(k) then
insert(t2kv, k)
end
t2k[k] = true
end
for k1, v1 in pairs(t1) do
local v2 = t2[k1]
if type(k1) == "table" then
local ok
for i = 1, #t2kv do
local tk = t2kv[i]
if table_eq(k1, tk) and recurse(v1, t2[tk]) then
remove(t2kv, i)
t2k[tk] = nil
ok = true
break
end
end
if not ok then return end
else
if v2 == nil then return end
t2k[k1] = nil
if not recurse(v1, v2) then return end
end
end
if next(t2k) then return end
return true
end
return recurse(T1, T2)
end
local function is_group(item)
return sub(item, 1, 6) == "group:"
end
@ -162,16 +279,25 @@ local function compressible(item, data)
return compression_active(data) and i3.compress_groups[item]
end
local function is_str(x)
return type(x) == "string"
local function clean_name(item)
if sub(item, 1, 1) == ":" or sub(item, 1, 1) == " " or sub(item, 1, 1) == "_" then
item = sub(item, 2)
end
return item
end
local function is_table(x)
return type(x) == "table"
local function msg(name, str)
return core.chat_send_player(name, fmt("[i3] %s", str))
end
local function true_str(str)
return is_str(str) and str ~= ""
local function err(str)
return core.log("error", str)
end
local function round(num, decimal)
local mul = 10 ^ decimal
return floor(num * mul + 0.5) / mul
end
local function is_fav(favs, query_item)
@ -216,118 +342,98 @@ local function sort_by_category(data)
data.items = new
end
local function clean_name(item)
if sub(item, 1, 1) == ":" or sub(item, 1, 1) == " " or sub(item, 1, 1) == "_" then
item = sub(item, 2)
end
return item
end
local function msg(name, str)
return core.chat_send_player(name, fmt("[i3] %s", str))
end
local function spawn_item(player, stack)
local dir = player:get_look_dir()
local ppos = player:get_pos()
ppos.y = ppos.y + 1.625
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
local S = core.get_translator "i3"
local ES = function(...) return core.formspec_escape(S(...)) end
return {
groups = {
-- Groups
is_group = is_group,
extract_groups = extract_groups,
item_has_groups = item_has_groups,
groups_to_items = groups_to_items,
},
compression = {
-- Compression
compressible = compressible,
compression_active = compression_active,
},
sorting = {
-- Sorting
search = search,
sort_by_category = sort_by_category,
apply_recipe_filters = apply_recipe_filters,
},
misc = {
-- Misc. functions
err = err,
msg = msg,
is_fav = is_fav,
is_str = is_str,
is_num = is_num,
is_func = is_func,
show_item = show_item,
spawn_item = spawn_item,
table_merge = table_merge,
},
true_str = true_str,
true_table = true_table,
clean_name = clean_name,
core = {
-- Core functions
clr = core.colorize,
ESC = core.formspec_escape,
check_privs = core.check_player_privs,
},
reg = {
-- Registered items
reg_items = core.registered_items,
reg_nodes = core.registered_nodes,
reg_craftitems = core.registered_craftitems,
reg_tools = core.registered_tools,
reg_entities = core.registered_entities,
reg_aliases = core.registered_aliases,
},
reg_entities = core.registered_entities,
reg_craftitems = core.registered_craftitems,
i18n = {
-- i18n
S = S,
ES = ES,
translate = core.get_translated_string,
},
string = {
fmt = string.format,
find = string.find,
gmatch = string.gmatch,
match = string.match,
-- String
sub = string.sub,
split = string.split,
find = string.find,
fmt = string.format,
upper = string.upper,
lower = string.lower,
split = string.split,
match = string.match,
gmatch = string.gmatch,
is_str = is_str,
true_str = true_str,
clean_name = clean_name,
},
table = {
-- Table
maxn = table.maxn,
sort = table.sort,
concat = table.concat,
copy = table.copy,
concat = table.concat,
insert = table.insert,
remove = table.remove,
indexof = table.indexof,
is_table = is_table,
},
table_eq = table_eq,
table_merge = table_merge,
table_replace = table_replace,
array_diff = array_diff,
math = {
-- Math
round = round,
min = math.min,
max = math.max,
floor = math.floor,
ceil = math.ceil,
floor = math.floor,
random = math.random,
},
vec = {
-- Vectors
vec_new = vector.new,
vec_add = vector.add,
vec_mul = vector.multiply,
vec_eq = vector.equals,
vec_round = vector.round,
},
vec_eq = vector.equals,
vec_mul = vector.multiply,
}

View File

@ -3,25 +3,17 @@ local damage_enabled = core.settings:get_bool "enable_damage"
local model_aliases = i3.files.model_alias()
local PNG, styles, fs_elements = i3.files.styles()
local clr, ESC = i3.need("clr", "ESC")
local S, ES, translate = i3.need("S", "ES", "translate")
local min, max, floor, ceil = i3.need("min", "max", "floor", "ceil")
local clr, ESC, check_privs = i3.need("clr", "ESC", "check_privs")
local min, max, floor, ceil, round = i3.need("min", "max", "floor", "ceil", "round")
local sprintf, find, match, sub, upper = i3.need("fmt", "find", "match", "sub", "upper")
local reg_items, reg_tools, reg_entities = i3.need("reg_items", "reg_tools", "reg_entities")
local maxn, sort, concat, copy, insert, remove = i3.need("maxn", "sort", "concat", "copy", "insert", "remove")
local true_str, is_fav, is_num = i3.need("true_str", "is_fav", "is_num")
local is_group, extract_groups, item_has_groups = i3.need("is_group", "extract_groups", "item_has_groups")
local groups_to_items, compression_active, compressible, true_str, is_fav =
i3.need("groups_to_items", "compression_active", "compressible", "true_str", "is_fav")
local function is_num(x)
return type(x) == "number"
end
local function round(num, decimal)
local mul = 10 ^ decimal
return floor(num * mul + 0.5) / mul
end
local groups_to_items, compression_active, compressible =
i3.need("groups_to_items", "compression_active", "compressible")
local function fmt(elem, ...)
if not fs_elements[elem] then
@ -290,7 +282,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
fs("image_button", ctn_len - 1.5, yi, icon_size, icon_size, "", vsb, "")
fs(fmt("tooltip[%s;%s]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint"))
if core.check_player_privs(player, {teleport = true}) then
if check_privs(player, {teleport = true}) then
local tp = fmt("waypoint_%u_teleport", i)
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",

View File

@ -8,10 +8,13 @@ local fmt, find, match, sub, lower = i3.need("fmt", "find", "match", "sub", "low
local vec_new, vec_mul, vec_eq, vec_round = i3.need("vec_new", "vec_mul", "vec_eq", "vec_round")
local sort, copy, insert, remove, indexof = i3.need("sort", "copy", "insert", "remove", "indexof")
local is_group, extract_groups, groups_to_items = i3.need("is_group", "extract_groups", "groups_to_items")
local search, sort_by_category, apply_recipe_filters = i3.need("search", "sort_by_category", "apply_recipe_filters")
local msg, is_str, is_fav, show_item, spawn_item, clean_name, compressible =
i3.need("msg", "is_str", "is_fav", "show_item", "spawn_item", "clean_name", "compressible")
local msg, is_str, is_fav = i3.need("msg", "is_str", "is_fav")
local is_group, extract_groups, groups_to_items =
i3.need("is_group", "extract_groups", "groups_to_items")
local search, sort_by_category, apply_recipe_filters =
i3.need("search", "sort_by_category", "apply_recipe_filters")
local show_item, spawn_item, clean_name, compressible, check_privs =
i3.need("show_item", "spawn_item", "clean_name", "compressible", "check_privs")
local old_is_creative_enabled = core.is_creative_enabled
@ -20,7 +23,7 @@ function core.is_creative_enabled(name)
return old_is_creative_enabled(name)
end
return core.check_player_privs(name, {creative = true}) or old_is_creative_enabled(name)
return check_privs(name, {creative = true}) or old_is_creative_enabled(name)
end
local function reset_data(data)

View File

@ -1,38 +1,13 @@
local set_fs = i3.files.api()
local singleplayer = core.is_singleplayer()
local fmt, search, table_merge, is_group, extract_groups, item_has_groups, apply_recipe_filters =
i3.need("fmt", "search", "table_merge", "is_group", "extract_groups", "item_has_groups", "apply_recipe_filters")
local fmt, search, table_merge, array_diff = i3.need("fmt", "search", "table_merge", "array_diff")
local is_group, extract_groups, item_has_groups, apply_recipe_filters =
i3.need("is_group", "extract_groups", "item_has_groups", "apply_recipe_filters")
local POLL_FREQ = 0.25
local HUD_TIMER_MAX = 1.5
local function array_diff(t1, t2)
local hash = {}
for i = 1, #t1 do
local v = t1[i]
hash[v] = true
end
for i = 1, #t2 do
local v = t2[i]
hash[v] = nil
end
local diff, c = {}, 0
for i = 1, #t1 do
local v = t1[i]
if hash[v] then
c = c + 1
diff[c] = v
end
end
return diff
end
local function get_filtered_items(player, data)
local items, known, c = {}, 0, 0

View File

@ -2,73 +2,12 @@ local replacements = {fuel = {}}
local fmt, match = i3.need("fmt", "match")
local reg_items, reg_aliases = i3.need("reg_items", "reg_aliases")
local maxn, copy, insert, remove = i3.need("maxn", "copy", "insert", "remove")
local maxn, copy, insert = i3.need("maxn", "copy", "insert")
local true_str, is_table, show_item, table_merge = i3.need("true_str", "is_table", "show_item", "table_merge")
local is_group, extract_groups, item_has_groups, groups_to_items =
i3.need("is_group", "extract_groups", "item_has_groups", "groups_to_items")
local function table_replace(t, val, new)
for k, v in pairs(t) do
if v == val then
t[k] = new
end
end
end
local function table_eq(T1, T2)
local avoid_loops = {}
local function recurse(t1, t2)
if type(t1) ~= type(t2) then return end
if not is_table(t1) then
return t1 == t2
end
if avoid_loops[t1] then
return avoid_loops[t1] == t2
end
avoid_loops[t1] = t2
local t2k, t2kv = {}, {}
for k in pairs(t2) do
if is_table(k) then
insert(t2kv, k)
end
t2k[k] = true
end
for k1, v1 in pairs(t1) do
local v2 = t2[k1]
if type(k1) == "table" then
local ok
for i = 1, #t2kv do
local tk = t2kv[i]
if table_eq(k1, tk) and recurse(v1, t2[tk]) then
remove(t2kv, i)
t2k[tk] = nil
ok = true
break
end
end
if not ok then return end
else
if v2 == nil then return end
t2k[k1] = nil
if not recurse(v1, v2) then return end
end
end
if next(t2k) then return end
return true
end
return recurse(T1, T2)
end
local true_str, is_table, show_item, table_merge, table_replace, table_eq =
i3.need("true_str", "is_table", "show_item", "table_merge", "table_replace", "table_eq")
local function get_burntime(item)
return core.get_craft_result{method = "fuel", items = {item}}.time

View File

@ -71,15 +71,13 @@ function i3.need(...)
local t = {}
for _, var in ipairs {...} do
for _, cat in pairs(common) do
for name, func in pairs(cat) do
for name, func in pairs(common) do
if var == name then
t[#t + 1] = func
break
end
end
end
end
return unpack(t)
end
@ -114,27 +112,6 @@ local function outdated(name)
core.show_formspec(name, "i3_outdated", fs)
end
local function init_data(player, info)
local name = player:get_player_name()
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
core.after(0, set_fs, player)
end
if rawget(_G, "armor") then
i3.modules.armor = true
armor:register_on_update(set_fs)
@ -201,9 +178,7 @@ local function get_init_items()
end
end
core.register_on_mods_loaded(function()
get_init_items()
local function disable_inventories()
if rawget(_G, "sfinv") then
function sfinv.set_player_inventory_formspec() return end
sfinv.enabled = false
@ -212,7 +187,28 @@ core.register_on_mods_loaded(function()
if rawget(_G, "unified_inventory") then
function unified_inventory.set_inventory_formspec() return end
end
end)
end
local function init_data(player, info)
local name = player:get_player_name()
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
core.after(0, set_fs, player)
end
local function init_waypoints(player)
local name = player:get_player_name()
@ -235,24 +231,12 @@ local function init_waypoints(player)
end
end
core.register_on_joinplayer(function(player)
local name = player:get_player_name()
local info = core.get_player_information and core.get_player_information(name)
if not info or get_formspec_version(info) < i3.MIN_FORMSPEC_VERSION then
i3.data[name] = nil
return outdated(name)
end
init_data(player, info)
init_backpack(player)
init_waypoints(player)
local function init_hudbar(player)
core.after(0, function()
player:hud_set_hotbar_itemcount(i3.HOTBAR_LEN)
player:hud_set_hotbar_image("i3_hotbar.png")
end)
end)
end
local function save_data(player_name)
local _data = copy(i3.data)
@ -272,6 +256,26 @@ local function save_data(player_name)
storage:set_string("data", slz(_data))
end
core.register_on_mods_loaded(function()
get_init_items()
disable_inventories()
end)
core.register_on_joinplayer(function(player)
local name = player:get_player_name()
local info = core.get_player_information and core.get_player_information(name)
if not info or get_formspec_version(info) < i3.MIN_FORMSPEC_VERSION then
i3.data[name] = nil
return outdated(name)
end
init_data(player, info)
init_backpack(player)
init_waypoints(player)
init_hudbar(player)
end)
core.register_on_leaveplayer(function(player)
local name = player:get_player_name()
save_data(name)