mirror of
				https://github.com/minetest-mods/mesecons.git
				synced 2025-11-04 04:55:26 +01:00 
			
		
		
		
	Merge branch 'improve-luacontroller' of https://github.com/ShadowNinja/minetest-mod-mesecons into ShadowNinja-improve-luacontroller
Conflicts: mesecons/legacy.lua mesecons_luacontroller/init.lua mesecons_microcontroller/init.lua
This commit is contained in:
		@@ -1,29 +1,30 @@
 | 
			
		||||
-- Ugly hack to prevent breaking compatibility with other mods
 | 
			
		||||
-- Just remove the following two functions to delete the hack, to be done when other mods have updated
 | 
			
		||||
function mesecon.receptor_on(self, pos, rules)
 | 
			
		||||
	if (self.receptor_on) then
 | 
			
		||||
		print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
 | 
			
		||||
		print("[Mesecons]          If you are the programmer of this mod, please update it ")
 | 
			
		||||
		print("[Mesecons]          to use mesecon.receptor_on instead. mesecon:* is deprecated")
 | 
			
		||||
		print("[Mesecons]          Otherwise, please make sure you're running the latest version")
 | 
			
		||||
		print("[Mesecons]          of that mod and inform the mod creator.")
 | 
			
		||||
	else
 | 
			
		||||
		rules = pos
 | 
			
		||||
		pos = self
 | 
			
		||||
	end
 | 
			
		||||
	mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon.receptor_off(self, pos, rules)
 | 
			
		||||
	if (self.receptor_off) then
 | 
			
		||||
		print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
 | 
			
		||||
		print("[Mesecons]          If you are the programmer of this mod, please update it ")
 | 
			
		||||
		print("[Mesecons]          to use mesecon.receptor_off instead. mesecon:* is deprecated")
 | 
			
		||||
		print("[Mesecons]          Otherwise, please make sure you're running the latest version")
 | 
			
		||||
		print("[Mesecons]          of that mod and inform the mod creator.")
 | 
			
		||||
	else
 | 
			
		||||
		rules = pos
 | 
			
		||||
		pos = self
 | 
			
		||||
	end
 | 
			
		||||
	mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
 | 
			
		||||
end
 | 
			
		||||
-- Ugly hack to prevent breaking compatibility with other mods
 | 
			
		||||
-- Just remove the following two functions to delete the hack, to be done when other mods have updated
 | 
			
		||||
function mesecon.receptor_on(self, pos, rules)
 | 
			
		||||
	if (self.receptor_on) then
 | 
			
		||||
		print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
 | 
			
		||||
		print("[Mesecons]          If you are the programmer of this mod, please update it ")
 | 
			
		||||
		print("[Mesecons]          to use mesecon.receptor_on instead. mesecon:* is deprecated")
 | 
			
		||||
		print("[Mesecons]          Otherwise, please make sure you're running the latest version")
 | 
			
		||||
		print("[Mesecons]          of that mod and inform the mod creator.")
 | 
			
		||||
	else
 | 
			
		||||
		rules = pos
 | 
			
		||||
		pos = self
 | 
			
		||||
	end
 | 
			
		||||
	mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon.receptor_off(self, pos, rules)
 | 
			
		||||
	if (self.receptor_off) then
 | 
			
		||||
		print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
 | 
			
		||||
		print("[Mesecons]          If you are the programmer of this mod, please update it ")
 | 
			
		||||
		print("[Mesecons]          to use mesecon.receptor_off instead. mesecon:* is deprecated")
 | 
			
		||||
		print("[Mesecons]          Otherwise, please make sure you're running the latest version")
 | 
			
		||||
		print("[Mesecons]          of that mod and inform the mod creator.")
 | 
			
		||||
	else
 | 
			
		||||
		rules = pos
 | 
			
		||||
		pos = self
 | 
			
		||||
	end
 | 
			
		||||
	mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,21 @@
 | 
			
		||||
--        ______
 | 
			
		||||
--       |
 | 
			
		||||
--       |
 | 
			
		||||
--       |        __       ___  _   __         _  _
 | 
			
		||||
-- |   | |       |  | |\ |  |  |_| |  | |  |  |_ |_|
 | 
			
		||||
-- |___| |______ |__| | \|  |  | \ |__| |_ |_ |_ |\
 | 
			
		||||
-- |
 | 
			
		||||
-- |
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
-- Reference
 | 
			
		||||
-- ports = get_real_portstates(pos): gets if inputs are powered from outside
 | 
			
		||||
-- newport = merge_portstates(state1, state2): just does result = state1 or state2 for every port
 | 
			
		||||
-- action_setports(pos, rule, state): activates/deactivates the mesecons according to the portstates (helper for action)
 | 
			
		||||
-- action(pos, ports): Applies new portstates to a luacontroller at pos
 | 
			
		||||
-- lc_update(pos): updates the controller at pos by executing the code
 | 
			
		||||
-- reset_meta (pos, code, errmsg): performs a software-reset, installs new code and prints error messages
 | 
			
		||||
-- reset (pos): performs a hardware reset, turns off all ports
 | 
			
		||||
-- ports = get_real_port_states(pos): gets if inputs are powered from outside
 | 
			
		||||
-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port
 | 
			
		||||
-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states
 | 
			
		||||
-- set_port_states(pos, ports): Applies new port states to a LuaController at pos
 | 
			
		||||
-- run(pos): runs the code in the controller at pos
 | 
			
		||||
-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error messages
 | 
			
		||||
-- resetn(pos): performs a hardware reset, turns off all ports
 | 
			
		||||
--
 | 
			
		||||
-- The Sandbox
 | 
			
		||||
-- The whole code of the controller runs in a sandbox,
 | 
			
		||||
@@ -20,62 +30,76 @@
 | 
			
		||||
 | 
			
		||||
local BASENAME = "mesecons_luacontroller:luacontroller"
 | 
			
		||||
 | 
			
		||||
