diff options
| -rw-r--r-- | mesecons_luacontroller/init.lua | 172 | 
1 files changed, 119 insertions, 53 deletions
diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua index f24a8ad..c125ec9 100644 --- a/mesecons_luacontroller/init.lua +++ b/mesecons_luacontroller/init.lua @@ -3,7 +3,7 @@  -- 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 +-- 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  -- @@ -21,10 +21,10 @@  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} +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 -- @@ -54,35 +54,58 @@ local merge_portstates = function (ports, vports)  	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 +local action_setports_on = function (pos, ports, vports) +	if vports.a ~= ports.a and ports.a then +		mesecon:receptor_on(pos, {rules.a})  	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 +	if vports.b ~= ports.b and ports.b then +		mesecon:receptor_on(pos, {rules.b})  	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 +	if vports.c ~= ports.c and ports.c then +		mesecon:receptor_on(pos, {rules.c})  	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 +	if vports.d ~= ports.d and ports.d then +		mesecon:receptor_on(pos, {rules.d}) +	end +end + +local action_setports_off = function (pos, ports, vports) +	local todo = {} +	if vports.a ~= ports.a and not ports.a then +		table.insert(todo, mesecon:addPosRule(pos, rules.a)) +	end +	if vports.b ~= ports.b and not ports.b then +		table.insert(todo, mesecon:addPosRule(pos, rules.b)) +	end +	if vports.c ~= ports.c and not ports.c then +		table.insert(todo, mesecon:addPosRule(pos, rules.c)) +	end +	if vports.d ~= ports.d and not ports.d then +		table.insert(todo, mesecon:addPosRule(pos, rules.d)) +	end + +	for _, t in ipairs(todo) do +		local link, rulename = mesecon:rules_link(pos, t) +		if link then +			mesecon:turnoff(t, rulename) +		end  	end  end  local action = function (pos, ports) -	local vports = minetest.registered_nodes[minetest.env:get_node(pos).name].virtual_portstates; -	local name = BASENAME +	local name = minetest.env:get_node(pos).name +	local vports = minetest.registered_nodes[name].virtual_portstates +	local newname = 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) +	if name ~= newname and vports then +		action_setports_off (pos, ports, vports) +		mesecon:swap_node(pos, newname) +		action_setports_on (pos, ports, vports) +	end  end  -------------------- @@ -106,7 +129,7 @@ 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  +	if h > 10 then   		return true  	else   		return false  @@ -135,7 +158,22 @@ local safeprint = function(param)  	print(dump(param))  end -local create_environment = function(pos, mem) +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 +		local meta = minetest.env:get_meta(pos) +		local interrupts = minetest.deserialize(meta:get_string("lc_interrupts")) or {} +		table.insert (interrupts, iid or 0) +		meta:set_string("lc_interrupts", minetest.serialize(interrupts)) +		minetest.after(time, interrupt, {pos=pos, iid = iid}) +	end +	return interrupt +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} @@ -144,7 +182,9 @@ local create_environment = function(pos, mem)  	return {	print = safeprint,  			pin = merge_portstates(vports, rports),  			port = vports, -			mem = mem} +			interrupt = getinterrupt(pos), +			mem = mem, +			event = event}  end  local create_sandbox = function (code, env) @@ -178,23 +218,40 @@ 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 i == event.iid then +			return true +		end +	end + +	return false +end +  ----------------------  -- Parsing function --  ---------------------- -local update = function (pos) +lc_update = function (pos, event)  	local meta = minetest.env:get_meta(pos) +	if not interrupt_allow(meta, event) 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) +	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) +	local success, msg = pcall(f, port)  	if not success then return msg end  	do_overheat(pos, meta) @@ -235,11 +292,15 @@ end  -- Node Registration --  ----------------------- +local output_rules={} +local input_rules={} +  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 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" @@ -260,31 +321,35 @@ 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 = { +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_on = function (pos, _, rulename) +			lc_update(pos, {type="on",  pin=rulename}) +		end, +		action_off = function (pos, _, rulename) +			lc_update(pos, {type="off", pin=rulename}) +		end +	}, +	receptor = +	{  		state = mesecon.state.on, -		rules = output_rules +		rules = output_rules[cid]  	} -end +}  local nodebox = {  		type = "fixed", @@ -322,11 +387,12 @@ minetest.register_node(nodename, {  	on_receive_fields = function(pos, formname, fields)  		reset(pos)  		reset_meta(pos, fields.code) -		local err = update(pos) +		local err = lc_update(pos, {type="program"})  		if err then print(err) end  		reset_meta(pos, fields.code, err)  	end,  	mesecons = mesecons, +	is_luacontroller = true,  	virtual_portstates = {	a = a == 1, -- virtual portstates are  					b = b == 1, -- the ports the the  					c = c == 1, -- controller powers itself  | 
