diff options
| author | Jeija <norrepli@gmail.com> | 2013-02-19 16:54:53 +0100 | 
|---|---|---|
| committer | Jeija <norrepli@gmail.com> | 2013-02-19 16:54:53 +0100 | 
| commit | 8827cfd66f616d8c9a093b1d3fe57effabdbb7e0 (patch) | |
| tree | 700d7f2a36ce774e2b2d2fdffac1d1e0e4e8c66d | |
| parent | d36dd865ad6580bbb3503da199640304b4ccef96 (diff) | |
| parent | 1c4ab938ad6d1a45dc30d0f276c75b248f9796cf (diff) | |
Merge branch 'luacontroller'
| -rw-r--r-- | mesecons/init.lua | 2 | ||||
| -rw-r--r-- | mesecons/internal.lua | 10 | ||||
| -rw-r--r-- | mesecons_luacontroller/depends.txt | 1 | ||||
| -rw-r--r-- | mesecons_luacontroller/init.lua | 451 | ||||
| -rw-r--r-- | mesecons_textures/textures/jeija_close_window.png | bin | 0 -> 323 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luac_background.png | bin | 0 -> 2016 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luac_runbutton.png | bin | 0 -> 4262 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luacontroller_LED_A.png | bin | 0 -> 3541 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luacontroller_LED_B.png | bin | 0 -> 3537 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luacontroller_LED_C.png | bin | 0 -> 3537 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luacontroller_LED_D.png | bin | 0 -> 3537 bytes | |||
| -rw-r--r-- | mesecons_textures/textures/jeija_luacontroller_top.png | bin | 0 -> 11913 bytes | 
12 files changed, 458 insertions, 6 deletions
| diff --git a/mesecons/init.lua b/mesecons/init.lua index 50ed4ca..7f6fe5d 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -98,7 +98,7 @@ function mesecon:receptor_off(pos, rules)  			if not mesecon:connected_to_receptor(np) then  				mesecon:turnoff(np, rulename)  			else -				mesecon:changesignal(np, minetest.env:get_node(np), rulename) +				mesecon:changesignal(np, minetest.env:get_node(np), rulename, mesecon.state.off)  			end  		end  	end diff --git a/mesecons/internal.lua b/mesecons/internal.lua index 2d84787..5e243cf 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -24,7 +24,7 @@  -- SIGNALS  -- mesecon:activate(pos, node)     --> Activates   the effector node at the specific pos (calls nodedef.mesecons.effector.action_on)  -- mesecon:deactivate(pos, node)   --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off) --- mesecon:changesignal(pos, node) --> Changes     the effector node at the specific pos (calls nodedef.mesecons.effector.action_change) +-- mesecon:changesignal(pos, node, rulename, newstate) --> Changes     the effector node at the specific pos (calls nodedef.mesecons.effector.action_change)  -- RULES  -- mesecon:add_rules(name, rules) | deprecated? --> Saves rules table by name @@ -193,10 +193,10 @@ function mesecon:deactivate(pos, node, rulename)  	end  end -function mesecon:changesignal(pos, node, rulename) +function mesecon:changesignal(pos, node, rulename, newstate)  	local effector = mesecon:get_effector(node.name)  	if effector and effector.action_change then -		effector.action_change (pos, node, rulename) +		effector.action_change (pos, node, rulename, newstate)  	end  end @@ -299,7 +299,7 @@ function mesecon:turnon(pos, rulename)  			end  		end  	elseif mesecon:is_effector(node.name) then -		mesecon:changesignal(pos, node, rulename) +		mesecon:changesignal(pos, node, rulename, mesecon.state.on)  		if mesecon:is_effector_off(node.name) then  			mesecon:activate(pos, node, rulename)  		end @@ -322,7 +322,7 @@ function mesecon:turnoff(pos, rulename)  			end  		end  	elseif mesecon:is_effector(node.name) then -		mesecon:changesignal(pos, node, rulename) +		mesecon:changesignal(pos, node, rulename, mesecon.state.off)  		if mesecon:is_effector_on(node.name)  		and not mesecon:is_powered(pos) then  			mesecon:deactivate(pos, node, rulename) diff --git a/mesecons_luacontroller/depends.txt b/mesecons_luacontroller/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mesecons_luacontroller/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua new file mode 100644 index 0000000..d0c98ad --- /dev/null +++ b/mesecons_luacontroller/init.lua @@ -0,0 +1,451 @@ +-- 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 +-- 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 +-- +-- 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, 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"} + +------------------ +-- Action stuff -- +------------------ +-- These helpers are required to set the portstates of the luacontroller + +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 generate_name = function (ports, overwrite) +	local overwrite = overwrite or {} +	local d = overwrite.d or (ports.d and 1 or 0) +	local c = overwrite.c or (ports.c and 1 or 0) +	local b = overwrite.b or (ports.b and 1 or 0) +	local a = overwrite.a or (ports.a and 1 or 0) +	return BASENAME..d..c..b..a +end + +local setport = function (pos, rule, ignore, state, ports) +	local ignorename = generate_name(ports, ignore) +	mesecon:swap_node(pos, ignorename) +	if state then +		mesecon:receptor_on(pos, {rule}) +	else +		mesecon:receptor_off(pos, {rule}) +	end +	if minetest.env:get_node(pos).name ~= ignorename then +		return true -- overridden by second process +	end +	return false -- success +end + +local action = function (pos, ports, forcereset) +	local name = minetest.env:get_node(pos).name +	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 ignore = {} + +		local interrupted +		if ports.a ~= vports.a then interrupted = setport(pos, rules.a, {a = 2}, ports.a, ports) end +		if interrupted and not forcereset then return end +		if ports.b ~= vports.b then interrupted = setport(pos, rules.b, {b = 2}, ports.b, ports) end +		if interrupted and not forcereset then return end +		if ports.c ~= vports.c then interrupted = setport(pos, rules.c, {c = 2}, ports.c, ports) end +		if interrupted and not forcereset then return end +		if ports.d ~= vports.d then interrupted = setport(pos, rules.d, {d = 2}, ports.d, ports) end +		if interrupted and not forcereset then return end + +		mesecon:swap_node(pos, newname) +	end +end + +local delayedaction = function (params) +	action(params.pos, params.ports) +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 > 20 then  +		return true +	else  +		return false  +	end +end + +local overheat_off = function(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"} +	for _, p in ipairs(prohibited) do +		if string.find(code, p) then +			return "Prohibited command: "..p +		end +	end +end + +local safeprint = function(param) +	print(dump(param)) +end + +local interrupt = function(params) +	lc_update(params.pos, {type="interrupt", iid = params.iid}) +end + +local getinterrupt = function(pos) +	local interrupt = function (time, iid) -- iid = interrupt id +		if type(time) ~= "number" then return end +		local iid = iid or math.random() +		local meta = minetest.env:get_meta(pos) +		local interrupts = minetest.deserialize(meta:get_string("lc_interrupts")) or {} +		table.insert (interrupts, iid) +		meta:set_string("lc_interrupts", minetest.serialize(interrupts)) +		minetest.after(time, interrupt, {pos=pos, iid = iid}) +	end +	return interrupt +end + +local getdigiline_send = function (pos) +	local digiline_send = function (channel, msg) +		if digiline then +			digiline:receptor_send(pos, digiline.rules.default, channel, msg) +		end +	end +	return digiline_send +end + +local create_environment = function(pos, mem, event) +	-- 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) + +	return {	print = safeprint, +			pin = merge_portstates(vports, rports), +			port = vports, +			interrupt = getinterrupt(pos), +			digiline_send = getdigiline_send(pos), +			mem = mem, +			tostring = tostring, +			tonumber = tonumber, +			string = string, +			event = event} +end + +local create_sandbox = function (code, env) +	-- Create Sandbox +	if code:byte(1) == 27 then +		return _, "You Hacker You! Don't use binary code!" +	end +	f, msg = loadstring(code) +	if not f then return _, msg end +	setfenv(f, env) +	return f +end + +local do_overheat = function (pos, meta) +	-- 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 true +	end +end + +local load_memory = function(meta) +	return minetest.deserialize(meta:get_string("lc_memory")) or {} +end + +local save_memory = function(meta, mem) +	meta:set_string("lc_memory", minetest.serialize(mem)) +end + +local interrupt_allow = function (meta, event) +	if event.type ~= "interrupt" then return true end + +	local interrupts = minetest.deserialize(meta:get_string("lc_interrupts")) or {} +	for _, i in ipairs(interrupts) do +		if minetest.serialize(i) == minetest.serialize(event.iid) then +			return true +		end +	end + +	return false +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 meta = minetest.env:get_meta(pos) +	if not interrupt_allow(meta, event) then return end +	if do_overheat(pos, meta) then return end + +	-- load code & mem from memory +	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 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(f) +	if not success then return msg end +	if ports_invalid(env.port) then return ports_invalid(env.port) end + +	save_memory(meta, mem) + +	-- Actually set the ports +	minetest.after(0, delayedaction, {pos = pos, ports = env.port}) +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]".. +		"background[-0.2,-0.25;10.4,8.75;jeija_luac_background.png]".. +		"textarea[0.2,0.6;10.2,5;code;;"..code.."]".. +		"image_button[3.75,6;2.5,1;jeija_luac_runbutton.png;program;]".. +		"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) +end + +local reset = function (pos) +	minetest.env:get_meta(pos):set_string("lc_interrupts", "") +	action(pos, {a=false, b=false, c=false, d=false}, true) +end + +--        ______ +--       | +-- |   | | +-- |___| |        __       ___  _   __         _  _ +-- |     |       |  | |\ |  |  |_| |  | |  |  |_ |_| +-- |     |______ |__| | \|  |  | \ |__| |_ |_ |_ |\ +-- + +----------------------- +-- Node Registration -- +----------------------- + +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 selectionbox = { +		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}) +		end +	} +} + +for a = 0, 2 do -- 0 = off; 1 = on; 2 = ignore +for b = 0, 2 do +for c = 0, 2 do +for d = 0, 2 do + +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} +else +	groups = {dig_immediate=2} +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(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" +		}, + +	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 = lc_update(pos, {type="program"}) +		if err then print(err) end +		reset_meta(pos, fields.code, err) +	end, +	mesecons = mesecons, +	digiline = digiline, +	is_luacontroller = true, +	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 + +------------------------ +-- Craft Registration -- +------------------------ + +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', ''}, +	} +}) + diff --git a/mesecons_textures/textures/jeija_close_window.png b/mesecons_textures/textures/jeija_close_window.pngBinary files differ new file mode 100644 index 0000000..5c27c6c --- /dev/null +++ b/mesecons_textures/textures/jeija_close_window.png diff --git a/mesecons_textures/textures/jeija_luac_background.png b/mesecons_textures/textures/jeija_luac_background.pngBinary files differ new file mode 100644 index 0000000..40e316c --- /dev/null +++ b/mesecons_textures/textures/jeija_luac_background.png diff --git a/mesecons_textures/textures/jeija_luac_runbutton.png b/mesecons_textures/textures/jeija_luac_runbutton.pngBinary files differ new file mode 100644 index 0000000..157507f --- /dev/null +++ b/mesecons_textures/textures/jeija_luac_runbutton.png diff --git a/mesecons_textures/textures/jeija_luacontroller_LED_A.png b/mesecons_textures/textures/jeija_luacontroller_LED_A.pngBinary files differ new file mode 100644 index 0000000..a187e8e --- /dev/null +++ b/mesecons_textures/textures/jeija_luacontroller_LED_A.png diff --git a/mesecons_textures/textures/jeija_luacontroller_LED_B.png b/mesecons_textures/textures/jeija_luacontroller_LED_B.pngBinary files differ new file mode 100644 index 0000000..738ba96 --- /dev/null +++ b/mesecons_textures/textures/jeija_luacontroller_LED_B.png diff --git a/mesecons_textures/textures/jeija_luacontroller_LED_C.png b/mesecons_textures/textures/jeija_luacontroller_LED_C.pngBinary files differ new file mode 100644 index 0000000..abe0fe6 --- /dev/null +++ b/mesecons_textures/textures/jeija_luacontroller_LED_C.png diff --git a/mesecons_textures/textures/jeija_luacontroller_LED_D.png b/mesecons_textures/textures/jeija_luacontroller_LED_D.pngBinary files differ new file mode 100644 index 0000000..cc10170 --- /dev/null +++ b/mesecons_textures/textures/jeija_luacontroller_LED_D.png diff --git a/mesecons_textures/textures/jeija_luacontroller_top.png b/mesecons_textures/textures/jeija_luacontroller_top.pngBinary files differ new file mode 100644 index 0000000..3128230 --- /dev/null +++ b/mesecons_textures/textures/jeija_luacontroller_top.png | 
