multiMiner

This commit is contained in:
kepler155c@gmail.com
2019-01-17 11:22:10 -05:00
parent ad671621e8
commit 7914990d6c
4 changed files with 252 additions and 107 deletions

View File

@@ -402,12 +402,12 @@ function Storage:export(target, slot, count, item)
local function provide(adapter) local function provide(adapter)
local amount = rawExport(adapter, target.adapter, item, count, slot) local amount = rawExport(adapter, target.adapter, item, count, slot)
_G._debug('EXT: %s(%d): %s -> %s%s',
item.displayName or item.name, amount, self:_sn(adapter.name), self:_sn(target.name),
slot and string.format('[%d]', slot) or '[*]')
if amount > 0 then if amount > 0 then
self:updateCache(adapter, item, -amount) self:updateCache(adapter, item, -amount)
_G._debug('EXT: %s(%d): %s -> %s%s',
item.displayName or item.name, amount, self:_sn(adapter.name), self:_sn(target.name),
slot and string.format('[%d]', slot) or '[*]')
end end
count = count - amount count = count - amount
total = total + amount total = total + amount
@@ -481,13 +481,13 @@ function Storage:import(source, slot, count, item)
local function insert(adapter) local function insert(adapter)
local amount = rawInsert(adapter, source.adapter, slot, count) local amount = rawInsert(adapter, source.adapter, slot, count)
_G._debug('INS: %s(%d): %s[%d] -> %s',
item.displayName or item.name, amount,
self:_sn(source.name), slot, self:_sn(adapter.name))
if amount > 0 then if amount > 0 then
self:updateCache(adapter, item, amount) self:updateCache(adapter, item, amount)
_G._debug('INS: %s(%d): %s[%d] -> %s',
item.displayName or item.name, amount,
self:_sn(source.name), slot, self:_sn(adapter.name))
-- record that we have imported this item into storage during this cycle -- record that we have imported this item into storage during this cycle
self.activity[key] = (self.activity[key] or 0) + amount self.activity[key] = (self.activity[key] or 0) + amount
end end

View File

@@ -1,11 +1,28 @@
{ {
[ "4486006f811b88cacd5f211fd579717e29b600cd" ] = { [ "4486006f811b88cacd5f211fd579717e29b600cd" ] = {
title = "Miner", title = "Simple",
category = "Apps", category = "Mining",
icon = " \0315\\\030 \031 \ icon = " \0315\\\030 \031 \
\0304\031f _ \030 \031c/\0315\\\ \0304\031f _ \030 \031c/\0315\\\
\0304 ", \0304 ",
run = "simpleMiner.lua", run = "simpleMiner.lua",
requires = 'turtle', requires = 'turtle',
}, },
[ "4486006f811b88cacd5f211fd579717e29b600cd" ] = {
title = "Scanning",
category = "Mining",
icon = " \0315\\\030 \031 \
\0304\031f _ \030 \031c/\0315\\\
\0304 ",
run = "scanningMiner.lua",
requires = 'turtle',
},
[ "4486006f811b88cacd5f211fd579717e29b600cd" ] = {
title = "Multi",
category = "Mining",
icon = " \0315\\\030 \031 \
\0304\031f _ \030 \031c/\0315\\\
\0304 ",
run = "multiMiner.lua",
},
} }

View File

