mirror of
https://github.com/theFox6/microexpansion.git
synced 2024-11-30 02:43:49 +01:00
351 lines
10 KiB
Lua
351 lines
10 KiB
Lua
-- interface
|
|
-- microexpansion/interface.lua
|
|
|
|
local me = microexpansion
|
|
local pipeworks_enabled = minetest.get_modpath("pipeworks") and true or false
|
|
|
|
-- Interfaces work by walking all connected blocks. We walk machines and inventories.
|
|
-- This explains which nodes are connected.
|
|
-- Missing from technic_plus, the generators, might be nice to be able
|
|
-- to feed them wood when the power is low.
|
|
-- Odd machines like the reactor or the force field aren't supported.
|
|
-- We'd have to figure out what we'd want to do with them.
|
|
local function can_connect(name)
|
|
if me.registered_inventory[name] then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function me.walk_connected(pos)
|
|
local nodes = {}
|
|
local visited = {}
|
|
visited[pos.x] = {}
|
|
visited[pos.x][pos.y] = {}
|
|
visited[pos.x][pos.y][pos.z] = true
|
|
local to_visit = {pos}
|
|
while #to_visit > 0 do
|
|
local pos = table.remove(to_visit)
|
|
local adjacent = {
|
|
{x=pos.x+1, y=pos.y, z=pos.z},
|
|
{x=pos.x-1, y=pos.y, z=pos.z},
|
|
{x=pos.x, y=pos.y+1, z=pos.z},
|
|
{x=pos.x, y=pos.y-1, z=pos.z},
|
|
{x=pos.x, y=pos.y, z=pos.z+1},
|
|
{x=pos.x, y=pos.y, z=pos.z-1},
|
|
}
|
|
for _,apos in pairs(adjacent) do
|
|
if not visited[apos.x] then
|
|
visited[apos.x] = {}
|
|
end
|
|
if not visited[apos.x][apos.y] then
|
|
visited[apos.x][apos.y] = {}
|
|
end
|
|
if visited[apos.x][apos.y][apos.z] ~= true then
|
|
visited[apos.x][apos.y][apos.z] = true
|
|
local napos = minetest.get_node(apos)
|
|
local nn = napos.name
|
|
if can_connect(nn) then
|
|
table.insert(nodes, {pos=apos, name=nn})
|
|
table.insert(to_visit, apos)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return nodes
|
|
end
|
|
|
|
local function chest_formspec(pos)
|
|
local net = me.get_connected_network(pos)
|
|
local list
|
|
list = [[
|
|
list[context;import;0,0.3;9,1]
|
|
list[context;export;0,0.3;9,1]
|
|
list[current_player;main;0,3.5;8,1;]
|
|
list[current_player;main;0,4.73;8,3;8]
|
|
listring[current_name;import]
|
|
listring[current_player;main]
|
|
]]
|
|
|
|
if net and not net:powered() then
|
|
list = "label[3,2;" .. minetest.colorize("red", "No power!") .. "]"
|
|
end
|
|
|
|
local formspec =
|
|
"size[9,7.5]"..
|
|
microexpansion.gui_bg ..
|
|
microexpansion.gui_slots ..
|
|
"label[0,-0.23;ME Interface]" ..
|
|
list
|
|
return formspec
|
|
end
|
|
|
|
local function update(pos,_,ev)
|
|
--me.log("INTERFACE: got event "..((ev and ev.type) or "<null>"), "error")
|
|
if ev.type == "connect" then
|
|
-- net.update_counts()
|
|
elseif ev.type == "disconnect" then
|
|
--
|
|
elseif ev.type == "power" then
|
|
local int_meta = minetest.get_meta(pos)
|
|
int_meta:set_string("formspec", chest_formspec(pos))
|
|
end
|
|
end
|
|
|
|
function me.reload_inventory(name, net, ctrl_inv, int_meta, n, pos, doinventories)
|
|
local func = me.registered_inventory and me.registered_inventory[name]
|
|
if func then
|
|
func(net, ctrl_inv, int_meta, n, pos, doinventories)
|
|
end
|
|
end
|
|
|
|
function me.chest_reload(net, ctrl_inv, int_meta, n, pos, doinventories)
|
|
if not doinventories then return end
|
|
local meta = minetest.get_meta(n.pos)
|
|
local inv = meta:get_inventory()
|
|
for i = 1, inv:get_size("main") do
|
|
local stack = inv:get_stack("main", i)
|
|
if not stack:is_empty() then
|
|
net:create_loan(stack, {pos=n.pos, invname="main", slot=i, ipos=pos}, ctrl_inv, int_meta)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
me.register_inventory("default:chest", me.chest_reload)
|
|
|
|
-- This never rewalks connected machines. To do that add a gui
|
|
-- rewalk and/or remove, replace.
|
|
function me.reload_interface(net, pos, doinventories)
|
|
if not net then return end
|
|
local ctrl_inv = net:get_inventory()
|
|
local int_meta = minetest.get_meta(pos)
|
|
local inv = int_meta:get_inventory()
|
|
local inventories = minetest.deserialize(int_meta:get_string("connected"))
|
|
-- not appropriate
|
|
-- me.send_event(pos, "connect")
|
|
int_meta:set_string("infotext", "chests: "..#inventories)
|
|
if not net.counts then
|
|
net.counts = {}
|
|
end
|
|
if not net.autocrafters then
|
|
net.autocrafters = {}
|
|
end
|
|
if not net.autocrafters_by_pos then
|
|
net.autocrafters_by_pos = {}
|
|
end
|
|
if not net.process then
|
|
net.process = {}
|
|
end
|
|
for _, n in pairs(inventories) do
|
|
local node = minetest.get_node(n.pos)
|
|
local name = node.name
|
|
-- me.log("INT: found a "..name, "error")
|
|
local outputs = me.output_by_typename[me.block_to_typename_map[name]]
|
|
if outputs then
|
|
for _, name in pairs(outputs) do
|
|
if not net.process[name] then
|
|
net.process[name] = {}
|
|
end
|
|
-- me.log("INT: registering "..name.." for the "..node.name, "error")
|
|
net.process[name][n.pos] = pos
|
|
end
|
|
else
|
|
me.reload_inventory(name, net, ctrl_inv, int_meta, n, pos, doinventories)
|
|
end
|
|
end
|
|
-- me.send_event(pos,...
|
|
end
|
|
|
|
-- [me chest] Register node
|
|
me.register_node("interface", {
|
|
description = "ME Interface",
|
|
usedfor = "Interface for ME system",
|
|
tiles = {
|
|
"chest_top",
|
|
"chest_top",
|
|
"chest_side",
|
|
"chest_side",
|
|
"chest_side",
|
|
"chest_side", -- TODO: Maybe customize it?
|
|
},
|
|
recipe = {
|
|
{ 1, {
|
|
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" },
|
|
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" },
|
|
{"default:steel_ingot", "default:chest", "default:steel_ingot" },
|
|
},
|
|
}
|
|
},
|
|
is_ground_content = false,
|
|
groups = { cracky = 1, me_connect = 1, tubedevice = 1, tubedevice_receiver = 1 },
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
me_update = update,
|
|
on_construct = function(pos)
|
|
local int_meta = minetest.get_meta(pos)
|
|
int_meta:set_string("formspec", chest_formspec(pos))
|
|
local inv = int_meta:get_inventory()
|
|
inv:set_size("export", 3)
|
|
inv:set_size("import", 3)
|
|
local inventories = me.walk_connected(pos)
|
|
int_meta:set_string("connected", minetest.serialize(inventories))
|
|
|
|
local net = me.get_connected_network(pos)
|
|
if net == nil then
|
|
int_meta:set_string("infotext", "No Network")
|
|
return
|
|
end
|
|
me.reload_interface(net, pos, true)
|
|
net:update_demand()
|
|
end,
|
|
can_dig = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
return inv:is_empty("import")
|
|
end,
|
|
on_destruct = function(pos)
|
|
local net = me.get_connected_network(pos)
|
|
if net == nil then return end
|
|
local inv = net:get_inventory()
|
|
|
|
local int_meta = minetest.get_meta(pos)
|
|
local inventories = minetest.deserialize(int_meta:get_string("connected"))
|
|
int_meta:set_string("infotext", "")
|
|
|
|
local to_remove = {}
|
|
for _, n in pairs(inventories) do
|
|
local pos = n.pos
|
|
if not to_remove[pos.x] then
|
|
to_remove[pos.x] = {}
|
|
end
|
|
if not to_remove[pos.x][pos.y] then
|
|
to_remove[pos.x][pos.y] = {}
|
|
end
|
|
if not to_remove[pos.x][pos.y][pos.z] then
|
|
to_remove[pos.x][pos.y][pos.z] = true
|
|
end
|
|
end
|
|
|
|
net:update_counts()
|
|
local loan_slot = me.loan.get_size(net, inv)
|
|
local ref
|
|
while loan_slot > 0 do
|
|
local lstack = me.loan.get_stack(net, inv, loan_slot)
|
|
if lstack:is_empty() then
|
|
-- TODO: Don't think this can happen now, update_counts
|
|
-- me.log("interface empty loan at "..loan_slot, "error")
|
|
goto continue
|
|
foobar()
|
|
end
|
|
-- me.log("interface removing loan at "..loan_slot, "error")
|
|
ref = me.network.get_ref(lstack)
|
|
if ref and to_remove[ref.pos.x] and to_remove[ref.pos.x][ref.pos.y] and to_remove[ref.pos.x][ref.pos.y][ref.pos.z] then
|
|
net:remove_loan(ref.pos, inv, lstack, loan_slot, ref)
|
|
end
|
|
::continue::
|
|
loan_slot = loan_slot - 1
|
|
end
|
|
net:update_counts()
|
|
|
|
-- pos is a table and does not have value semantics.
|
|
if net.autocrafters_by_pos then
|
|
for k, v in pairs(net.autocrafters_by_pos) do
|
|
if k.x == pos.x and k.y == pos.y and k.z == pos.z then
|
|
pos = k
|
|
break
|
|
end
|
|
end
|
|
if net.autocrafters_by_pos[pos] then
|
|
for name, apos in pairs(net.autocrafters_by_pos[pos]) do
|
|
-- deindex these upon removal of the interface controlling them
|
|
net.autocrafters_by_pos[pos][name] = nil
|
|
net.autocrafters[name][apos] = nil
|
|
end
|
|
end
|
|
end
|
|
if net.process then
|
|
-- todo: This is a little slow, speed it up? Interface removal is infrequent.
|
|
for _, v in pairs(net.process) do
|
|
for k, ipos in pairs(v) do
|
|
if ipos.x == pos.x and ipos.y == pos.y and ipos.z == pos.z then
|
|
pos = ipos
|
|
break
|
|
end
|
|
end
|
|
end
|
|
for name, v in pairs(net.process) do
|
|
for apos, ipos in pairs(v) do
|
|
if ipos == pos then
|
|
me.log("INTERFACE: killing a mchine for "..name, "error")
|
|
net.process[name][apos] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
net:update_demand()
|
|
end,
|
|
after_destruct = function(pos)
|
|
me.send_event(pos, "disconnect")
|
|
end,
|
|
allow_metadata_inventory_put = function(pos, listname, index, stack)
|
|
return stack:get_count()
|
|
end,
|
|
on_metadata_inventory_put = function(pos, _, _, stack)
|
|
local net = me.get_connected_network(pos)
|
|
if net == nil then
|
|
return
|
|
end
|
|
local ctrl_inv = net:get_inventory()
|
|
end,
|
|
allow_metadata_inventory_take = function(pos,_,_,stack) --args: pos, listname, index, stack, player
|
|
local net = me.get_connected_network(pos)
|
|
return stack:get_count()
|
|
end,
|
|
on_metadata_inventory_take = function(pos, _, _, stack)
|
|
local net = me.get_connected_network(pos)
|
|
if net == nil then
|
|
return
|
|
end
|
|
local ctrl_inv = net:get_inventory()
|
|
end,
|
|
-- tube connection
|
|
tube = {
|
|
can_insert = function(pos, _, stack) --pos, node, stack, direction
|
|
local net = me.get_connected_network(pos)
|
|
local inv = net:get_inventory()
|
|
|
|
local max_slots = inv:get_size("main")
|
|
local max_items = net.capacity_cache
|
|
|
|
local slots, items = 0, 0
|
|
-- Get amount of items in drive
|
|
for i = 1, max_slots do
|
|
local mstack = inv:get_stack("main", i)
|
|
if mstack:get_name() ~= "" then
|
|
slots = slots + 1
|
|
local num = mstack:get_count()
|
|
if num == 0 then num = 1 end
|
|
items = items + num
|
|
end
|
|
end
|
|
items = items + stack:get_count()
|
|
return max_items > items
|
|
end,
|
|
insert_object = function(pos, _, stack)
|
|
local net = me.get_connected_network(pos)
|
|
local leftovers = stack
|
|
if net then
|
|
local inv = net:get_inventory()
|
|
leftovers = me.insert_item(stack, net, inv, "main")
|
|
net:set_storage_space(true)
|
|
end
|
|
return leftovers
|
|
end,
|
|
connect_sides = {left=1, right=1, front=1, back=1, top=1, bottom=1},
|
|
},
|
|
after_place_node = pipeworks_enabled and pipeworks.after_place,
|
|
after_dig_node = pipeworks_enabled and pipeworks.after_dig,
|
|
})
|