plethora crafter rename to milo - wip

This commit is contained in:
kepler155c
2018-10-23 22:32:25 -04:00
parent a19960959b
commit 9664077f2e
27 changed files with 795 additions and 1520 deletions

View File

@@ -0,0 +1,24 @@
local Milo = require('milo')
local Util = require('util')
local Autocraft = {
priority = 100,
}
function Autocraft:cycle(context)
local list = { }
for _,res in pairs(context.resources) do
if res.auto then
res = Util.shallowCopy(res)
res.count = 256
list[Milo:uniqueKey(res)] = res
end
end
if not Util.empty(list) then
Milo:craftItems(list)
end
end
Milo:registerTask(Autocraft)

View File

@@ -0,0 +1,177 @@
local Craft = require('turtle.craft')
local itemDB = require('itemDB')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local demandCrafting = { }
local craftPage = UI.Page {
titleBar = UI.TitleBar { },
wizard = UI.Wizard {
y = 2, ey = -2,
pages = {
quantity = UI.Window {
index = 1,
text = UI.Text {
x = 6, y = 3,
value = 'Quantity',
},
count = UI.TextEntry {
x = 15, y = 3, width = 10,
limit = 6,
value = 1,
},
ejectText = UI.Text {
x = 6, y = 4,
value = 'Eject',
},
eject = UI.Chooser {
x = 15, y = 4, width = 7,
value = true,
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
},
},
resources = UI.Window {
index = 2,
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Name', key = 'displayName' },
{ heading = 'Total', key = 'total' , width = 5 },
{ heading = 'Used', key = 'used' , width = 5 },
{ heading = 'Need', key = 'need' , width = 5 },
},
sortColumn = 'displayName',
},
},
},
},
}
function craftPage:enable(item)
self.item = item
self:focusFirst()
self.titleBar.title = itemDB:getName(item)
-- self.wizard.pages.quantity.eject.value = true
UI.Page.enable(self)
end
function craftPage.wizard.pages.resources.grid:getDisplayValues(row)
local function dv(v)
if v == 0 then
return ''
end
return Util.toBytes(v)
end
row = Util.shallowCopy(row)
row.total = Util.toBytes(row.total)
row.used = dv(row.used)
row.need = dv(row.need)
return row
end
function craftPage.wizard.pages.resources.grid:getRowTextColor(row, selected)
if row.need > 0 then
return colors.orange
end
return UI.Grid:getRowTextColor(row, selected)
end
function craftPage.wizard:eventHandler(event)
if event.type == 'nextView' then
local count = tonumber(self.pages.quantity.count.value)
if not count or count <= 0 then
self.pages.quantity.count.backgroundColor = colors.red
self.pages.quantity.count:draw()
return false
end
self.pages.quantity.count.backgroundColor = colors.black
end
return UI.Wizard.eventHandler(self, event)
end
function craftPage.wizard.pages.resources:enable()
local items = Milo:listItems()
local count = tonumber(self.parent.quantity.count.value)
local recipe = Craft.findRecipe(craftPage.item)
if recipe then
local ingredients = Craft.getResourceList4(recipe, items, count)
for _,v in pairs(ingredients) do
v.displayName = itemDB:getName(v)
end
self.grid:setValues(ingredients)
else
self.grid:setValues({ })
end
return UI.Window.enable(self)
end
function craftPage:eventHandler(event)
if event.type == 'cancel' then
UI:setPreviousPage()
elseif event.type == 'accept' then
local key = Milo:uniqueKey(self.item)
demandCrafting[key] = Util.shallowCopy(self.item)
demandCrafting[key].count = tonumber(self.wizard.pages.quantity.count.value)
demandCrafting[key].ocount = demandCrafting[key].count
demandCrafting[key].forceCrafting = true
demandCrafting[key].eject = self.wizard.pages.quantity.eject.value == true
UI:setPreviousPage()
else
return UI.Page.eventHandler(self, event)
end
return true
end
local demandCraftingTask = {
priority = 20,
}
function demandCraftingTask:cycle(context)
local demandCrafted = { }
-- look directly at the adapter import activity to determine
-- if the item was imported into storage from any source.
-- The item does NOT need to come from the machine that did
-- the crafting.
for _,key in pairs(Util.keys(demandCrafting)) do
local item = demandCrafting[key]
local imported = context.inventoryAdapter.activity[key]
if imported then
item.crafted = math.min(imported, item.count)
item.count = math.max(0, item.count - item.crafted)
context.inventoryAdapter.activity[key] = imported - item.crafted
end
demandCrafted[key] = item
end
if Util.size(demandCrafted) > 0 then
Milo:craftItems(demandCrafted)
end
for _,key in pairs(Util.keys(demandCrafting)) do
local item = demandCrafting[key]
if item.crafted then
item.count = math.max(0, item.count - item.crafted)
if item.count <= 0 then
item.statusCode = 'success'
demandCrafting[key] = nil
if item.eject then
Milo:eject(item, item.ocount)
end
end
end
end
end
UI:addPage('craft', craftPage)
Milo:registerTask(demandCraftingTask)

