rework milo crafting

This commit is contained in:
kepler155c
2018-11-10 21:01:53 -05:00
parent aff05f8587
commit bc9028f0c7
10 changed files with 131 additions and 85 deletions

View File

@@ -74,7 +74,7 @@ function Milo:resetCraftingStatus()
for _,key in pairs(Util.keys(self.context.craftingQueue)) do for _,key in pairs(Util.keys(self.context.craftingQueue)) do
local item = self.context.craftingQueue[key] local item = self.context.craftingQueue[key]
if item.crafted >= item.count then if item.crafted >= item.requested then
self.context.craftingQueue[key] = nil self.context.craftingQueue[key] = nil
end end
end end
@@ -193,7 +193,7 @@ end
function Milo:craftAndEject(item, count) function Milo:craftAndEject(item, count)
local request = self:makeRequest(item, count, function(request) local request = self:makeRequest(item, count, function(request)
-- eject rest when finished crafted -- eject rest when finished crafted
return self:eject(item, request.count) return self:eject(item, request.requested)
end) end)
-- predict that we will eject that amount -- predict that we will eject that amount
@@ -238,7 +238,7 @@ function Milo:makeRequest(item, count, callback)
if request.craft > 0 then if request.craft > 0 then
item = Util.shallowCopy(item) item = Util.shallowCopy(item)
item.count = request.craft item.requested = request.craft
item.callback = callback item.callback = callback
self:requestCrafting(item) self:requestCrafting(item)
end end

View File

