diff options
| -rw-r--r-- | mesecons/actionqueue.lua | 119 | ||||
| -rw-r--r-- | mesecons/init.lua | 86 | ||||
| -rw-r--r-- | mesecons/internal.lua | 233 | ||||
| -rw-r--r-- | mesecons/legacy.lua | 29 | ||||
| -rw-r--r-- | mesecons/services.lua | 8 | ||||
| -rw-r--r-- | mesecons/settings.lua | 2 | ||||
| -rw-r--r-- | mesecons/util.lua | 12 | ||||
| -rw-r--r-- | mesecons_delayer/init.lua | 14 | ||||
| -rw-r--r-- | mesecons_gates/init.lua | 3 | ||||
| -rw-r--r-- | mesecons_luacontroller/init.lua | 51 | ||||
| -rw-r--r-- | mesecons_microcontroller/init.lua | 61 | 
11 files changed, 396 insertions, 222 deletions
| diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua new file mode 100644 index 0000000..cf74d47 --- /dev/null +++ b/mesecons/actionqueue.lua @@ -0,0 +1,119 @@ +mesecon.queue.actions={} -- contains all ActionQueue actions + +function mesecon.queue:add_function(name, func) +	mesecon.queue.funcs[name] = func +end + +-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten +-- use overwritecheck nil to never overwrite, but just add the event to the queue +-- priority specifies the order actions are executed within one globalstep, highest by default +-- should be between 0 and 1 +function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority) +	-- Create Action Table: +	time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution +	priority = priority or 1 +	action = {	pos=mesecon:tablecopy(pos), +			func=func, +			params=mesecon:tablecopy(params), +			time=time, +			owcheck=(overwritecheck and mesecon:tablecopy(overwritecheck)) or nil, +			priority=priority} + +	-- if not using the queue, (MESECONS_GLOBALSTEP off), just execute the function an we're done +	if not MESECONS_GLOBALSTEP and action.time == 0 then +		mesecon.queue:execute(action) +		return +	end + +	local toremove = nil +	-- Otherwise, add the action to the queue +	if overwritecheck then -- check if old action has to be overwritten / removed: +		for i, ac in ipairs(mesecon.queue.actions) do +			if(mesecon:cmpPos(pos, ac.pos) +			and mesecon:cmpAny(overwritecheck, ac.owcheck)) then +				toremove = i +				break +			end +		end +	end + +	if (toremove ~= nil) then +		table.remove(mesecon.queue.actions, toremove) +	end + +	table.insert(mesecon.queue.actions, action) +end + +-- execute the stored functions on a globalstep +-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function +-- this makes sure that resuming mesecons circuits when restarting minetest works fine +-- However, even that does not work in some cases, that's why we delay the time the globalsteps +-- start to be execute by 5 seconds +local get_highest_priority = function (actions) +	local highestp = 0, highesti +	for i, ac in ipairs(actions) do +		if ac.priority > highestp then +			highestp = ac.priority +			highesti = i +		end +	end + +	return highesti +end + +local m_time = 0 +minetest.register_globalstep(function (dtime) +	m_time = m_time + dtime +	if (m_time < MESECONS_RESUMETIME) then return end -- don't even try if server has not been running for XY seconds +	local actions = mesecon:tablecopy(mesecon.queue.actions) +	local actions_now={} + +	mesecon.queue.actions = {} + +	-- sort actions in execute now (actions_now) and for later (mesecon.queue.actions) +	for i, ac in ipairs(actions) do +		if ac.time > 0 then +			ac.time = ac.time - dtime -- executed later +			table.insert(mesecon.queue.actions, ac) +		else +			table.insert(actions_now, ac) +		end +	end + +	while(#actions_now > 0) do -- execute highest priorities first, until all are executed +		local hp = get_highest_priority(actions_now) +		mesecon.queue:execute(actions_now[hp]) +		table.remove(actions_now, hp) +	end +end) + +function mesecon.queue:execute(action) +	mesecon.queue.funcs[action.func](action.pos, unpack(action.params)) +end + + +-- Store and read the ActionQueue to / from a file +-- so that upcoming actions are remembered when the game +-- is restarted + +local wpath = minetest.get_worldpath() +local function file2table(filename) +	local f = io.open(filename, "r") +	if f==nil then return {} end +	local t = f:read("*all") +	f:close() +	if t=="" or t==nil then return {} end +	return minetest.deserialize(t) +end + +local function table2file(filename, table) +	local f = io.open(filename, "w") +	f:write(minetest.serialize(table)) +	f:close() +end + +mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue") + +minetest.register_on_shutdown(function() +	mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions) +end) diff --git a/mesecons/init.lua b/mesecons/init.lua index 640af4d..b5cf68b 100644 --- a/mesecons/init.lua +++ b/mesecons/init.lua @@ -42,37 +42,8 @@  -- PUBLIC VARIABLES  mesecon={} -- contains all functions and all global variables -mesecon.actions_on={} -- Saves registered function callbacks for mesecon on | DEPRECATED -mesecon.actions_off={} -- Saves registered function callbacks for mesecon off | DEPRECATED -mesecon.actions_change={} -- Saves registered function callbacks for mesecon change | DEPRECATED -mesecon.receptors={} --  saves all information about receptors  | DEPRECATED -mesecon.effectors={} --  saves all information about effectors  | DEPRECATED -mesecon.conductors={} -- saves all information about conductors | DEPRECATED - - -local wpath = minetest.get_worldpath() -local function read_file(fn) -	local f = io.open(fn, "r") -	if f==nil then return {} end -	local t = f:read("*all") -	f:close() -	if t=="" or t==nil then return {} end -	return minetest.deserialize(t) -end - -local function write_file(fn, tbl) -	local f = io.open(fn, "w") -	f:write(minetest.serialize(tbl)) -	f:close() -end - -mesecon.to_update = read_file(wpath.."/mesecon_to_update") -mesecon.r_to_update = read_file(wpath.."/mesecon_r_to_update") - -minetest.register_on_shutdown(function() -	write_file(wpath.."/mesecon_to_update",mesecon.to_update) -	write_file(wpath.."/mesecon_r_to_update",mesecon.r_to_update) -end) +mesecon.queue={} -- contains the ActionQueue +mesecon.queue.funcs={} -- contains all ActionQueue functions  -- Settings  dofile(minetest.get_modpath("mesecons").."/settings.lua") @@ -86,6 +57,10 @@ dofile(minetest.get_modpath("mesecons").."/presets.lua");  -- mostly things that make the source look cleaner  dofile(minetest.get_modpath("mesecons").."/util.lua"); +-- The ActionQueue +-- Saves all the actions that have to be execute in the future +dofile(minetest.get_modpath("mesecons").."/actionqueue.lua"); +  -- Internal stuff  -- This is the most important file  -- it handles signal transmission and basically everything else @@ -101,9 +76,22 @@ dofile(minetest.get_modpath("mesecons").."/legacy.lua");  -- API  -- these are the only functions you need to remember -function mesecon:receptor_on_i(pos, rules) +mesecon.queue:add_function("receptor_on", function (pos, rules)  	rules = rules or mesecon.rules.default +	-- if area (any of the rule targets) is not loaded, keep trying and call this again later +	if MESECONS_GLOBALSTEP then -- trying to enable resuming with globalstep disabled would cause an endless loop +		for _, rule in ipairs(mesecon:flattenrules(rules)) do +			local np = mesecon:addPosRule(pos, rule) +			-- if area is not loaded, keep trying +			if minetest.get_node_or_nil(np) == nil then +				mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) +				return +			end +		end +	end + +	-- execute action  	for _, rule in ipairs(mesecon:flattenrules(rules)) do  		local np = mesecon:addPosRule(pos, rule)  		local rulenames = mesecon:rules_link_rule_all(pos, rule) @@ -111,19 +99,26 @@ function mesecon:receptor_on_i(pos, rules)  			mesecon:turnon(np, rulename)  		end  	end -end +end)  function mesecon:receptor_on(pos, rules) -	if MESECONS_GLOBALSTEP then -		rules = rules or mesecon.rules.default -		mesecon.r_to_update[#mesecon.r_to_update+1]={pos=pos, rules=rules, action="on"} -	else -		mesecon:receptor_on_i(pos, rules) -	end +	mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)  end -function mesecon:receptor_off_i(pos, rules) +mesecon.queue:add_function("receptor_off", function (pos, rules)  	rules = rules or mesecon.rules.default + +	-- if area (any of the rule targets) is not loaded, keep trying and call this again later +	if MESECONS_GLOBALSTEP then +		for _, rule in ipairs(mesecon:flattenrules(rules)) do +			local np = mesecon:addPosRule(pos, rule) +			if minetest.get_node_or_nil(np) == nil then +				mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) +				return +			end +		end +	end +  	for _, rule in ipairs(mesecon:flattenrules(rules)) do  		local np = mesecon:addPosRule(pos, rule)  		local rulenames = mesecon:rules_link_rule_all(pos, rule) @@ -131,19 +126,14 @@ function mesecon:receptor_off_i(pos, rules)  			if not mesecon:connected_to_receptor(np, mesecon:invertRule(rule)) then  				mesecon:turnoff(np, rulename)  			else -				mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off) +				mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)  			end  		end  	end -end +end)  function mesecon:receptor_off(pos, rules) -	if MESECONS_GLOBALSTEP then -		rules = rules or mesecon.rules.default -		mesecon.r_to_update[#mesecon.r_to_update+1]={pos=pos, rules=rules, action="off"} -	else -		mesecon:receptor_off_i(pos, rules) -	end +	mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)  end diff --git a/mesecons/internal.lua b/mesecons/internal.lua index cb77f5d..3975b6a 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -22,9 +22,9 @@  -- mesecon:effector_get_rules(node)  --> Returns the input rules of the effector (mesecon.rules.default if none specified)  -- 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, rulename, newstate) --> Changes     the effector node at the specific pos (calls nodedef.mesecons.effector.action_change) +-- mesecon:activate(pos, node, recdepth)		--> Activates   the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher recdepths are executed later +-- mesecon:deactivate(pos, node, recdepth)		--> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), " +-- 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 @@ -41,8 +41,8 @@  -- HIGH-LEVEL Internals  -- mesecon:is_power_on(pos)             --> Returns true if pos emits power in any way  -- mesecon:is_power_off(pos)            --> Returns true if pos does not emit power in any way --- mesecon:turnon(pos, rulename)        --> Returns true  whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon --- mesecon:turnoff(pos, rulename)       --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff +-- mesecon:turnon(pos, rulename)        --> Returns true  whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion +-- mesecon:turnoff(pos, rulename)       --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion  -- mesecon:connected_to_receptor(pos)   --> Returns true if pos is connected to a receptor directly or via conductors; calls itself if pos is a conductor --> recursive  -- mesecon:rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)  -- mesecon:rules_link_anydir(outp., inp., d_outpr.)   --> Same as rules mesecon:rules_link but also returns true if output and input are swapped @@ -177,121 +177,76 @@ function mesecon:effector_get_rules(node)  	return mesecon.rules.default  end ---Signals +-- ####################### +-- # Signals (effectors) # +-- ####################### -function mesecon:activate(pos, node, rulename) -	if MESECONS_GLOBALSTEP then -		if rulename == nil then -			for _,rule in ipairs(mesecon:effector_get_rules(node)) do -				mesecon:activate(pos, node, rule) -			end -			return -		end -		add_action(pos, "on", rulename) -	else -		local effector = mesecon:get_effector(node.name) -		if effector and effector.action_on then -			effector.action_on (pos, node, rulename) -		end -	end -end +-- Activation: +mesecon.queue:add_function("activate", function (pos, rulename) +	node = minetest.get_node(pos) +	effector = mesecon:get_effector(node.name) -function mesecon:deactivate(pos, node, rulename) -	if MESECONS_GLOBALSTEP then -		if rulename == nil then -			for _,rule in ipairs(mesecon:effector_get_rules(node)) do -				mesecon:deactivate(pos, node, rule) -			end -			return -		end -		add_action(pos, "off", rulename) -	else -		local effector = mesecon:get_effector(node.name) -		if effector and effector.action_off then -			effector.action_off (pos, node, rulename) -		end +	if effector and effector.action_on then +		effector.action_on(pos, node, rulename)  	end -end +end) -function mesecon:changesignal(pos, node, rulename, newstate) -	 -	newstate = newstate or "on" -	--rulename = rulename or mesecon.rules.default -	if MESECONS_GLOBALSTEP then -		if rulename == nil then -			for _,rule in ipairs(mesecon:effector_get_rules(node)) do -				mesecon:changesignal(pos, node, rule, newstate) -			end -		return -		end -		add_action(pos, "c"..newstate, rulename) -	else -		local effector = mesecon:get_effector(node.name) -		if effector and effector.action_change then -			effector.action_change (pos, node, rulename, newstate) +function mesecon:activate(pos, node, rulename, recdepth) +	if rulename == nil then +		for _,rule in ipairs(mesecon:effector_get_rules(node)) do +			mesecon:activate(pos, node, rule, recdepth + 1)  		end +		return  	end +	mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / recdepth)  end -function execute_actions(dtime) -	local nactions = mesecon.to_update -	mesecon.to_update = {} -	for _,i in ipairs(nactions) do -		node = minetest.get_node(i.pos) -		if node.name=="ignore" then -			add_action(i.pos, i.action, i.rname) -		else -			effector = mesecon:get_effector(node.name) -			if i.action == "on" then -				if effector and effector.action_on then -					effector.action_on(i.pos, node, i.rname) -				end -			elseif i.action == "off" then -				if effector and effector.action_off then -					effector.action_off(i.pos, node, i.rname) -				end -			elseif i.action == "con" then -				if effector and effector.action_change then -					effector.action_change(i.pos, node, i.rname, "on") -				end -			elseif i.action == "coff" then -				if effector and effector.action_change then -					effector.action_change(i.pos, node, i.rname, "off") -				end -			end -		end + +-- Deactivation +mesecon.queue:add_function("deactivate", function (pos, rulename) +	node = minetest.get_node(pos) +	effector = mesecon:get_effector(node.name) + +	if effector and effector.action_off then +		effector.action_off(pos, node, rulename)  	end -	local nactions = mesecon.r_to_update -	mesecon.r_to_update = {} -	for _,i in ipairs(nactions) do -		if i.action == "on" then -			mesecon:receptor_on_i(i.pos, i.rules) -		else -			mesecon:receptor_off_i(i.pos,i.rules) +end) + +function mesecon:deactivate(pos, node, rulename, recdepth) +	if rulename == nil then +		for _,rule in ipairs(mesecon:effector_get_rules(node)) do +			mesecon:deactivate(pos, node, rule, recdepth + 1)  		end +		return  	end +	mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / recdepth)  end -minetest.register_globalstep(execute_actions) -function add_action(pos, action, rname) -	for _,i in ipairs(mesecon.to_update) do -		if i.pos.x == pos.x and i.pos.y == pos.y and i.pos.z == pos.z and i.rname.x == rname.x and i.rname.y == rname.y and i.rname.z == rname.z then -			if (i.action == "on" and action == "on") or (i.action == "off" and action == "off") then -				--nothing -			elseif i.action == "coff" and action == "on" then i.action = "on" -			elseif i.action == "con" and action == "off" then i.action = "off" -			else -				if action == "on" or action == "con" then i.action = "con" end -				if action == "off" or action == "coff" then i.action = "coff" end -			end -			break +-- Change +mesecon.queue:add_function("change", function (pos, rulename, changetype) +	node = minetest.get_node(pos) +	effector = mesecon:get_effector(node.name) + +	if effector and effector.action_change then +		effector.action_change(pos, node, rulename, changetype) +	end +end) + +function mesecon:changesignal(pos, node, rulename, newstate, recdepth) +	if rulename == nil then +		for _,rule in ipairs(mesecon:effector_get_rules(node)) do +			mesecon:changesignal(pos, node, rule, newstate, recdepth + 1)  		end +		return  	end -	mesecon.to_update[#mesecon.to_update+1] = {pos = pos, action = action, rname = rname} + +	mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / recdepth)  end ---Rules +-- ######### +-- # Rules # "Database" for rulenames +-- #########  function mesecon:add_rules(name, rules)  	mesecon.rules[name] = rules @@ -410,8 +365,15 @@ function mesecon:is_power_off(pos, rulename)  	return false  end -function mesecon:turnon(pos, rulename) +function mesecon:turnon(pos, rulename, recdepth) +	recdepth = recdepth or 2  	local node = minetest.get_node(pos) + +	if(node.name == "ignore") then +		-- try turning on later again +		mesecon.queue:add_action( +			pos, "turnon", {rulename, recdepth + 1}, nil, true) +	end  	if mesecon:is_conductor_off(node, rulename) then  		local rules = mesecon:conductor_get_rules(node) @@ -419,7 +381,7 @@ function mesecon:turnon(pos, rulename)  		if not rulename then  			for _, rule in ipairs(mesecon:flattenrules(rules)) do  				if mesecon:connected_to_receptor(pos, rule) then -					mesecon:turnon(pos, rule) +					mesecon:turnon(pos, rule, recdepth + 1)  				end  			end  			return @@ -429,54 +391,75 @@ function mesecon:turnon(pos, rulename)  		for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do  			local np = mesecon:addPosRule(pos, rule) -			local rulenames = mesecon:rules_link_rule_all(pos, rule) +			if(minetest.get_node(np).name == "ignore") then +				-- try turning on later again +				mesecon.queue:add_action( +					np, "turnon", {rulename, recdepth + 1}, nil, true) +			else +				local rulenames = mesecon:rules_link_rule_all(pos, rule) -			for _, rulename in ipairs(rulenames) do -				mesecon:turnon(np, rulename) +				for _, rulename in ipairs(rulenames) do +					mesecon:turnon(np, rulename, recdepth + 1) +				end  			end  		end  	elseif mesecon:is_effector(node.name) then -		mesecon:changesignal(pos, node, rulename, mesecon.state.on) +		mesecon:changesignal(pos, node, rulename, mesecon.state.on, recdepth)  		if mesecon:is_effector_off(node.name) then -			mesecon:activate(pos, node, rulename) +			mesecon:activate(pos, node, rulename, recdepth)  		end  	end  end -function mesecon:turnoff(pos, rulename) +mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) +	if (MESECONS_GLOBALSTEP) then -- do not resume if we don't use globalstep - that would cause an endless loop +		mesecon:turnon(pos, rulename, recdepth) +	end +end) + +function mesecon:turnoff(pos, rulename, recdepth) +	recdepth = recdepth or 2  	local node = minetest.get_node(pos) +	if(node.name == "ignore") then +		-- try turning on later again +		mesecon.queue:add_action( +			pos, "turnoff", {rulename, recdepth + 1}, nil, true) +	end +  	if mesecon:is_conductor_on(node, rulename) then  		local rules = mesecon:conductor_get_rules(node) -		--[[ -		if not rulename then -			for _, rule in ipairs(mesecon:flattenrules(rules)) do -				if mesecon:is_powered(pos, rule) then -					mesecon:turnoff(pos, rule) -				end -			end -			return -		end -		--]]  		minetest.swap_node(pos, {name = mesecon:get_conductor_off(node, rulename), param2 = node.param2})  		for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do  			local np = mesecon:addPosRule(pos, rule) -			local rulenames = mesecon:rules_link_rule_all(pos, rule) +			if(minetest.get_node(np).name == "ignore") then +				-- try turning on later again +				mesecon.queue:add_action( +					np, "turnoff", {rulename, recdepth + 1}, nil, true) +			else +				local rulenames = mesecon:rules_link_rule_all(pos, rule) -			for _, rulename in ipairs(rulenames) do -				mesecon:turnoff(np, rulename) +				for _, rulename in ipairs(rulenames) do +					mesecon:turnoff(np, rulename, recdepth + 1) +				end  			end  		end  	elseif mesecon:is_effector(node.name) then -		mesecon:changesignal(pos, node, rulename, mesecon.state.off) +		mesecon:changesignal(pos, node, rulename, mesecon.state.off, recdepth)  		if mesecon:is_effector_on(node.name)  		and not mesecon:is_powered(pos) then -			mesecon:deactivate(pos, node, rulename) +			mesecon:deactivate(pos, node, rulename, recdepth + 1)  		end  	end  end +mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) +	if (MESECONS_GLOBALSTEP) then -- do not resume if we don't use globalstep - that would cause an endless loop +		mesecon:turnoff(pos, rulename, recdepth) +	end +end) +  function mesecon:connected_to_receptor(pos, rulename)  	local node = minetest.get_node(pos) diff --git a/mesecons/legacy.lua b/mesecons/legacy.lua index a68bab4..c4334cf 100644 --- a/mesecons/legacy.lua +++ b/mesecons/legacy.lua @@ -2,4 +2,31 @@ minetest.swap_node = minetest.swap_node or function(pos, node)  	local data = minetest.get_meta(pos):to_table()
  	minetest.add_node(pos, node)
  	minetest.get_meta(pos):from_table(data)
 -end
