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.
This commit is contained in:
Jeija 2014-11-29 15:08:37 +01:00
parent d2373eb605
commit c326dc221a
6 changed files with 156 additions and 285 deletions

@ -240,7 +240,10 @@ function mesecon.changesignal(pos, node, rulename, newstate, depth)
return return
end 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 end
-- Conductors -- 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 for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
-- Check if input accepts from output -- Check if input accepts from output
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
if inputrule.sx == nil or outputrule.sx == nil return true, inputrule
or mesecon.cmpSpecial(inputrule, outputrule) then
return true, inputrule
end
end end
end end
end end
@ -537,10 +537,7 @@ function mesecon.rules_link_rule_all(output, rule)
for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
-- Check if input accepts from output -- Check if input accepts from output
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
if inputrule.sx == nil or rule.sx == nil table.insert(rules, inputrule)
or mesecon.cmpSpecial(inputrule, rule) then
table.insert(rules, inputrule)
end
end end
end end
return rules return rules
@ -558,10 +555,7 @@ function mesecon.rules_link_rule_all_inverted(input, rule)
for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
if outputrule.sx == nil or rule.sx == nil table.insert(rules, mesecon.invertRule(outputrule))
or mesecon.cmpSpecial(outputrule, rule) then
table.insert(rules, mesecon.invertRule(outputrule))
end
end end
end end
return rules return rules
@ -612,20 +606,11 @@ end
function mesecon.rotate_rules_right(rules) function mesecon.rotate_rules_right(rules)
local nr = {} local nr = {}
for i, rule in ipairs(rules) do for i, rule in ipairs(rules) do
if rule.sx then table.insert(nr, {
table.insert(nr, { x = -rule.z,
x = -rule.z, y = rule.y,
y = rule.y, z = rule.x,
z = rule.x, name = rule.name})
sx = -rule.sz,
sy = rule.sy,
sz = rule.sx})
else
table.insert(nr, {
x = -rule.z,
y = rule.y,
z = rule.x})
end
end end
return nr return nr
end end
@ -633,20 +618,11 @@ end
function mesecon.rotate_rules_left(rules) function mesecon.rotate_rules_left(rules)
local nr = {} local nr = {}
for i, rule in ipairs(rules) do for i, rule in ipairs(rules) do
if rule.sx then table.insert(nr, {
table.insert(nr, { x = rule.z,
x = rule.z, y = rule.y,
y = rule.y, z = -rule.x,
z = -rule.x, name = rule.name})
sx = rule.sz,
sy = rule.sy,
sz = -rule.sx})
else
table.insert(nr, {
x = rule.z,
y = rule.y,
z = -rule.x})
end
end end
return nr return nr
end end
@ -654,20 +630,11 @@ end
function mesecon.rotate_rules_down(rules) function mesecon.rotate_rules_down(rules)
local nr = {} local nr = {}
for i, rule in ipairs(rules) do for i, rule in ipairs(rules) do
if rule.sx then table.insert(nr, {
table.insert(nr, { x = -rule.y,
x = -rule.y, y = rule.x,
y = rule.x, z = rule.z,
z = rule.z, name = rule.name})
sx = -rule.sy,
sy = rule.sx,
sz = rule.sz})
else
table.insert(nr, {
x = -rule.y,
y = rule.x,
z = rule.z})
end
end end
return nr return nr
end end
@ -675,20 +642,11 @@ end
function mesecon.rotate_rules_up(rules) function mesecon.rotate_rules_up(rules)
local nr = {} local nr = {}
for i, rule in ipairs(rules) do for i, rule in ipairs(rules) do
if rule.sx then table.insert(nr, {
table.insert(nr, { x = rule.y,
x = rule.y, y = -rule.x,
y = -rule.x, z = rule.z,
z = rule.z, name = rule.name})
sx = rule.sy,
sy = -rule.sx,
sz = rule.sz})
else
table.insert(nr, {
x = rule.y,
y = -rule.x,
z = rule.z})
end
end end
return nr return nr
end end

