peripheral overhaul

This commit is contained in:
kepler155c
2018-01-06 06:08:39 -05:00
parent c48243eae5
commit f2b9efc80f
8 changed files with 176 additions and 108 deletions

View File

@@ -7,18 +7,16 @@ local ChestAdapter = class()
function ChestAdapter:init(args) function ChestAdapter:init(args)
local defaults = { local defaults = {
name = 'chest', name = 'chest',
direction = 'down',
wrapSide = 'bottom',
} }
Util.merge(self, defaults) Util.merge(self, defaults)
Util.merge(self, args) Util.merge(self, args)
local chest local chest
if self.autoDetect then if not self.side then
chest = Peripheral.getByMethod('list') chest = Peripheral.getByMethod('list')
else else
chest = Peripheral.getBySide(self.wrapSide) chest = Peripheral.getBySide(self.side)
if chest and not chest.list then if chest and not chest.list then
chest = nil chest = nil
end end
@@ -104,7 +102,7 @@ function ChestAdapter:craftItems()
end end
function ChestAdapter:getPercentUsed() function ChestAdapter:getPercentUsed()
if self.cache then if self.cache and self.getDrawerCount then
return math.floor(Util.size(self.cache) / self.getDrawerCount() * 100) return math.floor(Util.size(self.cache) / self.getDrawerCount() * 100)
end end
return 0 return 0

View File

@@ -2,7 +2,7 @@ local Util = require('util')
local Adapter = { } local Adapter = { }
function Adapter.wrap(args, computerInfo) function Adapter.wrap(args)
local adapters = { local adapters = {
--'refinedAdapter', --'refinedAdapter',
--'meAdapter', --'meAdapter',
@@ -10,34 +10,32 @@ function Adapter.wrap(args, computerInfo)
'chestAdapter', 'chestAdapter',
} }
if computerInfo then if args and args.side and args.facing and not args.direction then
args = Util.shallowCopy(args) args = Util.shallowCopy(args)
if not args.direction and computerInfo.facing then local horz = { top = 'down', bottom = 'up' }
local horz = { top = 'down', bottom = 'up' } args.direction = horz[args.side]
args.direction = horz[args.wrapSide]
if not args.direction then if not args.direction then
local sides = { local sides = {
front = 0, front = 0,
back = 2, back = 2,
right = 1, right = 1,
left = 3, left = 3,
} }
-- pretty sure computer/turtle have sides reversed -- pretty sure computer/turtle have sides reversed
local cards = { local cards = {
east = 0, east = 0,
south = 1, south = 1,
west = 2, west = 2,
north = 3, north = 3,
} }
local icards = { local icards = {
[ 0 ] = 'west', [ 0 ] = 'west',
[ 1 ] = 'north', [ 1 ] = 'north',
[ 2 ] = 'east', [ 2 ] = 'east',
[ 3 ] = 'south', [ 3 ] = 'south',
} }
args.direction = icards[(cards[computerInfo.facing] + sides[args.wrapSide]) % 4] args.direction = icards[(cards[args.facing] + sides[args.side]) % 4]
end
end end
end end

View File

