diff --git a/mod_sources.txt b/mod_sources.txt index 47317e7..2e7537e 100644 --- a/mod_sources.txt +++ b/mod_sources.txt @@ -73,12 +73,12 @@ origin https://github.com/minetest-mods/dynamic_liquid (fetch) Mod: environment/dynamic_liquid origin https://notabug.org/tenplus1/farming (fetch) -* master e699423 [origin/master] add popcorn +* master a5ea92b [origin/master] fix cocoa drops Mod: flora/farming origin https://github.com/daretmavi/i3.git (fetch) upstream https://github.com/minetest-mods/i3.git (fetch) -* main 57784ba [origin/main] Better solution for turning off progresive mode in creative +* main 7bd3e5d [origin/main] New Variable i3_no_trash_in_survival Better bool reading from settings Mod: gui/i3 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 origin https://github.com/appgurueu/modlib (fetch) -* master 56ad946 [origin/master] Bump version +* master abced34 [origin/master] Deal with Lua log file memory leak Mod: lib_api/modlib origin git@github.com:runsy/rcbows.git (fetch) @@ -190,7 +190,7 @@ origin https://gitlab.com/4w/hunger_ng.git (fetch) Mod: player/hunger_ng origin https://github.com/minetest-mods/skinsdb.git (fetch) -* master c53158d [origin/master] Update to work with Unified Inventory v2 i.e. the formspec v4 rewrite Requires UI "version-2" tag or commit a7556c50 or later and and Minetest v5.4.0 or later +* master 716a9a3 [origin/master] fix get_string() on wrong variable Mod: player/skinsdb origin https://github.com/stujones11/wield3d.git (fetch) diff --git a/mods/flora/farming/crops/cocoa.lua b/mods/flora/farming/crops/cocoa.lua index 1fc7875..b424639 100644 --- a/mods/flora/farming/crops/cocoa.lua +++ b/mods/flora/farming/crops/cocoa.lua @@ -135,11 +135,6 @@ local def = { tiles = {"farming_cocoa_1.png"}, paramtype = "light", walkable = false, - drop = { - items = { - {items = {"farming:cocoa_beans 1"}, rarity = 2}, - } - }, selection_box = { type = "fixed", fixed = {-0.3, -0.5, -0.3, 0.3, 0.5, 0.3} diff --git a/mods/gui/i3/init.lua b/mods/gui/i3/init.lua index 4fcb4a0..da63de7 100644 --- a/mods/gui/i3/init.lua +++ b/mods/gui/i3/init.lua @@ -20,8 +20,8 @@ local PNG, styles, fs_elements = loadfile(modpath .. "/etc/styles.lua")() local compress_groups, compressed = loadfile(modpath .. "/etc/compress.lua")() local group_stereotypes, group_names = loadfile(modpath .. "/etc/groups.lua")() -local progressive_mode = core.settings:get_bool "i3_progressive_mode" -local item_compression = core.settings:get_bool "i3_item_compression" +local progressive_mode = core.settings:get_bool("i3_progressive_mode", false) +local item_compression = core.settings:get_bool("i3_item_compression", true) local damage_enabled = core.settings:get_bool "enable_damage" local __3darmor, __skinsdb, __awards @@ -2010,7 +2010,9 @@ local function get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, a fs(fmt("list[current_player;craftpreview;%f,%f;1,1;]", 4.45, yoffset + 2.6))--, -- 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) - if core.is_creative_enabled(name) then + + 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 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) end diff --git a/mods/gui/i3/settingtypes.txt b/mods/gui/i3/settingtypes.txt index 42bc83e..8d4766d 100644 --- a/mods/gui/i3/settingtypes.txt +++ b/mods/gui/i3/settingtypes.txt @@ -3,3 +3,6 @@ i3_progressive_mode (Learn crafting recipes progressively) bool false # Regroup the items of the same type in the item list. i3_item_compression (Regroup items of the same type) bool true + +# ------------ NEW SETTINGS ------------ +i3_no_trash_in_survival (Trash is available only in creative) bool true diff --git a/mods/lib_api/modlib/Readme.md b/mods/lib_api/modlib/Readme.md index 7f86bb9..f42268b 100644 --- a/mods/lib_api/modlib/Readme.md +++ b/mods/lib_api/modlib/Readme.md @@ -27,6 +27,15 @@ logfile:init() assert(table.equals(logfile.root, {[{a = 1}] = {b = 2, c = 3}})) ``` +Both strings and tables are stored in a reference table. Unused strings won't be garbage collected as Lua doesn't allow marking them as weak references. +This means that setting lots of temporary strings will waste memory until you call `:rewrite()` on the log file. An alternative is to set the third parameter, `reference_strings`, to `false` (default value is `true`): + +```lua +persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}, false) +``` + +This will prevent strings from being referenced, possibly bloating file size, but saving memory. + ### Bluon Binary Lua object notation. **Experimental.** Handling of subnormal numbers (very small floats) may be broken. diff --git a/mods/lib_api/modlib/func.lua b/mods/lib_api/modlib/func.lua index c1f1883..8a287e6 100644 --- a/mods/lib_api/modlib/func.lua +++ b/mods/lib_api/modlib/func.lua @@ -17,7 +17,12 @@ function curry_tail(func, ...) return function(...) return func(unpack(modlib.table.concat({...}, args))) end end -function call(...) +function curry_full(func, ...) + local args = { ... } + return function() return func(unpack(args)) end +end + +function args(...) local args = { ... } return function(func) return func(unpack(args)) end end @@ -29,6 +34,31 @@ function values(...) return function() return unpack(args) end end +-- Equivalent to `for x, y, z in iterator(...) do callback(x, y, z) end` +function iterate(callback, iterator, ...) + local function _iterate(iterable, state, ...) + local function loop(...) + if ... == nil then return end + callback(...) + return loop(iterable(state, ...)) + end + return loop(iterable(state, ...)) + end + return _iterate(iterator(...)) +end + +-- Does not use select magic, stops at the first nil value +function aggregate(binary_func, total, ...) + if total == nil then return end + local function _aggregate(value, ...) + if value == nil then return end + total = binary_func(total, value) + return _aggregate(...) + end + _aggregate(...) + return total +end + function override_chain(func, override) return function(...) func(...) diff --git a/mods/lib_api/modlib/persistence.lua b/mods/lib_api/modlib/persistence.lua index b6a39eb..525e469 100644 --- a/mods/lib_api/modlib/persistence.lua +++ b/mods/lib_api/modlib/persistence.lua @@ -5,18 +5,31 @@ local assert, error, io, ipairs, loadfile, math, minetest, modlib, pairs, setfen local _ENV = {} setfenv(1, _ENV) -lua_log_file = {} +lua_log_file = { + -- default value + reference_strings = true +} local files = {} local metatable = {__index = lua_log_file} -function lua_log_file.new(file_path, root) - local self = setmetatable({file_path = assert(file_path), root = root}, metatable) +function lua_log_file.new(file_path, root, reference_strings) + local self = setmetatable({ + file_path = assert(file_path), + root = root, + reference_strings = reference_strings + }, metatable) if minetest then files[self] = true end return self end +local function set_references(self, table) + -- Weak table keys to allow the collection of dead reference tables + -- TODO garbage collect strings in the references table + self.references = setmetatable(table, {__mode = "k"}) +end + function lua_log_file:load() -- Bytecode is blocked by the engine local read = assert(loadfile(self.file_path)) @@ -27,7 +40,7 @@ function lua_log_file:load() env.R = env.R or {{}} self.reference_count = #env.R self.root = env.R[1] - self.references = modlib.table.flip(env.R) + set_references(self, {}) end function lua_log_file:open() @@ -99,12 +112,13 @@ function lua_log_file:_dump(value, is_key) self.references[value] = reference end if _type == "string" then - if is_key and value:len() <= key:len() and value:match"[%a_][%a%d_]*" then + 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 -- Short key return value, true end formatted = ("%q"):format(value) - if formatted:len() <= key:len() then + if (not reference_strings) or formatted:len() <= key:len() then -- Short string return formatted end @@ -133,10 +147,14 @@ function lua_log_file:_dump(value, is_key) end function lua_log_file:set(table, key, value) - table[key] = value if not self.references[table] then error"orphan table" end + if table[key] == value then + -- No change + return + end + table[key] = value table = self:_dump(table) local key, short_key = self:_dump(key, true) self:log(table .. (short_key and ("." .. key) or ("[" .. key .. "]")) .. "=" .. self:_dump(value)) @@ -147,7 +165,7 @@ function lua_log_file:set_root(key, value) end function lua_log_file:_write() - self.references = {} + set_references(self, {}) self.reference_count = 0 self:log"R={}" self:_dump(self.root) diff --git a/mods/lib_api/modlib/table.lua b/mods/lib_api/modlib/table.lua index ca14fcf..b96f89b 100644 --- a/mods/lib_api/modlib/table.lua +++ b/mods/lib_api/modlib/table.lua @@ -321,6 +321,22 @@ function foreach(table, func) end end +function deep_foreach_any(table, func) + local seen = {} + local function visit(value) + func(value) + if type(value) == "table" then + if seen[value] then return end + seen[value] = true + for k, v in pairs(value) do + visit(k) + visit(v) + end + end + end + visit(table) +end + function foreach_value(table, func) for _, v in pairs(table) do func(v) diff --git a/mods/lib_api/modlib/test.lua b/mods/lib_api/modlib/test.lua index 8c20bdb..ffff5b5 100644 --- a/mods/lib_api/modlib/test.lua +++ b/mods/lib_api/modlib/test.lua @@ -16,6 +16,17 @@ setfenv(1, setmetatable({}, { end })) +-- func +do + local tab = {a = 1, b = 2} + func.iterate(function(key, value) + assert(tab[key] == value) + tab[key] = nil + end, pairs, tab) + assert(next(tab) == nil) + assert(func.aggregate(func.add, 1, 2, 3) == 6) +end + -- string assert(string.escape_magic_chars"%" == "%%") @@ -50,6 +61,24 @@ do rope:write" " rope:write"world" assert(rope:to_text() == "hello world", rope:to_text()) + tab = {a = 1, b = {2}} + tab[3] = tab + local contents = { + a = 1, + [1] = 1, + b = 1, + [tab.b] = 1, + [2] = 1, + [tab] = 1, + [3] = 1 + } + table.deep_foreach_any(tab, function(content) + assert(contents[content], content) + contents[content] = 2 + end) + for _, value in pairs(contents) do + assert(value == 2) + end end -- heap @@ -195,14 +224,23 @@ test_from_string("#333", 0x333333FF) test_from_string("#694269", 0x694269FF) test_from_string("#11223344", 0x11223344) -local logfile = persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}) -logfile:init() -logfile.root = {} -logfile:rewrite() -logfile:set_root({a = 1}, {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge}) -logfile:close() -logfile:init() -assert(table.equals(logfile.root, {[{a = 1}] = {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge}})) +local function test_logfile(reference_strings) + local logfile = persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}, reference_strings) + logfile:init() + logfile.root = {a_longer_string = "test"} + logfile:rewrite() + logfile:set_root({a = 1}, {b = 2, c = 3, d = _G.math.huge, e = -_G.math.huge}) + logfile:close() + 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}})) + if not reference_strings then + for key in pairs(logfile.references) do + assert(type(key) ~= "string") + end + end +end +test_logfile(true) +test_logfile(false) -- in-game tests & b3d testing local tests = { diff --git a/mods/lib_api/modlib/vector.lua b/mods/lib_api/modlib/vector.lua index 1c903ce..a25312d 100644 --- a/mods/lib_api/modlib/vector.lua +++ b/mods/lib_api/modlib/vector.lua @@ -190,6 +190,14 @@ function angle(v, w) return math.acos(dot(v, w) / length(v) / length(w)) end +-- Uses Rodrigues' rotation formula +function rotate3(v, axis, angle) + local cos = math.cos(angle) + return multiply_scalar(v, cos) + + multiply_scalar(cross3(axis, v), math.sin(angle)) + + multiply_scalar(axis, dot(axis, v) * (1 - cos)) +end + function box_box_collision(diff, box, other_box) for index, diff in pairs(diff) do if box[index] + diff > other_box[index + 3] or other_box[index] > box[index + 3] + diff then diff --git a/mods/player/skinsdb/api.lua b/mods/player/skinsdb/api.lua index 87765d1..92e1a3f 100644 --- a/mods/player/skinsdb/api.lua +++ b/mods/player/skinsdb/api.lua @@ -5,7 +5,7 @@ function skins.get_player_skin(player) local meta = player:get_meta() if meta:get("skinsdb:skin_key") then -- Move player data prior July 2018 to mod storage - storage:set_string(player:get_player_name(), player:get_string("skinsdb:skin_key")) + storage:set_string(player:get_player_name(), meta:get_string("skinsdb:skin_key")) meta:set_string("skinsdb:skin_key", "") end local skin = storage:get_string(player:get_player_name())