mirror of
https://github.com/joe7575/techpack.git
synced 2024-11-26 00:53:44 +01:00
SaferLua Controller revised (events, loop control, data structures,...)
This commit is contained in:
parent
96cb7b3ea1
commit
b06e59d31f
@ -8,41 +8,67 @@
|
|||||||
LGPLv2.1+
|
LGPLv2.1+
|
||||||
See LICENSE.txt for more information
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
store.lua:
|
data_struct.lua:
|
||||||
|
|
||||||
|
see https://github.com/joe7575/techpack/wiki/Data-Structures
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
safer_lua.StoreHelp = [[
|
safer_lua.DataStructHelp = [[
|
||||||
Store - a secure shell over the LUA table type.
|
Data structures as a secure shell over the LUA table type.
|
||||||
|
see https://github.com/joe7575/techpack/wiki/Data-Structures
|
||||||
|
|
||||||
For records:
|
'Arrays' are lists of elements, which can be addressed
|
||||||
tbl = Store() --> {}
|
by means of an index:
|
||||||
tbl.set(key,value) --> {key=value}
|
|
||||||
tbl.get(key) --> value
|
|
||||||
|
|
||||||
'key' can be a number or string
|
|
||||||
'value' can be number, string, boolean, or Store
|
|
||||||
Example: tbl.set("a","test")
|
|
||||||
|
|
||||||
For lists:
|
a = Array(1,2,3,4) --> {1,2,3,4}
|
||||||
tbl = Store(1,2,3,4) --> {1,2,3,4}
|
a.add(6) --> {1,2,3,4,6}
|
||||||
tbl.insert(pos, value)
|
a.set(2, 8) --> {1,8,3,4,6}
|
||||||
tbl.remove(pos)
|
a.insert(5,7) --> {1,8,3,4,7,6}
|
||||||
|
a.remove(3) --> {1,8,4,7,6}
|
||||||
'pos' must be a number
|
a.insert(1, "hello") --> {"hello",1,8,4,7,6}
|
||||||
|
a.size() --> function returns 10
|
||||||
|
|
||||||
|
Unlike arrays, which are indexed by a range of numbers,
|
||||||
|
'stores' are indexed by keys:
|
||||||
|
|
||||||
Methods:
|
s = Store() --> {}
|
||||||
tbl.set(key, value) --> add/set a value
|
s.set("val", 12) --> {val = 12}
|
||||||
tbl.get(key) --> read a value
|
s.get("val") --> returns 12
|
||||||
tbl.size() --> return the table size
|
s.set(0, "hello") --> {val = 12, [0] = "hello"}
|
||||||
tbl.capa() --> return the max. capacity
|
s.del("val") --> {[0] = "hello"}
|
||||||
tbl.insert(pos, value) --> insert into list
|
s.size() --> function returns 6
|
||||||
tbl.remove(pos) --> return and remove from list
|
|
||||||
tbl.sort() -- sort list
|
A 'set' is an unordered collection with no duplicate
|
||||||
tbl.dump() --> format as string (debugging)
|
elements.
|
||||||
|
|
||||||
|
s = Set("Tom", "Lucy")
|
||||||
|
--> {Tom = true, Lucy = true}
|
||||||
|
s.del("Tom") --> {Lucy = true}
|
||||||
|
s.add("Susi") --> {Lucy = true, Susi = true}
|
||||||
|
s.has("Susi") --> function returns `true`
|
||||||
|
s.has("Mike") --> function returns `false`
|
||||||
|
s.size() --> function returns 11
|
||||||
]]
|
]]
|
||||||
|
|
||||||
function safer_lua.Store(...)
|
local function var_count(v)
|
||||||
|
if type(v) == "number" then
|
||||||
|
return 1
|
||||||
|
elseif type(v) == "boolean" then
|
||||||
|
return 1
|
||||||
|
elseif v == nil then
|
||||||
|
return 0
|
||||||
|
elseif type(v) == "string" then
|
||||||
|
return #v
|
||||||
|
elseif type(v) == "table" then
|
||||||
|
return v.size()
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function safer_lua.Store()
|
||||||
|
|
||||||
local new_t = {__data__ = {}}
|
local new_t = {__data__ = {}}
|
||||||
local mt = {}
|
local mt = {}
|
||||||
@ -52,56 +78,21 @@ function safer_lua.Store(...)
|
|||||||
|
|
||||||
mt.__newindex = function(t, k, v) return end
|
mt.__newindex = function(t, k, v) return end
|
||||||
|
|
||||||
mt.count = function(v)
|
mt.count = var_count
|
||||||
if type(v) == "number" then
|
|
||||||
return 1
|
|
||||||
elseif type(v) == "boolean" then
|
|
||||||
return 1
|
|
||||||
elseif v == nil then
|
|
||||||
return 0
|
|
||||||
elseif type(v) == "string" then
|
|
||||||
return #v
|
|
||||||
elseif type(v) == "table" then
|
|
||||||
return v.size()
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for idx = 1,select('#',...) do
|
|
||||||
local v = select(idx,...)
|
|
||||||
local cnt = mt.count(v)
|
|
||||||
if cnt then
|
|
||||||
Count = Count + cnt
|
|
||||||
if Count < safer_lua.MaxTableSize then
|
|
||||||
rawset(new_t.__data__,idx, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
new_t.set = function(k,v)
|
new_t.set = function(k,v)
|
||||||
if type(k) == "number" then
|
if type(k) == "number" then
|
||||||
local cnt = mt.count(v)
|
Count = Count - mt.count(rawget(new_t.__data__, k))
|
||||||
cnt = cnt - mt.count(rawget(new_t.__data__, k))
|
Count = Count + mt.count(v)
|
||||||
if Count + cnt < safer_lua.MaxTableSize then
|
rawset(new_t.__data__,k,v)
|
||||||
rawset(new_t.__data__,k,v)
|
|
||||||
Count = Count + cnt
|
|
||||||
end
|
|
||||||
elseif type(k) == "string" then
|
elseif type(k) == "string" then
|
||||||
local cnt = mt.count(rawget(new_t.__data__, k))
|
if rawget(new_t.__data__, k) then -- has entry?
|
||||||
if cnt == 0 then -- new entry?
|
Count = Count - mt.count(rawget(new_t.__data__, k))
|
||||||
cnt = mt.count(v)
|
else
|
||||||
cnt = cnt + mt.count(k)
|
Count = Count + mt.count(k)
|
||||||
elseif v == nil then -- delete entry?
|
|
||||||
cnt = - cnt - mt.count(k)
|
|
||||||
else -- overwrite
|
|
||||||
cnt = mt.count(v) - cnt
|
|
||||||
end
|
|
||||||
|
|
||||||
if Count + cnt < safer_lua.MaxTableSize then
|
|
||||||
rawset(new_t.__data__,k,v)
|
|
||||||
Count = Count + cnt
|
|
||||||
end
|
end
|
||||||
|
Count = Count + mt.count(v)
|
||||||
|
rawset(new_t.__data__,k,v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -109,34 +100,127 @@ function safer_lua.Store(...)
|
|||||||
return rawget(new_t.__data__, k)
|
return rawget(new_t.__data__, k)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
new_t.del = function(k)
|
||||||
|
Count = Count - mt.count(k)
|
||||||
|
Count = Count - mt.count(rawget(new_t.__data__, k))
|
||||||
|
rawset(new_t.__data__,k,nil)
|
||||||
|
end
|
||||||
|
|
||||||
new_t.size = function(t)
|
new_t.size = function(t)
|
||||||
return Count
|
return Count
|
||||||
end
|
end
|
||||||
|
|
||||||
new_t.capa = function(t)
|
new_t.dump = function(size)
|
||||||
return safer_lua.MaxTableSize
|
size = size or 200
|
||||||
|
local s = dump(new_t.__data__)
|
||||||
|
if #s > size then s = s:sub(1, size).."..." end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable(new_t, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function safer_lua.Array(...)
|
||||||
|
|
||||||
|
local new_t = {__data__ = {}}
|
||||||
|
local mt = {}
|
||||||
|
|
||||||
|
-- `all` will represent the number of both
|
||||||
|
local Count = 0
|
||||||
|
|
||||||
|
mt.__newindex = function(t, k, v) return end
|
||||||
|
|
||||||
|
mt.count = var_count
|
||||||
|
|
||||||
|
for idx = 1,select('#',...) do
|
||||||
|
local v = select(idx,...)
|
||||||
|
local cnt = mt.count(v)
|
||||||
|
if cnt then
|
||||||
|
Count = Count + cnt
|
||||||
|
rawset(new_t.__data__,idx, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.add = function(v)
|
||||||
|
Count = Count + mt.count(v)
|
||||||
|
local i = #new_t.__data__ + 1
|
||||||
|
table.insert(new_t.__data__,i,v)
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.set = function(i,v)
|
||||||
|
i = math.min(#new_t.__data__, i)
|
||||||
|
Count = Count - mt.count(rawget(new_t.__data__, i))
|
||||||
|
Count = Count + mt.count(v)
|
||||||
|
rawset(new_t.__data__,i,v)
|
||||||
end
|
end
|
||||||
|
|
||||||
new_t.insert = function(v, i)
|
new_t.insert = function(i, v)
|
||||||
local cnt = mt.count(v)
|
Count = Count + mt.count(v)
|
||||||
if i == nil then i = #new_t.__data__ + 1 end
|
i = math.min(#new_t.__data__, i)
|
||||||
if Count + cnt < safer_lua.MaxTableSize then
|
table.insert(new_t.__data__,i,v)
|
||||||
table.insert(new_t.__data__,i,v)
|
|
||||||
Count = Count + cnt
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
new_t.remove = function(i)
|
new_t.remove = function(i)
|
||||||
local v = table.remove(new_t.__data__,i)
|
local v = table.remove(new_t.__data__,i)
|
||||||
local cnt = mt.count(v)
|
Count = Count - mt.count(v)
|
||||||
Count = Count - cnt
|
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
new_t.sort = function()
|
new_t.size = function(t)
|
||||||
table.sort(new_t.__data__)
|
return Count
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.dump = function(size)
|
||||||
|
size = size or 200
|
||||||
|
local s = dump(new_t.__data__)
|
||||||
|
if #s > size then s = s:sub(1, size).."..." end
|
||||||
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return setmetatable(new_t, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function safer_lua.Set(...)
|
||||||
|
|
||||||
|
local new_t = {__data__ = {}}
|
||||||
|
local mt = {}
|
||||||
|
|
||||||
|
-- `all` will represent the number of both
|
||||||
|
local Count = 0
|
||||||
|
|
||||||
|
mt.__newindex = function(t, k, v) return end
|
||||||
|
|
||||||
|
mt.count = var_count
|
||||||
|
|
||||||
|
for idx = 1,select('#',...) do
|
||||||
|
local v = select(idx,...)
|
||||||
|
local cnt = mt.count(v)
|
||||||
|
if cnt then
|
||||||
|
Count = Count + cnt
|
||||||
|
rawset(new_t.__data__,v, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.add = function(k)
|
||||||
|
Count = Count + mt.count(k)
|
||||||
|
rawset(new_t.__data__,k, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.del = function(k)
|
||||||
|
Count = Count - mt.count(k)
|
||||||
|
rawset(new_t.__data__,k, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.has = function(k)
|
||||||
|
return rawget(new_t.__data__, k) == true
|
||||||
|
end
|
||||||
|
|
||||||
|
new_t.size = function(t)
|
||||||
|
return Count
|
||||||
|
end
|
||||||
|
|
||||||
new_t.dump = function(size)
|
new_t.dump = function(size)
|
||||||
size = size or 200
|
size = size or 200
|
||||||
local s = dump(new_t.__data__)
|
local s = dump(new_t.__data__)
|
||||||
@ -144,5 +228,5 @@ function safer_lua.Store(...)
|
|||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(new_t, mt)
|
return setmetatable(new_t, mt)
|
||||||
end
|
end
|
||||||
|
@ -13,18 +13,24 @@
|
|||||||
]]--
|
]]--
|
||||||
|
|
||||||
safer_lua.MaxCodeSize = 2000 -- size in length of byte code
|
safer_lua.MaxCodeSize = 2000 -- size in length of byte code
|
||||||
safer_lua.MaxTableSize = 1000 -- number of table entries considering string lenghts
|
safer_lua.MaxTableSize = 1000 -- sum over all table sizes
|
||||||
|
|
||||||
|
|
||||||
|
local function memsize()
|
||||||
|
return safer_lua.MaxTableSize
|
||||||
|
end
|
||||||
|
|
||||||
local BASE_ENV = {
|
local BASE_ENV = {
|
||||||
|
Array = safer_lua.Array,
|
||||||
Store = safer_lua.Store,
|
Store = safer_lua.Store,
|
||||||
|
Set = safer_lua.Set,
|
||||||
|
memsize = memsize,
|
||||||
math = {
|
math = {
|
||||||
floor = math.floor,
|
floor = math.floor,
|
||||||
abs = math.abs,
|
abs = math.abs,
|
||||||
max = math.max,
|
max = math.max,
|
||||||
min = math.min,
|
min = math.min,
|
||||||
random = math.random,
|
random = math.random,
|
||||||
|
|
||||||
},
|
},
|
||||||
tonumber = tonumber,
|
tonumber = tonumber,
|
||||||
tostring = tostring,
|
tostring = tostring,
|
||||||
@ -39,6 +45,16 @@ local function map(dest, source)
|
|||||||
return dest
|
return dest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function calc_used_mem_size(env)
|
||||||
|
local size = 0
|
||||||
|
for key,val in pairs(env) do
|
||||||
|
if type(val) == "table" and val.size ~= nil then
|
||||||
|
size = size + val.size() or 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return size
|
||||||
|
end
|
||||||
|
|
||||||
function safer_lua.config(max_code_size, max_table_size)
|
function safer_lua.config(max_code_size, max_table_size)
|
||||||
safer_lua.MaxCodeSize = max_code_size
|
safer_lua.MaxCodeSize = max_code_size
|
||||||
safer_lua.MaxTableSize = max_table_size
|
safer_lua.MaxTableSize = max_table_size
|
||||||
@ -49,7 +65,7 @@ local function compile(pos, text, label, err_clbk)
|
|||||||
text = text:gsub("%$", "S:")
|
text = text:gsub("%$", "S:")
|
||||||
local code, err = loadstring(text)
|
local code, err = loadstring(text)
|
||||||
if not code then
|
if not code then
|
||||||
err = err:gsub("%[string .+%]:", label)
|
err = err:gsub("%(load%):", label)
|
||||||
err_clbk(pos, err)
|
err_clbk(pos, err)
|
||||||
else
|
else
|
||||||
return code
|
return code
|
||||||
@ -89,10 +105,18 @@ end
|
|||||||
|
|
||||||
function safer_lua.run_loop(pos, elapsed, code, err_clbk)
|
function safer_lua.run_loop(pos, elapsed, code, err_clbk)
|
||||||
local env = getfenv(code)
|
local env = getfenv(code)
|
||||||
env.event = false
|
|
||||||
env.ticks = env.ticks + 1
|
|
||||||
env.elapsed = elapsed
|
env.elapsed = elapsed
|
||||||
|
if elapsed < 0 then -- event?
|
||||||
|
env.event = true
|
||||||
|
else
|
||||||
|
env.event = false
|
||||||
|
env.ticks = env.ticks + 1
|
||||||
|
end
|
||||||
local res, err = pcall(code)
|
local res, err = pcall(code)
|
||||||
|
if calc_used_mem_size(env) > safer_lua.MaxTableSize then
|
||||||
|
err_clbk("Memory limit exceeded")
|
||||||
|
return false
|
||||||
|
end
|
||||||
if not res then
|
if not res then
|
||||||
err = err:gsub("%[string .+%]:", "loop() ")
|
err = err:gsub("%[string .+%]:", "loop() ")
|
||||||
err_clbk(pos, err)
|
err_clbk(pos, err)
|
||||||
@ -100,18 +124,3 @@ function safer_lua.run_loop(pos, elapsed, code, err_clbk)
|
|||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function safer_lua.run_event(pos, code, err_clbk)
|
|
||||||
local env = getfenv(code)
|
|
||||||
env.event = true
|
|
||||||
env.elapsed = 0
|
|
||||||
local res, err = pcall(code)
|
|
||||||
if not res then
|
|
||||||
err = err:gsub("%[string .+%]:", "loop() ")
|
|
||||||
err_clbk(pos, err)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,6 @@
|
|||||||
|
|
||||||
safer_lua = {}
|
safer_lua = {}
|
||||||
|
|
||||||
dofile(minetest.get_modpath("safer_lua") .. "/store.lua")
|
dofile(minetest.get_modpath("safer_lua") .. "/data_struct.lua")
|
||||||
dofile(minetest.get_modpath("safer_lua") .. "/scanner.lua")
|
dofile(minetest.get_modpath("safer_lua") .. "/scanner.lua")
|
||||||
dofile(minetest.get_modpath("safer_lua") .. "/environ.lua")
|
dofile(minetest.get_modpath("safer_lua") .. "/environ.lua")
|
@ -33,7 +33,7 @@ end
|
|||||||
|
|
||||||
local function register_battery(ext, percent)
|
local function register_battery(ext, percent)
|
||||||
minetest.register_node("sl_controller:battery"..ext, {
|
minetest.register_node("sl_controller:battery"..ext, {
|
||||||
description = "Battery",
|
description = "Battery "..ext,
|
||||||
inventory_image = 'sl_controller_battery_inventory.png',
|
inventory_image = 'sl_controller_battery_inventory.png',
|
||||||
wield_image = 'sl_controller_battery_inventory.png',
|
wield_image = 'sl_controller_battery_inventory.png',
|
||||||
tiles = {
|
tiles = {
|
||||||
|
@ -19,8 +19,8 @@ sl_controller.register_function("get_input", {
|
|||||||
num = tostring(num or "")
|
num = tostring(num or "")
|
||||||
return sl_controller.get_input(self.meta.number, num)
|
return sl_controller.get_input(self.meta.number, num)
|
||||||
end,
|
end,
|
||||||
help = " $get_input(num) --> 'on', 'off', or nil\n"..
|
help = ' $get_input(num) --> "on", "off", or nil\n'..
|
||||||
" Read local input value from device with number 'num'.\n"..
|
' Read local input value from device with number "num".\n'..
|
||||||
' example: inp = $get_input("1234")\n'..
|
' example: inp = $get_input("1234")\n'..
|
||||||
" The device has to be connected with the controller."
|
" The device has to be connected with the controller."
|
||||||
})
|
})
|
||||||
@ -30,12 +30,23 @@ sl_controller.register_function("get_status", {
|
|||||||
num = tostring(num or "")
|
num = tostring(num or "")
|
||||||
return tubelib.send_request(num, "state", nil)
|
return tubelib.send_request(num, "state", nil)
|
||||||
end,
|
end,
|
||||||
help = " $get_status(num) --> 'stopped', 'running',\n"..
|
help = " $get_status(num) ,\n"..
|
||||||
" 'standby', 'blocked' or 'fault'\n"..
|
" Read status from a remote device. See\n"..
|
||||||
" Read status from a remote device.\n"..
|
" https://github.com/joe7575/techpack/wiki/nodes\n"..
|
||||||
' example: sts = $get_status("1234")'
|
' example: sts = $get_status("1234")'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
sl_controller.register_function("get_fuel_status", {
|
||||||
|
cmnd = function(self, num)
|
||||||
|
num = tostring(num or "")
|
||||||
|
return tubelib.send_request(num, "fuel", nil)
|
||||||
|
end,
|
||||||
|
help = " $get_fuel_status(num)\n"..
|
||||||
|
" Read fuel status from Harverster and Quarry.\n"..
|
||||||
|
' Fuel status is one of: "full","empty"\n'..
|
||||||
|
' example: sts = $get_fuel_status("1234")'
|
||||||
|
})
|
||||||
|
|
||||||
sl_controller.register_function("time_as_str", {
|
sl_controller.register_function("time_as_str", {
|
||||||
cmnd = function(self)
|
cmnd = function(self)
|
||||||
local t = minetest.get_timeofday()
|
local t = minetest.get_timeofday()
|
||||||
@ -65,8 +76,8 @@ sl_controller.register_function("playerdetector", {
|
|||||||
num = tostring(num or "")
|
num = tostring(num or "")
|
||||||
return tubelib.send_request(num, "name", nil)
|
return tubelib.send_request(num, "name", nil)
|
||||||
end,
|
end,
|
||||||
help = " $playerdetector(num) --> e.g. 'Joe'\n"..
|
help = ' $playerdetector(num) --> e.g. "Joe"\n'..
|
||||||
" '' is returned if no layer is nearby.\n"..
|
' "" is returned if no player is nearby.\n'..
|
||||||
' example: name = $playerdetector("1234")'
|
' example: name = $playerdetector("1234")'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -77,9 +88,9 @@ sl_controller.register_action("send_cmnd", {
|
|||||||
tubelib.send_message(num, self.meta.owner, nil, text, nil)
|
tubelib.send_message(num, self.meta.owner, nil, text, nil)
|
||||||
end,
|
end,
|
||||||
help = " $send_cmnd(num, text)\n"..
|
help = " $send_cmnd(num, text)\n"..
|
||||||
" Send a command to the device with number 'num'.\n"..
|
' Send a command to the device with number "num".\n'..
|
||||||
" For most devices: 'on', 'off'\n"..
|
" For more help, see:\n"..
|
||||||
" Signal Tower: 'green', 'amber', 'red'\n"..
|
" https://github.com/joe7575/techpack/wiki/nodes\n"..
|
||||||
' example: $send_cmnd("1234", "on")'
|
' example: $send_cmnd("1234", "on")'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -91,7 +102,7 @@ sl_controller.register_action("display", {
|
|||||||
tubelib.send_message(num, self.meta.owner, nil, "row", {row = row, str = text1..text2..text3})
|
tubelib.send_message(num, self.meta.owner, nil, "row", {row = row, str = text1..text2..text3})
|
||||||
end,
|
end,
|
||||||
help = " $display(num, row, text,...)\n"..
|
help = " $display(num, row, text,...)\n"..
|
||||||
" Send a text line to the display with number 'num'.\n"..
|
' Send a text line to the display with number "num".\n'..
|
||||||
" 'row' is a value from 1..9\n"..
|
" 'row' is a value from 1..9\n"..
|
||||||
" The function accepts up to 3 text parameters\n"..
|
" The function accepts up to 3 text parameters\n"..
|
||||||
' example: $display("0123", 1, "Hello ", name, " !")'
|
' example: $display("0123", 1, "Hello ", name, " !")'
|
||||||
@ -103,8 +114,8 @@ sl_controller.register_action("clear_screen", {
|
|||||||
tubelib.send_message(num, self.meta.owner, nil, "clear", nil)
|
tubelib.send_message(num, self.meta.owner, nil, "clear", nil)
|
||||||
end,
|
end,
|
||||||
help = " $clear_screen(num)\n"..
|
help = " $clear_screen(num)\n"..
|
||||||
" Clear the screen of the display\n"..
|
' Clear the screen of the display\n'..
|
||||||
" with number 'num'.\n"..
|
' with number "num".\n'..
|
||||||
' example: $clear_screen("1234")'
|
' example: $clear_screen("1234")'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -140,8 +151,8 @@ sl_controller.register_action("door", {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
help = " %door(pos, text)\n"..
|
help = " $door(pos, text)\n"..
|
||||||
" Open/Close a door at position 'pos'\n"..
|
' Open/Close a door at position "pos"\n'..
|
||||||
' example: door("123,7,-1200", "close")\n'..
|
' example: $door("123,7,-1200", "close")\n'..
|
||||||
" Hint: Use the Tubelib Programmer to\ndetermine the door position."
|
" Hint: Use the Tubelib Programmer to\ndetermine the door position."
|
||||||
})
|
})
|
||||||
|
@ -14,28 +14,22 @@
|
|||||||
|
|
||||||
local sHELP = [[SaferLua Controller
|
local sHELP = [[SaferLua Controller
|
||||||
|
|
||||||
SaferLua is a subset of Lua with the following restrictions:
|
This controller is used to control and monitor
|
||||||
- No loop keywords like: for, while, repeat,...
|
Tubelib/TechPack machines.
|
||||||
- No table construction {..}
|
This controller can be programmed in Lua.
|
||||||
- Limited set of available functions
|
|
||||||
- Store() as alternative to Lua tables
|
|
||||||
|
|
||||||
The controller needs a battery nearby.
|
|
||||||
|
|
||||||
The controller will be restarted with every
|
See on GitHub for more help: goo.gl/Et8D6n
|
||||||
server start. That means, init() will be
|
|
||||||
called again and all variables are reset.
|
|
||||||
To store the data non-volatile, use a Server.
|
|
||||||
commands: $server_read(), $server_write().
|
|
||||||
|
|
||||||
See: goo.gl/WRWZgt
|
The controller only runs, if a battery is
|
||||||
|
placed nearby.
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local Cache = {}
|
local Cache = {}
|
||||||
|
|
||||||
local tCommands = {}
|
local tCommands = {}
|
||||||
local tFunctions = {" Overview", " Store"}
|
local tFunctions = {" Overview", " Data structures"}
|
||||||
local tHelpTexts = {[" Overview"] = sHELP, [" Store"] = safer_lua.StoreHelp}
|
local tHelpTexts = {[" Overview"] = sHELP, [" Data structures"] = safer_lua.DataStructHelp}
|
||||||
local sFunctionList = ""
|
local sFunctionList = ""
|
||||||
local tFunctionIndex = {}
|
local tFunctionIndex = {}
|
||||||
|
|
||||||
@ -83,10 +77,33 @@ sl_controller.register_action("print", {
|
|||||||
text3 = tostring(text3 or "")
|
text3 = tostring(text3 or "")
|
||||||
output(pos, text1..text2..text3)
|
output(pos, text1..text2..text3)
|
||||||
end,
|
end,
|
||||||
help = "$print(text,...)\n"..
|
help = " $print(text,...)\n"..
|
||||||
"Send a text line to the output window.\n"..
|
" Send a text line to the output window.\n"..
|
||||||
"The function accepts up to 3 text strings\n"..
|
" The function accepts up to 3 text strings\n"..
|
||||||
'e.g. $print("Hello ", name, " !")'
|
' e.g. $print("Hello ", name, " !")'
|
||||||
|
})
|
||||||
|
|
||||||
|
sl_controller.register_action("loopcycle", {
|
||||||
|
cmnd = function(self, cycletime)
|
||||||
|
cycletime = math.floor(tonumber(cycletime) or 0)
|
||||||
|
local meta = minetest.get_meta(self.meta.pos)
|
||||||
|
meta:set_int("cycletime", cycletime)
|
||||||
|
meta:set_int("cyclecount", 0)
|
||||||
|
end,
|
||||||
|
help = "$loopcycle(seconds)\n"..
|
||||||
|
" This function allows to change the\n"..
|
||||||
|
" call frequency of the loop() function.\n"..
|
||||||
|
" value is in seconds, 0 = disable\n"..
|
||||||
|
' e.g. $loopcycle(10)'
|
||||||
|
})
|
||||||
|
|
||||||
|
sl_controller.register_action("events", {
|
||||||
|
cmnd = function(self, event)
|
||||||
|
self.events = event or false
|
||||||
|
end,
|
||||||
|
help = "$events(true/false)\n"..
|
||||||
|
" Enable/disable event handling.\n"..
|
||||||
|
' e.g. $events(true) -- enable events'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -224,6 +241,9 @@ local function start_controller(pos)
|
|||||||
|
|
||||||
meta:set_string("output", "<press update>")
|
meta:set_string("output", "<press update>")
|
||||||
meta:set_string("formspec", formspec3(meta))
|
meta:set_string("formspec", formspec3(meta))
|
||||||
|
meta:set_int("cycletime", 1)
|
||||||
|
meta:set_int("cyclecount", 0)
|
||||||
|
meta:set_int("cpu", 0)
|
||||||
|
|
||||||
if compile(pos, meta, number) then
|
if compile(pos, meta, number) then
|
||||||
meta:set_int("state", tubelib.RUNNING)
|
meta:set_int("state", tubelib.RUNNING)
|
||||||
@ -266,12 +286,8 @@ local function update_battery(meta, cpu)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function on_timer(pos, elapsed)
|
local function call_loop(pos, meta, elapsed)
|
||||||
local t = minetest.get_us_time()
|
local t = minetest.get_us_time()
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
if meta:get_int("state") ~= tubelib.RUNNING then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local number = meta:get_string("number")
|
local number = meta:get_string("number")
|
||||||
if Cache[number] or compile(pos, meta, number) then
|
if Cache[number] or compile(pos, meta, number) then
|
||||||
|
|
||||||
@ -293,6 +309,20 @@ local function on_timer(pos, elapsed)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function on_timer(pos, elapsed)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
-- considering cycle frequency
|
||||||
|
local cycletime = meta:get_int("cycletime") or 1
|
||||||
|
local cyclecount = (meta:get_int("cyclecount") or 0) + 1
|
||||||
|
if cyclecount < cycletime then
|
||||||
|
meta:set_int("cyclecount", cyclecount)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
meta:set_int("cyclecount", 0)
|
||||||
|
|
||||||
|
return call_loop(pos, meta, elapsed)
|
||||||
|
end
|
||||||
|
|
||||||
local function on_receive_fields(pos, formname, fields, player)
|
local function on_receive_fields(pos, formname, fields, player)
|
||||||
if minetest.is_protected(pos, player:get_player_name()) then
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
return
|
return
|
||||||
@ -369,7 +399,6 @@ minetest.register_node("sl_controller:controller", {
|
|||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local number = tubelib.add_node(pos, "sl_controller:controller")
|
local number = tubelib.add_node(pos, "sl_controller:controller")
|
||||||
meta:set_string("owner", placer:get_player_name())
|
meta:set_string("owner", placer:get_player_name())
|
||||||
--print("after_place_node", number)
|
|
||||||
meta:set_string("number", number)
|
meta:set_string("number", number)
|
||||||
meta:set_int("state", tubelib.STOPPED)
|
meta:set_int("state", tubelib.STOPPED)
|
||||||
meta:set_string("init", "-- called only once")
|
meta:set_string("init", "-- called only once")
|
||||||
@ -407,18 +436,24 @@ minetest.register_craft({
|
|||||||
recipe = {"smartline:controller"}
|
recipe = {"smartline:controller"}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
-- write inputs from remote nodes
|
||||||
local function set_input(number, input, val)
|
local function set_input(pos, number, input, val)
|
||||||
if input then
|
if input then
|
||||||
if Cache[number] and Cache[number].inputs then
|
if Cache[number] and Cache[number].inputs then
|
||||||
--print("set_input", input, val)
|
-- only one event per second
|
||||||
Cache[number].inputs[input] = val
|
local t = minetest.get_us_time()
|
||||||
|
if not Cache[number].last_event or Cache[number].last_event < t then
|
||||||
|
Cache[number].inputs[input] = val
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
minetest.after(0.1, call_loop, pos, meta, -1)
|
||||||
|
Cache[number].last_event = t + 1000000 -- add one second
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- used by the command "input"
|
||||||
function sl_controller.get_input(number, input)
|
function sl_controller.get_input(number, input)
|
||||||
--print("get_input", number, input, dump(Cache[number].inputs))
|
|
||||||
if input then
|
if input then
|
||||||
if Cache[number] and Cache[number].inputs then
|
if Cache[number] and Cache[number].inputs then
|
||||||
return Cache[number].inputs[input] or "off"
|
return Cache[number].inputs[input] or "off"
|
||||||
@ -429,14 +464,13 @@ end
|
|||||||
|
|
||||||
tubelib.register_node("sl_controller:controller", {}, {
|
tubelib.register_node("sl_controller:controller", {}, {
|
||||||
on_recv_message = function(pos, topic, payload)
|
on_recv_message = function(pos, topic, payload)
|
||||||
-----------------------------------------------------
|
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local number = meta:get_string("number")
|
local number = meta:get_string("number")
|
||||||
---------------------------------------------
|
|
||||||
if topic == "on" then
|
if topic == "on" then
|
||||||
set_input(number, payload, topic)
|
set_input(pos, number, payload, topic)
|
||||||
elseif topic == "off" then
|
elseif topic == "off" then
|
||||||
set_input(number, payload, topic)
|
set_input(pos, number, payload, topic)
|
||||||
elseif topic == "state" then
|
elseif topic == "state" then
|
||||||
local state = meta:get_int("state")
|
local state = meta:get_int("state")
|
||||||
return tubelib.statestring(state)
|
return tubelib.statestring(state)
|
||||||
|
@ -279,5 +279,5 @@ This file has further helper functions and is recommended for deeper study.
|
|||||||
## 7. History
|
## 7. History
|
||||||
|
|
||||||
2017-10-02 First draft
|
2017-10-02 First draft
|
||||||
2017-10-29 Commands start/stop replaced by on/off
|
2017-10-29 Commands start/stop replaced by on/off
|
||||||
2018-03-31 Corrections for 'send_request' and 'add_node'
|
2018-03-31 Corrections for 'send_request' and 'add_node'
|
||||||
|
Loading…
Reference in New Issue
Block a user