@ -27,12 +27,27 @@ mesecon.on_placenode = function (pos, node)
-- Effectors: Send changesignal and activate or deactivate -- Effectors: Send changesignal and activate or deactivate
if mesecon.is_effector(node.name) then if mesecon.is_effector(node.name) then
if mesecon.is_powered(pos) then local powered_rules = {}
mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "on", 1) local unpowered_rules = {}
mesecon.activate(pos, node, nil, 1)
-- 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 else
mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "off", 1) for _, r in ipairs(unpowered_rules) do
mesecon.deactivate(pos, node, nil, 1) mesecon.deactivate(pos, node, r, 1)
end
end end
end end
end end

@ -62,7 +62,7 @@ function mesecon.rule2bit(findrule, allrules)
end end
for m,metarule in ipairs( allrules) do for m,metarule in ipairs( allrules) do
for _, rule in ipairs(metarule ) 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 return m
end end
end end
@ -82,7 +82,7 @@ function mesecon.rule2metaindex(findrule, allrules)
for m, metarule in ipairs( allrules) do for m, metarule in ipairs( allrules) do
for _, rule in ipairs(metarule ) 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 return m
end end
end end
@ -153,7 +153,7 @@ function mesecon.set_bit(binary,bit,value)
end end
function mesecon.invertRule(r) 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 end
function mesecon.addPosRule(p, r) 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) return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
end 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 function mesecon.tablecopy(table) -- deep table copy
if type(table) ~= "table" then return table end -- no need to copy if type(table) ~= "table" then return table end -- no need to copy
local newtable = {} local newtable = {}

