mirror of
				https://github.com/minetest-mods/mesecons.git
				synced 2025-11-04 12:55:29 +01:00 
			
		
		
		
	Add luacontroller, a microcontroller that you can code in lua.
It still misses some functionality such as a persistent memory and a timer, but that is subject to change. The code runs in a sandbox. Speaking long term this will hopefully replace the old controller.
This commit is contained in:
		
							
								
								
									
										1
									
								
								mesecons_luacontroller/depends.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mesecons_luacontroller/depends.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
mesecons
 | 
			
		||||
							
								
								
									
										303
									
								
								mesecons_luacontroller/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								mesecons_luacontroller/init.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,303 @@
 | 
			
		||||
-- 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, ports, vports): activates/deactivates the mesecons according to the portstates (helper for action)
 | 
			
		||||
-- action(pos, ports): Applies new portstates to a luacontroller at pos
 | 
			
		||||
-- 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
 | 
			
		||||
--
 | 
			
		||||
-- The Sandbox
 | 
			
		||||
-- The whole code of the controller runs in a sandbox,
 | 
			
		||||
-- a very restricted environment.
 | 
			
		||||
-- However, as this does not prevent you from using e.g. loops,
 | 
			
		||||
-- we need to check for these prohibited commands first.
 | 
			
		||||
-- Actually the only way to damage the server is to
 | 
			
		||||
-- use too much memory from the sandbox.
 | 
			
		||||
-- You can add more functions to the environment
 | 
			
		||||
-- (see where local env is defined)
 | 
			
		||||
-- Something nice to play is is appending minetest.env to it.
 | 
			
		||||
 | 
			
		||||
local BASENAME = "mesecons_luacontroller:luacontroller"
 | 
			
		||||
 | 
			
		||||
local rules = {}
 | 
			
		||||
rules.a = {x = -1, y = 0, z =  0}
 | 
			
		||||
rules.b = {x =  0, y = 0, z =  1}
 | 
			
		||||
rules.c = {x =  1, y = 0, z =  0}
 | 
			
		||||
rules.d = {x =  0, y = 0, z = -1}
 | 
			
		||||
 | 
			
		||||
local get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
 | 
			
		||||
	ports = {
 | 
			
		||||
		a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a))
 | 
			
		||||
			and mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos),
 | 
			
		||||
		b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b))
 | 
			
		||||
			and mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos),
 | 
			
		||||
		c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c))
 | 
			
		||||
			and mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos),
 | 
			
		||||
		d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d))
 | 
			
		||||
			and mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos),
 | 
			
		||||
	}
 | 
			
		||||
	return ports
 | 
			
		||||
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
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local action_setports = function (pos, ports, vports)
 | 
			
		||||
	if vports.a ~= ports.a then
 | 
			
		||||
		if ports.a then mesecon:receptor_on(pos, {rules.a})
 | 
			
		||||
		else mesecon:receptor_off(pos, {rules.a}) end
 | 
			
		||||
	end
 | 
			
		||||
	if vports.b ~= ports.b then
 | 
			
		||||
		if ports.b then mesecon:receptor_on(pos, {rules.b})
 | 
			
		||||
		else mesecon:receptor_off(pos, {rules.b}) end
 | 
			
		||||
	end
 | 
			
		||||
	if vports.c ~= ports.c then
 | 
			
		||||
		if ports.c then mesecon:receptor_on(pos, {rules.c})
 | 
			
		||||
		else mesecon:receptor_off(pos, {rules.c}) end
 | 
			
		||||
	end
 | 
			
		||||
	if vports.d ~= ports.d then
 | 
			
		||||
		if ports.d then mesecon:receptor_on(pos, {rules.d})
 | 
			
		||||
		else mesecon:receptor_off(pos, {rules.d}) end
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local action = function (pos, ports)
 | 
			
		||||
	local vports = minetest.registered_nodes[minetest.env:get_node(pos).name].virtual_portstates;
 | 
			
		||||
	local name = BASENAME
 | 
			
		||||
		..tonumber(ports.d and 1 or 0)
 | 
			
		||||
		..tonumber(ports.c and 1 or 0)
 | 
			
		||||
		..tonumber(ports.b and 1 or 0)
 | 
			
		||||
		..tonumber(ports.a and 1 or 0)
 | 
			
		||||
	mesecon:swap_node(pos, name)
 | 
			
		||||
 | 
			
		||||
	action_setports (pos, ports, vports)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Overheat Stuff
 | 
			
		||||