local rules = {}
 | 
			
		||||
rules.a = {x = -1, y = 0, z =  0, name="A"}
 | 
			
		||||
rules.b = {x =  0, y = 0, z =  1, name="B"}
 | 
			
		||||
rules.c = {x =  1, y = 0, z =  0, name="C"}
 | 
			
		||||
rules.d = {x =  0, y = 0, z = -1, name="D"}
 | 
			
		||||
local rules = {
 | 
			
		||||
	a = {x = -1, y = 0, z =  0, name="A"},
 | 
			
		||||
	b = {x =  0, y = 0, z =  1, name="B"},
 | 
			
		||||
	c = {x =  1, y = 0, z =  0, name="C"},
 | 
			
		||||
	d = {x =  0, y = 0, z = -1, name="D"},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
------------------
 | 
			
		||||
-- Action stuff --
 | 
			
		||||
------------------
 | 
			
		||||
-- These helpers are required to set the portstates of the luacontroller
 | 
			
		||||
-- These helpers are required to set the port states of the luacontroller
 | 
			
		||||
 | 
			
		||||
function lc_update_real_portstates(pos, rulename, newstate)
 | 
			
		||||
local function update_real_port_states(pos, rule_name, new_state)
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	if rulename == nil then
 | 
			
		||||
	if rule_name == nil then
 | 
			
		||||
		meta:set_int("real_portstates", 1)
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local n = meta:get_int("real_portstates") - 1
 | 
			
		||||
	local L = {}
 | 
			
		||||
	for i = 1, 4 do
 | 
			
		||||
		L[i] = n%2
 | 
			
		||||
		n = math.floor(n/2)
 | 
			
		||||
		L[i] = n % 2
 | 
			
		||||
		n = math.floor(n / 2)
 | 
			
		||||
	end
 | 
			
		||||
	if rulename.x == nil then
 | 
			
		||||
		for _, rname in ipairs(rulename) do
 | 
			
		||||
			local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3]
 | 
			
		||||
	--                   (0,-1) (-1,0)      (1,0) (0,1)
 | 
			
		||||
	local pos_to_side = {  4,     1,   nil,   3,    2 }
 | 
			
		||||
	if rule_name.x == nil then
 | 
			
		||||
		for _, rname in ipairs(rule_name) do
 | 
			
		||||
			local port = pos_to_side[rname.x + (2 * rname.z) + 3]
 | 
			
		||||
			L[port] = (newstate == "on") and 1 or 0
 | 
			
		||||
		end
 | 
			
		||||
	else
 | 
			
		||||
		local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3]
 | 
			
		||||
		L[port] = (newstate == "on") and 1 or 0
 | 
			
		||||
		local port = pos_to_side[rule_name.x + (2 * rule_name.z) + 3]
 | 
			
		||||
		L[port] = (new_state == "on") and 1 or 0
 | 
			
		||||
	end
 | 
			
		||||
	meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
 | 
			
		||||
	meta:set_int("real_portstates",
 | 
			
		||||
		1 +
 | 
			
		||||
		1 * L[1] +
 | 
			
		||||
		2 * L[2] +
 | 
			
		||||
		4 * L[3] +
 | 
			
		||||
		8 * L[4])
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
 | 
			
		||||
 | 
			
		||||
local port_names = {"a", "b", "c", "d"}
 | 
			
		||||
 | 
			
		||||
local function get_real_port_states(pos)
 | 
			
		||||
	-- Determine if ports are powered (by itself or from outside)
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	local L = {}
 | 
			
		||||
	local n = meta:get_int("real_portstates") - 1
 | 
			
		||||
	for _, index in ipairs({"a", "b", "c", "d"}) do
 | 
			
		||||
		L[index] = ((n%2) == 1)
 | 
			
		||||
		n = math.floor(n/2)
 | 
			
		||||
	for _, name in ipairs(port_names) do
 | 
			
		||||
		L[name] = ((n % 2) == 1)
 | 
			
		||||
		n = math.floor(n / 2)
 | 
			
		||||
	end
 | 
			
		||||
	return L
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local merge_portstates = function (ports, vports)
 | 
			
		||||
	local npo = {a=false, b=false, c=false, d=false}
 | 
			
		||||
	npo.a = vports.a or ports.a
 | 
			
		||||
	npo.b = vports.b or ports.b
 | 
			
		||||
	npo.c = vports.c or ports.c
 | 
			
		||||
	npo.d = vports.d or ports.d
 | 
			
		||||
	return npo
 | 
			
		||||
 | 
			
		||||
local function merge_port_states(ports, vports)
 | 
			
		||||
	return {
 | 
			
		||||
		a = ports.a or vports.a,
 | 
			
		||||
		b = ports.b or vports.b,
 | 
			
		||||
		c = ports.c or vports.c,
 | 
			
		||||
		d = ports.d or vports.d,
 | 
			
		||||
	}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local generate_name = function (ports)
 | 
			
		||||
local function generate_name(ports)
 | 
			
		||||
	local d = ports.d and 1 or 0
 | 
			
		||||
	local c = ports.c and 1 or 0
 | 
			
		||||
	local b = ports.b and 1 or 0
 | 
			
		||||
@@ -83,7 +107,8 @@ local generate_name = function (ports)
 | 
			
		||||
	return BASENAME..d..c..b..a
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local setport = function (pos, rule, state)
 | 
			
		||||
 | 
			
		||||
local function set_port(pos, rule, state)
 | 
			
		||||
	if state then
 | 
			
		||||
		mesecon.receptor_on(pos, {rule})
 | 
			
		||||
	else
 | 
			
		||||
@@ -91,93 +116,114 @@ local setport = function (pos, rule, state)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local action = function (pos, ports)
 | 
			
		||||
 | 
			
		||||
