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

View File

@ -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

View File

@ -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

View File

@ -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 = {}

View File

@ -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", "", ""}})

View File

@ -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

View File

@ -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