This repository has been archived on 2019-06-10. You can view files and clone it, but cannot push or open issues or pull requests.
scriptblocks/core.lua

160 lines
5.7 KiB
Lua
Raw Normal View History

2018-09-06 05:04:07 +02:00
--
-- Minetest scriptblocks mod - Core
--
--
-- scriptblock = function(pos, node, sender, info, last, main_channel)
-- 'pos' and 'node' are the position and the node information of the
-- scriptblock being ran.
-- 'sender' would be the position of the node responsible for activating it.
-- 'info' is any information the previous node has sent to it.
-- 'last' is the information that 'info' /was/ before it was last changed.
-- 'channel' is the channel in which variables are stored.
--
-- <insert function code here>
--
-- return new_info, faces
-- Information to pass to the next node(s), and information on which adjacent
-- spaces we should even try to signal to. This return statement is
-- optional and can be omitted entirely.
-- end
-- Original rmod functions
scriptblocks.stringify = function(t)
if type(t) ~= 'table' then return tostring(t) end
return minetest.serialize(t):sub(('return '):len()+1, -1)
end
scriptblocks.compare = function(a, b)
-- Compare two tables by comparing their values -
-- also make sure to support nested tables.
if type(a) ~= 'table' or type(b) ~= 'table' then return a == b end
for i,j in pairs(a) do
if not compare(j, b[i]) then return false end
end
for i,j in pairs(b) do
if not compare(j, a[i]) then return false end
end
return true
end
-- TODO: Replace these functions with better ones
scriptblocks.get_storage = function()
return minetest.deserialize(
scriptblocks.storage:get_string('scriptblock')
) or {}
end
scriptblocks.set_storage = function(data)
return scriptblocks.storage:set_string('scriptblock', minetest.serialize(data))
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
-- Directly execute a scriptblock and return a queue with more scriptblocks
scriptblocks.run = function(pos, sender, info, last, channel, executions)
local local_queue = {}
if executions == nil then
executions = scriptblocks.max_length
elseif executions <= 0 then
return
end
-- Get information about this script block we are told to execute.
local node = minetest.get_node(pos)
local name = node.name
local def = minetest.registered_nodes[name]
-- If the block is a script block...
if def and def.scriptblock then
local new_info, faces = def.scriptblock(pos, node, sender, info, last, channel)
if not faces then
faces = {true, true, true, true, true, true}
end
-- Check neighboring nodes; if they also have scriptblock and aren't the sender, execute them.
for i=1,6 do
if faces[i] then
local dir = vector.new(0, 0, 0)
if i == 1 then dir.y = 1
elseif i == 2 then dir.y = -1
elseif i == 3 then dir.x = 1
elseif i == 4 then dir.x = -1
elseif i == 5 then dir.z = 1
elseif i == 6 then dir.z = -1 end
local new_pos = vector.add(pos, dir)
-- This is required, otherwise you'd have an unintentional feedback loop.
-- Feedback loops can still be created intentionally, though.
if not vector.equals(new_pos, sender) then
local new_node = minetest.get_node(new_pos)
local new_name = new_node.name
local new_def = minetest.registered_nodes[new_name]
if new_def and new_def.scriptblock then
local new_last
if new_info ~= nil then -- If something has been pushed to the stack,
new_last = info -- we update @last.
else
new_info = info -- Why bother updating it?
new_last = last
end
table.insert(local_queue, { new_pos, pos, new_info,
new_last, channel, executions - 1 })
end
end
end
end
end
return local_queue
end
-- Escape text
scriptblocks.escape = function(text, info, last)
local info = tostring(info or '')
local last = tostring(last or '')
if text == '@info' then return info end
if text == '@last' then return last end
if type(info) == 'table' then info = scriptblocks.stringify(info) or '' end
if type(last) == 'table' then last = scriptblocks.stringify(last) or '' end
return text and text:gsub('@info', info):gsub('@last', last)
end
-- Handle queued scriptblocks
minetest.register_globalstep(function(dtime)
local new_queue = {}
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
table.insert(new_queue, new_item)
end
end
if i > scriptblocks.max_per_step then
queue = new_queue
return
end
end
queue = new_queue
end)
-- A register with alias function to automatically add aliases
-- Uses register_alias_force() to unregister the original rmod one first.
scriptblocks.register_with_alias = function(name, def)
local new_name = minetest.get_current_modname() .. ':' .. name
minetest.register_node(new_name, def)
minetest.register_alias_force('rmod:scriptblock_' .. name, new_name)
end