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
2
api.lua
2
api.lua
@ -116,7 +116,7 @@ function microexpansion.register_node(itemstring, def)
|
||||
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
|
||||
|
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
|
@ -45,12 +45,12 @@ me.register_node("ctrl", {
|
||||
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")
|
||||
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)
|
||||
@ -86,6 +86,38 @@ me.register_node("ctrl", {
|
||||
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
|
||||
|
@ -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,36 +30,335 @@ 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)
|
||||
@ -110,18 +409,18 @@ end
|
||||
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
|
||||
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 = {
|
||||
@ -181,8 +480,13 @@ 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))
|
||||
|
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
|
@ -12,10 +12,12 @@ me.network = network
|
||||
|
||||
--- construct a new network
|
||||
-- @function [parent=#network] new
|
||||
-- @param #table o the object to become a network or nil
|
||||
-- @param #table or the object to become a network or nil
|
||||
-- @return #table the new network object
|
||||
function network.new(o)
|
||||
return setmetatable(o or {}, {__index = network})
|
||||
local ret = setmetatable(o or {}, {__index = network})
|
||||
ret.counts = {}
|
||||
return ret
|
||||
end
|
||||
|
||||
--- check if a node can be connected
|
||||
@ -38,6 +40,24 @@ function network.can_connect(np)
|
||||
return minetest.get_item_group(nn, "me_connect") > 0
|
||||
end
|
||||
|
||||
function network.get_ref(lstack)
|
||||
local tref = lstack:get_meta():get_string("me_store_reference")
|
||||
if tref == "" then
|
||||
-- me.log("REF: we tried, "..lstack:get_name(), "error")
|
||||
-- me.log("REF: fallback", "error")
|
||||
local location = lstack:get_location()
|
||||
if location.type == "undefined" then
|
||||
me.log("REF: we tried", "error")
|
||||
end
|
||||
local foo = minetest.get_inventory(location)
|
||||
local ref = nil
|
||||
-- TODO: Do we need this?
|
||||
return nil
|
||||
end
|
||||
local ref = minetest.deserialize(tref)
|
||||
return ref
|
||||
end
|
||||
|
||||
--- get all adjacent connected nodes
|
||||
-- @function [parent=#network] adjacent_connected_nodes
|
||||
-- @param #table pos the position of the base node
|
||||
@ -104,7 +124,7 @@ end
|
||||
function network:remove_power_capacity(power)
|
||||
self.power_storage = self.power_storage - power
|
||||
if self.power_storage < 0 then
|
||||
microexpansion.log("power storage of network "..self.." dropped below zero","warning")
|
||||
me.log("power storage of network "..self.." dropped below zero","warning")
|
||||
end
|
||||
end
|
||||
|
||||
@ -129,6 +149,12 @@ local function get_drive_capacity(pos)
|
||||
return cap
|
||||
end
|
||||
|
||||
local function get_interface_capacity(pos)
|
||||
local cap = 0
|
||||
local meta = minetest.get_meta(pos)
|
||||
return meta:get_int("capacity") or 0
|
||||
end
|
||||
|
||||
--- get the item capacity of a network
|
||||
-- @function [parent=#network] get_item_capacity
|
||||
-- @return #number the total number of items that can be stored in the network
|
||||
@ -138,44 +164,60 @@ function network:get_item_capacity()
|
||||
if me.get_node(npos).name == "microexpansion:drive" then
|
||||
cap = cap + get_drive_capacity(npos)
|
||||
end
|
||||
if me.get_node(npos).name == "microexpansion:interface" then
|
||||
cap = cap + get_interface_capacity(npos)
|
||||
end
|
||||
end
|
||||
self.capacity_cache = cap
|
||||
me.log("total capacity is "..cap, "error")
|
||||
return cap
|
||||
end
|
||||
|
||||
local function remove_slots(inv,ln,target,csize)
|
||||
for i = target, csize do
|
||||
local s = inv:get_stack(ln,i)
|
||||
if not s:is_empty() then
|
||||
inv:set_stack(ln, i, "")
|
||||
me.insert_item(s, inv, ln)
|
||||
function network:remove_slots(inv, listname, target, csize)
|
||||
-- me.log("removing slots on "..listname..", target is "..target.." and csize is "..csize, "error")
|
||||
for i = target+1, csize do
|
||||
local stack = inv:get_stack(listname, i)
|
||||
-- me.log("network remove_slot "..listname..":"..i.." "..stack:get_name(), "error")
|
||||
if not stack:is_empty() then
|
||||
-- me.log("BROKEN: after remove_slot, still "..stack:get_count().." "..stack:get_name().." left", "error")
|
||||
if true then return end
|
||||
foobar() -- This can't happen, we can only remove empty slots, and only 1 at that, at the end
|
||||
--inv:set_stack(listname, i, "")
|
||||
--me.insert_item(stack, self, inv, listname)
|
||||
me.remove_item(self, inv, listname, stack)
|
||||
if inv:get_stack("main", i):get_count() ~= 0 then
|
||||
-- me.log("BROKEN: after remove_slot, still "..inv:get_stack("main", i):get_count().." left", "error")
|
||||
end
|
||||
end
|
||||
end
|
||||
--perhaps allow list removal
|
||||
if target < 0 then
|
||||
-- TODO: audit, this sould be made impossible if it is, or removed.
|
||||
target = 1
|
||||
end
|
||||
inv:set_size(ln, target)
|
||||
inv:set_size(listname, target)
|
||||
end
|
||||
|
||||
function network:set_storage_space(count, listname)
|
||||
local c = count or 1
|
||||
local ln = listname or "main"
|
||||
listname = listname or "main"
|
||||
local inv = self:get_inventory()
|
||||
local csize = inv:get_size(ln)
|
||||
local csize = inv:get_size(listname)
|
||||
local space = 0
|
||||
local inside = 0
|
||||
local contents = inv:get_list(ln) or {}
|
||||
for _,s in pairs(contents) do
|
||||
if s:is_empty() then
|
||||
local contents = inv:get_list(listname) or {}
|
||||
for i,stack in pairs(contents) do
|
||||
if stack:is_empty() then
|
||||
space = space + 1
|
||||
-- me.log("STORAGE: found space at "..i.." now "..space, "error")
|
||||
else
|
||||
inside = inside + s:get_count()
|
||||
inside = inside + stack:get_count()
|
||||
end
|
||||
end
|
||||
local cap = self:get_item_capacity()
|
||||
--the capacity is allocated outside of the condition because it updates the cached capacity
|
||||
if count == true then
|
||||
me.log("STORAGE: current: "..inside.." capacity: "..cap, "error")
|
||||
if inside < cap then
|
||||
c = 1
|
||||
else
|
||||
@ -183,12 +225,13 @@ function network:set_storage_space(count,listname)
|
||||
end
|
||||
end
|
||||
local needed = c - space
|
||||
-- me.log("STORAGE: needed: "..needed, "error")
|
||||
if needed > 0 then
|
||||
needed = needed + csize
|
||||
inv:set_size(ln, needed)
|
||||
inv:set_size(listname, needed)
|
||||
elseif needed < 0 then
|
||||
needed = needed + csize
|
||||
remove_slots(inv,ln,needed,csize)
|
||||
self:remove_slots(inv, listname, needed, csize)
|
||||
end
|
||||
end
|
||||
|
||||
@ -202,6 +245,39 @@ function network:get_inventory_name()
|
||||
return "microexpansion_storage_"..cp.x.."_"..cp.y.."_"..cp.z
|
||||
end
|
||||
|
||||
function network:find_loan(inv, stack)
|
||||
if not self.byname["loan"] then
|
||||
self.byname["loan"] = {}
|
||||
end
|
||||
if not self.byname["loan"][stack:get_name()] then
|
||||
self.byname["loan"][stack:get_name()] = {}
|
||||
end
|
||||
local loan_slot = self.byname["loan"][stack:get_name()][stack:get_wear()]
|
||||
if loan_slot then
|
||||
-- me.log("init me.remove_item before update_loan", "error")
|
||||
self:update_loan(inv, loan_slot)
|
||||
-- me.log("init me.remove_item after update_loan", "error")
|
||||
end
|
||||
loan_slot = self.byname["loan"][stack:get_name()][stack:get_wear()]
|
||||
if loan_slot then
|
||||
local lstack = me.loan.get_stack(self, inv, loan_slot)
|
||||
if lstack:get_name() == stack:get_name() and lstack:get_wear() == stack:get_wear() then
|
||||
return loan_slot
|
||||
end
|
||||
self.byname["loan"][stack:get_name()][stack:get_wear()] = nil
|
||||
end
|
||||
-- me.log("init network find_loan searching all loans", "error")
|
||||
for loan_slot = 1, me.loan.get_size(self, inv) do
|
||||
local lstack = me.loan.get_stack(self, inv, loan_slot)
|
||||
if lstack:get_name() == stack:get_name() and lstack:get_wear() == stack:get_wear() then
|
||||
-- TODO: Same meta_data...
|
||||
self.byname["loan"][stack:get_name()][stack:get_wear()] = loan_slot
|
||||
return loan_slot
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function create_inventory(net)
|
||||
local invname = net:get_inventory_name()
|
||||
net.inv = minetest.create_detached_inventory(invname, {
|
||||
@ -235,15 +311,125 @@ local function create_inventory(net)
|
||||
end,
|
||||
on_put = function(inv, listname, _, stack)
|
||||
inv:remove_item(listname, stack)
|
||||
me.insert_item(stack, inv, listname)
|
||||
me.insert_item(stack, net, inv, listname)
|
||||
net:set_storage_space(true)
|
||||
end,
|
||||
allow_take = function(_, _, _, stack)
|
||||
return math.min(stack:get_count(),stack:get_stack_max())
|
||||
allow_take = function(inv, listname, slot, stack, player)
|
||||
-- This is not remove_item, we only remove the loan. This real
|
||||
-- item will be removed.
|
||||
me.log("REMOVE: network allow taking of "..stack:get_name().." from "..listname, "error")
|
||||
--me.log("COUNTS: allow_take "..minetest.serialize(net.counts), "error")
|
||||
--print(dump2(inv:get_list("loan")))
|
||||
-- me.log("LOANS: allow_take "..minetest.serialize(inv:get_list("loan")), "error")
|
||||
-- net:dump_loans(inv)
|
||||
local count = math.min(stack:get_count(),stack:get_stack_max())
|
||||
local orig_count = count
|
||||
if listname ~= "main" then
|
||||
return count
|
||||
end
|
||||
local on_loan = net.counts[stack:get_name()]
|
||||
local main_slot = nil
|
||||
local main_count = 0
|
||||
if on_loan then
|
||||
local found = false
|
||||
local mstack = inv:get_stack("main", slot)
|
||||
main_slot = slot
|
||||
local mbias = 0
|
||||
if net.bias and net.bias["main"] and net.bias["main"][stack:get_name()] then
|
||||
mbias = net.bias["main"][stack:get_name()]
|
||||
end
|
||||
main_count = mstack:get_count() + mbias
|
||||
if main_count - on_loan >= 1 then
|
||||
return math.min(mstack:get_count() + mbias - on_loan, count)
|
||||
end
|
||||
local update = false
|
||||
--me.log("COUNTS: allow_take2 "..minetest.serialize(net.counts), "error")
|
||||
--print(dump2(inv:get_list("loan")))
|
||||
-- net:dump_loans(inv)
|
||||
local loan_slot = net:find_loan(inv, stack)
|
||||
if loan_slot then
|
||||
-- me.log("found loan", "error")
|
||||
local lstack = me.loan.get_stack(net, inv, loan_slot)
|
||||
local loan_count = lstack:get_count()
|
||||
local ref = network.get_ref(lstack)
|
||||
local rinv = minetest.get_meta(ref.pos):get_inventory()
|
||||
local real_stack = nil
|
||||
if ref.drawer then
|
||||
local c = drawers.drawer_get_content(ref.pos, ref.slot)
|
||||
real_stack = ItemStack(c.name)
|
||||
real_stack:set_count(math.max(c.count-1,0))
|
||||
else
|
||||
real_stack = rinv:get_stack(ref.invname, ref.slot)
|
||||
end
|
||||
local same_name = real_stack:get_name() == stack:get_name()
|
||||
local same_wear = real_stack:get_wear() == stack:get_wear()
|
||||
-- TODO: Same meta_data...
|
||||
if same_name and same_wear and real_stack:get_count() >= 1 then
|
||||
found = true
|
||||
count = math.min(real_stack:get_count(), count)
|
||||
if real_stack:get_count() ~= loan_count then
|
||||
update = true
|
||||
-- The partial update won't be able to update the count of
|
||||
-- this slot as we are taking the whole thing, updating now
|
||||
-- before the contents are removed, so the loan remains
|
||||
if count == main_count then
|
||||
local mstack = inv:get_stack("main", main_slot)
|
||||
-- adding 1 is enough to keep it from disappearing
|
||||
mstack:set_count(main_count + 1)
|
||||
inv:set_stack("main", main_slot, mstack)
|
||||
loan_count = loan_count + 1
|
||||
lstack:set_count(loan_count)
|
||||
me.log("LOAN: allow_take to "..lstack:get_count(), "error")
|
||||
me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
end
|
||||
end
|
||||
if ref.drawer then
|
||||
local take = real_stack
|
||||
take:set_count(count)
|
||||
local c = drawers.drawer_get_content(ref.pos, "")
|
||||
drawers.drawer_take_item(ref.pos, take) -- TODO: unify with me.remove_item loan refilling code
|
||||
local c = drawers.drawer_get_content(ref.pos, "")
|
||||
else
|
||||
real_stack:set_count(real_stack:get_count() - count)
|
||||
rinv:set_stack(ref.invname, ref.slot, real_stack)
|
||||
end
|
||||
if loan_count - count == 0 then
|
||||
net:maybemoveloan(inv, loan_slot)
|
||||
-- me.log("LOAN: removed "..minetest.serialize(net.counts), "error")
|
||||
else
|
||||
lstack:set_count(loan_count - count)
|
||||
me.log("LOAN: allow_take loan to "..lstack:get_count(), "error")
|
||||
me.loan.set_stack(net, inv, loan_slot, lstack)
|
||||
end
|
||||
net.counts[stack:get_name()] = net.counts[stack:get_name()] - count
|
||||
me.add_capacity(ref.ipos, -count)
|
||||
else
|
||||
update = true
|
||||
end
|
||||
if not found then
|
||||
update = true
|
||||
-- me.log("Ouch, lost track, someone almost got free shit from us: "..stack:get_name().." "..tostring(count), "error")
|
||||
count = 0
|
||||
end
|
||||
if update then
|
||||
-- a little weighty, but someone touched the count and it
|
||||
-- wasn't us, make em pay for it.
|
||||
net:update_counts()
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end,
|
||||
on_take = function()
|
||||
on_take = function(inv, listname, index, stack, player)
|
||||
me.log("REMOVE: net taking of "..stack:get_count().." "..stack:get_name().." from "..listname, "error")
|
||||
local func = function()
|
||||
if inv:get_stack(listname, index):get_count() == 0 then
|
||||
me.maybemove(net, inv, listname, index, stack)
|
||||
end
|
||||
net:set_storage_space(true) -- TODO: remove, should not be necessary anymore, maybemove should do it
|
||||
end
|
||||
--update the inventory size in the next step as it is not allowed in on_take
|
||||
minetest.after(0, function() net:set_storage_space(true) end)
|
||||
minetest.after(0, func)
|
||||
end
|
||||
})
|
||||
end
|
||||
@ -259,9 +445,61 @@ end
|
||||
function network:load_inventory(lists)
|
||||
local inv = self:get_inventory()
|
||||
for listname,c in pairs(lists) do
|
||||
local empties = 0
|
||||
inv:set_size(listname, #c)
|
||||
for i,s in pairs(c) do
|
||||
inv:set_stack(listname,i,s)
|
||||
for i,stack in pairs(c) do
|
||||
stack = ItemStack(stack) -- and now we try it here
|
||||
inv:set_stack(listname, i-empties, stack)
|
||||
-- me.log("LOAD META0: "..stack:get_count().." "..stack:get_name(), "error")
|
||||
|
||||
if listname == "loan" then
|
||||
-- local tref = stack:get_meta():get_string("me_store_reference")
|
||||
-- me.log("LOAD META1: tref was "..tref, "error")
|
||||
|
||||
-- inv:get_stack(listname, i-empties):get_meta():set_string("me_store_reference", tref)
|
||||
|
||||
-- local inv_stack = inv:get_stack(listname, i-empties)
|
||||
-- local inv_meta = inv_stack:get_meta()
|
||||
-- inv_meta:set_string("me_store_reference", tref)
|
||||
-- inv:set_stack(listname, i-empties, inv_stack)
|
||||
-- inv_stack = inv:get_stack(listname, i-empties)
|
||||
|
||||
-- me.log("LOAD META1.1: tref was "..inv_meta:get_string("me_store_reference"), "error")
|
||||
-- me.log("LOAD META1.2: tref was "..inv_stack:get_meta():get_string("me_store_reference"), "error")
|
||||
-- me.log("LOAD META1.3: tref was "..inv:get_stack(listname, i-empties):get_meta():get_string("me_store_reference"), "error")
|
||||
-- inv:set_stack(listname, i-empties, ItemStack(inv_stack))
|
||||
--me.log("LOAD META1.4: tref was "..inv:get_stack(listname, i-empties):get_meta():get_string("me_store_reference"), "error")
|
||||
--me.log("LOAD META1.5: tref was "..inv_stack:get_meta():get_string("me_store_reference"), "error")
|
||||
|
||||
--local meta = inv:get_stack(listname, i-empties)
|
||||
--meta = meta:get_meta():get_string("me_store_reference")
|
||||
--me.log("LOAD META2: ref was "..minetest.serialize(meta), "error")
|
||||
--stack:get_meta():set_string("me_store_reference", tref)
|
||||
--meta = inv:get_stack(listname, i-empties)
|
||||
--meta = meta:get_meta():get_string("me_store_reference")
|
||||
--me.log("LOAD META3: ref was "..minetest.serialize(meta), "error")
|
||||
--me.log("loading network1: "..minetest.serialize(stack:get_meta():get_string("me_store_reference")), "error")
|
||||
-- stack = ItemStack(stack) -- tried moving this, was here
|
||||
-- me.log("loading network2: "..minetest.serialize(stack), "error")
|
||||
end
|
||||
-- me.log("loading network: "..minetest.serialize(stack), "error")
|
||||
if stack and not stack:is_empty() then
|
||||
-- me.log("loading network "..listname.." "..stack:get_name().." slot "..i, "error")
|
||||
-- TODO: missing bias
|
||||
-- does this load loans? Yes.
|
||||
if not self.byname then
|
||||
self.byname = {}
|
||||
end
|
||||
if not self.byname[listname] then
|
||||
self.byname[listname] = {}
|
||||
end
|
||||
if not self.byname[listname][stack:get_name()] then
|
||||
self.byname[listname][stack:get_name()] = {}
|
||||
end
|
||||
self.byname[listname][stack:get_name()][stack:get_wear()] = i-empties
|
||||
else
|
||||
empties = empties + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -281,10 +519,30 @@ end
|
||||
|
||||
function network:load()
|
||||
if self.strinv then
|
||||
-- me.log("LOADING: "..minetest.serialize(self.strinv), "error")
|
||||
self:load_inventory(self.strinv)
|
||||
end
|
||||
end
|
||||
|
||||
-- We don't save this data, rather we rewalk upon first use. If 1% of
|
||||
-- the people play per reboot, then this saves 99% of the work.
|
||||
-- Also, we don't actually read or write any of this data normally,
|
||||
-- only for active users, using 1% of the memory.
|
||||
-- TODO: I think all the storage for me should be handled the same way.
|
||||
-- As it is, we needlessly read and write all the networks for all the users and
|
||||
-- writing isn't crash friendly, whereas rewalking is crash friendly.
|
||||
-- We don't reload the loans, that is saved and restored already.
|
||||
function network:reload_network()
|
||||
self.autocrafters = {}
|
||||
self.autocrafters_by_pos = {}
|
||||
self.process = {}
|
||||
for ipos in me.connected_nodes(self.controller_pos) do
|
||||
if me.get_node(ipos).name == "microexpansion:interface" then
|
||||
me.reload_interface(self, ipos, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function network:serialize()
|
||||
local sert = {}
|
||||
for i,v in pairs(self) do
|
||||
@ -306,3 +564,428 @@ function network:destruct()
|
||||
self.controller_pos = nil
|
||||
self.inv = nil
|
||||
end
|
||||
|
||||
-- This ensure main_slot is right, and if not, update it
|
||||
function network:find_main(inv, ref, stack)
|
||||
local main_slot = ref.main_slot
|
||||
local mstack = inv:get_stack("main", ref.main_slot)
|
||||
if mstack:get_name() == stack:get_name() and mstack:get_wear() == stack:get_wear() then
|
||||
return mstack
|
||||
end
|
||||
for i = 1, inv:get_size("main") do
|
||||
mstack = inv:get_stack("main", i)
|
||||
if mstack:get_name() == stack:get_name() and mstack:get_wear() == stack:get_wear() then
|
||||
ref.main_slot = i
|
||||
return mstack
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- we can't update a loan with a bias, cause we don't know the old bias for this specific loan,
|
||||
-- therefore we have no clue about changes to the item count, therefore we can't update the
|
||||
-- item count.
|
||||
function network:update_loan(inv, loan_slot)
|
||||
me.log("LOAN: updating some 4", "error")
|
||||
local lstack = me.loan.get_stack(self, inv, loan_slot)
|
||||
local tref = lstack:get_meta():get_string("me_store_reference")
|
||||
me.log("LOAN: update_loan "..lstack:get_count().." "..lstack:get_name().." with ref "..tref, "error")
|
||||
local rinv = nil
|
||||
local real_stack = nil
|
||||
local same_name = nil
|
||||
local same_wear = nil
|
||||
local excess = nil
|
||||
if tref == nil then me.log("LOAN: bad tref in loan", "error") end
|
||||
-- if tref == nil then return end
|
||||
local ref = minetest.deserialize(tref)
|
||||
if ref == nil then me.log("LOAN: bad ref in loan", "error") end
|
||||
if ref == nil then return end
|
||||
rinv = minetest.get_meta(ref.pos):get_inventory()
|
||||
local rbias = 0
|
||||
local lbias = (self.bias and self.bias["loan"] and self.bias["loan"][loan_slot]) or 0
|
||||
if ref.drawer then
|
||||
local c = drawers.drawer_get_content(ref.pos, ref.slot)
|
||||
if c.name ~= lstack:get_name() then me.log("LOAN: bad drawer item in loan "..c.name.." "..lstack:get_name(), "error") end
|
||||
c.count = math.max(c.count-1,0) -- Poor man's locking
|
||||
real_stack = ItemStack(c.name)
|
||||
if c.count > math.pow(2,15) then
|
||||
rbias = rbias + c.count - math.pow(2,15)
|
||||
c.count = math.pow(2,15)
|
||||
end
|
||||
real_stack:set_count(c.count)
|
||||
else
|
||||
real_stack = rinv:get_stack(ref.invname, ref.slot)
|
||||
if real_stack:get_name() ~= lstack:get_name() then me.log("LOAN: bad chest item in loan "..real_stack:get_name().." "..lstack:get_name(), "error") end
|
||||
end
|
||||
-- local excess = (real_stack:get_count() + rbias) - (lstack:get_count() + lbias)
|
||||
-- TODO: This assumes meta is the same save "me_store_reference".
|
||||
same_name = real_stack:get_name() == lstack:get_name()
|
||||
same_wear = real_stack:get_wear() == lstack:get_wear()
|
||||
-- If someone updates the chest, update loan and counts
|
||||
if not same_name or not same_wear then
|
||||
me.log("inventory out of sync", "error")
|
||||
-- Not at all the same, remove the loan entirely
|
||||
if not inv:contains_item("main", lstack) then
|
||||
-- TODO: Update anything that can remove to have allow_metadata check
|
||||
-- remote inventories first so this cannot happen
|
||||
me.log("missing items on loan #1", "error")
|
||||
end
|
||||
me.remove_item(self, inv, "main", lstack) -- FIXME remove_loan or change_loan? lstack, remove tref and remove that from main.
|
||||
lstack:set_count(0)
|
||||
if not real_stack:is_empty() then
|
||||
local llstack = ItemStack(real_stack)
|
||||
llstack:get_meta():set_string("me_store_reference", tref)
|
||||
me.log("LOAN: update_loan to "..llstack:get_count()..llstack:get_name(), "error")
|
||||
me.loan.set_stack(self, inv, loan_slot, llstack) -- FIXME change loan?
|
||||
if rbias > 0 then
|
||||
if not self.bias then
|
||||
self.bias = {}
|
||||
end
|
||||
if not self.bias["loan"] then
|
||||
self.bias["loan"] = {}
|
||||
end
|
||||
self.bias["loan"][loan_slot] = rbias -- FIXME, lstack or llstack? was lstack, wrong
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
excess = real_stack:get_count() - lstack:get_count()
|
||||
me.log("update_loan exess is "..excess..", lc is "..lstack:get_count()..", rc is "..real_stack:get_count(), "error")
|
||||
local prev = self.counts[lstack:get_name()] or 0
|
||||
self.counts[lstack:get_name()] = prev + excess
|
||||
me.log("COUNT: update_loan loan now to "..self.counts[lstack:get_name()].." "..lstack:get_name()..", "..excess.." more", "error")
|
||||
if not real_stack:is_empty() then
|
||||
me.log("LOAN: updating some", "error")
|
||||
real_stack:get_meta():set_string("me_store_reference", tref)
|
||||
local llstack = ItemStack(real_stack)
|
||||
me.log("LOAN: update_loan to "..llstack:get_count().." "..llstack:get_name(), "error")
|
||||
me.loan.set_stack(self, inv, loan_slot, llstack)
|
||||
else
|
||||
me.log("LOAN: updating some 2", "error")
|
||||
remove_loan(ref.pos, inv, lstack, loan_slot, ref)
|
||||
end
|
||||
if excess > 0 then
|
||||
local extra = lstack
|
||||
extra:set_count(excess)
|
||||
extra:get_meta():set_string("me_store_reference", "")
|
||||
me.log("update_loan adding "..excess.." "..lstack:get_name().." to main", "error")
|
||||
local mstack = self:find_main(inv, ref, extra)
|
||||
if mstack and not mstack:is_empty() then
|
||||
mstack:set_count(mstack:get_count()+excess)
|
||||
else
|
||||
me.log("INV: went missing, readding", "error")
|
||||
me.insert_item(extra, self, inv, "main")
|
||||
end
|
||||
inv:set_stack("main", ref.main_slot, mstack)
|
||||
me.add_capacity(ref.ipos, excess)
|
||||
elseif excess < 0 then
|
||||
local deficit = lstack
|
||||
deficit:set_count(-excess)
|
||||
me.log("update_loan removing "..-excess.." "..lstack:get_name().." from main", "error")
|
||||
-- We should fix this so that this cannot happen. See above.
|
||||
-- For now, let's see if we can fix it up.
|
||||
if not inv:contains_item("main", deficit) then
|
||||
me.log("network no extra items to meet deficit, free items", "error")
|
||||
end
|
||||
-- TODO: This isn't a copy of the original meta, it is the original meta, and screws other loans, maybe?
|
||||
deficit:get_meta():set_string("me_store_reference", "")
|
||||
-- was: local mstack = inv:get_stack("main", ref.main_slot)
|
||||
local mstack = self:find_main(inv, ref, deficit)
|
||||
if mstack then
|
||||
mstack:set_count(mstack:get_count()+excess)
|
||||
inv:set_stack("main", ref.main_slot, mstack)
|
||||
if false and mstack:get_count() == 0 then -- should be impossible, we have an outstanding loan still?
|
||||
foobar()
|
||||
end
|
||||
me.add_capacity(ref.ipos, excess)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function network:update_loan_count(inv, loan_slot)
|
||||
me.log("COUNT: loan_slot "..loan_slot, "error")
|
||||
local lstack = me.loan.get_stack(self, inv, loan_slot)
|
||||
local lbias = (self.bias and self.bias["loan"] and self.bias["loan"][loan_slot]) or 0
|
||||
local prev = self.counts[lstack:get_name()] or 0
|
||||
self.counts[lstack:get_name()] = prev + lstack:get_count() + lbias
|
||||
me.log("COUNT: update_loan_count loan now to "..self.counts[lstack:get_name()].." "..lstack:get_name()..", "..(lstack:get_count() + lbias).." more, bias is "..lbias, "error")
|
||||
end
|
||||
|
||||
-- Check everything on loan. This is the cheapest possible version.
|
||||
-- We don't rewalk, we don't pick up new slots that now have contents.
|
||||
-- We don't even verify the type of node is the same type of node.
|
||||
function network:update_counts()
|
||||
local inv = self:get_inventory()
|
||||
for loan_slot = 1, me.loan.get_size(self, inv) do
|
||||
self:update_loan(inv, loan_slot)
|
||||
end
|
||||
-- Since we are rescanning 100%, we start with no old counts and we
|
||||
-- rebuild the counts
|
||||
self.counts = {}
|
||||
-- no, update_loan_count doesn't read from the inventory, if this is done, it has to be done
|
||||
-- by a inventory reader that will re-create it.
|
||||
--if self.bias and self.bias["loan"] then
|
||||
-- self.bias["loan"] = nil
|
||||
--end
|
||||
for loan_slot = 1, me.loan.get_size(self, inv) do
|
||||
self:update_loan_count(inv, loan_slot)
|
||||
end
|
||||
end
|
||||
|
||||
function network:sync_main(inv)
|
||||
local listname = "main"
|
||||
for i = 1, inv:get_size(listname) do
|
||||
local mstack = inv:get_stack(listname, i)
|
||||
if mstack:is_empty() and i < inv:get_size("main") then
|
||||
me.log("network sync_main, empty stack at pos "..i, "error")
|
||||
me.maybemove(self, inv, "main", i, mstack)
|
||||
else
|
||||
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 slot = self.byname[listname][mstack:get_name()][mstack:get_wear()]
|
||||
if not slot then
|
||||
me.log("network sync_main, missing "..mstack:get_name().." at pos "..i, "error")
|
||||
self.byname[listname][mstack:get_name()][mstack:get_wear()] = i
|
||||
elseif slot ~= i then
|
||||
me.log("network sync_main, wrong pos for "..mstack:get_name().." at pos "..i", found "..slot, "error")
|
||||
self.byname[listname][mstack:get_name()][mstack:get_wear()] = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function network:remove_real(ref, inv, stack, count)
|
||||
if ref.drawer then
|
||||
while count > math.pow(2,16)-1 do
|
||||
stack:set_count(math.pow(2,16)-1)
|
||||
drawers.drawer_take_large_item(ref.pos, stack)
|
||||
count = count - math.pow(2,16)-1
|
||||
end
|
||||
stack:set_count(count)
|
||||
drawers.drawer_take_large_item(ref.pos, stack)
|
||||
else
|
||||
local rinv = minetest.get_meta(ref.pos):get_inventory()
|
||||
stack:set_count(count)
|
||||
local rstack = rinv:get_stack(ref.invname, ref.slot)
|
||||
rstack:take_item(count)
|
||||
rinv:set_stack(ref.invname, ref.slot, rstack)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callers have to ensure net.counts exists before calling.
|
||||
-- Loans with bias only work for no wear and no metadata items. Only
|
||||
-- drawers can create bias loans and they don't support wear or
|
||||
-- metadata items. One should add chests first, then drawers, this will top off
|
||||
-- items in the drawers. If one wants to empty the chests, do the chests after the
|
||||
-- drawer.
|
||||
function network:create_loan(stack, ref, inv, int_meta, bias)
|
||||
local listname = "loan"
|
||||
local on_loan = self.counts[stack:get_name()] or 0
|
||||
local lbias = bias or 0
|
||||
inv = inv or get_inventory()
|
||||
local mstack = ItemStack(stack)
|
||||
local prev = int_meta:get_int("capacity") or 0
|
||||
local count = stack:get_count() + (bias or 0)
|
||||
int_meta:set_int("capacity", prev + count)
|
||||
-- me.log("total loaned items: "..tostring(prev + count))
|
||||
self:set_storage_space(true)
|
||||
local _, main_slot = me.insert_item(mstack, self, inv, "main", bias)
|
||||
local now_on_loan = self.counts[stack:get_name()] or 0
|
||||
local items_taken = now_on_loan - on_loan
|
||||
if items_taken > 0 then
|
||||
local loan_slot = self:find_loan(inv, stack)
|
||||
self:remove_real(ref, inv, stack, items_taken)
|
||||
prev = int_meta:get_int("capacity") or 0
|
||||
int_meta:set_int("capacity", prev - items_taken)
|
||||
count = count - items_taken
|
||||
if count == 0 then
|
||||
-- no actual loan in this case.
|
||||
return
|
||||
end
|
||||
if count > math.pow(2,15) then
|
||||
bias = count - math.pow(2,15)
|
||||
lbias = bias
|
||||
count = math.pow(2,15)
|
||||
else
|
||||
bias = nil
|
||||
lbias = 0
|
||||
stack:set_count(count)
|
||||
end
|
||||
end
|
||||
if main_slot == 1 then
|
||||
me.log("LARGE: creating loan for "..mstack:get_name()..", mc "..mstack:get_count()..", lc "..stack:get_count()..", lbias "..(bias or 0), "error")
|
||||
end
|
||||
self:set_storage_space(true)
|
||||
ref.main_slot = main_slot
|
||||
stack:get_meta():set_string("me_store_reference", minetest.serialize(ref))
|
||||
local loan_slot = me.loan.get_size(self, inv)+1
|
||||
me.loan.set_size(self, inv, loan_slot)
|
||||
-- me.log("loan size is now "..me.loan.get_size(self, inv))
|
||||
me.log("LOAN: create_loan to "..stack:get_count().." "..stack:get_name(), "error")
|
||||
me.loan.set_stack(self, inv, loan_slot, stack)
|
||||
me.log("INV: slot "..loan_slot.." now has "..stack:get_count().." "..stack:get_name().." in it", "error")
|
||||
if bias then
|
||||
if not self.bias then
|
||||
self.bias = {}
|
||||
end
|
||||
if not self.bias[listname] then
|
||||
self.bias[listname] = {}
|
||||
end
|
||||
self.bias[listname][loan_slot] = bias
|
||||
me.log("LARGE: "..self.bias[listname][loan_slot].." "..stack:get_name()..", added "..bias, "error")
|
||||
end
|
||||
prev = self.counts[stack:get_name()] or 0 -- TODO: Contemplate wear and meta for counts. Add wear, meta; no limit large counts to no wear, no meta
|
||||
self.counts[stack:get_name()] = prev + count
|
||||
me.log("COUNT: create_loan loan now to "..self.counts[stack:get_name()].." "..stack:get_name()..", "..count.." more", "error")
|
||||
end
|
||||
|
||||
-- This removes the entire loan slot, always
|
||||
function network:remove_loan(pos, inv, lstack, loan_slot, ref)
|
||||
me.log("LOAN: updating some 3", "error")
|
||||
lstack:get_meta():set_string("me_store_reference", "")
|
||||
local mstack = self:find_main(inv, ref, lstack)
|
||||
local main_slot = ref.main_slot
|
||||
if mstack == nil then mstack = ItemStack() end
|
||||
local omstack = ItemStack(mstack)
|
||||
me.log("network remove_loan of "..omstack:get_name()..", at "..main_slot, "error")
|
||||
local lbias = (self.bias and self.bias["loan"] and self.bias["loan"][loan_slot]) or 0
|
||||
local excess = 0
|
||||
local mbias = (self.bias and self.bias["main"] and self.bias["main"][mstack:get_name()]) or 0
|
||||
excess = (mstack:get_count() + mbias) - (lstack:get_count() + lbias)
|
||||
me.log("LOAN: remove_loan "..(mstack:get_count() + mbias).." "..mstack:get_name().." "..(lstack:get_count() + lbias).." on loan, lbias is "..lbias, "error")
|
||||
if lstack:get_name() == "default:steel_ingot" then
|
||||
me.log("LARGE: remove_loan excess "..excess.." for "..(lstack:get_name())..", mc "..mstack:get_count()..", mbias "..mbias..", lc "..lstack:get_count()..", lbias "..lbias..", slot "..loan_slot, "error")
|
||||
end
|
||||
if excess < 0 then
|
||||
me.log("network missing "..tostring(-excess).." "..lstack:get_name().." from loan, free items", "error")
|
||||
mstack:set_count(0)
|
||||
mbias = 0
|
||||
if self.bias and self.bias["main"] then
|
||||
self.bias["main"][mstack:get_name()] = nil
|
||||
end
|
||||
lbias = 0
|
||||
if self.bias and self.bias["loan"] then
|
||||
self.bias["loan"][loan_slot] = nil
|
||||
end
|
||||
excess = 0
|
||||
end
|
||||
if excess > math.pow(2,15) then
|
||||
me.log("LARGE: remove_loan remaining "..excess.." for "..lstack:get_name(), "error")
|
||||
mstack:set_count(math.pow(2,15))
|
||||
self.bias["main"][mstack:get_name()] = excess - math.pow(2,15)
|
||||
if self.bias and self.bias["loan"] then
|
||||
lbias = 0
|
||||
self.bias["loan"][loan_slot] = nil
|
||||
end
|
||||
else
|
||||
mstack:set_count(excess)
|
||||
if self.bias and self.bias["main"] then
|
||||
self.bias["main"][omstack:get_name()] = nil
|
||||
end
|
||||
if self.bias and self.bias["loan"] then
|
||||
lbias = 0
|
||||
self.bias["loan"][loan_slot] = nil
|
||||
end
|
||||
end
|
||||
inv:set_stack("main", main_slot, mstack)
|
||||
if mstack:get_count() == 0 then
|
||||
me.log("network cleaning up empty main slot now", "error")
|
||||
me.maybemove(self, inv, "main", main_slot, omstack)
|
||||
me.log("network cleaning up empty main slot now, done", "error")
|
||||
end
|
||||
-- me.loan.set_stack(self, inv, loan_slot, ItemStack())
|
||||
if self.bias and self.bias["loan"] then
|
||||
self.bias["loan"][loan_slot] = nil
|
||||
end
|
||||
local on_loan = self.counts[lstack:get_name()]
|
||||
if on_loan and on_loan >= lstack:get_count() + lbias then
|
||||
self.counts[lstack:get_name()] = on_loan - lstack:get_count() - lbias
|
||||
me.log("LOAN: remove_loan down to count "..self.counts[lstack:get_name()], "error")
|
||||
else
|
||||
me.log("wow, free items, network remove_loan fails to find previous loan counts, "..self.counts[lstack:get_name()].." "..lstack:get_name(), "error")
|
||||
self.counts[lstack:get_name()] = 0
|
||||
end
|
||||
|
||||
self:maybemoveloan(inv, loan_slot)
|
||||
end
|
||||
|
||||
-- like me.maybemove
|
||||
function network:maybemoveloan(inv, loan_slot)
|
||||
local loan_size = me.loan.get_size(self, inv)
|
||||
local stack = me.loan.get_stack(self, inv, loan_size)
|
||||
if stack:is_empty() then
|
||||
me.loan.set_size(self, inv, loan_size-1)
|
||||
return self:maybemoveloan(inv, loan_slot)
|
||||
end
|
||||
local do_update = false
|
||||
if loan_size > 1 and loan_slot < loan_size then
|
||||
local stack = me.loan.get_stack(self, inv, loan_size)
|
||||
if stack:is_empty() then -- should not be necessary
|
||||
me.log("network BAD loan", "error")
|
||||
-- This trips with interface place remove on main drawers
|
||||
foobar()
|
||||
end
|
||||
local prev = me.loan.get_stack(self, inv, loan_slot)
|
||||
if prev:get_count() ~= 0 then
|
||||
-- TODO: Should not be necessary, find real problem, full remove, refile check, replace interface
|
||||
if self.byname["loan"][prev:get_name()] then
|
||||
self.byname["loan"][prev:get_name()][prev:get_wear()] = nil
|
||||
end
|
||||
else
|
||||
-- don't remove the loan before, we need the name
|
||||
foobar()
|
||||
end
|
||||
me.log("LOAN: maybemoveloan to "..stack:get_count(), "error")
|
||||
me.loan.set_stack(self, inv, loan_slot, stack)
|
||||
-- me.log("maybemoveloan "..stack:get_name(), "error")
|
||||
-- me.log("maybemoveloan "..stack:get_count(), "error")
|
||||
-- me.log("maybemoveloan "..stack:get_wear(), "error")
|
||||
-- me.log("maybemoveloan "..loan_slot, "error")
|
||||
-- me.log("maybemoveloan "..minetest.serialize(self.byname), "error")
|
||||
-- me.log("maybemoveloan "..minetest.serialize(self.byname["loan"]), "error")
|
||||
-- TODO: Should not be necessary, find real problem, full remove, refile check, replace interface
|
||||
if self.byname["loan"][stack:get_name()] then
|
||||
self.byname["loan"][stack:get_name()][stack:get_wear()] = loan_slot
|
||||
end
|
||||
do_update = true
|
||||
else
|
||||
local stack = me.loan.get_stack(self, inv, loan_size)
|
||||
if stack:get_count() ~= 0 then
|
||||
-- me.log("maybemoveloan "..stack:get_name(), "error")
|
||||
-- me.log("maybemoveloan "..stack:get_count(), "error")
|
||||
-- me.log("maybemoveloan "..stack:get_wear(), "error")
|
||||
-- me.log("maybemoveloan "..loan_slot, "error")
|
||||
-- me.log("maybemoveloan "..minetest.serialize(self.byname), "error")
|
||||
-- me.log("maybemoveloan "..minetest.serialize(self.byname["loan"]), "error")
|
||||
-- TODO: Should not be necessary, find real problem, full remove, refile check, replace interface
|
||||
if self.byname["loan"] and self.byname["loan"][stack:get_name()] then
|
||||
self.byname["loan"][stack:get_name()][stack:get_wear()] = nil
|
||||
end
|
||||
else
|
||||
-- don't remove the loan before, we need the name
|
||||
foobar()
|
||||
end
|
||||
end
|
||||
me.loan.set_size(self, inv, loan_size-1)
|
||||
-- me.log("loan size is now "..me.loan.get_size(self, inv))
|
||||
if do_update then
|
||||
-- update_loan calls us and needs this updated by the time we return
|
||||
self:update_loan(inv, loan_slot)
|
||||
end
|
||||
end
|
||||
|
||||
function network:dump_loans(inv)
|
||||
me.log("COUNTS: dump_loans "..minetest.serialize(self.counts), "error")
|
||||
for i, j in pairs(inv:get_list("loan") or {}) do
|
||||
print(" slot "..dump(i).." "..j:to_string().." "..j:get_meta():get_string("me_store_reference"))
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
if leftovers and not leftovers:is_empty() then
|
||||
microexpansion.log("leftover items when transferring inventory", "warning")
|
||||
finv:add_item(fname, leftover)
|
||||
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)
|
@ -88,13 +88,13 @@ local function write_to_cell(cell, items, item_count)
|
||||
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,17 +111,60 @@ 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," ")))
|
||||
|
||||
-- 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)
|
||||
@ -132,7 +175,7 @@ local function write_drive_cells(pos,network)
|
||||
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")
|
||||
me.log("too many items to store in drive","info")
|
||||
break
|
||||
end
|
||||
size = microexpansion.get_cell_size(cells[cell_idx]:get_name())
|
||||
@ -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()
|
||||
@ -178,8 +222,11 @@ local function take_all(pos,net)
|
||||
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()
|
||||
@ -187,6 +234,7 @@ local function take_all(pos,net)
|
||||
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()
|
||||
@ -204,8 +252,7 @@ local function add_all(pos,net)
|
||||
end
|
||||
end
|
||||
for _,ostack in pairs(items) do
|
||||
me.insert_item(ostack, ctrl_inv, "main")
|
||||
print(ostack)
|
||||
me.insert_item(ostack, net, ctrl_inv, "main")
|
||||
end
|
||||
|
||||
net:update()
|
||||
@ -213,7 +260,7 @@ local function add_all(pos,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,15 +287,15 @@ 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)
|
||||
@ -258,14 +305,12 @@ local function update_drive(pos,_,ev)
|
||||
me.disconnect_drive(pos,false)
|
||||
end
|
||||
end
|
||||
else
|
||||
if fc then
|
||||
elseif fc then
|
||||
if fc.cpos then
|
||||
me.disconnect_drive(pos,false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- [me chest] Register node
|
||||
microexpansion.register_node("drive", {
|
||||
@ -295,14 +340,14 @@ microexpansion.register_node("drive", {
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec",
|
||||
"size[9,9.5]"..
|
||||
"size[9,7.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]
|
||||
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]
|
||||
@ -322,12 +367,12 @@ microexpansion.register_node("drive", {
|
||||
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
|
||||
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
|
||||
else
|
||||
return 1
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, _, _, stack)
|
||||
me.send_event(pos,"item_cap")
|
||||
@ -342,10 +387,12 @@ microexpansion.register_node("drive", {
|
||||
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")
|
||||
-- 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
|
||||
@ -369,8 +416,13 @@ microexpansion.register_node("drive", {
|
||||
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)
|
||||
--ctrl_inv:remove_item("main", ostack)
|
||||
end
|
||||
--print(stack:to_string())
|
||||
|
||||
|
@ -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
|
||||
@ -20,9 +21,17 @@ local function chest_formspec(pos, start_id, listname, page_max, q)
|
||||
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]
|
||||
]]
|
||||
@ -40,7 +49,7 @@ local function chest_formspec(pos, start_id, listname, page_max, q)
|
||||
tooltip[clear;Reset]
|
||||
]]
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected drives!") .. "]"
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected storage!") .. "]"
|
||||
end
|
||||
else
|
||||
list = "label[3,2;" .. minetest.colorize("red", "No connected network!") .. "]"
|
||||
@ -82,7 +91,7 @@ local function update_chest(pos,_,ev)
|
||||
end
|
||||
|
||||
-- [me chest] Register node
|
||||
microexpansion.register_node("term", {
|
||||
me.register_node("term", {
|
||||
description = "ME Terminal",
|
||||
usedfor = "Can interact with storage cells in ME networks",
|
||||
tiles = {
|
||||
@ -124,15 +133,20 @@ microexpansion.register_node("term", {
|
||||
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)
|
||||
me.remove_item(net, inv, "main", stack)
|
||||
end,
|
||||
tube = {
|
||||
can_insert = function(pos, _, stack) --pos, node, stack, direction
|
||||
@ -158,10 +172,9 @@ 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},
|
||||
},
|
||||
@ -171,15 +184,15 @@ microexpansion.register_node("term", {
|
||||
local net,cp = me.get_connected_network(pos)
|
||||
if net then
|
||||
if cp then
|
||||
microexpansion.log("network and ctrl_pos","info")
|
||||
me.log("network and ctrl_pos","info")
|
||||
else
|
||||
microexpansion.log("network but no ctrl_pos","warning")
|
||||
me.log("network but no ctrl_pos","warning")
|
||||
end
|
||||
else
|
||||
if cp then
|
||||
microexpansion.log("no network but ctrl_pos","warning")
|
||||
me.log("no network but ctrl_pos","warning")
|
||||
else
|
||||
microexpansion.log("no network and no ctrl_pos","info")
|
||||
me.log("no network and no ctrl_pos","info")
|
||||
end
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
@ -190,7 +203,7 @@ microexpansion.register_node("term", {
|
||||
if cp then
|
||||
ctrl_inv = net:get_inventory()
|
||||
else
|
||||
microexpansion.log("no network connected","warning")
|
||||
me.log("no network connected","warning")
|
||||
return
|
||||
end
|
||||
local inv
|
||||
@ -243,7 +256,7 @@ microexpansion.register_node("term", {
|
||||
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"))
|
||||
-- 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
|
||||
@ -251,7 +264,7 @@ microexpansion.register_node("term", {
|
||||
space = space - s:get_count()
|
||||
end
|
||||
end
|
||||
microexpansion.move_inv({ inv=pinv, name="main" }, { inv=ctrl_inv, name="main",huge=true }, space)
|
||||
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