-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
18 changed files
with
657 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
mesecons |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FPGAs can be used to chain multiple logic gates together in a compact manner. | ||
They come with 4 I/O ports and 10 internal registers, | ||
which can then be connected with eachother to form logic circuits.<br /> | ||
Supported gate types: <b>AND</b>, <b>OR</b>, <b>NOT</b>, <b>XOR</b>, <b>NAND</b>, <b>XNOR</b>, <b>Buffer</b> (=)<br /> | ||
I/O ports: <b>A B C D</b>; Registers: numbered <b>0</b> to <b>9</b> |
Unable to render rich display
Invalid image source.
Unable to render rich display
Invalid image source.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
The FPGA programmer can be used to copy gate configurations from one FPGA to another.<br /> | ||
Shift+Right-Click an FPGA to read its configuration and "remember" it. | ||
Left-click (punch) FPGAs to write the saved configuration to them. |
Unable to render rich display
Invalid image source.
Unable to render rich display
Invalid image source.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,374 @@ | ||
local plg = {} | ||
plg.rules = {} | ||
|
||
local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua") | ||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg) | ||
|
||
|
||
plg.register_nodes = function(template) | ||
-- each loop is for one of the 4 IO ports | ||
for a = 0, 1 do | ||
for b = 0, 1 do | ||
for c = 0, 1 do | ||
for d = 0, 1 do | ||
local ndef = table.copy(template) | ||
local nodename = "mesecons_fpga:fpga" | ||
.. tostring(d) .. tostring(c) .. tostring(b) .. tostring(a) | ||
|
||
-- build top texture string | ||
local texture = "jeija_fpga_top.png" | ||
if a == 1 then texture = texture .. "^jeija_microcontroller_LED_A.png" end | ||
if b == 1 then texture = texture .. "^jeija_microcontroller_LED_B.png" end | ||
if c == 1 then texture = texture .. "^jeija_microcontroller_LED_C.png" end | ||
if d == 1 then texture = texture .. "^jeija_microcontroller_LED_D.png" end | ||
ndef.tiles[1] = texture | ||
ndef.inventory_image = texture | ||
|
||
if (a + b + c + d) > 0 then | ||
ndef.groups["not_in_creative_inventory"] = 1 | ||
end | ||
|
||
-- interaction with mesecons (input / output) | ||
local rules_out = {} | ||
if a == 1 then table.insert(rules_out, {x = -1, y = 0, z = 0}) end | ||
if b == 1 then table.insert(rules_out, {x = 0, y = 0, z = 1}) end | ||
if c == 1 then table.insert(rules_out, {x = 1, y = 0, z = 0}) end | ||
if d == 1 then table.insert(rules_out, {x = 0, y = 0, z = -1}) end | ||
plg.rules[nodename] = rules_out | ||
|
||
local rules_in = {} | ||
if a == 0 then table.insert(rules_in, {x = -1, y = 0, z = 0}) end | ||
if b == 0 then table.insert(rules_in, {x = 0, y = 0, z = 1}) end | ||
if c == 0 then table.insert(rules_in, {x = 1, y = 0, z = 0}) end | ||
if d == 0 then table.insert(rules_in, {x = 0, y = 0, z = -1}) end | ||
ndef.mesecons.effector.rules = rules_in | ||
|
||
if (a + b + c + d) > 0 then | ||
ndef.mesecons.receptor = { | ||
state = mesecon.state.on, | ||
rules = rules_out, | ||
} | ||
end | ||
|
||
minetest.register_node(nodename, ndef) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
plg.register_nodes({ | ||
description = "FPGA", | ||
drawtype = "nodebox", | ||
tiles = { | ||
"", -- replaced later | ||
"jeija_microcontroller_bottom.png", | ||
"jeija_fpga_sides.png", | ||
"jeija_fpga_sides.png", | ||
"jeija_fpga_sides.png", | ||
"jeija_fpga_sides.png" | ||
}, | ||
inventory_image = "", -- replaced later | ||
sunlight_propagates = true, | ||
paramtype = "light", | ||
walkable = true, | ||
groups = {dig_immediate = 2, mesecon = 3}, | ||
drop = "mesecons_fpga:fpga0000", | ||
selection_box = { | ||
type = "fixed", | ||
fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, | ||
}, | ||
node_box = { | ||
type = "fixed", | ||
fixed = { | ||
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab | ||
{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board | ||
{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC | ||
} | ||
}, | ||
on_construct = function(pos) | ||
local meta = minetest.get_meta(pos) | ||
local is = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} } | ||
|
||
meta:set_string("instr", lcore.serialize(is)) | ||
meta:set_int("valid", 0) | ||
meta:set_string("formspec", plg.to_formspec_string(is)) | ||
meta:set_string("infotext", "FPGA") | ||
end, | ||
on_receive_fields = function(pos, formname, fields, sender) | ||
if fields.program == nil then return end -- we only care when the user clicks "Program" | ||
local meta = minetest.get_meta(pos) | ||
local is = plg.from_formspec_fields(fields) | ||
|
||
meta:set_string("instr", lcore.serialize(is)) | ||
plg.update_formspec(pos, is) | ||
end, | ||
sounds = default.node_sound_stone_defaults(), | ||
mesecons = { | ||
effector = { | ||
rules = {}, -- replaced later | ||
action_change = function(pos, node, rule, newstate) | ||
plg.ports_changed(pos, rule, newstate) | ||
plg.update(pos) | ||
end | ||
} | ||
}, | ||
after_dig_node = function(pos, node) | ||
mesecon.receptor_off(pos, plg.rules[node.name]) | ||
end, | ||
}) | ||
|
||
|
||
plg.to_formspec_string = function(is) | ||
local function dropdown_op(x, y, name, val) | ||
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" | ||
.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored? | ||
s = s .. " ,A,B,C,D,0,1,2,3,4,5,6,7,8,9;" | ||
if val == nil then | ||
s = s .. "0" -- actually selects no field at all | ||
elseif val.type == "io" then | ||
local mapping = { | ||
["A"] = 1, | ||
["B"] = 2, | ||
["C"] = 3, | ||
["D"] = 4, | ||
} | ||
s = s .. tostring(1 + mapping[val.port]) | ||
else -- "reg" | ||
s = s .. tostring(6 + val.n) | ||
end | ||
return s .. "]" | ||
end | ||
local function dropdown_action(x, y, name, val) | ||
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" | ||
.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored? | ||
s = s .. " , AND, OR, NOT, XOR,NAND, =,XNOR;" | ||
if val == nil then | ||
return s .. "0]" -- actually selects no field at all | ||
end | ||
local mapping = { | ||
["and"] = 1, | ||
["or"] = 2, | ||
["not"] = 3, | ||
["xor"] = 4, | ||
["nand"] = 5, | ||
["buf"] = 6, | ||
["xnor"] = 7, | ||
} | ||
return s .. tostring(1 + mapping[val]) .. "]" | ||
end | ||
local s = "size[9,9]".. | ||
"label[3.4,-0.15;FPGA gate configuration]".. | ||
"button_exit[7,7.5;2,2.5;program;Program]".. | ||
"box[4.2,0.5;0.03,7;#ffffff]".. | ||
"label[0.25,0.25;op. 1]".. | ||
"label[1.0,0.25;gate type]".. | ||
"label[2.125,0.25;op. 2]".. | ||
"label[3.15,0.25;dest]".. | ||
"label[4.5,0.25;op. 1]".. | ||
"label[5.25,0.25;gate type]".. | ||
"label[6.375,0.25;op. 2]".. | ||
"label[7.4,0.25;dest]" | ||
local x = 1 - 0.75 | ||
local y = 1 - 0.25 | ||
for i = 1, 14 do | ||
local cur = is[i] | ||
s = s .. dropdown_op (x , y, tostring(i).."op1", cur.op1) | ||
s = s .. dropdown_action(x+0.75 , y, tostring(i).."act", cur.action) | ||
s = s .. dropdown_op (x+1.875, y, tostring(i).."op2", cur.op2) | ||
s = s .. "label[" .. tostring(x+2.625) .. "," .. tostring(y+0.1) .. "; ->]" | ||
s = s .. dropdown_op (x+2.9 , y, tostring(i).."dst", cur.dst) | ||
y = y + 1 | ||
|
||
if i == 7 then | ||
x = 4.5 | ||
y = 1 - 0.25 | ||
end | ||
end | ||
return s | ||
end | ||
|
||
plg.from_formspec_fields = function(fields) | ||
local function read_op(s) | ||
if s == nil or s == " " then | ||
return nil | ||
elseif s == "A" or s == "B" or s == "C" or s == "D" then | ||
return {type = "io", port = s} | ||
else | ||
return {type = "reg", n = tonumber(s)} | ||
end | ||
end | ||
local function read_action(s) | ||
if s == nil or s == " " then | ||
return nil | ||
end | ||
local mapping = { | ||
[" AND"] = "and", | ||
[" OR"] = "or", | ||
[" NOT"] = "not", | ||
[" XOR"] = "xor", | ||
["NAND"] = "nand", | ||
[" ="] = "buf", | ||
["XNOR"] = "xnor", | ||
} | ||
return mapping[s] | ||
end | ||
local is = {} | ||
for i = 1, 14 do | ||
local cur = {} | ||
cur.op1 = read_op(fields[tonumber(i) .. "op1"]) | ||
cur.action = read_action(fields[tonumber(i) .. "act"]) | ||
cur.op2 = read_op(fields[tonumber(i) .. "op2"]) | ||
cur.dst = read_op(fields[tonumber(i) .. "dst"]) | ||
is[#is + 1] = cur | ||
end | ||
return is | ||
end | ||
|
||
plg.update_formspec = function(pos, is) | ||
if type(is) == "string" then -- serialized string | ||
is = lcore.deserialize(is) | ||
end | ||
local meta = minetest.get_meta(pos) | ||
local form = plg.to_formspec_string(is) | ||
|
||
local err = lcore.validate(is) | ||
if err == nil then | ||
meta:set_int("valid", 1) | ||
meta:set_string("infotext", "FPGA (functional)") | ||
else | ||
meta:set_int("valid", 0) | ||
meta:set_string("infotext", "FPGA") | ||
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg)) | ||
form = form .. plg.red_box_around(err.i) .. | ||
"label[0.25,8.25;The gate configuration is erroneous in the marked area:]".. | ||
"label[0.25,8.5;" .. fmsg .. "]" | ||
end | ||
|
||
meta:set_string("formspec", form) | ||
|
||
-- reset ports and run programmed logic | ||
plg.setports(pos, false, false, false, false) | ||
plg.update(pos) | ||
end | ||
|
||
plg.red_box_around = function(i) | ||
local x, y | ||
if i > 7 then | ||
x = 4.5 | ||
y = 0.75 + (i - 8) | ||
else | ||
x = 0.25 | ||
y = 0.75 + (i - 1) | ||
end | ||
return string.format("box[%f,%f;3.8,0.8;#ff0000]", x-0.1, y-0.05) | ||
end | ||
|
||
|
||
plg.update = function(pos) | ||
local meta = minetest.get_meta(pos) | ||
if meta:get_int("valid") ~= 1 then | ||
return | ||
end | ||
|
||
local is = lcore.deserialize(meta:get_string("instr")) | ||
local A, B, C, D = plg.getports(pos) | ||
A, B, C, D = lcore.interpret(is, A, B, C, D) | ||
plg.setports(pos, A, B, C, D) | ||
end | ||
|
||
plg.ports_changed = function(pos, rule, newstate) | ||
if rule == nil then return end | ||
local meta = minetest.get_meta(pos) | ||
local states | ||
|
||
local s = meta:get_string("portstates") | ||
if s == nil then | ||
states = {false, false, false, false} | ||
else | ||
states = { | ||
s:sub(1, 1) == "1", | ||
s:sub(2, 2) == "1", | ||
s:sub(3, 3) == "1", | ||
s:sub(4, 4) == "1", | ||
} | ||
end | ||
|
||
-- trick to transform rules (see register_node) into port number | ||
local portno = ({4, 1, nil, 3, 2})[3 + rule.x + 2*rule.z] | ||
states[portno] = (newstate == "on") | ||
|
||
meta:set_string("portstates", | ||
(states[1] and "1" or "0") .. (states[2] and "1" or "0") .. | ||
(states[3] and "1" or "0") .. (states[4] and "1" or "0") | ||
) | ||
end | ||
|
||
plg.getports = function(pos) -- gets merged states of INPUT & OUTPUT | ||
local sin, sout | ||
|
||
local s = minetest.get_meta(pos):get_string("portstates") | ||
if s == nil then | ||
sin = {false, false, false, false} | ||
else | ||
sin = { | ||
s:sub(1, 1) == "1", | ||
s:sub(2, 2) == "1", | ||
s:sub(3, 3) == "1", | ||
s:sub(4, 4) == "1", | ||
} | ||
end | ||
|
||
local name = minetest.get_node(pos).name | ||
assert(name:find("mesecons_fpga:fpga") == 1) | ||
local off = #"mesecons_fpga:fpga" | ||
sout = { | ||
name:sub(off+4, off+4) == "1", | ||
name:sub(off+3, off+3) == "1", | ||
name:sub(off+2, off+2) == "1", | ||
name:sub(off+1, off+1) == "1", | ||
} | ||
|
||
return unpack({ | ||
sin[1] or sout[1], | ||
sin[2] or sout[2], | ||
sin[3] or sout[3], | ||
sin[4] or sout[4], | ||
}) | ||
end | ||
|
||
plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT | ||
local base = "mesecons_fpga:fpga" | ||
|
||
local name = base | ||
.. (D and "1" or "0") .. (C and "1" or "0") | ||
.. (B and "1" or "0") .. (A and "1" or "0") | ||
minetest.swap_node(pos, {name = name, param2 = minetest.get_node(pos).param2}) | ||
|
||
if A ~= nil then | ||
local ru = plg.rules[base .. "0001"] | ||
if A then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end | ||
end | ||
if B ~= nil then | ||
local ru = plg.rules[base .. "0010"] | ||
if B then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end | ||
end | ||
if C ~= nil then | ||
local ru = plg.rules[base .. "0100"] | ||
if C then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end | ||
end | ||
if D ~= nil then | ||
local ru = plg.rules[base .. "1000"] | ||
if D then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end | ||
end | ||
end | ||
|
||
|
||
minetest.register_craft({ | ||
output = "mesecons_fpga:fpga0000 2", | ||
recipe = { | ||
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, | ||
{'mesecons_materials:silicon', 'mesecons_materials:silicon'}, | ||
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
local lg = {} | ||
|
||
-- (de)serialize | ||
lg.serialize = function(t) | ||
local function _op(t) | ||
if t == nil then | ||
return " " | ||
elseif t.type == "io" then | ||
return t.port | ||
else -- t.type == "reg" | ||
return tostring(t.n) | ||
end | ||
end | ||
local function _action(s) | ||
if s == nil then | ||
return " " | ||
end | ||
local mapping = { | ||
["and"] = "&", | ||
["or"] = "|", | ||
["not"] = "~", | ||
["xor"] = "^", | ||
["nand"] = "?", --dunno | ||
["buf"] = "_", | ||
["xnor"] = "=", | ||
} | ||
return mapping[s] | ||
end | ||
|
||
local s = "" | ||
for i = 1, 14 do | ||
local cur = t[i] | ||
if next(cur) ~= nil then | ||
s = s .. _op(cur.op1) .. _action(cur.action) .. _op(cur.op2) .. _op(cur.dst) | ||
end | ||
s = s .. "/" | ||
end | ||
return s | ||
end | ||
|
||
lg.deserialize = function(s) | ||
local function _op(c) | ||
if c == "A" or c == "B" or c == "C" or c == "D" then | ||
return {type = "io", port = c} | ||
elseif c == " " then | ||
return nil | ||
else | ||
return {type = "reg", n = tonumber(c)} | ||
end | ||
end | ||
local function _action(c) | ||
local mapping = { | ||
["&"] = "and", | ||
["|"] = "or", | ||
["~"] = "not", | ||
["^"] = "xor", | ||
["?"] = "nand", | ||
["_"] = "buf", | ||
["="] = "xnor", | ||
[" "] = nil, | ||
} | ||
return mapping[c] | ||
end | ||
|
||
local ret = {} | ||
for part in s:gmatch("(.-)/") do | ||
local parsed | ||
if part == "" then | ||
parsed = {} | ||
else | ||
parsed = { | ||
action = _action( part:sub(2,2) ), | ||
op1 = _op( part:sub(1,1) ), | ||
op2 = _op( part:sub(3,3) ), | ||
dst = _op( part:sub(4,4) ), | ||
} | ||
end | ||
ret[#ret + 1] = parsed | ||
end | ||
-- More than 14 instructions (write to all 10 regs + 4 outputs) | ||
-- will not pass the write-once requirement of the validator | ||
assert(#ret == 14) | ||
return ret | ||
end | ||
|
||
-- validation | ||
lg.validate_single = function(t, i) | ||
local function is_reg_written_to(t, n, max) | ||
for i = 1, max-1 do | ||
if next(t[i]) ~= nil | ||
and t[i].dst and t[i].dst.type == "reg" | ||
and t[i].dst.n == n then | ||
return true | ||
end | ||
end | ||
return false | ||
end | ||
local function compare_op(t1, t2, allow_same_io) | ||
if t1 == nil or t2 == nil then | ||
return false | ||
elseif t1.type ~= t2.type then | ||
return false | ||
end | ||
if t1.type == "reg" and t1.n == t2.n then | ||
return true | ||
elseif t1.type == "io" and t1.port == t2.port then | ||
return not allow_same_io | ||
end | ||
return false | ||
end | ||
local elem = t[i] | ||
-- check for completeness | ||
if elem.action == nil then | ||
return {i = i, msg = "Gate type required"} | ||
elseif elem.action == "not" or elem.action == "buf" then | ||
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then | ||
return {i = i, msg = "Second operand (only) and destination required"} | ||
end | ||
else | ||
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then | ||
return {i = i, msg = "Operands and destination required"} | ||
end | ||
end | ||
-- check whether operands/destination are identical | ||
if compare_op(elem.op1, elem.op2) then | ||
return {i = i, msg = "Operands cannot be identical"} | ||
end | ||
if compare_op(elem.op1, elem.dst, true) or compare_op(elem.op2, elem.dst, true) then | ||
return {i = i, msg = "Destination and operands must be different"} | ||
end | ||
-- check whether operands point to defined registers | ||
if elem.op1 ~= nil and elem.op1.type == "reg" | ||
and not is_reg_written_to(t, elem.op1.n, i) then | ||
return {i = i, msg = "First operand is undefined register"} | ||
end | ||
if elem.op2.type == "reg" and not is_reg_written_to(t, elem.op2.n, i) then | ||
return {i = i, msg = "Second operand is undefined register"} | ||
end | ||
-- check whether destination points to undefined register | ||
if elem.dst.type == "reg" and is_reg_written_to(t, elem.dst.n, i) then | ||
return {i = i, msg = "Destination is already used register"} | ||
end | ||
|
||
return nil | ||
end | ||
|
||
lg.validate = function(t) | ||
for i = 1, 14 do | ||
if next(t[i]) ~= nil then | ||
local r = lg.validate_single(t, i) | ||
if r ~= nil then | ||
return r | ||
end | ||
end | ||
end | ||
return nil | ||
end | ||
|
||
-- interpreter | ||
lg.interpret = function(t, a, b, c, d) | ||
local function _action(s, v1, v2) | ||
if s == "and" then | ||
return v1 and v2 | ||
elseif s == "or" then | ||
return v1 or v2 | ||
elseif s == "not" then | ||
return not v2 | ||
elseif s == "xor" then | ||
return v1 ~= v2 | ||
elseif s == "nand" then | ||
return not (v1 and v2) | ||
elseif s == "buf" then | ||
return v2 | ||
else -- s == "xnor" | ||
return v1 == v2 | ||
end | ||
end | ||
local function _op(t, regs, io_in) | ||
if t.type == "reg" then | ||
return regs[t.n] | ||
else -- t.type == "io" | ||
return io_in[t.port] | ||
end | ||
end | ||
|
||
local io_in = {A=a, B=b, C=c, D=d} | ||
local regs = {} | ||
local io_out = {} | ||
for i = 1, 14 do | ||
local cur = t[i] | ||
if next(cur) ~= nil then | ||
local v1, v2 | ||
if cur.op1 ~= nil then | ||
v1 = _op(cur.op1, regs, io_in) | ||
end | ||
v2 = _op(cur.op2, regs, io_in) | ||
|
||
local result = _action(cur.action, v1, v2) | ||
|
||
if cur.dst.type == "reg" then | ||
regs[cur.dst.n] = result | ||
else -- cur.dst.type == "io" | ||
io_out[cur.dst.port] = result | ||
end | ||
end | ||
end | ||
return io_out.A, io_out.B, io_out.C, io_out.D | ||
end | ||
|
||
return lg |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
return function(plg) | ||
|
||
|
||
minetest.register_tool("mesecons_fpga:programmer", { | ||
description = "FPGA Programmer", | ||
inventory_image = "jeija_fpga_programmer.png", | ||
stack_max = 1, | ||
on_place = function(itemstack, placer, pointed_thing) | ||
if pointed_thing.type ~= "node" then | ||
return itemstack | ||
end | ||
|
||
local pos = pointed_thing.under | ||
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then | ||
return itemstack | ||
end | ||
|
||
local meta = minetest.get_meta(pos) | ||
if meta:get_string("instr") == "//////////////" then | ||
minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.") | ||
return itemstack | ||
end | ||
itemstack:set_metadata(meta:get_string("instr")) | ||
minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!") | ||
|
||
return itemstack | ||
end, | ||
on_use = function(itemstack, user, pointed_thing) | ||
if pointed_thing.type ~= "node" then | ||
return itemstack | ||
end | ||
|
||
local pos = pointed_thing.under | ||
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then | ||
return itemstack | ||
end | ||
|
||
local imeta = itemstack:get_metadata() | ||
if imeta == "" then | ||
minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.") | ||
return itemstack | ||
end | ||
|
||
local meta = minetest.get_meta(pos) | ||
meta:set_string("instr", imeta) | ||
plg.update_formspec(pos, imeta) | ||
minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!") | ||
|
||
return itemstack | ||
end | ||
}) | ||
|
||
minetest.register_craft({ | ||
output = "mesecons_fpga:programmer", | ||
recipe = { | ||
{'group:mesecon_conductor_craftable'}, | ||
{'mesecons_materials:silicon'}, | ||
} | ||
}) | ||
|
||
|
||
end |