@@ -27,12 +27,12 @@ listCount = 0,
self.localName = modem.getNameLocal() self.localName = modem.getNameLocal()
Event.on({ 'device_attach', 'device_detach' }, function(e, dev) Event.on({ 'device_attach', 'device_detach' }, function(e, dev)
--_debug('%s: %s', e, tostring(dev)) _debug('%s: %s', e, tostring(dev))
self:initStorage() self:initStorage()
end) end)
Event.onInterval(15, function() Event.onInterval(15, function()
self:showStorage() self:showStorage()
-- _debug('STORAGE: cache: %d/%d', self.hits, self.misses) _debug('STORAGE: cache: %d/%d', self.hits, self.misses)
end) end)
end end
@@ -248,17 +248,8 @@ function Storage:trash(source, slot, count)
end end
function Storage:import(source, slot, count, item) function Storage:import(source, slot, count, item)
return self:insert(slot, count, nil, item, source)
end
function Storage:insert(slot, qty, toSlot, item, source)
local total = 0 local total = 0
-- toSlot is not really valid with this adapter
if toSlot then
error('Storage: toSlot is not valid')
end
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':') local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
if not self.cache then if not self.cache then
@@ -266,9 +257,9 @@ function Storage:insert(slot, qty, toSlot, item, source)
end end
local function insert(adapter) local function insert(adapter)
local amount = adapter:insert(slot, qty, toSlot, source or self.localName) local amount = adapter:insert(slot, count, nil, source or self.localName)
if amount > 0 then if amount > 0 then
_debug('INS: %s(%d): %s[%d] -> %s', _G._debug('INS: %s(%d): %s[%d] -> %s',
item.name, amount, item.name, amount,
source or self.localName, slot, adapter.name) source or self.localName, slot, adapter.name)
self.dirty = true self.dirty = true
@@ -284,7 +275,7 @@ _debug('INS: %s(%d): %s[%d] -> %s',
end end
]] ]]
end end
qty = qty - amount count = count - amount
total = total + amount total = total + amount
end end
@@ -293,8 +284,8 @@ _debug('INS: %s(%d): %s[%d] -> %s',
-- TODO: proper checking using ignore dmg/nbt -- TODO: proper checking using ignore dmg/nbt
if remote.lock == key or remote.lock == item.name then if remote.lock == key or remote.lock == item.name then
insert(remote.adapter) insert(remote.adapter)
if qty > 0 then -- TODO: only if void flag set if count > 0 then -- TODO: only if void flag set
total = total + self:trash(source, slot, qty) total = total + self:trash(source, slot, count)
end end
return total return total
end end
@@ -302,7 +293,7 @@ _debug('INS: %s(%d): %s[%d] -> %s',
if self.cache[key] then -- is this item in some chest if self.cache[key] then -- is this item in some chest
for _, adapter in self:onlineAdapters() do for _, adapter in self:onlineAdapters() do
if qty <= 0 then if count <= 0 then
break break
end end
if adapter.cache and adapter.cache[key] and not adapter.lock then if adapter.cache and adapter.cache[key] and not adapter.lock then
@@ -313,7 +304,7 @@ _debug('INS: %s(%d): %s[%d] -> %s',
-- high to low priority -- high to low priority
for remote in self:onlineAdapters() do for remote in self:onlineAdapters() do
if qty <= 0 then if count <= 0 then
break break
end end
if not remote.lock then if not remote.lock then

View File

@@ -16,9 +16,9 @@ local Craft = {
MACHINE_LOOKUP = 'usr/config/machine_crafting.db', MACHINE_LOOKUP = 'usr/config/machine_crafting.db',
} }
local function clearGrid(inventoryAdapter) local function clearGrid(storage)
turtle.eachFilledSlot(function(slot) turtle.eachFilledSlot(function(slot)
inventoryAdapter:insert(slot.index, slot.count, nil, slot) storage:import(storage.localName, slot.index, slot.count, slot)
end) end)
for i = 1, 16 do for i = 1, 16 do
@@ -76,7 +76,7 @@ function Craft.sumIngredients(recipe)
return t return t
end end
local function machineCraft(recipe, inventoryAdapter, machineName, request, count, item) local function machineCraft(recipe, storage, machineName, request, count, item)
local machine = device[machineName] local machine = device[machineName]
if not machine then if not machine then
request.status = 'machine not found' request.status = 'machine not found'
@@ -94,7 +94,7 @@ local function machineCraft(recipe, inventoryAdapter, machineName, request, coun
local xferred = { } local xferred = { }
for k,v in pairs(recipe.ingredients) do for k,v in pairs(recipe.ingredients) do
local provided = inventoryAdapter:provide(splitKey(v), count, k, machineName) local provided = storage:provide(splitKey(v), count, k, machineName)
xferred[k] = { xferred[k] = {
key = v, key = v,
count = provided, count = provided,
@@ -103,7 +103,7 @@ local function machineCraft(recipe, inventoryAdapter, machineName, request, coun
-- take back out whatever we put in -- take back out whatever we put in
for k2,v2 in pairs(xferred) do for k2,v2 in pairs(xferred) do
if v2.count > 0 then if v2.count > 0 then
inventoryAdapter:import(machineName, k2, v2.count, splitKey(v2.key)) storage:import(machineName, k2, v2.count, splitKey(v2.key))
end end
end end
request.status = 'Invalid recipe' request.status = 'Invalid recipe'
@@ -116,8 +116,8 @@ local function machineCraft(recipe, inventoryAdapter, machineName, request, coun
item.pending[recipe.result] = count * recipe.count item.pending[recipe.result] = count * recipe.count
end end
local function turtleCraft(recipe, inventoryAdapter, request, count) local function turtleCraft(recipe, storage, request, count)
if not clearGrid(inventoryAdapter) then if not clearGrid(storage) then
request.status = 'grid in use' request.status = 'grid in use'
request.statusCode = Craft.STATUS_ERROR request.statusCode = Craft.STATUS_ERROR
return return
@@ -125,7 +125,7 @@ local function turtleCraft(recipe, inventoryAdapter, request, count)
for k,v in pairs(recipe.ingredients) do for k,v in pairs(recipe.ingredients) do
local item = splitKey(v) local item = splitKey(v)
if inventoryAdapter:provide(item, count, k) ~= count then if storage:provide(item, count, k) ~= count then
-- FIX: ingredients cannot be stacked -- FIX: ingredients cannot be stacked
request.status = 'unknown error' request.status = 'unknown error'
request.statusCode = Craft.STATUS_ERROR request.statusCode = Craft.STATUS_ERROR
@@ -137,20 +137,23 @@ local function turtleCraft(recipe, inventoryAdapter, request, count)
if turtle.craft() then if turtle.craft() then
request.crafted = request.crafted + count * recipe.count request.crafted = request.crafted + count * recipe.count
request.status = 'crafted' request.status = 'crafted'
request.statusCode = Craft.STATUS_INFO request.statusCode = Craft.STATUS_SUCCESS
return true else
request.status = 'Failed to craft'
request.statusCode = Craft.STATUS_ERROR
end end
request.status = 'Failed to craft' clearGrid(storage)
request.statusCode = Craft.STATUS_ERROR return request.statusCode == Craft.STATUS_SUCCESS
end end
function Craft.processPending(item, inventoryAdapter) function Craft.processPending(item, storage)
for key, count in pairs(item.pending) do for key, count in pairs(item.pending) do
local imported = inventoryAdapter.activity[key] local imported = storage.activity[key]
if imported then if imported then
local amount = math.min(imported, count) local amount = math.min(imported, count)
inventoryAdapter.activity[key] = imported - amount storage.activity[key] = imported - amount
item.pending[key] = count - amount item.pending[key] = count - amount
item.ingredients[key].crafted = item.ingredients[key].crafted + amount
if item.pending[key] <= 0 then if item.pending[key] <= 0 then
item.pending[key] = nil item.pending[key] = nil
end end
@@ -158,7 +161,7 @@ function Craft.processPending(item, inventoryAdapter)
end end
end end
function Craft.craftRecipe(recipe, count, inventoryAdapter, origItem) function Craft.craftRecipe(recipe, count, storage, origItem)
if type(recipe) == 'string' then if type(recipe) == 'string' then
recipe = Craft.recipes[recipe] recipe = Craft.recipes[recipe]
if not recipe then if not recipe then
@@ -166,11 +169,7 @@ function Craft.craftRecipe(recipe, count, inventoryAdapter, origItem)
end end
end end
local crafted = Craft.craftRecipeInternal(recipe, count, inventoryAdapter, origItem) return Craft.craftRecipeInternal(recipe, count, storage, origItem)
origItem.crafted = math.min(origItem.count, origItem.crafted + crafted)
return crafted
end end
local function adjustCounts(recipe, count, ingredients) local function adjustCounts(recipe, count, ingredients)
@@ -184,9 +183,15 @@ local function adjustCounts(recipe, count, ingredients)
result.count = result.count + (count * recipe.count) result.count = result.count + (count * recipe.count)
end end
function Craft.craftRecipeInternal(recipe, count, inventoryAdapter, origItem) function Craft.craftRecipeInternal(recipe, count, storage, origItem)
local request = origItem.ingredients[recipe.result] local request = origItem.ingredients[recipe.result]
if origItem.pending[recipe.result] then
request.status = 'processing'
request.statusCode = Craft.STATUS_INFO
return 0
end
local canCraft = Craft.getCraftableAmount(recipe, count, origItem.ingredients) local canCraft = Craft.getCraftableAmount(recipe, count, origItem.ingredients)
if not origItem.forceCrafting and canCraft == 0 then if not origItem.forceCrafting and canCraft == 0 then
return 0 return 0
@@ -199,6 +204,8 @@ function Craft.craftRecipeInternal(recipe, count, inventoryAdapter, origItem)
count = canCraft count = canCraft
end end
_G._debug({'eval', recipe.result, count })
local maxCount = recipe.maxCount or math.floor(64 / recipe.count) local maxCount = recipe.maxCount or math.floor(64 / recipe.count)
for key,icount in pairs(Craft.sumIngredients(recipe)) do for key,icount in pairs(Craft.sumIngredients(recipe)) do
@@ -213,8 +220,9 @@ function Craft.craftRecipeInternal(recipe, count, inventoryAdapter, origItem)
if not irecipe then if not irecipe then
return 0 return 0
end end
local iqty = need - itemCount local iqty = need - itemCount
local crafted = Craft.craftRecipeInternal(irecipe, iqty, inventoryAdapter, origItem) local crafted = Craft.craftRecipeInternal(irecipe, iqty, storage, origItem)
if not origItem.forceCrafting and crafted < iqty then if not origItem.forceCrafting and crafted < iqty then
return 0 return 0
end end
@@ -224,23 +232,16 @@ function Craft.craftRecipeInternal(recipe, count, inventoryAdapter, origItem)
end end
end end
local crafted = 0 local crafted = 0
while canCraft > 0 do while canCraft > 0 do
if origItem.pending[recipe.result] then
request.status = 'processing'
request.statusCode = Craft.STATUS_INFO
break
end
local batch = math.min(canCraft, maxCount) local batch = math.min(canCraft, maxCount)
local machine = Craft.machineLookup[recipe.result]
if Craft.machineLookup[recipe.result] then _G._debug({ 'crafting', recipe.result, batch })
if not machineCraft(recipe, inventoryAdapter, if machine then
Craft.machineLookup[recipe.result], request, batch, origItem) then if not machineCraft(recipe, storage, machine, request, batch, origItem) then
break break
end end
elseif not turtleCraft(recipe, inventoryAdapter, request, batch) then elseif not turtleCraft(recipe, storage, request, batch) then
break break
end end
@@ -275,7 +276,7 @@ end
-- determine the full list of ingredients needed to craft -- determine the full list of ingredients needed to craft
-- a quantity of a recipe. -- a quantity of a recipe.
function Craft.getResourceList(inRecipe, items, inCount) function Craft.getResourceList(inRecipe, items, inCount, pending)
local summed = { } local summed = { }
local function sumItems(recipe, key, count) local function sumItems(recipe, key, count)
@@ -295,6 +296,10 @@ function Craft.getResourceList(inRecipe, items, inCount)
local used = math.min(summedItem.count, total) local used = math.min(summedItem.count, total)
local need = total - used local need = total - used
if pending and pending[key] then
need = need - pending[key]
end
if recipe.craftingTools and recipe.craftingTools[key] then if recipe.craftingTools and recipe.craftingTools[key] then
summedItem.total = 1 summedItem.total = 1
if summedItem.count > 0 then if summedItem.count > 0 then
@@ -325,8 +330,13 @@ function Craft.getResourceList(inRecipe, items, inCount)
end end
inCount = math.ceil(inCount / inRecipe.count) inCount = math.ceil(inCount / inRecipe.count)
for ikey,iqty in pairs(Craft.sumIngredients(inRecipe)) do if pending and pending[inRecipe.result] then
sumItems(inRecipe, ikey, math.ceil(inCount * iqty)) inCount = inCount - pending[inRecipe.result]
end
if inCount > 0 then
for ikey,iqty in pairs(Craft.sumIngredients(inRecipe)) do
sumItems(inRecipe, ikey, math.ceil(inCount * iqty))
end
end end
return summed return summed
@@ -339,7 +349,7 @@ function Craft.getResourceList4(inRecipe, items, count)
end end
-- given a certain quantity, return how many of those can be crafted -- given a certain quantity, return how many of those can be crafted
function Craft.getCraftableAmount(inRecipe, count, items, missing) function Craft.getCraftableAmount(inRecipe, inCount, items, missing)
local function sumItems(recipe, summedItems, count) local function sumItems(recipe, summedItems, count)
local canCraft = 0 local canCraft = 0
@@ -367,7 +377,7 @@ function Craft.getCraftableAmount(inRecipe, count, items, missing)
return canCraft return canCraft
end end
return sumItems(inRecipe, { }, math.ceil(count / inRecipe.count)) return sumItems(inRecipe, { }, math.ceil(inCount / inRecipe.count))
end end
function Craft.loadRecipes() function Craft.loadRecipes()

17
milo/apps/water.lua Normal file
View File

@@ -0,0 +1,17 @@
local os = _G.os
local turtle = _G.turtle
while true do
turtle.placeDown('minecraft:bucket:0')
turtle.placeDown('minecraft:glass_bottle:0')
for k,v in pairs(turtle.getInventory()) do
if v.name == 'minecraft:concrete_powder' then
turtle.select(k)
for _ = 1, v.count do
turtle.placeDown()
turtle.digDown()
end
end
end
os.pullEvent('turtle_inventory')
end

View File

@@ -15,10 +15,11 @@ function craftTask:craft(recipe, item)
if Milo:isCraftingPaused() then if Milo:isCraftingPaused() then
return return
end end
Craft.processPending(item, context.storage) Craft.processPending(item, context.storage)
item.ingredients = Craft.getResourceList(recipe, Milo:listItems(), item.count - item.crafted) --TODO: this needs to take into account what is pending
item.ingredients = Craft.getResourceList(
recipe, Milo:listItems(), item.requested - item.crafted, item.pending)
for k, v in pairs(item.ingredients) do for k, v in pairs(item.ingredients) do
v.crafted = v.used v.crafted = v.used
@@ -29,24 +30,39 @@ function craftTask:craft(recipe, item)
v.statusCode = Craft.STATUS_ERROR v.statusCode = Craft.STATUS_ERROR
end end
end end
item.ingredients[recipe.result] = Util.shallowCopy(item) item.ingredients[recipe.result] = item
item.ingredients[recipe.result].total = item.count item.ingredients[recipe.result].total = item.count
item.ingredients[recipe.result].crafted = item.crafted item.ingredients[recipe.result].crafted = item.crafted
Craft.craftRecipe(recipe, item.count - item.crafted, context.storage, item) _G._p2 = item
Milo:clearGrid() if not item.history then
item.history = { }
end
local t = Util.shallowCopy(item)
t.history = { input = { }, output = { } }
for k,v in pairs(item.ingredients) do
t.history.input[k] = Util.shallowCopy(v)
end
table.insert(item.history, t)
Craft.craftRecipe(recipe, item.requested - item.crafted, context.storage, item)
for k,v in pairs(item.ingredients) do
t.history.output[k] = Util.shallowCopy(v)
end
end end
function craftTask:cycle() function craftTask:cycle()
for _,key in pairs(Util.keys(context.craftingQueue)) do for _,key in pairs(Util.keys(context.craftingQueue)) do
local item = context.craftingQueue[key] local item = context.craftingQueue[key]
if item.count - item.crafted > 0 then if item.requested - item.crafted > 0 then
local recipe = Craft.findRecipe(key) local recipe = Craft.findRecipe(key)
if recipe then if recipe then
sync(turtle, function() sync(turtle, function()
self:craft(recipe, item) self:craft(recipe, item)
end) end)
if item.callback and item.crafted >= item.count then if item.callback and item.crafted >= item.requested then
item.callback(item) -- invoke callback item.callback(item) -- invoke callback
end end
elseif not context.controllerAdapter then elseif not context.controllerAdapter then

View File

@@ -100,7 +100,7 @@ function craftPage.wizard.pages.resources:enable()
local count = tonumber(self.parent.quantity.count.value) local count = tonumber(self.parent.quantity.count.value)
local recipe = Craft.findRecipe(craftPage.item) local recipe = Craft.findRecipe(craftPage.item)
if recipe then if recipe then
local ingredients = Craft.getResourceList(recipe, items, count) local ingredients = Craft.getResourceList4(recipe, items, count)
for _,v in pairs(ingredients) do for _,v in pairs(ingredients) do
v.displayName = itemDB:getName(v) v.displayName = itemDB:getName(v)
end end
@@ -117,11 +117,11 @@ function craftPage:eventHandler(event)
elseif event.type == 'accept' then elseif event.type == 'accept' then
local item = Util.shallowCopy(self.item) local item = Util.shallowCopy(self.item)
item.count = tonumber(self.wizard.pages.quantity.count.value) item.requested = tonumber(self.wizard.pages.quantity.count.value)
item.forceCrafting = true item.forceCrafting = true
if self.wizard.pages.quantity.eject.value then if self.wizard.pages.quantity.eject.value then
item.callback = function(request) item.callback = function(request)
Milo:eject(item, request.count) Milo:eject(item, request.requested)
end end
end end
Milo:requestCrafting(item) Milo:requestCrafting(item)

View File

@@ -9,22 +9,35 @@ local function filter(a)
return a.imports return a.imports
end end
-- TODO: ignore damage/nbt
function ImportTask:cycle(context) function ImportTask:cycle(context)
for inventory in context.storage:filterActive('machine', filter) do for inventory in context.storage:filterActive('machine', filter) do
for _, entry in pairs(inventory.imports) do for _, entry in pairs(inventory.imports) do
local function itemMatchesFilter(item)
if not entry.ignoreDamage and not entry.ignoreNbtHash then
return entry.filter[item.key]
end
for key in pairs(entry.filter) do
local v = Milo:splitKey(key)
if item.name == v.name and
(entry.ignoreDamage or item.damage == v.damage) and
(entry.ignoreNbtHash or item.nbtHash == v.nbtHash) then
return true
end
end
end
local function matchesFilter(item) local function matchesFilter(item)
if not entry.filter then if not entry.filter then
return true return true
end end
local key = Milo:uniqueKey(item)
if entry.blacklist then if entry.blacklist then
return not entry.filter[key] return not itemMatchesFilter(item)
end end
return entry.filter[key]
return itemMatchesFilter(item)
end end
local function importSlot(slotNo) local function importSlot(slotNo)

View File

@@ -47,9 +47,8 @@ function jobMonitor:updateList(craftList)
for _,v in pairs(craftList) do for _,v in pairs(craftList) do
table.insert(t, v) table.insert(t, v)
v.index = #t v.index = #t
v.showRemaining = true for k2,v2 in pairs(v.ingredients or { }) do
for k2,v2 in pairs(v.ingredients) do if v2.key ~= v.key --[[and v2.statusCode ]] then
if v2.key ~= v.key and v2.statusCode then
table.insert(t, v2) table.insert(t, v2)
if not v2.displayName then if not v2.displayName then
v2.displayName = itemDB:getName(k2) v2.displayName = itemDB:getName(k2)
@@ -67,12 +66,12 @@ end
function jobMonitor.grid:getDisplayValues(row) function jobMonitor.grid:getDisplayValues(row)
row = Util.shallowCopy(row) row = Util.shallowCopy(row)
if row.showRemaining then if row.requested then
row.remaining = math.max(0, row.count - row.crafted) row.remaining = math.max(0, row.requested - row.crafted)
else else
row.displayName = ' ' .. row.displayName row.displayName = ' ' .. row.displayName
end end
row.progress = string.format('%d/%d', row.crafted, row.count) --row.progress = string.format('%d/%d', row.crafted, row.count)
return row return row
end end

View File

@@ -95,7 +95,7 @@ local function client(socket)
local transferred = context.storage:export( local transferred = context.storage:export(
context.localName, context.localName,
nil, nil,
request.count, request.requested,
data.item) data.item)
turtle.eachFilledSlot(function(slot) turtle.eachFilledSlot(function(slot)

View File

@@ -29,7 +29,7 @@ function ReplenishTask:cycle(context)
Milo:requestCrafting({ Milo:requestCrafting({
damage = res.ignoreDamage and 0 or item.damage, damage = res.ignoreDamage and 0 or item.damage,
nbtHash = nbtHash, nbtHash = nbtHash,
count = res.low - count, requested = res.low - count,
name = item.name, name = item.name,
displayName = item.displayName, displayName = item.displayName,
replenish = true, replenish = true,
@@ -37,7 +37,7 @@ function ReplenishTask:cycle(context)
else else
local request = context.craftingQueue[Milo:uniqueKey(item)] local request = context.craftingQueue[Milo:uniqueKey(item)]
if request and request.replenish then if request and request.replenish then
request.count = request.crafted --request.count = request.crafted
end end
end end
end end