View File

@@ -0,0 +1,31 @@
local itemDB = require('itemDB')
local Milo = require('milo')
local device = _G.device
local ExportTask = {
priority = 5,
}
function ExportTask:cycle(context)
for target, v in pairs(context.config.remoteDefaults) do
if v.exports then
local machine = device[target]
if machine and machine.getItemMeta then
for _, entry in pairs(v.exports) do
local slot = machine.getItemMeta(entry.slot) or { count = 0 }
local maxCount = slot.maxCount or itemDB:getMaxCount(entry.name)
local count = maxCount - slot.count
if count > 0 then
context.inventoryAdapter:provide(
itemDB:splitKey(entry.name), count, entry.slot, target)
end
end
else
debug('Invalid export target: ' .. target)
end
end
end
end
Milo:registerTask(ExportTask)

213
milo/plugins/exportView.lua Normal file
View File

@@ -0,0 +1,213 @@
local itemDB = require('itemDB')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local device = _G.device
local itemSlideout = UI.SlideOut {
backgroundColor = colors.cyan,
menuBar = UI.MenuBar {
buttons = {
{ text = 'Save', event = 'save' },
{ text = 'Cancel', event = 'cancel' },
{ text = 'Refresh', event = 'refresh', x = -9 },
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -6,
columns = {
{ heading = 'Name', key = 'displayName', width = 31 },
{ heading = 'Qty', key = 'count' , width = 5 },
},
sortColumn = 'displayName',
help = 'Select item to export',
},
filter = UI.TextEntry {
x = 2, ex = 18, y = -3,
limit = 50,
shadowText = 'filter',
backgroundColor = colors.lightGray,
backgroundFocusColor = colors.lightGray,
},
form = UI.Form {
x = 21, y = -4, height = 3,
margin = 1,
manualControls = true,
[1] = UI.Chooser {
width = 7,
formLabel = 'Slot', formKey = 'slot',
nochoice = 1,
help = 'Export into this slot',
},
[2] = UI.Chooser {
width = 7,
formLabel = 'Ignore Dmg', formKey = 'ignoreDamage',
pruneEmpty = true,
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore damage of item when exporting'
},
[3] = UI.Chooser {
width = 7,
formLabel = 'Ignore NBT', formKey = 'ignoreNbtHash',
pruneEmpty = true,
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore NBT of item when exporting'
},
},
statusBar = UI.StatusBar {
backgroundColor = colors.cyan,
},
}
function itemSlideout:filterItems(t, filter)
if filter and #filter > 0 then
local r = {}
filter = filter:lower()
for _,v in pairs(t) do
if string.find(v.lname, filter) then
table.insert(r, v)
end
end
return r
end
return t
end
function itemSlideout.grid:enable()
if not self.allItems then
self.allItems = Milo:listItems()
Milo:mergeResources(self.allItems)
self:setValues(self.allItems)
end
UI.Grid.enable(self)
end
function itemSlideout:show(machine, entry)
self.machine = machine
self.entry = entry
self.form.choices = { }
local m = device[machine.name]
for k = 1, m.size() do
table.insert(self.form[1].choices, {
name = k,
value = k,
})
end
if not entry.slot then
entry.slot = 1
end
self.form:setValues(entry)
UI.SlideOut.show(self)
self:setFocus(self.filter)
--self.filter:focus()
end
function itemSlideout:eventHandler(event)
if event.type == 'text_change' then
local t = self:filterItems(self.grid.allItems, event.text)
self.grid:setValues(t)
self.grid:draw()
elseif event.type == 'focus_change' then
self.statusBar:setStatus(event.focused.help)
elseif event.type == 'save' then
local selected = self.grid:getSelected()
if not selected then
self.statusBar:setStatus('Select an item to export')
else
self.form:save()
self.form.values.name = itemDB:makeKey(selected)
table.insert(self.machine.exports, self.form.values)
self:hide()
end
elseif event.type == 'cancel' then
self:hide()
elseif event.type == 'refresh' then
self.allItems = Milo:listItems()
Milo:mergeResources(self.allItems)
local t = self:filterItems(self.allItems, self.filter.value)
self.grid:setValues(t)
self.grid:draw()
self.filter:focus()
else
return UI.SlideOut.eventHandler(self, event)
end
return true
end
local exportView = UI.Window {
mtype = 'machine',
title = 'Export item into machine',
index = 3,
grid = UI.ScrollingGrid {
x = 2, ex = -6, y = 2, ey = -2,
columns = {
{ heading = 'Slot', key = 'slot', width = 4 },
{ heading = 'Item', key = 'displayName' },
},
sortColumn = 'slot',
},
add = UI.Button {
x = -4, y = 4,
text = '+', event = 'add_export', help = '...',
},
remove = UI.Button {
x = -4, y = 6,
text = '-', event = 'remove_export', help = '...',
},
}
function exportView:save(machine)
machine.exports = not Util.empty(self.grid.values) and self.grid.values or nil
return true
end
function exportView:setMachine(machine)
self.machine = machine
if not self.machine.exports then
self.machine.exports = { }
end
self.grid:setValues(machine.exports)
end
function exportView.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.displayName = itemDB:getName(row.name)
return row
end
function exportView:eventHandler(event)
if event.type == 'grid_select' then
itemSlideout:show(self.machine, self.grid:getSelected())
elseif event.type == 'add_export' then
itemSlideout:show(self.machine, { })
elseif event.type == 'remove_export' then
local row = self.grid:getSelected()
if row then
Util.removeByValue(self.grid.values, row)
self.grid:update()
self.grid:draw()
end
end
end
UI:getPage('machineWizard'):add({ items = itemSlideout })
UI:getPage('machineWizard').wizard:add({ export = exportView })

View File

@@ -0,0 +1,27 @@
local Milo = require('milo')
local device = _G.device
local ImportTask = {
priority = 3,
}
function ImportTask:cycle(context)
for source, v in pairs(context.config.remoteDefaults) do
if v.imports then
local machine = device[source]
if machine and machine.getItemMeta then
for slotNo in pairs(v.imports) do
local slot = machine.getItemMeta(slotNo)
if slot then
context.inventoryAdapter:insert(slotNo, slot.count, nil, slot, source)
end
end
else
debug('Invalid import source: ' .. source)
end
end
end
end
Milo:registerTask(ImportTask)

View File

@@ -0,0 +1,56 @@
local UI = require('ui')
local Util = require('util')
local device = _G.device
local importView = UI.Window {
mtype = 'machine',
title = 'Import item from machine',
index = 4,
grid = UI.ScrollingGrid {
y = 2, ey = -2,
columns = {
{ heading = 'Slot', key = 'slot', width = 4 },
{ heading = 'Import', key = 'import' },
},
sortColumn = 'slot',
help = 'Double-click to toggle'
},
}
function importView:setMachine(machine)
local m = device[machine.name]
local t = { }
for k = 1, m.size() do
t[k] = { slot = k }
end
if machine.imports then
for k,v in pairs(machine.imports) do
t[k] = { slot = k, import = v }
end
end
self.grid:setValues(t)
end
function importView:save(machine)
local t = { }
for k,v in pairs(self.grid.values) do
if v.import then
t[k] = true
end
end
machine.imports = not Util.empty(t) and t or nil
return true
end
function importView:eventHandler(event)
if event.type == 'grid_select' then
event.selected.import = not event.selected.import
self.grid:draw()
end
end
UI:getPage('machineWizard').wizard:add({ import = importView })

View File

@@ -0,0 +1,24 @@
local Milo = require('milo')
local device = _G.device
local InputChest = {
priority = 1,
}
function InputChest:cycle(context)
for name,v in pairs(context.config.remoteDefaults) do
if v.mtype == 'input' then
local inventory = device[name]
local list = inventory and inventory.list and inventory.list()
if list then
for slotNo, slot in pairs(list) do
context.inventoryAdapter:insert(slotNo, slot.count, nil, slot, name)
end
end
end
end
end
Milo:registerTask(InputChest)

248
milo/plugins/item.lua Normal file
View File

@@ -0,0 +1,248 @@
local Ansi = require('ansi')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local device = _G.device
local context = Milo:getContext()
local itemPage = UI.Page {
titleBar = UI.TitleBar {
title = 'Limit Resource',
previousPage = true,
event = 'form_cancel',
},
form = UI.Form {
x = 1, y = 2, height = 10, ex = -1,
[1] = UI.TextEntry {
width = 7,
formLabel = 'Min', formKey = 'low', help = 'Craft if below min'
},
[2] = UI.TextEntry {
width = 7,
formLabel = 'Max', formKey = 'limit', help = 'Eject if above max'
},
--[[
[3] = UI.Chooser {
width = 7,
formLabel = 'Autocraft', formKey = 'auto',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Craft until out of ingredients'
},
]]
[4] = UI.Chooser {
width = 7,
formLabel = 'Ignore Dmg', formKey = 'ignoreDamage',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore damage of item'
},
[5] = UI.Chooser {
width = 7,
formLabel = 'Ignore NBT', formKey = 'ignoreNbtHash',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore NBT of item'
},
--[[
[6] = UI.Button {
x = 2, y = -2, width = 10,
formLabel = 'Redstone',
event = 'show_rs',
text = 'Configure',
},
]]
infoButton = UI.Button {
x = 2, y = -2,
event = 'show_info',
text = 'Info',
},
},
rsControl = UI.SlideOut {
backgroundColor = colors.cyan,
titleBar = UI.TitleBar {
title = "Redstone Control",
},
form = UI.Form {
y = 2,
[1] = UI.Chooser {
width = 7,
formLabel = 'RS Control', formKey = 'rsControl',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Control via redstone'
},
[2] = UI.Chooser {
width = 25,
formLabel = 'RS Device', formKey = 'rsDevice',
--choices = devices,
help = 'Redstone Device'
},
[3] = UI.Chooser {
width = 10,
formLabel = 'RS Side', formKey = 'rsSide',
--nochoice = 'No',
choices = {
{ name = 'up', value = 'up' },
{ name = 'down', value = 'down' },
{ name = 'east', value = 'east' },
{ name = 'north', value = 'north' },
{ name = 'west', value = 'west' },
{ name = 'south', value = 'south' },
},
help = 'Output side'
},
},
},
info = UI.SlideOut {
titleBar = UI.TitleBar {
title = "Information",
},
textArea = UI.TextArea {
x = 2, ex = -2, y = 3, ey = -4,
backgroundColor = colors.black,
},
cancel = UI.Button {
ex = -2, y = -2, width = 6,
text = 'Okay',
event = 'hide_info',
},
},
statusBar = UI.StatusBar { }
}
function itemPage:enable(item)
self.item = Util.shallowCopy(item)
self.form:setValues(self.item)
self.titleBar.title = item.displayName or item.name
UI.Page.enable(self)
self:focusFirst()
end
function itemPage.rsControl:enable()
local devices = self.form[1].choices
Util.clear(devices)
for _,dev in pairs(device) do
if dev.setOutput then
table.insert(devices, { name = dev.name, value = dev.name })
end
end
if Util.size(devices) == 0 then
table.insert(devices, { name = 'None found', values = '' })
end
UI.SlideOut.enable(self)
end
function itemPage.rsControl:eventHandler(event)
if event.type == 'form_cancel' then
self:hide()
elseif event.type == 'form_complete' then
self:hide()
else
return UI.SlideOut.eventHandler(self, event)
end
return true
end
function itemPage:eventHandler(event)
if event.type == 'form_cancel' then
UI:setPreviousPage()
elseif event.type == 'show_rs' then
self.rsControl:show()
elseif event.type == 'show_info' then
local value =
string.format('%s%s%s\n%s\n',
Ansi.orange, self.item.displayName, Ansi.reset,
self.item.name)
if self.item.nbtHash then
value = value .. self.item.nbtHash .. '\n'
end
value = value .. string.format('\n%sDamage:%s %s',
Ansi.yellow, Ansi.reset, self.item.damage)
if self.item.maxDamage and self.item.maxDamage > 0 then
value = value .. string.format(' (max: %s)', self.item.maxDamage)
end
if self.item.maxCount then
value = value .. string.format('\n%sStack Size: %s%s',
Ansi.yellow, Ansi.reset, self.item.maxCount)
end
self.info.textArea.value = value
self.info:show()
elseif event.type == 'hide_info' then
self.info:hide()
elseif event.type == 'focus_change' then
self.statusBar:setStatus(event.focused.help)
self.statusBar:draw()
elseif event.type == 'form_complete' then
local values = self.form.values
local originalKey = Milo:uniqueKey(self.item)
local filtered = Util.shallowCopy(values)
filtered.low = tonumber(filtered.low)
filtered.limit = tonumber(filtered.limit)
if filtered.auto ~= true then
filtered.auto = nil
end
if filtered.rsControl ~= true then
filtered.rsControl = nil
filtered.rsSide = nil
filtered.rsDevice = nil
end
if filtered.ignoreDamage == true then
filtered.damage = 0
else
filtered.ignoreDamage = nil
end
if filtered.ignoreNbtHash == true then
filtered.nbtHash = nil
else
filtered.ignoreNbtHash = nil
end
context.resources[originalKey] = nil
context.resources[Milo:uniqueKey(filtered)] = filtered
filtered.count = nil
Milo:saveResources()
UI:setPreviousPage()
else
return UI.Page.eventHandler(self, event)
end
return true
end
UI:addPage('item', itemPage)

65
milo/plugins/jobList.lua Normal file
View File

@@ -0,0 +1,65 @@
local Milo = require('milo')
local Peripheral = require('peripheral')
local UI = require('ui')
local colors = _G.colors
local context = Milo:getContext()
local mon = Peripheral.lookup(context.config.monitor) or
error('Monitor is not attached')
local display = UI.Device {
device = mon,
textScale = .5,
}
local jobList = UI.Page {
parent = display,
grid = UI.Grid {
sortColumn = 'displayName',
backgroundFocusColor = colors.black,
columns = {
{ heading = 'Qty', key = 'count', width = 6 },
{ heading = 'Crafting', key = 'displayName', width = display.width / 2 - 10 },
{ heading = 'Status', key = 'status', width = display.width - 10 },
},
},
}
function jobList:showError(msg)
self.grid:clear()
self.grid:centeredWrite(math.ceil(self.grid.height / 2), msg)
self:sync()
end
function jobList:updateList(craftList)
self.grid:setValues(craftList)
self.grid:update()
self:draw()
self:sync()
end
function jobList.grid:getRowTextColor(row, selected)
if row.statusCode == Milo.STATUS_ERROR then
return colors.red
elseif row.statusCode == Milo.STATUS_WARNING then
return colors.yellow
elseif row.statusCode == Milo.STATUS_INFO then
return colors.lime
end
return UI.Grid:getRowTextColor(row, selected)
end
jobList:enable()
jobList:draw()
jobList:sync()
local JobListTask = {
priority = 80,
}
function JobListTask:cycle()
jobList:updateList(Milo:getCraftingStatus())
end
Milo:registerTask(JobListTask)
context.jobList = jobList

61
milo/plugins/learn.lua Normal file
View File

@@ -0,0 +1,61 @@
local Milo = require('milo')
local UI = require('ui')
local context = Milo:getContext()
local learnPage = UI.Dialog {
height = 6, width = UI.term.width - 6,
title = 'Learn Recipe',
chooser = UI.Chooser {
x = 8, y = 3,
width = 20,
},
cancel = UI.Button {
x = 3, y = -2,
text = 'Cancel', event = 'cancel'
},
accept = UI.Button {
ex = -3, y = -2,
width = 8,
text = 'Ok', event = 'accept',
},
}
function learnPage:enable()
self.chooser.choices = { }
for k in pairs(context.learnTypes) do
table.insert(self.chooser.choices, {
name = k,
value = k,
})
end
self.chooser.value =
Milo:getState('learnType') or
self.chooser.choices[1].value
self:focusFirst()
UI.Dialog.enable(self)
end
function learnPage:disable()
UI.Dialog.disable(self)
end
function learnPage:eventHandler(event)
if event.type == 'cancel' then
UI:setPreviousPage()
elseif event.type == 'accept' then
local choice = self.chooser.value
Milo:setState('learnType', choice)
UI:setPage(context.learnTypes[choice])
else
return UI.Dialog.eventHandler(self, event)
end
return true
end
UI:addPage('learn', learnPage)

View File

@@ -0,0 +1,35 @@
local Milo = require('milo')
local LimitTask = {
priority = 10,
}
function LimitTask:cycle(context)
local trashcan
for k,v in pairs(context.config.remoteDefaults) do
if v.mtype == 'trashcan' then
trashcan = k
break
end
end
if not trashcan then
return
end
for _,res in pairs(context.resources) do
if res.limit then
local item = Milo:getItemWithQty(res, res.ignoreDamage, res.ignoreNbtHash)
if item and item.count > res.limit then
context.inventoryAdapter:provide(
{ name = item.name, damage = item.damage, nbtHash = item.nbtHash },
item.count - res.limit,
nil,
trashcan)
end
end
end
end
Milo:registerTask(LimitTask)

224
milo/plugins/listing.lua Normal file
View File

@@ -0,0 +1,224 @@
local Craft = require('turtle.craft')
local itemDB = require('itemDB')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local os = _G.os
local context = Milo:getContext()
local function queue(fn)
while Milo:isCraftingPaused() do
os.sleep(1)
end
fn()
end
local function filterItems(t, filter, displayMode)
if filter or displayMode > 0 then
local r = { }
if filter then
filter = filter:lower()
end
for _,v in pairs(t) do
if not filter or string.find(v.lname, filter, 1, true) then
if not displayMode or
displayMode == 0 or
displayMode == 1 and v.count > 0 or
displayMode == 2 and v.has_recipe then
table.insert(r, v)
end
end
end
return r
end
return t
end
local listingPage = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Learn', event = 'learn' },
{ text = 'Forget', event = 'forget' },
{ text = 'Craft', event = 'craft' },
{ text = 'Refresh', event = 'refresh', x = -9 },
},
},
grid = UI.Grid {
y = 2, ey = -2,
columns = {
{ heading = ' Qty', key = 'count' , width = 4, justify = 'right' },
{ heading = 'Name', key = 'displayName' },
{ heading = 'Min', key = 'low' , width = 4 },
{ heading = 'Max', key = 'limit' , width = 4 },
},
sortColumn = 'displayName',
},
statusBar = UI.StatusBar {
filter = UI.TextEntry {
x = 1, ex = -4,
limit = 50,
shadowText = 'filter',
shadowTextColor = colors.gray,
backgroundColor = colors.cyan,
backgroundFocusColor = colors.cyan,
accelerators = {
[ 'enter' ] = 'craft',
},
},
display = UI.Button {
x = -3,
event = 'toggle_display',
value = 0,
text = 'A',
},
},
notification = UI.Notification(),
accelerators = {
r = 'refresh',
q = 'quit',
[ 'control-e' ] = 'eject',
[ 'control-s' ] = 'eject_stack',
[ 'control-m' ] = 'machines',
},
displayMode = 0,
}
function listingPage.statusBar:draw()
return UI.Window.draw(self)
end
function listingPage.grid:getRowTextColor(row, selected)
if row.is_craftable then
return colors.yellow
end
if row.has_recipe then
return colors.cyan
end
return UI.Grid:getRowTextColor(row, selected)
end
function listingPage.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.count = row.count > 0 and Util.toBytes(row.count) or ''
if row.low then
row.low = Util.toBytes(row.low)
end
if row.limit then
row.limit = Util.toBytes(row.limit)
end
return row
end
function listingPage:eventHandler(event)
debug(event)
if event.type == 'quit' then
UI:exitPullEvents()
elseif event.type == 'eject' then
local item = self.grid:getSelected()
if item then
queue(function() Milo:eject(item, 1) end)
end
elseif event.type == 'eject_stack' then
local item = self.grid:getSelected()
if item then
queue(function() Milo:eject(item, itemDB:getMaxCount(item)) end)
end
elseif event.type == 'machines' then
UI:setPage('machines')
elseif event.type == 'details' or event.type == 'grid_select_right' then
local item = self.grid:getSelected()
if item then
UI:setPage('item', item)
end
elseif event.type == 'refresh' then
self:refresh()
self.grid:draw()
self.statusBar.filter:focus()
elseif event.type == 'toggle_display' then
local values = {
[0] = 'A',
[1] = 'I',
[2] = 'C',
}
event.button.value = (event.button.value + 1) % 3
self.displayMode = event.button.value
event.button.text = values[event.button.value]
event.button:draw()
self:applyFilter()
self.grid:draw()
elseif event.type == 'learn' then
UI:setPage('learn')
elseif event.type == 'craft' or event.type == 'grid_select' then
local item = self.grid:getSelected()
if Craft.findRecipe(item) or true then -- or item.is_craftable then
UI:setPage('craft', self.grid:getSelected())
else
self.notification:error('No recipe defined')
end
elseif event.type == 'forget' then
local item = self.grid:getSelected()
if item then
local key = Milo:uniqueKey(item)
if context.userRecipes[key] then
context.userRecipes[key] = nil
Util.writeTable(Milo.RECIPES_FILE, context.userRecipes)
Craft.loadRecipes()
end
if context.resources[key] then
context.resources[key] = nil
Milo:saveResources()
end
self.notification:info('Forgot: ' .. item.name)
self:refresh()
self.grid:draw()
end
elseif event.type == 'text_change' then
self.filter = event.text
if #self.filter == 0 then
self.filter = nil
end
self:applyFilter()
self.grid:draw()
self.statusBar.filter:focus()
else
UI.Page.eventHandler(self, event)
end
return true
end
function listingPage:enable()
self:refresh()
self:setFocus(self.statusBar.filter)
UI.Page.enable(self)
end
function listingPage:refresh()
self.allItems = Milo:listItems()
Milo:mergeResources(self.allItems)
self:applyFilter()
end
function listingPage:applyFilter()
local t = filterItems(self.allItems, self.filter, self.displayMode)
self.grid:setValues(t)
end
UI:addPage('listing', listingPage)