@ -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 for rotations = 0, node.param2 - 1 do
rules = mesecon.rotate_rules_left(rules) rules = mesecon.rotate_rules_left(rules)
end end
return rules return rules
end end
function gate_get_output_rules(node) local function gate_get_output_rules(node)
rules = {{x=1, y=0, z=0}} return gate_rotate_rules(node, {{x=1, y=0, z=0}})
return gate_rotate_rules(node)
end end
function gate_get_input_rules_oneinput(node) local 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, {{x=-1, y=0, z=0}})
return gate_rotate_rules(node)
end end
function gate_get_input_rules_twoinputs(node) local function gate_get_input_rules_twoinputs(node)
rules = { return gate_rotate_rules(node, {{x=0, y=0, z=1, name="input1"},
{x=0, y=0, z=1}, {x=0, y=0, z=-1, name="input2"}})
{x=0, y=0, z=-1},
{x=1, y=0, z=0}}
return gate_rotate_rules(node)
end end
function update_gate(pos, node, rulename, newstate) local function set_gate(pos, node, state)
yc_update_real_portstates(pos, node, rulename, newstate) local gate = minetest.registered_nodes[node.name]
gate = get_gate(pos)
L = rotate_ports( if mesecon.do_overheat(pos) then
yc_get_real_portstates(pos), minetest.remove_node(pos)
minetest.get_node(pos).param2 mesecon.receptor_off(pos, gate_get_output_rules(node))
) minetest.add_item(pos, gate.drop)
if gate == "diode" then elseif state then
set_gate(pos, L.a) minetest.swap_node(pos, {name = gate.onstate, param2=node.param2})
elseif gate == "not" then mesecon.receptor_on(pos, gate_get_output_rules(node))
set_gate(pos, not L.a) else
elseif gate == "nand" then minetest.swap_node(pos, {name = gate.offstate, param2=node.param2})
set_gate(pos, not(L.b and L.d)) mesecon.receptor_off(pos, gate_get_output_rules(node))
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))
end end
end end
function set_gate(pos, on) local function update_gate(pos, node, link, newstate)
gate = get_gate(pos) local gate = minetest.registered_nodes[node.name]
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
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 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 elseif gate.inputnumber == 2 then
get_rules = gate_get_input_rules_twoinputs local meta = minetest.get_meta(pos)
end meta:set_int(link.name, newstate == "on" and 1 or 0)
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
tiles = "jeija_microcontroller_bottom.png^".. local val1 = meta:get_int("input1") == 1
"jeija_gate_"..onoff..".png^".. local val2 = meta:get_int("input2") == 1
"jeija_gate_"..gate.name..".png" set_gate(pos, node, gate.assess(val1, val2))
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
}
}
})
end end
end end
minetest.register_craft({ function register_gate(name, inputnumber, assess, recipe)
output = 'mesecons_gates:diode_off', local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or
recipe = { gate_get_input_rules_oneinput
{'', '', ''}, local description = "Mesecons Logic Gate: "..name
{'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons_torch:mesecon_torch_on'},
{'', '', ''},
},
})
minetest.register_craft({ local basename = "mesecons_gates:"..name
output = 'mesecons_gates:not_off', mesecon.register_node(basename, {
recipe = { description = description,
{'', '', ''}, inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png",
{'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons:mesecon'}, 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({ minetest.register_craft({output = basename.."_off", recipe = recipe})
output = 'mesecons_gates:and_off', end
recipe = {
{'mesecons:mesecon', '', ''},
{'', 'mesecons_materials:silicon', 'mesecons:mesecon'},
{'mesecons:mesecon', '', ''},
},
})
minetest.register_craft({ register_gate("diode", 1, function (input) return input end,
output = 'mesecons_gates:nand_off', {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}})
recipe = {
{'mesecons:mesecon', '', ''},
{'', 'mesecons_materials:silicon', 'mesecons_torch:mesecon_torch_on'},
{'mesecons:mesecon', '', ''},
},
})
minetest.register_craft({ register_gate("not", 1, function (input) return not input end,
output = 'mesecons_gates:xor_off', {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}})
recipe = {
{'mesecons:mesecon', '', ''}, register_gate("and", 2, function (val1, val2) return val1 and val2 end,
{'', 'mesecons_materials:silicon', 'mesecons_materials:silicon'}, {{"mesecons:mesecon", "", ""},
{'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", "", ""}})

@ -94,7 +94,7 @@ function mesecon.mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio
-- add nodes -- add nodes
for _, n in ipairs(nodes) do 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.add_node(np, n.node)
minetest.get_meta(np):from_table(n.meta) minetest.get_meta(np):from_table(n.meta)
end end
@ -123,8 +123,8 @@ mesecon.register_on_mvps_move(function(moved_nodes)
end) end)
function mesecon.mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) 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) local np = mesecon.addPosRule(pos, dir)
nn = minetest.get_node(np) local nn = minetest.get_node(np)
if ((not minetest.registered_nodes[nn.name]) --unregistered node if ((not minetest.registered_nodes[nn.name]) --unregistered node
or minetest.registered_nodes[nn.name].liquidtype == "none") --non-liquid node or minetest.registered_nodes[nn.name].liquidtype == "none") --non-liquid node

@ -55,8 +55,8 @@ piston_get_direction = function(dir, node)
end end
local piston_remove_pusher = function(pos, node) local piston_remove_pusher = function(pos, node)
pistonspec = minetest.registered_nodes[node.name].mesecons_piston local pistonspec = minetest.registered_nodes[node.name].mesecons_piston
dir = piston_get_direction(pistonspec.dir, node) local dir = piston_get_direction(pistonspec.dir, node)
local pusherpos = mesecon.addPosRule(pos, dir) local pusherpos = mesecon.addPosRule(pos, dir)
local pushername = minetest.get_node(pusherpos).name local pushername = minetest.get_node(pusherpos).name
@ -100,9 +100,9 @@ local piston_off = function(pos, node)
piston_remove_pusher(pos, node) piston_remove_pusher(pos, node)
if pistonspec.sticky then if pistonspec.sticky then
dir = piston_get_direction(pistonspec.dir, node) local dir = piston_get_direction(pistonspec.dir, node)
pullpos = mesecon.addPosRule(pos, dir) local pullpos = mesecon.addPosRule(pos, dir)
stack = mesecon.mvps_pull_single(pullpos, dir) local stack = mesecon.mvps_pull_single(pullpos, dir)
mesecon.mvps_process_stack(pos, dir, stack) mesecon.mvps_process_stack(pos, dir, stack)
end end
end end