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 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,14 +517,11 @@ 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
or mesecon.cmpSpecial(inputrule, outputrule) then
return true, inputrule return true, inputrule
end end
end end
end end
end end
end
return false return false
end end
@ -537,12 +537,9 @@ 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
or mesecon.cmpSpecial(inputrule, rule) then
table.insert(rules, inputrule) table.insert(rules, inputrule)
end end
end end
end
return rules return rules
end end
@ -558,12 +555,9 @@ 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
or mesecon.cmpSpecial(outputrule, rule) then
table.insert(rules, mesecon.invertRule(outputrule)) table.insert(rules, mesecon.invertRule(outputrule))
end end
end end
end
return rules return rules
end end
@ -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,
sx = -rule.sz, name = rule.name})
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,
sx = rule.sz, name = rule.name})
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,
sx = -rule.sy, name = rule.name})
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,
sx = rule.sy, name = rule.name})
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

View File

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

View File

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

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 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(
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))
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 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.remove_node(pos)
minetest.after(0.2, function (pos) mesecon.receptor_off(pos, gate_get_output_rules(node))
mesecon.receptor_off(pos, mesecon.rules.flat) minetest.add_item(pos, gate.drop)
end , pos) -- wait for pending parsings elseif state then
minetest.add_item(pos, "mesecons_gates:"..gate.."_off") minetest.swap_node(pos, {name = gate.onstate, param2=node.param2})
end mesecon.receptor_on(pos, gate_get_output_rules(node))
else
function rotate_ports(L, param2) minetest.swap_node(pos, {name = gate.offstate, param2=node.param2})
for rotations=0, param2-1 do mesecon.receptor_off(pos, gate_get_output_rules(node))
port = L.a
L.a = L.b
L.b = L.c
L.c = L.d
L.d = port
end end
return L
end end
gates = { local function update_gate(pos, node, link, newstate)
{name = "diode", inputnumber = 1}, local gate = minetest.registered_nodes[node.name]
{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 local val1 = meta:get_int("input1") == 1
if on == 1 then local val2 = meta:get_int("input2") == 1
onoff = "on" set_gate(pos, node, gate.assess(val1, val2))
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 end
end
tiles = "jeija_microcontroller_bottom.png^".. function register_gate(name, inputnumber, assess, recipe)
"jeija_gate_"..onoff..".png^".. local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or
"jeija_gate_"..gate.name..".png" gate_get_input_rules_oneinput
local description = "Mesecons Logic Gate: "..name
node_box = { local basename = "mesecons_gates:"..name
type = "fixed", mesecon.register_node(basename, {
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, description = description,
inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
drawtype = "nodebox", drawtype = "nodebox",
tiles = {tiles}, drop = basename.."_off",
inventory_image = tiles, selection_box = nodebox,
selection_box = node_box, node_box = nodebox,
node_box = node_box,
walkable = true, 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(), sounds = default.node_sound_stone_defaults(),
mesecons_gate = gate.name, assess = assess,
mesecons = onstate = basename.."_on",
{ offstate = basename.."_off",
receptor = inputnumber = inputnumber
{ },{
state = mesecon_state, 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 rules = gate_get_output_rules
}, }, effector = {
effector = rules = get_inputrules,
{
rules = get_rules,
action_change = update_gate 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
}}
}) })
end
minetest.register_craft({output = basename.."_off", recipe = recipe})
end end
minetest.register_craft({ register_gate("diode", 1, function (input) return input end,
output = 'mesecons_gates:diode_off', {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}})
recipe = {
{'', '', ''},
{'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons_torch:mesecon_torch_on'},
{'', '', ''},
},
})
minetest.register_craft({ register_gate("not", 1, function (input) return not input end,
output = 'mesecons_gates:not_off', {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}})
recipe = {
{'', '', ''},
{'mesecons:mesecon', 'mesecons_torch:mesecon_torch_on', 'mesecons:mesecon'},
{'', '', ''},
},
})
minetest.register_craft({ register_gate("and", 2, function (val1, val2) return val1 and val2 end,
output = 'mesecons_gates:and_off', {{"mesecons:mesecon", "", ""},
recipe = { {"", "mesecons_materials:silicon", "mesecons:mesecon"},
{'mesecons:mesecon', '', ''}, {"mesecons:mesecon", "", ""}})
{'', 'mesecons_materials:silicon', 'mesecons:mesecon'},
{'mesecons:mesecon', '', ''},
},
})
minetest.register_craft({ register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end,
output = 'mesecons_gates:nand_off', {{"mesecons:mesecon", "", ""},
recipe = { {"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"},
{'mesecons:mesecon', '', ''}, {"mesecons:mesecon", "", ""}})
{'', 'mesecons_materials:silicon', 'mesecons_torch:mesecon_torch_on'},
{'mesecons:mesecon', '', ''},
},
})
minetest.register_craft({ register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end,
output = 'mesecons_gates:xor_off', {{"mesecons:mesecon", "", ""},
recipe = { {"", "mesecons_materials:silicon", "mesecons_materials:silicon"},
{'mesecons:mesecon', '', ''}, {"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 -- 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

View File

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