View File

@@ -0,0 +1,172 @@
local Craft = require('turtle.craft')
local itemDB = require('itemDB')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local device = _G.device
local turtle = _G.turtle
local MACHINE_LOOKUP = 'usr/config/machine_crafting.db'
local context = Milo:getContext()
local function getTurtleInventory()
local introspectionModule = device['plethora:introspection'] or
error('Introspection module not found')
local list = { }
for i = 1,16 do
list[i] = introspectionModule.getInventory().getItemMeta(i)
end
return list
end
local machineLearnWizard = UI.Page {
titleBar = UI.TitleBar { title = 'Learn a crafting recipe' },
wizard = UI.Wizard {
y = 2, ey = -2,
pages = {
machine = UI.Window {
index = 1,
grid = UI.ScrollingGrid {
y = 2, ey = -2,
values = context.config.remoteDefaults,
columns = {
{ heading = 'Name', key = 'displayName' },
},
sortColumn = 'displayName',
},
},
confirmation = UI.Window {
index = 2,
notice = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2,
backgroundColor = colors.black,
value =
[[Place items in slots according to the machine's inventory.
Place the result in the last slot of the turtle.
Example: Slot 1 is the top slot in a furnace.]],
},
},
},
},
notification = UI.Notification { },
}
local pages = machineLearnWizard.wizard.pages
local machine
function pages.machine.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.displayName = row.displayName or row.name
return row
end
function pages.machine:validate()
-- TODO: validation should only be invoked when moving forward (i think)
-- TODO: index number validation in wizard
local selected = self.grid:getSelected()
if not selected then
machineLearnWizard.notification:error('No machines configured')
return
end
machine = device[selected.name]
if not machine then
machineLearnWizard.notification:error('Machine not found')
return
end
if not machine.size then
machineLearnWizard.notification:error('Invalid machine')
return
end
return true
end
function pages.confirmation:validate()
local inventory = getTurtleInventory()
local result = inventory[16]
local slotCount = machine.size()
inventory[16] = nil
if not result then
machineLearnWizard.notification:error('Result must be placed in last slot')
return
end
if Util.empty(inventory) then
machineLearnWizard.notification:error('Ingredients not present')
return
end
for k in pairs(inventory) do
if k > slotCount then
machineLearnWizard.notification:error(
'Slot ' .. k .. ' is not valid\nThe valid slots are 1 - ' .. machine.size())
return
end
end
local recipe = {
count = result.count,
ingredients = { },
maxCount = result.maxCount ~= 64 and result.maxCount or nil,
}
for k,v in pairs(inventory) do
recipe.ingredients[k] = Milo:uniqueKey(v)
end
local key = Milo:uniqueKey(result)
-- save the recipe
context.userRecipes[key] = recipe
Util.writeTable(Milo.RECIPES_FILE, context.userRecipes)
Craft.loadRecipes()
-- save the machine association
Craft.machineLookup[key] = machine.name
Util.writeTable(MACHINE_LOOKUP, Craft.machineLookup)
local listingPage = UI:getPage('listing')
local displayName = itemDB:getName(result)
listingPage.statusBar.filter:setValue(displayName)
listingPage.notification:success('Learned: ' .. displayName)
listingPage.filter = displayName
listingPage:refresh()
listingPage.grid:draw()
return true
end
function machineLearnWizard:enable()
Milo:pauseCrafting()
UI.Page.enable(self)
end
function machineLearnWizard:disable()
Milo:resumeCrafting()
UI.Page.disable(self)
end
function machineLearnWizard:eventHandler(event)
if event.type == 'cancel' or event.type == 'accept' then
turtle.emptyInventory()
UI:setPage('listing')
else
return UI.Page.eventHandler(self, event)
end
return true
end
context.learnTypes['Machine processing'] = machineLearnWizard

