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)
if amount > 0 then
self:updateCache(adapter, item, -amount)
_G._debug('EXT: %s(%d): %s -> %s%s', _G._debug('EXT: %s(%d): %s -> %s%s',
item.displayName or item.name, amount, self:_sn(adapter.name), self:_sn(target.name), item.displayName or item.name, amount, self:_sn(adapter.name), self:_sn(target.name),
slot and string.format('[%d]', slot) or '[*]') slot and string.format('[%d]', slot) or '[*]')
if amount > 0 then
self:updateCache(adapter, item, -amount)
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)
if amount > 0 then
self:updateCache(adapter, item, amount)
_G._debug('INS: %s(%d): %s[%d] -> %s', _G._debug('INS: %s(%d): %s[%d] -> %s',
item.displayName or item.name, amount, item.displayName or item.name, amount,
self:_sn(source.name), slot, self:_sn(adapter.name)) self:_sn(source.name), slot, self:_sn(adapter.name))
if amount > 0 then
self:updateCache(adapter, item, amount)
-- 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
end
local function emptySlots(retain)
local slots = turtle.getFilledSlots() local slots = turtle.getFilledSlots()
for _,slot in pairs(slots) do for _,slot in pairs(slots) do
if not retain[slot.key] then if not retain[slot.key] then
turtle.select(slot.index) turtle.select(slot.index)
turtle.dropUp(64) turtle.dropAt(pt, 64)
end 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
turtle.gotoY(topPoint.y)
while not turtle._goto(topPoint) do
os.sleep(.5)
end end
-- drop off
local box = Point.makeBox(
{ x = chestPoint.x - 3, y = chestPoint.y + 3, z = chestPoint.z - 3 },
{ x = chestPoint.x + 3, y = chestPoint.y, z = chestPoint.z + 3 }
)
turtle.setMovementStrategy('pathing')
turtle.setPathingBox(Point.normalizeBox(box))
turtle.setPolicy('none')
while not turtle.moveAgainst(chestPoint) do
os.sleep(.5)
end
emptySlots({ }, chestPoint)
turtle.pathfind(Point.above(topPoint))
turtle.setMovementStrategy('goto')
turtle.setPolicy('turtleSafe')
else
turtle.gotoY(spt.y)
turtle._goto(spt)
emptySlots({ }, Point.above(spt))
end end
error('GPS locate failed')
end end
if turtle then if turtle then
turtles[id] = turtle turtles[member.id] = turtle
turtle.resetState() turtle.reset()
enableGPS()
turtle.setPolicy('turtleSafe') turtle.setPolicy('turtleSafe')
turtle.setMovementStrategy('goto') turtle.setMovementStrategy('goto')
turtle.setPoint(point)
repeat repeat
local pt = getNextPoint(turtle) local pt = getNextPoint(turtle)
if pt then if pt then
member.status = 'digging'
turtle.digAt(pt, pt.name) 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 else
dropOff()
end
end
end
else
member.status = 'waiting'
os.sleep(1) os.sleep(1)
end end
if turtle.getItemCount(15) > 0 then if member.fuel < 100 then
emptySlots(blockTypes) member.status = 'out of fuel'
turtle.condense()
end
if turtle.getItemCount(15) > 0 then
turtle._goto(spt)
emptySlots({ })
end
if turtle.getFuelLevel() < 100 then
turtle._goto(spt)
emptySlots({ })
break break
end end
until abort until member.abort
end end
if chestPoint then
dropOff()
while not turtle._goto(Point.above(spt)) do
os.sleep(.5)
end
turtle.setPolicy('digOnly')
turtle._goto(spt) turtle._goto(spt)
turtles[id] = nil else
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
@@ -191,31 +269,50 @@ function page:scan()
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 end
function page.grid:getDisplayValues(row) 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
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()
if not abort then
page:scan() 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)
Event.onTimeout(.5, function()
page:scan() page:scan()
page.grid:setValues(page.totals) 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