From 7cf99da1a5486f18aab016c41bbdf576edf65b6a Mon Sep 17 00:00:00 2001 From: upsilon Date: Thu, 9 Apr 2020 16:13:51 +0200 Subject: [PATCH 01/13] LuaBlock: Major changes in mod storage usage Data associated to a LuaBlock is redundantly stored in both its metadata and in the mod storage so that it is not possible to hack a LuaBlock by changing its metadata or copying it using WorldEdit. This commit changes how it is done: * Store full code instead of storing MD5 checksum, which avoids bug caused by serializing non-ASCII strings using minetest.serialize, * Also store owner, * Use `minetest.hash_node_position` instead of deprecated vector_extras set_data_to_pos etc, * Remove mod storage data associated with the LuaBlock when destroying it, * Create helper functions for manipulating the mod storage in moremesecons_utils, I will soon update other parts of MoreMesecons as well to use them. This commit breaks backwards compatibility: previously created LuaBlocks will have to be reset by opening the formspec and pressing the `Submit` button. This commit also fixes an unrelated bug: code in the formspec was not correctly escaped using minetest.formspec_escape. --- moremesecons_luablock/init.lua | 44 +- moremesecons_luablock/md5_lua/.travis.yml | 34 -- moremesecons_luablock/md5_lua/CHANGELOG.md | 5 - moremesecons_luablock/md5_lua/MIT-LICENSE.txt | 20 - moremesecons_luablock/md5_lua/README.md | 55 --- moremesecons_luablock/md5_lua/md5.lua | 396 ------------------ .../md5_lua/rockspecs/md5-1.0-0.rockspec | 21 - .../md5_lua/rockspecs/md5-1.0-1.rockspec | 21 - .../md5_lua/rockspecs/md5-1.0-2.rockspec | 21 - .../md5_lua/rockspecs/md5-1.1-0.rockspec | 21 - .../md5_lua/spec/md5_spec.lua | 40 -- moremesecons_utils/init.lua | 24 ++ 12 files changed, 50 insertions(+), 652 deletions(-) delete mode 100644 moremesecons_luablock/md5_lua/.travis.yml delete mode 100644 moremesecons_luablock/md5_lua/CHANGELOG.md delete mode 100644 moremesecons_luablock/md5_lua/MIT-LICENSE.txt delete mode 100644 moremesecons_luablock/md5_lua/README.md delete mode 100644 moremesecons_luablock/md5_lua/md5.lua delete mode 100644 moremesecons_luablock/md5_lua/rockspecs/md5-1.0-0.rockspec delete mode 100644 moremesecons_luablock/md5_lua/rockspecs/md5-1.0-1.rockspec delete mode 100644 moremesecons_luablock/md5_lua/rockspecs/md5-1.0-2.rockspec delete mode 100644 moremesecons_luablock/md5_lua/rockspecs/md5-1.1-0.rockspec delete mode 100644 moremesecons_luablock/md5_lua/spec/md5_spec.lua diff --git a/moremesecons_luablock/init.lua b/moremesecons_luablock/init.lua index a13b64f..3d93e54 100644 --- a/moremesecons_luablock/init.lua +++ b/moremesecons_luablock/init.lua @@ -1,20 +1,21 @@ -local md5 = dofile(minetest.get_modpath(minetest.get_current_modname()).."/md5_lua/md5.lua") local storage = minetest.get_mod_storage() -local hash_table = minetest.deserialize(storage:get_string("hash_table")) or {} +local pos_data = moremesecons.get_storage_data(storage, "pos_data") -local function set_md5(pos, code) - vector.set_data_to_pos(hash_table, pos.z,pos.y,pos.x, md5.sum(code)) - storage:set_string("hash_table", minetest.serialize(hash_table)) +local function set_data(pos, code, owner) + local data = { + code = code, + owner = owner + } + moremesecons.set_data_to_pos(pos_data, pos, data) end -local function check_md5(pos, code) - local stored_sum = vector.get_data_from_pos(hash_table, pos.z,pos.y,pos.x) - if not stored_sum then - -- Legacy - set_md5(pos, code) - return true +local function check_data(pos, code, owner) + local stored_data = moremesecons.get_data_from_pos(pos_data, pos) + if not stored_data then + return false end - if md5.sum(code) ~= stored_sum then + if code ~= stored_data.code + or owner ~= stored_data.owner then return false end return true @@ -22,11 +23,11 @@ end local function make_formspec(meta, pos) - local code = meta:get_string("code") + local code = minetest.formspec_escape(meta:get_string("code")) local errmsg = minetest.formspec_escape(meta:get_string("errmsg")) meta:set_string("formspec", "size[10,8;]" .. - "textarea[0.5,0.5;10,7;code;Code;"..code.."]" .. + "textarea[0.5,0.5;9.5,7;code;Code;"..code.."]" .. "label[0.1,7;"..errmsg.."]" .. "button_exit[4,7.5;2,1;submit;Submit]") end @@ -97,22 +98,26 @@ minetest.register_node("moremesecons_luablock:luablock", { end meta:set_string("code", fields.code) - set_md5(pos, fields.code) + set_data(pos, fields.code, name) make_formspec(meta, pos) end, can_dig = function(pos, player) local meta = minetest.get_meta(pos) return meta:get_string("owner") == player:get_player_name() end, + on_destruct = function(pos) + moremesecons.remove_data_from_pos(pos_data, pos) + end, mesecons = {effector = { action_on = function(npos, node) local meta = minetest.get_meta(npos) local code = meta:get_string("code") + local owner = meta:get_string("owner") if code == "" then return end - if not check_md5(npos, code) then - minetest.log("warning", "[moremesecons_luablock] Code of LuaBlock at pos "..minetest.pos_to_string(npos).." does not match with its md5 checksum!") + if not check_data(npos, code, owner) then + minetest.log("warning", "[moremesecons_luablock] Metadata of LuaBlock at pos "..minetest.pos_to_string(npos).." does not match its mod storage data!") return end -- We do absolutely no check there. @@ -127,7 +132,10 @@ minetest.register_node("moremesecons_luablock:luablock", { return end -- Set the "pos" global - local old_pos = pos -- In case there's already an existing "pos" global + local old_pos + if minetest.global_exists("pos") then + old_pos = pos -- In case there's already an existing "pos" global + end pos = table.copy(npos) local good, err = pcall(func) pos = old_pos diff --git a/moremesecons_luablock/md5_lua/.travis.yml b/moremesecons_luablock/md5_lua/.travis.yml deleted file mode 100644 index 90bd434..0000000 --- a/moremesecons_luablock/md5_lua/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: python -sudo: false - -env: - - LUA="lua=5.1" - - LUA="lua=5.2" - - LUA="lua=5.3" - - LUA="luajit=2.0" - - LUA="luajit=2.1" - -before_install: - - pip install hererocks - - hererocks lua_install -r^ --$LUA - - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH - -install: - - luarocks install busted - - luarocks install luacov - - luarocks install luacov-coveralls - -script: - - busted --verbose --coverage - -after_success: - - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install - -branches: - except: - - gh-pages - -notifications: - email: - on_success: change - on_failure: always diff --git a/moremesecons_luablock/md5_lua/CHANGELOG.md b/moremesecons_luablock/md5_lua/CHANGELOG.md deleted file mode 100644 index a48c47a..0000000 --- a/moremesecons_luablock/md5_lua/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ - -# 1.1.0 - -* Fixes error with long strings in Lua 5.1 (@pgimeno) -* Adds incremental mode (@pgimeno) diff --git a/moremesecons_luablock/md5_lua/MIT-LICENSE.txt b/moremesecons_luablock/md5_lua/MIT-LICENSE.txt deleted file mode 100644 index 1630e47..0000000 --- a/moremesecons_luablock/md5_lua/MIT-LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software - -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. diff --git a/moremesecons_luablock/md5_lua/README.md b/moremesecons_luablock/md5_lua/README.md deleted file mode 100644 index 391b441..0000000 --- a/moremesecons_luablock/md5_lua/README.md +++ /dev/null @@ -1,55 +0,0 @@ -md5.lua [![Build Status](https://travis-ci.org/kikito/md5.lua.svg)](https://travis-ci.org/kikito/md5.lua) -========================================================================================================= - -This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1. - -It implements md5.sum and md5.sumhex like the [kernel project md5 package](http://www.keplerproject.org/md5/), but it's done completely in Lua, with no dependencies on other libs or C files. - -Usage -===== - -Simple example: - - local md5 = require 'md5' - - local md5_as_data = md5.sum(message) -- returns raw bytes - local md5_as_hex = md5.sumhexa(message) -- returns a hex string - local md5_as_hex2 = md5.tohex(md5_as_data) -- returns the same string as md5_as_hex - -Incremental example (for computing md5 of streams, or big files which have to be loaded in chunks - new since 1.1.0): - - local m = md5.new() - m:update('some bytes') - m:update('some more bytes') - m:update('etc') - return md5.tohex(m:finish()) - -Credits -======= - -This is a cleanup of an implementation by Adam Baldwin - https://gist.github.com/evilpacket/3647908 - -Which in turn was a mix of the bitwise lib, http://luaforge.net/projects/bit/ by hanzhao (`abrash_han - at - hotmail.com`), -and http://equi4.com/md5/md5calc.lua, by Equi 4 Software. - -Lua 5.2 and LuaJIT compatibility by [Positive07](https://github.com/kikito/md5.lua/pull/2) - -A very important fix and the incremental variant by [pgimeno](https://github.com/kikito/md5.lua/pull/10) - - -License -======= - -This library, as well as all the previous ones in which is based, is released under the MIT license (See license file for details). - -Specs -===== - -The specs for this library are implemented with [busted](http://ovinelabs.com/busted/). In order to run them, install busted and then: - - cd path/to/where/the/spec/folder/is - busted - - - - diff --git a/moremesecons_luablock/md5_lua/md5.lua b/moremesecons_luablock/md5_lua/md5.lua deleted file mode 100644 index 5e73ba6..0000000 --- a/moremesecons_luablock/md5_lua/md5.lua +++ /dev/null @@ -1,396 +0,0 @@ -local md5 = { - _VERSION = "md5.lua 1.1.0", - _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)", - _URL = "https://github.com/kikito/md5.lua", - _LICENSE = [[ - MIT LICENSE - - Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software - - 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. - ]] -} - --- bit lib implementions - -local char, byte, format, rep, sub = - string.char, string.byte, string.format, string.rep, string.sub -local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift - -local ok, bit = pcall(require, 'bit') -if ok then - bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift -else - ok, bit = pcall(require, 'bit32') - - if ok then - - bit_not = bit.bnot - - local tobit = function(n) - return n <= 0x7fffffff and n or -(bit_not(n) + 1) - end - - local normalize = function(f) - return function(a,b) return tobit(f(tobit(a), tobit(b))) end - end - - bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor) - bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift) - - else - - local function tbl2number(tbl) - local result = 0 - local power = 1 - for i = 1, #tbl do - result = result + tbl[i] * power - power = power * 2 - end - return result - end - - local function expand(t1, t2) - local big, small = t1, t2 - if(#big < #small) then - big, small = small, big - end - -- expand small - for i = #small + 1, #big do - small[i] = 0 - end - end - - local to_bits -- needs to be declared before bit_not - - bit_not = function(n) - local tbl = to_bits(n) - local size = math.max(#tbl, 32) - for i = 1, size do - if(tbl[i] == 1) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - return tbl2number(tbl) - end - - -- defined as local above - to_bits = function (n) - if(n < 0) then - -- negative - return to_bits(bit_not(math.abs(n)) + 1) - end - -- to bits table - local tbl = {} - local cnt = 1 - local last - while n > 0 do - last = n % 2 - tbl[cnt] = last - n = (n-last)/2 - cnt = cnt + 1 - end - - return tbl - end - - bit_or = function(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - for i = 1, #tbl_m do - if(tbl_m[i]== 0 and tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl2number(tbl) - end - - bit_and = function(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - for i = 1, #tbl_m do - if(tbl_m[i]== 0 or tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl2number(tbl) - end - - bit_xor = function(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - for i = 1, #tbl_m do - if(tbl_m[i] ~= tbl_n[i]) then - tbl[i] = 1 - else - tbl[i] = 0 - end - end - - return tbl2number(tbl) - end - - bit_rshift = function(n, bits) - local high_bit = 0 - if(n < 0) then - -- negative - n = bit_not(math.abs(n)) + 1 - high_bit = 0x80000000 - end - - local floor = math.floor - - for i=1, bits do - n = n/2 - n = bit_or(floor(n), high_bit) - end - return floor(n) - end - - bit_lshift = function(n, bits) - if(n < 0) then - -- negative - n = bit_not(math.abs(n)) + 1 - end - - for i=1, bits do - n = n*2 - end - return bit_and(n, 0xFFFFFFFF) - end - end -end - --- convert little-endian 32-bit int to a 4-char string -local function lei2str(i) - local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end - return f(0)..f(8)..f(16)..f(24) -end - --- convert raw string to big-endian int -local function str2bei(s) - local v=0 - for i=1, #s do - v = v * 256 + byte(s, i) - end - return v -end - --- convert raw string to little-endian int -local function str2lei(s) - local v=0 - for i = #s,1,-1 do - v = v*256 + byte(s, i) - end - return v -end - --- cut up a string in little-endian ints of given size -local function cut_le_str(s,...) - local o, r = 1, {} - local args = {...} - for i=1, #args do - table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) - o = o + args[i] - end - return r -end - -local swap = function (w) return str2bei(lei2str(w)) end - --- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) --- 10/02/2001 jcw@equi4.com - -local CONSTS = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 -} - -local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end -local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end -local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end -local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end -local z=function (ff,a,b,c,d,x,s,ac) - a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF) - -- be *very* careful that left shift does not cause rounding! - return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b -end - -local function transform(A,B,C,D,X) - local a,b,c,d=A,B,C,D - local t=CONSTS - - a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) - d=z(f,d,a,b,c,X[ 1],12,t[ 2]) - c=z(f,c,d,a,b,X[ 2],17,t[ 3]) - b=z(f,b,c,d,a,X[ 3],22,t[ 4]) - a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) - d=z(f,d,a,b,c,X[ 5],12,t[ 6]) - c=z(f,c,d,a,b,X[ 6],17,t[ 7]) - b=z(f,b,c,d,a,X[ 7],22,t[ 8]) - a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) - d=z(f,d,a,b,c,X[ 9],12,t[10]) - c=z(f,c,d,a,b,X[10],17,t[11]) - b=z(f,b,c,d,a,X[11],22,t[12]) - a=z(f,a,b,c,d,X[12], 7,t[13]) - d=z(f,d,a,b,c,X[13],12,t[14]) - c=z(f,c,d,a,b,X[14],17,t[15]) - b=z(f,b,c,d,a,X[15],22,t[16]) - - a=z(g,a,b,c,d,X[ 1], 5,t[17]) - d=z(g,d,a,b,c,X[ 6], 9,t[18]) - c=z(g,c,d,a,b,X[11],14,t[19]) - b=z(g,b,c,d,a,X[ 0],20,t[20]) - a=z(g,a,b,c,d,X[ 5], 5,t[21]) - d=z(g,d,a,b,c,X[10], 9,t[22]) - c=z(g,c,d,a,b,X[15],14,t[23]) - b=z(g,b,c,d,a,X[ 4],20,t[24]) - a=z(g,a,b,c,d,X[ 9], 5,t[25]) - d=z(g,d,a,b,c,X[14], 9,t[26]) - c=z(g,c,d,a,b,X[ 3],14,t[27]) - b=z(g,b,c,d,a,X[ 8],20,t[28]) - a=z(g,a,b,c,d,X[13], 5,t[29]) - d=z(g,d,a,b,c,X[ 2], 9,t[30]) - c=z(g,c,d,a,b,X[ 7],14,t[31]) - b=z(g,b,c,d,a,X[12],20,t[32]) - - a=z(h,a,b,c,d,X[ 5], 4,t[33]) - d=z(h,d,a,b,c,X[ 8],11,t[34]) - c=z(h,c,d,a,b,X[11],16,t[35]) - b=z(h,b,c,d,a,X[14],23,t[36]) - a=z(h,a,b,c,d,X[ 1], 4,t[37]) - d=z(h,d,a,b,c,X[ 4],11,t[38]) - c=z(h,c,d,a,b,X[ 7],16,t[39]) - b=z(h,b,c,d,a,X[10],23,t[40]) - a=z(h,a,b,c,d,X[13], 4,t[41]) - d=z(h,d,a,b,c,X[ 0],11,t[42]) - c=z(h,c,d,a,b,X[ 3],16,t[43]) - b=z(h,b,c,d,a,X[ 6],23,t[44]) - a=z(h,a,b,c,d,X[ 9], 4,t[45]) - d=z(h,d,a,b,c,X[12],11,t[46]) - c=z(h,c,d,a,b,X[15],16,t[47]) - b=z(h,b,c,d,a,X[ 2],23,t[48]) - - a=z(i,a,b,c,d,X[ 0], 6,t[49]) - d=z(i,d,a,b,c,X[ 7],10,t[50]) - c=z(i,c,d,a,b,X[14],15,t[51]) - b=z(i,b,c,d,a,X[ 5],21,t[52]) - a=z(i,a,b,c,d,X[12], 6,t[53]) - d=z(i,d,a,b,c,X[ 3],10,t[54]) - c=z(i,c,d,a,b,X[10],15,t[55]) - b=z(i,b,c,d,a,X[ 1],21,t[56]) - a=z(i,a,b,c,d,X[ 8], 6,t[57]) - d=z(i,d,a,b,c,X[15],10,t[58]) - c=z(i,c,d,a,b,X[ 6],15,t[59]) - b=z(i,b,c,d,a,X[13],21,t[60]) - a=z(i,a,b,c,d,X[ 4], 6,t[61]) - d=z(i,d,a,b,c,X[11],10,t[62]) - c=z(i,c,d,a,b,X[ 2],15,t[63]) - b=z(i,b,c,d,a,X[ 9],21,t[64]) - - return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF), - bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF) -end - ----------------------------------------------------------------- - -local function md5_update(self, s) - self.pos = self.pos + #s - s = self.buf .. s - for ii = 1, #s - 63, 64 do - local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) - assert(#X == 16) - X[0] = table.remove(X,1) -- zero based! - self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X) - end - self.buf = sub(s, math.floor(#s/64)*64 + 1, #s) - return self -end - -local function md5_finish(self) - local msgLen = self.pos - local padLen = 56 - msgLen % 64 - - if msgLen % 64 > 56 then padLen = padLen + 64 end - - if padLen == 0 then padLen = 64 end - - local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000)) - md5_update(self, s) - - assert(self.pos % 64 == 0) - return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d) -end - ----------------------------------------------------------------- - -function md5.new() - return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68], - pos = 0, - buf = '', - update = md5_update, - finish = md5_finish } -end - -function md5.tohex(s) - return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16))) -end - -function md5.sum(s) - return md5.new():update(s):finish() -end - -function md5.sumhexa(s) - return md5.tohex(md5.sum(s)) -end - -return md5 diff --git a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-0.rockspec b/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-0.rockspec deleted file mode 100644 index 4103148..0000000 --- a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-0.rockspec +++ /dev/null @@ -1,21 +0,0 @@ -package = "md5" -version = "1.0-0" -source = { - url = "https://github.com/kikito/md5.lua/archive/v1.0.0.tar.gz", - dir = "md5.lua-1.0.0" -} -description = { - summary = "MD5 sum in pure Lua, with no C and no external dependencies", - detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", - homepage = "https://github.com/kikito/md5.lua", - license = "MIT" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "builtin", - modules = { - md5 = "md5.lua" - } -} diff --git a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-1.rockspec b/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-1.rockspec deleted file mode 100644 index f9f5203..0000000 --- a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-1.rockspec +++ /dev/null @@ -1,21 +0,0 @@ -package = "md5" -version = "1.0-1" -source = { - url = "https://github.com/kikito/md5.lua/archive/v1.0.1.tar.gz", - dir = "md5.lua-1.0.1" -} -description = { - summary = "MD5 sum in pure Lua, with no C and no external dependencies", - detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", - homepage = "https://github.com/kikito/md5.lua", - license = "MIT" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "builtin", - modules = { - md5 = "md5.lua" - } -} diff --git a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-2.rockspec b/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-2.rockspec deleted file mode 100644 index c8034f9..0000000 --- a/moremesecons_luablock/md5_lua/rockspecs/md5-1.0-2.rockspec +++ /dev/null @@ -1,21 +0,0 @@ -package = "md5" -version = "1.0-2" -source = { - url = "https://github.com/kikito/md5.lua/archive/v1.0.2.tar.gz", - dir = "md5.lua-1.0.2" -} -description = { - summary = "MD5 sum in pure Lua, with no C and no external dependencies", - detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", - homepage = "https://github.com/kikito/md5.lua", - license = "MIT" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "builtin", - modules = { - md5 = "md5.lua" - } -} diff --git a/moremesecons_luablock/md5_lua/rockspecs/md5-1.1-0.rockspec b/moremesecons_luablock/md5_lua/rockspecs/md5-1.1-0.rockspec deleted file mode 100644 index ef1b392..0000000 --- a/moremesecons_luablock/md5_lua/rockspecs/md5-1.1-0.rockspec +++ /dev/null @@ -1,21 +0,0 @@ -package = "md5" -version = "1.1-0" -source = { - url = "https://github.com/kikito/md5.lua/archive/v1.1.0.tar.gz", - dir = "md5.lua-1.1.0" -} -description = { - summary = "MD5 sum in pure Lua, with no C and no external dependencies", - detailed = "This pure-Lua module computes md5 in Lua 5.1, Lua 5.2 and LuaJIT, using native bit-manipulation libraries when available, and falling back to table-based manipulation of integers in 5.1", - homepage = "https://github.com/kikito/md5.lua", - license = "MIT" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "builtin", - modules = { - md5 = "md5.lua" - } -} diff --git a/moremesecons_luablock/md5_lua/spec/md5_spec.lua b/moremesecons_luablock/md5_lua/spec/md5_spec.lua deleted file mode 100644 index 69dde39..0000000 --- a/moremesecons_luablock/md5_lua/spec/md5_spec.lua +++ /dev/null @@ -1,40 +0,0 @@ -local md5 = require('md5') - -local function hex2bin(hex) - local result, _ = hex:gsub('..', function(hexval) - return string.char(tonumber(hexval, 16)) - end) - return result -end - -describe('md5', function() - describe('md5.sumhexa', function() - it('works', function() - assert.equal(md5.sumhexa("asdf"), '912ec803b2ce49e4a541068d495ab570') - assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog'), '9e107d9d372bb6826bd81d3542a419d6') - assert.equal(md5.sumhexa('The quick brown fox jumps over the lazy dog.'), 'e4d909c290d0fb1ca068ffaddf22cbd0') - assert.equal(md5.sumhexa(''), 'd41d8cd98f00b204e9800998ecf8427e') - assert.equal(md5.sumhexa(('1'):rep(824)), 'a126fd3611ab8d9b7e8a3384e2fa78a0') - assert.equal(md5.sumhexa(('1'):rep(1528)), '3750b6a29d923b633e05d6ae76895664') - local state = md5.new() - state:update('Hello') - state:update(', World!') - assert.equal(md5.tohex(state:finish()), '65a8e27d8879283831b664bd8b7f0ad4') - end) - end) - - describe('md5.sum', function() - it('works', function() - assert.equal(md5.sum("asdf"), hex2bin '912ec803b2ce49e4a541068d495ab570') - assert.equal(md5.sum('The quick brown fox jumps over the lazy dog'), hex2bin '9e107d9d372bb6826bd81d3542a419d6') - assert.equal(md5.sum('The quick brown fox jumps over the lazy dog.'), hex2bin 'e4d909c290d0fb1ca068ffaddf22cbd0') - assert.equal(md5.sum(''), hex2bin 'd41d8cd98f00b204e9800998ecf8427e') - assert.equal(md5.sum(('1'):rep(824)), hex2bin 'a126fd3611ab8d9b7e8a3384e2fa78a0') - assert.equal(md5.sum(('1'):rep(1528)), hex2bin '3750b6a29d923b633e05d6ae76895664') - local state = md5.new() - state:update('Hello') - state:update(', World!') - assert.equal(state:finish(), hex2bin '65a8e27d8879283831b664bd8b7f0ad4') - end) - end) -end) diff --git a/moremesecons_utils/init.lua b/moremesecons_utils/init.lua index d986272..1a6d2eb 100644 --- a/moremesecons_utils/init.lua +++ b/moremesecons_utils/init.lua @@ -28,6 +28,30 @@ function moremesecons.setting(modname, settingname, default, min) end end +-- Storage helpers + +function moremesecons.get_storage_data(storage, name) + return { + tab = minetest.deserialize(storage:get_string(name)) or {}, + name = name, + storage = storage + } +end + +function moremesecons.set_data_to_pos(sto, pos, data) + sto.tab[minetest.hash_node_position(pos)] = data + sto.storage:set_string(sto.name, minetest.serialize(sto.tab)) +end + +function moremesecons.get_data_from_pos(sto, pos) + return sto.tab[minetest.hash_node_position(pos)] +end + +function moremesecons.remove_data_from_pos(sto, pos) + sto.tab[minetest.hash_node_position(pos)] = nil + sto.storage:set_string(sto.name, minetest.serialize(sto.tab)) +end + -- Vector helpers -- All the following functions are from the vector_extras mod (https://github.com/HybridDog/vector_extras). -- If you enable that mod, its functions will be used instead of the ones defined below From 4dbc96eafac9da4f04a36ec2dd7cfaaa1a80b8fe Mon Sep 17 00:00:00 2001 From: upsilon Date: Thu, 9 Apr 2020 17:02:31 +0200 Subject: [PATCH 02/13] New digiline interface for the adjustable player detector The name of the detected player can now be requested by sending {command = "get"} to the detector. The detection radius can be changed by sending {radius = value}. --- .../init.lua | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/moremesecons_adjustable_player_detector/init.lua b/moremesecons_adjustable_player_detector/init.lua index d704098..4cab0b7 100644 --- a/moremesecons_adjustable_player_detector/init.lua +++ b/moremesecons_adjustable_player_detector/init.lua @@ -37,18 +37,18 @@ local object_detector_scan = function (pos) local scan_all = scanname == "" local scan_names = scanname:split(',') local radius = meta:get_int("radius") - if radius == 0 then + if radius <= 0 then radius = 6 end for _,obj in pairs(minetest.get_objects_inside_radius(pos, radius)) do local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil! if isname ~= "" then if scan_all then - return true + return true, isname end for _, name in ipairs(scan_names) do if isname == name then - return true + return true, isname end end end @@ -65,12 +65,32 @@ local object_detector_digiline = { if channel ~= active_channel then return end - meta:set_string("scanname", msg) - if meta:get_string("formspec") ~= "" then + if type(msg) == "string" then + meta:set_string("scanname", msg) make_formspec(meta) + elseif type(msg) == "table" then + if msg.radius then + local r = tonumber(msg.radius) + if r then + meta:set_int("radius", tonumber(msg.radius)) + make_formspec(meta) + end + end + if msg.scanname then + meta:set_string("scanname", msg.scanname) + make_formspec(meta) + end + if msg.command and msg.command == "get" then + local found, name = object_detector_scan(pos) + if not found then + name = "" + end + digiline:receptor_send(pos, digiline.rules.default, channel, name) + end end end, - } + }, + receptor = {} } minetest.register_node("moremesecons_adjustable_player_detector:player_detector_off", { From 5d29cdce5b5ff8499c8e85cd2744413296adb9d8 Mon Sep 17 00:00:00 2001 From: upsilon Date: Thu, 9 Apr 2020 19:21:40 +0200 Subject: [PATCH 03/13] Avoid activating wireless that no longer exist. --- moremesecons_wireless/init.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/moremesecons_wireless/init.lua b/moremesecons_wireless/init.lua index f757016..b234198 100644 --- a/moremesecons_wireless/init.lua +++ b/moremesecons_wireless/init.lua @@ -120,6 +120,18 @@ local function register_wireless(pos) update_mod_storage() end +local function check_wireless_exists(pos) + local nn = minetest.get_node(pos).name + if nn:sub(1, 30) == "moremesecons_wireless:wireless" then + return true + elseif nn ~= "ignore" then + -- Defer the remove_wireless() call so it doesn't interfere + -- with ipairs(). + minetest.after(0, remove_wireless, pos) + return false + end +end + local is_jammed local function wireless_activate(pos) if is_jammed(pos) then @@ -137,7 +149,7 @@ local function wireless_activate(pos) minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_on"}) for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id then + if i ~= id and check_wireless_exists(wl_pos) then minetest.swap_node(wl_pos, {name = "moremesecons_wireless:wireless_on"}) mesecon.receptor_on(wl_pos) end @@ -159,7 +171,7 @@ local function wireless_deactivate(pos) minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_off"}) for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id then + if i ~= id and check_wireless_exists(wl_pos) then minetest.swap_node(wl_pos, {name = "moremesecons_wireless:wireless_off"}) mesecon.receptor_off(wl_pos) end @@ -181,7 +193,7 @@ local function on_digiline_receive(pos, node, channel, msg) end for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id then + if i ~= id and check_wireless_exists(wl_pos) then digiline:receptor_send(wl_pos, digiline.rules.default, channel, msg) end end From 8c8cdd38ff2cc31fecfbc36816fd0c2106762f5d Mon Sep 17 00:00:00 2001 From: upsilon Date: Thu, 9 Apr 2020 19:22:15 +0200 Subject: [PATCH 04/13] Add mesecons_luacontroller as a dependency to the luacontroller tool. --- moremesecons_luacontroller_tool/depends.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/moremesecons_luacontroller_tool/depends.txt b/moremesecons_luacontroller_tool/depends.txt index a259a42..001eb43 100644 --- a/moremesecons_luacontroller_tool/depends.txt +++ b/moremesecons_luacontroller_tool/depends.txt @@ -1,2 +1,3 @@ mesecons +mesecons_luacontroller moremesecons_utils From 899ea4aa29c5af82a60b2fd9bce682ae3278cbe2 Mon Sep 17 00:00:00 2001 From: upsilon Date: Thu, 9 Apr 2020 19:27:11 +0200 Subject: [PATCH 05/13] Wireless: remove legacy code. --- moremesecons_wireless/init.lua | 41 ---------------------------------- 1 file changed, 41 deletions(-) diff --git a/moremesecons_wireless/init.lua b/moremesecons_wireless/init.lua index b234198..58958d5 100644 --- a/moremesecons_wireless/init.lua +++ b/moremesecons_wireless/init.lua @@ -388,44 +388,3 @@ if moremesecons.setting("wireless", "enable_lbm", false) then action = register_wireless }) end - - --- Legacy -if storage and storage:get_string("wireless_rids") and storage:get_string("wireless_rids") ~= "" then - -- Upgrade mod storage! - local wireless_rids = minetest.deserialize(storage:get_string("wireless_rids")) - local old_wireless = table.copy(wireless) - wireless = {} - - minetest.after(0, function(old_wireless) - -- After loading all mods, try to guess owners based on the areas mod database. - -- That won't work for all wireless. Owners of remaining wireless will be set - -- to the first player using their formspec. - if not areas then - return - end - for RID, pos in ipairs(old_wireless) do - local numerous_owners = false - local owner - for _, area in pairs(areas:getAreasAtPos(pos)) do - if owner and area.owner ~= owner then - numerous_owners = true - break - end - owner = area.owner - end - - if not numerous_owners and owner then - set_owner(pos, owner) - set_channel(pos, minetest.get_meta(pos):get_string("channel")) - end - end - end, old_wireless) - - -- Remove wireless_rids from storage - storage:from_table({ - jammers = jammers, - wireless_meta = wireless_meta, - wireless = wireless - }) -end From be7982a453b2e44ac9f94b6d885721ed43a56327 Mon Sep 17 00:00:00 2001 From: upsilon Date: Sat, 11 Apr 2020 12:45:33 +0200 Subject: [PATCH 06/13] Major wireless refactor --- moremesecons_wireless/init.lua | 343 +++++++++++++++++++++------------ 1 file changed, 219 insertions(+), 124 deletions(-) diff --git a/moremesecons_wireless/init.lua b/moremesecons_wireless/init.lua index 58958d5..ebc7536 100644 --- a/moremesecons_wireless/init.lua +++ b/moremesecons_wireless/init.lua @@ -1,107 +1,145 @@ local storage = minetest.get_mod_storage() -local wireless = minetest.deserialize(storage:get_string("wireless")) or {} -local wireless_meta = minetest.deserialize(storage:get_string("wireless_meta")) or {owners = {}, channels = {}, ids = {}} -local jammers = minetest.deserialize(storage:get_string("jammers")) or {} +-- Names wireless_meta, and jammers were used in old versions of this mod. +-- There is legacy code at the end of this file to migrate the mod storage. +local wireless = minetest.deserialize(storage:get_string("networks")) or {} +local wireless_meta = moremesecons.get_storage_data(storage, "wireless_meta_2") +local jammers = moremesecons.get_storage_data(storage, "jammers_2") local function update_mod_storage() - storage:set_string("wireless", minetest.serialize(wireless)) - storage:set_string("wireless_meta", minetest.serialize(wireless_meta)) - storage:set_string("jammers", minetest.serialize(jammers)) + storage:set_string("networks", minetest.serialize(wireless)) end --- localize these functions with small names because they work fairly fast -local get = vector.get_data_from_pos -local set = vector.set_data_to_pos -local remove = vector.remove_data_from_pos - +local wireless_effector_off local function remove_wireless(pos) - local owner = get(wireless_meta.owners, pos.z,pos.y,pos.x) - if not owner or owner == "" then - return - end - remove(wireless_meta.owners, pos.z,pos.y,pos.x) - if not wireless[owner] or not next(wireless[owner]) then - wireless[owner] = nil + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then return end - local channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - if not channel or channel == "" then + if not wls.owner or wls.owner == "" then + moremesecons.remove_data_from_pos(wireless_meta, pos) return end - table.remove(wireless[owner][channel], get(wireless_meta.ids, pos.z,pos.y,pos.x)) - if #wireless[owner][channel] == 0 then - wireless[owner][channel] = nil - if not next(wireless[owner]) then - wireless[owner] = nil + if not wireless[wls.owner] or not next(wireless[wls.owner]) then + wireless[wls.owner] = nil + moremesecons.remove_data_from_pos(wireless_meta, pos) + return + end + + if not wls.channel or wls.channel == "" then + moremesecons.remove_data_from_pos(wireless_meta, pos) + return + end + + local network = wireless[wls.owner][wls.channel] + + if network.sources[wls.id] then + wireless_effector_off(pos) + end + + moremesecons.remove_data_from_pos(wireless_meta, pos) + + network.members[wls.id] = nil + if not next(network.members) then + wireless[wls.owner][wls.channel] = nil + if not next(wireless[wls.owner]) then + wireless[wls.owner] = nil end end - - remove(wireless_meta.channels, pos.z,pos.y,pos.x) - remove(wireless_meta.ids, pos.z,pos.y,pos.x) + update_mod_storage() end -local set_channel local function set_owner(pos, owner) if not owner or owner == "" then return end + + remove_wireless(pos) + local meta = minetest.get_meta(pos) - meta:set_string("owner", owner) - set(wireless_meta.owners, pos.z,pos.y,pos.x, owner) + if meta then + meta:set_string("owner", owner) + end + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) or {} + wls.owner = owner + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + if not wireless[owner] then wireless[owner] = {} end - local channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - if channel and channel ~= "" then - if not wireless[owner][channel] then - wireless[owner][channel] = {} - end - set_channel(pos, channel) + if meta then + meta:set_string("infotext", "Wireless owned by " .. owner .. " on " .. ((wls.channel and wls.channel ~= "") and "channel " .. wls.channel or "undefined channel")) end - - meta:set_string("infotext", "Wireless owned by " .. owner .. " on " .. ((channel and channel ~= "") and "channel " .. channel or "undefined channel")) end -function set_channel(pos, channel) +local wireless_receptor_on +local wireless_receptor_off +local wireless_effector_on +local function set_channel(pos, channel) if not channel or channel == "" then return end local meta = minetest.get_meta(pos) - local owner = get(wireless_meta.owners, pos.z,pos.y,pos.x) - if not owner or owner == "" then + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls or wls.owner == "" then return end - local old_channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - if old_channel and old_channel ~= "" and old_channel ~= channel then + if wls.id then remove_wireless(pos) - set_owner(pos, owner) end - meta:set_string("channel", channel) - set(wireless_meta.channels, pos.z,pos.y,pos.x, channel) - if not wireless[owner] then - wireless[owner] = {} + if meta then + meta:set_string("channel", channel) end - if not wireless[owner][channel] then - wireless[owner][channel] = {} + wls.channel = channel + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if not wireless[wls.owner] then + wireless[wls.owner] = {} + end + if not wireless[wls.owner][channel] then + wireless[wls.owner][channel] = { + members = {}, + sources = {} + } end - local id = get(wireless_meta.ids, pos.z,pos.y,pos.x) - if id then - wireless[owner][channel][id] = pos + -- Find the first free ID + local id = 1 + while wireless[wls.owner][channel].members[id] do + id = id + 1 + end + wls.id = id + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + local network = wireless[wls.owner][channel] + + network.members[id] = pos + + if meta then + meta:set_int("id", id) + end + + update_mod_storage() + + if meta then + meta:set_string("infotext", "Wireless owned by " .. wls.owner .. " on channel " .. channel) + end + + if wls.effector then + wireless_effector_on(pos) + elseif next(network.sources) then + wireless_receptor_on(pos, id, network, false) else - table.insert(wireless[owner][channel], pos) - meta:set_int("id", #wireless[owner][channel]) - set(wireless_meta.ids, pos.z,pos.y,pos.x, #wireless[owner][channel]) + wireless_receptor_off(pos, id, network, false) end - - meta:set_string("infotext", "Wireless owned by " .. owner .. " on channel " .. channel) end local function register_wireless(pos) @@ -110,14 +148,14 @@ local function register_wireless(pos) if owner == "" then return end + remove_wireless(pos) + set_owner(pos, owner) local channel = meta:get_string("channel") if channel ~= "" then set_channel(pos, channel) end - - update_mod_storage() end local function check_wireless_exists(pos) @@ -126,56 +164,93 @@ local function check_wireless_exists(pos) return true elseif nn ~= "ignore" then -- Defer the remove_wireless() call so it doesn't interfere - -- with ipairs(). + -- with pairs(). minetest.after(0, remove_wireless, pos) return false end end +function wireless_receptor_on(pos, id, network, check) + if check == false or check_wireless_exists(pos) then + minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_on"}) + if not network.sources[id] then + mesecon.receptor_on(pos) + end + end +end + +function wireless_receptor_off(pos, id, network, check) + if check == false or check_wireless_exists(pos) then + minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_off"}) + mesecon.receptor_off(pos) + end +end + +function activate_network(owner, channel) + local network = wireless[owner][channel] + for i, wl_pos in pairs(network.members) do + wireless_receptor_on(wl_pos, id, network) + end +end + +local function deactivate_network(owner, channel) + local network = wireless[owner][channel] + for i, wl_pos in pairs(network.members) do + wireless_receptor_off(wl_pos, i, network) + end +end + local is_jammed -local function wireless_activate(pos) +function wireless_effector_on(pos) if is_jammed(pos) then -- jamming doesn't disallow receiving signals, only sending them return end - local channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - local owner = get(wireless_meta.owners, pos.z,pos.y,pos.x) - local id = get(wireless_meta.ids, pos.z,pos.y,pos.x) - - if owner == "" or not wireless[owner] or channel == "" or not wireless[owner][channel] then + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then return end - minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_on"}) - for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id and check_wireless_exists(wl_pos) then - minetest.swap_node(wl_pos, {name = "moremesecons_wireless:wireless_on"}) - mesecon.receptor_on(wl_pos) - end + wls.effector = true + + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if wls.owner == "" or not wireless[wls.owner] or wls.channel == "" or not wireless[wls.owner][wls.channel] then + return end + + local network = wireless[wls.owner][wls.channel] + network.sources[wls.id] = true + activate_network(wls.owner, wls.channel) + + update_mod_storage() end -local function wireless_deactivate(pos) - if is_jammed(pos) then +function wireless_effector_off(pos) + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then return end - local channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - local owner = get(wireless_meta.owners, pos.z,pos.y,pos.x) - local id = get(wireless_meta.ids, pos.z,pos.y,pos.x) + wls.effector = nil + moremesecons.set_data_to_pos(wireless_meta, pos, wls) - if owner == "" or not wireless[owner] or channel == "" or not wireless[owner][channel] then + if wls.owner == "" or not wireless[wls.owner] or wls.channel == "" or not wireless[wls.owner][wls.channel] then return end - minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_off"}) - for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id and check_wireless_exists(wl_pos) then - minetest.swap_node(wl_pos, {name = "moremesecons_wireless:wireless_off"}) - mesecon.receptor_off(wl_pos) - end + local network = wireless[wls.owner][wls.channel] + network.sources[wls.id] = nil + if not next(network.sources) then + deactivate_network(wls.owner, wls.channel) + else + -- There is another source in the network. Turn this wireless into + -- a receptor. + mesecon.receptor_on(pos) end + + update_mod_storage() end local function on_digiline_receive(pos, node, channel, msg) @@ -184,17 +259,15 @@ local function on_digiline_receive(pos, node, channel, msg) return end - local channel = get(wireless_meta.channels, pos.z,pos.y,pos.x) - local owner = get(wireless_meta.owners, pos.z,pos.y,pos.x) - local id = get(wireless_meta.ids, pos.z,pos.y,pos.x) + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) - if owner == "" or not wireless[owner] or channel == "" or not wireless[owner][channel] then + if wls.owner == "" or not wireless[wls.owner] or channel == "" or not wireless[wls.owner][wls.channel] then return end - for i, wl_pos in ipairs(wireless[owner][channel]) do - if i ~= id and check_wireless_exists(wl_pos) then - digiline:receptor_send(wl_pos, digiline.rules.default, channel, msg) + for i, wl_pos in pairs(wireless[wls.owner][wls.channel].members) do + if i ~= wls.id and check_wireless_exists(wl_pos) then + digiline:receptor_send(wl_pos, digiline.rules.default, wls.channel, msg) end end end @@ -215,13 +288,11 @@ mesecon.register_node("moremesecons_wireless:wireless", { end, on_destruct = function(pos) remove_wireless(pos) - update_mod_storage() mesecon.receptor_off(pos) end, after_place_node = function(pos, placer) local placername = placer:get_player_name() set_owner(pos, placer:get_player_name()) - update_mod_storage() end, on_receive_fields = function(pos, _, fields, player) local meta = minetest.get_meta(pos) @@ -232,7 +303,6 @@ mesecon.register_node("moremesecons_wireless:wireless", { -- Old wireless if not minetest.is_protected(pos, playername) then set_owner(pos, playername) - update_mod_storage() else return end @@ -240,58 +310,48 @@ mesecon.register_node("moremesecons_wireless:wireless", { if playername == owner then set_channel(pos, fields.channel) - update_mod_storage() end end, }, { tiles = {"moremesecons_wireless_off.png"}, groups = {cracky=3}, mesecons = {effector = { - action_on = wireless_activate, + action_on = wireless_effector_on }}, }, { tiles = {"moremesecons_wireless_on.png"}, groups = {cracky=3, not_in_creative_inventory=1}, mesecons = {effector = { - action_off = wireless_deactivate + action_off = wireless_effector_off }}, }) minetest.register_alias("moremesecons_wireless:wireless", "moremesecons_wireless:wireless_off") -local jammers = {} -local function add_jammer(pos) - if get(jammers, pos.z,pos.y,pos.x) then - return - end - set(jammers, pos.z,pos.y,pos.x, true) - update_mod_storage() -end - local function remove_jammer(pos) - remove(jammers, pos.z,pos.y,pos.x) - update_mod_storage() + moremesecons.remove_data_from_pos(jammers, pos) +end + +local function add_jammer(pos) + remove_jammer(pos) + moremesecons.set_data_to_pos(jammers, pos, true) end --- looks big, but should work fast function is_jammed(pos) local JAMMER_MAX_DISTANCE = moremesecons.setting("wireless", "jammer_max_distance", 15, 1) + local JAMMER_MAX_DISTANCE_SQUARE = JAMMER_MAX_DISTANCE^2 -- Cache this result - local pz,py,px = vector.unpack(pos) - for z,yxs in pairs(jammers) do - if math.abs(pz-z) <= JAMMER_MAX_DISTANCE then - for y,xs in pairs(yxs) do - if math.abs(py-y) <= JAMMER_MAX_DISTANCE then - for x in pairs(xs) do - if math.abs(px-x) <= JAMMER_MAX_DISTANCE - and (px-x)^2+(py-y)^2+(pz-z)^2 <= JAMMER_MAX_DISTANCE^2 then - return true - end - end - end - end + for pos_hash, _ in pairs(jammers.tab) do + local j_pos = minetest.get_position_from_hash(pos_hash) + -- Fast comparisons first + if math.abs(pos.x - j_pos.x) <= JAMMER_MAX_DISTANCE and + math.abs(pos.y - j_pos.y) <= JAMMER_MAX_DISTANCE and + math.abs(pos.z - j_pos.z) <= JAMMER_MAX_DISTANCE and + (pos.x - j_pos.x)^2 + (pos.y - j_pos.y)^2 + (pos.z - j_pos.z)^2 <= JAMMER_MAX_DISTANCE_SQUARE then + return true end end + return false end @@ -388,3 +448,38 @@ if moremesecons.setting("wireless", "enable_lbm", false) then action = register_wireless }) end + +-- Legacy +if storage:get_string("wireless_meta_2") == "" then + local wireless_meta_1 = minetest.deserialize(storage:get_string("wireless_meta")) + if not wireless_meta_1 then + return + end + + minetest.log("action", "[moremesecons_wireless] Migrating mod storage data...") + local jammers_1 = minetest.deserialize(storage:get_string("jammers")) + + local get = vector.get_data_from_pos + local set = vector.set_data_to_pos + local remove = vector.remove_data_from_pos + + for z, data_z in pairs(wireless_meta_1.owners) do + for y, data_y in pairs(data_z) do + for x, owner in pairs(data_y) do + local pos = {x = x, y = y, z = z} + set_owner(pos, owner) + set_channel(pos, get(wireless_meta_1.channels, z,y,x)) + end + end + end + + for z, data_z in pairs(jammers_1) do + for y, data_y in pairs(data_z) do + for x, jammer in pairs(data_y) do + local pos = {x = x, y = y, z = z} + moremesecons.set_data_to_pos(jammers, pos, jammer) + end + end + end + minetest.log("action", "[moremesecons_wireless] Done!") +end From 54030d1620a1ab8dd59fb1a76a10a0f4f5f4cd5e Mon Sep 17 00:00:00 2001 From: upsilon Date: Sat, 11 Apr 2020 13:01:17 +0200 Subject: [PATCH 07/13] Wireless: transmit digilines messages on all channels --- moremesecons_wireless/init.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/moremesecons_wireless/init.lua b/moremesecons_wireless/init.lua index ebc7536..5d163ff 100644 --- a/moremesecons_wireless/init.lua +++ b/moremesecons_wireless/init.lua @@ -254,8 +254,7 @@ function wireless_effector_off(pos) end local function on_digiline_receive(pos, node, channel, msg) - local setchan = minetest.get_meta(pos):get_string("channel") -- Note : the digiline channel is the same as the wireless channel. TODO: Making two different channels and a more complex formspec ? - if channel ~= setchan or is_jammed(pos) or setchan == "" then + if is_jammed(pos) then return end @@ -267,7 +266,7 @@ local function on_digiline_receive(pos, node, channel, msg) for i, wl_pos in pairs(wireless[wls.owner][wls.channel].members) do if i ~= wls.id and check_wireless_exists(wl_pos) then - digiline:receptor_send(wl_pos, digiline.rules.default, wls.channel, msg) + digiline:receptor_send(wl_pos, digiline.rules.default, channel, msg) end end end From 9aa0e6ab3d83ae3fcd65968ef617619b72681356 Mon Sep 17 00:00:00 2001 From: HybridDog Date: Mon, 13 Apr 2020 18:11:34 +0200 Subject: [PATCH 08/13] Add MapDataStorage code as replacement for get_data_from_pos etc. In comparison to using Minetest's hash_node_position, this saves additional information about the z-only and zy-only components, which is what the vector_extras code did. In comparison to the old vector_extras code, this does not create lots of lua tables, which is slow, but instead uses one table as hashmap. --- moremesecons_utils/init.lua | 238 +++++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 3 deletions(-) diff --git a/moremesecons_utils/init.lua b/moremesecons_utils/init.lua index 1a6d2eb..37c513f 100644 --- a/moremesecons_utils/init.lua +++ b/moremesecons_utils/init.lua @@ -52,9 +52,241 @@ function moremesecons.remove_data_from_pos(sto, pos) sto.storage:set_string(sto.name, minetest.serialize(sto.tab)) end --- Vector helpers --- All the following functions are from the vector_extras mod (https://github.com/HybridDog/vector_extras). --- If you enable that mod, its functions will be used instead of the ones defined below +-- Some additional vector helpers + +-- The same as minetest.hash_node_position; I copied it to ensure backwards +-- compatibility and used hexadecimal number notation +local function node_position_key(pos) + return (pos.z + 0x8000) * 0x10000 * 0x10000 + + (pos.y + 0x8000) * 0x10000 + + pos.x + 0x8000 +end + +local MapDataStorage = {} +setmetatable(MapDataStorage, {__call = function() + local obj = {} + setmetatable(obj, MapDataStorage) + return obj +end}) +MapDataStorage.__index = { + getAt = function(self, pos) + return self[node_position_key(pos)] + end, + setAt = function(self, pos, data) + -- If x, y or z is omitted, the key corresponds to a position outside + -- of the map (hopefully), so it can be used to skip lines and planes + local vi_z = (pos.z + 0x8000) * 0x10000 * 0x10000 + local vi_zy = vi_z + (pos.y + 0x8000) * 0x10000 + local vi = vi_zy + pos.x + 0x8000 + local is_new = self[vi] == nil + self[vi] = data + if is_new then + self[vi_z] = (self[vi_z] or 0) + 1 + self[vi_zy] = (self[vi_zy] or 0) + 1 + end + end, + removeAt = function(self, pos) + local vi_z = (pos.z + 0x8000) * 0x10000 * 0x10000 + local vi_zy = vi_z + (pos.y + 0x8000) * 0x10000 + local vi = vi_zy + pos.x + 0x8000 + if self[vi] == nil then + -- Nothing to remove + return + end + self[vi] = nil + -- Update existence information for the xy plane and x line + self[vi_z] = self[vi_z] - 1 + if self[vi_z] == 0 then + self[vi_z] = nil + self[vi_zy] = nil + return + end + self[vi_zy] = self[vi_zy] - 1 + if self[vi_zy] == 0 then + self[vi_zy] = nil + end + end, + iter = function(self, pos1, pos2) + local ystride = 0x10000 + local zstride = 0x10000 * 0x10000 + + -- Skip z values where no data can be found + pos1 = vector.new(pos1) + local vi_z = (pos1.z + 0x8000) * 0x10000 * 0x10000 + while not self[vi_z] do + pos1.z = pos1.z + 1 + vi_z = vi_z + zstride + if pos1.z > pos2.z then + -- There are no values to iterate through + return function() return end + end + end + -- Skipping y values is not yet implemented and may require much code + + local xrange = pos2.x - pos1.x + 1 + local yrange = pos2.y - pos1.y + 1 + local zrange = pos2.z - pos1.z + 1 + + -- x-only and y-only parts of the vector index of pos1 + local vi_y = (pos1.y + 0x8000) * 0x10000 + local vi_x = pos1.x + 0x8000 + + local y = 0 + local z = 0 + + local vi = node_position_key(pos1) + local pos = vector.new(pos1) + local nextaction = vi + xrange + pos.x = pos.x - 1 + vi = vi - 1 + local function iterfunc() + -- continue along x until it needs to jump + vi = vi + 1 + pos.x = pos.x + 1 + if vi ~= nextaction then + local v = self[vi] + if v == nil then + -- No data here + return iterfunc() + end + -- The returned position must not be changed + return pos, v + end + + -- Reset x position + vi = vi - xrange + -- Go along y until pos2.y is exceeded + while true do + y = y + 1 + pos.y = pos.y + 1 + -- Set vi to index(pos1.x, pos1.y + y, pos1.z + z) + vi = vi + ystride + if y == yrange then + break + end + if self[vi - vi_x] then + nextaction = vi + xrange + + vi = vi - 1 + pos.x = pos1.x - 1 + return iterfunc() + end + -- Nothing along this x line, so increase y again + end + + -- Go back along y + vi = vi - yrange * ystride + y = 0 + pos.y = pos1.y + -- Go along z until pos2.z is exceeded + while true do + z = z + 1 + pos.z = pos.z + 1 + vi = vi + zstride + if z == zrange then + -- Cuboid finished, return nil + return + end + if self[vi - vi_x - vi_y] then + y = 0 + nextaction = vi + xrange + + vi = vi - 1 + pos.x = pos1.x - 1 + return iterfunc() + end + -- Nothing in this xy plane, so increase z again + end + end + return iterfunc + end, + iterAll = function(self) + local pairsfunc = pairs(self) + local function iterfunc() + local vi, v = pairsfunc() + if not vi then + return + end + local z = math.floor(vi / (0x10000 * 0x10000)) + vi = vi - z * 0x10000 * 0x10000 + local y = math.floor(vi / 0x10000) + if y == 0 or z == 0 then + -- The index does not refer to a position inside the map + return iterfunc() + end + local x = vi - y * 0x10000 - 0x8000 + y = y - 0x8000 + z = z - 0x8000 + return {x=x, y=y, z=z}, v + end + end, +} +moremesecons.MapDataStorage = MapDataStorage + + +-- This testing code shows an example usage of the MapDataStorage code +local function do_test() + print("Test if iter returns correct positions when a lot is set") + local data = MapDataStorage() + local k = 0 + for x = -5, 3 do + for y = -5, 3 do + for z = -5, 3 do + k = k + 1 + data:setAt({x=x, y=y, z=z}, k) + end + end + end + local expected_positions = {} + for z = -4, 2 do + for y = -4, 2 do + for x = -4, 2 do + expected_positions[#expected_positions+1] = {x=x, y=y, z=z} + end + end + end + local i = 0 + for pos, v in data:iter({x=-4, y=-4, z=-4}, {x=2, y=2, z=2}) do + i = i + 1 + assert(vector.equals(pos, expected_positions[i])) + end + + print("Test if iter works correctly on a corner") + local found = false + for pos, v in data:iter({x=-8, y=-7, z=-80}, {x=-5, y=-5, z=-5}) do + assert(not found) + found = true + assert(vector.equals(pos, {x=-5, y=-5, z=-5})) + end + assert(found) + + print("Test if iter finds all corners") + local expected_positions = {} + local k = 1 + for _, z in ipairs({-9, -6}) do + for _, y in ipairs({-9, -6}) do + for _, x in ipairs({-8, -6}) do + local pos = {x=x, y=y, z=z} + expected_positions[#expected_positions+1] = pos + data:setAt(pos, k) + k = k + 1 + end + end + end + local i = 1 + for pos, v in data:iter({x=-8, y=-9, z=-9}, {x=-6, y=-6, z=-6}) do + assert(v == i) + assert(vector.equals(pos, expected_positions[i])) + i = i + 1 + --~ print("found " .. minetest.pos_to_string(pos)) + end + assert(i == 8 + 1, "Not enough or too many corners found") + + --~ data:iterAll() +end + +do_test() + if not vector.get_data_from_pos then function vector.get_data_from_pos(tab, z,y,x) From 0000cfb474cbf9e10ee3234a469be78acb4f6b5a Mon Sep 17 00:00:00 2001 From: HybridDog Date: Mon, 13 Apr 2020 19:30:15 +0200 Subject: [PATCH 09/13] Remove old vector_extras code and use the MapDataStorage --- README.md | 10 +- moremesecons_jammer/init.lua | 34 ++---- moremesecons_luacontroller_tool/init.lua | 4 - moremesecons_teleporter/init.lua | 14 +-- moremesecons_utils/depends.txt | 1 - moremesecons_utils/init.lua | 145 +++++++++++++++-------- moremesecons_wireless/init.lua | 10 +- 7 files changed, 124 insertions(+), 94 deletions(-) delete mode 100644 moremesecons_utils/depends.txt diff --git a/README.md b/README.md index fcb429a..f58e817 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # MoreMesecons -Based on Mesecons by Jeija -By @paly2 and @HybridDog -With the participation of @LeMagnesium (bugfix), @Ataron (textures), @JAPP (texture). +Based on Mesecons by Jeija
+By @paly2 and @HybridDog
+With the participation of @LeMagnesium (bugfix), @Ataron (textures), @JAPP (texture). -Dependencies: [Mesecons](https://github.com/Jeija/minetest-mod-mesecons/) -Optional dependencies: [vector_extras](https://github.com/HybridDog/vector_extras/) [digilines](https://github.com/minetest-mods/digilines) +Dependencies: [Mesecons](https://github.com/Jeija/minetest-mod-mesecons/)
+Optional dependencies: [digilines](https://github.com/minetest-mods/digilines) MoreMesecons is a mod for minetest which adds some mesecons items. diff --git a/moremesecons_jammer/init.lua b/moremesecons_jammer/init.lua index 92bf7dd..1e4e3f1 100644 --- a/moremesecons_jammer/init.lua +++ b/moremesecons_jammer/init.lua @@ -1,45 +1,35 @@ -- see wireless jammer -local get = vector.get_data_from_pos -local set = vector.set_data_to_pos -local remove = vector.remove_data_from_pos - local storage = minetest.get_mod_storage() -local jammers = minetest.deserialize(storage:get_string("jammers")) or {} +local jammers = moremesecons.load_MapDataStorage_legacy(storage, "jammers_v2", + "jammers") local function update_mod_storage() - storage:set_string("jammers", minetest.serialize(jammers)) + storage:set_string("jammers_v2", jammers:serialize()) end local function add_jammer(pos) - if get(jammers, pos.z,pos.y,pos.x) then + if jammers:getAt(pos) then return end - set(jammers, pos.z,pos.y,pos.x, true) + jammers:setAt(pos, true) update_mod_storage() end local function remove_jammer(pos) - remove(jammers, pos.z,pos.y,pos.x) + jammers:removeAt(pos) update_mod_storage() end local function is_jammed(pos) local JAMMER_MAX_DISTANCE = moremesecons.setting("jammer", "max_distance", 10, 1) - local pz,py,px = vector.unpack(pos) - for z,yxs in pairs(jammers) do - if math.abs(pz-z) <= JAMMER_MAX_DISTANCE then - for y,xs in pairs(yxs) do - if math.abs(py-y) <= JAMMER_MAX_DISTANCE then - for x in pairs(xs) do - if math.abs(px-x) <= JAMMER_MAX_DISTANCE - and (px-x)^2+(py-y)^2+(pz-z)^2 <= JAMMER_MAX_DISTANCE^2 then - return true - end - end - end - end + local minp = vector.subtract(pos, JAMMER_MAX_DISTANCE) + local maxp = vector.add(pos, JAMMER_MAX_DISTANCE) + for p in jammers:iter(minp, maxp) do + local d = vector.subtract(pos, p) + if d.x ^ 2 + d.y ^ 2 + d.z ^ 2 <= JAMMER_MAX_DISTANCE^2 then + return true end end return false diff --git a/moremesecons_luacontroller_tool/init.lua b/moremesecons_luacontroller_tool/init.lua index a50876e..ca53801 100644 --- a/moremesecons_luacontroller_tool/init.lua +++ b/moremesecons_luacontroller_tool/init.lua @@ -1,7 +1,3 @@ ---[[ -vector_extras there: https://github.com/HybridDog/vector_extras -]] - local templates = {MoreMesecons = { logic = [[-- AND port.a = pin.b and pin.c diff --git a/moremesecons_teleporter/init.lua b/moremesecons_teleporter/init.lua index 315630d..87bca1f 100644 --- a/moremesecons_teleporter/init.lua +++ b/moremesecons_teleporter/init.lua @@ -1,19 +1,19 @@ local storage = minetest.get_mod_storage() local teleporters = minetest.deserialize(storage:get_string("teleporters")) or {} -local teleporters_rids = minetest.deserialize(storage:get_string("teleporters_rids")) or {} -local jammers = minetest.deserialize(storage:get_string("jammers")) or {} +local teleporters_rids = moremesecons.load_MapDataStorage_legacy(storage, + "teleporters_rids_v2", "teleporters_rids") local function update_mod_storage() storage:set_string("teleporters", minetest.serialize(teleporters)) - storage:set_string("teleporters_rids", minetest.serialize(teleporters_rids)) + storage:set_string("teleporters_rids_v2", teleporters_rids:serialize()) end local function register(pos) - if not vector.get_data_from_pos(teleporters_rids, pos.z,pos.y,pos.x) then + if not teleporters_rids:getAt(pos) then table.insert(teleporters, pos) - vector.set_data_to_pos(teleporters_rids, pos.z,pos.y,pos.x, #teleporters) + teleporters_rids:setAt(pos, #teleporters) update_mod_storage() end end @@ -89,10 +89,10 @@ minetest.register_node("moremesecons_teleporter:teleporter", { sounds = default.node_sound_stone_defaults(), on_construct = register, on_destruct = function(pos) - local RID = vector.get_data_from_pos(teleporters_rids, pos.z,pos.y,pos.x) + local RID = teleporters_rids:getAt(pos) if RID then table.remove(teleporters, RID) - vector.remove_data_from_pos(teleporters_rids, pos.z,pos.y,pos.x) + teleporters_rids:removeAt(pos) update_mod_storage() end end, diff --git a/moremesecons_utils/depends.txt b/moremesecons_utils/depends.txt deleted file mode 100644 index 926e802..0000000 --- a/moremesecons_utils/depends.txt +++ /dev/null @@ -1 +0,0 @@ -vector_extras? diff --git a/moremesecons_utils/init.lua b/moremesecons_utils/init.lua index 37c513f..98ed9d8 100644 --- a/moremesecons_utils/init.lua +++ b/moremesecons_utils/init.lua @@ -85,6 +85,16 @@ MapDataStorage.__index = { self[vi_zy] = (self[vi_zy] or 0) + 1 end end, + setAtI = function(self, vi, data) + local vi_zy = vi - vi % 0x10000 + local vi_z = vi - vi % (0x10000 * 0x10000) + local is_new = self[vi] == nil + self[vi] = data + if is_new then + self[vi_z] = (self[vi_z] or 0) + 1 + self[vi_zy] = (self[vi_zy] or 0) + 1 + end + end, removeAt = function(self, pos) local vi_z = (pos.z + 0x8000) * 0x10000 * 0x10000 local vi_zy = vi_z + (pos.y + 0x8000) * 0x10000 @@ -201,9 +211,10 @@ MapDataStorage.__index = { return iterfunc end, iterAll = function(self) - local pairsfunc = pairs(self) + local previous_vi = nil local function iterfunc() - local vi, v = pairsfunc() + local vi, v = next(self, previous_vi) + previous_vi = vi if not vi then return end @@ -219,11 +230,91 @@ MapDataStorage.__index = { z = z - 0x8000 return {x=x, y=y, z=z}, v end + return iterfunc + end, + serialize = function(self) + local serialize_data = minetest.serialize + local indices = {} + local values = {} + local i = 1 + for pos, v in self:iterAll() do + local vi = node_position_key(pos) + -- Convert the double reversible to a string; + -- minetest.serialize does not (yet) do this + indices[i] = ("%a"):format(vi) + values[i] = serialize_data(v) + end + result = { + version = "MapDataStorage_v1", + indices = "return {" .. table.concat(indices, ",") .. "}", + values = "return {" .. table.concat(values, ",") .. "}", + } + return minetest.serialize(result) end, } +MapDataStorage.deserialize = function(txtdata) + local data = minetest.deserialize(txtdata) + if data.version ~= "MapDataStorage_v1" then + minetest.log("error", "Unknown MapDataStorage version: " .. + data.version) + end + -- I assume that minetest.deserialize correctly deserializes the indices, + -- which are in the %a format + indices = minetest.deserialize(data.indices) + values = minetest.deserialize(data.values) + data = MapDataStorage() + for i = 1,#indices do + local vi = indices[i] + local v = values[i] + data:setAtI(vi, v) + end + return data +end moremesecons.MapDataStorage = MapDataStorage +-- Legacy + +-- vector_extras there: https://github.com/HybridDog/vector_extras +-- Creates a MapDataStorage object from old vector_extras generated table +function moremesecons.load_old_data_from_pos(t) + local data = MapDataStorage() + for z, yxv in pairs(t) do + for y, xv in pairs(yxv) do + for x, v in pairs(xv) do + data:setAt({x=x, y=y, z=z}, v) + end + end + end + return data +end + +function moremesecons.load_old_dfp_storage(modstorage, name) + local data = minetest.deserialize(modstorage:get_string(name)) + if not data then + return + end + return moremesecons.load_old_data_from_pos(data) +end + +function moremesecons.load_MapDataStorage_legacy(modstorage, name, oldname) + local t_old = moremesecons.load_old_dfp_storage(modstorage, oldname) + local t + if t_old and t_old ~= "" then + t = t_old + modstorage:set_string(name, t:serialize()) + modstorage:set_string(oldname, nil) + return t + end + t = modstorage:get_string("teleporters_rids_v2") + if t and t ~= "" then + return MapDataStorage.deserialize(t) + end + return MapDataStorage() +end + + + -- This testing code shows an example usage of the MapDataStorage code local function do_test() print("Test if iter returns correct positions when a lot is set") @@ -284,53 +375,5 @@ local function do_test() --~ data:iterAll() end +--~ do_test() -do_test() - - -if not vector.get_data_from_pos then - function vector.get_data_from_pos(tab, z,y,x) - local data = tab[z] - if data then - data = data[y] - if data then - return data[x] - end - end - end -end - -if not vector.set_data_to_pos then - function vector.set_data_to_pos(tab, z,y,x, data) - if tab[z] then - if tab[z][y] then - tab[z][y][x] = data - return - end - tab[z][y] = {[x] = data} - return - end - tab[z] = {[y] = {[x] = data}} - end -end - -if not vector.remove_data_from_pos then - function vector.remove_data_from_pos(tab, z,y,x) - if vector.get_data_from_pos(tab, z,y,x) == nil then - return - end - tab[z][y][x] = nil - if not next(tab[z][y]) then - tab[z][y] = nil - end - if not next(tab[z]) then - tab[z] = nil - end - end -end - -if not vector.unpack then - function vector.unpack(pos) - return pos.z, pos.y, pos.x - end -end diff --git a/moremesecons_wireless/init.lua b/moremesecons_wireless/init.lua index 5d163ff..dbed9a3 100644 --- a/moremesecons_wireless/init.lua +++ b/moremesecons_wireless/init.lua @@ -458,16 +458,18 @@ if storage:get_string("wireless_meta_2") == "" then minetest.log("action", "[moremesecons_wireless] Migrating mod storage data...") local jammers_1 = minetest.deserialize(storage:get_string("jammers")) - local get = vector.get_data_from_pos - local set = vector.set_data_to_pos - local remove = vector.remove_data_from_pos + local get = function(t, pos) + -- FIXME: this does not test explicitly for false, + -- but channel is never false + return t[pos.z] and t[pos.z][pos.y] and t[pos.z][pos.y][pos.x] + end for z, data_z in pairs(wireless_meta_1.owners) do for y, data_y in pairs(data_z) do for x, owner in pairs(data_y) do local pos = {x = x, y = y, z = z} set_owner(pos, owner) - set_channel(pos, get(wireless_meta_1.channels, z,y,x)) + set_channel(pos, get(wireless_meta_1.channels, pos)) end end end From f2de7c89b1cbbf6eddfd441dbdf64f7609c61c71 Mon Sep 17 00:00:00 2001 From: upsilon Date: Wed, 29 Apr 2020 12:43:29 +0200 Subject: [PATCH 10/13] MapDataStorage: change serialization in mod storage Use minetest.serialize on the full values table instead of serializing each value independently and concatenating. --- moremesecons_utils/init.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/moremesecons_utils/init.lua b/moremesecons_utils/init.lua index 98ed9d8..c908be0 100644 --- a/moremesecons_utils/init.lua +++ b/moremesecons_utils/init.lua @@ -233,7 +233,6 @@ MapDataStorage.__index = { return iterfunc end, serialize = function(self) - local serialize_data = minetest.serialize local indices = {} local values = {} local i = 1 @@ -242,12 +241,12 @@ MapDataStorage.__index = { -- Convert the double reversible to a string; -- minetest.serialize does not (yet) do this indices[i] = ("%a"):format(vi) - values[i] = serialize_data(v) + values[i] = v end result = { version = "MapDataStorage_v1", indices = "return {" .. table.concat(indices, ",") .. "}", - values = "return {" .. table.concat(values, ",") .. "}", + values = minetest.serialize(values), } return minetest.serialize(result) end, @@ -260,8 +259,11 @@ MapDataStorage.deserialize = function(txtdata) end -- I assume that minetest.deserialize correctly deserializes the indices, -- which are in the %a format - indices = minetest.deserialize(data.indices) - values = minetest.deserialize(data.values) + local indices = minetest.deserialize(data.indices) + local values = minetest.deserialize(data.values) + if not indices or not values then + return MapDataStorage() + end data = MapDataStorage() for i = 1,#indices do local vi = indices[i] @@ -306,7 +308,7 @@ function moremesecons.load_MapDataStorage_legacy(modstorage, name, oldname) modstorage:set_string(oldname, nil) return t end - t = modstorage:get_string("teleporters_rids_v2") + t = modstorage:get_string(name) if t and t ~= "" then return MapDataStorage.deserialize(t) end From 7ba7a5cceb2e56c9f9f61ac0e806983da26a4483 Mon Sep 17 00:00:00 2001 From: upsilon Date: Wed, 29 Apr 2020 18:06:17 +0200 Subject: [PATCH 11/13] MapDataStorage: replace "%a" format with "%.17g" --- moremesecons_utils/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moremesecons_utils/init.lua b/moremesecons_utils/init.lua index c908be0..848381d 100644 --- a/moremesecons_utils/init.lua +++ b/moremesecons_utils/init.lua @@ -240,7 +240,7 @@ MapDataStorage.__index = { local vi = node_position_key(pos) -- Convert the double reversible to a string; -- minetest.serialize does not (yet) do this - indices[i] = ("%a"):format(vi) + indices[i] = ("%.17g"):format(vi) values[i] = v end result = { From de765f7f7bd3151711210c63ffae046bec27f7cd Mon Sep 17 00:00:00 2001 From: upsilon Date: Sat, 9 May 2020 13:18:44 +0200 Subject: [PATCH 12/13] LuaBlock: run in separate environment, add a "mem" table --- moremesecons_luablock/init.lua | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/moremesecons_luablock/init.lua b/moremesecons_luablock/init.lua index 3d93e54..7ce07c6 100644 --- a/moremesecons_luablock/init.lua +++ b/moremesecons_luablock/init.lua @@ -120,25 +120,30 @@ minetest.register_node("moremesecons_luablock:luablock", { minetest.log("warning", "[moremesecons_luablock] Metadata of LuaBlock at pos "..minetest.pos_to_string(npos).." does not match its mod storage data!") return end - -- We do absolutely no check there. - -- There is no limitation in the number of instruction the LuaBlock can execute - -- or the usage it can make of loops. - -- It is executed in the global namespace. - -- Remember: *The LuaBlock is highly dangerous and should be manipulated cautiously!* - local func, err = loadstring(code) + + local env = {} + for k, v in pairs(_G) do + env[k] = v + end + env.pos = table.copy(npos) + env.mem = minetest.deserialize(meta:get_string("mem")) or {} + + local func, err + if _VERSION == "Lua 5.1" then + func, err = loadstring(code) + if func then + setfenv(func, env) + end + else + func, err = load(code, nil, "t", env) + end if not func then meta:set_string("errmsg", err) make_formspec(meta, pos) return end - -- Set the "pos" global - local old_pos - if minetest.global_exists("pos") then - old_pos = pos -- In case there's already an existing "pos" global - end - pos = table.copy(npos) + local good, err = pcall(func) - pos = old_pos if not good then -- Runtime error meta:set_string("errmsg", err) @@ -146,6 +151,8 @@ minetest.register_node("moremesecons_luablock:luablock", { return end + meta:set_string("mem", minetest.serialize(env.mem)) + meta:set_string("errmsg", "") make_formspec(meta, pos) end From 67875f9c6e0bcbea6ffc4263ff5a887dae7d7378 Mon Sep 17 00:00:00 2001 From: upsilon Date: Sun, 10 May 2020 10:09:34 +0200 Subject: [PATCH 13/13] Fix bug allowing timegate duplication Fixes #13 --- moremesecons_timegate/init.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/moremesecons_timegate/init.lua b/moremesecons_timegate/init.lua index 87bda43..7872bab 100644 --- a/moremesecons_timegate/init.lua +++ b/moremesecons_timegate/init.lua @@ -25,11 +25,14 @@ local function timegate_activate(pos, node) node.name = "moremesecons_timegate:timegate_on" minetest.swap_node(pos, node) mesecon.receptor_on(pos) - minetest.after(time, function(pos, node) - mesecon.receptor_off(pos) - node.name = "moremesecons_timegate:timegate_off" - minetest.swap_node(pos, node) - end, pos, node) + minetest.after(time, function() + local node = minetest.get_node(pos) + if node.name == "moremesecons_timegate:timegate_on" then + mesecon.receptor_off(pos) + node.name = "moremesecons_timegate:timegate_off" + minetest.swap_node(pos, node) + end + end) end boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab