package management

This commit is contained in:
kepler155c
2018-11-03 18:14:11 -04:00
parent aa66b1c663
commit 1f7ef4a483
124 changed files with 1274 additions and 9 deletions

9
pickup/.package Normal file
View File

@@ -0,0 +1,9 @@
{
required = {
'opus-develop-1.8',
},
title = 'Move resources around with turtles',
repository = 'kepler155c/opus-apps/develop1.8/pickup',
description = [[ ... ]],
licence = 'MIT',
}

321
pickup/pickup.lua Normal file
View File

@@ -0,0 +1,321 @@
_G.requireInjector()
local Event = require('event')
local ChestAdapter = require('chestAdapter18')
local Point = require('point')
local Socket = require('socket')
local Util = require('util')
local device = _G.device
local os = _G.os
local peripheral = _G.peripheral
local printError = _G.printError
local turtle = _G.turtle
if not turtle then
error('Can only be run on a turtle')
end
local blocks = { }
local items = { }
local locations = Util.readTable('/usr/config/pickup') or {
pickups = { },
cells = { },
refills = { },
fluids = { },
}
local fuel = {
item = {
name = 'minecraft:coal',
damage = 0,
},
qty = 64
}
local slots
turtle.setMoveCallback(function()
if slots then
for _,slot in pairs(slots) do
if turtle.getItemCount(slot.index) ~= slot.qty then
printError('Slots changed')
Event.exitPullEvents()
end
end
end
end)
local function gotoPoint(pt, doDetect)
slots = turtle.getInventory()
while not turtle.pathfind(pt, { blocks = blocks }) do
if turtle.isAborted() then
error('aborted')
end
turtle.setStatus('blocked')
os.sleep(5)
end
if doDetect and not turtle.detectDown() then
printError('Missing target')
Event.exitPullEvents()
end
end
local function dropOff(pt)
if turtle.selectSlotWithItems() then
gotoPoint(pt, true)
turtle.emptyInventory(turtle.dropDown)
if pt == locations.dropPt then
print('refreshing items')
local chestAdapter = ChestAdapter()
items = chestAdapter:refresh()
end
end
end
local function refuel()
if turtle.getFuelLevel() < 5000 and locations.dropPt then
print('refueling')
turtle.setStatus('refueling')
gotoPoint(locations.dropPt, true)
dropOff(locations.dropPt)
local chestAdapter = ChestAdapter({
wrapSide = 'bottom',
direction = 'up',
})
while turtle.getFuelLevel() < 5000 do
turtle.select(1)
chestAdapter:provide(fuel.item, fuel.qty, 1)
turtle.refuel(64)
print(turtle.getFuelLevel())
os.sleep(1)
end
end
end
local function pickUp(pt)
turtle.setStatus('picking up')
gotoPoint(pt, true)
while true do
if not turtle.selectOpenSlot() then
dropOff(locations.dropPt)
gotoPoint(pt, true)
end
turtle.select(1)
if not turtle.suckDown(64) then
return
end
end
end
local function checkCell(pt)
if not turtle.selectOpenSlot() then
dropOff(locations.dropPt)
end
print('checking cell')
turtle.setStatus('recharging')
gotoPoint(pt, true)
local c = peripheral.wrap('bottom')
local energy = c.getMaxEnergyStored() -
c.getEnergyStored()
if energy > 20000 then
print('charging cell')
turtle.selectOpenSlot()
turtle.digDown()
gotoPoint(locations.chargePt, true)
turtle.dropDown()
os.sleep(energy / 20000)
turtle.suckDown()
print('replacing cell')
gotoPoint(pt)
if not turtle.placeDown() then
error('could not place down cell')
end
end
end
local function fluid(points)
print('checking fluid')
turtle.setStatus('fluiding')
gotoPoint(points.source, true)
turtle.select(1)
turtle.digDown()
gotoPoint(points.target)
if not turtle.placeDown() then
error('could not place fluid container')
end
os.sleep(5)
turtle.digDown()
gotoPoint(points.source)
turtle.placeDown()
end
local function refill(entry)
dropOff(locations.dropPt)
turtle.setStatus('refilling')
gotoPoint(locations.dropPt)
local chestAdapter = ChestAdapter()
for _,item in pairs(entry.items) do
chestAdapter:provide(item, tonumber(item.qty), turtle.selectOpenSlot())
end
if turtle.selectSlotWithItems() then
if entry.point then
dropOff(entry.point)
end
end
end
local function makeKey(pt)
return string.format('%d:%d:%d', pt.x, pt.y, pt.z)
end
local function pickupHost(socket)
while true do
local data = socket:read()
if not data then
print('pickup: closing connection to ' .. socket.dhost)
return
end
print('command: ' .. data.type)
if data.type == 'pickup' then
local key = makeKey(data.point)
locations.pickups[key] = data.point
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' })
elseif data.type == 'items' then
socket:write( { type = "response", response = items })
elseif data.type == 'refill' then
local key = makeKey(data.entry.point)
locations.refills[key] = data.entry
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' })
elseif data.type == 'setPickup' then
locations.dropPt = data.point
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'Location set' })
elseif data.type == 'setRecharge' then
locations.chargePt = data.point
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'Location set' })
elseif data.type == 'charge' then
local key = makeKey(data.point)
locations.cells[key] = data.point
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' })
elseif data.type == 'clear' then
local key = makeKey(data.point)
locations.refills[key] = nil
locations.cells[key] = nil
locations.fluids[key] = nil
locations.pickups[key] = nil
Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'cleared' })
else
print('unknown command')
end
end
end
if device.wireless_modem then
Event.addRoutine(function()
while true do
print('waiting for connection on port 5222')
local socket = Socket.server(5222)
print('pickup: connection from ' .. socket.dhost)
Event.addRoutine(function() pickupHost(socket) end)
end
end)
end
local function eachEntry(t, fn)
local keys = Util.keys(t)
for _,key in pairs(keys) do
if t[key] then
if turtle.isAborted() then
return
end
fn(t[key])
end
end
end
local function eachClosestEntry(t, fn)
local points = { }
for k,v in pairs(t) do
v = Util.shallowCopy(v)
v.key = k
table.insert(points, v)
end
while not Util.empty(points) do
local closest = Point.closest(turtle.point, points)
if turtle.isAborted() then
return
end
if t[closest.key] then
fn(closest)
end
for k,v in pairs(points) do
if v.key == closest.key then
table.remove(points, k)
break
end
end
end
end
Event.addRoutine(function()
if not turtle.enableGPS() then
error('turtle: No GPS found')
end
refuel()
while true do
if locations.dropPt then
eachClosestEntry(locations.pickups, pickUp)
eachEntry(locations.refills, refill)
refuel()
end
dropOff(locations.dropPt)
eachEntry(locations.fluids, fluid)
if locations.chargePt then
eachEntry(locations.cells, checkCell)
end
print('sleeping')
turtle.setStatus('sleeping')
if turtle.isAborted() then
printError('aborted')
break
end
os.sleep(60)
end
Event.exitPullEvents()
end)
turtle.run(function()
Event.pullEvents()
end)