local function clean_port_states(ports)
 | 
			
		||||
	ports.a = ports.a and true or false
 | 
			
		||||
	ports.b = ports.b and true or false
 | 
			
		||||
	ports.c = ports.c and true or false
 | 
			
		||||
	ports.d = ports.d and true or false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function set_port_states(pos, ports)
 | 
			
		||||
	local node = minetest.get_node(pos)
 | 
			
		||||
	local name = node.name
 | 
			
		||||
	clean_port_states(ports)
 | 
			
		||||
	local vports = minetest.registered_nodes[name].virtual_portstates
 | 
			
		||||
	local newname = generate_name(ports)
 | 
			
		||||
	local new_name = generate_name(ports)
 | 
			
		||||
 | 
			
		||||
	if name ~= newname and vports then
 | 
			
		||||
		local rules_on  = {}
 | 
			
		||||
		local rules_off = {}
 | 
			
		||||
	if name ~= new_name and vports then
 | 
			
		||||
		minetest.swap_node(pos, {name = new_name, param2 = node.param2})
 | 
			
		||||
 | 
			
		||||
		minetest.swap_node(pos, {name = newname, param2 = node.param2})
 | 
			
		||||
 | 
			
		||||
		if ports.a ~= vports.a then setport(pos, rules.a, ports.a) end
 | 
			
		||||
		if ports.b ~= vports.b then setport(pos, rules.b, ports.b) end
 | 
			
		||||
		if ports.c ~= vports.c then setport(pos, rules.c, ports.c) end
 | 
			
		||||
		if ports.d ~= vports.d then setport(pos, rules.d, ports.d) end
 | 
			
		||||
		if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
 | 
			
		||||
		if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
 | 
			
		||||
		if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
 | 
			
		||||
		if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--------------------
 | 
			
		||||
-- Overheat stuff --
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
local overheat_off = function(pos)
 | 
			
		||||
-----------------
 | 
			
		||||
-- Overheating --
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
local function overheat_off(pos)
 | 
			
		||||
	mesecon.receptor_off(pos, mesecon.rules.flat)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-------------------
 | 
			
		||||
-- Parsing stuff --
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
local code_prohibited = function(code)
 | 
			
		||||
	-- Clean code
 | 
			
		||||
	local prohibited = {"while", "for", "repeat", "until", "function", "goto"}
 | 
			
		||||
	for _, p in ipairs(prohibited) do
 | 
			
		||||
		if string.find(code, p) then
 | 
			
		||||
			return "Prohibited command: "..p
 | 
			
		||||
		end
 | 
			
		||||
local function overheat(pos, meta)
 | 
			
		||||
	if mesecon.do_overheat(pos) then -- If too hot
 | 
			
		||||
		local node = minetest.get_node(pos)
 | 
			
		||||
		node.name = BASENAME.."_burnt"
 | 
			
		||||
		minetest.swap_node(pos, node)
 | 
			
		||||
		-- Wait for pending operations
 | 
			
		||||
		minetest.after(0.2, overheat_off, pos)
 | 
			
		||||
		return true
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local safe_print = function(param)
 | 
			
		||||
	print(dump(param))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
deep_copy = function(original, visited) --deep copy that removes functions
 | 
			
		||||
	visited = visited or {}
 | 
			
		||||
	if visited[original] ~= nil then --already visited this node
 | 
			
		||||
		return visited[original]
 | 
			
		||||
-------------------------
 | 
			
		||||
-- Parsing and running --
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
-- Limit printing to prevent flooding
 | 
			
		||||
local print_count = 0
 | 
			
		||||
 | 
			
		||||
