multiMiner
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user