mirror of
https://github.com/theFox6/microexpansion.git
synced 2024-11-26 09:03:51 +01:00
Checkpoint.
This commit is contained in:
parent
f5aee436d0
commit
9235b7bad1
134
api.lua
134
api.lua
@ -3,66 +3,66 @@ local BASENAME = "microexpansion"
|
||||
|
||||
-- [function] Register Recipe
|
||||
function microexpansion.register_recipe(output, recipe)
|
||||
-- Check if disabled
|
||||
if recipe.disabled == true then
|
||||
return
|
||||
end
|
||||
-- Check if disabled
|
||||
if recipe.disabled == true then
|
||||
return
|
||||
end
|
||||
|
||||
for _,r in ipairs(recipe) do
|
||||
local def = {
|
||||
for _,r in ipairs(recipe) do
|
||||
local def = {
|
||||
type = type(r[2]) == "string" and r[2] or nil,
|
||||
output = output.." "..(r[1] or 1),
|
||||
recipe = r[3] or r[2]
|
||||
}
|
||||
minetest.register_craft(def)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- [function] Register oredef
|
||||
function microexpansion.register_oredef(ore, defs)
|
||||
-- Check if disabled
|
||||
if defs.disabled == true then
|
||||
return
|
||||
end
|
||||
-- Check if disabled
|
||||
if defs.disabled == true then
|
||||
return
|
||||
end
|
||||
|
||||
for _,d in ipairs(defs) do
|
||||
d.ore = "microexpansion:"..ore
|
||||
for _,d in ipairs(defs) do
|
||||
d.ore = "microexpansion:"..ore
|
||||
minetest.register_ore(d)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- [local function] Choose description colour
|
||||
local function desc_colour(status, desc)
|
||||
if status == "unstable" then
|
||||
return minetest.colorize("orange", desc)
|
||||
elseif status == "no" then
|
||||
return minetest.colorize("red", desc)
|
||||
else
|
||||
return minetest.colorize("white", desc)
|
||||
end
|
||||
if status == "unstable" then
|
||||
return minetest.colorize("orange", desc)
|
||||
elseif status == "no" then
|
||||
return minetest.colorize("red", desc)
|
||||
else
|
||||
return minetest.colorize("white", desc)
|
||||
end
|
||||
end
|
||||
|
||||
-- [function] Register Item
|
||||
function microexpansion.register_item(itemstring, def)
|
||||
-- Check if disabled
|
||||
if def.disabled == true then
|
||||
return
|
||||
end
|
||||
-- Set usedfor
|
||||
if def.usedfor then
|
||||
def.description = def.description .. "\n"..minetest.colorize("grey", def.usedfor)
|
||||
end
|
||||
-- Update inventory image
|
||||
if def.inventory_image then
|
||||
def.inventory_image = BASENAME.."_"..def.inventory_image..".png"
|
||||
else
|
||||
def.inventory_image = BASENAME.."_"..itemstring..".png"
|
||||
end
|
||||
-- Colour description
|
||||
def.description = desc_colour(def.status, def.description)
|
||||
-- Check if disabled
|
||||
if def.disabled == true then
|
||||
return
|
||||
end
|
||||
-- Set usedfor
|
||||
if def.usedfor then
|
||||
def.description = def.description .. "\n"..minetest.colorize("grey", def.usedfor)
|
||||
end
|
||||
-- Update inventory image
|
||||
if def.inventory_image then
|
||||
def.inventory_image = BASENAME.."_"..def.inventory_image..".png"
|
||||
else
|
||||
def.inventory_image = BASENAME.."_"..itemstring..".png"
|
||||
end
|
||||
-- Colour description
|
||||
def.description = desc_colour(def.status, def.description)
|
||||
|
||||
-- Register craftitem
|
||||
minetest.register_craftitem(BASENAME..":"..itemstring, def)
|
||||
-- Register craftitem
|
||||
minetest.register_craftitem(BASENAME..":"..itemstring, def)
|
||||
|
||||
-- if recipe, Register recipe
|
||||
if def.recipe then
|
||||
@ -93,43 +93,43 @@ function microexpansion.register_node(itemstring, def)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Colour description
|
||||
def.description = desc_colour(def.status, def.description)
|
||||
-- Update connect_sides
|
||||
if def.connect_sides == "nobottom" then
|
||||
def.connect_sides = { "top", "front", "left", "back", "right" }
|
||||
elseif def.connect_sides == "machine" then
|
||||
def.connect_sides = { "top", "bottom", "left", "back", "right" }
|
||||
end
|
||||
-- Colour description
|
||||
def.description = desc_colour(def.status, def.description)
|
||||
-- Update connect_sides
|
||||
if def.connect_sides == "nobottom" then
|
||||
def.connect_sides = { "top", "front", "left", "back", "right" }
|
||||
elseif def.connect_sides == "machine" then
|
||||
def.connect_sides = { "top", "bottom", "left", "back", "right" }
|
||||
end
|
||||
|
||||
-- Register node
|
||||
minetest.register_node(BASENAME..":"..itemstring, def)
|
||||
-- Register node
|
||||
minetest.register_node(BASENAME..":"..itemstring, def)
|
||||
|
||||
-- if recipe, Register recipe
|
||||
if def.recipe then
|
||||
microexpansion.register_recipe(BASENAME..":"..itemstring, def.recipe)
|
||||
end
|
||||
-- if recipe, Register recipe
|
||||
if def.recipe then
|
||||
microexpansion.register_recipe(BASENAME..":"..itemstring, def.recipe)
|
||||
end
|
||||
|
||||
-- if oredef, Register oredef
|
||||
if def.oredef then
|
||||
microexpansion.register_oredef(BASENAME..":"..itemstring, def.oredef)
|
||||
end
|
||||
-- if oredef, Register oredef
|
||||
if def.oredef then
|
||||
microexpansion.register_oredef(BASENAME..":"..itemstring, def.oredef)
|
||||
end
|
||||
end
|
||||
|
||||
-- get a node, if nessecary load it
|
||||
-- get a node, if necessary load it
|
||||
function microexpansion.get_node(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if node then return node end
|
||||
local vm = VoxelManip()
|
||||
vm:read_from_map(pos, pos)
|
||||
return minetest.get_node(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if node then return node end
|
||||
local vm = VoxelManip()
|
||||
vm:read_from_map(pos, pos)
|
||||
return minetest.get_node(pos)
|
||||
end
|
||||
|
||||
function microexpansion.update_node(pos,event)
|
||||
local node = microexpansion.get_node(pos)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
local ev = event or {type = "n/a"}
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
local ev = event or {type = "n/a"}
|
||||
if def.me_update then
|
||||
def.me_update(pos,node,ev)
|
||||
end
|
||||
def.me_update(pos,node,ev)
|
||||
end
|
||||
end
|
||||
|
2
mod.conf
2
mod.conf
@ -1,4 +1,4 @@
|
||||
name = microexpansion
|
||||
description = A storage managing solution to get an overview over all your items.
|
||||
depends = default
|
||||
optional_depends = pipeworks
|
||||
optional_depends = pipeworks, drawers, technic_plus
|
||||
|
477
modules/network/autocraft.lua
Normal file
477
modules/network/autocraft.lua
Normal file
@ -0,0 +1,477 @@
|
||||
local me = microexpansion
|
||||
|
||||
local pipeworks_craft_time = 1
|
||||
|
||||
function me.autocraft_next_start(net)
|
||||
if net.pending then
|
||||
-- start subsequent autocrafting jobs sequentially.
|
||||
-- We really only need zero/not zero for build to queue actions or not
|
||||
return net.pending.time[net.pending.max_index]
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function me.start_crafting(pos, step_time)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:set(step_time, 0)
|
||||
end
|
||||
|
||||
local function round(v)
|
||||
return math.floor(v + 0.5)
|
||||
end
|
||||
|
||||
-- technic_plus doesn't export machine speed. We
|
||||
-- use this to know exactly how long a machine will take to process
|
||||
-- anything, after that time, we know it is done and we can grab the
|
||||
-- outputs, no polling. We do this for efficiency.
|
||||
me.speed = {
|
||||
["default:furnace"] = 1,
|
||||
}
|
||||
|
||||
-- Use to wire in how long a machine takes to process something.
|
||||
function me.set_speed(name, speed)
|
||||
me.speed[name] = speed
|
||||
end
|
||||
|
||||
-- Sometimes the poor autocrafter doesn't have infinite input and output room
|
||||
-- for a craft, break large ones up to fit.
|
||||
-- Also machine inputs/outputs don't fit.
|
||||
me.maximums = {
|
||||
}
|
||||
|
||||
-- Allow a maximum craft to be defined to avoid overrunning machine
|
||||
-- inputs and outputs and the autocrafter inputs and output..
|
||||
function me.register_max(name, count)
|
||||
me.maximums[name] = count
|
||||
end
|
||||
|
||||
|
||||
local function build(net, cpos, inv, name, count, stack, sink, time)
|
||||
-- The autocrafters nor the machines can take really large amounts
|
||||
-- of things, help them out.
|
||||
local max = me.maximums[name]
|
||||
if not max then
|
||||
-- If no explicit max, assume this is a pipeworks autocrafter and
|
||||
-- it only has 12 outputs.
|
||||
max = stack:get_stack_max()*12
|
||||
end
|
||||
if max and count > max then
|
||||
local next_time = time
|
||||
local built = true
|
||||
while count > 1 and built do
|
||||
local substack = ItemStack(stack)
|
||||
max = math.min(max, count)
|
||||
substack:set_count(max)
|
||||
local step_time
|
||||
built, step_time = build(net, cpos, inv, name, max, substack, sink, next_time)
|
||||
if not built then
|
||||
-- we are done, can't craft, so stop
|
||||
else
|
||||
next_time = math.max(next_time, next_time + step_time)
|
||||
end
|
||||
count = count - max
|
||||
end
|
||||
local step_time = next_time - time
|
||||
return built, step_time
|
||||
end
|
||||
me.log("BUILD: count is "..count.." and stack size is "..stack:get_count(), "error")
|
||||
local dat = {}
|
||||
local second_output = nil
|
||||
if net.process and net.process[name] then
|
||||
dat.apos, dat.ipos = next(net.process[name])
|
||||
dat.rinv = minetest.get_meta(dat.apos):get_inventory()
|
||||
me.log("INT: looking up output "..name, "error")
|
||||
local inputs = me.find_by_output(name)
|
||||
local machine_name = minetest.get_node(dat.apos).name
|
||||
local typename = me.block_to_typename_map[machine_name]
|
||||
dat.recip = me.get_recipe(typename, inputs)
|
||||
me.log("MACHINE: "..machine_name.." typename is "..typename.." and time is "..tostring(dat.recip.time), "error")
|
||||
dat.recip.input = inputs
|
||||
-- freezer can produce two outputs, we only care about the first.
|
||||
if dat.recip.output[1] then
|
||||
second_output = dat.recip.output[2]
|
||||
dat.recip.output = dat.recip.output[1]
|
||||
end
|
||||
dat.ostack = ItemStack(dat.recip.output)
|
||||
-- me.log("SEE: "..machine_name.." "..minetest.serialize(technic.recipes))
|
||||
local speed = me.speed[machine_name]
|
||||
local craft_count = dat.ostack:get_count()
|
||||
local total = math.ceil(count/craft_count)
|
||||
-- crafting 4 carbon plates misses taking 1 carbin plate on output, make this bigger
|
||||
-- we'll try 1 for now, figure out right formula. 1 looks perfect
|
||||
dat.recip.time = round((total+1)*dat.recip.time/speed)
|
||||
if second_output then
|
||||
second_output = ItemStack(second_output)
|
||||
second_output:set_count(second_output:get_count()*total)
|
||||
end
|
||||
me.log("MACHINE: "..machine_name.." is speed "..speed.." and final time is "..dat.recip.time, "error")
|
||||
elseif net.autocrafters[name] then
|
||||
-- fill all recipe slots, wait, grab all output slots
|
||||
-- "src" "dst" "recipe" "output"
|
||||
dat.apos, dat.ipos = next(net.autocrafters[name])
|
||||
-- TODO: If we set up pipeworks ac, then we remove interface for it and craft
|
||||
-- it goes to ac, and dies here. Flush net.autocrafters for all the
|
||||
-- attached inventories during interface removal.
|
||||
dat.rinv = minetest.get_meta(dat.apos):get_inventory()
|
||||
if dat.rinv == nil then
|
||||
me.log("no inventory", "error")
|
||||
return
|
||||
end
|
||||
dat.ostack = dat.rinv:get_stack("output", 1)
|
||||
if dat.ostack:get_name() ~= name then
|
||||
-- invalidate it
|
||||
net.autocrafters[name][dat.apos] = nil
|
||||
-- me.log("invalidating autocrafter", "error")
|
||||
return
|
||||
end
|
||||
else
|
||||
me.log("can't craft a "..name, "error")
|
||||
return
|
||||
end
|
||||
dat.isink = function(sstack)
|
||||
me.log("TIMER: prep inputs, moving "..sstack:get_count().." "..sstack:get_name(), "error")
|
||||
return dat.rinv:add_item("src", sstack)
|
||||
end
|
||||
local craft_count = dat.ostack:get_count()
|
||||
-- These will be returned to the me system
|
||||
local extra = ItemStack(name)
|
||||
local total = math.ceil(count/craft_count)
|
||||
extra:set_count(total*craft_count - count)
|
||||
me.log("AC: count "..count.." craft_count "..craft_count.." extra "..extra:get_count(), "error");
|
||||
-- we craft a minimum of count, to the multiple of the crafting count
|
||||
count = total
|
||||
me.log("AC: numcount "..count, "error");
|
||||
|
||||
local consume = {}
|
||||
if net.process and net.process[name] then
|
||||
for i = 1, #dat.recip.input do
|
||||
local inp = dat.recip.input[i]
|
||||
me.log("MID: consuming "..inp:get_name().." count: "..count.." inp:getcount: "..inp:get_count(), "error")
|
||||
consume[inp:get_name()] = (consume[inp:get_name()] or 0) + count*inp:get_count()
|
||||
end
|
||||
else
|
||||
for i = 1, 9 do
|
||||
local inp = dat.rinv:get_stack("recipe", i)
|
||||
if inp and not inp:is_empty() then
|
||||
consume[inp:get_name()] = (consume[inp:get_name()] or 0) + count*inp:get_count()
|
||||
end
|
||||
end
|
||||
end
|
||||
local replace = true
|
||||
local next_time = time
|
||||
me.log("PREP: pre count is "..count, "error")
|
||||
-- prepwork
|
||||
me.log("PREP: count is "..count, "error")
|
||||
local prepworkbits = {}
|
||||
local previous_ac_size = inv:get_size("ac")
|
||||
me.log("PREP: ac size at top is "..previous_ac_size, "error")
|
||||
for name, count in pairs(consume) do
|
||||
local istack = ItemStack(name)
|
||||
if count >= math.pow(2,16) then
|
||||
replace = false
|
||||
break
|
||||
end
|
||||
-- Don't consume the last item by autocrafting
|
||||
istack:set_count(count+1)
|
||||
local hasit = inv:contains_item("main", istack)
|
||||
istack:set_count(count)
|
||||
me.log("ac checking "..name, "error")
|
||||
if hasit then
|
||||
me.log("ac grabbing "..name, "error")
|
||||
local grabbed = me.remove_item(net, inv, "main", istack)
|
||||
if grabbed then
|
||||
me.log("ac grabbed "..name, "error")
|
||||
local slot = inv:get_size("ac")+1
|
||||
inv:set_size("ac", slot)
|
||||
inv:set_stack("ac", slot, grabbed)
|
||||
-- and later we do this:
|
||||
prepworkbits[function()
|
||||
me.log("PREP: about to move "..name, "error")
|
||||
local stack = inv:get_stack("ac", slot)
|
||||
me.log("PREP: before move actual content of slot "..slot.." is "..stack:get_count().." "..stack:get_name(), "error")
|
||||
local leftovers = dat.rinv:add_item("src", stack)
|
||||
me.log("PREP: post move into real inventory "..leftovers:get_count().." leftovers", "error")
|
||||
me.log("PREP: did move "..name, "error")
|
||||
inv:set_stack("ac", slot, leftovers)
|
||||
end] = name
|
||||
-- and then something moves the size of ac back to before we started
|
||||
end
|
||||
else
|
||||
-- Try and autocraft it
|
||||
me.log("AC: recursive crafting "..count.." "..istack:get_count(), "error")
|
||||
local built, step_time = build(net, cpos, inv, name, count, istack, dat.isink, time)
|
||||
if built then
|
||||
hasit = true
|
||||
next_time = math.max(next_time, time + step_time)
|
||||
else
|
||||
me.log("can't craft "..istack:get_count().." "..istack:get_name(), "error")
|
||||
end
|
||||
end
|
||||
replace = replace and hasit
|
||||
end
|
||||
local prepwork = function ()
|
||||
-- Do all the little bits of prepwork
|
||||
for func, name in pairs(prepworkbits) do
|
||||
me.log("PREPing: before "..name, "error")
|
||||
func()
|
||||
me.log("PREPing: done "..name, "error")
|
||||
end
|
||||
end
|
||||
-- end of prepwork
|
||||
if not replace then
|
||||
-- If we don't have everything, and can't craft it, we're stuck,
|
||||
-- do as much as we can, then nothing else
|
||||
me.log("missing items", "error")
|
||||
-- Existing items are already loaded.
|
||||
return
|
||||
end
|
||||
local main_action_time = count * pipeworks_craft_time + 1
|
||||
if net.process and net.process[name] then
|
||||
main_action_time = dat.recip.time + 1
|
||||
end
|
||||
local main_action = function()
|
||||
me.log("ACTION: prep for "..stack:get_name(), "error")
|
||||
prepwork()
|
||||
-- and once we are done with all the postponed work, we can reduce "ac"
|
||||
-- lifetimes are more complex than you can imagine.
|
||||
-- We use a simple rule. When all done, there is nothing left. At that point,
|
||||
-- we can put any leftovers back into the main inventory.
|
||||
-- Even this might be too soon, if we have multiple independent crafts going, we
|
||||
-- need the last one.
|
||||
if previous_ac_size == 0 then
|
||||
for i = 1,inv:get_size("ac") do
|
||||
local stack = inv:get_stack("ac", i)
|
||||
if stack:get_count() ~= 0 then
|
||||
me.log("AC: putting "..stack:get_count().." "..stack:get_name().." back into main inventory", "error")
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
if leftovers:get_count() > 0 then
|
||||
-- drop on floor, todo: play sound
|
||||
minetest.add_item(cpos, leftovers)
|
||||
end
|
||||
end
|
||||
end
|
||||
me.log("PREP: ac size is now down to "..previous_ac_size, "error")
|
||||
inv:set_size("ac", previous_ac_size)
|
||||
end
|
||||
me.log("ACTION: main for "..stack:get_name(), "error")
|
||||
local rmeta = minetest.get_meta(dat.apos)
|
||||
|
||||
-- Let's start up the crafter since we loaded it up to run
|
||||
if (net.process and net.process[name]) or rmeta:get_int("enabled") == 1 then
|
||||
local timer = minetest.get_node_timer(dat.apos)
|
||||
if not timer:is_started() then
|
||||
me.log("TIMER: starting ac now for "..stack:get_name(), "error")
|
||||
timer:start(pipeworks_craft_time)
|
||||
end
|
||||
me.log("TIMER: registering timer for "..stack:get_name(), "error")
|
||||
local action_time_step = count * pipeworks_craft_time + 1
|
||||
if net.process and net.process[name] then
|
||||
action_time_step = dat.recip.time + 1
|
||||
end
|
||||
local action = function(net)
|
||||
me.log("ACTION: post craft for "..stack:get_name(), "error")
|
||||
me.log("TIMER: moving "..stack:get_count().." "..stack:get_name(), "error")
|
||||
-- deal with output and replacements
|
||||
local dst_stack = dat.rinv:remove_item("dst", stack)
|
||||
if dst_stack:get_count() ~= stack:get_count() then
|
||||
me.log("wow, missing items that should have been crafted "..stack:get_name(), "error")
|
||||
-- me.log("saw "..dst_stack:get_count().." items instead of "..stack:get_count().." items", "error")
|
||||
end
|
||||
if not dst_stack:is_empty() then
|
||||
me.log("TIMER: inserting "..dst_stack:get_count().." "..dst_stack:get_name(), "error")
|
||||
local leftovers = sink(dst_stack)
|
||||
if leftovers and not leftovers:is_empty() then
|
||||
me.log("autocrafter overflow, backpressuring", "error")
|
||||
-- If any don't fit, back pressure on the crafter, we don't
|
||||
-- mean to do this, and want to chunk the crafting items smaller
|
||||
dat.rinv:add_item("dst", leftovers)
|
||||
end
|
||||
end
|
||||
if not extra:is_empty() then
|
||||
dst_stack = dat.rinv:remove_item("dst", extra)
|
||||
if dst_stack:get_count() ~= extra:get_count() then
|
||||
me.log("wow, missing items that should have been crafted "..stack:get_name(), "error")
|
||||
me.log("saw "..dst_stack:get_count().." items instead of "..extra:get_count().." items", "error")
|
||||
end
|
||||
if not dst_stack:is_empty() then
|
||||
local leftovers = me.insert_item(dst_stack, net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
if leftovers and not leftovers:is_empty() then
|
||||
me.log("autocrafter overflow, backpressuring", "error")
|
||||
-- If any don't fit, back pressure on the crafter, we don't
|
||||
-- mean to do this, and want to chunk the crafting items smaller
|
||||
dat.rinv:add_item("dst", leftovers)
|
||||
end
|
||||
end
|
||||
end
|
||||
if second_output then
|
||||
local second = dat.rinv:remove_item("dst", second_output)
|
||||
if second and not second:is_empty() then
|
||||
local leftovers = sink(second)
|
||||
if leftovers and not leftovers:is_empty() then
|
||||
me.log("autocrafter overflow, backpressuring", "error")
|
||||
-- If any don't fit, back pressure on the crafter, we don't
|
||||
-- mean to do this, and want to chunk the crafting items smaller
|
||||
dat.rinv:add_item("dst", leftovers)
|
||||
end
|
||||
end
|
||||
end
|
||||
me.log("ACTION: done post craft for "..stack:get_name(), "error")
|
||||
end
|
||||
local net,cpos = me.get_connected_network(dat.ipos)
|
||||
me.later(net, cpos, action, next_time + action_time_step)
|
||||
end
|
||||
me.log("ACTION: main done for "..stack:get_name(), "error")
|
||||
end
|
||||
|
||||
local net,cpos = me.get_connected_network(dat.ipos)
|
||||
-- queue main action for later
|
||||
me.log("LATER: main action for "..stack:get_name().." in "..next_time.." seconds", "error")
|
||||
me.later(net, cpos, main_action, next_time)
|
||||
|
||||
-- The step time is the prep time and the main_action_time
|
||||
local step_time = next_time - time + main_action_time
|
||||
return true, step_time
|
||||
end
|
||||
|
||||
-- time is absolute, starting from 0 from the front of a craft or
|
||||
-- non-zero if a previous craft was running.
|
||||
function me.later(net, cpos, action, time)
|
||||
if not net.pending then
|
||||
net.pending = {}
|
||||
net.pending.time = {}
|
||||
end
|
||||
local i = (net.pending.max_index or 0) + 1
|
||||
net.pending.max_index = i
|
||||
net.pending[i] = action
|
||||
net.pending.time[i] = time
|
||||
if not net.pending.index then
|
||||
net.pending.index = 1
|
||||
end
|
||||
if i == 1 then
|
||||
me.log("TIMER: starting timer to fire at "..time.." seconds", "error")
|
||||
me.start_crafting(cpos, time+0.1)
|
||||
else
|
||||
-- me.log("TIMER: did not start timer for later, index "..i.." at time "..time, "error")
|
||||
-- bubble sort the entry back to the right spot
|
||||
while i > 1 do
|
||||
-- me.log("TIME ds: "..i.." "..net.pending.time[i].." "..net.pending.time[i-1], "error")
|
||||
if net.pending.time[i] < net.pending.time[i-1] then
|
||||
-- if out of order, swap. This works as previously the list was sorted
|
||||
local t = net.pending.time[i-1]
|
||||
net.pending.time[i-1] = net.pending.time[i]
|
||||
net.pending.time[i] = t
|
||||
t = net.pending[i-1]
|
||||
net.pending[i-1] = net.pending[i]
|
||||
net.pending[i] = t
|
||||
if i == 2 then
|
||||
me.start_crafting(cpos, net.pending.time[1]+0.1)
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function me.autocraft(autocrafterCache, cpos, net, linv, inv, count)
|
||||
local ostack = linv:get_stack("output", 1)
|
||||
local name = ostack:get_name()
|
||||
me.log("crafting "..name.." "..tostring(count), "error")
|
||||
|
||||
local stack = ItemStack(name)
|
||||
local craft_count = ostack:get_count()
|
||||
me.log("auto: craft_count "..craft_count.." count "..count, "error")
|
||||
-- we craft a minimum of count, to the multiple of the crafting count
|
||||
count = math.ceil(count/craft_count)
|
||||
me.log("auto: count is now "..count, "error")
|
||||
stack:set_count(count*craft_count)
|
||||
me.log("auto: stack size is now "..stack:get_count(), "error")
|
||||
me.log("auto: and build count is "..(count*craft_count), "error")
|
||||
|
||||
-- me.log("autocrafters: "..minetest.serialize(net.autocrafters), "error")
|
||||
|
||||
if not net.process then
|
||||
-- rewalk the interfaces on the network to rebuild the machines.
|
||||
net:reload_network()
|
||||
end
|
||||
if net.autocrafters[name] or net.process[name] then
|
||||
me.log("using pipeworks autocrafter", "error")
|
||||
local sink = function(stack)
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
return leftovers
|
||||
end
|
||||
local start_time = me.autocraft_next_start(net)
|
||||
local built, step_time = build(net, cpos, inv, name, count*craft_count, stack, sink, start_time)
|
||||
if built then
|
||||
me.log("crafting "..stack:get_count().." "..stack:get_name().." in "..step_time.." seconds", "error")
|
||||
else
|
||||
me.log("can't craft "..stack:get_count().." "..stack:get_name(), "error")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
me.log("using microexpansion autocrafter", "error")
|
||||
local consume = {}
|
||||
for i = 1, 9 do
|
||||
local inp = linv:get_stack("recipe", i)
|
||||
if inp and inp:get_name() ~= "" then
|
||||
consume[inp:get_name()] = (consume[inp:get_name()] or 0) + count*inp:get_count()
|
||||
end
|
||||
end
|
||||
local replace = true
|
||||
for name, count in pairs(consume) do
|
||||
local stack = ItemStack(name)
|
||||
if count >= math.pow(2,16) then
|
||||
replace = false
|
||||
break
|
||||
end
|
||||
-- Don't consume the last item by autocrafting
|
||||
stack:set_count(count+1)
|
||||
replace = replace and inv:contains_item("main", stack)
|
||||
end
|
||||
if replace then
|
||||
for name, count in pairs(consume) do
|
||||
local stack = ItemStack(name)
|
||||
stack:set_count(count)
|
||||
me.log("REMOVE: "..count.." "..stack:get_name(), "error")
|
||||
if not inv:contains_item("main", stack) then
|
||||
fixme1()
|
||||
end
|
||||
local ret = me.remove_item(net, inv, "main", stack)
|
||||
if ret:get_count() ~= stack:get_count() then
|
||||
me.log("AUTO: found "..(ret:get_count()).." "..(stack:get_name()).." but wanted "..stack:get_count(), "error")
|
||||
-- fixme2()
|
||||
end
|
||||
end
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
if leftovers:get_count() > 0 then
|
||||
-- Ick, no room, just drop on the floor. Maybe player inventory?
|
||||
minetest.add_item(cpos, leftovers)
|
||||
end
|
||||
net:set_storage_space(true)
|
||||
-- deal with replacements
|
||||
local hash = minetest.hash_node_position(cpos)
|
||||
local craft = autocrafterCache[hash] or me.get_craft(cpos, linv, hash)
|
||||
for i = 1, 9 do
|
||||
if (craft.decremented_input.items[i]:get_count() ~= linv:get_stack("recipe", i):get_count()
|
||||
or craft.decremented_input.items[i]:get_name() ~= linv:get_stack("recipe", i):get_name())
|
||||
and not craft.decremented_input.items[i]:is_empty() then
|
||||
local leftovers = me.insert_item(craft.decremented_input.items[i], net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
if leftovers:get_count() > 0 then
|
||||
-- Ick, no room, just drop on the floor. Maybe player inventory?
|
||||
minetest.add_item(cpos, leftovers)
|
||||
end
|
||||
end
|
||||
if replace then
|
||||
linv:set_stack("output", 1, craft.output.item)
|
||||
else
|
||||
linv:set_list("output", {})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -7,50 +7,50 @@ local network = me.network
|
||||
|
||||
-- [register node] Controller
|
||||
me.register_node("ctrl", {
|
||||
description = "ME Controller",
|
||||
tiles = {
|
||||
"ctrl_sides",
|
||||
"ctrl_bottom",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides"
|
||||
},
|
||||
recipe = {
|
||||
description = "ME Controller",
|
||||
tiles = {
|
||||
"ctrl_sides",
|
||||
"ctrl_bottom",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides",
|
||||
"ctrl_sides"
|
||||
},
|
||||
recipe = {
|
||||
{ 1, {
|
||||
{"default:steel_ingot", "microexpansion:steel_infused_obsidian_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:steel_infused_obsidian_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"},
|
||||
},
|
||||
}
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.375, -0.375, -0.375, 0.375, 0.375, 0.375}, -- Core
|
||||
{0.1875, -0.5, -0.5, 0.5, 0.5, -0.1875}, -- Corner1
|
||||
{-0.5, -0.5, -0.5, -0.1875, 0.5, -0.1875}, -- Corner2
|
||||
{-0.5, -0.5, 0.1875, -0.1875, 0.5, 0.5}, -- Corner3
|
||||
{0.1875, -0.5, 0.1875, 0.5, 0.5, 0.5}, -- Corner4
|
||||
{-0.5, -0.4375, -0.5, 0.5, -0.1875, 0.5}, -- Bottom
|
||||
{-0.5, 0.1875, -0.5, 0.5, 0.5, -0.1875}, -- Top1
|
||||
{0.1875, 0.1875, -0.5, 0.5, 0.5, 0.5}, -- Top2
|
||||
{-0.5, 0.1875, -0.5, -0.1875, 0.5, 0.5}, -- Top3
|
||||
{-0.5, 0.1875, 0.1875, 0.5, 0.5, 0.5}, -- Top4
|
||||
{-0.1875, -0.5, -0.1875, 0.1875, -0.25, 0.1875}, -- Bottom2
|
||||
},
|
||||
},
|
||||
groups = { cracky = 1, me_connect = 1, },
|
||||
connect_sides = "nobottom",
|
||||
me_update = function(pos,_,ev)
|
||||
local cnet = me.get_network(pos)
|
||||
if cnet == nil then
|
||||
microexpansion.log("no network for ctrl at pos "..minetest.pos_to_string(pos),"error")
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.375, -0.375, -0.375, 0.375, 0.375, 0.375}, -- Core
|
||||
{0.1875, -0.5, -0.5, 0.5, 0.5, -0.1875}, -- Corner1
|
||||
{-0.5, -0.5, -0.5, -0.1875, 0.5, -0.1875}, -- Corner2
|
||||
{-0.5, -0.5, 0.1875, -0.1875, 0.5, 0.5}, -- Corner3
|
||||
{0.1875, -0.5, 0.1875, 0.5, 0.5, 0.5}, -- Corner4
|
||||
{-0.5, -0.4375, -0.5, 0.5, -0.1875, 0.5}, -- Bottom
|
||||
{-0.5, 0.1875, -0.5, 0.5, 0.5, -0.1875}, -- Top1
|
||||
{0.1875, 0.1875, -0.5, 0.5, 0.5, 0.5}, -- Top2
|
||||
{-0.5, 0.1875, -0.5, -0.1875, 0.5, 0.5}, -- Top3
|
||||
{-0.5, 0.1875, 0.1875, 0.5, 0.5, 0.5}, -- Top4
|
||||
{-0.1875, -0.5, -0.1875, 0.1875, -0.25, 0.1875}, -- Bottom2
|
||||
},
|
||||
},
|
||||
groups = { cracky = 1, me_connect = 1, },
|
||||
connect_sides = "nobottom",
|
||||
me_update = function(pos,_,ev)
|
||||
local net = me.get_network(pos)
|
||||
if net == nil then
|
||||
me.log("no network for ctrl at pos "..minetest.pos_to_string(pos),"error")
|
||||
return
|
||||
end
|
||||
cnet:update()
|
||||
net:update()
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
@ -60,13 +60,13 @@ me.register_node("ctrl", {
|
||||
|
||||
meta:set_string("infotext", "Network Controller")
|
||||
end,
|
||||
after_place_node = function(pos, player)
|
||||
local name = player:get_player_name()
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", "Network Controller (owned by "..name..")")
|
||||
meta:set_string("owner", name)
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
after_place_node = function(pos, player)
|
||||
local name = player:get_player_name()
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", "Network Controller (owned by "..name..")")
|
||||
meta:set_string("owner", name)
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
local net,idx = me.get_network(pos)
|
||||
--disconnect all those who need the network
|
||||
me.send_event(pos,"disconnect",{net=net})
|
||||
@ -78,61 +78,93 @@ me.register_node("ctrl", {
|
||||
end
|
||||
--disconnect all those that haven't realized the network is gone
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
--disconnect all those that haven't realized the controller was disconnected
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
machine = {
|
||||
type = "controller",
|
||||
},
|
||||
end,
|
||||
machine = {
|
||||
type = "controller",
|
||||
},
|
||||
on_timer = function(pos, elapsed)
|
||||
::top::
|
||||
me.log("TIMER: starting service", "error")
|
||||
local net = me.get_network(pos)
|
||||
if not net then return false end
|
||||
if not net.pending then return false end
|
||||
local i = net.pending.index
|
||||
local action = net.pending[i]
|
||||
-- me.log("TIMER: doing service", "error")
|
||||
if not action then
|
||||
net.pending = nil
|
||||
return false
|
||||
end
|
||||
local prev_time = net.pending.time[i]
|
||||
action(net)
|
||||
net.pending[i] = nil
|
||||
net.pending.time[i] = nil
|
||||
net.pending.index = i + 1
|
||||
if net.pending[i+1] then
|
||||
local next_action_time = net.pending.time[i+1]
|
||||
local step_time = next_action_time - prev_time
|
||||
me.log("TIMER: starting next timer for "..step_time.." seconds", "error")
|
||||
if step_time == 0 then
|
||||
goto top
|
||||
end
|
||||
me.start_crafting(pos, step_time)
|
||||
else
|
||||
-- me.log("TIMER: ending service", "error")
|
||||
net.pending = nil
|
||||
end
|
||||
return false
|
||||
end,
|
||||
})
|
||||
|
||||
-- [register node] Cable
|
||||
me.register_machine("cable", {
|
||||
description = "ME Cable",
|
||||
tiles = {
|
||||
"cable",
|
||||
},
|
||||
recipe = {
|
||||
description = "ME Cable",
|
||||
tiles = {
|
||||
"cable",
|
||||
},
|
||||
recipe = {
|
||||
{ 12, "shapeless", {
|
||||
"microexpansion:steel_infused_obsidian_ingot", "microexpansion:machine_casing"
|
||||
"microexpansion:steel_infused_obsidian_ingot", "microexpansion:machine_casing"
|
||||
},
|
||||
}
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "connected",
|
||||
fixed = {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25},
|
||||
connect_top = {-0.25, -0.25, -0.25, 0.25, 0.5, 0.25}, -- y+
|
||||
connect_bottom = {-0.25, -0.5, -0.25, 0.25, 0.25, 0.25}, -- y-
|
||||
connect_front = {-0.25, -0.25, -0.5, 0.25, 0.25, 0.25}, -- z-
|
||||
connect_back = {-0.25, -0.25, 0.25, 0.25, 0.25, 0.5 }, -- z+
|
||||
connect_left = {-0.5, -0.25, -0.25, 0.25, 0.25, 0.25}, -- x-
|
||||
connect_right = {-0.25, -0.25, -0.25, 0.5, 0.25, 0.25}, -- x+
|
||||
},
|
||||
paramtype = "light",
|
||||
groups = { crumbly = 1, },
|
||||
--TODO: move these functions into the registration
|
||||
on_construct = function(pos)
|
||||
me.send_event(pos,"connect")
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
me_update = function(pos,_,ev)
|
||||
if ev then
|
||||
if ev.type ~= "disconnect" then return end
|
||||
end
|
||||
--maybe this shouldn't be called on every update
|
||||
local meta = minetest.get_meta(pos)
|
||||
if me.get_connected_network(pos) then
|
||||
meta:set_string("infotext", "Network connected")
|
||||
else
|
||||
meta:set_string("infotext", "No Network")
|
||||
end
|
||||
end,
|
||||
machine = {
|
||||
type = "conductor",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "connected",
|
||||
fixed = {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25},
|
||||
connect_top = {-0.25, -0.25, -0.25, 0.25, 0.5, 0.25}, -- y+
|
||||
connect_bottom = {-0.25, -0.5, -0.25, 0.25, 0.25, 0.25}, -- y-
|
||||
connect_front = {-0.25, -0.25, -0.5, 0.25, 0.25, 0.25}, -- z-
|
||||
connect_back = {-0.25, -0.25, 0.25, 0.25, 0.25, 0.5 }, -- z+
|
||||
connect_left = {-0.5, -0.25, -0.25, 0.25, 0.25, 0.25}, -- x-
|
||||
connect_right = {-0.25, -0.25, -0.25, 0.5, 0.25, 0.25}, -- x+
|
||||
},
|
||||
paramtype = "light",
|
||||
groups = { crumbly = 1, },
|
||||
--TODO: move these functions into the registration
|
||||
on_construct = function(pos)
|
||||
me.send_event(pos,"connect")
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
me_update = function(pos,_,ev)
|
||||
if ev then
|
||||
if ev.type ~= "disconnect" then return end
|
||||
end
|
||||
--maybe this shouldn't be called on every update
|
||||
local meta = minetest.get_meta(pos)
|
||||
if me.get_connected_network(pos) then
|
||||
meta:set_string("infotext", "Network connected")
|
||||
else
|
||||
meta:set_string("infotext", "No Network")
|
||||
end
|
||||
end,
|
||||
machine = {
|
||||
type = "conductor",
|
||||
},
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
local me = microexpansion
|
||||
me.networks = {}
|
||||
local networks = me.networks
|
||||
local path = microexpansion.get_module_path("network")
|
||||
local path = me.get_module_path("network")
|
||||
|
||||
--deprecated: use ItemStack(x) instead
|
||||
--[[
|
||||
@ -30,98 +30,397 @@ local function split_stack_values(stack)
|
||||
end
|
||||
--]]
|
||||
|
||||
function me.insert_item(stack, inv, listname)
|
||||
if me.settings.huge_stacks == false then
|
||||
return inv:add_item(listname, stack)
|
||||
end
|
||||
local to_insert = type(stack) == "userdata" and stack or ItemStack(stack)
|
||||
local found = false
|
||||
for i = 0, inv:get_size(listname) do
|
||||
local inside = inv:get_stack(listname, i)
|
||||
if inside:get_name() == to_insert:get_name() and inside:get_wear() == to_insert:get_wear() then
|
||||
if inside:get_meta():equals(to_insert:get_meta()) then
|
||||
local total_count = inside:get_count() + to_insert:get_count()
|
||||
-- bigger item count is not possible, we only have unsigned 16 bit
|
||||
if total_count <= math.pow(2,16) then
|
||||
if not inside:set_count(total_count) then
|
||||
microexpansion.log("adding items to stack in microexpansion network failed","error")
|
||||
print("stack is now " .. inside:to_string())
|
||||
end
|
||||
inv:set_stack(listname, i, inside)
|
||||
found = true
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
return inv:add_item(listname, stack)
|
||||
local annotate_large_stack = function(stack, count)
|
||||
local description = minetest.registered_items[stack:get_name()]
|
||||
if description then
|
||||
-- steel is an alias and won't be found in here, skip it
|
||||
description = description.description
|
||||
--stack:set_count(1)
|
||||
--This screw up everything, autocrafting, item removal and more
|
||||
--stack:get_meta():set_string("description", description.." "..count)
|
||||
stack:get_meta():set_string("description", "")
|
||||
end
|
||||
end
|
||||
|
||||
function me.insert_item(stack, net, inv, listname, bias)
|
||||
if stack == nil then
|
||||
foobar()
|
||||
return ItemStack(), 0
|
||||
end
|
||||
stack = type(stack) == "userdata" and stack or ItemStack(stack)
|
||||
if stack:get_name() == "" then
|
||||
-- foobar() -- TODO: can trip, ignore for now
|
||||
return ItemStack(), 0
|
||||
end
|
||||
local slot
|
||||
assert(net, not stack:is_empty())
|
||||
local found = false
|
||||
if not net.byname then
|
||||
net.byname = {}
|
||||
end
|
||||
if not net.byname[listname] then
|
||||
net.byname[listname] = {}
|
||||
end
|
||||
if not net.byname[listname][stack:get_name()] then
|
||||
net.byname[listname][stack:get_name()] = {}
|
||||
end
|
||||
--if not net.byname[listname][stack:get_name()][stack:get_wear()] then
|
||||
-- net.byname[listname][stack:get_name()][stack:get_wear()] = {}
|
||||
--end
|
||||
local meta = stack:get_meta()
|
||||
-- slot = net.byname[listname][stack:get_name()][stack:get_wear()][meta]
|
||||
-- assert(net, minetest.serialize(meta))
|
||||
::was_empty::
|
||||
slot = net.byname[listname][stack:get_name()][stack:get_wear()]
|
||||
-- me.log("checking "..listname.." slot "..tostring(slot).." has "..stack:get_name().." in it", "error")
|
||||
if not slot then
|
||||
local ret = inv:add_item(listname, stack) -- TODO: fix to use set_stack, careful capacity
|
||||
slot = inv:get_size(listname)
|
||||
-- me.log(listname.." slot "..tostring(slot).." should now have "..stack:get_name().." in it", "error")
|
||||
-- me.log(listname.." slot "..tostring(slot).." has "..inv:get_stack(listname, slot):get_name().." in it", "error")
|
||||
if inv:get_stack(listname, slot):get_name() ~= stack:get_name() then
|
||||
return ret, 0
|
||||
--net:sync_main(inv)
|
||||
-- TODO: infinite loop on full?
|
||||
--goto was_empty
|
||||
end
|
||||
-- net.byname[listname][stack:get_name()][stack:get_wear()][meta] = slot
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = slot
|
||||
-- me.log("byname is "..minetest.serialize(net.byname), "error")
|
||||
if bias then
|
||||
if not net.bias then
|
||||
net.bias = {}
|
||||
end
|
||||
if not net.bias[listname] then
|
||||
net.bias[listname] = {}
|
||||
end
|
||||
if not net.bias[listname][stack:get_name()] then
|
||||
net.bias[listname][stack:get_name()] = 0
|
||||
end
|
||||
net.bias[listname][stack:get_name()] = net.bias[listname][stack:get_name()] + bias
|
||||
me.log("LARGE: init insert_item bias "..bias.." for "..stack:get_name(), "error")
|
||||
local mstack = inv:get_stack(listname, slot)
|
||||
annotate_large_stack(mstack, mstack:get_count()+net.bias[listname][stack:get_name()])
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
end
|
||||
return ret, slot
|
||||
end
|
||||
local mstack = inv:get_stack(listname, slot)
|
||||
-- me.log(listname.." slot "..tostring(slot).." has "..mstack:get_name().." in it", "error")
|
||||
if mstack:is_empty() then
|
||||
-- me.log("adding items to stack in microexpansion network was going to fail, fixing", "error")
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
goto was_empty
|
||||
end
|
||||
-- me.log("init insert_item "..stack:get_name(), "error")
|
||||
-- me.log("init insert_item "..mstack:get_name(), "error")
|
||||
if mstack:get_name() ~= stack:get_name() then
|
||||
-- me.log("adding items to stack in microexpansion network was going to fail, wrong item, fixing", "error")
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
goto was_empty
|
||||
end
|
||||
local mbias = (net.bias and net.bias[listname] and net.bias[listname][stack:get_name()]) or 0
|
||||
local total_count = mstack:get_count() + mbias + stack:get_count() + (bias or 0)
|
||||
-- me.log("insert_item "..mstack:get_name().." "..tostring(total_count), "error")
|
||||
-- bigger item count is not possible, we only have unsigned 16 bit
|
||||
if total_count > math.pow(2,15) then
|
||||
-- We handle overflows by storing the excess stores into a bias number for the slot.
|
||||
-- This give us lua max int (2^48 or so) for the actual count.
|
||||
if not net.bias then
|
||||
net.bias = {}
|
||||
end
|
||||
if not net.bias[listname] then
|
||||
net.bias[listname] = {}
|
||||
end
|
||||
if not net.bias[listname][stack:get_name()] then
|
||||
net.bias[listname][stack:get_name()] = 0
|
||||
end
|
||||
net.bias[listname][stack:get_name()] = total_count - math.pow(2,15)
|
||||
me.log("LARGE: overflow bias "..stack:get_count().." for "..stack:get_name(), "error")
|
||||
total_count = math.pow(2,15)
|
||||
end
|
||||
local addition_real_loaned = total_count - mstack:get_count()
|
||||
mstack:set_count(total_count)
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
-- if there is one or more loans for the item, add stack:get_count()
|
||||
-- + (bias or 0) to them and update those inventories, if they have room
|
||||
local remaining = stack:get_count() + (bias or 0)
|
||||
local loan_slot = net:find_loan(inv, stack)
|
||||
if loan_slot then
|
||||
me.loan.bump_loan(net, inv, loan_slot, remaining, addition_real_loaned)
|
||||
end
|
||||
return ItemStack(), slot
|
||||
end
|
||||
|
||||
function me.add_capacity(ipos, count)
|
||||
local int_meta = minetest.get_meta(ipos)
|
||||
local prev = int_meta:get_int("capacity") or 0
|
||||
int_meta:set_int("capacity", prev + count)
|
||||
end
|
||||
|
||||
function me.remove_item(net, inv, listname, stack)
|
||||
if not stack then return ItemStack() end
|
||||
if stack == "" then return ItemStack() end
|
||||
if type(stack) == string then
|
||||
me.log("REMOVE: converting "..stack, "error")
|
||||
stack = ItemStack(stack)
|
||||
end
|
||||
-- stack = ItemStack(stack):set_count(stack:get_count())
|
||||
-- this can dump...
|
||||
me.log("type is "..type(stack), "error")
|
||||
-- me.log("serial is "..minetest.serialize(stack), "error")
|
||||
if stack:get_count() == 0 then return ItemStack() end
|
||||
me.log("me.remove_item "..listname, "error")
|
||||
me.log("me.remove_item "..listname.." "..stack:get_count().." "..stack:get_name(), "error")
|
||||
-- me.log("me.remove_item "..listname.." "..stack:get_wear(), "error")
|
||||
if listname ~= "main" then
|
||||
foobar()
|
||||
return inv:remove_item(listname, stack)
|
||||
end
|
||||
if not net.byname[listname] or not net.byname[listname][stack:get_name()] then
|
||||
return ItemStack()
|
||||
end
|
||||
local slot = net.byname[listname][stack:get_name()][stack:get_wear()]
|
||||
if not slot then
|
||||
me.log("wanted to remove "..stack:get_name().." from "..listname..", but didn't find anything", "error")
|
||||
return ItemStack()
|
||||
end
|
||||
local mstack = inv:get_stack(listname, slot)
|
||||
me.log("init remove item "..tostring(stack:get_count()).." "..stack:get_name(), "error")
|
||||
if stack:get_name() ~= mstack:get_name()
|
||||
or stack:get_wear() ~= mstack:get_wear()
|
||||
or not stack:get_meta():equals(mstack:get_meta()) then
|
||||
me.log("wanted to remove "..stack:get_name().." from "..listname..", but had "..mstack:get_name().." in slot "..slot, "error")
|
||||
-- foobar()
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
return ItemStack()
|
||||
end
|
||||
local mbias = 0
|
||||
if net.bias and net.bias[listname] then
|
||||
mbias = net.bias[listname][stack:get_name()] or 0
|
||||
end
|
||||
local on_loan = net.counts[stack:get_name()]
|
||||
local remaining = mstack:get_count() + mbias - stack:get_count()
|
||||
me.log("init me.remove_item has "..(on_loan or 0).." on loan and "..remaining.." remaining", "error")
|
||||
if on_loan and remaining < on_loan then
|
||||
me.log("init me.remove_item has "..on_loan.." on loan and "..remaining.." remaining", "error")
|
||||
local loan_slot = net:find_loan(inv, stack)
|
||||
-- find_loan can update main, refetch
|
||||
mstack = inv:get_stack(listname, slot)
|
||||
if not loan_slot then
|
||||
-- someone updated the real inventories, there are no more of these
|
||||
return ItemStack()
|
||||
end
|
||||
local lstack = me.loan.get_stack(net, inv, loan_slot)
|
||||
if lstack:is_empty() then
|
||||
return ItemStack()
|
||||
end
|
||||
local ref = me.network.get_ref(lstack)
|
||||
local real_count = nil
|
||||
if ref.drawer then
|
||||
local c = drawers.drawer_get_content(ref.pos, ref.slot)
|
||||
c.count = math.max(c.count-1,0) -- Poor man's locking
|
||||
local count = math.min(stack:get_count(), c.count)
|
||||
me.log("init removing "..count.." items from drawer", "error")
|
||||
stack:set_count(count)
|
||||
local take = stack
|
||||
drawers.drawer_take_large_item(ref.pos, take)
|
||||
c.count = c.count - count
|
||||
real_count = c.count
|
||||
if real_count > math.pow(2,15) then
|
||||
real_count = math.pow(2,15)
|
||||
end
|
||||
-- me.log("CAPACITY: drawer "..-count, "error")
|
||||
-- me.add_capacity(ref.ipos, -count)
|
||||
else
|
||||
local rinv = minetest.get_meta(ref.pos):get_inventory()
|
||||
local real_stack = rinv:get_stack(ref.invname, ref.slot)
|
||||
local count = math.min(stack:get_count(), real_stack:get_count())
|
||||
me.log("init removing "..count.." items from chest", "error")
|
||||
stack:set_count(count)
|
||||
real_count = real_stack:get_count()-count
|
||||
real_stack:set_count(real_count)
|
||||
rinv:set_stack(ref.invname, ref.slot, real_stack)
|
||||
-- me.log("CAPACITY: chest "..-count, "error")
|
||||
-- me.add_capacity(ref.ipos, -count)
|
||||
end
|
||||
me.log("init now down to "..real_count.." items", "error")
|
||||
local lcount = lstack:get_count() -- it was mc 1 excess 0 lcount 1 rc 1
|
||||
local excess = real_count - lcount -- it was mc 1 excess -1 lcount 2 rc 1
|
||||
me.log("it was "..mstack:get_count().." "..excess.." "..lcount.." "..real_count, "error") -- fails with: 1 -1
|
||||
if real_count == 0 then
|
||||
me.log("init me.remove_item before remove_loan chest", "error")
|
||||
net:remove_loan(ref.pos, inv, lstack, loan_slot, ref)
|
||||
elseif excess ~= 0 then
|
||||
-- update loan and main with new excess
|
||||
lstack:set_count(lcount + excess)
|
||||
me.log("LOAN: me.remove_item loan to "..lstack:get_count(), "error")
|
||||
me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
mstack:set_count(mstack:get_count() + excess)
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
if mstack:is_empty() then
|
||||
me.maybemove(net, inv, listname, slot, stack)
|
||||
end
|
||||
-- TODO: Think this is wrong, only adjust by excess no stack:get_count()
|
||||
--net.counts[lstack:get_name()] = net.counts[lstack:get_name()] - stack:get_count()
|
||||
--me.add_capacity(ref.ipos, -stack:get_count())
|
||||
me.log("CAPACITY: is "..excess, "error")
|
||||
net.counts[lstack:get_name()] = net.counts[lstack:get_name()] + excess
|
||||
me.add_capacity(ref.ipos, excess)
|
||||
end
|
||||
return stack
|
||||
end
|
||||
if remaining > 0 then
|
||||
if remaining > math.pow(2,15) then
|
||||
if not net.bias then
|
||||
net.bias = {}
|
||||
end
|
||||
if not net.bias[listname] then
|
||||
net.bias[listname] = {}
|
||||
end
|
||||
me.log("LARGE: total count "..remaining.." for "..stack:get_name(), "error")
|
||||
annotate_large_stack(mstack, remaining)
|
||||
net.bias[listname][stack:get_name()] = remaining - math.pow(2,15)
|
||||
remaining = math.pow(2,15)
|
||||
end
|
||||
mstack:set_count(remaining)
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
return stack
|
||||
end
|
||||
if remaining < 0 then
|
||||
me.log("init wow, missing "..tostring(-remaining).." "..stack:get_name().." during removal, taking less", "error")
|
||||
-- take fewer
|
||||
stack:set_count(mstack:get_count() + mbias)
|
||||
remaining = 0
|
||||
end
|
||||
mstack:set_count(remaining)
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
me.log("init me.remove_item bottom before", "error")
|
||||
me.maybemove(net, inv, listname, slot, stack)
|
||||
me.log("init me.remove_item bottom after", "error")
|
||||
return stack
|
||||
end
|
||||
|
||||
function me.maybemove(net, inv, listname, slot, stack)
|
||||
if stack == nil then
|
||||
-- me.log("init nil stack", "error")
|
||||
return
|
||||
end
|
||||
if net == nil then
|
||||
-- me.log("init nil net", "error")
|
||||
return
|
||||
end
|
||||
if inv == nil then
|
||||
-- me.log("init nil inv", "error")
|
||||
return
|
||||
end
|
||||
-- me.log("init maybemove "..stack:get_name(), "error")
|
||||
if not net.byname or not net.byname[listname] or not net.byname[listname][stack:get_name()] then
|
||||
me.log("byname on "..listname.." is already nil", "error")
|
||||
else
|
||||
-- slot has been completely removed, deindex it
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
end
|
||||
if net.bias and net.bias[listname] then
|
||||
net.bias[listname][stack:get_name()] = nil
|
||||
end
|
||||
-- Move the last or the second to the last if the last is empty,
|
||||
-- back to the hole left by the removed items
|
||||
local main_size = inv:get_size(listname)
|
||||
-- me.log("CALC main_size"..main_size.." slot "..slot, "error")
|
||||
if slot < main_size and main_size > 1 then
|
||||
local orig_slot = main_size
|
||||
local mstack = inv:get_stack(listname, orig_slot)
|
||||
-- me.log("CALC count "..mstack:get_count().." orig_slot-1 "..orig_slot-1, "error")
|
||||
if mstack:is_empty() and slot < orig_slot-1 and orig_slot-1 > 1 then
|
||||
orig_slot = orig_slot-1
|
||||
mstack = inv:get_stack(listname, orig_slot)
|
||||
end
|
||||
if not mstack:is_empty() then
|
||||
inv:set_stack(listname, orig_slot, ItemStack())
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
-- [meta]
|
||||
-- me.log("CALC not empty, old "..stack:get_name().." new "..mstack:get_name(), "error")
|
||||
if net.byname and net.byname[listname] and net.byname[listname][stack:get_name()] then
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
end
|
||||
net.byname[listname][mstack:get_name()][mstack:get_wear()] = slot
|
||||
else
|
||||
inv:set_stack(listname, slot, mstack)
|
||||
-- me.log("CALC empty, old "..stack:get_name(), "error")
|
||||
if net.byname and net.byname[listname] and net.byname[listname][stack:get_name()] then
|
||||
net.byname[listname][stack:get_name()][stack:get_wear()] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
inv:set_size(listname, main_size-1)
|
||||
end
|
||||
|
||||
dofile(path.."/loan.lua") -- Loan Management
|
||||
dofile(path.."/network.lua") -- Network Management
|
||||
dofile(path.."/autocraft.lua") -- Autocrafting
|
||||
|
||||
-- generate iterator to find all connected nodes
|
||||
function me.connected_nodes(start_pos,include_ctrl)
|
||||
-- nodes to be checked
|
||||
local open_list = {{pos = start_pos}}
|
||||
-- nodes that were checked
|
||||
local closed_set = {}
|
||||
-- local connected nodes function to reduce table lookups
|
||||
local adjacent_connected_nodes = me.network.adjacent_connected_nodes
|
||||
-- return the generated iterator
|
||||
return function ()
|
||||
-- start looking for next pos
|
||||
local open = false
|
||||
-- pos to be checked
|
||||
local current
|
||||
-- find next unclosed
|
||||
while not open do
|
||||
-- get unchecked pos
|
||||
current = table.remove(open_list)
|
||||
-- none are left
|
||||
if current == nil then return end
|
||||
-- assume it's open
|
||||
open = true
|
||||
-- check the closed positions
|
||||
for _,closed in pairs(closed_set) do
|
||||
-- if current is unclosed
|
||||
if vector.equals(closed,current.pos) then
|
||||
--found one was closed
|
||||
open = false
|
||||
end
|
||||
end
|
||||
end
|
||||
-- get all connected nodes
|
||||
local nodes = adjacent_connected_nodes(current.pos,include_ctrl)
|
||||
-- iterate through them
|
||||
for _,n in pairs(nodes) do
|
||||
-- mark position to be checked
|
||||
table.insert(open_list,n)
|
||||
end
|
||||
-- add this one to the closed set
|
||||
table.insert(closed_set,current.pos)
|
||||
-- return the one to be checked
|
||||
return current.pos,current.name
|
||||
-- nodes to be checked
|
||||
local open_list = {{pos = start_pos}}
|
||||
-- nodes that were checked
|
||||
local closed_set = {}
|
||||
-- local connected nodes function to reduce table lookups
|
||||
local adjacent_connected_nodes = me.network.adjacent_connected_nodes
|
||||
-- return the generated iterator
|
||||
return function ()
|
||||
-- start looking for next pos
|
||||
local open = false
|
||||
-- pos to be checked
|
||||
local current
|
||||
-- find next unclosed
|
||||
while not open do
|
||||
-- get unchecked pos
|
||||
current = table.remove(open_list)
|
||||
-- none are left
|
||||
if current == nil then return end
|
||||
-- assume it's open
|
||||
open = true
|
||||
-- check the closed positions
|
||||
for _,closed in pairs(closed_set) do
|
||||
-- if current is unclosed
|
||||
if vector.equals(closed,current.pos) then
|
||||
--found one was closed
|
||||
open = false
|
||||
end
|
||||
end
|
||||
end
|
||||
-- get all connected nodes
|
||||
local nodes = adjacent_connected_nodes(current.pos,include_ctrl)
|
||||
-- iterate through them
|
||||
for _,n in pairs(nodes) do
|
||||
-- mark position to be checked
|
||||
table.insert(open_list,n)
|
||||
end
|
||||
-- add this one to the closed set
|
||||
table.insert(closed_set,current.pos)
|
||||
-- return the one to be checked
|
||||
return current.pos,current.name
|
||||
end
|
||||
end
|
||||
|
||||
-- get network connected to position
|
||||
function me.get_connected_network(start_pos)
|
||||
for npos,nn in me.connected_nodes(start_pos,true) do
|
||||
if nn == "microexpansion:ctrl" then
|
||||
local network = me.get_network(npos)
|
||||
if network then
|
||||
return network,npos
|
||||
end
|
||||
end
|
||||
end
|
||||
for npos,nn in me.connected_nodes(start_pos,true) do
|
||||
if nn == "microexpansion:ctrl" then
|
||||
local net = me.get_network(npos)
|
||||
if net then
|
||||
return net,npos
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function me.update_connected_machines(start_pos,event,include_start)
|
||||
microexpansion.log("updating connected machines","action")
|
||||
me.log("updating connected machines", "action")
|
||||
local ev = event or {type = "n/a"}
|
||||
local sn = microexpansion.get_node(start_pos)
|
||||
local sn = me.get_node(start_pos)
|
||||
local sd = minetest.registered_nodes[sn.name]
|
||||
local sm = sd.machine or {}
|
||||
ev.origin = {
|
||||
@ -134,7 +433,7 @@ function me.update_connected_machines(start_pos,event,include_start)
|
||||
if include_start or not vector.equals(npos,start_pos) then
|
||||
me.update_node(npos,ev)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function me.send_event(spos,type,data)
|
||||
@ -148,31 +447,31 @@ function me.send_event(spos,type,data)
|
||||
end
|
||||
|
||||
function me.get_network(pos)
|
||||
for i,net in pairs(networks) do
|
||||
if net.controller_pos then
|
||||
if vector.equals(pos, net.controller_pos) then
|
||||
return net,i
|
||||
end
|
||||
end
|
||||
end
|
||||
for i,net in pairs(networks) do
|
||||
if net.controller_pos then
|
||||
if vector.equals(pos, net.controller_pos) then
|
||||
return net,i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dofile(path.."/ctrl.lua") -- Controller/wires
|
||||
|
||||
-- load networks
|
||||
function me.load()
|
||||
local f = io.open(me.worldpath.."/microexpansion_networks", "r")
|
||||
if f then
|
||||
local res = minetest.deserialize(f:read("*all"))
|
||||
f:close()
|
||||
if type(res) == "table" then
|
||||
for _,n in pairs(res) do
|
||||
local net = me.network.new(n)
|
||||
net:load()
|
||||
table.insert(me.networks,net)
|
||||
end
|
||||
end
|
||||
end
|
||||
local f = io.open(me.worldpath.."/microexpansion_networks", "r")
|
||||
if f then
|
||||
local res = minetest.deserialize(f:read("*all"))
|
||||
f:close()
|
||||
if type(res) == "table" then
|
||||
for _,n in pairs(res) do
|
||||
local net = me.network.new(n)
|
||||
net:load()
|
||||
table.insert(me.networks,net)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- load now
|
||||
@ -181,12 +480,17 @@ me.load()
|
||||
-- save networks
|
||||
function me.save()
|
||||
local data = {}
|
||||
for _,v in pairs(me.networks) do
|
||||
table.insert(data,v:serialize())
|
||||
for _,net in pairs(me.networks) do
|
||||
-- We rebuild this data by walking as they contain non-serializable content.
|
||||
-- All other data is serialized and survives.
|
||||
net.autocrafters = nil
|
||||
net.autocrafters_by_pos = nil
|
||||
net.process = nil
|
||||
table.insert(data,net:serialize())
|
||||
end
|
||||
local f = io.open(me.worldpath.."/microexpansion_networks", "w")
|
||||
f:write(minetest.serialize(data))
|
||||
f:close()
|
||||
local f = io.open(me.worldpath.."/microexpansion_networks", "w")
|
||||
f:write(minetest.serialize(data))
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- save on server shutdown
|
||||
|
108
modules/network/loan.lua
Normal file
108
modules/network/loan.lua
Normal file
@ -0,0 +1,108 @@
|
||||
local me = microexpansion
|
||||
local loan = {
|
||||
}
|
||||
me.loan = loan
|
||||
|
||||
function me.loan.get_stack(net, inv, loan_slot)
|
||||
local lstack = inv:get_stack("loan", loan_slot)
|
||||
return lstack
|
||||
end
|
||||
|
||||
function me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
inv:set_stack("loan", loan_slot, lstack)
|
||||
end
|
||||
|
||||
function me.loan.get_size(net, inv)
|
||||
return inv:get_size("loan")
|
||||
end
|
||||
|
||||
function me.loan.set_size(net, inv, size)
|
||||
return inv:set_size("loan", size)
|
||||
end
|
||||
|
||||
function me.loan.bump_loan(net, inv, loan_slot, remaining, addition_real_loaned)
|
||||
local lstack = me.loan.get_stack(net, inv, loan_slot)
|
||||
local ref
|
||||
local real_count
|
||||
if lstack:is_empty() then
|
||||
-- TODO: should never happen, verify and remove
|
||||
return
|
||||
end
|
||||
ref = me.network.get_ref(lstack)
|
||||
real_count = nil
|
||||
local prev_lstack_count = lstack:get_count()
|
||||
if ref.drawer then
|
||||
local stack = ItemStack(lstack)
|
||||
-- the drawer api only allow up to 2^16-1, ask them for a better api, 2^48 max
|
||||
local count = math.pow(2,16)-1
|
||||
-- ensure that lstack:get_count() + spare below is at most 2^16-1
|
||||
count = math.min(count, math.pow(2,16)-1 - lstack:get_count())
|
||||
-- ensure at most 2^16-1 as the stack api doesn't allow more
|
||||
count = math.min(count, remaining)
|
||||
-- if the loan size is already maximal, then we can't update the loan any
|
||||
if count > 0 then
|
||||
stack:set_count(count)
|
||||
|
||||
-- bump up the actual inventory, spare is how many fit
|
||||
local excess = drawers.drawer_insert_object(ref.pos, stack, ref.slot)
|
||||
local spare = count - excess:get_count()
|
||||
|
||||
-- bump loan by spare
|
||||
lstack:set_count(lstack:get_count() + spare)
|
||||
me.log("LOAN: bump_loan to "..lstack:get_count(), "error")
|
||||
me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
net.counts[lstack:get_name()] = net.counts[lstack:get_name()] + spare
|
||||
me.log("COUNT: loan now to "..net.counts[lstack:get_name()].." "..lstack:get_name()..", "..spare.." more", "error")
|
||||
me.log("LOAN: adril "..addition_real_loaned.." loan "..prev_lstack_count.." and adjustment(spare) "..spare, "error")
|
||||
addition_real_loaned = math.min(addition_real_loaned, spare)
|
||||
me.add_capacity(ref.ipos, addition_real_loaned)
|
||||
|
||||
-- reduce remaining by spare
|
||||
remaining = remaining - spare
|
||||
end
|
||||
else
|
||||
local rinv = minetest.get_meta(ref.pos):get_inventory()
|
||||
local real_stack = rinv:get_stack(ref.invname, ref.slot)
|
||||
local max = real_stack:get_stack_max()
|
||||
if real_stack:get_count() < max then
|
||||
local spare = max - real_stack:get_count()
|
||||
spare = math.min(spare, remaining)
|
||||
-- me.log("bumping "..lstack:get_name().." by "..spare, "error")
|
||||
|
||||
-- bump up the actual inventory by spare
|
||||
real_stack:set_count(real_stack:get_count() + spare)
|
||||
rinv:set_stack(ref.invname, ref.slot, real_stack)
|
||||
|
||||
-- bump loan by spare
|
||||
lstack:set_count(lstack:get_count() + spare)
|
||||
-- me.log("bumping "..lstack:get_name().." to "..lstack:get_count(), "error")
|
||||
me.log("LOAN: bump_loan to "..lstack:get_count(), "error")
|
||||
me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
-- me.log("COUNTS: "..minetest.serialize(net.counts), "error")
|
||||
net.counts[lstack:get_name()] = net.counts[lstack:get_name()] + spare
|
||||
me.log("COUNT: bump_loan loan now to "..net.counts[lstack:get_name()].." "..lstack:get_name()..", "..spare.." more", "error")
|
||||
me.log("LOAN: adril "..addition_real_loaned.." loan "..prev_lstack_count.." and adjustment(spare) "..spare, "error")
|
||||
addition_real_loaned = math.min(addition_real_loaned, spare)
|
||||
me.add_capacity(ref.ipos, addition_real_loaned)
|
||||
|
||||
-- reduce remaining by spare
|
||||
remaining = remaining - spare
|
||||
end
|
||||
end
|
||||
-- This code is misguided. We've already added them as real, we can
|
||||
-- only add them to a loan if those items are added to that
|
||||
-- inventory being loaded. This is only possible if there is room.
|
||||
if false and remaining > 0 then
|
||||
if not net.bias then
|
||||
net.bias = {}
|
||||
end
|
||||
if not net.bias["loan"] then
|
||||
net.bias["loan"] = {}
|
||||
end
|
||||
if not net.bias["loan"][loan_slot] then
|
||||
net.bias["loan"][loan_slot] = 0
|
||||
end
|
||||
net.bias["loan"][loan_slot] = net.bias["loan"][loan_slot] + remaining
|
||||
me.log("LARGE: bump_loan bias is "..net.bias["loan"][loan_slot].." "..lstack:get_name()..", "..remaining.." more", "error")
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,7 @@ function microexpansion.int_to_pagenum(int)
|
||||
end
|
||||
|
||||
-- [function] Move items from inv to inv
|
||||
function microexpansion.move_inv(inv1, inv2, max)
|
||||
function microexpansion.move_inv(net, inv1, inv2, max)
|
||||
if max <= 0 then return end
|
||||
local finv, tinv = inv1.inv, inv2.inv
|
||||
local fname, tname = inv1.name, inv2.name
|
||||
@ -66,14 +66,14 @@ function microexpansion.move_inv(inv1, inv2, max)
|
||||
end
|
||||
if tinv and tinv:room_for_item(tname, v) then
|
||||
if huge then
|
||||
microexpansion.insert_item(v, tinv, tname)
|
||||
microexpansion.insert_item(v, net, tinv, tname)
|
||||
finv:remove_item(fname, v)
|
||||
else
|
||||
local leftover = tinv:add_item(tname, v)
|
||||
local leftovers = tinv:add_item(tname, v)
|
||||
finv:remove_item(fname, v)
|
||||
if leftover and not(leftover:is_empty()) then
|
||||
microexpansion.log("leftover items when transferring inventory","warning")
|
||||
finv:add_item(fname, leftover)
|
||||
if leftovers and not leftovers:is_empty() then
|
||||
microexpansion.log("leftover items when transferring inventory", "warning")
|
||||
finv:add_item(fname, leftovers)
|
||||
end
|
||||
end
|
||||
inserted = inserted + v:get_count()
|
||||
|
756
modules/storage/cterminal.lua
Normal file
756
modules/storage/cterminal.lua
Normal file
@ -0,0 +1,756 @@
|
||||
-- crafting terminal
|
||||
-- microexpansion/cterminal.lua
|
||||
|
||||
-- TODO: Bugs, can't craft sticks, oil extract by using the
|
||||
-- output. Does work when updating the recipe. Groups are hanky. We
|
||||
-- only use the last recipe registered. Would be nice to be able to
|
||||
-- cycle trough them. We handle this by merely requiring the user to
|
||||
-- select the input recipe they want.
|
||||
|
||||
-- TODO: Bugs in original, if you remove controller, this wipes all drives
|
||||
-- Spacing sucks.
|
||||
|
||||
-- The search list doesn't update when main updates or when autocrafting updates.
|
||||
|
||||
local autocrafterCache = {} -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second
|
||||
|
||||
local me = microexpansion
|
||||
local pipeworks_enabled = minetest.get_modpath("pipeworks") and true or false
|
||||
|
||||
-- [me chest] Get formspec
|
||||
local function chest_formspec(pos, start_id, listname, page_max, q)
|
||||
local list
|
||||
local page_number = ""
|
||||
local buttons = ""
|
||||
local query = q or ""
|
||||
local net,cpos = me.get_connected_network(pos)
|
||||
|
||||
if cpos then
|
||||
local inv = net:get_inventory()
|
||||
if listname and (inv:get_size(listname) > 0 or net:get_item_capacity() > 0) then
|
||||
local ctrlinvname = net:get_inventory_name()
|
||||
if listname == "main" then
|
||||
list = "list[detached:"..ctrlinvname..";"
|
||||
.. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
else
|
||||
list = "list[context;" .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
end
|
||||
if minetest.get_modpath("i3") then
|
||||
list = list .. [[
|
||||
list[current_player;main;0,8.5;9,4;]
|
||||
]]
|
||||
else
|
||||
list = list .. [[
|
||||
list[current_player;main;0,8.5;8,1;]
|
||||
list[current_player;main;0,9.73;8,3;8]
|
||||
]]
|
||||
end
|
||||
list = list .. [[
|
||||
list[context;recipe;0.22,5.22;3,3;]
|
||||
list[context;output;4,6.22;1,1;]
|
||||
]]
|
||||
list = list .. [[
|
||||
listring[current_player;main]
|
||||
listring[detached:]]..ctrlinvname..[[;main]
|
||||
listring[current_player;main]
|
||||
listring[context;recipe]
|
||||
listring[current_player;main]
|
||||
listring[context;output]
|
||||
listring[current_player;main]
|
||||
]]
|
||||
buttons = [[
|
||||
button[3.56,4.35;1.8,0.9;tochest;To Drive]
|
||||
tooltip[tochest;Move everything from your inventory to the ME network.]
|
||||
button[5.4,4.35;0.8,0.9;prev;<]
|
||||
button[7.25,4.35;0.8,0.9;next;>]
|
||||
tooltip[prev;Previous]
|
||||
tooltip[next;Next]
|
||||
field[0.29,4.6;2.2,1;filter;;]]..query..[[]
|
||||
button[2.1,4.5;0.8,0.5;search;?]
|
||||
button[2.75,4.5;0.8,0.5;clear;X]
|
||||
tooltip[search;Search]
|
||||
tooltip[clear;Reset]
|
||||
field[6,5.42;2,1;autocraft;;1]
|
||||
tooltip[autocraft;Number of items to Craft]
|
||||
]]
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected storage!") .. "]"
|
||||
end
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected network!") .. "]"
|
||||
end
|
||||
if page_max then
|
||||
page_number = "label[6.15,4.5;" .. math.floor((start_id / 32)) + 1 ..
|
||||
"/" .. page_max .."]"
|
||||
end
|
||||
|
||||
return [[
|
||||
size[9,12.5]
|
||||
]]..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
list ..
|
||||
[[
|
||||
label[0,-0.23;ME Crafting Terminal]
|
||||
field_close_on_enter[filter;false]
|
||||
field_close_on_enter[autocraft;false]
|
||||
]]..
|
||||
page_number ..
|
||||
buttons
|
||||
end
|
||||
|
||||
local function update_chest(pos,_,ev)
|
||||
--for now all events matter
|
||||
|
||||
local net = me.get_connected_network(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if net == nil then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
return
|
||||
end
|
||||
local size = net:get_item_capacity()
|
||||
local page_max = me.int_to_pagenum(size) + 1
|
||||
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
end
|
||||
|
||||
-- From pipeworks/autocrafter.lua
|
||||
local function count_index(invlist)
|
||||
local index = {}
|
||||
for _, stack in pairs(invlist) do
|
||||
if not stack:is_empty() then
|
||||
local stack_name = stack:get_name()
|
||||
index[stack_name] = (index[stack_name] or 0) + stack:get_count()
|
||||
end
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
||||
-- From pipeworks/autocrafter.lua
|
||||
function me.get_craft(pos, inventory, hash)
|
||||
local hash = hash or minetest.hash_node_position(pos)
|
||||
local craft = autocrafterCache[hash]
|
||||
if not craft then
|
||||
local recipe = inventory:get_list("recipe")
|
||||
for i = 1, 9 do
|
||||
if recipe[i]:get_count() > 1 then
|
||||
recipe[i] = ItemStack(recipe[i]:get_name())
|
||||
end
|
||||
end
|
||||
local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
|
||||
craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
|
||||
autocrafterCache[hash] = craft
|
||||
end
|
||||
return craft
|
||||
end
|
||||
|
||||
-- From pipeworks/autocrafter.lua
|
||||
-- note, that this function assumes allready being updated to virtual items
|
||||
-- and doesn't handle recipes with stacksizes > 1
|
||||
local function after_recipe_change(pos, inventory)
|
||||
local meta = minetest.get_meta(pos)
|
||||
-- if we emptied the grid, there's no point in keeping it running or cached
|
||||
if inventory:is_empty("recipe") then
|
||||
autocrafterCache[minetest.hash_node_position(pos)] = nil
|
||||
inventory:set_stack("output", 1, "")
|
||||
return
|
||||
end
|
||||
local recipe = inventory:get_list("recipe")
|
||||
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
local craft = autocrafterCache[hash]
|
||||
|
||||
if craft then
|
||||
-- check if it changed
|
||||
local cached_recipe = craft.recipe
|
||||
for i = 1, 9 do
|
||||
if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
|
||||
autocrafterCache[hash] = nil -- invalidate recipe
|
||||
craft = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
craft = craft or me.get_craft(pos, inventory, hash)
|
||||
local output_item = craft.output.item
|
||||
inventory:set_stack("output", 1, output_item)
|
||||
end
|
||||
|
||||
-- From pipeworks/autocrafter.lua
|
||||
-- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
|
||||
-- if minetest supports query by group one day, this might replace them
|
||||
-- with a canonical version instead
|
||||
local function normalize(item_list)
|
||||
for i = 1, #item_list do
|
||||
local name = item_list[i]
|
||||
if not minetest.registered_items[name] then
|
||||
item_list[i] = ""
|
||||
if name == "group:stick" then
|
||||
item_list[i] = "default:stick"
|
||||
elseif name == "group:glass" then
|
||||
item_list[i] = "default:glass"
|
||||
elseif name == "group:wood" then
|
||||
name = "moretrees:oak_planks"
|
||||
if minetest.registered_items[name] then
|
||||
item_list[i] = name
|
||||
else
|
||||
item_list[i] = "default:wood"
|
||||
end
|
||||
elseif name == "group:wood" then
|
||||
item_list[i] = "moretrees:oak_trunk"
|
||||
elseif name == "group:wool" then
|
||||
item_list[i] = "wool:white"
|
||||
elseif name == "group:sand" then
|
||||
item_list[i] = "default:sand"
|
||||
elseif name == "group:stone" then
|
||||
item_list[i] = "default:cobble"
|
||||
elseif name == "group:leaves" then
|
||||
name = "moretrees:sequoia_leaves"
|
||||
if minetest.registered_items[name] then
|
||||
item_list[i] = name
|
||||
else
|
||||
item_list[i] = "default:leaves"
|
||||
end
|
||||
elseif name == "group:coal" then
|
||||
item_list[i] = "default:coal"
|
||||
elseif name == "group:tree" then
|
||||
item_list[i] = "default:tree"
|
||||
end
|
||||
end
|
||||
end
|
||||
return item_list
|
||||
end
|
||||
|
||||
-- 0 to 34
|
||||
function me.uranium_dust(p)
|
||||
return "technic:uranium"..(p == 7 and "" or p).."_dust"
|
||||
end
|
||||
for pa = 0, 34 do
|
||||
-- uranium_dust(pa)
|
||||
-- me.uranium_dust(pa-1).." 2"
|
||||
-- No, this would require a billion uranium to do this. :-(
|
||||
-- Make a uranium centrifuge controller and have it be smart.
|
||||
--me.register_output_by_typename("separating", "")
|
||||
end
|
||||
|
||||
me.output_by_typename = {
|
||||
-- aka me.register_output_by_typename("cooking", "default:stone")
|
||||
["cooking"] = { "default:stone" }
|
||||
}
|
||||
|
||||
-- Used to register what machine types (typename) produce which outputs.
|
||||
-- Used to figure out what machine to use to create the given output.
|
||||
-- If multiple outputs are produced, only use the main output, not the
|
||||
-- incidental output.
|
||||
function me.register_output_by_typename(typename, output)
|
||||
if not me.output_by_typename[typename] then
|
||||
me.output_by_typename[typename] = {}
|
||||
end
|
||||
table.insert(me.output_by_typename[typename], output)
|
||||
end
|
||||
|
||||
|
||||
function me.register_output_to_inputs(output, inputs)
|
||||
me.log("REG: output "..output.." from inputs "..dump(inputs))
|
||||
me.map_output_to_inputs[output] = inputs
|
||||
end
|
||||
|
||||
|
||||
me.map_output_to_inputs = {
|
||||
-- furnace ("cooking")
|
||||
["default:stone"] = { ItemStack("default:cobble") },
|
||||
}
|
||||
|
||||
|
||||
|
||||
function me.find_by_output(name)
|
||||
-- TODO: we'd love to be able to look this stuff up in the recipes.
|
||||
-- technic.recipes["technic:doped_silicon_wafer"].alloy.recipes[4].input[1]
|
||||
return me.map_output_to_inputs[name]
|
||||
end
|
||||
|
||||
function me.register_inventory(name, func)
|
||||
-- me.log("INVENTORY: registering "..name, "error")
|
||||
if not me.registered_inventory then
|
||||
me.registered_inventory = {}
|
||||
end
|
||||
me.registered_inventory[name] = func
|
||||
end
|
||||
|
||||
-- Allow any type of machine process to be registered. For example,
|
||||
-- "alloy" for an alloy furnace for example. These must be done
|
||||
-- before specific me.register_inventory calls, as that one needs to
|
||||
-- override this call.
|
||||
function me.register_typename(name, typename)
|
||||
me.block_to_typename_map[name] = typename
|
||||
me.register_inventory(name, function() end)
|
||||
end
|
||||
|
||||
me.block_to_typename_map = {
|
||||
}
|
||||
|
||||
-- default wiring
|
||||
me.register_typename("default:furnace", "cooking")
|
||||
|
||||
function me.get_recipe(typename, inputs)
|
||||
return technic.get_recipe(typename, inputs)
|
||||
end
|
||||
|
||||
-- TODO: Removing an output when the recipe is empty that is in
|
||||
-- net.autocrafters should not be allowed as the output in that case
|
||||
-- is virtual. It can be removed if rinv:"output" has the item iff
|
||||
-- that item is removed from the autocrafter's output.
|
||||
local function on_output_change(pos, linv, stack)
|
||||
local name = stack:get_name()
|
||||
-- me.log("PROCESS: "..name.." was found0", "error")
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
local has_enough = true
|
||||
local function clear_recipe()
|
||||
local has_enough = true
|
||||
for i = 1, 9 do
|
||||
local prev = linv:get_stack("recipe", i)
|
||||
if prev and prev:get_name() ~= "" and not inv:room_for_item("main", prev) then
|
||||
-- full, no room to remove
|
||||
has_enough = false
|
||||
elseif prev and prev:get_name() ~= "" and me.insert_item(prev, net, inv, "main"):get_count() > 0 then
|
||||
net:set_storage_space(true)
|
||||
-- full, no room to remove
|
||||
-- push into player inventory?
|
||||
-- Don't have to worry about this happening until minetest is fully multithreaded
|
||||
has_enough = false
|
||||
else
|
||||
net:set_storage_space(true)
|
||||
linv:set_stack("recipe", i, ItemStack(""))
|
||||
end
|
||||
end
|
||||
return has_enough
|
||||
end
|
||||
if not net.process then
|
||||
-- rewalk the interfaces on the network to rebuild loans and machines.
|
||||
net:reload_network()
|
||||
end
|
||||
if net and net.process[name] then
|
||||
-- me.log("PROCESS: "..name.." was found1", "error")
|
||||
has_enough = clear_recipe()
|
||||
local pos,ipos = next(net.process[name])
|
||||
if has_enough and pos then
|
||||
-- me.log("PROCESS: "..name.." was found2", "error")
|
||||
local inputs = me.find_by_output(name)
|
||||
-- me.log("PROCESS: inputs are "..dump(inputs), "error")
|
||||
local machine_name = minetest.get_node(pos).name
|
||||
local typename = me.block_to_typename_map[machine_name]
|
||||
local recip = typename and me.get_recipe(typename, inputs)
|
||||
if recip and recip.output then
|
||||
recip.intput = inputs
|
||||
-- me.log("PROCESS: "..name.." was found for "..typename.." on a "..machine_name, "error")
|
||||
-- freezer can produce two outputs, we only care about the first.
|
||||
if recip.output[1] then
|
||||
recip.output = recip.output[1]
|
||||
end
|
||||
stack = ItemStack(recip.output)
|
||||
linv:set_stack("output", 1, stack)
|
||||
-- me.log("PROCESS: and the output is "..minetest.serialize(recip.output), "error")
|
||||
-- me.log("PROCESS: and the output is "..stack:get_name(), "error")
|
||||
else
|
||||
me.log("PROCESS: "..name.." was missing from recipe on a "..machine_name, "error")
|
||||
linv:set_stack("output", 1, ItemStack())
|
||||
end
|
||||
end
|
||||
return 0
|
||||
elseif net and net.autocrafters[name] then
|
||||
has_enough = clear_recipe()
|
||||
if has_enough then
|
||||
local pos,ipos = next(net.autocrafters[name])
|
||||
if pos then
|
||||
local rinv = minetest.get_meta(pos):get_inventory()
|
||||
stack = ItemStack(rinv:get_stack("output", 1))
|
||||
linv:set_stack("output", 1, stack)
|
||||
else
|
||||
-- me.log("pos in autocrafters was missing", "error")
|
||||
linv:set_stack("output", 1, ItemStack())
|
||||
end
|
||||
else
|
||||
linv:set_stack("output", 1, ItemStack())
|
||||
end
|
||||
return 0
|
||||
end
|
||||
local input = minetest.get_craft_recipe(name)
|
||||
if not input.items or input.type ~= "normal" then return 0 end
|
||||
local items, width = normalize(input.items), input.width
|
||||
local item_idx, width_idx = 1, 1
|
||||
for i = 1, 9 do
|
||||
local prev = linv:get_stack("recipe", i)
|
||||
if prev and prev:get_name() ~= "" and not inv:room_for_item("main", prev) then
|
||||
-- full, no room to remove
|
||||
has_enough = false
|
||||
if width_idx <= width then
|
||||
item_idx = item_idx + 1
|
||||
end
|
||||
elseif prev and prev:get_name() ~= "" and me.insert_item(prev, net, inv, "main"):get_count() > 0 then
|
||||
net:set_storage_space(true)
|
||||
-- full, no room to remove
|
||||
-- push into player inventory?
|
||||
-- Don't have to worry about this happening until minetest is fully multithreaded
|
||||
has_enough = false
|
||||
if width_idx <= width then
|
||||
item_idx = item_idx + 1
|
||||
end
|
||||
elseif width_idx <= width then
|
||||
net:set_storage_space(true)
|
||||
if inv:contains_item("main", items[item_idx]) then
|
||||
me.remove_item(net, inv, "main", ItemStack(items[item_idx]))
|
||||
linv:set_stack("recipe", i, items[item_idx])
|
||||
else
|
||||
has_enough = false
|
||||
linv:set_stack("recipe", i, ItemStack(""))
|
||||
end
|
||||
item_idx = item_idx + 1
|
||||
else
|
||||
linv:set_stack("recipe", i, ItemStack(""))
|
||||
end
|
||||
width_idx = (width_idx < 3) and (width_idx + 1) or 1
|
||||
end
|
||||
-- we'll set the output slot in after_recipe_change to the actual result of the new recipe
|
||||
after_recipe_change(pos, linv)
|
||||
return 0
|
||||
end
|
||||
|
||||
-- [me cterminal] Register node
|
||||
me.register_node("cterminal", {
|
||||
description = "ME Crafting Terminal",
|
||||
usedfor = "Can interact with storage cells in ME networks",
|
||||
tiles = {
|
||||
"chest_top",
|
||||
"chest_top",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_front",
|
||||
},
|
||||
recipe = {
|
||||
{ 1, {
|
||||
{"microexpansion:term", "default:chest"},
|
||||
},
|
||||
}
|
||||
},
|
||||
is_ground_content = false,
|
||||
groups = { cracky = 1, me_connect = 1, tubedevice = 1, tubedevice_receiver = 1 },
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
me_update = update_chest,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
meta:set_string("inv_name", "none")
|
||||
meta:set_int("page", 1)
|
||||
|
||||
local own_inv = meta:get_inventory()
|
||||
own_inv:set_size("src", 1)
|
||||
own_inv:set_size("recipe", 3*3)
|
||||
own_inv:set_size("output", 1)
|
||||
|
||||
local net = me.get_connected_network(pos)
|
||||
me.send_event(pos,"connect",{net=net})
|
||||
if net then
|
||||
update_chest(pos)
|
||||
end
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
can_dig = function(pos, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty("recipe")
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
me.log("Allow a move from "..from_list.." to "..to_list, "error")
|
||||
local meta = minetest.get_meta(pos)
|
||||
if to_list == "search" then
|
||||
local net = me.get_connected_network(pos)
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
local inv = net:get_inventory()
|
||||
local stack = linv:get_stack(from_list, from_index)
|
||||
stack:set_count(count)
|
||||
-- local meta = minetest.get_meta(pos)
|
||||
-- meta:set_string("infotext", "allow moving: "..stack:get_name())
|
||||
-- TODO: Check capacity? Test.
|
||||
me.insert_item(stack, net, inv, "main")
|
||||
return count
|
||||
end
|
||||
if to_list == "recipe" and from_list == "search" then
|
||||
local net = me.get_connected_network(pos)
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
local inv = net:get_inventory()
|
||||
local stack = linv:get_stack(from_list, from_index)
|
||||
local meta = minetest.get_meta(pos)
|
||||
count = math.min(count, stack:get_stack_max())
|
||||
stack:set_count(count)
|
||||
me.remove_item(net, inv, "main", stack)
|
||||
return count
|
||||
end
|
||||
if to_list == "output" then
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
local stack = linv:get_stack(from_list, from_index)
|
||||
return on_output_change(pos, linv, stack)
|
||||
end
|
||||
return count
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
-- This is used for removing items from "search", "recipe" and "output".
|
||||
--me.log("Allow a take from "..listname, "error")
|
||||
local count = stack:get_count()
|
||||
if listname == "search" or listname == "recipe" then
|
||||
count = math.min(count, stack:get_stack_max())
|
||||
end
|
||||
--[[if listname == "main" then
|
||||
-- This should be unused, we don't have a local inventory called main.
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
local ret = me.remove_item(net, inv, "main", stack)
|
||||
me.log("REMOVE: after remove count is "..ret:get_count(), "error")
|
||||
return ret:get_count()
|
||||
end
|
||||
]]
|
||||
return count
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
if listname == "output" then
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
return on_output_change(pos, linv, stack)
|
||||
elseif listname == "search" or listname == "main" then
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
-- TODO: Check full inv, should be fixed now, confirm.
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
return stack:get_count() - leftovers:get_count()
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, _, stack)
|
||||
if listname == "recipe" then
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
after_recipe_change(pos, linv)
|
||||
elseif listname == "search" or listname == "main" then
|
||||
-- done above in allow, nothing left to do here
|
||||
elseif listname == output then
|
||||
-- done above
|
||||
else
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
if leftovers:get_count() > 0 then
|
||||
fixme()
|
||||
end
|
||||
net:set_storage_space(true)
|
||||
end
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, listname, index, stack)
|
||||
me.log("A taking of "..stack:get_name().." from "..listname, "error")
|
||||
if listname == "output" then
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
local num_left = linv:get_stack("output", 1):get_count()
|
||||
-- We only need to consume the recipe if there are no more items
|
||||
-- if num_left ~= 0 then return end
|
||||
if num_left > 1 then return end
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
local replace = true
|
||||
-- This assumes that all inputs are only just 1 item, always true?
|
||||
for i = 1, 9 do
|
||||
local inp = linv:get_stack("recipe", i)
|
||||
if inp and inp:get_name() ~= "" then
|
||||
local consume = ItemStack(inp:get_name())
|
||||
replace = replace and (inp:get_count() > 1 or inv:contains_item("main", consume))
|
||||
end
|
||||
end
|
||||
for i = 1, 9 do
|
||||
local inp = linv:get_stack("recipe", i)
|
||||
if inp and inp:get_name() ~= "" then
|
||||
if inp:get_count() == 1 then
|
||||
if inv:contains_item("main", inp) then
|
||||
local r = me.remove_item(net, inv, "main", inp)
|
||||
if r:get_count() ~= 1 then
|
||||
linv:set_stack("recipe", i, ItemStack(""))
|
||||
replace = false
|
||||
end
|
||||
else
|
||||
linv:set_stack("recipe", i, ItemStack(""))
|
||||
replace = false
|
||||
end
|
||||
else
|
||||
local stack_copy = ItemStack(inp)
|
||||
stack_copy:set_count(inp:get_count()-1)
|
||||
linv:set_stack("recipe", i, stack_copy)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- deal with replacements
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
local craft = autocrafterCache[hash] or me.get_craft(pos, linv, hash)
|
||||
for i = 1, 9 do
|
||||
if (craft.decremented_input.items[i]:get_count() ~= linv:get_stack("recipe", i):get_count()
|
||||
or craft.decremented_input.items[i]:get_name() ~= linv:get_stack("recipe", i):get_name())
|
||||
and not craft.decremented_input.items[i]:is_empty() then
|
||||
local leftovers = me.insert_item(craft.decremented_input.items[i], net, inv, "main")
|
||||
if leftovers:get_count() > 0 then
|
||||
-- Ick, no room, just drop on the floor. Maybe player inventory?
|
||||
minetest.add_item(pos, leftovers)
|
||||
end
|
||||
end
|
||||
if replace then
|
||||
linv:set_stack("output", 1, craft.output.item)
|
||||
else
|
||||
linv:set_list("output", {})
|
||||
end
|
||||
end
|
||||
elseif listname == "recipe" then
|
||||
local linv = minetest.get_meta(pos):get_inventory()
|
||||
after_recipe_change(pos, linv)
|
||||
elseif listname ~= "main" then
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
me.remove_item(net, inv, "main", stack)
|
||||
end
|
||||
end,
|
||||
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
me.log("A move from "..from_list.." to "..to_list, "error")
|
||||
if to_list == "recipe" or from_list == "recipe" then
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
after_recipe_change(pos, inv)
|
||||
end
|
||||
end,
|
||||
tube = {
|
||||
can_insert = function(pos, _, stack) --pos, node, stack, direction
|
||||
-- TODO: update to use capacity_cache?
|
||||
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 dstack = inv:get_stack("main", i)
|
||||
if dstack:get_name() ~= "" then
|
||||
slots = slots + 1
|
||||
local num = dstack: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 inv = net:get_inventory()
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
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,
|
||||
on_receive_fields = function(pos, _, fields, sender)
|
||||
local net,cpos = me.get_connected_network(pos)
|
||||
if net then
|
||||
if cpos then
|
||||
me.log("network and ctrl_pos","info")
|
||||
else
|
||||
me.log("network but no ctrl_pos","warning")
|
||||
end
|
||||
else
|
||||
if cpos then
|
||||
me.log("no network but ctrl_pos","warning")
|
||||
else
|
||||
me.log("no network and no ctrl_pos","info")
|
||||
end
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local page = meta:get_int("page")
|
||||
local inv_name = meta:get_string("inv_name")
|
||||
local own_inv = meta:get_inventory()
|
||||
local ctrl_inv
|
||||
if cpos then
|
||||
ctrl_inv = net:get_inventory()
|
||||
else
|
||||
me.log("no network connected","warning")
|
||||
return
|
||||
end
|
||||
local inv
|
||||
if inv_name == "main" then
|
||||
inv = ctrl_inv
|
||||
assert(inv,"no control inv")
|
||||
else
|
||||
inv = own_inv
|
||||
assert(inv,"no own inv")
|
||||
end
|
||||
local page_max = math.floor(inv:get_size(inv_name) / 32) + 1
|
||||
if inv_name == "none" then
|
||||
return
|
||||
end
|
||||
if fields.next then
|
||||
if page + 32 > inv:get_size(inv_name) then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page + 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page + 32, inv_name, page_max))
|
||||
elseif fields.prev then
|
||||
if page - 32 < 1 then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page - 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page - 32, inv_name, page_max))
|
||||
elseif fields.search or fields.key_enter_field == "filter" then
|
||||
own_inv:set_size("search", 0)
|
||||
if fields.filter == "" then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
else
|
||||
local tab = {}
|
||||
for i = 1, ctrl_inv:get_size("main") do
|
||||
local match = ctrl_inv:get_stack("main", i):get_name():find(fields.filter)
|
||||
if match then
|
||||
tab[#tab + 1] = ctrl_inv:get_stack("main", i)
|
||||
end
|
||||
end
|
||||
own_inv:set_list("search", tab)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "search")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "search", page_max, fields.filter))
|
||||
end
|
||||
elseif fields.clear then
|
||||
own_inv:set_size("search", 0)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
elseif fields.tochest then
|
||||
local pinv = minetest.get_inventory({type="player", name=sender:get_player_name()})
|
||||
-- TODO: test and fix, net:set_storage_space(pinv:get_size("main"))
|
||||
local space = net:get_item_capacity()
|
||||
local contents = ctrl_inv:get_list("main") or {}
|
||||
for _,s in pairs(contents) do
|
||||
if not s:is_empty() then
|
||||
space = space - s:get_count()
|
||||
end
|
||||
end
|
||||
me.move_inv(net, { inv=pinv, name="main" }, { inv=ctrl_inv, name="main", huge=true }, space)
|
||||
net:set_storage_space(true)
|
||||
elseif fields.autocraft or fields.key_enter_field == "autocraft" then
|
||||
if fields.autocraft ~= "" and tonumber(fields.autocraft) ~= nil then
|
||||
local count = tonumber(fields.autocraft)
|
||||
fields.autocraft = nil
|
||||
if not own_inv:get_stack("output", 1):is_empty() and count < math.pow(2,16) then
|
||||
me.autocraft(autocrafterCache, pos, net, own_inv, ctrl_inv, count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
42
modules/storage/drawer-api.lua
Normal file
42
modules/storage/drawer-api.lua
Normal file
@ -0,0 +1,42 @@
|
||||
--[[
|
||||
Minetest Mod Storage Drawers - A Mod adding storage drawers
|
||||
|
||||
Copyright (C) 2017-2020 Linus Jahn <lnj@kaidan.im>
|
||||
Copyright (C) 2016 Mango Tango <mtango688@gmail.com>
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
function drawers.drawer_take_large_item(pos, itemstack)
|
||||
local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)]
|
||||
|
||||
if not drawer_visuals then
|
||||
return ItemStack("")
|
||||
end
|
||||
|
||||
for _, visual in pairs(drawer_visuals) do
|
||||
if visual.itemName == itemstack:get_name() then
|
||||
return visual:take_items(itemstack:get_count())
|
||||
end
|
||||
end
|
||||
|
||||
return ItemStack()
|
||||
end
|
39
modules/storage/drawer-interop.lua
Normal file
39
modules/storage/drawer-interop.lua
Normal file
@ -0,0 +1,39 @@
|
||||
-- Interoperability file for drawers support.
|
||||
local me = microexpansion
|
||||
|
||||
me.register_inventory("drawers:wood1", function(net, ctrl_inv, int_meta, n, pos, doinventories)
|
||||
if not doinventories then return end
|
||||
local c = drawers.drawer_get_content(n.pos, "")
|
||||
if c.name ~= "" and c.count > 1 then
|
||||
-- A poor man's locking system will have us never remove the last item from a drawer.
|
||||
c.count = c.count-1
|
||||
local stack = ItemStack(c.name)
|
||||
local bias = nil
|
||||
if c.count > math.pow(2,15) then -- assumes me.settings.huge_stacks == true
|
||||
bias = c.count - math.pow(2,15)
|
||||
c.count = math.pow(2,15)
|
||||
end
|
||||
stack:set_count(c.count)
|
||||
net:create_loan(stack, {pos=n.pos, drawer=true, slot="", ipos=pos}, ctrl_inv, int_meta, bias)
|
||||
end
|
||||
-- local rest = drawers.drawer_insert_object(n.pos, ItemStack("default:stone"), "")
|
||||
-- meta:set_int("count", meta:get_int("count")+1)
|
||||
-- drawers.remove_visuals(n.pos)
|
||||
-- drawers.spawn_visuals(n.pos)
|
||||
end)
|
||||
|
||||
me.register_inventory("drawers:wood2", function(net, ctrl_inv, int_meta, n, pos, doinventories)
|
||||
if not doinventories then return end
|
||||
-- local c = drawers.drawer_get_content(n.pos, "")
|
||||
-- local rest = drawers.drawer_insert_object(n.pos, ItemStack("default:stone"), "")
|
||||
end)
|
||||
|
||||
me.register_inventory("drawers:wood4", function(net, ctrl_inv, int_meta, n, pos, doinventories)
|
||||
if not doinventories then return end
|
||||
-- local c = drawers.drawer_get_content(n.pos, "")
|
||||
-- local rest = drawers.drawer_insert_object(n.pos, ItemStack("default:stone"), "")
|
||||
end)
|
||||
|
||||
me.register_inventory("drawers:controller", function(net, ctrl_inv, int_meta, n, pos)
|
||||
-- inv:add_item("src", ItemStack("default:stone"))
|
||||
end)
|
@ -39,7 +39,7 @@ local function get_drive_controller(pos)
|
||||
for i,d in pairs(netdrives) do
|
||||
if d.dpos then
|
||||
if vector.equals(pos, d.dpos) then
|
||||
return d,i
|
||||
return d,i
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -51,10 +51,10 @@ local function set_drive_controller(dpos,setd,cpos,i)
|
||||
local dt = netdrives[i]
|
||||
if dt then
|
||||
if setd then
|
||||
dt.dpos = dpos
|
||||
dt.dpos = dpos
|
||||
end
|
||||
if cpos ~= nil then
|
||||
dt.cpos = cpos
|
||||
dt.cpos = cpos
|
||||
end
|
||||
else
|
||||
netdrives[i] = {dpos = dpos, cpos = cpos}
|
||||
@ -63,10 +63,10 @@ local function set_drive_controller(dpos,setd,cpos,i)
|
||||
local dt = get_drive_controller(dpos)
|
||||
if dt then
|
||||
if setd then
|
||||
dt.dpos = dpos
|
||||
dt.dpos = dpos
|
||||
end
|
||||
if cpos ~= nil then
|
||||
dt.cpos = cpos
|
||||
dt.cpos = cpos
|
||||
end
|
||||
else
|
||||
table.insert(netdrives,{dpos = dpos, cpos = cpos})
|
||||
@ -75,26 +75,26 @@ local function set_drive_controller(dpos,setd,cpos,i)
|
||||
end
|
||||
|
||||
local function write_to_cell(cell, items, item_count)
|
||||
local size = microexpansion.get_cell_size(cell:get_name())
|
||||
local item_meta = cell:get_meta()
|
||||
--print(dump2(items,"cell_items"))
|
||||
item_meta:set_string("items", minetest.serialize(items))
|
||||
local base_desc = minetest.registered_craftitems[cell:get_name()].microexpansion.base_desc
|
||||
-- Calculate Percentage
|
||||
local percent = math.floor(item_count / size * 100)
|
||||
-- Update description
|
||||
item_meta:set_string("description", base_desc.."\n"..
|
||||
minetest.colorize("grey", tostring(item_count).."/"..tostring(size).." Items ("..tostring(percent).."%)"))
|
||||
return cell
|
||||
local size = microexpansion.get_cell_size(cell:get_name())
|
||||
local item_meta = cell:get_meta()
|
||||
--print(dump2(items,"cell_items"))
|
||||
item_meta:set_string("items", minetest.serialize(items))
|
||||
local base_desc = minetest.registered_craftitems[cell:get_name()].microexpansion.base_desc
|
||||
-- Calculate Percentage
|
||||
local percent = math.floor(item_count / size * 100)
|
||||
-- Update description
|
||||
item_meta:set_string("description", base_desc.."\n"..
|
||||
minetest.colorize("grey", tostring(item_count).."/"..tostring(size).." Items ("..tostring(percent).."%)"))
|
||||
return cell
|
||||
end
|
||||
|
||||
local function write_drive_cells(pos,network)
|
||||
local function write_drive_cells(pos, net)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local own_inv = meta:get_inventory()
|
||||
if network == nil then
|
||||
if net == nil then
|
||||
return false
|
||||
end
|
||||
local ctrl_inv = network:get_inventory()
|
||||
local ctrl_inv = net:get_inventory()
|
||||
local cells = {}
|
||||
for i = 1, own_inv:get_size("main") do
|
||||
local cell = own_inv:get_stack("main", i)
|
||||
@ -111,40 +111,83 @@ local function write_drive_cells(pos,network)
|
||||
local items_in_cell_count = 0
|
||||
local cell_items = {}
|
||||
|
||||
net:update_counts()
|
||||
if not net.counts then
|
||||
net.counts = {}
|
||||
end
|
||||
for i = 1, ctrl_inv:get_size("main") do
|
||||
local stack_inside = ctrl_inv:get_stack("main", i)
|
||||
local item_string = stack_inside:to_string()
|
||||
local stack = ctrl_inv:get_stack("main", i)
|
||||
local item_string = stack:to_string()
|
||||
if item_string ~= "" then
|
||||
item_string = item_string:split(" ")
|
||||
local item_count = stack_inside:get_count()
|
||||
lbias = (net.counts and net.counts[stack:get_name()]) or 0
|
||||
local mbias = (net.bias and net.bias["main"] and net.bias["main"][stack:get_name()]) or 0
|
||||
if mbias > lbias and lbias > 0 then
|
||||
mbias = mbias - lbias
|
||||
lbias = 0
|
||||
net.bias["main"][stack:get_name()] = mbias
|
||||
net.counts[stack:get_name()] = nil
|
||||
elseif lbias > mbias and mbias > 0 then
|
||||
lbias = lbias - mbias
|
||||
mbias = 0
|
||||
net.counts[stack:get_name()] = lbias
|
||||
net.bias["main"][stack:get_name()] = nil
|
||||
elseif mbias == lbias and mbias > 0 then
|
||||
net.bias["main"][stack:get_name()] = nil
|
||||
net.counts[stack:get_name()] = nil
|
||||
end
|
||||
local item_count = stack:get_count() + mbias
|
||||
-- TODO: on_loan includes the >32k bias in it, so, therefore the
|
||||
-- stack:get_count() + mbias should have it in it.
|
||||
local on_loan = net.counts[stack:get_name()] or 0
|
||||
item_count = item_count - on_loan
|
||||
if item_count < 0 then
|
||||
me.log("LOAN: drive "..item_count.." "..stack:get_name().." "..on_loan.." on loan", "error")
|
||||
-- TODO: we need to update the count faster and we need to update counts from actual inventories
|
||||
-- and not allow taking unless there is an actual item there, mostly done now
|
||||
-- TODO: In theory this should be impossible now, but we have
|
||||
-- bugs with cell removal and insert, see wow
|
||||
me.log("wow, free items "..stack:get_name().." during drive write, "..tostring(-item_count).." extra, with a loan of "..on_loan, "error")
|
||||
item_count = 0
|
||||
if mbias > 0 then
|
||||
net.bias["main"][stack:get_name()] = nil
|
||||
end
|
||||
end
|
||||
if item_count > 1 and item_string[2] ~= tostring(item_count) then
|
||||
microexpansion.log("stack count differs from second field of the item string","warning")
|
||||
me.log("stack count differs from second field of the item string","warning")
|
||||
end
|
||||
while item_count ~= 0 and cell_idx ~= nil do
|
||||
--print(("stack to store: %q"):format(table.concat(item_string," ")))
|
||||
if size < items_in_cell_count + item_count then
|
||||
local space = size - items_in_cell_count
|
||||
item_string[2] = tostring(space)
|
||||
table.insert(cell_items,table.concat(item_string," "))
|
||||
items_in_cell_count = items_in_cell_count + space
|
||||
--print(("stack to store: %q"):format(table.concat(item_string," ")))
|
||||
|
||||
own_inv:set_stack("main", cell_idx, write_to_cell(cells[cell_idx],cell_items,items_in_cell_count))
|
||||
cell_idx = next(cells, cell_idx)
|
||||
if cell_idx == nil then
|
||||
--there may be other drives within the network
|
||||
microexpansion.log("too many items to store in drive","info")
|
||||
break
|
||||
end
|
||||
size = microexpansion.get_cell_size(cells[cell_idx]:get_name())
|
||||
items_in_cell_count = 0
|
||||
cell_items = {}
|
||||
item_count = item_count - space
|
||||
else
|
||||
items_in_cell_count = items_in_cell_count + item_count
|
||||
item_string[2] = tostring(item_count)
|
||||
table.insert(cell_items,table.concat(item_string," "))
|
||||
item_count = 0
|
||||
end
|
||||
-- TODO: This should fail if we write 64k items onto a 64k
|
||||
-- drive (or larger). Fix by writting the number first, that's
|
||||
-- the bias and then the name. This requires that no node in
|
||||
-- the storage system starts with a number. Then in read,
|
||||
-- support that.
|
||||
|
||||
if size < items_in_cell_count + item_count then
|
||||
local space = size - items_in_cell_count
|
||||
item_string[2] = tostring(space)
|
||||
table.insert(cell_items,table.concat(item_string," "))
|
||||
items_in_cell_count = items_in_cell_count + space
|
||||
|
||||
own_inv:set_stack("main", cell_idx, write_to_cell(cells[cell_idx],cell_items,items_in_cell_count))
|
||||
cell_idx = next(cells, cell_idx)
|
||||
if cell_idx == nil then
|
||||
--there may be other drives within the network
|
||||
me.log("too many items to store in drive","info")
|
||||
break
|
||||
end
|
||||
size = microexpansion.get_cell_size(cells[cell_idx]:get_name())
|
||||
items_in_cell_count = 0
|
||||
cell_items = {}
|
||||
item_count = item_count - space
|
||||
else
|
||||
items_in_cell_count = items_in_cell_count + item_count
|
||||
item_string[2] = tostring(item_count)
|
||||
table.insert(cell_items,table.concat(item_string," "))
|
||||
item_count = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
if cell_idx == nil then
|
||||
@ -162,6 +205,7 @@ local function write_drive_cells(pos,network)
|
||||
end
|
||||
|
||||
local function take_all(pos,net)
|
||||
-- me.log("take_all", "error")
|
||||
local meta = minetest.get_meta(pos)
|
||||
local own_inv = meta:get_inventory()
|
||||
local ctrl_inv = net:get_inventory()
|
||||
@ -172,21 +216,25 @@ local function take_all(pos,net)
|
||||
if name ~= "" then
|
||||
local its = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
for _,s in pairs(its) do
|
||||
table.insert(items,s)
|
||||
table.insert(items,s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _,ostack in pairs(items) do
|
||||
--this returns 99 (max count) even if it removes more
|
||||
ctrl_inv:remove_item("main", ostack)
|
||||
print(ostack)
|
||||
--ctrl_inv:remove_item("main", ostack)
|
||||
local postack = ItemStack(ostack)
|
||||
-- me.log("drive take_all remove_item "..minetest.serialize(ostack), "error")
|
||||
me.log("DRIVE: take_all remove_item "..tostring(postack:get_count()).." "..postack:get_name(), "error")
|
||||
me.remove_item(net, ctrl_inv, "main", postack)
|
||||
end
|
||||
|
||||
|
||||
net:update()
|
||||
me.send_event(pos,"items")
|
||||
end
|
||||
|
||||
local function add_all(pos,net)
|
||||
-- me.log("add_all", "error")
|
||||
local meta = minetest.get_meta(pos)
|
||||
local own_inv = meta:get_inventory()
|
||||
local ctrl_inv = net:get_inventory()
|
||||
@ -197,23 +245,22 @@ local function add_all(pos,net)
|
||||
if name ~= "" then
|
||||
local its = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
if its then
|
||||
for _,s in pairs(its) do
|
||||
table.insert(items,s)
|
||||
end
|
||||
for _,s in pairs(its) do
|
||||
table.insert(items,s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _,ostack in pairs(items) do
|
||||
me.insert_item(ostack, ctrl_inv, "main")
|
||||
print(ostack)
|
||||
end
|
||||
|
||||
for _,ostack in pairs(items) do
|
||||
me.insert_item(ostack, net, ctrl_inv, "main")
|
||||
end
|
||||
|
||||
net:update()
|
||||
me.send_event(pos,"items",{net = net})
|
||||
end
|
||||
|
||||
function me.disconnect_drive(pos,ncpos)
|
||||
microexpansion.log("disconnecting drive at "..minetest.pos_to_string(pos),"action")
|
||||
me.log("disconnecting drive at "..minetest.pos_to_string(pos),"action")
|
||||
local fc,i = get_drive_controller(pos)
|
||||
if not fc.cpos then
|
||||
return
|
||||
@ -228,7 +275,7 @@ function me.disconnect_drive(pos,ncpos)
|
||||
if fnet then
|
||||
take_all(pos,fnet)
|
||||
else
|
||||
microexpansion.log("drive couldn't take items from its former network","warning")
|
||||
me.log("drive couldn't take items from its former network","warning")
|
||||
end
|
||||
end
|
||||
|
||||
@ -240,141 +287,146 @@ local function update_drive(pos,_,ev)
|
||||
local cnet = ev.net or me.get_connected_network(pos)
|
||||
if cnet then
|
||||
if not fc then
|
||||
microexpansion.log("connecting drive at "..minetest.pos_to_string(pos),"action")
|
||||
me.log("connecting drive at "..minetest.pos_to_string(pos), "action")
|
||||
set_drive_controller(pos,true,cnet.controller_pos,i)
|
||||
add_all(pos,cnet)
|
||||
elseif not fc.cpos then
|
||||
microexpansion.log("connecting drive at "..minetest.pos_to_string(pos),"action")
|
||||
me.log("connecting drive at "..minetest.pos_to_string(pos), "action")
|
||||
set_drive_controller(pos,false,cnet.controller_pos,i)
|
||||
add_all(pos,cnet)
|
||||
elseif not vector.equals(fc.cpos,cnet.controller_pos) then
|
||||
microexpansion.log("reconnecting drive at "..minetest.pos_to_string(pos),"action")
|
||||
me.log("reconnecting drive at "..minetest.pos_to_string(pos), "action")
|
||||
write_drive_cells(pos,me.get_network(fc.cpos))
|
||||
set_drive_controller(pos,false,cnet.controller_pos,i)
|
||||
add_all(pos,cnet)
|
||||
me.disconnect_drive(pos,cnet.controller_pos)
|
||||
else
|
||||
if ev.origin.name == "microexpansion:ctrl" then
|
||||
me.disconnect_drive(pos,false)
|
||||
me.disconnect_drive(pos,false)
|
||||
end
|
||||
end
|
||||
else
|
||||
if fc then
|
||||
if fc.cpos then
|
||||
me.disconnect_drive(pos,false)
|
||||
end
|
||||
elseif fc then
|
||||
if fc.cpos then
|
||||
me.disconnect_drive(pos,false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- [me chest] Register node
|
||||
microexpansion.register_node("drive", {
|
||||
description = "ME Drive",
|
||||
usedfor = "Stores items into ME storage cells",
|
||||
tiles = {
|
||||
"chest_top",
|
||||
"chest_top",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"drive_full",
|
||||
},
|
||||
recipe = {
|
||||
description = "ME Drive",
|
||||
usedfor = "Stores items into ME storage cells",
|
||||
tiles = {
|
||||
"chest_top",
|
||||
"chest_top",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"drive_full",
|
||||
},
|
||||
recipe = {
|
||||
{ 1, {
|
||||
{"default:steel_ingot", "default:chest", "default:steel_ingot" },
|
||||
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" },
|
||||
{"default:steel_ingot", "default:chest", "default:steel_ingot" },
|
||||
{"default:steel_ingot", "default:chest", "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 },
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
me_update = update_drive,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec",
|
||||
"size[9,9.5]"..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
[[
|
||||
label[0,-0.23;ME Drive]
|
||||
list[context;main;0,0.3;8,4]
|
||||
list[current_player;main;0,5.5;8,1;]
|
||||
list[current_player;main;0,6.73;8,3;8]
|
||||
listring[current_name;main]
|
||||
listring[current_player;main]
|
||||
field_close_on_enter[filter;false]
|
||||
]])
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 10)
|
||||
me.send_event(pos,"connect")
|
||||
end,
|
||||
can_dig = function(pos, player)
|
||||
if minetest.is_protected(pos, player) then
|
||||
return false
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty("main")
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
is_ground_content = false,
|
||||
groups = { cracky = 1, me_connect = 1 },
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
me_update = update_drive,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec",
|
||||
"size[9,7.5]"..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
[[
|
||||
label[0,-0.23;ME Drive]
|
||||
list[context;main;0,0.3;5,2]
|
||||
list[current_player;main;0,3.5;8,1;]
|
||||
list[current_player;main;0,4.73;8,3;8]
|
||||
listring[current_name;main]
|
||||
listring[current_player;main]
|
||||
field_close_on_enter[filter;false]
|
||||
]])
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 10)
|
||||
me.send_event(pos,"connect")
|
||||
end,
|
||||
can_dig = function(pos, player)
|
||||
if minetest.is_protected(pos, player) then
|
||||
return false
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty("main")
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
allow_metadata_inventory_put = function(_, _, _, stack)
|
||||
if minetest.is_protected(pos, player) or minetest.get_item_group(stack:get_name(), "microexpansion_cell") == 0 then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, _, _, stack)
|
||||
me.send_event(pos,"item_cap")
|
||||
local network = me.get_connected_network(pos)
|
||||
if network == nil then
|
||||
return
|
||||
end
|
||||
local ctrl_inv = network:get_inventory()
|
||||
local items = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
if items == nil then
|
||||
print("no items")
|
||||
me.send_event(pos,"items",{net=network})
|
||||
return
|
||||
end
|
||||
network:set_storage_space(#items)
|
||||
for _,s in pairs(items) do
|
||||
me.insert_item(s, ctrl_inv, "main")
|
||||
end
|
||||
me.send_event(pos,"items",{net=network})
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos,_,_,stack, player) --args: pos, listname, index, stack, player
|
||||
if minetest.is_protected(pos, player) then
|
||||
return 0
|
||||
end
|
||||
local network = me.get_connected_network(pos)
|
||||
write_drive_cells(pos,network)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, _, _, stack)
|
||||
local network = me.get_connected_network(pos)
|
||||
if network == nil then
|
||||
return
|
||||
end
|
||||
me.send_event(pos,"item_cap",{net=network})
|
||||
local ctrl_inv = network:get_inventory()
|
||||
local items = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
if items == nil then
|
||||
network:update()
|
||||
return
|
||||
end
|
||||
for _,ostack in pairs(items) do
|
||||
--this returns 99 (max count) even if it removes more
|
||||
ctrl_inv:remove_item("main", ostack)
|
||||
end
|
||||
--print(stack:to_string())
|
||||
allow_metadata_inventory_put = function(pos, _, _, stack, player)
|
||||
if minetest.is_protected(pos, player)
|
||||
or minetest.get_item_group(stack:get_name(), "microexpansion_cell") == 0 then
|
||||
return 0
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, _, _, stack)
|
||||
me.send_event(pos,"item_cap")
|
||||
local network = me.get_connected_network(pos)
|
||||
if network == nil then
|
||||
return
|
||||
end
|
||||
local ctrl_inv = network:get_inventory()
|
||||
local items = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
if items == nil then
|
||||
print("no items")
|
||||
me.send_event(pos,"items",{net=network})
|
||||
return
|
||||
end
|
||||
-- network:set_storage_space(#items)
|
||||
for _,stack in pairs(items) do
|
||||
network:set_storage_space(true)
|
||||
me.insert_item(stack, network, ctrl_inv, "main")
|
||||
end
|
||||
network:set_storage_space(true)
|
||||
me.send_event(pos,"items",{net=network})
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos,_,_,stack, player) --args: pos, listname, index, stack, player
|
||||
if minetest.is_protected(pos, player) then
|
||||
return 0
|
||||
end
|
||||
local network = me.get_connected_network(pos)
|
||||
write_drive_cells(pos,network)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, _, _, stack)
|
||||
local network = me.get_connected_network(pos)
|
||||
if network == nil then
|
||||
return
|
||||
end
|
||||
me.send_event(pos,"item_cap",{net=network})
|
||||
local ctrl_inv = network:get_inventory()
|
||||
local items = minetest.deserialize(stack:get_meta():get_string("items"))
|
||||
if items == nil then
|
||||
network:update()
|
||||
return
|
||||
end
|
||||
for _,ostack in pairs(items) do
|
||||
local postack = ItemStack(ostack)
|
||||
-- me.log("drive meta_inv_take remove_item "..tostring(postack:get_count()).." "..postack:get_name(), "error")
|
||||
-- TODO: this was here, but did nothing? me.remove_item(network, ctrl_inv, "main", postack)
|
||||
-- No, this is the main item removal on cell removal from drive
|
||||
me.remove_item(network, ctrl_inv, "main", postack)
|
||||
--this returns 99 (max count) even if it removes more
|
||||
--ctrl_inv:remove_item("main", ostack)
|
||||
end
|
||||
--print(stack:to_string())
|
||||
|
||||
network:update()
|
||||
me.send_event(pos,"items",{net=network})
|
||||
end,
|
||||
me.send_event(pos,"items",{net=network})
|
||||
end,
|
||||
})
|
||||
|
@ -13,3 +13,18 @@ dofile(module_path.."/storage.lua")
|
||||
-- Load machines
|
||||
dofile(module_path.."/drive.lua")
|
||||
dofile(module_path.."/terminal.lua")
|
||||
dofile(module_path.."/cterminal.lua")
|
||||
dofile(module_path.."/interface.lua")
|
||||
local drawers_enabled = minetest.get_modpath("drawers") and true or false
|
||||
if drawers_enabled then
|
||||
dofile(module_path.."/drawer-api.lua") -- Extra Drawer api
|
||||
dofile(module_path.."/drawer-interop.lua")
|
||||
end
|
||||
local technic_enabled = minetest.get_modpath("technic") and true or false
|
||||
if technic_enabled then
|
||||
dofile(module_path.."/technic-interop.lua")
|
||||
end
|
||||
local pipeworks_enabled = minetest.get_modpath("pipeworks") and true or false
|
||||
if pipeworks_enabled then
|
||||
dofile(module_path.."/pipeworks-interop.lua")
|
||||
end
|
||||
|
313
modules/storage/interface.lua
Normal file
313
modules/storage/interface.lua
Normal file
@ -0,0 +1,313 @@
|
||||
-- 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 update(pos,_,ev)
|
||||
if ev.type == "connect" then
|
||||
-- net.update_counts()
|
||||
elseif ev.type == "disconnect" then
|
||||
--
|
||||
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",
|
||||
"size[9,7.5]"..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
[[
|
||||
label[0,-0.23;ME Interface]
|
||||
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]
|
||||
field_close_on_enter[filter;false]
|
||||
]])
|
||||
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)
|
||||
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
|
||||
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,
|
||||
})
|
25
modules/storage/pipeworks-interop.lua
Normal file
25
modules/storage/pipeworks-interop.lua
Normal file
@ -0,0 +1,25 @@
|
||||
-- Interoperability file for pipework support.
|
||||
local me = microexpansion
|
||||
|
||||
me.register_inventory("pipeworks:autocrafter", function(net, ctrl_inv, int_meta, n, pos)
|
||||
local meta = minetest.get_meta(n.pos)
|
||||
local rinv = meta:get_inventory()
|
||||
-- Autoinsert all the outputs
|
||||
--for i = 1, rinv:get_size("dst")
|
||||
-- local stack = rinv:get_stack("dst", i)
|
||||
-- local leftovers = me.insert_item(stack, net, ctrl_inv, "main")
|
||||
-- rinv:set_stack("dst", i, leftovers)
|
||||
--end
|
||||
-- register the crafted items so the autocrafter can use them
|
||||
local craft = rinv:get_stack("output", 1)
|
||||
if not craft:is_empty() then
|
||||
if not net.autocrafters_by_pos[pos] then
|
||||
net.autocrafters_by_pos[pos] = {}
|
||||
end
|
||||
net.autocrafters_by_pos[pos][craft:get_name()] = n.pos
|
||||
if not net.autocrafters[craft:get_name()] then
|
||||
net.autocrafters[craft:get_name()] = {}
|
||||
end
|
||||
net.autocrafters[craft:get_name()][n.pos] = pos
|
||||
end
|
||||
end)
|
@ -2,7 +2,7 @@
|
||||
|
||||
--TODO: use storagecomp for crafting
|
||||
|
||||
-- [drive] 8k
|
||||
-- [drive] 1k
|
||||
microexpansion.register_cell("cell_1k", {
|
||||
description = "1k ME Storage Cell",
|
||||
capacity = 1000,
|
||||
@ -16,7 +16,7 @@ microexpansion.register_cell("cell_1k", {
|
||||
},
|
||||
})
|
||||
|
||||
-- [drive] 8k
|
||||
-- [drive] 2k
|
||||
microexpansion.register_cell("cell_2k", {
|
||||
description = "2k ME Storage Cell",
|
||||
capacity = 2000,
|
||||
@ -31,7 +31,7 @@ microexpansion.register_cell("cell_2k", {
|
||||
},
|
||||
})
|
||||
|
||||
-- [drive] 16k
|
||||
-- [drive] 4k
|
||||
microexpansion.register_cell("cell_4k", {
|
||||
description = "4k ME Storage Cell",
|
||||
capacity = 4000,
|
||||
@ -44,7 +44,7 @@ microexpansion.register_cell("cell_4k", {
|
||||
},
|
||||
})
|
||||
|
||||
-- [drive] 16k
|
||||
-- [drive] 8k
|
||||
microexpansion.register_cell("cell_8k", {
|
||||
description = "8k ME Storage Cell",
|
||||
capacity = 8000,
|
||||
@ -53,7 +53,7 @@ microexpansion.register_cell("cell_8k", {
|
||||
},
|
||||
})
|
||||
|
||||
-- [drive] 32k
|
||||
-- [drive] 16k
|
||||
microexpansion.register_cell("cell_16k", {
|
||||
description = "16k ME Storage Cell",
|
||||
capacity = 16000,
|
||||
|
234
modules/storage/technic-interop.lua
Normal file
234
modules/storage/technic-interop.lua
Normal file
@ -0,0 +1,234 @@
|
||||
-- Interoperability file for technic and technic_plus support.
|
||||
local me = microexpansion
|
||||
|
||||
|
||||
-- technic_plus doesn't export machine speed, so wire it in here. We
|
||||
-- use this to know exactly how long a machine will take to process
|
||||
-- anything, after that time, we know it is done and we can grab the
|
||||
-- outputs, no polling. We do this for efficiency.
|
||||
|
||||
-- The speeds of the various machines:
|
||||
me.set_speed("technic:electric_furnace", 2)
|
||||
me.set_speed("technic:mv_electric_furnace", 4)
|
||||
me.set_speed("technic:hv_electric_furnace", 12)
|
||||
me.set_speed("technic:lv_alloy_furnace", 1)
|
||||
me.set_speed("technic:mv_alloy_furnace", 1.5)
|
||||
me.set_speed("technic:lv_compressor", 1)
|
||||
me.set_speed("technic:mv_compressor", 2)
|
||||
me.set_speed("technic:hv_compressor", 5)
|
||||
me.set_speed("technic:lv_extractor", 1)
|
||||
me.set_speed("technic:mv_extractor", 2)
|
||||
me.set_speed("technic:lv_grinder", 1)
|
||||
me.set_speed("technic:mv_grinder", 2)
|
||||
me.set_speed("technic:hv_grinder", 5)
|
||||
me.set_speed("technic:mv_centrifuge", 2)
|
||||
me.set_speed("technic:mv_freezer", 0.5)
|
||||
|
||||
-- ======================================================================== --
|
||||
|
||||
|
||||
-- Register maximal output sizes for all the ingredients we produce.
|
||||
-- We also break up deeply recursive crafts that would blow a pipeworks
|
||||
|
||||
-- autocrafter if it tried to make something.
|
||||
-- might not be necessary, but maybe it is. It might limit
|
||||
-- oversupply of inputs to batteries.
|
||||
me.register_max("technic:lv_battery_box0", 3)
|
||||
me.register_max("technic:battery", 12)
|
||||
|
||||
-- HV furnace only has 4 output slots
|
||||
me.register_max("technic:cast_iron_ingot", 20)
|
||||
me.register_max("mesecons_materials:glue", 380)
|
||||
me.register_max("mesecons_materials:fiber", 380)
|
||||
me.register_max("default:stone", 20)
|
||||
me.register_max("basic_materials:plastic_sheet", 380)
|
||||
me.register_max("basic_materials:paraffin", 380)
|
||||
|
||||
-- HV grinder only has 4 output slots
|
||||
me.register_max("technic:coal_dust", 380)
|
||||
me.register_max("technic:gold_dust", 380)
|
||||
me.register_max("technic:sulfur_dust", 380)
|
||||
me.register_max("technic:stone_dust", 380)
|
||||
me.register_max("default:gravel", 380)
|
||||
me.register_max("default:sand", 380)
|
||||
me.register_max("default:snowblock", 380)
|
||||
me.register_max("technic:rubber_tree_grindings", 380)
|
||||
|
||||
-- MV alloy furnace only has 4 output slots
|
||||
me.register_max("technic:doped_silicon_wafer", 380)
|
||||
me.register_max("technic:silicon_wafer", 380)
|
||||
me.register_max("basic_materials:brass_ingot", 380)
|
||||
me.register_max("default:bronze_ingot", 380)
|
||||
me.register_max("technic:stainless_steel_ingot", 380)
|
||||
me.register_max("technic:rubber", 380)
|
||||
me.register_max("bucket:bucket_lava", 4)
|
||||
me.register_max("technic:carbon_steel_ingot", 380)
|
||||
|
||||
-- LV extractor only has 4 output slots
|
||||
me.register_max("technic:raw_latex", 380)
|
||||
|
||||
-- HV compressor only has 4 output slots
|
||||
me.register_max("technic:composite_plate", 380)
|
||||
me.register_max("technic:copper_plate", 380)
|
||||
me.register_max("technic:graphite", 380)
|
||||
me.register_max("technic:carbon_plate", 380)
|
||||
me.register_max("technic:uranium_fuel", 380)
|
||||
me.register_max("default:diamond", 380)
|
||||
|
||||
-- freezer only has 4 output slots
|
||||
me.register_max("default:ice", 380)
|
||||
|
||||
-- ======================================================================== --
|
||||
|
||||
|
||||
-- The type of machines all the machines are: We have to list these
|
||||
-- before me.register_inventory.
|
||||
me.register_typename("technic:electric_furnace", "cooking")
|
||||
me.register_typename("technic:mv_electric_furnace", "cooking")
|
||||
me.register_typename("technic:hv_electric_furnace", "cooking")
|
||||
me.register_typename("technic:lv_grinder", "grinding")
|
||||
me.register_typename("technic:mv_grinder", "grinding")
|
||||
me.register_typename("technic:hv_grinder", "grinding")
|
||||
me.register_typename("technic:coal_alloy_furnace", "alloy")
|
||||
me.register_typename("technic:lv_alloy_furnace", "alloy")
|
||||
me.register_typename("technic:mv_alloy_furnace", "alloy")
|
||||
me.register_typename("technic:lv_extractor", "extracting")
|
||||
me.register_typename("technic:mv_extractor", "extracting")
|
||||
me.register_typename("technic:lv_compressor", "compressing")
|
||||
me.register_typename("technic:mv_compressor", "compressing")
|
||||
me.register_typename("technic:hv_compressor", "compressing")
|
||||
me.register_typename("technic:mv_centrifuge", "separating")
|
||||
me.register_typename("technic:mv_freezer", "freezing")
|
||||
|
||||
-- ======================================================================== --
|
||||
|
||||
|
||||
-- The various blocks and how to interface to them:
|
||||
me.register_inventory("technic:gold_chest", me.chest_reload)
|
||||
me.register_inventory("technic:mithril_chest", me.chest_reload)
|
||||
|
||||
me.register_inventory("technic:quarry", function(net, ctrl_inv, int_meta, n, pos)
|
||||
local meta = minetest.get_meta(n.pos)
|
||||
local rinv = meta:get_inventory()
|
||||
for i = 1, rinv:get_size("cache") do
|
||||
local stack = rinv:get_stack("cache", i)
|
||||
if not stack:is_empty() then
|
||||
local leftovers = me.insert_item(stack, net, ctrl_inv, "main")
|
||||
rinv:set_stack("cache", i, leftovers)
|
||||
end
|
||||
end
|
||||
-- we can set up a timer to recheck the cache every 30 seconds and
|
||||
-- clean it out for example.
|
||||
end)
|
||||
|
||||
me.register_inventory("technic:mv_centrifuge", function(net, ctrl_inv, int_meta, n, pos)
|
||||
local meta = minetest.get_meta(n.pos)
|
||||
local rinv = meta:get_inventory()
|
||||
for i = 1, rinv:get_size("dst") do
|
||||
local stack = rinv:get_stack("dst", i)
|
||||
if not stack:is_empty() then
|
||||
local leftovers = me.insert_item(stack, net, ctrl_inv, "main")
|
||||
rinv:set_stack("dst", i, leftovers)
|
||||
end
|
||||
end
|
||||
for i = 1, rinv:get_size("dst2") do
|
||||
local stack = rinv:get_stack("dst2", i)
|
||||
if not stack:is_empty() then
|
||||
local leftovers = me.insert_item(stack, net, ctrl_inv, "main")
|
||||
rinv:set_stack("dst2", i, leftovers)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ======================================================================== --
|
||||
|
||||
|
||||
-- The various outputs the various machine types can generate:
|
||||
me.register_output_by_typename("cooking", "technic:cast_iron_ingot")
|
||||
me.register_output_by_typename("cooking", "mesecons_materials:glue")
|
||||
me.register_output_by_typename("cooking", "mesecons_materials:fiber")
|
||||
me.register_output_by_typename("cooking", "basic_materials:plastic_sheet")
|
||||
me.register_output_by_typename("cooking", "basic_materials:paraffin")
|
||||
|
||||
me.register_output_by_typename("grinding", "technic:coal_dust")
|
||||
me.register_output_by_typename("grinding", "technic:gold_dust")
|
||||
me.register_output_by_typename("grinding", "technic:sulfur_dust")
|
||||
me.register_output_by_typename("grinding", "technic:stone_dust")
|
||||
me.register_output_by_typename("grinding", "default:gravel")
|
||||
me.register_output_by_typename("grinding", "default:sand")
|
||||
me.register_output_by_typename("grinding", "default:snowblock")
|
||||
me.register_output_by_typename("grinding", "technic:rubber_tree_grindings")
|
||||
|
||||
me.register_output_by_typename("alloy", "technic:doped_silicon_wafer")
|
||||
me.register_output_by_typename("alloy", "technic:silicon_wafer")
|
||||
me.register_output_by_typename("alloy", "basic_materials:brass_ingot")
|
||||
me.register_output_by_typename("alloy", "default:bronze_ingot")
|
||||
me.register_output_by_typename("alloy", "technic:stainless_steel_ingot")
|
||||
me.register_output_by_typename("alloy", "technic:rubber")
|
||||
me.register_output_by_typename("alloy", "bucket:bucket_lava")
|
||||
me.register_output_by_typename("alloy", "technic:carbon_steel_ingot")
|
||||
|
||||
me.register_output_by_typename("extracting", "technic:raw_latex")
|
||||
|
||||
me.register_output_by_typename("compressing", "technic:composite_plate")
|
||||
me.register_output_by_typename("compressing", "technic:copper_plate")
|
||||
me.register_output_by_typename("compressing", "technic:graphite")
|
||||
me.register_output_by_typename("compressing", "technic:carbon_plate")
|
||||
me.register_output_by_typename("compressing", "technic:uranium_fuel")
|
||||
me.register_output_by_typename("compressing", "default:diamond")
|
||||
|
||||
-- Any of these worth doing? TODO: Uranium, sure.
|
||||
--me.register_output_by_typename("separating", "")
|
||||
|
||||
me.register_output_by_typename("freezing", "default:ice")
|
||||
|
||||
-- ======================================================================== --
|
||||
|
||||
-- The inputs required for the given output. The inputs are exact count, the output it just
|
||||
-- for 1. We'll figure out how many are actually produced later. For multiple outputs
|
||||
-- only list the more interesting one.
|
||||
-- furnace ("cooking")
|
||||
me.register_output_to_inputs("technic:cast_iron_ingot", { ItemStack("default:steel_ingot") })
|
||||
me.register_output_to_inputs("mesecons_materials:glue", { ItemStack("technic:raw_latex") })
|
||||
me.register_output_to_inputs("mesecons_materials:fiber", { ItemStack("mesecons_materials:glue") })
|
||||
me.register_output_to_inputs("basic_materials:plastic_sheet", { ItemStack("basic_materials:paraffin") })
|
||||
me.register_output_to_inputs("basic_materials:paraffin", { ItemStack("basic_materials:oil_extract") })
|
||||
|
||||
-- grinder ("grinding")
|
||||
me.register_output_to_inputs("technic:coal_dust", { ItemStack("default:coal_lump") })
|
||||
me.register_output_to_inputs("technic:gold_dust", { ItemStack("default:gold_lump") })
|
||||
me.register_output_to_inputs("technic:sulfur_dust", { ItemStack("technic:sulfur_lump") })
|
||||
me.register_output_to_inputs("technic:stone_dust", { ItemStack("default:stone") })
|
||||
me.register_output_to_inputs("default:gravel", { ItemStack("default:cobble") })
|
||||
me.register_output_to_inputs("default:sand", { ItemStack("default:gravel") })
|
||||
me.register_output_to_inputs("default:snowblock", { ItemStack("default:ice") })
|
||||
-- TODO: Something about this doesn't work: recheck, think it is fixed now
|
||||
me.register_output_to_inputs("technic:rubber_tree_grindings", { ItemStack("moretrees:rubber_tree_trunk") })
|
||||
|
||||
-- alloy_furnace ("alloy")
|
||||
-- The most useful alloy recipes. We don't do the less useful ones as we don't yet have
|
||||
-- a way for the user to say, no, don't do that.
|
||||
me.register_output_to_inputs("technic:doped_silicon_wafer", { ItemStack("technic:gold_dust"), ItemStack("technic:silicon_wafer") })
|
||||
me.register_output_to_inputs("technic:silicon_wafer", { ItemStack("default:sand 2"), ItemStack("technic:coal_dust 2") })
|
||||
me.register_output_to_inputs("basic_materials:brass_ingot", { ItemStack("default:copper_ingot 2"), ItemStack("technic:zinc_ingot") })
|
||||
me.register_output_to_inputs("default:bronze_ingot", { ItemStack("default:copper_ingot 7"), ItemStack("default:tin_ingot") })
|
||||
me.register_output_to_inputs("technic:stainless_steel_ingot", { ItemStack("technic:carbon_steel_ingot 4"), ItemStack("technic:chromium_ingot") })
|
||||
me.register_output_to_inputs("technic:rubber", { ItemStack("technic:raw_latex 4"), ItemStack("technic:coal_dust 2") })
|
||||
me.register_output_to_inputs("bucket:bucket_lava", { ItemStack("default:obsidian"), ItemStack("bucket:bucket_empty") })
|
||||
me.register_output_to_inputs("technic:carbon_steel_ingot", { ItemStack("default:steel_ingot 2"), ItemStack("technic:coal_dust") })
|
||||
|
||||
-- extractor ("extracting")
|
||||
me.register_output_to_inputs("technic:raw_latex", { ItemStack("technic:rubber_tree_grindings 4") })
|
||||
|
||||
-- compressor ("compressing")
|
||||
me.register_output_to_inputs("technic:composite_plate", { ItemStack("technic:mixed_metal_ingot") })
|
||||
me.register_output_to_inputs("technic:copper_plate", { ItemStack("default:copper_ingot 5") })
|
||||
me.register_output_to_inputs("technic:graphite", { ItemStack("technic:coal_dust 4") })
|
||||
me.register_output_to_inputs("technic:carbon_plate", { ItemStack("technic:carbon_cloth") })
|
||||
me.register_output_to_inputs("technic:uranium_fuel", { ItemStack("technic:uranium35_ingot 5") })
|
||||
me.register_output_to_inputs("default:diamond", { ItemStack("technic:graphite 25") })
|
||||
|
||||
-- centrifuge ("separating")
|
||||
|
||||
-- freezer ("freezing")
|
||||
me.register_output_to_inputs("default:ice", { ItemStack("bucket:bucket_water") })
|
@ -1,3 +1,4 @@
|
||||
-- terminal
|
||||
-- microexpansion/machines.lua
|
||||
|
||||
local me = microexpansion
|
||||
@ -5,136 +6,149 @@ local pipeworks_enabled = minetest.get_modpath("pipeworks") and true or false
|
||||
|
||||
-- [me chest] Get formspec
|
||||
local function chest_formspec(pos, start_id, listname, page_max, q)
|
||||
local list
|
||||
local page_number = ""
|
||||
local buttons = ""
|
||||
local query = q or ""
|
||||
local net,cp = me.get_connected_network(pos)
|
||||
local list
|
||||
local page_number = ""
|
||||
local buttons = ""
|
||||
local query = q or ""
|
||||
local net,cp = me.get_connected_network(pos)
|
||||
|
||||
if cp then
|
||||
if listname and net:get_item_capacity() > 0 then
|
||||
local ctrlinvname = net:get_inventory_name()
|
||||
if listname == "main" then
|
||||
list = "list[detached:"..ctrlinvname..";"
|
||||
.. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
else
|
||||
list = "list[context;" .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
end
|
||||
list = list .. [[
|
||||
list[current_player;main;0,5.5;8,1;]
|
||||
list[current_player;main;0,6.73;8,3;8]
|
||||
listring[detached:]]..ctrlinvname..[[;main]
|
||||
listring[current_player;main]
|
||||
]]
|
||||
buttons = [[
|
||||
button[3.56,4.35;1.8,0.9;tochest;To Drive]
|
||||
tooltip[tochest;Move everything from your inventory to the ME network.]
|
||||
button[5.4,4.35;0.8,0.9;prev;<]
|
||||
button[7.25,4.35;0.8,0.9;next;>]
|
||||
tooltip[prev;Previous]
|
||||
tooltip[next;Next]
|
||||
field[0.29,4.6;2.2,1;filter;;]]..query..[[]
|
||||
button[2.1,4.5;0.8,0.5;search;?]
|
||||
button[2.75,4.5;0.8,0.5;clear;X]
|
||||
tooltip[search;Search]
|
||||
tooltip[clear;Reset]
|
||||
]]
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected drives!") .. "]"
|
||||
end
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected network!") .. "]"
|
||||
end
|
||||
if page_max then
|
||||
page_number = "label[6.15,4.5;" .. math.floor((start_id / 32)) + 1 ..
|
||||
"/" .. page_max .."]"
|
||||
end
|
||||
if cp then
|
||||
if listname and net:get_item_capacity() > 0 then
|
||||
local ctrlinvname = net:get_inventory_name()
|
||||
if listname == "main" then
|
||||
list = "list[detached:"..ctrlinvname..";"
|
||||
.. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
else
|
||||
list = "list[context;" .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]"
|
||||
end
|
||||
if minetest.get_modpath("i3") then
|
||||
list = list .. [[
|
||||
list[current_player;main;0,5.5;9,4;]
|
||||
]]
|
||||
else
|
||||
list = list .. [[
|
||||
list[current_player;main;0,5.5;8,1;]
|
||||
list[current_player;main;0,6.73;8,3;8]
|
||||
]]
|
||||
end
|
||||
list = list .. [[
|
||||
listring[detached:]]..ctrlinvname..[[;main]
|
||||
listring[current_player;main]
|
||||
]]
|
||||
buttons = [[
|
||||
button[3.56,4.35;1.8,0.9;tochest;To Drive]
|
||||
tooltip[tochest;Move everything from your inventory to the ME network.]
|
||||
button[5.4,4.35;0.8,0.9;prev;<]
|
||||
button[7.25,4.35;0.8,0.9;next;>]
|
||||
tooltip[prev;Previous]
|
||||
tooltip[next;Next]
|
||||
field[0.29,4.6;2.2,1;filter;;]]..query..[[]
|
||||
button[2.1,4.5;0.8,0.5;search;?]
|
||||
button[2.75,4.5;0.8,0.5;clear;X]
|
||||
tooltip[search;Search]
|
||||
tooltip[clear;Reset]
|
||||
]]
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected storage!") .. "]"
|
||||
end
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected network!") .. "]"
|
||||
end
|
||||
if page_max then
|
||||
page_number = "label[6.15,4.5;" .. math.floor((start_id / 32)) + 1 ..
|
||||
"/" .. page_max .."]"
|
||||
end
|
||||
|
||||
return [[
|
||||
size[9,9.5]
|
||||
]]..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
list ..
|
||||
[[
|
||||
label[0,-0.23;ME Terminal]
|
||||
field_close_on_enter[filter;false]
|
||||
]]..
|
||||
page_number ..
|
||||
buttons
|
||||
return [[
|
||||
size[9,9.5]
|
||||
]]..
|
||||
microexpansion.gui_bg ..
|
||||
microexpansion.gui_slots ..
|
||||
list ..
|
||||
[[
|
||||
label[0,-0.23;ME Terminal]
|
||||
field_close_on_enter[filter;false]
|
||||
]]..
|
||||
page_number ..
|
||||
buttons
|
||||
end
|
||||
|
||||
local function update_chest(pos,_,ev)
|
||||
--for now all events matter
|
||||
|
||||
local network = me.get_connected_network(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if network == nil then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
return
|
||||
end
|
||||
local size = network:get_item_capacity()
|
||||
local page_max = me.int_to_pagenum(size) + 1
|
||||
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
local network = me.get_connected_network(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if network == nil then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
return
|
||||
end
|
||||
local size = network:get_item_capacity()
|
||||
local page_max = me.int_to_pagenum(size) + 1
|
||||
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
end
|
||||
|
||||
-- [me chest] Register node
|
||||
microexpansion.register_node("term", {
|
||||
description = "ME Terminal",
|
||||
usedfor = "Can interact with storage cells in ME networks",
|
||||
tiles = {
|
||||
"chest_top",
|
||||
"chest_top",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_front",
|
||||
},
|
||||
recipe = {
|
||||
me.register_node("term", {
|
||||
description = "ME Terminal",
|
||||
usedfor = "Can interact with storage cells in ME networks",
|
||||
tiles = {
|
||||
"chest_top",
|
||||
"chest_top",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_side",
|
||||
"chest_front",
|
||||
},
|
||||
recipe = {
|
||||
{ 1, {
|
||||
{"default:steel_ingot", "default:chest", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:chest", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "microexpansion:cable", "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_chest,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
meta:set_string("inv_name", "none")
|
||||
meta:set_int("page", 1)
|
||||
is_ground_content = false,
|
||||
groups = { cracky = 1, me_connect = 1, tubedevice = 1, tubedevice_receiver = 1 },
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
me_update = update_chest,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", chest_formspec(pos, 1))
|
||||
meta:set_string("inv_name", "none")
|
||||
meta:set_int("page", 1)
|
||||
|
||||
local own_inv = meta:get_inventory()
|
||||
own_inv:set_size("src", 1)
|
||||
local own_inv = meta:get_inventory()
|
||||
own_inv:set_size("src", 1)
|
||||
|
||||
local net = me.get_connected_network(pos)
|
||||
me.send_event(pos,"connect",{net=net})
|
||||
if net then
|
||||
update_chest(pos)
|
||||
end
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
local net = me.get_connected_network(pos)
|
||||
me.send_event(pos,"connect",{net=net})
|
||||
if net then
|
||||
update_chest(pos)
|
||||
end
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
me.send_event(pos,"disconnect")
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
-- TODO: Check capacity, only allow if room
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, _, stack)
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
me.insert_item(stack, inv, "main")
|
||||
me.insert_item(stack, net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, listname, _, stack)
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
inv:remove_item("main", stack)
|
||||
end,
|
||||
tube = {
|
||||
on_metadata_inventory_take = function(pos, listname, _, stack)
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
me.remove_item(net, inv, "main", stack)
|
||||
end,
|
||||
tube = {
|
||||
can_insert = function(pos, _, stack) --pos, node, stack, direction
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
@ -144,13 +158,13 @@ microexpansion.register_node("term", {
|
||||
local slots, items = 0, 0
|
||||
-- Get amount of items in drive
|
||||
for i = 1, max_slots do
|
||||
local dstack = inv:get_stack("main", i)
|
||||
if dstack:get_name() ~= "" then
|
||||
slots = slots + 1
|
||||
local num = dstack:get_count()
|
||||
if num == 0 then num = 1 end
|
||||
items = items + num
|
||||
end
|
||||
local dstack = inv:get_stack("main", i)
|
||||
if dstack:get_name() ~= "" then
|
||||
slots = slots + 1
|
||||
local num = dstack:get_count()
|
||||
if num == 0 then num = 1 end
|
||||
items = items + num
|
||||
end
|
||||
end
|
||||
items = items + stack:get_count()
|
||||
return max_items > items
|
||||
@ -158,101 +172,100 @@ microexpansion.register_node("term", {
|
||||
insert_object = function(pos, _, stack)
|
||||
local net = me.get_connected_network(pos)
|
||||
local inv = net:get_inventory()
|
||||
me.insert_item(stack, inv, "main")
|
||||
local leftovers = me.insert_item(stack, net, inv, "main")
|
||||
net:set_storage_space(true)
|
||||
--TODO: leftover
|
||||
return ItemStack()
|
||||
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,
|
||||
on_receive_fields = function(pos, _, fields, sender)
|
||||
local net,cp = me.get_connected_network(pos)
|
||||
if net then
|
||||
if cp then
|
||||
microexpansion.log("network and ctrl_pos","info")
|
||||
else
|
||||
microexpansion.log("network but no ctrl_pos","warning")
|
||||
end
|
||||
else
|
||||
if cp then
|
||||
microexpansion.log("no network but ctrl_pos","warning")
|
||||
else
|
||||
microexpansion.log("no network and no ctrl_pos","info")
|
||||
end
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local page = meta:get_int("page")
|
||||
local inv_name = meta:get_string("inv_name")
|
||||
local own_inv = meta:get_inventory()
|
||||
local ctrl_inv
|
||||
if cp then
|
||||
ctrl_inv = net:get_inventory()
|
||||
else
|
||||
microexpansion.log("no network connected","warning")
|
||||
return
|
||||
end
|
||||
local inv
|
||||
if inv_name == "main" then
|
||||
inv = ctrl_inv
|
||||
assert(inv,"no control inv")
|
||||
else
|
||||
inv = own_inv
|
||||
assert(inv,"no own inv")
|
||||
end
|
||||
local page_max = math.floor(inv:get_size(inv_name) / 32) + 1
|
||||
if inv_name == "none" then
|
||||
return
|
||||
end
|
||||
if fields.next then
|
||||
if page + 32 > inv:get_size(inv_name) then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page + 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page + 32, inv_name, page_max))
|
||||
elseif fields.prev then
|
||||
if page - 32 < 1 then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page - 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page - 32, inv_name, page_max))
|
||||
elseif fields.search or fields.key_enter_field == "filter" then
|
||||
own_inv:set_size("search", 0)
|
||||
if fields.filter == "" then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
else
|
||||
local tab = {}
|
||||
for i = 1, ctrl_inv:get_size("main") do
|
||||
local match = ctrl_inv:get_stack("main", i):get_name():find(fields.filter)
|
||||
if match then
|
||||
tab[#tab + 1] = ctrl_inv:get_stack("main", i)
|
||||
end
|
||||
end
|
||||
own_inv:set_list("search", tab)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "search")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "search", page_max, fields.filter))
|
||||
end
|
||||
elseif fields.clear then
|
||||
own_inv:set_size("search", 0)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
elseif fields.tochest then
|
||||
local pinv = minetest.get_inventory({type="player", name=sender:get_player_name()})
|
||||
net:set_storage_space(pinv:get_size("main"))
|
||||
local space = net:get_item_capacity()
|
||||
on_receive_fields = function(pos, _, fields, sender)
|
||||
local net,cp = me.get_connected_network(pos)
|
||||
if net then
|
||||
if cp then
|
||||
me.log("network and ctrl_pos","info")
|
||||
else
|
||||
me.log("network but no ctrl_pos","warning")
|
||||
end
|
||||
else
|
||||
if cp then
|
||||
me.log("no network but ctrl_pos","warning")
|
||||
else
|
||||
me.log("no network and no ctrl_pos","info")
|
||||
end
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local page = meta:get_int("page")
|
||||
local inv_name = meta:get_string("inv_name")
|
||||
local own_inv = meta:get_inventory()
|
||||
local ctrl_inv
|
||||
if cp then
|
||||
ctrl_inv = net:get_inventory()
|
||||
else
|
||||
me.log("no network connected","warning")
|
||||
return
|
||||
end
|
||||
local inv
|
||||
if inv_name == "main" then
|
||||
inv = ctrl_inv
|
||||
assert(inv,"no control inv")
|
||||
else
|
||||
inv = own_inv
|
||||
assert(inv,"no own inv")
|
||||
end
|
||||
local page_max = math.floor(inv:get_size(inv_name) / 32) + 1
|
||||
if inv_name == "none" then
|
||||
return
|
||||
end
|
||||
if fields.next then
|
||||
if page + 32 > inv:get_size(inv_name) then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page + 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page + 32, inv_name, page_max))
|
||||
elseif fields.prev then
|
||||
if page - 32 < 1 then
|
||||
return
|
||||
end
|
||||
meta:set_int("page", page - 32)
|
||||
meta:set_string("formspec", chest_formspec(pos, page - 32, inv_name, page_max))
|
||||
elseif fields.search or fields.key_enter_field == "filter" then
|
||||
own_inv:set_size("search", 0)
|
||||
if fields.filter == "" then
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
else
|
||||
local tab = {}
|
||||
for i = 1, ctrl_inv:get_size("main") do
|
||||
local match = ctrl_inv:get_stack("main", i):get_name():find(fields.filter)
|
||||
if match then
|
||||
tab[#tab + 1] = ctrl_inv:get_stack("main", i)
|
||||
end
|
||||
end
|
||||
own_inv:set_list("search", tab)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "search")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "search", page_max, fields.filter))
|
||||
end
|
||||
elseif fields.clear then
|
||||
own_inv:set_size("search", 0)
|
||||
meta:set_int("page", 1)
|
||||
meta:set_string("inv_name", "main")
|
||||
meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max))
|
||||
elseif fields.tochest then
|
||||
local pinv = minetest.get_inventory({type="player", name=sender:get_player_name()})
|
||||
-- TODO: test and fix, net:set_storage_space(pinv:get_size("main"))
|
||||
local space = net:get_item_capacity()
|
||||
local contents = ctrl_inv:get_list("main") or {}
|
||||
for _,s in pairs(contents) do
|
||||
if not s:is_empty() then
|
||||
space = space - s:get_count()
|
||||
end
|
||||
if not s:is_empty() then
|
||||
space = space - s:get_count()
|
||||
end
|
||||
end
|
||||
microexpansion.move_inv({ inv=pinv, name="main" }, { inv=ctrl_inv, name="main",huge=true }, space)
|
||||
net:set_storage_space(true)
|
||||
end
|
||||
end,
|
||||
me.move_inv(net, { inv=pinv, name="main" }, { inv=ctrl_inv, name="main", huge=true }, space)
|
||||
net:set_storage_space(true)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user