From c326dc221a4ee6a1b55b681eb1456d7da62de7fb Mon Sep 17 00:00:00 2001 From: Jeija Date: Sat, 29 Nov 2014 15:08:37 +0100 Subject: [PATCH] Rewrite Logic Gates: Makes it super-easy to add new gates and cleans up code Fix bugs in the Luacontroller (when placing, false input pin values were given) and fix variables leaking into the global environment in pistons. --- mesecons/internal.lua | 96 ++++--------- mesecons/services.lua | 25 +++- mesecons/util.lua | 10 +- mesecons_gates/init.lua | 294 +++++++++++++------------------------- mesecons_mvps/init.lua | 6 +- mesecons_pistons/init.lua | 10 +- 6 files changed, 156 insertions(+), 285 deletions(-) diff --git a/mesecons/internal.lua b/mesecons/internal.lua index cee90d2..d62df1f 100644 --- a/mesecons/internal.lua +++ b/mesecons/internal.lua @@ -240,7 +240,10 @@ function mesecon.changesignal(pos, node, rulename, newstate, depth) return end - mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / depth) + -- Include "change" in overwritecheck so that it cannot be overwritten + -- by "active" / "deactivate" that will be called upon the node at the same time. + local overwritecheck = {"change", rulename} + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, overwritecheck, 1 / depth) end -- Conductors @@ -514,10 +517,7 @@ function mesecon.rules_link(output, input, dug_outputrules) --output/input are p for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do -- Check if input accepts from output if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then - if inputrule.sx == nil or outputrule.sx == nil - or mesecon.cmpSpecial(inputrule, outputrule) then - return true, inputrule - end + return true, inputrule end end end @@ -537,10 +537,7 @@ function mesecon.rules_link_rule_all(output, rule) for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do -- Check if input accepts from output if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then - if inputrule.sx == nil or rule.sx == nil - or mesecon.cmpSpecial(inputrule, rule) then - table.insert(rules, inputrule) - end + table.insert(rules, inputrule) end end return rules @@ -558,10 +555,7 @@ function mesecon.rules_link_rule_all_inverted(input, rule) for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then - if outputrule.sx == nil or rule.sx == nil - or mesecon.cmpSpecial(outputrule, rule) then - table.insert(rules, mesecon.invertRule(outputrule)) - end + table.insert(rules, mesecon.invertRule(outputrule)) end end return rules @@ -612,20 +606,11 @@ end function mesecon.rotate_rules_right(rules) local nr = {} for i, rule in ipairs(rules) do - if rule.sx then - table.insert(nr, { - x = -rule.z, - y = rule.y, - z = rule.x, - sx = -rule.sz, - sy = rule.sy, - sz = rule.sx}) - else - table.insert(nr, { - x = -rule.z, - y = rule.y, - z = rule.x}) - end + table.insert(nr, { + x = -rule.z, + y = rule.y, + z = rule.x, + name = rule.name}) end return nr end @@ -633,20 +618,11 @@ end function mesecon.rotate_rules_left(rules) local nr = {} for i, rule in ipairs(rules) do - if rule.sx then - table.insert(nr, { - x = rule.z, - y = rule.y, - z = -rule.x, - sx = rule.sz, - sy = rule.sy, - sz = -rule.sx}) - else - table.insert(nr, { - x = rule.z, - y = rule.y, - z = -rule.x}) - end + table.insert(nr, { + x = rule.z, + y = rule.y, + z = -rule.x, + name = rule.name}) end return nr end @@ -654,20 +630,11 @@ end function mesecon.rotate_rules_down(rules) local nr = {} for i, rule in ipairs(rules) do - if rule.sx then - table.insert(nr, { - x = -rule.y, - y = rule.x, - z = rule.z, - sx = -rule.sy, - sy = rule.sx, - sz = rule.sz}) - else - table.insert(nr, { - x = -rule.y, - y = rule.x, - z = rule.z}) - end + table.insert(nr, { + x = -rule.y, + y = rule.x, + z = rule.z, + name = rule.name}) end return nr end @@ -675,20 +642,11 @@ end function mesecon.rotate_rules_up(rules) local nr = {} for i, rule in ipairs(rules) do - if rule.sx then - table.insert(nr, { - x = rule.y, - y = -rule.x, - z = rule.z, - sx = rule.sy, - sy = -rule.sx, - sz = rule.sz}) - else - table.insert(nr, { - x = rule.y, - y = -rule.x, - z = rule.z}) - end + table.insert(nr, { + x = rule.y, + y = -rule.x, + z = rule.z, + name = rule.name}) end return nr end diff --git a/mesecons/services.lua b/mesecons/services.lua index 36d9b80..215fb31 100644 --- a/mesecons/services.lua +++ b/mesecons/services.lua @@ -27,12 +27,27 @@ mesecon.on_placenode = function (pos, node) -- Effectors: Send changesignal and activate or deactivate if mesecon.is_effector(node.name) then - if mesecon.is_powered(pos) then - mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "on", 1) - mesecon.activate(pos, node, nil, 1) + local powered_rules = {} + local unpowered_rules = {} + + -- for each input rule, check if powered + for _, r in ipairs(mesecon.effector_get_rules(node)) do + local powered = mesecon.is_powered(pos, r) + if powered then table.insert(powered_rules, r) + else table.insert(unpowered_rules, r) end + + local state = powered and mesecon.state.on or mesecon.state.off + mesecon.changesignal(pos, node, r, state, 1) + end + + if (#powered_rules > 0) then + for _, r in ipairs(powered_rules) do + mesecon.activate(pos, node, r, 1) + end else - mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "off", 1) - mesecon.deactivate(pos, node, nil, 1) + for _, r in ipairs(unpowered_rules) do + mesecon.deactivate(pos, node, r, 1) + end end end end diff --git a/mesecons/util.lua b/mesecons/util.lua index 11cc95a..a64e00c 100644 --- a/mesecons/util.lua +++ b/mesecons/util.lua @@ -62,7 +62,7 @@ function mesecon.rule2bit(findrule, allrules) end for m,metarule in ipairs( allrules) do for _, rule in ipairs(metarule ) do - if mesecon.cmpPos(findrule, rule) and mesecon.cmpSpecial(findrule, rule) then + if mesecon.cmpPos(findrule, rule) then return m end end @@ -82,7 +82,7 @@ function mesecon.rule2metaindex(findrule, allrules) for m, metarule in ipairs( allrules) do for _, rule in ipairs(metarule ) do - if mesecon.cmpPos(findrule, rule) and mesecon.cmpSpecial(findrule, rule) then + if mesecon.cmpPos(findrule, rule) then return m end end @@ -153,7 +153,7 @@ function mesecon.set_bit(binary,bit,value) end function mesecon.invertRule(r) - return {x = -r.x, y = -r.y, z = -r.z, sx = r.sx, sy = r.sy, sz = r.sz} + return {x = -r.x, y = -r.y, z = -r.z} end function mesecon.addPosRule(p, r) @@ -164,10 +164,6 @@ function mesecon.cmpPos(p1, p2) return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z) end -function mesecon.cmpSpecial(r1, r2) - return (r1.sx == r2.sx and r1.sy == r2.sy and r1.sz == r2.sz) -end - function mesecon.tablecopy(table) -- deep table copy if type(table) ~= "table" then return table end -- no need to copy local newtable = {} diff --git a/mesecons_gates/init.lua b/mesecons_gates/init.lua index 345c32c..2b6771a 100644 --- a/mesecons_gates/init.lua +++ b/mesecons_gates/init.lua @@ -1,222 +1,124 @@ -function gate_rotate_rules(node) +local nodebox = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }}, +} + +local function gate_rotate_rules(node, rules) for rotations = 0, node.param2 - 1 do rules = mesecon.rotate_rules_left(rules) end return rules end -function gate_get_output_rules(node) - rules = {{x=1, y=0, z=0}} - return gate_rotate_rules(node) +local function gate_get_output_rules(node) + return gate_rotate_rules(node, {{x=1, y=0, z=0}}) end -function gate_get_input_rules_oneinput(node) - rules = {{x=-1, y=0, z=0}, {x=1, y=0, z=0}} - return gate_rotate_rules(node) +local function gate_get_input_rules_oneinput(node) + return gate_rotate_rules(node, {{x=-1, y=0, z=0}}) end -function gate_get_input_rules_twoinputs(node) - rules = { - {x=0, y=0, z=1}, - {x=0, y=0, z=-1}, - {x=1, y=0, z=0}} - return gate_rotate_rules(node) +local function gate_get_input_rules_twoinputs(node) + return gate_rotate_rules(node, {{x=0, y=0, z=1, name="input1"}, + {x=0, y=0, z=-1, name="input2"}}) end -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), - minetest.get_node(pos).param2 - ) - if gate == "diode" then - set_gate(pos, L.a) - elseif gate == "not" then - set_gate(pos, not L.a) - elseif gate == "nand" then - set_gate(pos, not(L.b and L.d)) - elseif gate == "and" then - set_gate(pos, L.b and L.d) - elseif gate == "xor" then - set_gate(pos, (L.b and not L.d) or (not L.b and L.d)) +local function set_gate(pos, node, state) + local gate = minetest.registered_nodes[node.name] + + if mesecon.do_overheat(pos) then + minetest.remove_node(pos) + mesecon.receptor_off(pos, gate_get_output_rules(node)) + minetest.add_item(pos, gate.drop) + elseif state then + minetest.swap_node(pos, {name = gate.onstate, param2=node.param2}) + mesecon.receptor_on(pos, gate_get_output_rules(node)) + else + minetest.swap_node(pos, {name = gate.offstate, param2=node.param2}) + mesecon.receptor_off(pos, gate_get_output_rules(node)) end end -function set_gate(pos, on) - gate = get_gate(pos) - local meta = minetest.get_meta(pos) - if on ~= gate_state(pos) then - if mesecon.do_overheat(pos) then - pop_gate(pos) - else - local node = minetest.get_node(pos) - if on then - minetest.swap_node(pos, {name = "mesecons_gates:"..gate.."_on", param2=node.param2}) - mesecon.receptor_on(pos, - gate_get_output_rules(node)) - else - minetest.swap_node(pos, {name = "mesecons_gates:"..gate.."_off", param2=node.param2}) - mesecon.receptor_off(pos, - gate_get_output_rules(node)) - end - end - end -end +local function update_gate(pos, node, link, newstate) + local gate = minetest.registered_nodes[node.name] -function get_gate(pos) - return minetest.registered_nodes[minetest.get_node(pos).name].mesecons_gate -end - -function gate_state(pos) - name = minetest.get_node(pos).name - return string.find(name, "_on") ~= nil -end - -function pop_gate(pos) - gate = get_gate(pos) - minetest.remove_node(pos) - minetest.after(0.2, function (pos) - mesecon.receptor_off(pos, mesecon.rules.flat) - end , pos) -- wait for pending parsings - minetest.add_item(pos, "mesecons_gates:"..gate.."_off") -end - -function rotate_ports(L, param2) - for rotations=0, param2-1 do - port = L.a - L.a = L.b - L.b = L.c - L.c = L.d - L.d = port - end - return L -end - -gates = { -{name = "diode", inputnumber = 1}, -{name = "not" , inputnumber = 1}, -{name = "nand" , inputnumber = 2}, -{name = "and" , inputnumber = 2}, -{name = "xor" , inputnumber = 2}} - -local onoff, drop, nodename, description, groups -for _, gate in ipairs(gates) do if gate.inputnumber == 1 then - get_rules = gate_get_input_rules_oneinput + set_gate(pos, node, gate.assess(newstate == "on")) elseif gate.inputnumber == 2 then - get_rules = gate_get_input_rules_twoinputs - end - for on = 0, 1 do - nodename = "mesecons_gates:"..gate.name - if on == 1 then - onoff = "on" - drop = nodename.."_off" - nodename = nodename.."_"..onoff - description = "You hacker you!" - groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1} - else - onoff = "off" - drop = nil - nodename = nodename.."_"..onoff - description = gate.name.." Gate" - groups = {dig_immediate=2, overheat = 1} - end + local meta = minetest.get_meta(pos) + meta:set_int(link.name, newstate == "on" and 1 or 0) - tiles = "jeija_microcontroller_bottom.png^".. - "jeija_gate_"..onoff..".png^".. - "jeija_gate_"..gate.name..".png" - - node_box = { - type = "fixed", - fixed = { - {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, - }, - } - - local mesecon_state - if on == 1 then - mesecon_state = mesecon.state.on - else - mesecon_state = mesecon.state.off - end - - minetest.register_node(nodename, { - description = description, - paramtype = "light", - paramtype2 = "facedir", - drawtype = "nodebox", - tiles = {tiles}, - inventory_image = tiles, - selection_box = node_box, - node_box = node_box, - walkable = true, - on_construct = function(pos) - local meta = minetest.get_meta(pos) - update_gate(pos) - end, - groups = groups, - drop = drop, - sounds = default.node_sound_stone_defaults(), - mesecons_gate = gate.name, - mesecons = - { - receptor = - { - state = mesecon_state, - rules = gate_get_output_rules - }, - effector = - { - rules = get_rules, - action_change = update_gate - } - } - }) + local val1 = meta:get_int("input1") == 1 + local val2 = meta:get_int("input2") == 1 + set_gate(pos, node, gate.assess(val1, val2)) end end -minetest.register_craft({ - output = 'mesecons_gates:diode_off', - recipe = { - {'', '', ''}, - {'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons_torch:mesecon_torch_on'}, - {'', '', ''}, - }, -}) +function register_gate(name, inputnumber, assess, recipe) + local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or + gate_get_input_rules_oneinput + local description = "Mesecons Logic Gate: "..name -minetest.register_craft({ - output = 'mesecons_gates:not_off', - recipe = { - {'', '', ''}, - {'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons:mesecon'}, - {'', '', ''}, - }, -}) + local basename = "mesecons_gates:"..name + mesecon.register_node(basename, { + description = description, + inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png", + paramtype = "light", + paramtype2 = "facedir", + drawtype = "nodebox", + drop = basename.."_off", + selection_box = nodebox, + node_box = nodebox, + walkable = true, + sounds = default.node_sound_stone_defaults(), + assess = assess, + onstate = basename.."_on", + offstate = basename.."_off", + inputnumber = inputnumber + },{ + tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^".. + "jeija_gate_"..name..".png"}, + groups = {dig_immediate = 2}, + mesecons = { receptor = { + state = "off", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + },{ + tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^".. + "jeija_gate_"..name..".png"}, + groups = {dig_immediate = 2, not_in_creative_inventory = 1}, + mesecons = { receptor = { + state = "on", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + }) -minetest.register_craft({ - output = 'mesecons_gates:and_off', - recipe = { - {'mesecons:mesecon', '', ''}, - {'', 'mesecons_materials:silicon', 'mesecons:mesecon'}, - {'mesecons:mesecon', '', ''}, - }, -}) + minetest.register_craft({output = basename.."_off", recipe = recipe}) +end -minetest.register_craft({ - output = 'mesecons_gates:nand_off', - recipe = { - {'mesecons:mesecon', '', ''}, - {'', 'mesecons_materials:silicon', 'mesecons_torch:mesecon_torch_on'}, - {'mesecons:mesecon', '', ''}, - }, -}) +register_gate("diode", 1, function (input) return input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}}) -minetest.register_craft({ - output = 'mesecons_gates:xor_off', - recipe = { - {'mesecons:mesecon', '', ''}, - {'', 'mesecons_materials:silicon', 'mesecons_materials:silicon'}, - {'mesecons:mesecon', '', ''}, - }, -}) +register_gate("not", 1, function (input) return not input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}}) + +register_gate("and", 2, function (val1, val2) return val1 and val2 end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons:mesecon"}, + {"mesecons:mesecon", "", ""}}) + +register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"}, + {"mesecons:mesecon", "", ""}}) + +register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_materials:silicon"}, + {"mesecons:mesecon", "", ""}}) diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index 163ad28..bcbda17 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -94,7 +94,7 @@ function mesecon.mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio -- add nodes for _, n in ipairs(nodes) do - np = mesecon.addPosRule(n.pos, dir) + local np = mesecon.addPosRule(n.pos, dir) minetest.add_node(np, n.node) minetest.get_meta(np):from_table(n.meta) end @@ -123,8 +123,8 @@ mesecon.register_on_mvps_move(function(moved_nodes) end) function mesecon.mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) - np = mesecon.addPosRule(pos, dir) - nn = minetest.get_node(np) + local np = mesecon.addPosRule(pos, dir) + local nn = minetest.get_node(np) if ((not minetest.registered_nodes[nn.name]) --unregistered node or minetest.registered_nodes[nn.name].liquidtype == "none") --non-liquid node diff --git a/mesecons_pistons/init.lua b/mesecons_pistons/init.lua index b247039..71e63e7 100644 --- a/mesecons_pistons/init.lua +++ b/mesecons_pistons/init.lua @@ -55,8 +55,8 @@ piston_get_direction = function(dir, node) end local piston_remove_pusher = function(pos, node) - pistonspec = minetest.registered_nodes[node.name].mesecons_piston - dir = piston_get_direction(pistonspec.dir, node) + local pistonspec = minetest.registered_nodes[node.name].mesecons_piston + local dir = piston_get_direction(pistonspec.dir, node) local pusherpos = mesecon.addPosRule(pos, dir) local pushername = minetest.get_node(pusherpos).name @@ -100,9 +100,9 @@ local piston_off = function(pos, node) piston_remove_pusher(pos, node) if pistonspec.sticky then - dir = piston_get_direction(pistonspec.dir, node) - pullpos = mesecon.addPosRule(pos, dir) - stack = mesecon.mvps_pull_single(pullpos, dir) + local dir = piston_get_direction(pistonspec.dir, node) + local pullpos = mesecon.addPosRule(pos, dir) + local stack = mesecon.mvps_pull_single(pullpos, dir) mesecon.mvps_process_stack(pos, dir, stack) end end