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:
parent
a450b91c03
commit
aa24cb41fd
85
core.lua
85
core.lua
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
4
init.lua
4
init.lua
|
@ -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
|
||||
|
|
16
mesecons.lua
16
mesecons.lua
|
@ -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,
|
||||
|
|
234
scriptblock.lua
234
scriptblock.lua
|
@ -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')
|
||||
|
|
Reference in New Issue