Merge https://github.com/minetest-mods/mesecons into HEAD
|
@ -1 +1,3 @@
|
|||
*~
|
||||
*.patch
|
||||
*.diff
|
||||
|
|
|
@ -1,96 +1,140 @@
|
|||
mesecon.queue.actions={} -- contains all ActionQueue actions
|
||||
--[[
|
||||
Mesecons uses something it calls an ActionQueue.
|
||||
|
||||
function mesecon.queue:add_function(name, func)
|
||||
mesecon.queue.funcs[name] = func
|
||||
The ActionQueue holds functions and actions.
|
||||
Functions are added on load time with a specified name.
|
||||
Actions are preserved over server restarts.
|
||||
|
||||
Each action consists of a position, the name of an added function to be called,
|
||||
the params that should be used in this function call (additionally to the pos),
|
||||
the time after which it should be executed, an optional overwritecheck and a
|
||||
priority.
|
||||
|
||||
If time = 0, the action will be executed in the next globalstep, otherwise the
|
||||
earliest globalstep when it will be executed is the after next globalstep.
|
||||
|
||||
It is guaranteed, that for two actions ac1, ac2 where ac1 ~= ac2,
|
||||
ac1.time == ac2.time, ac1.priority == ac2.priority and ac1 was added earlier
|
||||
than ac2, ac1 will be executed before ac2 (but in the same globalstep).
|
||||
|
||||
Note: Do not pass references in params, as they can not be preserved.
|
||||
|
||||
Also note: Some of the guarantees here might be dropped at some time.
|
||||
]]
|
||||
|
||||
|
||||
-- localize for speed
|
||||
local queue = mesecon.queue
|
||||
|
||||
queue.actions = {} -- contains all ActionQueue actions
|
||||
|
||||
function queue:add_function(name, func)
|
||||
queue.funcs[name] = func
|
||||
end
|
||||
|
||||
-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
|
||||
-- use overwritecheck nil to never overwrite, but just add the event to the queue
|
||||
-- priority specifies the order actions are executed within one globalstep, highest first
|
||||
-- should be between 0 and 1
|
||||
function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
|
||||
function queue:add_action(pos, func, params, time, overwritecheck, priority)
|
||||
-- Create Action Table:
|
||||
time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
|
||||
priority = priority or 1
|
||||
local action = { pos=mesecon.tablecopy(pos),
|
||||
func=func,
|
||||
params=mesecon.tablecopy(params or {}),
|
||||
time=time,
|
||||
owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
|
||||
priority=priority}
|
||||
local action = {
|
||||
pos = mesecon.tablecopy(pos),
|
||||
func = func,
|
||||
params = mesecon.tablecopy(params or {}),
|
||||
time = time,
|
||||
owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
|
||||
priority = priority
|
||||
}
|
||||
|
||||
local toremove = nil
|
||||
-- Otherwise, add the action to the queue
|
||||
if overwritecheck then -- check if old action has to be overwritten / removed:
|
||||
for i, ac in ipairs(mesecon.queue.actions) do
|
||||
if(vector.equals(pos, ac.pos)
|
||||
and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
|
||||
toremove = i
|
||||
-- check if old action has to be overwritten / removed:
|
||||
if overwritecheck then
|
||||
for i, ac in ipairs(queue.actions) do
|
||||
if vector.equals(pos, ac.pos)
|
||||
and mesecon.cmpAny(overwritecheck, ac.owcheck) then
|
||||
-- remove the old action
|
||||
table.remove(queue.actions, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (toremove ~= nil) then
|
||||
table.remove(mesecon.queue.actions, toremove)
|
||||
end
|
||||
|
||||
table.insert(mesecon.queue.actions, action)
|
||||
table.insert(queue.actions, action)
|
||||
end
|
||||
|
||||
-- execute the stored functions on a globalstep
|
||||
-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
|
||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine
|
||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine (hm, where do we do this?)
|
||||
-- However, even that does not work in some cases, that's why we delay the time the globalsteps
|
||||
-- start to be execute by 5 seconds
|
||||
local get_highest_priority = function (actions)
|
||||
local highestp = -1
|
||||
local highesti
|
||||
for i, ac in ipairs(actions) do
|
||||
if ac.priority > highestp then
|
||||
highestp = ac.priority
|
||||
highesti = i
|
||||
end
|
||||
end
|
||||
-- start to be execute by 4 seconds
|
||||
|
||||
return highesti
|
||||
end
|
||||
local function globalstep_func(dtime)
|
||||
local actions = queue.actions
|
||||
-- split into two categories:
|
||||
-- actions_now: actions to execute now
|
||||
-- queue.actions: actions to execute later
|
||||
local actions_now = {}
|
||||
queue.actions = {}
|
||||
|
||||
local m_time = 0
|
||||
local resumetime = mesecon.setting("resumetime", 4)
|
||||
minetest.register_globalstep(function (dtime)
|
||||
m_time = m_time + dtime
|
||||
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
|
||||
-- after starting the server before processing the ActionQueue, don't set this too low
|
||||
if (m_time < resumetime) then return end
|
||||
local actions = mesecon.tablecopy(mesecon.queue.actions)
|
||||
local actions_now={}
|
||||
|
||||
mesecon.queue.actions = {}
|
||||
|
||||
-- sort actions into two categories:
|
||||
-- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions)
|
||||
for i, ac in ipairs(actions) do
|
||||
for _, ac in ipairs(actions) do
|
||||
if ac.time > 0 then
|
||||
ac.time = ac.time - dtime -- executed later
|
||||
table.insert(mesecon.queue.actions, ac)
|
||||
-- action ac is to be executed later
|
||||
-- ~> insert into queue.actions
|
||||
ac.time = ac.time - dtime
|
||||
table.insert(queue.actions, ac)
|
||||
else
|
||||
-- action ac is to be executed now
|
||||
-- ~> insert into actions_now
|
||||
table.insert(actions_now, ac)
|
||||
end
|
||||
end
|
||||
|
||||
while(#actions_now > 0) do -- execute highest priorities first, until all are executed
|
||||
local hp = get_highest_priority(actions_now)
|
||||
mesecon.queue:execute(actions_now[hp])
|
||||
table.remove(actions_now, hp)
|
||||
-- stable-sort the executed actions after their priority
|
||||
-- some constructions might depend on the execution order, hence we first
|
||||
-- execute the actions that had a lower index in actions_now
|
||||
local old_action_order = {}
|
||||
for i, ac in ipairs(actions_now) do
|
||||
old_action_order[ac] = i
|
||||
end
|
||||
end)
|
||||
table.sort(actions_now, function(ac1, ac2)
|
||||
if ac1.priority ~= ac2.priority then
|
||||
return ac1.priority > ac2.priority
|
||||
else
|
||||
return old_action_order[ac1] < old_action_order[ac2]
|
||||
end
|
||||
end)
|
||||
|
||||
function mesecon.queue:execute(action)
|
||||
-- execute highest priorities first, until all are executed
|
||||
for _, ac in ipairs(actions_now) do
|
||||
queue:execute(ac)
|
||||
end
|
||||
end
|
||||
|
||||
-- delay the time the globalsteps start to be execute by 4 seconds
|
||||
do
|
||||
local m_time = 0
|
||||
local resumetime = mesecon.setting("resumetime", 4)
|
||||
local globalstep_func_index = #minetest.registered_globalsteps + 1
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
m_time = m_time + dtime
|
||||
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
|
||||
-- after starting the server before processing the ActionQueue, don't set this too low
|
||||
if m_time < resumetime then
|
||||
return
|
||||
end
|
||||
-- replace this globalstep function
|
||||
minetest.registered_globalsteps[globalstep_func_index] = globalstep_func
|
||||
end)
|
||||
end
|
||||
|
||||
function queue:execute(action)
|
||||
-- ignore if action queue function name doesn't exist,
|
||||
-- (e.g. in case the action queue savegame was written by an old mesecons version)
|
||||
if mesecon.queue.funcs[action.func] then
|
||||
mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
|
||||
if queue.funcs[action.func] then
|
||||
queue.funcs[action.func](action.pos, unpack(action.params))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,8 +142,8 @@ end
|
|||
-- Store and read the ActionQueue to / from a file
|
||||
-- so that upcoming actions are remembered when the game
|
||||
-- is restarted
|
||||
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||
queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
|
||||
mesecon.table2file("mesecon_actionqueue", queue.actions)
|
||||
end)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
default
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons
|
||||
depends = default
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 191 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 844 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 838 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 550 B After Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 204 B After Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 362 B |
|
@ -186,19 +186,11 @@ function mesecon.invertRule(r)
|
|||
return vector.multiply(r, -1)
|
||||
end
|
||||
|
||||
function mesecon.tablecopy(table) -- deep table copy
|
||||
if type(table) ~= "table" then return table end -- no need to copy
|
||||
local newtable = {}
|
||||
|
||||
for idx, item in pairs(table) do
|
||||
if type(item) == "table" then
|
||||
newtable[idx] = mesecon.tablecopy(item)
|
||||
else
|
||||
newtable[idx] = item
|
||||
end
|
||||
function mesecon.tablecopy(obj) -- deep copy
|
||||
if type(obj) == "table" then
|
||||
return table.copy(obj)
|
||||
end
|
||||
|
||||
return newtable
|
||||
return obj
|
||||
end
|
||||
|
||||
function mesecon.cmpAny(t1, t2)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
mesecons
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_alias
|
||||
depends = mesecons
|
|
@ -1 +0,0 @@
|
|||
mesecons
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_blinkyplant
|
||||
depends = mesecons
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 394 B |
|
@ -1,2 +0,0 @@
|
|||
mesecons
|
||||
mesecons_receiver
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 4.3 KiB |
|
@ -8,7 +8,7 @@ mesecon.button_turnoff = function (pos)
|
|||
return
|
||||
end
|
||||
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2})
|
||||
minetest.sound_play("mesecons_button_pop", {pos = pos})
|
||||
minetest.sound_play("mesecons_button_pop", { pos = pos }, true)
|
||||
local rules = mesecon.rules.buttonlike_get(node)
|
||||
mesecon.receptor_off(pos, rules)
|
||||
end
|
||||
|
@ -46,7 +46,7 @@ minetest.register_node("mesecons_button:button_off", {
|
|||
on_rightclick = function (pos, node)
|
||||
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
|
||||
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
|
||||
minetest.sound_play("mesecons_button_push", {pos=pos})
|
||||
minetest.sound_play("mesecons_button_push", { pos = pos }, true)
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_button
|
||||
depends = mesecons, mesecons_receiver
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 409 B |
Before Width: | Height: | Size: 434 B After Width: | Height: | Size: 220 B |
|
@ -1 +0,0 @@
|
|||
mesecons
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 33 KiB |
|
@ -110,7 +110,7 @@ local function resolve_commands(commands, pos)
|
|||
local nearest, farthest = nil, nil
|
||||
local min_distance, max_distance = math.huge, -1
|
||||
for index, player in pairs(players) do
|
||||
local distance = vector.distance(pos, player:getpos())
|
||||
local distance = vector.distance(pos, player:get_pos())
|
||||
if distance < min_distance then
|
||||
min_distance = distance
|
||||
nearest = player:get_player_name()
|
||||
|
@ -174,7 +174,8 @@ end
|
|||
local function can_dig(pos, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string("owner")
|
||||
return owner == "" or owner == player:get_player_name()
|
||||
return owner == "" or owner == player:get_player_name() or
|
||||
minetest.check_player_privs(player, "protection_bypass")
|
||||
end
|
||||
|
||||
minetest.register_node("mesecons_commandblock:commandblock_off", {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_commandblock
|
||||
depends = mesecons
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 183 B |
|
@ -1 +0,0 @@
|
|||
mesecons
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -33,19 +33,9 @@ end
|
|||
|
||||
-- Register the 2 (states) x 4 (delay times) delayers
|
||||
|
||||
for i = 1, 4 do
|
||||
local groups = {}
|
||||
if i == 1 then
|
||||
groups = {bendy=2,snappy=1,dig_immediate=2}
|
||||
else
|
||||
groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1}
|
||||
end
|
||||
local delaytime = { 0.1, 0.3, 0.5, 1.0 }
|
||||
|
||||
local delaytime
|
||||
if i == 1 then delaytime = 0.1
|
||||
elseif i == 2 then delaytime = 0.3
|
||||
elseif i == 3 then delaytime = 0.5
|
||||
elseif i == 4 then delaytime = 1.0 end
|
||||
for i = 1, 4 do
|
||||
|
||||
local boxes = {
|
||||
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
||||
|
@ -61,19 +51,9 @@ local boxes = {
|
|||
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
|
||||
}
|
||||
|
||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
description = "Delayer",
|
||||
-- Delayer definition defaults
|
||||
local def = {
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"mesecons_delayer_off_"..tostring(i)..".png",
|
||||
"mesecons_delayer_bottom.png",
|
||||
"mesecons_delayer_ends_off.png",
|
||||
"mesecons_delayer_ends_off.png",
|
||||
"mesecons_delayer_sides_off.png",
|
||||
"mesecons_delayer_sides_off.png"
|
||||
},
|
||||
inventory_image = "mesecons_delayer_off_1.png",
|
||||
wield_image = "mesecons_delayer_off_1.png",
|
||||
walkable = true,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
|
@ -83,26 +63,46 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
|||
type = "fixed",
|
||||
fixed = boxes
|
||||
},
|
||||
groups = groups,
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
drop = 'mesecons_delayer:delayer_off_1',
|
||||
on_punch = function (pos, node)
|
||||
if node.name=="mesecons_delayer:delayer_off_1" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_2", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_off_2" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_3", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_off_3" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_4", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_off_4" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_1", param2=node.param2})
|
||||
end
|
||||
end,
|
||||
delayer_time = delaytime,
|
||||
delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
|
||||
delayer_time = delaytime[i],
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_blast = mesecon.on_blastnode,
|
||||
drop = "mesecons_delayer:delayer_off_1",
|
||||
}
|
||||
|
||||
-- Deactivated delayer definition defaults
|
||||
local off_groups = {bendy=2,snappy=1,dig_immediate=2}
|
||||
if i > 1 then
|
||||
off_groups.not_in_creative_inventory = 1
|
||||
end
|
||||
|
||||
local off_state = {
|
||||
description = "Delayer",
|
||||
tiles = {
|
||||
"mesecons_delayer_off_"..tostring(i)..".png",
|
||||
"mesecons_delayer_bottom.png",
|
||||
"mesecons_delayer_ends_off.png",
|
||||
"mesecons_delayer_ends_off.png",
|
||||
"mesecons_delayer_sides_off.png",
|
||||
"mesecons_delayer_sides_off.png"
|
||||
},
|
||||
inventory_image = "mesecons_delayer_off_1.png",
|
||||
wield_image = "mesecons_delayer_off_1.png",
|
||||
groups = off_groups,
|
||||
on_punch = function(pos, node, puncher)
|
||||
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.swap_node(pos, {
|
||||
name = "mesecons_delayer:delayer_off_"..tostring(i % 4 + 1),
|
||||
param2 = node.param2
|
||||
})
|
||||
end,
|
||||
delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
|
||||
mesecons = {
|
||||
receptor =
|
||||
{
|
||||
|
@ -115,13 +115,15 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
|||
action_on = delayer_activate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
}
|
||||
for k, v in pairs(def) do
|
||||
off_state[k] = off_state[k] or v
|
||||
end
|
||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state)
|
||||
|
||||
|
||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
-- Activated delayer definition defaults
|
||||
local on_state = {
|
||||
description = "You hacker you",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"mesecons_delayer_on_"..tostring(i)..".png",
|
||||
"mesecons_delayer_bottom.png",
|
||||
|
@ -129,36 +131,19 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
|||
"mesecons_delayer_ends_on.png",
|
||||
"mesecons_delayer_sides_on.png",
|
||||
"mesecons_delayer_sides_on.png"
|
||||
},
|
||||
walkable = true,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = boxes
|
||||
},
|
||||
groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
drop = 'mesecons_delayer:delayer_off_1',
|
||||
on_punch = function (pos, node)
|
||||
if node.name=="mesecons_delayer:delayer_on_1" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_2", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_on_2" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_3", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_on_3" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_4", param2=node.param2})
|
||||
elseif node.name=="mesecons_delayer:delayer_on_4" then
|
||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_1", param2=node.param2})
|
||||
on_punch = function(pos, node, puncher)
|
||||
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.swap_node(pos, {
|
||||
name = "mesecons_delayer:delayer_on_"..tostring(i % 4 + 1),
|
||||
param2 = node.param2
|
||||
})
|
||||
end,
|
||||
delayer_time = delaytime,
|
||||
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
receptor =
|
||||
{
|
||||
|
@ -171,8 +156,12 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
|||
action_off = delayer_deactivate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
}
|
||||
for k, v in pairs(def) do
|
||||
on_state[k] = on_state[k] or v
|
||||
end
|
||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), on_state)
|
||||
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_delayer
|
||||
depends = mesecons
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 562 B After Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 446 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 538 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 181 B |
|
@ -1,2 +0,0 @@
|
|||
mesecons
|
||||
mesecons_materials
|
|
@ -1,8 +1,11 @@
|
|||
The node detector is a receptor. It changes its state when either any node
|
||||
or a specific node is detected. Right-click it to set a nodename to scan for.
|
||||
It can also receive digiline signals. You can either send "GET" and it will
|
||||
respond with the detected nodename or you can send any other string and it will
|
||||
set this string as the node to scan for.
|
||||
It can also receive digiline signals. For example, you can send
|
||||
<code>{distance=4, scanname="default:dirt"}</code>
|
||||
to set distance to 4 and scan for dirt. You can omit either parameter.
|
||||
There is also a command parameter: <code>{command="get"}</code> will respond
|
||||
with the detected nodename and <code>{command="scan"}</code> will respond with
|
||||
a boolean using the distance and nodename of the detector.
|
||||
Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt.
|
||||
The distance parameter specifies how many blocks are between the node detector and the node to detect.
|
||||
Automatic scanning with Mesecons output only works when the detector is in an active block, but Digilines queries always work.
|
||||
|
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 7.1 KiB |
|
@ -189,28 +189,49 @@ local function node_detector_scan(pos)
|
|||
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
|
||||
end
|
||||
|
||||
local function node_detector_send_node_name(pos, node, channel, meta)
|
||||
local distance = meta:get_int("distance")
|
||||
local distance_max = mesecon.setting("node_detector_distance_max", 10)
|
||||
if distance < 0 then distance = 0 end
|
||||
if distance > distance_max then distance = distance_max end
|
||||
local nodename = minetest.get_node(
|
||||
vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
|
||||
).name
|
||||
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
|
||||
end
|
||||
|
||||
-- set player name when receiving a digiline signal on a specific channel
|
||||
local node_detector_digiline = {
|
||||
effector = {
|
||||
action = function(pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local distance = meta:get_int("distance")
|
||||
local distance_max = mesecon.setting("node_detector_distance_max", 10)
|
||||
if distance < 0 then distance = 0 end
|
||||
if distance > distance_max then distance = distance_max end
|
||||
|
||||
if channel ~= meta:get_string("digiline_channel") then return end
|
||||
|
||||
if msg == GET_COMMAND then
|
||||
local nodename = minetest.get_node(
|
||||
vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
|
||||
).name
|
||||
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
|
||||
if type(msg) == "table" then
|
||||
if msg.distance or msg.scanname then
|
||||
if msg.distance then
|
||||
meta:set_string("distance", msg.distance)
|
||||
end
|
||||
if msg.scanname then
|
||||
meta:set_string("scanname", msg.scanname)
|
||||
end
|
||||
node_detector_make_formspec(pos)
|
||||
end
|
||||
if msg.command == "get" then
|
||||
node_detector_send_node_name(pos, node, channel, meta)
|
||||
elseif msg.command == "scan" then
|
||||
local result = node_detector_scan(pos)
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, result)
|
||||
end
|
||||
else
|
||||
meta:set_string("scanname", msg)
|
||||
node_detector_make_formspec(pos)
|
||||
if msg == GET_COMMAND then
|
||||
node_detector_send_node_name(pos, node, channel, meta)
|
||||
else
|
||||
meta:set_string("scanname", msg)
|
||||
node_detector_make_formspec(pos)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
@ -218,7 +239,7 @@ local node_detector_digiline = {
|
|||
}
|
||||
|
||||
local function after_place_node_detector(pos, placer)
|
||||
local placer_pos = placer:getpos()
|
||||
local placer_pos = placer:get_pos()
|
||||
if not placer_pos then
|
||||
return
|
||||
end
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_detector
|
||||
depends = mesecons, mesecons_materials
|
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 640 B |
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 687 B |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 655 B |
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 693 B |
|
@ -1,2 +0,0 @@
|
|||
mesecons
|
||||
doors
|
|
@ -13,9 +13,9 @@ local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
|
|||
minetest.swap_node(pos, {name = replace, param2 = p2})
|
||||
|
||||
if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then
|
||||
minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true)
|
||||
else
|
||||
minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -79,10 +79,10 @@ local function trapdoor_switch(pos, node)
|
|||
local state = minetest.get_meta(pos):get_int("state")
|
||||
|
||||
if state == 1 then
|
||||
minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true)
|
||||
minetest.set_node(pos, {name="doors:trapdoor", param2 = node.param2})
|
||||
else
|
||||
minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true)
|
||||
minetest.set_node(pos, {name="doors:trapdoor_open", param2 = node.param2})
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
name = mesecons_doors
|
||||
depends = mesecons, doors
|
|
@ -1,12 +1,5 @@
|
|||
local screwdriver_exists = minetest.global_exists("screwdriver")
|
||||
|
||||
local corner_nodebox = {
|
||||
type = "fixed",
|
||||
-- ±0.001 is to prevent z-fighting
|
||||
fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, 3/32}}
|
||||
}
|
||||
|
||||
local corner_selectionbox = {
|
||||
type = "fixed",
|
||||
fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 },
|
||||
|
@ -25,14 +18,11 @@ local corner_get_rules = function (node)
|
|||
end
|
||||
|
||||
minetest.register_node("mesecons_extrawires:corner_on", {
|
||||
drawtype = "nodebox",
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_corner.obj",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_curved_tb_on.png",
|
||||
"jeija_insulated_wire_curved_tb_on.png^[transformR270",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_ends_on.png",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_ends_on.png"
|
||||
{ name = "jeija_insulated_wire_sides_on.png", backface_culling = true },
|
||||
{ name = "jeija_insulated_wire_ends_on.png", backface_culling = true },
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
|
@ -55,15 +45,12 @@ minetest.register_node("mesecons_extrawires:corner_on", {
|
|||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:corner_off", {
|
||||
drawtype = "nodebox",
|
||||
drawtype = "mesh",
|
||||
description = "Insulated Mesecon Corner",
|
||||
mesh = "mesecons_extrawires_corner.obj",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_curved_tb_off.png",
|
||||
"jeija_insulated_wire_curved_tb_off.png^[transformR270",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_ends_off.png",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_ends_off.png"
|
||||
{ name = "jeija_insulated_wire_sides_off.png", backface_culling = true },
|
||||
{ name = "jeija_insulated_wire_ends_off.png", backface_culling = true },
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
|
@ -87,8 +74,7 @@ minetest.register_node("mesecons_extrawires:corner_off", {
|
|||
minetest.register_craft({
|
||||
output = "mesecons_extrawires:corner_off 3",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", ""},
|
||||
{"", "mesecons_insulated:insulated_off", ""},
|
||||
{"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"},
|
||||
{"", "mesecons_insulated:insulated_off"},
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
default
|
||||
mesecons
|
||||
screwdriver?
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,91 @@
|
|||
local rotate
|
||||
if minetest.global_exists("screwdriver") then rotate = screwdriver.rotate_simple end
|
||||
|
||||
local doublecorner_selectionbox = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
||||
}
|
||||
|
||||
local rules = {
|
||||
{
|
||||
{ x = 1, y = 0, z = 0 },
|
||||
{ x = 0, y = 0, z = 1 },
|
||||
},
|
||||
{
|
||||
{ x = -1, y = 0, z = 0 },
|
||||
{ x = 0, y = 0, z = -1 },
|
||||
},
|
||||
}
|
||||
|
||||
local doublecorner_rules = {}
|
||||
for k = 1, 4 do
|
||||
doublecorner_rules[k] = table.copy(rules)
|
||||
for i, r in ipairs(rules) do
|
||||
rules[i] = mesecon.rotate_rules_left(r)
|
||||
end
|
||||
end
|
||||
|
||||
local function doublecorner_get_rules(node)
|
||||
return doublecorner_rules[node.param2 % 4 + 1]
|
||||
end
|
||||
|
||||
local doublecorner_states = {
|
||||
"mesecons_extrawires:doublecorner_00",
|
||||
"mesecons_extrawires:doublecorner_01",
|
||||
"mesecons_extrawires:doublecorner_10",
|
||||
"mesecons_extrawires:doublecorner_11",
|
||||
}
|
||||
local wire1_states = { "off", "off", "on", "on" }
|
||||
local wire2_states = { "off", "on", "off", "on" }
|
||||
|
||||
for k, state in ipairs(doublecorner_states) do
|
||||
local w1 = wire1_states[k]
|
||||
local w2 = wire2_states[k]
|
||||
local groups = { dig_immediate = 3 }
|
||||
if k ~= 1 then groups.not_in_creative_inventory = 1 end
|
||||
minetest.register_node(state, {
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_doublecorner.obj",
|
||||
description = "Insulated Mesecon Double Corner",
|
||||
tiles = {
|
||||
{ name = "jeija_insulated_wire_sides_" .. w1 .. ".png", backface_culling = true },
|
||||
{ name = "jeija_insulated_wire_ends_" .. w1 .. ".png", backface_culling = true },
|
||||
{ name = "jeija_insulated_wire_sides_" .. w2 .. ".png", backface_culling = true },
|
||||
{ name = "jeija_insulated_wire_ends_" .. w2 .. ".png", backface_culling = true },
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = doublecorner_selectionbox,
|
||||
groups = groups,
|
||||
drop = doublecorner_states[1],
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {
|
||||
conductor = {
|
||||
states = doublecorner_states,
|
||||
rules = doublecorner_get_rules,
|
||||
},
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = rotate,
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "mesecons_extrawires:doublecorner_00",
|
||||
recipe = {
|
||||
"mesecons_extrawires:corner_off",
|
||||
"mesecons_extrawires:corner_off",
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "mesecons_extrawires:corner_off 2",
|
||||
recipe = {
|
||||
"mesecons_extrawires:doublecorner_00",
|
||||
},
|
||||
})
|
|
@ -1,5 +1,6 @@
|
|||
dofile(minetest.get_modpath("mesecons_extrawires").."/crossover.lua");
|
||||
dofile(minetest.get_modpath("mesecons_extrawires").."/tjunction.lua");
|
||||
dofile(minetest.get_modpath("mesecons_extrawires").."/corner.lua");
|
||||
dofile(minetest.get_modpath("mesecons_extrawires").."/doublecorner.lua");
|
||||
dofile(minetest.get_modpath("mesecons_extrawires").."/vertical.lua");
|
||||
dofile(minetest.get_modpath("mesecons_extrawires").."/mesewire.lua");
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
name = mesecons_extrawires
|
||||
depends = default, mesecons
|
||||
optional_depends = screwdriver
|
|
@ -0,0 +1,125 @@
|
|||
# Вершины
|
||||
# Провод 1
|
||||
# 1 (ниж. внутр.)
|
||||
v 0.093750 -0.531250 -0.501000
|
||||
v 0.093750 -0.531250 -0.331726
|
||||
v 0.331726 -0.531250 -0.093750
|
||||
v 0.501000 -0.531250 -0.093750
|
||||
# 5 (ниж. наруж.)
|
||||
v -0.093750 -0.531250 -0.501000
|
||||
v -0.093750 -0.531250 -0.254061
|
||||
v 0.254061 -0.531250 0.093750
|
||||
v 0.501000 -0.531250 0.093750
|
||||
# 9 (верх. внутр.)
|
||||
v 0.093750 -0.406250 -0.501000
|
||||
v 0.093750 -0.406250 -0.331726
|
||||
v 0.331726 -0.406250 -0.093750
|
||||
v 0.501000 -0.406250 -0.093750
|
||||
# 13 (верх. наруж.)
|
||||
v -0.093750 -0.406250 -0.501000
|
||||
v -0.093750 -0.406250 -0.254061
|
||||
v 0.254061 -0.406250 0.093750
|
||||
v 0.501000 -0.406250 0.093750
|
||||
# Текстурные координаты
|
||||
# 1 (ниж.)
|
||||
vt 0.000000 0.406250
|
||||
vt 0.168274 0.406250
|
||||
vt 0.331726 0.406250
|
||||
vt 0.668274 0.406250
|
||||
vt 0.831726 0.406250
|
||||
vt 1.000000 0.406250
|
||||
vt 0.000000 0.593750
|
||||
vt 0.245939 0.593750
|
||||
vt 0.254061 0.593750
|
||||
vt 0.745939 0.593750
|
||||
vt 0.754061 0.593750
|
||||
vt 1.000000 0.593750
|
||||
# 13 (верх.)
|
||||
vt 0.000000 0.406250
|
||||
vt 0.245939 0.406250
|
||||
vt 0.254061 0.406250
|
||||
vt 0.745939 0.406250
|
||||
vt 0.754061 0.406250
|
||||
vt 1.000000 0.406250
|
||||
vt 0.000000 0.593750
|
||||
vt 0.168274 0.593750
|
||||
vt 0.331726 0.593750
|
||||
vt 0.668274 0.593750
|
||||
vt 0.831726 0.593750
|
||||
vt 1.000000 0.593750
|
||||
# 25 (внутр.)
|
||||
vt 1.000000 0.093750
|
||||
vt 0.831726 0.093750
|
||||
vt 0.668274 0.093750
|
||||
vt 0.331726 0.093750
|
||||
vt 0.168274 0.093750
|
||||
vt 0.000000 0.093750
|
||||
vt 1.000000 -0.031250
|
||||
vt 0.831726 -0.031250
|
||||
vt 0.668274 -0.031250
|
||||
vt 0.331726 -0.031250
|
||||
vt 0.168274 -0.031250
|
||||
vt 0.000000 -0.031250
|
||||
# 37 (внеш.)
|
||||
vt 0.000000 -0.031250
|
||||
vt 0.245939 -0.031250
|
||||
vt 0.254061 -0.031250
|
||||
vt 0.745939 -0.031250
|
||||
vt 0.754061 -0.031250
|
||||
vt 1.000000 -0.031250
|
||||
vt 0.000000 0.093750
|
||||
vt 0.245939 0.093750
|
||||
vt 0.254061 0.093750
|
||||
vt 0.745939 0.093750
|
||||
vt 0.754061 0.093750
|
||||
vt 1.000000 0.093750
|
||||
# 49 (торец)
|
||||
vt 0.406250 -0.031250
|
||||
vt 0.406250 0.093750
|
||||
vt 0.593750 -0.031250
|
||||
vt 0.593750 0.093750
|
||||
# Нормали
|
||||
# 1
|
||||
vn 1.000000 0.000000 0.000000
|
||||
vn 0.000000 1.000000 0.000000
|
||||
vn 0.000000 0.000000 1.000000
|
||||
vn 0.707107 0.000000 0.707107
|
||||
# 5
|
||||
vn -1.000000 0.000000 0.000000
|
||||
vn 0.000000 -1.000000 0.000000
|
||||
vn 0.000000 0.000000 -1.000000
|
||||
vn -0.707107 0.000000 -0.707107
|
||||
# Грани
|
||||
g Sides1
|
||||
# Часть 1
|
||||
f 5/37/1 6/38/1 14/44/1
|
||||
f 5/37/1 14/44/1 13/43/1
|
||||
f 13/13/2 14/14/2 10/20/2
|
||||
f 13/13/2 10/20/2 9/19/2
|
||||
f 9/25/5 10/26/5 2/32/5
|
||||
f 9/25/5 2/32/5 1/31/5
|
||||
f 1/1/6 2/2/6 6/8/6
|
||||
f 1/1/6 6/8/6 5/7/6
|
||||
# Часть 2
|
||||
f 6/39/4 7/40/4 15/46/4
|
||||
f 6/39/4 15/46/4 14/45/4
|
||||
f 14/15/2 15/16/2 11/22/2
|
||||
f 14/15/2 11/22/2 10/21/2
|
||||
f 10/27/8 11/28/8 3/34/8
|
||||
f 10/27/8 3/34/8 2/33/8
|
||||
f 2/3/6 3/4/6 7/10/6
|
||||
f 2/3/6 7/10/6 6/9/6
|
||||
# Часть 3
|
||||
f 7/41/3 8/42/3 16/48/3
|
||||
f 7/41/3 16/48/3 15/47/3
|
||||
f 15/17/2 16/18/2 12/24/2
|
||||
f 15/17/2 12/24/2 11/23/2
|
||||
f 11/29/7 12/30/7 4/36/7
|
||||
f 11/29/7 4/36/7 3/35/7
|
||||
f 3/5/6 4/6/6 8/12/6
|
||||
f 3/5/6 8/12/6 7/11/6
|
||||
g Ends1
|
||||
f 1/49/3 5/51/3 13/52/3
|
||||
f 1/49/3 13/52/3 9/50/3
|
||||
f 4/49/1 12/50/1 16/52/1
|
||||
f 4/49/1 16/52/1 8/51/1
|
|
@ -0,0 +1,180 @@
|
|||
# Вершины
|
||||
# Провод 1
|
||||
# 1 (ниж. внутр.)
|
||||
v 0.093750 -0.531250 -0.501000
|
||||
v 0.093750 -0.531250 -0.331726
|
||||
v 0.331726 -0.531250 -0.093750
|
||||
v 0.501000 -0.531250 -0.093750
|
||||
# 5 (ниж. наруж.)
|
||||
v -0.093750 -0.531250 -0.501000
|
||||
v -0.093750 -0.531250 -0.254061
|
||||
v 0.254061 -0.531250 0.093750
|
||||
v 0.501000 -0.531250 0.093750
|
||||
# 9 (верх. внутр.)
|
||||
v 0.093750 -0.406250 -0.501000
|
||||
v 0.093750 -0.406250 -0.331726
|
||||
v 0.331726 -0.406250 -0.093750
|
||||
v 0.501000 -0.406250 -0.093750
|
||||
# 13 (верх. наруж.)
|
||||
v -0.093750 -0.406250 -0.501000
|
||||
v -0.093750 -0.406250 -0.254061
|
||||
v 0.254061 -0.406250 0.093750
|
||||
v 0.501000 -0.406250 0.093750
|
||||
# Провод 2
|
||||
# 17 (ниж. внутр.)
|
||||
v -0.093750 -0.531250 0.501000
|
||||
v -0.093750 -0.531250 0.331726
|
||||
v -0.331726 -0.531250 0.093750
|
||||
v -0.501000 -0.531250 0.093750
|
||||
# 21 (ниж. наруж.)
|
||||
v 0.093750 -0.531250 0.501000
|
||||
v 0.093750 -0.531250 0.254061
|
||||
v -0.254061 -0.531250 -0.093750
|
||||
v -0.501000 -0.531250 -0.093750
|
||||
# 25 (верх. внутр.)
|
||||
v -0.093750 -0.406250 0.501000
|
||||
v -0.093750 -0.406250 0.331726
|
||||
v -0.331726 -0.406250 0.093750
|
||||
v -0.501000 -0.406250 0.093750
|
||||
# 29 (верх. наруж.)
|
||||
v 0.093750 -0.406250 0.501000
|
||||
v 0.093750 -0.406250 0.254061
|
||||
v -0.254061 -0.406250 -0.093750
|
||||
v -0.501000 -0.406250 -0.093750
|
||||
# Текстурные координаты
|
||||
# 1 (ниж.)
|
||||
vt 0.000000 0.406250
|
||||
vt 0.168274 0.406250
|
||||
vt 0.331726 0.406250
|
||||
vt 0.668274 0.406250
|
||||
vt 0.831726 0.406250
|
||||
vt 1.000000 0.406250
|
||||
vt 0.000000 0.593750
|
||||
vt 0.245939 0.593750
|
||||
vt 0.254061 0.593750
|
||||
vt 0.745939 0.593750
|
||||
vt 0.754061 0.593750
|
||||
vt 1.000000 0.593750
|
||||
# 13 (верх.)
|
||||
vt 0.000000 0.406250
|
||||
vt 0.245939 0.406250
|
||||
vt 0.254061 0.406250
|
||||
vt 0.745939 0.406250
|
||||
vt 0.754061 0.406250
|
||||
vt 1.000000 0.406250
|
||||
vt 0.000000 0.593750
|
||||
vt 0.168274 0.593750
|
||||
vt 0.331726 0.593750
|
||||
vt 0.668274 0.593750
|
||||
vt 0.831726 0.593750
|
||||
vt 1.000000 0.593750
|
||||
# 25 (внутр.)
|
||||
vt 1.000000 0.093750
|
||||
vt 0.831726 0.093750
|
||||
vt 0.668274 0.093750
|
||||
vt 0.331726 0.093750
|
||||
vt 0.168274 0.093750
|
||||
vt 0.000000 0.093750
|
||||
vt 1.000000 -0.031250
|
||||
vt 0.831726 -0.031250
|
||||
vt 0.668274 -0.031250
|
||||
vt 0.331726 -0.031250
|
||||
vt 0.168274 -0.031250
|
||||
vt 0.000000 -0.031250
|
||||
# 37 (внеш.)
|
||||
vt 0.000000 -0.031250
|
||||
vt 0.245939 -0.031250
|
||||
vt 0.254061 -0.031250
|
||||
vt 0.745939 -0.031250
|
||||
vt 0.754061 -0.031250
|
||||
vt 1.000000 -0.031250
|
||||
vt 0.000000 0.093750
|
||||
vt 0.245939 0.093750
|
||||
vt 0.254061 0.093750
|
||||
vt 0.745939 0.093750
|
||||
vt 0.754061 0.093750
|
||||
vt 1.000000 0.093750
|
||||
# 49 (торец)
|
||||
vt 0.406250 -0.031250
|
||||
vt 0.406250 0.093750
|
||||
vt 0.593750 -0.031250
|
||||
vt 0.593750 0.093750
|
||||
# Нормали
|
||||
# 1
|
||||
vn 1.000000 0.000000 0.000000
|
||||
vn 0.000000 1.000000 0.000000
|
||||
vn 0.000000 0.000000 1.000000
|
||||
vn 0.707107 0.000000 0.707107
|
||||
# 5
|
||||
vn -1.000000 0.000000 0.000000
|
||||
vn 0.000000 -1.000000 0.000000
|
||||
vn 0.000000 0.000000 -1.000000
|
||||
vn -0.707107 0.000000 -0.707107
|
||||
# Грани
|
||||
# Грани
|
||||
g Sides1
|
||||
# Часть 1
|
||||
f 5/37/1 6/38/1 14/44/1
|
||||
f 5/37/1 14/44/1 13/43/1
|
||||
f 13/13/2 14/14/2 10/20/2
|
||||
f 13/13/2 10/20/2 9/19/2
|
||||
f 9/25/5 10/26/5 2/32/5
|
||||
f 9/25/5 2/32/5 1/31/5
|
||||
f 1/1/6 2/2/6 6/8/6
|
||||
f 1/1/6 6/8/6 5/7/6
|
||||
# Часть 2
|
||||
f 6/39/4 7/40/4 15/46/4
|
||||
f 6/39/4 15/46/4 14/45/4
|
||||
f 14/15/2 15/16/2 11/22/2
|
||||
f 14/15/2 11/22/2 10/21/2
|
||||
f 10/27/8 11/28/8 3/34/8
|
||||
f 10/27/8 3/34/8 2/33/8
|
||||
f 2/3/6 3/4/6 7/10/6
|
||||
f 2/3/6 7/10/6 6/9/6
|
||||
# Часть 3
|
||||
f 7/41/3 8/42/3 16/48/3
|
||||
f 7/41/3 16/48/3 15/47/3
|
||||
f 15/17/2 16/18/2 12/24/2
|
||||
f 15/17/2 12/24/2 11/23/2
|
||||
f 11/29/7 12/30/7 4/36/7
|
||||
f 11/29/7 4/36/7 3/35/7
|
||||
f 3/5/6 4/6/6 8/12/6
|
||||
f 3/5/6 8/12/6 7/11/6
|
||||
g Ends1
|
||||
f 1/49/3 5/51/3 13/52/3
|
||||
f 1/49/3 13/52/3 9/50/3
|
||||
f 4/49/1 12/50/1 16/52/1
|
||||
f 4/49/1 16/52/1 8/51/1
|
||||
g Sides2
|
||||
# Часть 1
|
||||
f 21/37/1 22/38/1 30/44/1
|
||||
f 21/37/1 30/44/1 29/43/1
|
||||
f 29/13/2 30/14/2 26/20/2
|
||||
f 29/13/2 26/20/2 25/19/2
|
||||
f 25/25/5 26/26/5 18/32/5
|
||||
f 25/25/5 18/32/5 17/31/5
|
||||
f 17/1/6 18/2/6 22/8/6
|
||||
f 17/1/6 22/8/6 21/7/6
|
||||
# Часть 2
|
||||
f 22/39/4 23/40/4 31/46/4
|
||||
f 22/39/4 31/46/4 30/45/4
|
||||
f 30/15/2 31/16/2 27/22/2
|
||||
f 30/15/2 27/22/2 26/21/2
|
||||
f 26/27/8 27/28/8 19/34/8
|
||||
f 26/27/8 19/34/8 18/33/8
|
||||
f 18/3/6 19/4/6 23/10/6
|
||||
f 18/3/6 23/10/6 22/9/6
|
||||
# Часть 3
|
||||
f 23/41/3 24/42/3 32/48/3
|
||||
f 23/41/3 32/48/3 31/47/3
|
||||
f 31/17/2 32/18/2 28/24/2
|
||||
f 31/17/2 28/24/2 27/23/2
|
||||
f 27/29/7 28/30/7 20/36/7
|
||||
f 27/29/7 20/36/7 19/35/7
|
||||
f 19/5/6 20/6/6 24/12/6
|
||||
f 19/5/6 24/12/6 23/11/6
|
||||
g Ends2
|
||||
f 17/49/3 21/51/3 29/52/3
|
||||
f 17/49/3 29/52/3 25/50/3
|
||||
f 20/49/1 28/50/1 32/52/1
|
||||
f 20/49/1 32/52/1 24/51/1
|
|
@ -88,7 +88,6 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
|
|||
minetest.register_craft({
|
||||
output = "mesecons_extrawires:tjunction_off 3",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"},
|
||||
{"", "mesecons_insulated:insulated_off", ""},
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
mesecons
|
||||
screwdriver?
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 519 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,10 +1,11 @@
|
|||
local plg = {}
|
||||
plg.rules = {}
|
||||
-- per-player formspec positions
|
||||
plg.open_formspecs = {}
|
||||
|
||||
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
|
||||
|
@ -93,16 +94,20 @@ plg.register_nodes({
|
|||
|
||||
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"
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if not minetest.is_player(clicker) then
|
||||
return
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local is = plg.from_formspec_fields(fields)
|
||||
local name = clicker:get_player_name()
|
||||
-- Erase formspecs of old FPGAs
|
||||
meta:set_string("formspec", "")
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
plg.update_formspec(pos, is)
|
||||
plg.open_formspecs[name] = pos
|
||||
local is = lcore.deserialize(meta:get_string("instr"))
|
||||
minetest.show_formspec(name, "mesecons:fpga", plg.to_formspec_string(is, nil))
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
|
@ -116,6 +121,12 @@ plg.register_nodes({
|
|||
},
|
||||
after_dig_node = function(pos, node)
|
||||
mesecon.receptor_off(pos, plg.rules[node.name])
|
||||
for name, open_pos in pairs(plg.open_formspecs) do
|
||||
if vector.equals(pos, open_pos) then
|
||||
minetest.close_formspec(name, "mesecons:fpga")
|
||||
plg.open_formspecs[name] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
|
@ -153,13 +164,12 @@ plg.register_nodes({
|
|||
end
|
||||
|
||||
meta:set_string("instr", lcore.serialize(instr))
|
||||
plg.update_formspec(pos, instr)
|
||||
plg.update_meta(pos, instr)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
plg.to_formspec_string = function(is)
|
||||
plg.to_formspec_string = function(is, err)
|
||||
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?
|
||||
|
@ -180,26 +190,20 @@ plg.to_formspec_string = function(is)
|
|||
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
|
||||
local selected = 0
|
||||
local titles = { " " }
|
||||
for i, data in ipairs(lcore.get_operations()) do
|
||||
titles[i + 1] = data.fs_name
|
||||
if val == data.gate then
|
||||
selected = i + 1
|
||||
end
|
||||
end
|
||||
local mapping = {
|
||||
["and"] = 1,
|
||||
["or"] = 2,
|
||||
["not"] = 3,
|
||||
["xor"] = 4,
|
||||
["nand"] = 5,
|
||||
["buf"] = 6,
|
||||
["xnor"] = 7,
|
||||
}
|
||||
return s .. tostring(1 + mapping[val]) .. "]"
|
||||
return ("dropdown[%f,%f;1.125,0.5;%s;%s;%i]"):format(
|
||||
x, y, name, table.concat(titles, ","), selected)
|
||||
end
|
||||
local s = "size[9,9]"..
|
||||
"label[3.4,-0.15;FPGA gate configuration]"..
|
||||
"button_exit[7,7.5;2,2.5;program;Program]"..
|
||||
"button[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]"..
|
||||
|
@ -225,6 +229,12 @@ plg.to_formspec_string = function(is)
|
|||
y = 1 - 0.25
|
||||
end
|
||||
end
|
||||
if err then
|
||||
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
|
||||
s = s .. 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
|
||||
return s
|
||||
end
|
||||
|
||||
|
@ -239,20 +249,11 @@ plg.from_formspec_fields = function(fields)
|
|||
end
|
||||
end
|
||||
local function read_action(s)
|
||||
if s == nil or s == " " then
|
||||
return nil
|
||||
for i, data in ipairs(lcore.get_operations()) do
|
||||
if data.fs_name == s then
|
||||
return data.gate
|
||||
end
|
||||
end
|
||||
local mapping = {
|
||||
["AND"] = "and",
|
||||
["OR"] = "or",
|
||||
["NOT"] = "not",
|
||||
["XOR"] = "xor",
|
||||
["NAND"] = "nand",
|
||||
["="] = "buf",
|
||||
["XNOR"] = "xnor",
|
||||
}
|
||||
s = s:gsub("^%s*", "") -- remove leading spaces
|
||||
return mapping[s]
|
||||
end
|
||||
local is = {}
|
||||
for i = 1, 14 do
|
||||
|
@ -266,12 +267,11 @@ plg.from_formspec_fields = function(fields)
|
|||
return is
|
||||
end
|
||||
|
||||
plg.update_formspec = function(pos, is)
|
||||
plg.update_meta = 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
|
||||
|
@ -280,17 +280,20 @@ plg.update_formspec = function(pos, is)
|
|||
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)
|
||||
|
||||
-- Refresh open formspecs
|
||||
local form = plg.to_formspec_string(is, err)
|
||||
for name, open_pos in pairs(plg.open_formspecs) do
|
||||
if vector.equals(pos, open_pos) then
|
||||
minetest.show_formspec(name, "mesecons:fpga", form)
|
||||
end
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
plg.red_box_around = function(i)
|
||||
|
@ -409,6 +412,38 @@ plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
|
|||
end
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
if formname ~= "mesecons:fpga" or fields.quit then
|
||||
plg.open_formspecs[player_name] = nil -- potential garbage
|
||||
return
|
||||
end
|
||||
if not fields.program then
|
||||
return -- we only care when the user clicks "Program"
|
||||
end
|
||||
local pos = plg.open_formspecs[player_name]
|
||||
if minetest.is_protected(pos, player_name) then
|
||||
minetest.record_protection_violation(pos, player_name)
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local is = plg.from_formspec_fields(fields)
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
local err = plg.update_meta(pos, is)
|
||||
|
||||
if not err then
|
||||
plg.open_formspecs[player_name] = nil
|
||||
-- Close on success
|
||||
minetest.close_formspec(player_name, "mesecons:fpga")
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
plg.open_formspecs[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mesecons_fpga:fpga0000 2",
|
||||
|
|
|
@ -1,5 +1,27 @@
|
|||
|
||||
local lg = {}
|
||||
|
||||
local operations = {
|
||||
-- table index: Index in the formspec dropdown
|
||||
-- gate: Internal name
|
||||
-- short: Serialized form, single character
|
||||
-- fs_name: Display name, padded to 4 characters
|
||||
-- func: Function that applies the operation
|
||||
-- unary: Whether this gate only has one input
|
||||
{ gate = "and", short = "&", fs_name = " AND", func = function(a, b) return a and b end },
|
||||
{ gate = "or", short = "|", fs_name = " OR", func = function(a, b) return a or b end },
|
||||
{ gate = "not", short = "~", fs_name = " NOT", func = function(a, b) return not b end, unary = true },
|
||||
{ gate = "xor", short = "^", fs_name = " XOR", func = function(a, b) return a ~= b end },
|
||||
{ gate = "nand", short = "?", fs_name = "NAND", func = function(a, b) return not (a and b) end },
|
||||
{ gate = "buf", short = "_", fs_name = " =", func = function(a, b) return b end, unary = true },
|
||||
{ gate = "xnor", short = "=", fs_name = "XNOR", func = function(a, b) return a == b end },
|
||||
{ gate = "nor", short = "!", fs_name = " NOR", func = function(a, b) return not (a or b) end },
|
||||
}
|
||||
|
||||
lg.get_operations = function()
|
||||
return operations
|
||||
end
|
||||
|
||||
-- (de)serialize
|
||||
lg.serialize = function(t)
|
||||
local function _op(t)
|
||||
|
@ -11,20 +33,14 @@ lg.serialize = function(t)
|
|||
return tostring(t.n)
|
||||
end
|
||||
end
|
||||
local function _action(s)
|
||||
if s == nil then
|
||||
return " "
|
||||
-- Serialize actions (gates) from eg. "and" to "&"
|
||||
local function _action(action)
|
||||
for i, data in ipairs(operations) do
|
||||
if data.gate == action then
|
||||
return data.short
|
||||
end
|
||||
end
|
||||
local mapping = {
|
||||
["and"] = "&",
|
||||
["or"] = "|",
|
||||
["not"] = "~",
|
||||
["xor"] = "^",
|
||||
["nand"] = "?", --dunno
|
||||
["buf"] = "_",
|
||||
["xnor"] = "=",
|
||||
}
|
||||
return mapping[s]
|
||||
return " "
|
||||
end
|
||||
|
||||
local s = ""
|
||||
|
@ -48,18 +64,14 @@ lg.deserialize = function(s)
|
|||
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]
|
||||
-- Deserialize actions (gates) from eg. "&" to "and"
|
||||
local function _action(action)
|
||||
for i, data in ipairs(operations) do
|
||||
if data.short == action then
|
||||
return data.gate
|
||||
end
|
||||
end
|
||||
-- nil
|
||||
end
|
||||
|
||||
local ret = {}
|
||||
|
@ -109,16 +121,25 @@ lg.validate_single = function(t, i)
|
|||
return false
|
||||
end
|
||||
local elem = t[i]
|
||||
|
||||
local gate_data
|
||||
for j, data in ipairs(operations) do
|
||||
if data.gate == elem.action then
|
||||
gate_data = data
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- 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 not gate_data then
|
||||
return {i = i, msg = "Gate type is required"}
|
||||
elseif gate_data.unary then
|
||||
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then
|
||||
return {i = i, msg = "Second operand (only) and destination required"}
|
||||
return {i = i, msg = "Second operand (only) and destination are required"}
|
||||
end
|
||||
else
|
||||
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
|
||||
return {i = i, msg = "Operands and destination required"}
|
||||
return {i = i, msg = "Operands and destination are required"}
|
||||
end
|
||||
end
|
||||
-- check whether operands/destination are identical
|
||||
|
@ -159,21 +180,12 @@ 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
|
||||
for i, data in ipairs(operations) do
|
||||
if data.gate == s then
|
||||
return data.func(v1, v2)
|
||||
end
|
||||
end
|
||||
return false -- unknown gate
|
||||
end
|
||||
local function _op(t, regs, io_in)
|
||||
if t.type == "reg" then
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
name = mesecons_fpga
|
||||
depends = mesecons
|
||||
optional_depends = screwdriver
|
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 256 B |