local function safe_print(param)
 | 
			
		||||
	local to_print = dump(param, "")
 | 
			
		||||
	print_count = print_count + 1 + (#to_print / 64)
 | 
			
		||||
	for c in to_print:gmatch("\n") do
 | 
			
		||||
		print_count = print_count + 1
 | 
			
		||||
	end
 | 
			
		||||
	if type(original) == 'table' then --nested table
 | 
			
		||||
		local copy = {}
 | 
			
		||||
		visited[original] = copy
 | 
			
		||||
		for key, value in next, original, nil do
 | 
			
		||||
			copy[deep_copy(key, visited)] = deep_copy(value, visited)
 | 
			
		||||
		end
 | 
			
		||||
		setmetatable(copy, deep_copy(getmetatable(original), visited))
 | 
			
		||||
		return copy
 | 
			
		||||
	elseif type(original) == 'function' then --ignore functions
 | 
			
		||||
		return nil
 | 
			
		||||
	else --by-value type
 | 
			
		||||
		return original
 | 
			
		||||
	if print_count > 8 then
 | 
			
		||||
		error("Too much printing!")
 | 
			
		||||
	end
 | 
			
		||||
	print(to_print)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local safe_serialize = function(value)
 | 
			
		||||
	return minetest.serialize(deep_copy(value))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
mesecon.queue:add_function("lc_interrupt", function (pos, iid, luac_id)
 | 
			
		||||
	-- There is no luacontroller anymore / it has been reprogrammed / replaced
 | 
			
		||||
	if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end
 | 
			
		||||
	lc_update(pos, {type="interrupt", iid = iid})
 | 
			
		||||
minetest.register_globalstep(function(dtime)
 | 
			
		||||
	print_count = print_count - dtime
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
local getinterrupt = function(pos)
 | 
			
		||||
	local interrupt = function (time, iid) -- iid = interrupt id
 | 
			
		||||
 | 
			
		||||
local function remove_functions(x)
 | 
			
		||||
	local tp = type(x)
 | 
			
		||||
	if tp == "table" then
 | 
			
		||||
		for key, value in pairs(x) do
 | 
			
		||||
			local key_t, val_t = type(key), type(value)
 | 
			
		||||
			if key_t == "function" or val_t == "function" then
 | 
			
		||||
				x[key] = nil
 | 
			
		||||
			else
 | 
			
		||||
				if key_t == "table" then
 | 
			
		||||
					remove_functions(key)
 | 
			
		||||
				end
 | 
			
		||||
				if val_t == "table" then
 | 
			
		||||
					remove_functions(value)
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	elseif tp == "function" then
 | 
			
		||||
		return nil
 | 
			
		||||
	end
 | 
			
		||||
	return x
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function get_interrupt(pos)
 | 
			
		||||
	-- iid = interrupt id
 | 
			
		||||
	local function interrupt(time, iid)
 | 
			
		||||
		if type(time) ~= "number" then return end
 | 
			
		||||
		luac_id = minetest.get_meta(pos):get_int("luac_id")
 | 
			
		||||
		mesecon.queue:add_action(pos, "lc_interrupt", {iid, luac_id}, time, iid, 1)
 | 
			
		||||
		local luac_id = minetest.get_meta(pos):get_int("luac_id")
 | 
			
		||||
		mesecon.queue:add_action(pos, "LuaController interrupt", {iid, luac_id}, time, iid, 1)
 | 
			
		||||
	end
 | 
			
		||||
	return interrupt
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local getdigiline_send = function(pos)
 | 
			
		||||
 | 
			
		||||
local function get_digiline_send(pos)
 | 
			
		||||
	if not digiline then return end
 | 
			
		||||
	-- Send messages on next serverstep
 | 
			
		||||
	return function(channel, msg)
 | 
			
		||||
		minetest.after(0, function()
 | 
			
		||||
			digiline:receptor_send(pos, digiline.rules.default, channel, msg)
 | 
			
		||||
@@ -185,146 +231,180 @@ local getdigiline_send = function(pos)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local create_environment = function(pos, mem, event)
 | 
			
		||||
 | 
			
		||||
local safe_globals = {
 | 
			
		||||
	"assert", "error", "ipairs", "next", "pairs", "pcall", "select",
 | 
			
		||||
	"tonumber", "tostring", "type", "unpack", "_VERSION", "xpcall", 
 | 
			
		||||
}
 | 
			
		||||
local function create_environment(pos, mem, event)
 | 
			
		||||
	-- Gather variables for the environment
 | 
			
		||||
	local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates
 | 
			
		||||
	vports = {a = vports.a, b = vports.b, c = vports.c, d = vports.d}
 | 
			
		||||
	local rports = get_real_portstates(pos)
 | 
			
		||||
	local vports_copy = {}
 | 
			
		||||
	for k, v in pairs(vports) do vports_copy[k] = v end
 | 
			
		||||
	local rports = get_real_port_states(pos)
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
			print = safe_print,
 | 
			
		||||
			pin = merge_portstates(vports, rports),
 | 
			
		||||
			port = vports,
 | 
			
		||||
			interrupt = getinterrupt(pos),
 | 
			
		||||
			digiline_send = getdigiline_send(pos),
 | 
			
		||||
			mem = mem,
 | 
			
		||||
			tostring = tostring,
 | 
			
		||||
			tonumber = tonumber,
 | 
			
		||||
			heat = minetest.get_meta(pos):get_int("heat"),
 | 
			
		||||
			-- overheat_max Unit: actions per second, checks are every 1 second
 | 
			
		||||
			heat_max = mesecon.setting("overheat_max", 20),
 | 
			
		||||
			string = {
 | 
			
		||||
				byte = string.byte,
 | 
			
		||||
				char = string.char,
 | 
			
		||||
				find = string.find,
 | 
			
		||||
				format = string.format,
 | 
			
		||||
				gmatch = string.gmatch,
 | 
			
		||||
				gsub = string.gsub,
 | 
			
		||||
				len = string.len,
 | 
			
		||||
				lower = string.lower,
 | 
			
		||||
				upper = string.upper,
 | 
			
		||||
				match = string.match,
 | 
			
		||||
				rep = string.rep,
 | 
			
		||||
				reverse = string.reverse,
 | 
			
		||||
				sub = string.sub,
 | 
			
		||||
			},
 | 
			
		||||
			math = {
 | 
			
		||||
				abs = math.abs,
 | 
			
		||||
				acos = math.acos,
 | 
			
		||||
				asin = math.asin,
 | 
			
		||||
				atan = math.atan,
 | 
			
		||||
				atan2 = math.atan2,
 | 
			
		||||
				ceil = math.ceil,
 | 
			
		||||
				cos = math.cos,
 | 
			
		||||
				cosh = math.cosh,
 | 
			
		||||
				deg = math.deg,
 | 
			
		||||
				exp = math.exp,
 | 
			
		||||
				floor = math.floor,
 | 
			
		||||
				fmod = math.fmod,
 | 
			
		||||
				frexp = math.frexp,
 | 
			
		||||
				huge = math.huge,
 | 
			
		||||
				ldexp = math.ldexp,
 | 
			
		||||
				log = math.log,
 | 
			
		||||
				log10 = math.log10,
 | 
			
		||||
				max = math.max,
 | 
			
		||||
				min = math.min,
 | 
			
		||||
				modf = math.modf,
 | 
			
		||||
				pi = math.pi,
 | 
			
		||||
				pow = math.pow,
 | 
			
		||||
				rad = math.rad,
 | 
			
		||||
				random = math.random,
 | 
			
		||||
				sin = math.sin,
 | 
			
		||||
				sinh = math.sinh,
 | 
			
		||||
				sqrt = math.sqrt,
 | 
			
		||||
				tan = math.tan,
 | 
			
		||||
				tanh = math.tanh,
 | 
			
		||||
			},
 | 
			
		||||
			table = {
 | 
			
		||||
				insert = table.insert,
 | 
			
		||||
				maxn = table.maxn,
 | 
			
		||||
				remove = table.remove,
 | 
			
		||||
				sort = table.sort
 | 
			
		||||
			},
 | 
			
		||||
			event = event,
 | 
			
		||||
	-- Create new library tables on each call to prevent one LuaController
 | 
			
		||||
	-- from breaking a library and messing up other LuaControllers.
 | 
			
		||||
	local env = {
 | 
			
		||||
		pin = merge_port_states(vports, rports),
 | 
			
		||||
		port = vports_copy,
 | 
			
		||||
		event = event,
 | 
			
		||||
		mem = mem,
 | 
			
		||||
		heat = minetest.get_meta(pos):get_int("heat"),
 | 
			
		||||
		heat_max = mesecon.setting("overheat_max", 20),
 | 
			
		||||
		print = safe_print,
 | 
			
		||||
		interrupt = get_interrupt(pos),
 | 
			
		||||
		digiline_send = get_digiline_send(pos),
 | 
			
		||||
		string = {
 | 
			
		||||
			byte = string.byte,
 | 
			
		||||
			char = string.char,
 | 
			
		||||
			format = string.format,
 | 
			
		||||
			gsub = string.gsub,
 | 
			
		||||
			len = string.len,
 | 
			
		||||
			lower = string.lower,
 | 
			
		||||
			upper = string.upper,
 | 
			
		||||
			rep = string.rep,
 | 
			
		||||
			reverse = string.reverse,
 | 
			
		||||
			sub = string.sub,
 | 
			
		||||
		},
 | 
			
		||||
		math = {
 | 
			
		||||
			abs = math.abs,
 | 
			
		||||
			acos = math.acos,
 | 
			
		||||
			asin = math.asin,
 | 
			
		||||
			atan = math.atan,
 | 
			
		||||
			atan2 = math.atan2,
 | 
			
		||||
			ceil = math.ceil,
 | 
			
		||||
			cos = math.cos,
 | 
			
		||||
			cosh = math.cosh,
 | 
			
		||||
			deg = math.deg,
 | 
			
		||||
			exp = math.exp,
 | 
			
		||||
			floor = math.floor,
 | 
			
		||||
			fmod = math.fmod,
 | 
			
		||||
			frexp = math.frexp,
 | 
			
		||||
			huge = math.huge,
 | 
			
		||||
			ldexp = math.ldexp,
 | 
			
		||||
			log = math.log,
 | 
			
		||||
			log10 = math.log10,
 | 
			
		||||
			max = math.max,
 | 
			
		||||
			min = math.min,
 | 
			
		||||
			modf = math.modf,
 | 
			
		||||
			pi = math.pi,
 | 
			
		||||
			pow = math.pow,
 | 
			
		||||
			rad = math.rad,
 | 
			
		||||
			random = math.random,
 | 
			
		||||
			sin = math.sin,
 | 
			
		||||
			sinh = math.sinh,
 | 
			
		||||
			sqrt = math.sqrt,
 | 
			
		||||
			tan = math.tan,
 | 
			
		||||
			tanh = math.tanh,
 | 
			
		||||
		},
 | 
			
		||||
		table = {
 | 
			
		||||
			concat = table.concat,
 | 
			
		||||
			insert = table.insert,
 | 
			
		||||
			maxn = table.maxn,
 | 
			
		||||
			remove = table.remove,
 | 
			
		||||
			sort = table.sort,
 | 
			
		||||
		},
 | 
			
		||||
		os = {
 | 
			
		||||
			clock = os.clock,
 | 
			
		||||
			difftime = os.difftime,
 | 
			
		||||
			time = os.time,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	env._G = env
 | 
			
		||||
 | 
			
		||||
	for _, name in pairs(safe_globals) do
 | 
			
		||||
		env[name] = _G[name]
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return env
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local create_sandbox = function (code, env)
 | 
			
		||||
	-- Create Sandbox
 | 
			
		||||
 | 
			
		||||
local function timeout()
 | 
			
		||||
	debug.sethook()  -- Clear hook
 | 
			
		||||
	error("Code timed out!")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function code_prohibited(code)
 | 
			
		||||
	-- LuaJIT doesn't increment the instruction counter when running
 | 
			
		||||
	-- loops, so we have to sanitize inputs if we're using LuaJIT.
 | 
			
		||||
	if not jit then
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
	local prohibited = {"while", "for", "do", "repeat", "until", "goto"}
 | 
			
		||||
	code = " "..code.." "
 | 
			
		||||
	for _, p in ipairs(prohibited) do
 | 
			
		||||
		if string.find(code, "[^%w_]"..p.."[^%w_]") then
 | 
			
		||||
			return "Prohibited command: "..p
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function create_sandbox(code, env)
 | 
			
		||||
	if code:byte(1) == 27 then
 | 
			
		||||
		return _, "You Hacker You! Don't use binary code!"
 | 
			
		||||
		return nil, "Binary code prohibited."
 | 
			
		||||
	end
 | 
			
		||||
	local f, msg = loadstring(code)
 | 
			
		||||
	if not f then return _, msg end
 | 
			
		||||
	if not f then return nil, msg end
 | 
			
		||||
	setfenv(f, env)
 | 
			
		||||
	return f
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local lc_overheat = function (pos, meta)
 | 
			
		||||
	if mesecon.do_overheat(pos) then -- if too hot
 | 
			
		||||
		local node = minetest.get_node(pos)
 | 
			
		||||
		minetest.swap_node(pos, {name = BASENAME.."_burnt", param2 = node.param2})
 | 
			
		||||
		minetest.after(0.2, overheat_off, pos) -- wait for pending operations
 | 
			
		||||
		return true
 | 
			
		||||
	return function(...)
 | 
			
		||||
		debug.sethook(timeout, "", 10000)
 | 
			
		||||
		local ok, ret = pcall(f, ...)
 | 
			
		||||
		debug.sethook()  -- Clear hook
 | 
			
		||||
		if not ok then error(ret) end
 | 
			
		||||
		return ret
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local load_memory = function(meta)
 | 
			
		||||
 | 
			
		||||
local function load_memory(meta)
 | 
			
		||||
	return minetest.deserialize(meta:get_string("lc_memory")) or {}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local save_memory = function(meta, mem)
 | 
			
		||||
	meta:set_string("lc_memory", safe_serialize(mem))
 | 
			
		||||
 | 
			
		||||
local function save_memory(meta, mem)
 | 
			
		||||
	meta:set_string("lc_memory",
 | 
			
		||||
		minetest.serialize(
 | 
			
		||||
			remove_functions(mem)
 | 
			
		||||
		)
 | 
			
		||||
	)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local ports_invalid = function (var)
 | 
			
		||||
	if type(var) == "table" then
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
	return "The ports you set are invalid"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
----------------------
 | 
			
		||||
-- Parsing function --
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
lc_update = function (pos, event)
 | 
			
		||||
local function run(pos, event)
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	if lc_overheat(pos) then return end
 | 
			
		||||
	if overheat(pos) then return end
 | 
			
		||||
 | 
			
		||||
	-- load code & mem from memory
 | 
			
		||||
	-- Load code & mem from meta
 | 
			
		||||
	local mem  = load_memory(meta)
 | 
			
		||||
	local code = meta:get_string("code")
 | 
			
		||||
 | 
			
		||||
	-- make sure code is ok and create environment
 | 
			
		||||
	local prohibited = code_prohibited(code)
 | 
			
		||||
	if prohibited then return prohibited end
 | 
			
		||||
	local err = code_prohibited(code)
 | 
			
		||||
	if err then return err end
 | 
			
		||||
 | 
			
		||||
	-- Create environment
 | 
			
		||||
	local env = create_environment(pos, mem, event)
 | 
			
		||||
 | 
			
		||||
	-- create the sandbox and execute code
 | 
			
		||||
	local chunk, msg = create_sandbox (code, env)
 | 
			
		||||
	if not chunk then return msg end
 | 
			
		||||
	local success, msg = pcall(chunk)
 | 
			
		||||
	-- Create the sandbox and execute code
 | 
			
		||||
	local f, msg = create_sandbox(code, env)
 | 
			
		||||
	if not f then return msg end
 | 
			
		||||
	local success, msg = pcall(f)
 | 
			
		||||
	if not success then return msg end
 | 
			
		||||
	if ports_invalid(env.port) then return ports_invalid(env.port) end
 | 
			
		||||
	if type(env.port) ~= "table" then
 | 
			
		||||
		return "Ports set are invalid."
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	save_memory(meta, mem)
 | 
			
		||||
	save_memory(meta, env.mem)
 | 
			
		||||
 | 
			
		||||
	-- Actually set the ports
 | 
			
		||||
	action(pos, env.port)
 | 
			
		||||
	set_port_states(pos, env.port)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local reset_meta = function(pos, code, errmsg)
 | 
			
		||||
local function reset_meta(pos, code, errmsg)
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	meta:set_string("code", code)
 | 
			
		||||
	code = minetest.formspec_escape(code or "")
 | 
			
		||||
@@ -336,171 +416,163 @@ local reset_meta = function(pos, code, errmsg)
 | 
			
		||||
		"image_button_exit[9.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"..
 | 
			
		||||
		"label[0.1,5;"..errmsg.."]")
 | 
			
		||||
	meta:set_int("heat", 0)
 | 
			
		||||
	meta:set_int("luac_id", math.random(1, 1000000))
 | 
			
		||||
	meta:set_int("luac_id", math.random(1, 65535))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local reset = function (pos)
 | 
			
		||||
	action(pos, {a=false, b=false, c=false, d=false})
 | 
			
		||||
local function reset(pos)
 | 
			
		||||
	set_port_states(pos, {a=false, b=false, c=false, d=false})
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--        ______
 | 
			
		||||
--       |
 | 
			
		||||
--       |
 | 
			
		||||
--       |        __       ___  _   __         _  _
 | 
			
		||||
-- |   | |       |  | |\ |  |  |_| |  | |  |  |_ |_|
 | 
			
		||||
-- |___| |______ |__| | \|  |  | \ |__| |_ |_ |_ |\
 | 
			
		||||
-- |
 | 
			
		||||
-- |
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
mesecon.queue:add_function("LuaController interrupt", function(pos, iid, luac_id)
 | 
			
		||||
	-- There is no LuaController anymore / it has been reprogrammed / replaced
 | 
			
		||||
	if minetest.get_meta(pos):get_int("luac_id") ~= luac_id then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	run(pos, {type="interrupt", iid = iid})
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-----------------------
 | 
			
		||||
-- Node Registration --
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
local output_rules={}
 | 
			
		||||
local input_rules={}
 | 
			
		||||
local output_rules = {}
 | 
			
		||||
local input_rules = {}
 | 
			
		||||
 | 
			
		||||
local nodebox = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = {
 | 
			
		||||
			{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
 | 
			
		||||
			{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board
 | 
			
		||||
			{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC
 | 
			
		||||
		}
 | 
			
		||||
local node_box = {
 | 
			
		||||
	type = "fixed",
 | 
			
		||||
	fixed = {
 | 
			
		||||
		{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab
 | 
			
		||||
		{-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board
 | 
			
		||||
		{-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local selectionbox = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
 | 
			
		||||
	}
 | 
			
		||||
local selection_box = {
 | 
			
		||||
	type = "fixed",
 | 
			
		||||
	fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local digiline = {
 | 
			
		||||
	receptor = {},
 | 
			
		||||
	effector = {
 | 
			
		||||
		action = function (pos, node, channel, msg)
 | 
			
		||||
			lc_update (pos, {type = "digiline", channel = channel, msg = msg})
 | 
			
		||||
		action = function(pos, node, channel, msg)
 | 
			
		||||
			run(pos, {type = "digiline", channel = channel, msg = msg})
 | 
			
		||||
		end
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
local function on_receive_fields(pos, form_name, fields)
 | 
			
		||||
	if not fields.program then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	reset(pos)
 | 
			
		||||
	reset_meta(pos, fields.code)
 | 
			
		||||
	local err = run(pos, {type="program"})
 | 
			
		||||
	if err then
 | 
			
		||||
		print(err)
 | 
			
		||||
		reset_meta(pos, fields.code, err)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
for a = 0, 1 do -- 0 = off; 1 = on
 | 
			
		||||
for a = 0, 1 do -- 0 = off  1 = on
 | 
			
		||||
for b = 0, 1 do
 | 
			
		||||
for c = 0, 1 do
 | 
			
		||||
for d = 0, 1 do
 | 
			
		||||
	local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
 | 
			
		||||
	local node_name = BASENAME..cid
 | 
			
		||||
	local top = "jeija_luacontroller_top.png"
 | 
			
		||||
	if a == 1 then
 | 
			
		||||
		top = top.."^jeija_luacontroller_LED_A.png"
 | 
			
		||||
	end
 | 
			
		||||
	if b == 1 then
 | 
			
		||||
		top = top.."^jeija_luacontroller_LED_B.png"
 | 
			
		||||
	end
 | 
			
		||||
	if c == 1 then
 | 
			
		||||
		top = top.."^jeija_luacontroller_LED_C.png"
 | 
			
		||||
	end
 | 
			
		||||
	if d == 1 then
 | 
			
		||||
		top = top.."^jeija_luacontroller_LED_D.png"
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
 | 
			
		||||
local nodename = BASENAME..cid
 | 
			
		||||
local top = "jeija_luacontroller_top.png"
 | 
			
		||||
if a == 1 then
 | 
			
		||||
	top = top.."^jeija_luacontroller_LED_A.png"
 | 
			
		||||
end
 | 
			
		||||
if b == 1 then
 | 
			
		||||
	top = top.."^jeija_luacontroller_LED_B.png"
 | 
			
		||||
end
 | 
			
		||||
if c == 1 then
 | 
			
		||||
	top = top.."^jeija_luacontroller_LED_C.png"
 | 
			
		||||
end
 | 
			
		||||
if d == 1 then
 | 
			
		||||
	top = top.."^jeija_luacontroller_LED_D.png"
 | 
			
		||||
end
 | 
			
		||||
	local groups
 | 
			
		||||
	if a + b + c + d ~= 0 then
 | 
			
		||||
		groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1}
 | 
			
		||||
	else
 | 
			
		||||
		groups = {dig_immediate=2, overheat = 1}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
if a + b + c + d ~= 0 then
 | 
			
		||||
	groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1}
 | 
			
		||||
else
 | 
			
		||||
	groups = {dig_immediate=2, overheat = 1}
 | 
			
		||||
end
 | 
			
		||||
	output_rules[cid] = {}
 | 
			
		||||
	input_rules[cid] = {}
 | 
			
		||||
	if a == 1 then table.insert(output_rules[cid], rules.a) end
 | 
			
		||||
	if b == 1 then table.insert(output_rules[cid], rules.b) end
 | 
			
		||||
	if c == 1 then table.insert(output_rules[cid], rules.c) end
 | 
			
		||||
	if d == 1 then table.insert(output_rules[cid], rules.d) end
 | 
			
		||||
 | 
			
		||||
output_rules[cid] = {}
 | 
			
		||||
input_rules[cid] = {}
 | 
			
		||||
if (a == 1) then table.insert(output_rules[cid], rules.a) end
 | 
			
		||||
if (b == 1) then table.insert(output_rules[cid], rules.b) end
 | 
			
		||||
if (c == 1) then table.insert(output_rules[cid], rules.c) end
 | 
			
		||||
if (d == 1) then table.insert(output_rules[cid], rules.d) end
 | 
			
		||||
	if a == 0 then table.insert( input_rules[cid], rules.a) end
 | 
			
		||||
	if b == 0 then table.insert( input_rules[cid], rules.b) end
 | 
			
		||||
	if c == 0 then table.insert( input_rules[cid], rules.c) end
 | 
			
		||||
	if d == 0 then table.insert( input_rules[cid], rules.d) end
 | 
			
		||||
 | 
			
		||||
if (a == 0) then table.insert(input_rules[cid], rules.a) end
 | 
			
		||||
if (b == 0) then table.insert(input_rules[cid], rules.b) end
 | 
			
		||||
if (c == 0) then table.insert(input_rules[cid], rules.c) end
 | 
			
		||||
if (d == 0) then table.insert(input_rules[cid], rules.d) end
 | 
			
		||||
 | 
			
		||||
local mesecons = {
 | 
			
		||||
	effector =
 | 
			
		||||
	{
 | 
			
		||||
		rules = input_rules[cid],
 | 
			
		||||
		action_change = function (pos, _, rulename, newstate)
 | 
			
		||||
			lc_update_real_portstates(pos, rulename, newstate)
 | 
			
		||||
			lc_update(pos, {type=newstate,  pin=rulename})
 | 
			
		||||
		end,
 | 
			
		||||
	},
 | 
			
		||||
	receptor =
 | 
			
		||||
	{
 | 
			
		||||
		state = mesecon.state.on,
 | 
			
		||||
		rules = output_rules[cid]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
minetest.register_node(nodename, {
 | 
			
		||||
	description = "Luacontroller",
 | 
			
		||||
	drawtype = "nodebox",
 | 
			
		||||
	tiles = {
 | 
			
		||||
		top,
 | 
			
		||||
		"jeija_microcontroller_bottom.png",
 | 
			
		||||
		"jeija_microcontroller_sides.png",
 | 
			
		||||
		"jeija_microcontroller_sides.png",
 | 
			
		||||
		"jeija_microcontroller_sides.png",
 | 
			
		||||
		"jeija_microcontroller_sides.png"
 | 
			
		||||
	local mesecons = {
 | 
			
		||||
		effector = {
 | 
			
		||||
			rules = input_rules[cid],
 | 
			
		||||
			action_change = function (pos, _, rule_name, new_state)
 | 
			
		||||
				update_real_port_states(pos, rule_name, new_state)
 | 
			
		||||
				run(pos, {type=new_state,  pin=rule_name})
 | 
			
		||||
			end,
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
	inventory_image = top,
 | 
			
		||||
	paramtype = "light",
 | 
			
		||||
	groups = groups,
 | 
			
		||||
	drop = BASENAME.."0000",
 | 
			
		||||
	sunlight_propagates = true,
 | 
			
		||||
	selection_box = selectionbox,
 | 
			
		||||
	node_box = nodebox,
 | 
			
		||||
	on_construct = reset_meta,
 | 
			
		||||
	on_receive_fields = function(pos, formname, fields)
 | 
			
		||||
		if not fields.program then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		reset(pos)
 | 
			
		||||
		reset_meta(pos, fields.code)
 | 
			
		||||
		local err = lc_update(pos, {type="program"})
 | 
			
		||||
		if err then
 | 
			
		||||
			print(err)
 | 
			
		||||
			reset_meta(pos, fields.code, err)
 | 
			
		||||
		end
 | 
			
		||||
	end,
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	mesecons = mesecons,
 | 
			
		||||
	digiline = digiline,
 | 
			
		||||
	virtual_portstates = {	a = a == 1, -- virtual portstates are
 | 
			
		||||
				b = b == 1, -- the ports the the
 | 
			
		||||
				c = c == 1, -- controller powers itself
 | 
			
		||||
				d = d == 1},-- so those that light up
 | 
			
		||||
	after_dig_node = function (pos, node)
 | 
			
		||||
		mesecon.receptor_off(pos, output_rules)
 | 
			
		||||
	end,
 | 
			
		||||
	is_luacontroller = true,
 | 
			
		||||
})
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
------------------------------
 | 
			
		||||
-- overheated luacontroller --
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
local mesecons_burnt = {
 | 
			
		||||
	effector =
 | 
			
		||||
	{
 | 
			
		||||
		rules = mesecon.rules.flat,
 | 
			
		||||
		action_change = function (pos, _, rulename, newstate)
 | 
			
		||||
			-- only update portstates when changes are triggered
 | 
			
		||||
			lc_update_real_portstates(pos, rulename, newstate)
 | 
			
		||||
		end
 | 
			
		||||
		receptor = {
 | 
			
		||||
			state = mesecon.state.on,
 | 
			
		||||
			rules = output_rules[cid]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	minetest.register_node(node_name, {
 | 
			
		||||
		description = "LuaController",
 | 
			
		||||
		drawtype = "nodebox",
 | 
			
		||||
		tiles = {
 | 
			
		||||
			top,
 | 
			
		||||
			"jeija_microcontroller_bottom.png",
 | 
			
		||||
			"jeija_microcontroller_sides.png",
 | 
			
		||||
			"jeija_microcontroller_sides.png",
 | 
			
		||||
			"jeija_microcontroller_sides.png",
 | 
			
		||||
			"jeija_microcontroller_sides.png"
 | 
			
		||||
		},
 | 
			
		||||
		inventory_image = top,
 | 
			
		||||
		paramtype = "light",
 | 
			
		||||
		groups = groups,
 | 
			
		||||
		drop = BASENAME.."0000",
 | 
			
		||||
		sunlight_propagates = true,
 | 
			
		||||
		selection_box = selection_box,
 | 
			
		||||
		node_box = node_box,
 | 
			
		||||
		on_construct = reset_meta,
 | 
			
		||||
		on_receive_fields = on_receive_fields,
 | 
			
		||||
		on_timer = handle_timer,
 | 
			
		||||
		sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
		mesecons = mesecons,
 | 
			
		||||
		digiline = digiline,
 | 
			
		||||
		-- Virtual portstates are the ports that
 | 
			
		||||
		-- the node shows as powered up (light up).
 | 
			
		||||
		virtual_portstates = {
 | 
			
		||||
			a = a == 1,
 | 
			
		||||
			b = b == 1,
 | 
			
		||||
			c = c == 1,
 | 
			
		||||
			d = d == 1,
 | 
			
		||||
		},
 | 
			
		||||
		after_dig_node = function (pos, node)
 | 
			
		||||
			mesecon.receptor_off(pos, output_rules)
 | 
			
		||||
		end,
 | 
			
		||||
		is_luacontroller = true,
 | 
			
		||||
	})
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
------------------------------
 | 
			
		||||
-- Overheated LuaController --
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
minetest.register_node(BASENAME .. "_burnt", {
 | 
			
		||||
	drawtype = "nodebox",
 | 
			
		||||
@@ -520,21 +592,17 @@ minetest.register_node(BASENAME .. "_burnt", {
 | 
			
		||||
	selection_box = selectionbox,
 | 
			
		||||
	node_box = nodebox,
 | 
			
		||||
	on_construct = reset_meta,
 | 
			
		||||
	on_receive_fields = function(pos, formname, fields)
 | 
			
		||||
		if fields.quit then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		reset(pos)
 | 
			
		||||
		reset_meta(pos, fields.code)
 | 
			
		||||
		local err = lc_update(pos, {type="program"})
 | 
			
		||||
		if err then
 | 
			
		||||
			print(err)
 | 
			
		||||
			reset_meta(pos, fields.code, err)
 | 
			
		||||
		end
 | 
			
		||||
	end,
 | 
			
		||||
	on_receive_fields = on_receive_fields,
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	virtual_portstates = {a = false, b = false, c = false, d = false},
 | 
			
		||||
	mesecons = mesecons_burnt,
 | 
			
		||||
	mesecons = {
 | 
			
		||||
		effector = {
 | 
			
		||||
			rules = mesecon.rules.flat,
 | 
			
		||||
			action_change = function(pos, _, rule_name, new_state)
 | 
			
		||||
				update_real_portstates(pos, rule_name, new_state)
 | 
			
		||||
			end,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
------------------------
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user