local heat = function (meta) -- warm up
 | 
			
		||||
	h = meta:get_int("heat")
 | 
			
		||||
	if h ~= nil then
 | 
			
		||||
		meta:set_int("heat", h + 1)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local cool = function (meta) -- cool down after a while
 | 
			
		||||
	h = meta:get_int("heat")
 | 
			
		||||
	if h ~= nil then
 | 
			
		||||
		meta:set_int("heat", h - 1)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local overheat = function (meta) -- determine if too hot
 | 
			
		||||
	h = meta:get_int("heat")
 | 
			
		||||
	if h == nil then return true end -- if nil then overheat
 | 
			
		||||
	if h > 30 then 
 | 
			
		||||
		return true
 | 
			
		||||
	else 
 | 
			
		||||
		return false 
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local overheat_off = function(pos)
 | 
			
		||||
	rules = mesecon:get_rules("mesecons_microcontroller:microcontroller1111")
 | 
			
		||||
	mesecon:receptor_off(pos, rules)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local update = function (pos)
 | 
			
		||||
	local meta = minetest.env:get_meta(pos)
 | 
			
		||||
	code = meta:get_string("code")
 | 
			
		||||
 | 
			
		||||
	-- Clean code
 | 
			
		||||
	local prohibited = {"while", "for", "repeat", "until"}
 | 
			
		||||
	for _, p in ipairs(prohibited) do
 | 
			
		||||
		if string.find(code, p) then
 | 
			
		||||
			return "Prohibited command: "..p
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- Gather variables for the environment
 | 
			
		||||
	local vports = minetest.registered_nodes[minetest.env: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 env = {	print = print,
 | 
			
		||||
				selfpos = pos,
 | 
			
		||||
				dump = dump,
 | 
			
		||||
				pin = merge_portstates(vports, rports),
 | 
			
		||||
				port = vports}
 | 
			
		||||
 | 
			
		||||
	-- Create Sandbox
 | 
			
		||||
	if code:byte(1) == 27 then
 | 
			
		||||
		return "You Hacker You! Don't use binary code!"
 | 
			
		||||
	end
 | 
			
		||||
	local f, msg = loadstring(code)
 | 
			
		||||
	if not f then return msg end
 | 
			
		||||
	setfenv(f, env)
 | 
			
		||||
	success, msg = pcall(f)
 | 
			
		||||
 | 
			
		||||
	-- Overheat protection
 | 
			
		||||
	heat(meta)
 | 
			
		||||
	minetest.after(0.5, cool, meta)
 | 
			
		||||
	if overheat(meta) then
 | 
			
		||||
		minetest.env:remove_node(pos)
 | 
			
		||||
		minetest.after(0.2, overheat_off, pos) -- wait for pending operations
 | 
			
		||||
		minetest.env:add_item(pos, BASENAME.."0000")
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- Actually set the ports
 | 
			
		||||
	if not success then
 | 
			
		||||
		return msg
 | 
			
		||||
	else
 | 
			
		||||
		action(pos, env.port)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local reset_meta = function(pos, code, errmsg)
 | 
			
		||||
	local meta = minetest.env:get_meta(pos)
 | 
			
		||||
	code = code or "";
 | 
			
		||||
	errmsg = errmsg or "";
 | 
			
		||||
	errmsg = string.gsub(errmsg, "%[", "(") -- would otherwise
 | 
			
		||||
	errmsg = string.gsub(errmsg, "%]", ")") -- corrupt formspec
 | 
			
		||||
	meta:set_string("code", code)
 | 
			
		||||
	meta:set_string("formspec", "size[10,8]"..
 | 
			
		||||
		"textarea[0.2,0.4;10.2,5;code;Code:;"..code.."]"..
 | 
			
		||||
		"button[3.5,7.5;2,0;program;Program]"..
 | 
			
		||||
		"image_button_exit[9.62,-0.35;0.7,0.7;jeija_close_window.png;exit;]"..
 | 
			
		||||
		"label[0.1,4.5;"..errmsg.."]")
 | 
			
		||||
	meta:set_int("heat", 0)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local reset = function (pos)
 | 
			
		||||
	action(pos, {a=false, b=false, c=false, d=false})
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--        ______
 | 
			
		||||
--       |
 | 
			
		||||
-- |   | |
 | 
			
		||||
-- |___| |        __       ___  _   __         _  _
 | 
			
		||||
-- |     |       |  | |\ |  |  |_| |  | |  |  |_ |_|
 | 
			
		||||
-- |     |______ |__| | \|  |  | \ |__| |_ |_ |_ |\
 | 
			
		||||
--
 | 
			
		||||
-- Actually register all the stuff:
 | 
			
		||||
 | 
			
		||||
for a = 0, 1 do
 | 
			
		||||
for b = 0, 1 do
 | 
			
		||||
for c = 0, 1 do
 | 
			
		||||
for d = 0, 1 do
 | 
			
		||||
local nodename = BASENAME..tostring(d)..tostring(c)..tostring(b)..tostring(a)
 | 
			
		||||
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}
 | 
			
		||||