\ No newline at end of file +end
 +
 +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"}
 +
 +function legacy_update_ports(pos)
 +	local meta = minetest.get_meta(pos)
 +	L = {
 +		a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a),
 +			mesecon:invertRule(rules.a)) and
 +			mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos),
 +		b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b),
 +			mesecon:invertRule(rules.b)) and
 +			mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos),
 +		c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c),
 +			mesecon:invertRule(rules.c)) and
 +			mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos),
 +		d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d),
 +			mesecon:invertRule(rules.d)) and
 +			mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos),
 +	}
 +	local n = (L.a and 1 or 0) + (L.b and 2 or 0) + (L.c and 4 or 0) + (L.d and 8 or 0) + 1
 +	meta:set_int("real_portstates", n)
 +	return L
 +end
 diff --git a/mesecons/services.lua b/mesecons/services.lua index 9d192ae..de0c8b6 100644 --- a/mesecons/services.lua +++ b/mesecons/services.lua @@ -6,19 +6,19 @@ mesecon.on_placenode = function (pos, node)  			mesecon:turnon (pos)  			--mesecon:receptor_on (pos, mesecon:conductor_get_rules(node))  		else -			mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "on") -			mesecon:activate(pos, node) +			mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "on", 1) +			mesecon:activate(pos, node, nil, 1)  		end  	elseif mesecon:is_conductor_on(node) then  		minetest.swap_node(pos, {name = mesecon:get_conductor_off(node)})  	elseif mesecon:is_effector_on (node.name) then -		mesecon:deactivate(pos, node) +		mesecon:deactivate(pos, node, nil, 1)  	end  end  mesecon.on_dignode = function (pos, node)  	if mesecon:is_conductor_on(node) then -		mesecon:receptor_off_i(pos, mesecon:conductor_get_rules(node)) +		mesecon:receptor_off(pos, mesecon:conductor_get_rules(node))  	elseif mesecon:is_receptor_on(node.name) then  		mesecon:receptor_off(pos, mesecon:receptor_get_rules(node))  	end diff --git a/mesecons/settings.lua b/mesecons/settings.lua index e35bb1e..593a79b 100644 --- a/mesecons/settings.lua +++ b/mesecons/settings.lua @@ -7,3 +7,5 @@ PISTON_MAXIMUM_PUSH = 15  MOVESTONE_MAXIMUM_PUSH = 100
  MESECONS_GLOBALSTEP = true	-- true = receptors/effectors won't be updated
  				-- until next globalstep, decreases server load
 +MESECONS_RESUMETIME = 4		-- time to wait when starting the server before
 +				-- processing the ActionQueue, don't set this too low
 diff --git a/mesecons/util.lua b/mesecons/util.lua index b3ca7a0..91d435a 100644 --- a/mesecons/util.lua +++ b/mesecons/util.lua @@ -169,6 +169,7 @@ function mesecon:cmpSpecial(r1, r2)  end  function mesecon:tablecopy(table) -- deep table copy +	if type(table) ~= "table" then return table end -- no need to copy  	local newtable = {}  	for idx, item in pairs(table) do @@ -181,3 +182,14 @@ function mesecon:tablecopy(table) -- deep table copy  	return newtable  end + +function mesecon:cmpAny(t1, t2) +	if type(t1) ~= type(t2) then return false end +	if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end + +	for i, e in pairs(t1) do +		if not mesecon:cmpAny(e, t2[i]) then return false end +	end + +	return true +end diff --git a/mesecons_delayer/init.lua b/mesecons_delayer/init.lua index a03737c..4ec0ebc 100644 --- a/mesecons_delayer/init.lua +++ b/mesecons_delayer/init.lua @@ -17,28 +17,18 @@ end  -- Functions that are called after the delay time -local delayer_turnon = function(params) -	local rules = delayer_get_output_rules(params.node) -	mesecon:receptor_on(params.pos, rules) -end - -local delayer_turnoff = function(params) -	local rules = delayer_get_output_rules(params.node) -	mesecon:receptor_off(params.pos, rules) -end -  local delayer_activate = function(pos, node)  	local def = minetest.registered_nodes[node.name]  	local time = def.delayer_time  	minetest.swap_node(pos, {name = def.delayer_onstate, param2=node.param2}) -	minetest.after(time, delayer_turnon , {pos = pos, node = node}) +	mesecon.queue:add_action(pos, "receptor_on", {rules=delayer_get_output_rules(node)}, time, nil)  end  local delayer_deactivate = function(pos, node)  	local def = minetest.registered_nodes[node.name]  	local time = def.delayer_time  	minetest.swap_node(pos, {name = def.delayer_offstate, param2=node.param2}) -	minetest.after(time, delayer_turnoff, {pos = pos, node = node}) +	mesecon.queue:add_action(pos, "receptor_off", {rules=delayer_get_output_rules(node)}, time, nil)  end  -- Register the 2 (states) x 4 (delay times) delayers diff --git a/mesecons_gates/init.lua b/mesecons_gates/init.lua index 1a9ee83..51ed4af 100644 --- a/mesecons_gates/init.lua +++ b/mesecons_gates/init.lua @@ -23,7 +23,8 @@ function gate_get_input_rules_twoinputs(node)  	return gate_rotate_rules(node)  end -function update_gate(pos) +function update_gate(pos, node, rulename, newstate) +	yc_update_real_portstates(pos, node, rulename, newstate)  	gate = get_gate(pos)  	L = rotate_ports(  		yc_get_real_portstates(pos), diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua index acbf023..c9a765e 100644 --- a/mesecons_luacontroller/init.lua +++ b/mesecons_luacontroller/init.lua @@ -31,18 +31,46 @@ rules.d = {x =  0, y = 0, z = -1, name="D"}  ------------------  -- These helpers are required to set the portstates of the luacontroller +function lc_update_real_portstates(pos, rulename, newstate) +	local meta = minetest.get_meta(pos) +	if rulename == nil then +		meta:set_int("real_portstates", 1) +		return +	end +	local n = meta:get_int("real_portstates") - 1 +	if n < 0 then +		legacy_update_ports(pos) +		n = meta:get_int("real_portstates") - 1 +	end +	local L = {} +	for i = 1, 4 do +		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] +			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 +	end +	meta:set_int("real_portstates", 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) -	ports = { -		a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a), mesecon:invertRule(rules.a)) -			and mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos), -		b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b), mesecon:invertRule(rules.b)) -			and mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos), -		c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c), mesecon:invertRule(rules.c)) -			and mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos), -		d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d), mesecon:invertRule(rules.d)) -			and mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos), -	} -	return ports +	local meta = minetest.get_meta(pos) +	local L = {} +	local n = meta:get_int("real_portstates") - 1 +	if n < 0 then +		return legacy_update_ports(pos) +	end +	for _, index in ipairs({"a", "b", "c", "d"}) do +		L[index] = ((n%2) == 1) +		n = math.floor(n/2) +	end +	return L  end  local merge_portstates = function (ports, vports) @@ -457,6 +485,7 @@ local mesecons = {  	{  		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,  	}, diff --git a/mesecons_microcontroller/init.lua b/mesecons_microcontroller/init.lua index 55faa5c..b6134da 100644 --- a/mesecons_microcontroller/init.lua +++ b/mesecons_microcontroller/init.lua @@ -39,7 +39,8 @@ mesecon:add_rules(nodename, rules)  local mesecons = {effector =  {  	rules = input_rules, -	action_change = function (pos, node, rulename) +	action_change = function (pos, node, rulename, newstate) +		yc_update_real_portstates(pos, node, rulename, newstate)  		update_yc(pos)  	end  }} @@ -633,25 +634,45 @@ function yc_set_portstate(port, state, L)  	return L  end -function yc_get_real_portstates(pos) -- port powered or not (by itself or from outside)? -	rulesA = mesecon:get_rules("mesecons_microcontroller:microcontroller0001") -	rulesB = mesecon:get_rules("mesecons_microcontroller:microcontroller0010") -	rulesC = mesecon:get_rules("mesecons_microcontroller:microcontroller0100") -	rulesD = mesecon:get_rules("mesecons_microcontroller:microcontroller1000") -	L = { -		a = mesecon:is_power_on(mesecon:addPosRule(pos, rulesA[1]), -			mesecon:invertRule(rulesA[1])) and -			mesecon:rules_link(mesecon:addPosRule(pos, rulesA[1]), pos), -		b = mesecon:is_power_on(mesecon:addPosRule(pos, rulesB[1]), -			mesecon:invertRule(rulesB[1])) and -			mesecon:rules_link(mesecon:addPosRule(pos, rulesB[1]), pos), -		c = mesecon:is_power_on(mesecon:addPosRule(pos, rulesC[1]), -			mesecon:invertRule(rulesC[1])) and -			mesecon:rules_link(mesecon:addPosRule(pos, rulesC[1]), pos), -		d = mesecon:is_power_on(mesecon:addPosRule(pos, rulesD[1]), -			mesecon:invertRule(rulesD[1])) and -			mesecon:rules_link(mesecon:addPosRule(pos, rulesD[1]), pos), -	} +function yc_update_real_portstates(pos, node, rulename, newstate) +	local meta = minetest.get_meta(pos) +	if rulename == nil then +		meta:set_int("real_portstates", 1) +		return +	end +	local n = meta:get_int("real_portstates") - 1 +	if n < 0 then +		legacy_update_ports(pos) +		n = meta:get_int("real_portstates") - 1 +	end +	local L = {} +	for i = 1, 4 do +		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] +			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 +	end +	meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4]) +end + +function yc_get_real_portstates(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 +	if n < 0 then +		return legacy_update_ports(pos) +	end +	for _, index in ipairs({"a", "b", "c", "d"}) do +		L[index] = ((n%2) == 1) +		n = math.floor(n/2) +	end  	return L  end | 