View File

@@ -0,0 +1,24 @@
local Milo = require('milo')
local device = _G.device
local PotionImportTask = {
priority = 3,
}
function PotionImportTask:cycle(context)
for _, v in pairs(device) do
if v.type == 'minecraft:brewing_stand' and v.getBrewTime() == 0 then
local list = v.list()
if not list[4] and list[1] then
for i = 1, 3 do
if list[i] then
context.inventoryAdapter:insert(i, 1, nil, list[i], v.name)
end
end
end
end
end
end
Milo:registerTask(PotionImportTask)

View File

@@ -0,0 +1,46 @@
local itemDB = require('itemDB')
local Milo = require('milo')
local ReplenishTask = {
priority = 30,
}
function ReplenishTask:cycle(context)
local craftList = { }
for _,res in pairs(context.resources) do
if res.low then
local item = Milo:getItemWithQty(res, res.ignoreDamage, res.ignoreNbtHash)
if not item then
item = {
damage = res.damage,
nbtHash = res.nbtHash,
name = res.name,
displayName = itemDB:getName(res),
count = 0
}
end
if item.count < res.low then
if res.ignoreDamage then
item.damage = 0
end
local key = Milo:uniqueKey(res)
craftList[key] = {
damage = item.damage,
nbtHash = item.nbtHash,
count = res.low - item.count,
name = item.name,
displayName = item.displayName,
status = '',
rsControl = res.rsControl,
}
end
end
end
Milo:craftItems(craftList)
end
Milo:registerTask(ReplenishTask)