else
 | 
			
		||||
	groups = {dig_immediate=2}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local output_rules={}
 | 
			
		||||
if (a == 1) then table.insert(output_rules, rules.a) end
 | 
			
		||||
if (b == 1) then table.insert(output_rules, rules.b) end
 | 
			
		||||
if (c == 1) then table.insert(output_rules, rules.c) end
 | 
			
		||||
if (d == 1) then table.insert(output_rules, rules.d) end
 | 
			
		||||
 | 
			
		||||
local input_rules={}
 | 
			
		||||
if (a == 0) then table.insert(input_rules, rules.a) end
 | 
			
		||||
if (b == 0) then table.insert(input_rules, rules.b) end
 | 
			
		||||
if (c == 0) then table.insert(input_rules, rules.c) end
 | 
			
		||||
if (d == 0) then table.insert(input_rules, rules.d) end
 | 
			
		||||
 | 
			
		||||
local mesecons = {effector =
 | 
			
		||||
{
 | 
			
		||||
	rules = input_rules,
 | 
			
		||||
	action_change = function (pos)
 | 
			
		||||
		update(pos)
 | 
			
		||||
	end
 | 
			
		||||
}}
 | 
			
		||||
if nodename ~= BASENAME.."0000" then
 | 
			
		||||
	mesecons.receptor = {
 | 
			
		||||
		state = mesecon.state.on,
 | 
			
		||||
		rules = output_rules
 | 
			
		||||
	}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
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 selectionbox = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
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"
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		reset(pos)
 | 
			
		||||
		reset_meta(pos, fields.code)
 | 
			
		||||
		local err = update(pos)
 | 
			
		||||
		if err then print(err) end
 | 
			
		||||
		reset_meta(pos, fields.code, err)
 | 
			
		||||
	end,
 | 
			
		||||
	mesecons = mesecons,
 | 
			
		||||
	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,
 | 
			
		||||
})
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
minetest.register_craft({
 | 
			
		||||
	output = BASENAME.."0000 2",
 | 
			
		||||
	recipe = {
 | 
			
		||||
		{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
 | 
			
		||||
		{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
 | 
			
		||||
		{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''},
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_close_window.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_close_window.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 7.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_A.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_A.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_B.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_B.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_C.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_C.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_D.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_LED_D.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_textures/textures/jeija_luacontroller_top.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 12 KiB  | 
		Reference in New Issue
	
	Block a user