Make code more efficient

Mass changes:
 • Make the queue handler only run when required and with a delay of `tick_delay`.
 • Launch the queue handler if it is not running and a queue item is added.
 • Add `scriptblocks.create_formspec_handler()` to shrink code size by de-duplicating code.
 • Add pipeworks-style protected program namespaces.
This commit is contained in:
luk3yx 2018-09-06 20:48:28 +12:00
parent a450b91c03
commit aa24cb41fd
5 changed files with 126 additions and 233 deletions

View File

@ -50,14 +50,44 @@ scriptblocks.set_storage = function(data)
return scriptblocks.storage:set_string('scriptblock', minetest.serialize(data))
end
-- Is the channel reserved for another user?
scriptblocks.check_channel = function(name, channel, readonly)
-- Channel name RegEx from https://github.com/minetest-mods/pipeworks
-- Possibly(?) licensed under the GNU LGPL 2.1
local victim, sep = channel:match('^([^:;]+)([:;])')
if victim and sep then
local valid = victim == name
if victim ~= name and (sep ~= ';' or not readonly) then
minetest.chat_send_player(name, 'Sorry, only ' .. victim ..
' may use that channel.')
return true
end
end
return false
end
-- Is the node protected?
scriptblocks.check_protection = function(pos, name, channel, readonly)
if type(name) ~= 'string' then
name = name:get_player_name()
end
if minetest.is_protected(pos, name) and
not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return true
end
if channel then
return scriptblocks.check_channel(name, channel, readonly)
end
return false
end
-- To avoid lag and stack overflows, we add the data to a queue and then execute it with a globalstep.
local queue = {}
-- Easily add items to the queue
scriptblocks.queue = function(pos, sender, info, last, channel)
table.insert(queue, {pos, sender, info, last, channel})
end
local queue_lock = false
-- Directly execute a scriptblock and return a queue with more scriptblocks
scriptblocks.run = function(pos, sender, info, last, channel, executions)
@ -131,10 +161,12 @@ scriptblocks.escape = function(text, info, last)
return text and text:gsub('@info', info):gsub('@last', last)
end
-- Handle queued scriptblocks
minetest.register_globalstep(function(dtime)
-- Handle queued scriptblocks, but only when required.
local handle_queue
handle_queue = function()
queue_lock = true
local new_queue = {}
for i,data in pairs(queue) do
for i, data in pairs(queue) do
local new_list = scriptblocks.run(unpack(data))
if new_list then
for _,new_item in pairs(new_list) do
@ -143,12 +175,27 @@ minetest.register_globalstep(function(dtime)
end
if i > scriptblocks.max_per_step then
queue = new_queue
return
break
end
end
queue = new_queue
end)
if #queue > 0 then
minetest.after(scriptblocks.tick_delay, handle_queue)
else
queue_lock = false
end
end
-- Easily add items to the queue
scriptblocks.queue = function(pos, sender, info, last, channel)
table.insert(queue, {pos, sender, info, last, channel})
if not queue_lock then
-- Start the queue handler
handle_queue()
end
end
-- A register with alias function to automatically add aliases
-- Uses register_alias_force() to unregister the original rmod one first.
@ -157,3 +204,19 @@ scriptblocks.register_with_alias = function(name, def)
minetest.register_node(new_name, def)
minetest.register_alias_force('rmod:scriptblock_' .. name, new_name)
end
-- An easy(-ish) formspec handler
scriptblocks.create_formspec_handler = function(ro, ...)
local names = {...}
return function(pos, formname, fields, sender)
if scriptblocks.check_protection(pos, sender, fields.channel, ro) then
return
end
local meta = minetest.get_meta(pos)
for _, i in ipairs(names) do
if fields[i] then
meta:set_string(i, fields[i])
end
end
end
end

View File

@ -11,23 +11,13 @@ scriptblocks.register_with_alias('digiline_receiver', {
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string('formspec', [[
field[progchannel;]] .. scriptblocks.program_channel .. [[;${progchannel}]
field[channel;]] .. scriptblocks.program_channel .. [[;${channel}]
field[digichannel;Digiline channel;${digichannel}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.digichannel) then
minetest.get_meta(pos):set_string('digichannel', fields.digichannel)
end
if (fields.progchannel) then
minetest.get_meta(pos):set_string('progchannel', fields.progchannel)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'channel', 'digichannel'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
return
end,
@ -36,7 +26,7 @@ field[digichannel;Digiline channel;${digichannel}]
effector = {
action = function (pos, node, msgchannel, msg)
local meta = minetest.get_meta(pos)
local progchannel = meta:get_string('progchannel')
local progchannel = meta:get_string('channel')
local digichannel = meta:get_string('digichannel')
if msgchannel ~= digichannel then return end

View File

@ -9,6 +9,10 @@ scriptblocks = {
-- The maximum amount of scriptblocks processed during a globalstep
max_per_step = 24,
-- The "tick" delay - How long to wait between processing scriptblocks
-- NOTE: If this is set too high, scriptblocks will appear unresponsive.
tick_delay = 0.1,
}
-- Get the mod path and storage

View File

@ -15,19 +15,9 @@ field[channel;]] .. scriptblocks.program_channel .. [[;${channel}]
field[info;Starting @info;${info}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string('channel', fields.channel)
end
if (fields.info) then
minetest.get_meta(pos):set_string('info', fields.info)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'channel', 'info'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
return
end,

View File

@ -4,6 +4,10 @@
scriptblocks.program_channel = 'Program channel'
local a_b_formspec_handler = scriptblocks.create_formspec_handler(
false, 'a', 'b'
)
scriptblocks.register_with_alias('set', {
description = 'Scriptblocks: Set',
tiles = {'scriptblocks_set.png'},
@ -17,22 +21,11 @@ field[varname;Varname;${varname}]
field[value;Value;${value}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string('channel', fields.channel)
end
if (fields.varname) then
minetest.get_meta(pos):set_string('varname', fields.varname)
end
if (fields.value) then
minetest.get_meta(pos):set_string('value', fields.value)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'channel', 'varname', 'value'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local channel = scriptblocks.escape(meta:get_string('channel'), info, last)
@ -65,19 +58,11 @@ field[channel;]] .. scriptblocks.program_channel .. [[ (optional);${channel}]
field[varname;Varname;${varname}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string('channel', fields.channel)
end
if (fields.varname) then
minetest.get_meta(pos):set_string('varname', fields.varname)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
true, 'channel', 'varname'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local channel = scriptblocks.escape(meta:get_string('channel'), info, last)
@ -106,19 +91,9 @@ field[player;Player (optional);${player}]
field[message;Message;${message}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.player) then
minetest.get_meta(pos):set_string('player', fields.player)
end
if (fields.message) then
minetest.get_meta(pos):set_string('message', fields.message)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'player', 'message'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local plr = scriptblocks.escape(meta:get_string('player'), info, last)
@ -214,19 +189,8 @@ field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -250,19 +214,8 @@ field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -286,19 +239,8 @@ field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -321,20 +263,7 @@ scriptblocks.register_with_alias('divide', {
field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
end,on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -357,20 +286,7 @@ scriptblocks.register_with_alias('modulo', {
field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
end,on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -419,19 +335,9 @@ field[propname;Attribute Name;${propname}]
field[value;Value;${value}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.propname) then
minetest.get_meta(pos):set_string('propname', fields.propname)
end
if (fields.value) then
minetest.get_meta(pos):set_string('value', fields.value)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'propname', 'value'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local propname = scriptblocks.escape(meta:get_string('propname'), info, last)
@ -472,16 +378,9 @@ scriptblocks.register_with_alias('get_attribute', {
field[propname;Attribute Name;${propname}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.propname) then
minetest.get_meta(pos):set_string('propname', fields.propname)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'propname'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local propname = scriptblocks.escape(meta:get_string('propname'), info, last)
@ -549,20 +448,7 @@ scriptblocks.register_with_alias('equals', {
field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
end,on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -582,20 +468,7 @@ scriptblocks.register_with_alias('lt', {
field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
end,on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -615,20 +488,7 @@ scriptblocks.register_with_alias('gt', {
field[a;A;${a}]
field[b;B;${b}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.a) then
minetest.get_meta(pos):set_string('a', fields.a)
end
if (fields.b) then
minetest.get_meta(pos):set_string('b', fields.b)
end
end,
end,on_recieve_fields = a_b_formspec_handler,
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local a = scriptblocks.escape(meta:get_string('a'), info, last)
@ -660,16 +520,9 @@ scriptblocks.register_with_alias('number', {
field[number;Number literal;${number}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.number) then
minetest.get_meta(pos):set_string('number', fields.number)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'number'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local number = meta:get_string('number')
@ -688,16 +541,9 @@ scriptblocks.register_with_alias('string', {
field[str;String literal;${str}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.str) then
minetest.get_meta(pos):set_string('str', fields.str)
end
end,
on_receive_fields = scriptblocks.create_formspec_handler(
false, 'str'
),
scriptblock = function (pos, node, sender, info, last, main_channel)
local meta = minetest.get_meta(pos)
local str = meta:get_string('str')