@@ -28,35 +28,18 @@ local function locate()
end end
local spt = GPS.getPoint() or error('GPS failure') local spt = GPS.getPoint() or error('GPS failure')
local chestPoint -- location of chest
local blockTypes = { } -- blocks types requested to mine local blockTypes = { } -- blocks types requested to mine
local turtles = { } local turtles = { } -- active turtles
local pool = { } -- all turtles
local queue = { } -- actual blocks to mine local queue = { } -- actual blocks to mine
local abort local abort
local page = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Scan', event = 'scan' },
{ text = 'Abort', event = 'abort' },
},
},
grid = UI.ScrollingGrid {
y = 2, ey = -4,
columns = {
{ heading = 'Name', key = 'displayName' },
{ heading = 'Count', key = 'count', width = 5, justify = 'right' },
},
sortColumn = 'displayName',
},
info = UI.Window {
y = -3,
}
}
local function hijackTurtle(remoteId) local function hijackTurtle(remoteId)
local socket, msg = Socket.connect(remoteId, 188) local socket, msg = Socket.connect(remoteId, 188)
if not socket then if not socket then
printError(remoteId)
error(msg) error(msg)
end end
@@ -69,7 +52,7 @@ local function hijackTurtle(remoteId)
socket:write({ fn = method, args = { ... } }) socket:write({ fn = method, args = { ... } })
local resp = socket:read() local resp = socket:read()
if not resp then if not resp then
error('timed out') error('timed out: ' .. method)
end end
return table.unpack(resp) return table.unpack(resp)
end end
@@ -87,72 +70,157 @@ local function getNextPoint(turtle)
end end
end end
local function run(id) local function run(member, point)
Event.addRoutine(function() Event.addRoutine(function()
local turtle = hijackTurtle(id) --local _, m = pcall(function()
member.active = true
local turtle = hijackTurtle(member.id)
if turtle.getFuelLevel(id) < 100 then local function emptySlots(retain, pt)
return local slots = turtle.getFilledSlots()
end for _,slot in pairs(slots) do
if not retain[slot.key] then
local function emptySlots(retain) turtle.select(slot.index)
local slots = turtle.getFilledSlots() turtle.dropAt(pt, 64)
for _,slot in pairs(slots) do end
if not retain[slot.key] then
turtle.select(slot.index)
turtle.dropUp(64)
end end
end end
end
local function enableGPS() local function dropOff()
for _ = 1, 3 do if chestPoint then
if turtle.enableGPS() then local topPoint = Point.copy(chestPoint)
return topPoint.y = topPoint.y + 2
end turtle.gotoY(topPoint.y)
end while not turtle._goto(topPoint) do
error('GPS locate failed') os.sleep(.5)
end end
if turtle then -- drop off
turtles[id] = turtle local box = Point.makeBox(
{ x = chestPoint.x - 3, y = chestPoint.y + 3, z = chestPoint.z - 3 },
turtle.resetState() { x = chestPoint.x + 3, y = chestPoint.y, z = chestPoint.z + 3 }
enableGPS() )
turtle.setPolicy('turtleSafe') turtle.setMovementStrategy('pathing')
turtle.setMovementStrategy('goto') turtle.setPathingBox(Point.normalizeBox(box))
turtle.setPolicy('none')
repeat while not turtle.moveAgainst(chestPoint) do
local pt = getNextPoint(turtle) os.sleep(.5)
if pt then end
turtle.digAt(pt, pt.name) emptySlots({ }, chestPoint)
turtle.pathfind(Point.above(topPoint))
turtle.setMovementStrategy('goto')
turtle.setPolicy('turtleSafe')
else else
os.sleep(1) turtle.gotoY(spt.y)
end
if turtle.getItemCount(15) > 0 then
emptySlots(blockTypes)
turtle.condense()
end
if turtle.getItemCount(15) > 0 then
turtle._goto(spt) turtle._goto(spt)
emptySlots({ }) emptySlots({ }, Point.above(spt))
end end
if turtle.getFuelLevel() < 100 then end
turtle._goto(spt)
emptySlots({ }) if turtle then
break turtles[member.id] = turtle
turtle.reset()
turtle.setPolicy('turtleSafe')
turtle.setMovementStrategy('goto')
turtle.setPoint(point)
repeat
local pt = getNextPoint(turtle)
if pt then
member.status = 'digging'
turtle.digAt(pt, pt.name)
if turtle.getItemCount(15) > 0 then
member.status = 'ejecting trash'
emptySlots(blockTypes, Point.above(turtle.getPoint()))
turtle.condense()
if turtle.getItemCount(15) > 0 then
member.status = 'dropping off'
if not chestPoint then
member.abort = true
member.status = 'full'
else
dropOff()
end
end
end
else
member.status = 'waiting'
os.sleep(1)
end
if member.fuel < 100 then
member.status = 'out of fuel'
break
end
until member.abort
end
if chestPoint then
dropOff()
while not turtle._goto(Point.above(spt)) do
os.sleep(.5)
end end
until abort turtle.setPolicy('digOnly')
end turtle._goto(spt)
turtle._goto(spt) else
turtles[id] = nil turtle.gotoY(spt.y)
turtle._goto(spt)
end
--end)
turtles[member.id] = nil
--member.status = m
member.active = false
end) end)
end end
local blocksTab = UI.Window {
tabTitle = 'Blocks',
grid = UI.ScrollingGrid {
y = 1,
columns = {
{ heading = 'Name', key = 'displayName' },
{ heading = 'Count', key = 'count', width = 5, justify = 'right' },
},
sortColumn = 'displayName',
},
}
local turtlesTab = UI.Window {
tabTitle = 'Turtles',
grid = UI.ScrollingGrid {
y = 1,
values = pool,
columns = {
{ heading = 'ID', key = 'label', width = 12, },
{ heading = 'Fuel', key = 'fuel', width = 5, justify = 'right' },
{ heading = 'Status', key = 'status' },
},
sortColumn = 'label',
},
}
local page = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Scan', event = 'scan' },
{ text = 'Abort', event = 'abort' },
},
},
tabs = UI.Tabs {
y = 2, ey = -2,
[1] = blocksTab,
[2] = turtlesTab,
},
info = UI.Window {
y = -1,
backgroundColor = colors.gray,
}
}
function page.info:draw() function page.info:draw()
self:clear() self:clear()
self:write(2, 1, 'Turtles: ' .. Util.size(turtles)) self:write(2, 1, 'Turtles: ' .. Util.size(turtles))
self:write(2, 2, 'Queue: ' .. Util.size(queue)) self:write(20, 1, 'Queue: ' .. Util.size(queue))
end end
function page:scan() function page:scan()
@@ -162,6 +230,7 @@ function page:scan()
return return
end end
local rawBlocks = scanner:scan() local rawBlocks = scanner:scan()
local candidates = { }
self.totals = Util.reduce(rawBlocks, self.totals = Util.reduce(rawBlocks,
function(acc, b) function(acc, b)
@@ -175,6 +244,15 @@ function page:scan()
entry.count = entry.count + 1 entry.count = entry.count + 1
end end
if b.name == 'computercraft:turtle_advanced' or
b.name == 'computercraft:turtle' then
table.insert(candidates, b)
end
if b.name == 'minecraft:chest' then
chestPoint = b
end
-- add relevant blocks to queue -- add relevant blocks to queue
b.x = gpt.x + b.x b.x = gpt.x + b.x
b.y = gpt.y + b.y b.y = gpt.y + b.y
@@ -190,32 +268,51 @@ function page:scan()
queue[b.pkey] = nil queue[b.pkey] = nil
end end
end, end,
{ }) { })
for _, b in pairs(candidates) do
local v = scanner.getBlockMeta(b.x - gpt.x, b.y - gpt.y, b.z - gpt.z)
if v and v.computer then
local member = pool[v.computer.id]
if not member then
member = {
id = v.computer.id,
label = v.computer.label,
}
pool[v.computer.id] = member
end
member.fuel = v.turtle.fuel
member.distance = 0
if not v.computer.isOn then
member.status = 'Powered off'
elseif v.turtle.fuel < 100 and not member.active then
member.status = 'Not enough fuel'
elseif not member.active and not member.abort then
local pt = Point.copy(b)
pt.heading = Point.facings[v.state.facing].heading
run(member, pt)
end
end
end
end end
function page.grid:getDisplayValues(row) function blocksTab.grid:getDisplayValues(row)
row = Util.shallowCopy(row) row = Util.shallowCopy(row)
row.count = Util.toBytes(row.count) row.count = Util.toBytes(row.count)
return row return row
end end
function page.grid:getRowTextColor(row, selected) function blocksTab.grid:getRowTextColor(row, selected)
return blockTypes[row.key] and return blockTypes[row.key] and
colors.yellow or colors.yellow or
UI.Grid.getRowTextColor(self, row, selected) UI.Grid.getRowTextColor(self, row, selected)
end end
function page:eventHandler(event) function blocksTab:eventHandler(event)
if event.type == 'scan' then if event.type == 'grid_select' then
self.grid:setValues(self.totals) local key = event.selected.key
self.grid:draw()
elseif event.type == 'abort' then
spt = Point.above(locate())
abort = true
elseif event.type == 'grid_select' then
local key = self.grid:getSelected().key
if blockTypes[key] then if blockTypes[key] then
for k,v in pairs(queue) do for k,v in pairs(queue) do
if v.key == key then if v.key == key then
@@ -224,42 +321,72 @@ function page:eventHandler(event)
end end
blockTypes[key] = nil blockTypes[key] = nil
else else
blockTypes[self.grid:getSelected().key] = true blockTypes[key] = true
end end
self.grid:draw() self.grid:draw()
end
end
function page:eventHandler(event)
if event.type == 'scan' then
blocksTab.grid:setValues(self.totals)
blocksTab.grid:draw()
self.tabs:selectTab(blocksTab)
elseif event.type == 'abort' then
for _, v in pairs(pool) do
v.abort = true
v.status = 'aborting'
end
spt = Point.above(locate())
abort = true
end end
UI.Page.eventHandler(self, event) UI.Page.eventHandler(self, event)
end end
Event.onInterval(3, function() Event.onInterval(3, function()
page:scan() if not abort then
page:scan()
end
end) end)
Event.onInterval(1, function() Event.onInterval(1, function()
if not abort then if not abort then
for k,v in pairs(network) do for id,v in pairs(network) do
if v.active and v.distance and v.distance < 16 and if v.fuel then
not turtles[k] and v.fuel and v.fuel > 100 then if pool[id] then
turtles[k] = run(k) pool[id].fuel = v.fuel
elseif not v.active and turtles[k] then pool[id].distance = v.distance
turtles[k] = nil end
end end
end end
elseif Util.size(turtles) == 0 then elseif Util.size(turtles) == 0 then
Event.exitPullEvents() Event.exitPullEvents()
end end
if turtlesTab.enabled then
turtlesTab.grid:update()
turtlesTab.grid:draw()
end
page.info:draw() page.info:draw()
page.info:sync() page.info:sync()
end) end)
page:scan() Event.onTimeout(.5, function()
page.grid:setValues(page.totals) page:scan()
blocksTab.grid:setValues(page.totals)
end)
UI:setPage(page) UI:setPage(page)
Event.onTerminate(function() Event.onTerminate(function()
spt = Point.above(locate()) spt = Point.above(locate())
for _, v in pairs(pool) do
v.status = 'aborting'
v.abort = true
end
abort = true abort = true
end) end)

View File

@@ -103,6 +103,7 @@ end
function page.detail:eventHandler(event) function page.detail:eventHandler(event)
if event.type == 'grid_select' then if event.type == 'grid_select' then
projecting = event.selected projecting = event.selected
_G._p = scanner.getBlockMeta(projecting.x, projecting.y, projecting.z)
else else
return UI.SlideOut.eventHandler(self, event) return UI.SlideOut.eventHandler(self, event)
end end