Autocrafting improvements

This commit is contained in:
kepler155c
2017-12-23 01:48:36 -05:00
parent 863b7ff600
commit 85c5f542a8
10 changed files with 1059 additions and 232 deletions

View File

@@ -11,6 +11,7 @@ local Util = require('util')
local colors = _G.colors
local multishell = _ENV.multishell
local term = _G.term
local turtle = _G.turtle
multishell.setTitle(multishell.getCurrent(), 'Crafter')
@@ -25,6 +26,7 @@ local inventoryAdapter = ChestAdapter(config.inventory)
local RESOURCE_FILE = 'usr/config/resources.db'
local RECIPES_FILE = 'usr/config/recipes2.db'
local MACHINES_FILE = 'usr/config/machines.db'
local recipes = Util.readTable(RECIPES_FILE) or { }
local resources
@@ -60,14 +62,21 @@ local function getItemQuantity(items, res)
return count
end
local function getItemWithQty(items, res)
local function getItemWithQty(items, res, ignoreNbtHash)
for _,v in pairs(items) do
if res.name == v.name and
((not res.damage and v.maxDamage > 0) or res.damage == v.damage) and
((not res.nbtHash and v.nbtHash) or res.nbtHash == v.nbtHash) then
((ignoreNbtHash and v.nbtHash) or res.nbtHash == v.nbtHash) then
debug('found')
debug(v)
return v
end
end
debug('nope:' .. uniqueKey(res))
local item = Util.shallowCopy(res)
item.count = 0
item.maxCount = 1
return item
end
local function mergeResources(t)
@@ -129,69 +138,78 @@ local function clearGrid()
end
local function gotoMachine(machine)
for _ = 1, machine do
for _ = 1, machine.index do
if not turtle.back() then
return
end
end
return true
end
local function canCraft(recipe, items, count)
count = math.ceil(count / recipe.count)
local icount = Util.size(recipe.ingredients)
local maxSlots = math.floor(16 / icount)
for key,qty in pairs(recipe.ingredients) do
local item = getItem(items, itemDB:splitKey(key))
if not item then
return 0, itemDB:getName(key)
end
local x = math.min(math.floor(item.count / qty), item.maxCount * maxSlots)
count = math.min(x, count)
end
return count, ''
end
local function craftItem(recipe, recipeKey, items, cItem, count)
repeat until not turtle.forward()
local resource = resources[recipeKey]
if not resource or not resource.machine then
cItem.status = 'machine not selected'
return false
return
end
local machine = Util.find(machines, 'order', resource.machine)
if not machine then
cItem.status = 'invalid machine'
return
end
if count == 0 then
cItem.status = 'missing something'
return false
for key in pairs(recipe.ingredients) do
local item = getItemWithQty(items, itemDB:splitKey(key), recipe.ignoreNbtHash)
if item.count == 0 then
cItem.status = 'Missing: ' .. (item.displayName or itemDB:getName(item))
return false
end
end
return
end
local slot = 1
for key,qty in pairs(recipe.ingredients) do
local item = itemDB:get(key)
if not item then
cItem.status = 'failed'
return false
local item = getItemWithQty(items, itemDB:splitKey(key), recipe.ignoreNbtHash)
if item.count == 0 then
debug(item)
cItem.status = 'Missing: ' .. (item.displayName or itemDB:getName(item))
return
end
local c = count * qty
while c > 0 do
local maxCount = math.min(c, item.maxCount)
inventoryAdapter:provide(item, maxCount, slot)
if turtle.getItemCount(slot) == 0 then -- ~= maxCount then FIXXX !!!
cItem.status = 'failed'
return false
if turtle.getItemCount(slot) ~= maxCount then -- ~= maxCount then FIXXX !!!
cItem.status = 'Extract failed: ' .. (item.displayName or itemDB:getName(item))
return
end
c = c - maxCount
slot = slot + 1
end
end
if not gotoMachine(resource.machine) then
if not gotoMachine(machine) then
cItem.status = 'failed to find machine'
else
if resource.dir == 'up' then
if machine.empty then
local s, l = pcall(Peripheral.call,
turtle.getAction(machine.dir).side, 'list')
if not s then
cItem.status = l
return
elseif not Util.empty(l) then
cItem.status = 'machine busy'
return
end
end
if machine.dir == 'up' then
turtle.emptyInventory(turtle.dropUp)
else
turtle.emptyInventory(turtle.dropDown)
@@ -212,15 +230,7 @@ local function expandList(list)
for key,qty in pairs(recipe.ingredients) do
local item = getItemWithQty(items, itemDB:splitKey(key))
if not item then
item = itemDB:get(key)
if not item then
--item = itemDB:splitKey(key)
break
end
item.count = 0
end
local item = getItemWithQty(items, itemDB:splitKey(key), recipe.ignoreNbtHash)
local need = qty * count
local irecipe = recipes[key]
@@ -271,6 +281,7 @@ end
local function craftItems(craftList)
expandList(craftList)
lastItems = inventoryAdapter:listItems() -- refresh counts
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
@@ -315,10 +326,17 @@ local function loadResources()
resources = Util.readTable(RESOURCE_FILE) or { }
for k,v in pairs(resources) do
Util.merge(v, itemDB:splitKey(k))
if not v.machine then
local recipe = recipes[k]
v.machine = recipe.machine
v.dir = recipe.dir or 'down'
if v.dir then
for _,m in pairs(machines) do
if m.index == v.machine and m.dir == v.dir then
v.machine = m.order
v.dir = nil
break
end
end
if v.dir then
error('did not find')
end
end
end
end
@@ -328,6 +346,7 @@ local function saveResources()
for k,v in pairs(resources) do
v = Util.shallowCopy(v)
v.name = nil
v.damage = nil
v.nbtHash = nil
@@ -359,6 +378,9 @@ local function findMachines()
if not machine then
local _
_, machine = turtle.getAction(dir).inspect()
if not machine or type(machine) ~= 'table' then
machine = { name = 'Unknown' }
end
end
if machine and type(machine) == 'table' then
local rawName = getName(side) or machine.name
@@ -384,6 +406,16 @@ local function findMachines()
getMachine('up')
index = index + 1
until not turtle.back()
local mf = Util.readTable(MACHINES_FILE) or { }
for _,m in pairs(machines) do
local m2 = Util.find(mf, 'order', m.order)
if m2 then
m.name = m2.name or m.name
m.empty = m2.empty
m.ignore = m2.ignore
end
end
end
local function jobMonitor()
@@ -458,6 +490,10 @@ local itemPage = UI.Page {
},
machines = UI.SlideOut {
backgroundColor = colors.cyan,
titleBar = UI.TitleBar {
title = 'Select Machine',
previousPage = true,
},
grid = UI.ScrollingGrid {
y = 2, ey = -4,
values = machines,
@@ -476,7 +512,6 @@ local itemPage = UI.Page {
x = -9, y = -2,
text = 'Cancel', event = 'cancelMachine',
},
statusBar = UI.StatusBar(),
},
statusBar = UI.StatusBar { }
}
@@ -491,11 +526,7 @@ function itemPage:enable(item)
self:focusFirst()
end
function itemPage.machines:draw()
UI.Window.draw(self)
self:centeredWrite(1, 'Select machine', nil, colors.yellow)
end
--[[
function itemPage.machines:eventHandler(event)
if event.type == 'grid_focus_row' then
self.statusBar:setStatus(string.format('%d %s', event.selected.index, event.selected.dir))
@@ -504,6 +535,7 @@ function itemPage.machines:eventHandler(event)
end
return true
end
]]
function itemPage:eventHandler(event)
if event.type == 'form_cancel' then
@@ -513,17 +545,18 @@ function itemPage:eventHandler(event)
UI:setPage('learn', self.item)
elseif event.type == 'setMachine' then
self.item.machine = self.machines.grid:getSelected().index
self.item.dir = self.machines.grid:getSelected().dir
self.item.machine = self.machines.grid:getSelected().order
self.machines:hide()
elseif event.type == 'cancelMachine' then
self.machines:hide()
elseif event.type == 'selectMachine' then
self.machines.grid:update()
local machineCopy = Util.shallowCopy(machines)
Util.filterInplace(machineCopy, function(m) return not m.ignore end)
self.machines.grid:setValues(machineCopy)
if self.item.machine then
local _, index = Util.find(machines, 'index', self.item.machine)
local _, index = Util.find(machineCopy, 'order', self.item.machine)
if index then
self.machines.grid:setIndex(index)
end
@@ -544,7 +577,6 @@ function itemPage:eventHandler(event)
end
filtered.low = tonumber(filtered.low)
filtered.machine = self.item.machine
filtered.dir = self.item.dir
if values.ignoreDamage == true then
filtered.damage = 0
@@ -685,11 +717,113 @@ function learnPage:eventHandler(event)
return true
end
local machinesPage = UI.Page {
titleBar = UI.TitleBar {
previousPage = true,
title = 'Machines',
},
grid = UI.Grid {
y = 2, ey = -2,
values = machines,
columns = {
{ heading = 'Name', key = 'name' },
{ heading = 'Side', key = 'dir', width = 5 },
{ heading = 'Index', key = 'index', width = 5 },
},
sortColumn = 'order',
},
detail = UI.SlideOut {
backgroundColor = colors.cyan,
form = UI.Form {
x = 1, y = 2, ex = -1, ey = -2,
[1] = UI.TextEntry {
formLabel = 'Name', formKey = 'name', help = '...',
limit = 64,
},
[2] = UI.Chooser {
width = 7,
formLabel = 'Hidden', formKey = 'ignore',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Do not show this machine'
},
[3] = UI.Chooser {
width = 7,
formLabel = 'Empty', formKey = 'empty',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Check if machine is empty before crafting'
},
},
statusBar = UI.StatusBar(),
},
statusBar = UI.StatusBar {
values = 'Select Machine',
},
accelerators = {
h = 'toggle_hidden',
}
}
function machinesPage:enable()
self.grid:update()
UI.Page.enable(self)
end
function machinesPage.detail:eventHandler(event)
if event.type == 'focus_change' then
self.statusBar:setStatus(event.focused.help)
end
return UI.SlideOut.eventHandler(self, event)
end
function machinesPage.grid:getRowTextColor(row, selected)
if row.ignore then
return colors.yellow
end
return UI.Grid:getRowTextColor(row, selected)
end
function machinesPage:eventHandler(event)
if event.type == 'grid_select' then
self.detail.form:setValues(event.selected)
self.detail:show()
elseif event.type == 'toggle_hidden' then
local selected = self.grid:getSelected()
if selected then
selected.ignore = not selected.ignore
Util.writeTable(MACHINES_FILE, machines)
self:draw()
end
elseif event.type == 'form_complete' then
self.detail.form.values.empty = self.detail.form.values.empty == true
self.detail.form.values.ignore = self.detail.form.values.ignore == true
Util.writeTable(MACHINES_FILE, machines)
self.detail:hide()
elseif event.type == 'form_cancel' then
self.detail:hide()
else
UI.Page.eventHandler(self, event)
end
return true
end
local listingPage = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Forget', event = 'forget' },
{ text = 'Refresh', event = 'refresh' },
{ text = 'Machines', event = 'machines' },
{ text = 'Refresh', event = 'refresh', x = -9 },
},
},
grid = UI.Grid {
@@ -768,6 +902,9 @@ function listingPage:eventHandler(event)
self.grid:draw()
self.statusBar.filter:focus()
elseif event.type == 'machines' then
UI:setPage('machines')
elseif event.type == 'craft' then
UI:setPage('craft', self.grid:getSelected())
@@ -823,8 +960,8 @@ function listingPage:applyFilter()
self.grid:setValues(t)
end
loadResources()
findMachines()
loadResources()
repeat until not turtle.forward()
clearGrid()
jobMonitor()
@@ -832,6 +969,7 @@ lastItems = inventoryAdapter:listItems()
UI:setPages({
listing = listingPage,
machines = machinesPage,
item = itemPage,
learn = learnPage,
})
@@ -851,14 +989,16 @@ Event.onInterval(30, function()
turtle.refuel()
end
lastItems = inventoryAdapter:listItems()
local craftList = watchResources(lastItems)
if lastItems then
local craftList = watchResources(lastItems)
jobListGrid:setValues(craftList)
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
jobListGrid:setValues(craftList)
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
craftItems(craftList)
craftItems(craftList)
end
end)
UI:pullEvents()