@@ -73,29 +73,15 @@ function itemDB:get(key, enforceNBT)
end end
end end
if key.nbtHash and not enforceNBT then if key.nbtHash then
item = self:get({ name = key.name, damage = key.damage }) item = self:get({ name = key.name, damage = key.damage })
if item and (item.maxDamage > 0 or item.damage == key.damage) then
if item and item.ignoreNBT then
item = Util.shallowCopy(item) item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash item.nbtHash = key.nbtHash
item.damage = key.damage
return item return item
end end
local damage = tonumber(key.damage)
debug('scan: ' .. makeKey(key))
for _,item in pairs(self.data) do
if item.name == key.name and
((not damage or item.maxDamage > 0) or damage == item.damage) and
item.nbtHash then
item = Util.shallowCopy(item)
item.damage = damage or item.damage
if item.maxDamage > 0 and item.damage and item.damage > 0 then
item.displayName = string.format('%s (damage: %s)', item.displayName, item.damage)
end
item.nbtHash = key.nbtHash
return item
end
end
end end
end end
@@ -103,23 +89,55 @@ end
If the base item contains an NBT hash, then the NBT hash uniquely If the base item contains an NBT hash, then the NBT hash uniquely
identifies this item. identifies this item.
]]-- ]]--
function itemDB:add(item, detail) function itemDB:add(baseItem, detail)
local nItem = { name = item.name, damage = item.damage, nbtHash = item.nbtHash } local nItem = {
if detail.maxDamage > 0 then name = baseItem.name,
nItem.damage = '*' damage = baseItem.damage,
end nbtHash = baseItem.nbtHash,
}
-- if detail.maxDamage > 0 then
-- nItem.damage = '*'
-- end
debug('--')
debug('adding ' .. makeKey(nItem))
nItem.displayName = safeString(detail.displayName) nItem.displayName = safeString(detail.displayName)
nItem.maxCount = detail.maxCount nItem.maxCount = detail.maxCount
nItem.maxDamage = detail.maxDamage nItem.maxDamage = detail.maxDamage
TableDB.add(self, makeKey(nItem), nItem) for k,item in pairs(self.data) do
if nItem.name == item.name and
if detail.maxDamage > 0 then nItem.displayName == item.displayName then
nItem = Util.shallowCopy(nItem) debug('found: ' .. makeKey(item))
nItem.damage = item.damage if nItem.nbtHash ~= item.nbtHash and nItem.damage ~= item.damage then
nItem.damage = '*'
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
debug('removing all ' .. makeKey(nItem))
break
elseif nItem.damage ~= item.damage then
nItem.damage = '*'
self.data[k] = nil
debug('removing damage ' .. makeKey(nItem))
break
elseif nItem.nbtHash ~= item.nbtHash then
nItem.nbtHash = nil
nItem.ignoreNBT = true
debug('removing nbt ' .. makeKey(nItem))
self.data[k] = nil
break
end
end
end end
debug('final ' .. makeKey(nItem))
TableDB.add(self, makeKey(nItem), nItem)
nItem = Util.shallowCopy(nItem)
nItem.damage = baseItem.damage
nItem.nbtHash = baseItem.nbtHash
return nItem return nItem
end end

View File