View File

@@ -0,0 +1,44 @@
local UI = require('ui')
local colors = _G.colors
local storageView = UI.Window {
mtype = 'storage',
title = 'Storage Options',
index = 2,
backgroundColor = colors.cyan,
form = UI.Form {
x = 1, y = 2, ex = -1, ey = -2,
manualControls = true,
[1] = UI.TextEntry {
formLabel = 'Priority', formKey = 'priority',
help = 'Larger values get precedence',
limit = 4,
validate = 'numeric', pruneEmpty = true,
},
[2] = UI.TextEntry {
formLabel = 'Lock to', formKey = 'lockWith',
help = 'Locks chest to a single item type',
width = 18, limit = 64, pruneEmpty = true,
},
[3] = UI.Button {
x = -9, ey = -4,
text = 'Detect', help = 'Determine what is currently present',
},
},
}
function storageView:enable()
UI.Window.enable(self)
self:focusFirst()
end
function storageView:validate()
return self.form:save()
end
function storageView:setMachine(machine)
self.form:setValues(machine)
end
UI:getPage('machineWizard').wizard:add({ storage = storageView })

View File

@@ -0,0 +1,175 @@
local Craft = require('turtle.craft')
local itemDB = require('itemDB')
local Milo = require('milo')
local UI = require('ui')
local Util = require('util')
local device = _G.device
local turtle = _G.turtle
local context = Milo:getContext()
local function getTurtleInventory()
local introspectionModule = device['plethora:introspection'] or
error('Introspection module not found')
local list = { }
for i = 1,16 do
list[i] = introspectionModule.getInventory().getItemMeta(i)
end
return list
end
local function learnRecipe()
local ingredients = getTurtleInventory()
if not ingredients then
return false, 'No recipe defined'
end
turtle.select(1)
if not turtle.craft() then
return false, 'Failed to craft'
end
local results = getTurtleInventory()
if not results or not results[1] then
return false, 'Failed to craft'
end
local maxCount
local newRecipe = {
ingredients = ingredients,
}
local numResults = 0
for _,v in pairs(results) do
if v.count > 0 then
numResults = numResults + 1
end
end
if numResults > 1 then
for _,v1 in pairs(results) do
for _,v2 in pairs(ingredients) do
if v1.name == v2.name and
v1.nbtHash == v2.nbtHash and
(v1.damage == v2.damage or
(v1.maxDamage > 0 and v2.maxDamage > 0 and
v1.damage ~= v2.damage)) then
if not newRecipe.crafingTools then
newRecipe.craftingTools = { }
end
local tool = Util.shallowCopy(v2)
if tool.maxDamage > 0 then
tool.damage = '*'
end
--[[
Turtles can only craft one item at a time using a tool :(
]]--
maxCount = 1
newRecipe.craftingTools[Milo:uniqueKey(tool)] = true
v1.craftingTool = true
break
end
end
end
end
local recipe
for _,v in pairs(results) do
if not v.craftingTool then
recipe = v
if maxCount then
recipe.maxCount = maxCount
end
break
end
end
if not recipe then
debug(results)
debug(newRecipe)
error('Failed - view system log')
end
newRecipe.count = recipe.count
local key = Milo:uniqueKey(recipe)
if recipe.maxCount ~= 64 then
newRecipe.maxCount = recipe.maxCount
end
for k,ingredient in pairs(Util.shallowCopy(ingredients)) do
if ingredient.maxDamage > 0 then
-- ingredient.damage = '*' -- I don't think this is right
end
ingredients[k] = Milo:uniqueKey(ingredient)
end
context.userRecipes[key] = newRecipe
Util.writeTable(Milo.RECIPES_FILE, context.userRecipes)
Craft.loadRecipes()
turtle.emptyInventory()
return recipe
end
local turtleLearnWizard = UI.Page {
titleBar = UI.TitleBar { title = 'Learn a crafting recipe' },
wizard = UI.Wizard {
y = 2, ey = -3,
pages = {
confirmation = UI.Window {
index = 1,
notice = UI.TextArea {
x = 2, ex = -2, y = 2, ey = -2,
value =
[[Place recipe in turtle!]],
},
},
},
},
notification = UI.Notification { },
}
function turtleLearnWizard:enable()
Milo:pauseCrafting()
UI.Page.enable(self)
end
function turtleLearnWizard:disable()
Milo:resumeCrafting()
UI.Page.disable(self)
end
function turtleLearnWizard.wizard.pages.confirmation:validate()
local recipe, msg = learnRecipe(self)
if recipe then
local listingPage = UI:getPage('listing')
local displayName = itemDB:getName(recipe)
listingPage.statusBar.filter:setValue(displayName)
listingPage.notification:success('Learned: ' .. displayName)
listingPage.filter = displayName
listingPage:refresh()
listingPage.grid:draw()
return true
else
turtleLearnWizard.notification:error(msg)
end
end
function turtleLearnWizard:eventHandler(event)
if event.type == 'cancel' or event.type == 'accept' then
UI:setPage('listing')
else
return UI.Page.eventHandler(self, event)
end
return true
end
context.learnTypes['Turtle crafting'] = turtleLearnWizard