From daa0251632742f73fc33073573dc1e07a78de4ab Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Wed, 14 Jul 2021 11:51:47 +0200 Subject: [PATCH] Use tabs not spaces --- Readme.md | 80 ++++++------ hashlist.lua | 80 ++++++------ luon.lua | 279 ++++++++++++++++++++-------------------- minetest.lua | 2 +- minetest/luon.lua | 36 +++--- minetest/schematic.lua | 286 ++++++++++++++++++++--------------------- table.lua | 26 ++-- 7 files changed, 395 insertions(+), 394 deletions(-) diff --git a/Readme.md b/Readme.md index 3f26aff..b5d4fab 100644 --- a/Readme.md +++ b/Readme.md @@ -44,21 +44,21 @@ Binary Lua object notation. **Experimental.** Handling of subnormal numbers (ver ```lua def = { - aux_is_valid = function(object) - return is_valid - end, - aux_len = function(object) - return length_in_bytes - end, - -- read type byte, stream providing :read(count), map of references -> id - aux_read = function(type, stream, references) - ... = stream:read(...) - return object - end, - -- object to be written, stream providing :write(text), list of references - aux_write = function(object, stream, references) - stream:write(...) - end + aux_is_valid = function(object) + return is_valid + end, + aux_len = function(object) + return length_in_bytes + end, + -- read type byte, stream providing :read(count), map of references -> id + aux_read = function(type, stream, references) + ... = stream:read(...) + return object + end, + -- object to be written, stream providing :write(text), list of references + aux_write = function(object, stream, references) + stream:write(...) + end } ``` @@ -128,22 +128,22 @@ assert(modlib.bluon:read(object, rope) == true) ```lua -- Serializes all userdata to a constant string: local custom_bluon = bluon.new{ - aux_is_valid = function(object) - return type(object) == "userdata" - end, - aux_len = function(object) - return 1 + ("userdata"):len()) - end, - aux_read = function(type, stream, references) - assert(type == 100, "unsupported type") - assert(stream:read(("userdata"):len()) == "userdata") - return userdata() - end, - -- object to be written, stream providing :write(text), list of references - aux_write = function(object, stream, references) - assert(type(object) == "userdata") - stream:write"\100userdata" - end + aux_is_valid = function(object) + return type(object) == "userdata" + end, + aux_len = function(object) + return 1 + ("userdata"):len()) + end, + aux_read = function(type, stream, references) + assert(type == 100, "unsupported type") + assert(stream:read(("userdata"):len()) == "userdata") + return userdata() + end, + -- object to be written, stream providing :write(text), list of references + aux_write = function(object, stream, references) + assert(type(object) == "userdata") + stream:write"\100userdata" + end } -- Write to text local rope = modlib.table.rope{} @@ -255,21 +255,21 @@ A schematic format with support for metadata and baked light data. **Experimenta * Fixes * Colorspec - * Stricter patterns in `colorspec:from_string` - * `colorspec:to_string` works now + * Stricter patterns in `colorspec:from_string` + * `colorspec:to_string` works now * Lua log file - * Patched memory leaks - * Added option to not reference strings - * Handling of circular tables + * Patched memory leaks + * Added option to not reference strings + * Handling of circular tables * Additions * `luon`: Configurable serialization to and from Lua with circular and string reference support - * `minetest.luon` even supports `ItemStack` and `AreaStore` + * `minetest.luon` even supports `ItemStack` and `AreaStore` * `vector.rotate3` * `table.deep_foreach_any` * `func`: - * `func.iterate` - * `func.aggregate` - * Functional wrappers for operators + * `func.iterate` + * `func.aggregate` + * Functional wrappers for operators * Improvements * Code quality * Performance diff --git a/hashlist.lua b/hashlist.lua index 5e84623..5036618 100644 --- a/hashlist.lua +++ b/hashlist.lua @@ -9,82 +9,82 @@ list.metatable = metatable -- Takes a list function list:new() - self.head = 0 - self.length = #self - return setmetatable(self, metatable) + self.head = 0 + self.length = #self + return setmetatable(self, metatable) end function list:in_bounds(index) - return index >= 1 and index <= self.length + return index >= 1 and index <= self.length end function list:get(index) - return self[self.head + index] + return self[self.head + index] end function list:set(index, value) - assert(value ~= nil) - self[self.head + index] = value + assert(value ~= nil) + self[self.head + index] = value end function list:len() - return self.length + return self.length end function list:ipairs() - local index = 1 - return function() - if index > self.length then - return - end - return index, self[self.head + index] - end + local index = 1 + return function() + if index > self.length then + return + end + return index, self[self.head + index] + end end function list:rpairs() - local index = self.length - return function() - if index < 1 then - return - end - return index, self[self.head + index] - end + local index = self.length + return function() + if index < 1 then + return + end + return index, self[self.head + index] + end end function list:push_tail(value) - assert(value ~= nil) - self.length = self.length + 1 - self[self.head + self.length] = value + assert(value ~= nil) + self.length = self.length + 1 + self[self.head + self.length] = value end function list:get_tail() - return self[self.head + self.length] + return self[self.head + self.length] end function list:pop_tail() - if self.length == 0 then return end - local value = self:get_tail() - self[self.head + self.length] = nil - self.length = self.length - 1 - return value + if self.length == 0 then return end + local value = self:get_tail() + self[self.head + self.length] = nil + self.length = self.length - 1 + return value end function list:push_head(value) - self[self.head] = value - self.head = self.head - 1 - self.length = self.length + 1 + self[self.head] = value + self.head = self.head - 1 + self.length = self.length + 1 end function list:get_head() - return self[self.head + 1] + return self[self.head + 1] end function list:pop_head() - if self.length == 0 then return end - local value = self:get_head() - self.head = self.head + 1 - self[self.head] = nil - return value + if self.length == 0 then return end + local value = self:get_head() + self.head = self.head + 1 + self[self.head] = nil + return value end return list \ No newline at end of file diff --git a/luon.lua b/luon.lua index 94e4032..c7c01ec 100644 --- a/luon.lua +++ b/luon.lua @@ -1,16 +1,16 @@ local assert, next, pairs, pcall, error, type, table_insert, table_concat, string_format, string_match, setmetatable, select, setfenv, math_huge, loadfile, loadstring - = assert, next, pairs, pcall, error, type, table.insert, table.concat, string.format, string.match, setmetatable, select, setfenv, math.huge, loadfile, loadstring + = assert, next, pairs, pcall, error, type, table.insert, table.concat, string.format, string.match, setmetatable, select, setfenv, math.huge, loadfile, loadstring local count_objects = modlib.table.count_objects -- 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) + succ[string.char(char)] = string.char(char + 1) end local function quote(string) - return string_format("%q", string) + return string_format("%q", string) end local _ENV = {} @@ -19,169 +19,170 @@ local metatable = {__index = _ENV} _ENV.metatable = metatable function new(self) - return setmetatable(self, metatable) + return setmetatable(self, metatable) end function aux_write(_self, _object) - -- returns reader, arguments - return + -- returns reader, arguments + return end aux_read = {} function write(self, value, 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 = {} - -- TODO sort objects by count, give frequently referenced objects shorter references - for object, count in pairs(count_objects(value)) do - local type_ = type(object) - if count >= 2 and (type_ ~= "string" or #reference + 2 < #object) then - local ref = table_concat(reference) - write(ref) - write"=" - write(type_ == "table" and "{}" or quote(object)) - write";" - references[object] = ref - if type_ == "table" then - to_fill[object] = ref - 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 - return write(ref) - 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 - -- TODO move aux_write to start, to allow dealing with metatables etc.? - (function(func, ...) - -- functions are the only way to deal with varargs - if not func then - return error("unsupported type: " .. type_) - end - write(func) - write"(" - local n = select("#", ...) - local args = {...} - for i = 1, n - 1 do - dump(args[i]) - write"," - end - if n > 0 then - write(args[n]) - end - write")" - end)(self:aux_write(value)) - end - end - for table, ref in pairs(to_fill) do - for k, v in pairs(table) do - write(ref) - if is_short_key(k) then - write"." - write(k) - else - write"[" - dump(k) - write"]" - end - write"=" - dump(v) - write";" - end - end - write"return " - dump(value) + 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 = {} + -- TODO sort objects by count, give frequently referenced objects shorter references + for object, count in pairs(count_objects(value)) do + local type_ = type(object) + if count >= 2 and (type_ ~= "string" or #reference + 2 < #object) then + local ref = table_concat(reference) + write(ref) + write"=" + write(type_ == "table" and "{}" or quote(object)) + write";" + references[object] = ref + if type_ == "table" then + to_fill[object] = ref + 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 + return write(ref) + 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 + -- TODO move aux_write to start, to allow dealing with metatables etc.? + (function(func, ...) + -- functions are the only way to deal with varargs + if not func then + return error("unsupported type: " .. type_) + end + write(func) + write"(" + local n = select("#", ...) + local args = {...} + for i = 1, n - 1 do + dump(args[i]) + write"," + end + if n > 0 then + write(args[n]) + end + write")" + end)(self:aux_write(value)) + end + end + for table, ref in pairs(to_fill) do + for k, v in pairs(table) do + write(ref) + if is_short_key(k) then + write"." + write(k) + else + write"[" + dump(k) + write"]" + end + write"=" + dump(v) + write";" + end + end + write"return " + dump(value) end function write_file(self, value, file) - return self:write(value, function(text) - file:write(text) - end) + return self:write(value, function(text) + file:write(text) + end) end function write_string(self, value) - local rope = {} - self:write(value, function(text) - table_insert(rope, text) - end) - return table_concat(rope) + local rope = {} + self:write(value, function(text) + table_insert(rope, text) + end) + return table_concat(rope) end function read(self, ...) local read = assert(...) -- math.huge is serialized to inf, 0/0 is serialized to -nan + -- TODO verify this is actually the case, see https://en.wikipedia.org/wiki/Printf_format_string setfenv(read, setmetatable({inf = math_huge, nan = 0/0}, {__index = self.aux_read})) local success, value_or_err = pcall(read) - if success then - return value_or_err - end - return nil, value_or_err + if success then + return value_or_err + end + return nil, value_or_err end function read_file(self, path) - return self:read(loadfile(path)) + return self:read(loadfile(path)) end function read_string(self, string) - return self:read(loadstring(string)) + return self:read(loadstring(string)) end return _ENV \ No newline at end of file diff --git a/minetest.lua b/minetest.lua index 4b2b8a4..cffa9be 100644 --- a/minetest.lua +++ b/minetest.lua @@ -1,6 +1,6 @@ local _ENV = setmetatable({}, {__index = _G}) local function load(filename) - assert(loadfile(modlib.mod.get_resource(modlib.modname, "minetest", filename .. ".lua")))(_ENV) + assert(loadfile(modlib.mod.get_resource(modlib.modname, "minetest", filename .. ".lua")))(_ENV) end load"misc" load"collisionboxes" diff --git a/minetest/luon.lua b/minetest/luon.lua index e22a9d9..aafb28d 100644 --- a/minetest/luon.lua +++ b/minetest/luon.lua @@ -1,29 +1,29 @@ -- Localize globals local getmetatable, AreaStore, ItemStack - = getmetatable, AreaStore, ItemStack + = getmetatable, AreaStore, ItemStack -- Metatable lookup for classes specified in lua_api.txt, section "Class reference" local AreaStoreMT = getmetatable(AreaStore()) local ItemStackMT = getmetatable(ItemStack"") local metatables = { - [AreaStoreMT] = {name = "AreaStore", method = AreaStoreMT.to_string}, - [ItemStackMT] = {name = "ItemStack", method = ItemStackMT.to_table}, - -- TODO expand + [AreaStoreMT] = {name = "AreaStore", method = AreaStoreMT.to_string}, + [ItemStackMT] = {name = "ItemStack", method = ItemStackMT.to_table}, + -- TODO expand } (...).luon = modlib.luon.new{ - aux_write = function(_, value) - local type = metatables[getmetatable(value)] - if type then - return type.name, type.method(value) - end - end, - aux_read = { - AreaStore = function(...) - local store = AreaStore() - store:from_string(...) - return store - end, - ItemStack = ItemStack - } + aux_write = function(_, value) + local type = metatables[getmetatable(value)] + if type then + return type.name, type.method(value) + end + end, + aux_read = { + AreaStore = function(...) + local store = AreaStore() + store:from_string(...) + return store + end, + ItemStack = ItemStack + } } \ No newline at end of file diff --git a/minetest/schematic.lua b/minetest/schematic.lua index 7b534ad..78247c6 100644 --- a/minetest/schematic.lua +++ b/minetest/schematic.lua @@ -1,6 +1,6 @@ -- Localize globals local VoxelArea, ItemStack, assert, error, io, ipairs, math, minetest, modlib, next, pairs, setmetatable, string, table, type, vector - = VoxelArea, ItemStack, assert, error, io, ipairs, math, minetest, modlib, next, pairs, setmetatable, string, table, type, vector + = VoxelArea, ItemStack, assert, error, io, ipairs, math, minetest, modlib, next, pairs, setmetatable, string, table, type, vector -- Set environment local _ENV = ... @@ -10,179 +10,179 @@ schematic = {} local metatable = {__index = schematic} function schematic.setmetatable(self) - return setmetatable(self, metatable) + return setmetatable(self, metatable) end function schematic.create(self, pos_min, pos_max) - self.size = vector.subtract(pos_max, pos_min) - local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) - local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) - local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } - local nodes, light_values, param2s = {}, self.light_values and {}, {} - local vm_nodes, vm_light_values, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() - local node_names, node_ids = {}, {} - local i = 0 - for index in voxelarea:iterp(pos_min, pos_max) do - if nodes[index] == minetest.CONTENT_UNKNOWN or nodes[index] == minetest.CONTENT_IGNORE then - error("unknown or ignore node at " .. minetest.pos_to_string(voxelarea:position(index))) - end - local name = minetest.get_name_from_content_id(vm_nodes[index]) - local id = node_ids[name] - if not id then - table.insert(node_names, name) - id = #node_names - node_ids[name] = id - end - i = i + 1 - nodes[i] = id - if self.light_values then - light_values[i] = vm_light_values[index] - end - param2s[i] = vm_param2s[index] - end - local metas = self.metas - if metas or metas == nil then - local indexing = vector.add(self.size, 1) - metas = {} - for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do - local meta = minetest.get_meta(pos):to_table() - if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then - local relative = vector.subtract(pos, pos_min) - metas[((relative.z * indexing.y) + relative.y) * indexing.x + relative.x] = meta - end - end - end - self.node_names = node_names - self.nodes = nodes - self.light_values = light_values - self.param2s = param2s - self.metas = metas - return schematic.setmetatable(self) + self.size = vector.subtract(pos_max, pos_min) + local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) + local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) + local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } + local nodes, light_values, param2s = {}, self.light_values and {}, {} + local vm_nodes, vm_light_values, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() + local node_names, node_ids = {}, {} + local i = 0 + for index in voxelarea:iterp(pos_min, pos_max) do + if nodes[index] == minetest.CONTENT_UNKNOWN or nodes[index] == minetest.CONTENT_IGNORE then + error("unknown or ignore node at " .. minetest.pos_to_string(voxelarea:position(index))) + end + local name = minetest.get_name_from_content_id(vm_nodes[index]) + local id = node_ids[name] + if not id then + table.insert(node_names, name) + id = #node_names + node_ids[name] = id + end + i = i + 1 + nodes[i] = id + if self.light_values then + light_values[i] = vm_light_values[index] + end + param2s[i] = vm_param2s[index] + end + local metas = self.metas + if metas or metas == nil then + local indexing = vector.add(self.size, 1) + metas = {} + for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do + local meta = minetest.get_meta(pos):to_table() + if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then + local relative = vector.subtract(pos, pos_min) + metas[((relative.z * indexing.y) + relative.y) * indexing.x + relative.x] = meta + end + end + end + self.node_names = node_names + self.nodes = nodes + self.light_values = light_values + self.param2s = param2s + self.metas = metas + return schematic.setmetatable(self) end function schematic:write_to_voxelmanip(voxelmanip, pos_min) - local pos_max = vector.add(pos_min, self.size) - local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) - local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } - local nodes, light_values, param2s, metas = self.nodes, self.light_values, self.param2s, self.metas - local vm_nodes, vm_lights, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() - for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do - -- Clear all metadata. Due to an engine bug, nodes will actually have empty metadata. - minetest.get_meta(pos):from_table{} - end - local content_ids = {} - for index, name in ipairs(self.node_names) do - content_ids[index] = assert(minetest.get_content_id(name), ("unknown node %q"):format(name)) - end - local i = 0 - for index in voxelarea:iterp(pos_min, pos_max) do - i = i + 1 - vm_nodes[index] = content_ids[nodes[i]] - if light_values then - vm_lights[index] = light_values[i] - end - vm_param2s[index] = param2s[i] - end - voxelmanip:set_data(vm_nodes) - if light_values then - voxelmanip:set_light_data(vm_lights) - end - voxelmanip:set_param2_data(vm_param2s) - if metas then - local indexing = vector.add(self.size, 1) - for index, meta in pairs(metas) do - local floored = math.floor(index / indexing.x) - local relative = { - x = index % indexing.x, - y = floored % indexing.y, - z = math.floor(floored / indexing.y) - } - minetest.get_meta(vector.add(relative, pos_min)):from_table(meta) - end - end + local pos_max = vector.add(pos_min, self.size) + local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) + local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } + local nodes, light_values, param2s, metas = self.nodes, self.light_values, self.param2s, self.metas + local vm_nodes, vm_lights, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() + for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do + -- Clear all metadata. Due to an engine bug, nodes will actually have empty metadata. + minetest.get_meta(pos):from_table{} + end + local content_ids = {} + for index, name in ipairs(self.node_names) do + content_ids[index] = assert(minetest.get_content_id(name), ("unknown node %q"):format(name)) + end + local i = 0 + for index in voxelarea:iterp(pos_min, pos_max) do + i = i + 1 + vm_nodes[index] = content_ids[nodes[i]] + if light_values then + vm_lights[index] = light_values[i] + end + vm_param2s[index] = param2s[i] + end + voxelmanip:set_data(vm_nodes) + if light_values then + voxelmanip:set_light_data(vm_lights) + end + voxelmanip:set_param2_data(vm_param2s) + if metas then + local indexing = vector.add(self.size, 1) + for index, meta in pairs(metas) do + local floored = math.floor(index / indexing.x) + local relative = { + x = index % indexing.x, + y = floored % indexing.y, + z = math.floor(floored / indexing.y) + } + minetest.get_meta(vector.add(relative, pos_min)):from_table(meta) + end + end end function schematic:place(pos_min) - local pos_max = vector.add(pos_min, self.size) - local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) - self:write_to_voxelmanip(voxelmanip, pos_min) - voxelmanip:write_to_map(not self.light_values) - return voxelmanip + local pos_max = vector.add(pos_min, self.size) + local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) + self:write_to_voxelmanip(voxelmanip, pos_min) + voxelmanip:write_to_map(not self.light_values) + return voxelmanip end local function table_to_byte_string(tab) - if not tab then return end - return table.concat(modlib.table.map(tab, string.char)) + if not tab then return end + return table.concat(modlib.table.map(tab, string.char)) end local function write_bluon(self, stream) - local metas, light_values, param2s = self.metas, self.light_values, self.param2s - self.metas = modlib.table.copy(metas) - for _, meta in pairs(self.metas) do - for _, list in pairs(meta.inventory) do - for index, stack in pairs(list) do - list[index] = stack:to_string() - end - end - end - self.light_values, self.param2s = table_to_byte_string(light_values), table_to_byte_string(param2s) - modlib.bluon:write(self, stream) - self.metas, self.light_values, self.param2s = metas, light_values, param2s + local metas, light_values, param2s = self.metas, self.light_values, self.param2s + self.metas = modlib.table.copy(metas) + for _, meta in pairs(self.metas) do + for _, list in pairs(meta.inventory) do + for index, stack in pairs(list) do + list[index] = stack:to_string() + end + end + end + self.light_values, self.param2s = table_to_byte_string(light_values), table_to_byte_string(param2s) + modlib.bluon:write(self, stream) + self.metas, self.light_values, self.param2s = metas, light_values, param2s end function schematic:write_bluon(path) - local file = io.open(path, "wb") - -- Header, short for "ModLib Bluon Schematic" - file:write"MLBS" - write_bluon(self, file) - file:close() + local file = io.open(path, "wb") + -- Header, short for "ModLib Bluon Schematic" + file:write"MLBS" + write_bluon(self, file) + file:close() end local function byte_string_to_table(self, field) - local byte_string = self[field] - if not byte_string then return end - local tab = {} - for i = 1, #byte_string do - tab[i] = byte_string:byte(i) - end - self[field] = tab + local byte_string = self[field] + if not byte_string then return end + local tab = {} + for i = 1, #byte_string do + tab[i] = byte_string:byte(i) + end + self[field] = tab end local function read_bluon(file) - local self = modlib.bluon:read(file) - assert(not file:read(1), "expected EOF") - for _, meta in pairs(self.metas) do - for _, list in pairs(meta.inventory) do - for index, itemstring in pairs(list) do - assert(type(itemstring) == "string") - list[index] = ItemStack(itemstring) - end - end - end - byte_string_to_table(self, "light_values") - byte_string_to_table(self, "param2s") - return self + local self = modlib.bluon:read(file) + assert(not file:read(1), "expected EOF") + for _, meta in pairs(self.metas) do + for _, list in pairs(meta.inventory) do + for index, itemstring in pairs(list) do + assert(type(itemstring) == "string") + list[index] = ItemStack(itemstring) + end + end + end + byte_string_to_table(self, "light_values") + byte_string_to_table(self, "param2s") + return self end function schematic.read_bluon(path) - local file = io.open(path, "rb") - assert(file:read(4) == "MLBS", "not a modlib bluon schematic") - return schematic.setmetatable(read_bluon(file)) + local file = io.open(path, "rb") + assert(file:read(4) == "MLBS", "not a modlib bluon schematic") + return schematic.setmetatable(read_bluon(file)) end function schematic:write_zlib_bluon(path, compression) - local file = io.open(path, "wb") - -- Header, short for "ModLib Zlib-compressed-bluon Schematic" - file:write"MLZS" - local rope = modlib.table.rope{} - write_bluon(self, rope) - local text = rope:to_text() - file:write(minetest.compress(text, "deflate", compression or 9)) - file:close() + local file = io.open(path, "wb") + -- Header, short for "ModLib Zlib-compressed-bluon Schematic" + file:write"MLZS" + local rope = modlib.table.rope{} + write_bluon(self, rope) + local text = rope:to_text() + file:write(minetest.compress(text, "deflate", compression or 9)) + file:close() end function schematic.read_zlib_bluon(path) - local file = io.open(path, "rb") - assert(file:read(4) == "MLZS", "not a modlib zlib compressed bluon schematic") - return schematic.setmetatable(read_bluon(modlib.text.inputstream(minetest.decompress(file:read"*a", "deflate")))) + local file = io.open(path, "rb") + assert(file:read(4) == "MLZS", "not a modlib zlib compressed bluon schematic") + return schematic.setmetatable(read_bluon(modlib.text.inputstream(minetest.decompress(file:read"*a", "deflate")))) end \ No newline at end of file diff --git a/table.lua b/table.lua index 6dab63a..e934ed6 100644 --- a/table.lua +++ b/table.lua @@ -339,25 +339,25 @@ end -- Recursively counts occurences of objects (non-primitives including strings) in a table. function count_objects(value) - local counts = {} + local counts = {} if value == nil then -- Early return for nil return counts end - local function count_values(value) + local function count_values(value) local type_ = type(value) if type_ == "boolean" or type_ == "number" then return end - local count = counts[value] - counts[value] = (count or 0) + 1 - if not count and type_ == "table" then - for k, v in pairs(value) do - count_values(k) - count_values(v) - end - end - end - count_values(value) - return counts + local count = counts[value] + counts[value] = (count or 0) + 1 + if not count and type_ == "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)