@@ -23,24 +23,21 @@ local turtle = _G.turtle
multishell.setTitle(multishell.getCurrent(), 'Resource Manager') multishell.setTitle(multishell.getCurrent(), 'Resource Manager')
local config = { local config = {
computerFacing = 'north',
inventory = 'back',
craftingChest = 'top',
controller = 'none',
trashDirection = 'up', -- trash /chest in relation to chest trashDirection = 'up', -- trash /chest in relation to chest
computer = { monitor = 'type/monitor',
facing = 'north',
desc = 'Direction computer or turtle is facing',
},
inventory = { wrapSide = 'back',
desc = 'Location of main inventory' },
craftingChest = { wrapSide = 'top',
desc = 'Vanilla chest used for crafting' },
controller = { wrapSide = 'right',
desc = 'optional - AE or refined storage controller - can be same as main inventory' },
} }
Config.loadWithCheck('inventoryManager', config) Config.loadWithCheck('inventoryManager', config)
local inventoryAdapter = InventoryAdapter.wrap(config.inventory, config.computer) local inventoryAdapter = InventoryAdapter.wrap({ side = config.inventory, facing = config.computerFacing })
local turtleChestAdapter = InventoryAdapter.wrap(config.craftingChest, config.computer) local turtleChestAdapter = InventoryAdapter.wrap({ side = config.craftingChest, facing = config.computerFacing })
local controllerAdapter = ControllerAdapter.wrap(config.controller, config.computer) local controllerAdapter = ControllerAdapter.wrap({ side = config.controller, facing = config.computerFacing })
local duckAntenna local duckAntenna
if not inventoryAdapter then if not inventoryAdapter then
@@ -359,7 +356,7 @@ local function craftItems(craftList, allItems)
end end
local function jobMonitor() local function jobMonitor()
local mon = Peripheral.getByType('monitor') local mon = Peripheral.lookup(config.monitor)
if mon then if mon then
mon = UI.Device({ mon = UI.Device({
@@ -759,6 +756,8 @@ function itemPage:eventHandler(event)
end end
resources[originalKey] = nil resources[originalKey] = nil
resources[uniqueKey(filtered)] = filtered resources[uniqueKey(filtered)] = filtered
filtered.count = nil
saveResources() saveResources()
UI:setPreviousPage() UI:setPreviousPage()

View File

@@ -1,6 +1,6 @@
_G.requireInjector() _G.requireInjector()
local ChestAdapter = require('chestAdapter18') local InventoryAdapter = require('inventoryAdapter')
local Config = require('config') local Config = require('config')
local Event = require('event') local Event = require('event')
local itemDB = require('itemDB') local itemDB = require('itemDB')
@@ -18,16 +18,26 @@ local turtle = _G.turtle
multishell.setTitle(multishell.getCurrent(), 'Crafter') multishell.setTitle(multishell.getCurrent(), 'Crafter')
local config = { local config = {
inventory = { direction = 'north', wrapSide = 'front' }, computerFacing = 'north',
monitor = 'monitor',
} }
Config.load('crafter', config) Config.load('crafter', config)
repeat until not turtle.forward() repeat until not turtle.forward()
local inventoryAdapter = ChestAdapter(config.inventory)
local RESOURCE_FILE = 'usr/config/resources.db' local inventoryAdapter = InventoryAdapter.wrap({ side = 'front', facing = config.computerFacing })
local RECIPES_FILE = 'usr/config/recipes2.db' if not inventoryAdapter then
local MACHINES_FILE = 'usr/config/machines.db' error('Invalid inventory configuration')
end
local RESOURCE_FILE = 'usr/config/resources.db'
local RECIPES_FILE = 'usr/config/recipes2.db'
local MACHINES_FILE = 'usr/config/machines.db'
local STATUS_ERROR = 'error'
local STATUS_INFO = 'info'
local STATUS_SUCCESS = 'success'
local STATUS_WARNING = 'warning'
local recipes = Util.readTable(RECIPES_FILE) or { } local recipes = Util.readTable(RECIPES_FILE) or { }
local resources local resources
@@ -63,20 +73,6 @@ local function getItemQuantity(items, res)
return count return count
end end
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
((ignoreNbtHash and v.nbtHash) or res.nbtHash == v.nbtHash) then
return v
end
end
local item = Util.shallowCopy(res)
item.count = 0
item.maxCount = 1
return item
end
local function mergeResources(t) local function mergeResources(t)
for _,v in pairs(resources) do for _,v in pairs(resources) do
local item = getItem(t, v) local item = getItem(t, v)
@@ -183,23 +179,41 @@ local function getItems()
return items return items
end end
local function craftItem(ikey, item, items) local function craftItem(ikey, item, items, machineStatus)
dock() dock()
local resource = resources[ikey] local resource = resources[ikey]
if not resource or not resource.machine then if not resource or not resource.machine then
item.status = 'machine not selected' item.statusCode = STATUS_ERROR
item.status = 'machine not defined'
return return
end end
local machine = Util.find(machines, 'order', resource.machine) local machine = Util.find(machines, 'order', resource.machine)
if not machine then if not machine then
item.statusCode = STATUS_ERROR
item.status = 'invalid machine' item.status = 'invalid machine'
return return
end end
local ms = machineStatus[machine.order]
if not ms then
ms = { count = 0 }
machineStatus[machine.order] = ms
end
local slot = 1 local slot = 1
local maxCount = math.ceil(item.need / item.recipe.count) local maxCount = math.ceil(item.need / item.recipe.count)
maxCount = math.min(machine.maxCount or 64, maxCount)
if maxCount > 0 and maxCount - ms.count <= 0 then
item.statusCode = STATUS_INFO
item.status = 'machine busy'
return
end
maxCount = maxCount - ms.count
for key,qty in pairs(item.recipe.ingredients) do for key,qty in pairs(item.recipe.ingredients) do
local ingredient = itemDB:get(key) local ingredient = itemDB:get(key)
local c = math.min(maxCount * qty, getItemQuantity(items, ingredient)) local c = math.min(maxCount * qty, getItemQuantity(items, ingredient))
@@ -208,13 +222,17 @@ local function craftItem(ikey, item, items)
if c < maxCount then if c < maxCount then
maxCount = c maxCount = c
end end
if maxCount == 0 then if maxCount <= 0 then
item.status = 'Missing ' .. ingredient.displayName item.status = 'Missing ' .. ingredient.displayName
item.statusCode = 'missing' item.statusCode = STATUS_WARNING
return return
end end
end end
if machine.maxCount then
ms.count = ms.count + maxCount
end
for key,qty in pairs(item.recipe.ingredients) do for key,qty in pairs(item.recipe.ingredients) do
local ingredient = itemDB:get(key) local ingredient = itemDB:get(key)
-- local c = item.craftable * qty -- local c = item.craftable * qty
@@ -222,6 +240,7 @@ local function craftItem(ikey, item, items)
inventoryAdapter:provide(ingredient, maxCount * qty, slot) inventoryAdapter:provide(ingredient, maxCount * qty, slot)
if turtle.getItemCount(slot) ~= maxCount * qty then -- ~= maxCount then FIXXX !!! if turtle.getItemCount(slot) ~= maxCount * qty then -- ~= maxCount then FIXXX !!!
item.status = 'Extract failed: ' .. (ingredient.displayName or itemDB:getName(ingredient)) item.status = 'Extract failed: ' .. (ingredient.displayName or itemDB:getName(ingredient))
item.statusCode = STATUS_ERROR
debug({ key, maxCount }) debug({ key, maxCount })
return return
end end
@@ -232,6 +251,7 @@ debug({ key, maxCount })
if not gotoMachine(machine) then if not gotoMachine(machine) then
item.status = 'failed to find machine' item.status = 'failed to find machine'
item.statusCode = STATUS_ERROR
else else
if machine.empty then if machine.empty then
local s, l = pcall(Peripheral.call, local s, l = pcall(Peripheral.call,
@@ -250,9 +270,11 @@ debug({ key, maxCount })
end end
debug { s, l } debug { s, l }
if not s then if not s then
item.statusCode = STATUS_ERROR
item.status = l item.status = l
return return
elseif not Util.empty(l) then elseif not Util.empty(l) then
item.statusCode = STATUS_INFO
item.status = 'machine busy' item.status = 'machine busy'
return return
end end
@@ -264,8 +286,10 @@ debug { s, l }
turtle.emptyInventory(turtle.dropDown) turtle.emptyInventory(turtle.dropDown)
end end
if #turtle.getFilledSlots() ~= 0 then if #turtle.getFilledSlots() ~= 0 then
item.statusCode = STATUS_INFO
item.status = 'machine busy' item.status = 'machine busy'
else else
item.statusCode = STATUS_SUCCESS
item.status = 'crafting' item.status = 'crafting'
end end
end end
@@ -336,6 +360,7 @@ local function watchResources(items)
end end
local function craftItems() local function craftItems()
local machineStatus = { }
local items = getItems() local items = getItems()
local craftList = watchResources(items) local craftList = watchResources(items)
local list = expandList(craftList, items) local list = expandList(craftList, items)
@@ -345,14 +370,17 @@ local function craftItems()
jobListGrid:sync() jobListGrid:sync()
for key, item in pairs(list) do for key, item in pairs(list) do
if item.need > 0 and item.recipe then if item.need > 0 and item.recipe then
craftItem(key, item, items) craftItem(key, item, items, machineStatus)
dock() dock()
items = getItems() -- should decrement count instead ... items = getItems() -- should decrement count instead ...
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
clearGrid() clearGrid()
elseif item.need > 0 then
item.status = 'no recipe'
item.statusCode = STATUS_WARNING
end end
jobListGrid:update()
jobListGrid:draw()
jobListGrid:sync()
end end
end end
@@ -434,12 +462,13 @@ local function findMachines()
end end
m.empty = m2.empty m.empty = m2.empty
m.ignore = m2.ignore m.ignore = m2.ignore
m.maxCount = m2.maxCount
end end
end end
end end
local function jobMonitor() local function jobMonitor()
local mon = Peripheral.getByType('monitor') local mon = Peripheral.lookup(config.monitor)
if mon then if mon then
mon = UI.Device({ mon = UI.Device({
@@ -463,10 +492,12 @@ local function jobMonitor()
}) })
function jobListGrid:getRowTextColor(row, selected) function jobListGrid:getRowTextColor(row, selected)
if row.status == '(no recipe)'then if row.statusCode == STATUS_ERROR then
return colors.red return colors.red
elseif row.statusCode == 'missing' then elseif row.statusCode == STATUS_WARNING then
return colors.yellow return colors.yellow
elseif row.statusCode == STATUS_SUCCESS then
return colors.lime
end end
return UI.Grid:getRowTextColor(row, selected) return UI.Grid:getRowTextColor(row, selected)
@@ -793,6 +824,10 @@ local machinesPage = UI.Page {
}, },
help = 'Check if machine is empty before crafting' help = 'Check if machine is empty before crafting'
}, },
[4] = UI.TextEntry {
formLabel = 'Max Craft', formKey = 'maxCount', help = '...',
limit = 4,
},
}, },
statusBar = UI.StatusBar(), statusBar = UI.StatusBar(),
}, },
@@ -839,6 +874,7 @@ function machinesPage:eventHandler(event)
elseif event.type == 'form_complete' then elseif event.type == 'form_complete' then
self.detail.form.values.empty = self.detail.form.values.empty == true self.detail.form.values.empty = self.detail.form.values.empty == true
self.detail.form.values.ignore = self.detail.form.values.ignore == true self.detail.form.values.ignore = self.detail.form.values.ignore == true
self.detail.form.values.maxCount = tonumber(self.detail.form.values.maxCount)
Util.writeTable(MACHINES_FILE, machines) Util.writeTable(MACHINES_FILE, machines)
self.detail:hide() self.detail:hide()
@@ -1018,4 +1054,4 @@ Event.onInterval(30, function()
end) end)
UI:pullEvents() UI:pullEvents()
--jobListGrid.parent:reset() jobListGrid.parent:reset()

View File

@@ -22,7 +22,7 @@ local UID = 0
local multishell = { } local multishell = { }
local processes = { } local processes = { }
local parentTerm = term.current() local parentTerm = term.current()
local sessionFile = args[1] or 'config/mwm' local sessionFile = args[1] or 'usr/config/mwm'
local running local running
local monitor local monitor

View File

@@ -8,7 +8,7 @@ local Util = require('util')
local colors = _G.colors local colors = _G.colors
local multishell = _ENV.multishell local multishell = _ENV.multishell
local storage = InventoryAdapter.wrap({ autoDetect = true }) local storage = InventoryAdapter.wrap()
if not storage then if not storage then
error('Not connected to a valid inventory') error('Not connected to a valid inventory')
end end

19
apps/termShare.lua Normal file
View File

@@ -0,0 +1,19 @@
local device = _G.device
local multishell = _ENV.multishell
local os = _G.os
local term = _G.term
-- list this terminal in the devices list so it's available via
-- peripheral sharing
local args = { ... }
local name = args[1] or error('Syntax: termShare [device name] <title>')
local title = args[2]
device[name] = term.current()
if title then
multishell.setTitle(multishell.getCurrent(), title)
end
os.pullEvent('char')
device[name] = nil