233
pickup/pickupRemote.lua Normal file
View File

@@ -0,0 +1,233 @@
if not device.wireless_modem then
error('Wireless modem is required')
end
requireInjector(getfenv(1))
local Event = require('event')
local GPS = require('gps')
local Socket = require('socket')
local UI = require('ui')
local Util = require('util')
multishell.setTitle(multishell.getCurrent(), 'Pickup Remote')
local id
local mainPage = UI.Page({
menu = UI.Menu({
centered = true,
y = 2,
height = 8,
menuItems = {
{ prompt = 'Pickup', event = 'pickup', help = 'Pickup items from this location' },
{ prompt = 'Charge cell', event = 'charge', help = 'Recharge this cell' },
{ prompt = 'Refill', event = 'refill', help = 'Recharge this cell' },
{ prompt = 'Set drop off location', event = 'setPickup', help = 'Recharge this cell' },
{ prompt = 'Set recharge location', event = 'setRecharge', help = 'Recharge this cell' },
{ prompt = 'Clear', event = 'clear', help = 'Remove this location' },
},
}),
statusBar = UI.StatusBar(),
accelerators = {
q = 'quit',
},
})
local refillPage = UI.Page({
menuBar = UI.MenuBar({
y = 1,
buttons = {
{ text = 'Done', event = 'done', help = 'Pickup items from this location' },
{ text = 'Back', event = 'back', help = 'Recharge this cell' },
},
}),
grid1 = UI.ScrollingGrid({
columns = {
{ heading = 'Name', key = 'name', width = UI.term.width-9 },
{ heading = 'Qty', key = 'fQty', width = 5 },
},
sortColumn = 'name',
height = 8,
y = 3,
}),
grid2 = UI.ScrollingGrid({
columns = {
{ heading = 'Name', key = 'name', width = UI.term.width-9 },
{ heading = 'Qty', key = 'qty', width = 5 },
},
sortColumn = 'name',
height = 4,
y = 12,
}),
statusBar = UI.StatusBar(),
accelerators = {
q = 'quit',
},
})
refillPage.menuBar:add({
filter = UI.TextEntry({
x = UI.term.width-10,
width = 10,
})
})
local function sendCommand(cmd)
local socket = Socket.connect(id, 5222)
if not socket then
mainPage.statusBar:timedStatus('Unable to connect', 3)
return
end
socket:write(cmd)
local m = socket:read(3)
socket:close()
if m then
return m.response
end
mainPage.statusBar:timedStatus('No response', 3)
end
local function getPoint()
local gpt = GPS.getPoint(2)
if not gpt then
mainPage.statusBar:timedStatus('Unable to get location', 3)
end
gpt.y = gpt.y - 1
return gpt
end
function refillPage:eventHandler(event)
if event.type == 'grid_select' then
local item = {
name = event.selected.name,
id = event.selected.id,
dmg = event.selected.dmg,
qty = 0,
}
local dialog = UI.Dialog({
x = 1,
width = UI.term.width,
text = UI.Text({ x = 3, y = 3, value = 'Quantity' }),
textEntry = UI.TextEntry({ x = 14, y = 3 })
})
dialog.eventHandler = function(self, event)
if event.type == 'accept' then
local l = tonumber(self.textEntry.value)
if l and l <= 1024 and l > 0 then
item.qty = self.textEntry.value
table.insert(refillPage.grid2.values, item)
refillPage.grid2:update()
UI:setPreviousPage()
else
self.statusBar:timedStatus('Invalid Quantity', 3)
end
return true
end
return UI.Dialog.eventHandler(self, event)
end
dialog.titleBar.title = item.name
dialog:setFocus(dialog.textEntry)
UI:setPage(dialog)
elseif event.type == 'text_change' then
local text = event.text
if #text == 0 then
self.grid1.values = self.allItems
else
self.grid1.values = { }
for _,item in pairs(self.allItems) do
if string.find(item.lname, text) then
table.insert(self.grid1.values, item)
end
end
end
--self.grid:adjustWidth()
self.grid1:update()
self.grid1:setIndex(1)
self.grid1:draw()
elseif event.type == 'back' then
UI:setPreviousPage()
elseif event.type == 'done' then
UI:setPage(mainPage)
local pt = getPoint()
if pt then
local response = sendCommand({ type = 'refill', entry = { point = pt, items = self.grid2.values } })
if response then
mainPage.statusBar:timedStatus(response, 3)
end
end
elseif event.type == 'grid_focus_row' then
self.statusBar:setStatus(event.selected.id .. ':' .. event.selected.dmg)
self.statusBar:draw()
end
return UI.Page.eventHandler(self, event)
end
function refillPage:enable()
for _,item in pairs(self.allItems) do
item.lname = string.lower(item.name)
item.fQty = Util.toBytes(item.qty)
end
self.grid1:setValues(self.allItems)
self.menuBar.filter.value = ''
self.menuBar.filter.pos = 1
self:setFocus(self.menuBar.filter)
UI.Page.enable(self)
end
function mainPage:eventHandler(event)
if event.type == 'quit' then
Event.exitPullEvents()
elseif event.type == 'refill' then
local response = sendCommand({ type = 'items' })
if response then
refillPage.allItems = response
refillPage.grid2:setValues({ })
UI:setPage(refillPage)
end
elseif event.type == 'pickup' or event.type == 'setPickup' or
event.type == 'setRecharge' or event.type == 'charge' or
event.type == 'clear' then
local pt = getPoint()
if pt then
local response = sendCommand({ type = event.type, point = pt })
if response then
self.statusBar:timedStatus(response, 3)
end
end
end
return UI.Page.eventHandler(self, event)
end
local args = { ... }
if #args == 1 then
id = tonumber(args[1])
end
if not id then
error('Syntax: pickupRemote <turtle ID>')
end
UI:setPage(mainPage)
Event.pullEvents()
UI.term:reset()