diff options
| -rw-r--r-- | mesecons/legacy.lua | 59 | ||||
| -rw-r--r-- | mesecons_luacontroller/init.lua | 737 | 
2 files changed, 425 insertions, 371 deletions
| diff --git a/mesecons/legacy.lua b/mesecons/legacy.lua index c09b5a4..6d8ccca 100644 --- a/mesecons/legacy.lua +++ b/mesecons/legacy.lua @@ -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 + diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua index 637b2e5..2cbebd6 100644 --- a/mesecons_luacontroller/init.lua +++ b/mesecons_luacontroller/init.lua @@ -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,83 +116,92 @@ 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) - -	if name ~= newname and vports then -		local rules_on  = {} -		local rules_off = {} +	local new_name = generate_name(ports) -		minetest.swap_node(pos, {name = newname, param2 = node.param2}) +	if name ~= new_name and vports then +		minetest.swap_node(pos, {name = new_name, 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) + +------------------------- +-- Parsing and running -- +------------------------- + +local function safe_print(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] -	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) +minetest.register_globalstep(function(dtime) +	print_count = print_count - dtime +end) + + +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 -		setmetatable(copy, deep_copy(getmetatable(original), visited)) -		return copy -	elseif type(original) == 'function' then --ignore functions +	elseif tp == "function" then  		return nil -	else --by-value type -		return original  	end +	return x  end -local safe_serialize = function(value) -	return minetest.serialize(deep_copy(value)) -end - -mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) -	-- 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}) -end) - -local getinterrupt = function(pos) -	local interrupt = function (time, iid) -- iid = interrupt id +local function get_interrupt(pos) +	-- iid = interrupt id +	local function interrupt(time, iid)  		if type(time) ~= "number" then return end  		local luac_id = minetest.get_meta(pos):get_int("luac_id")  		mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) @@ -175,9 +209,9 @@ local getinterrupt = function(pos)  	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 +219,186 @@ 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) - -	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, +	local vports_copy = {} +	for k, v in pairs(vports) do vports_copy[k] = v end +	local rports = get_real_port_states(pos) + +	-- 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)) -end -local ports_invalid = function (var) -	if type(var) == "table" then -		return false -	end -	return "The ports you set are invalid" +local function save_memory(meta, mem) +	meta:set_string("lc_memory", +		minetest.serialize( +			remove_functions(mem) +		) +	)  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) +mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) +	-- 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) + +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,172 +410,155 @@ 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 ---        ______ ---       | ---       | ---       |        __       ___  _   __         _  _ --- |   | |       |  | |\ |  |  |_| |  | |  |  |_ |_| --- |___| |______ |__| | \|  |  | \ |__| |_ |_ |_ |\ --- | --- | ---  -----------------------  -- 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 - -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 +	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 -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 - -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] +	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 + +	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, +		}, +		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" +	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 = 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, -}) +		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 -- +-- 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 -	} -} -  minetest.register_node(BASENAME .. "_burnt", {  	drawtype = "nodebox",  	tiles = { @@ -518,23 +575,19 @@ minetest.register_node(BASENAME .. "_burnt", {  	drop = BASENAME.."0000",  	sunlight_propagates = true,  	selection_box = selectionbox, -	node_box = nodebox, +	node_box = node_box,  	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_port_states(pos, rule_name, new_state) +			end, +		}, +	},  })  ------------------------ | 
