From 755c37bc9bd80de2b2acfa502cff67728470c60d Mon Sep 17 00:00:00 2001 From: kepler155c Date: Sun, 14 Oct 2018 15:37:54 -0400 Subject: [PATCH] new icon set + scanning miner --- apps/farm.lua | 44 ++- apps/scanningMiner.lua | 596 +++++++++++++++++++++++++++++++++++++++++ etc/apps/opus-apps.db | 52 +++- 3 files changed, 670 insertions(+), 22 deletions(-) create mode 100644 apps/scanningMiner.lua diff --git a/apps/farm.lua b/apps/farm.lua index 088c412..a3b37da 100644 --- a/apps/farm.lua +++ b/apps/farm.lua @@ -1,15 +1,29 @@ _G.requireInjector(_ENV) local Point = require('point') -local Util = require('util') +local Util = require('util') -local scanner = device['plethora:scanner'] +local scanner = device['plethora:scanner'] or error('Plethora scanner required') + +local crops = { + ['minecraft:wheat'] = + { seed = 'minecraft:wheat_seeds', mature = 7 }, + ['minecraft:carrots'] = + { seed = 'minecraft:carrot', mature = 7 }, + ['minecraft:potatoes'] = + { seed = 'minecraft:potato', mature = 7 }, + ['minecraft:beetroots'] = + { seed = 'minecraft:beetroot_seeds', mature = 3 }, +} local function scan() local blocks = scanner.scan() Util.filterInplace(blocks, function(v) - return v.name == 'minecraft:wheat' and - scanner.getBlockMeta(v.x, v.y, v.z).metadata == 7 + if v.name == 'minecraft:reeds' then + return v.y == 0 + end + return crops[v.name] and + scanner.getBlockMeta(v.x, v.y, v.z).metadata == crops[v.name].mature end) return blocks @@ -18,21 +32,31 @@ end local function harvest(blocks) Point.eachClosest(turtle.point, blocks, function(b) Util.print(b) - turtle.goto(Point.above(b)) - turtle.digDown() - turtle.placeDown('minecraft:wheat_seeds') + if b.name == 'minecraft:reeds' then + turtle.goto(b) + else + turtle.goto(Point.above(b)) + turtle.digDown() + turtle.placeDown(crops[b.name].seed) + turtle.select(1) + end end) end turtle.reset() -local directions = { [5] = 2, [3] = 3, [4] = 0, [2] = 1, } -turtle.placeUp('minecraft:chest') +local directions = { [5] = 2, [3] = 3, [4] = 0, [2] = 1, } +turtle.placeUp('minecraft:chest') or error('Missing chest') local _, bi = turtle.inspectUp() turtle.digUp() turtle.point.heading = directions[bi.metadata] +turtle.setPolicy('digOnly') + while true do + print('scanning') local blocks = scan() + turtle.setPoint({ x = 0, y = 0, z = 0, heading = turtle.point.heading }) harvest(blocks) + print('sleeping') os.sleep(10) -end \ No newline at end of file +end diff --git a/apps/scanningMiner.lua b/apps/scanningMiner.lua new file mode 100644 index 0000000..b72d02f --- /dev/null +++ b/apps/scanningMiner.lua @@ -0,0 +1,596 @@ +--[[ + Efficient miner + + GPS is required. + + Miner Requires: + Diamond pick + Ender Modem + Plethora scanner + Bucket +--]] +_G.requireInjector(_ENV) + +local Event = require('event') +local GPS = require('gps') +local Point = require('point') +local UI = require('ui') +local Util = require('util') + +local colors = _G.colors +local fs = _G.fs +local os = _G.os +local peripheral = _G.peripheral +local read = _G.read +local turtle = _G.turtle + +local args = { ... } +local options = { + chunks = { arg = 'c', type = 'number', value = -1, + desc = 'Number of chunks to mine' }, + setTrash = { arg = 's', type = 'flag', value = false, + desc = 'Set trash items' }, + help = { arg = 'h', type = 'flag', value = false, + desc = 'Displays the options' }, +} + +local MIN_FUEL = 7500 +local LOW_FUEL = 1500 +local MAX_FUEL = turtle.getFuelLimit() + +local DICTIONARY_FILE = 'usr/config/mining.dictionary' +local PROGRESS_FILE = 'usr/config/scanning_mining.progress' + +local mining +local ignores = { + ignore = true, + retain = true, +} + +local dictionary = { + data = Util.readTable(DICTIONARY_FILE) or { + [ 'minecraft:chest' ] = 'suck', + [ 'minecraft:lava' ] = 'liquid_fuel', + [ 'minecraft:flowing_lava' ] = 'liquid_fuel', + [ 'minecraft:bedrock' ] = 'ignore', + [ 'minecraft:flowing_water' ] = 'ignore', + [ 'minecraft:water' ] = 'ignore', + [ 'minecraft:air' ] = 'ignore', + [ 'minecraft:bucket' ] = 'retain', + [ 'computercraft:advanced_modem' ] = 'retain', + [ 'minecraft:diamond_pickaxe' ] = 'retain', + [ 'plethora:module' ] = 'retain', + }, +} + +function dictionary:write() + Util.writeTable(DICTIONARY_FILE, self.data) +end +function dictionary:mineable(name, damage) + self.data[name .. ':' .. damage] = nil +end +function dictionary:ignore(name, damage) + if damage then + self.data[name .. ':' .. damage] = 'ignore' + else + self.data[name] = 'ignore' + end +end +function dictionary:get(name, damage) + return self.data[name] or self.data[name .. ':' .. damage] +end +function dictionary:isTrash(name, damage) + return self:get(name, damage) == 'ignore' +end + +local page = UI.Page { + menuBar = UI.MenuBar { + buttons = { + --{ text = 'Mine', event = 'mine' }, + { text = 'Ignore', event = 'ignore' }, + { text = 'Ignore All', event = 'ignore_all' }, + }, + }, + grid = UI.Grid { + y = 2, ey = -2, + sortColumn = 'name', + columns = { + { heading = 'Resource', key = 'displayName' }, + { heading = 'Count', key = 'count', width = 6 }, + }, + }, + statusBar = UI.StatusBar { + columns = { + { key = 'status' }, + { key = 'fuel', width = 6 }, + }, + }, + accelerators = { + q = 'cancel', + } +} + +function page:eventHandler(event) + local t = self.grid:getSelected() + if t then + if event.type == 'mine' then + dictionary:mineable(t.name, t.damage) + dictionary:write() + + elseif event.type == 'ignore' then + dictionary:ignore(t.name, t.damage) + dictionary:write() + self.grid:draw() + + elseif event.type == 'ignore_all' then + dictionary:ignore(t.name) + dictionary:write() + self.grid:draw() + end + end + if event.type == 'quit' then + turtle.abort(true) + end + UI.Page.eventHandler(self, event) +end + +function page.grid:getRowTextColor(row, selected) + if dictionary:get(row.name, row.damage) == 'ignore' then + return colors.lightGray + end + if row.displayName == self.nextBlock then + return colors.yellow + end + return UI.Grid.getRowTextColor(self, row, selected) +end + +local function getChunkCoordinates(diameter, index, x, z) + local dirs = { -- circumference of grid + { xd = 0, zd = 1, heading = 1 }, -- south + { xd = -1, zd = 0, heading = 2 }, + { xd = 0, zd = -1, heading = 3 }, + { xd = 1, zd = 0, heading = 0 } -- east + } + -- always move east when entering the next diameter + if index == 0 then + dirs[4].x = x + 16 + dirs[4].z = z + return dirs[4] + end + local dir = dirs[math.floor(index / (diameter - 1)) + 1] + dir.x = x + dir.xd * 16 + dir.z = z + dir.zd * 16 + return dir +end + +local function getCornerOf(c) + return math.floor(c.x / 16) * 16, math.floor(c.z / 16) * 16 +end + +local function nextChunk() + local x, z = getCornerOf({ x = mining.x, z = mining.z }) + local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2) + mining.chunkIndex = mining.chunkIndex + 1 + + if mining.chunkIndex >= points then + mining.diameter = mining.diameter + 2 + mining.chunkIndex = 0 + end + + if mining.chunks ~= -1 then + local chunks = math.pow(mining.diameter-2, 2) + mining.chunkIndex + if chunks >= mining.chunks then + return false + end + end + + local nc = getChunkCoordinates(mining.diameter, mining.chunkIndex, x, z) + + -- enter next chunk + mining.x = nc.x + mining.z = nc.z + + Util.writeTable(PROGRESS_FILE, mining) + + return true +end + +local function status(newStatus) + turtle.setStatus(newStatus) + page.statusBar:setValue('status', newStatus) + page.statusBar:draw() + page:sync() +end + +local function refuel() + if turtle.getFuelLevel() < MIN_FUEL then + local oldStatus = turtle.getStatus() + status('refueling') + + turtle.refuel('minecraft:coal:0', 32) + if turtle.getFuelLevel() < MIN_FUEL then + turtle.eachFilledSlot(function(slot) + if turtle.getFuelLevel() < MIN_FUEL then + turtle.select(slot.index) + turtle.refuel(64) + end + end) + end + status(oldStatus) + end + + turtle.select(1) +end + +local function safeGoto(x, z, y, h) + local oldStatus = turtle.getStatus() + + while not turtle._goto({ x = x, z = z, y = y or turtle.point.y, heading = h }) do + --status('stuck') + if turtle.isAborted() then + return false + end + os.sleep(3) + end + turtle.setStatus(oldStatus) + return true +end + +local function safeGotoY(y) + local oldStatus = turtle.getStatus() + while not turtle.gotoY(y) do + status('stuck') + if turtle.isAborted() then + return false + end + os.sleep(1) + end + turtle.setStatus(oldStatus) + return true +end + +local function unload() + local oldStatus = turtle.getStatus() + status('unloading') + local pt = Util.shallowCopy(turtle.point) + safeGotoY(0) + + safeGoto(0, 0, 0) + if not turtle.detectUp() then + error('no chest') + end + local slots = turtle.getFilledSlots() + for _,slot in pairs(slots) do + local action = dictionary:get(slot.name, slot.damage) + if not ignores[action] then + turtle.select(slot.index) + turtle.dropUp(64) + end + end + turtle.condense() + turtle.select(1) + safeGoto(pt.x, pt.z, 0, pt.heading) + + safeGotoY(pt.y) + status(oldStatus) +end + +local function ejectTrash() + turtle.eachFilledSlot(function(slot) + if dictionary:isTrash(slot.name, slot.damage) then + turtle.select(slot.index) + turtle.dropDown(64) + end + end) +end + +local function checkSpace() + if turtle.getItemCount(15) > 0 then + refuel() + local oldStatus = turtle.getStatus() + status('condensing') + ejectTrash() + turtle.condense() + if turtle.getItemCount(15) > 0 then + unload() + end + status(oldStatus) + turtle.select(1) + end +end + +local function collectDrops(suckAction) + for _ = 1, 50 do + checkSpace() + if not suckAction() then + break + end + end +end + +local function equip(side, item) + if not turtle.equip(side, item) then + turtle.selectSlotWithQuantity(0) + turtle.equip(side) + if not turtle.equip(side, item) then + error('Unable to equip ' .. item) + end + end +end + +local function scan() + equip('left', 'plethora:module') + local blocks = peripheral.call('left', 'scan') + equip('left', 'minecraft:diamond_pickaxe') + + local bedrock = -256 + local counts = { } + + for _, b in pairs(blocks) do + if b.x == 0 and b.y == 0 and b.z == 0 then + b.name = 'minecraft:air' + end + b.x = b.x + turtle.point.x + b.y = b.y + turtle.point.y + b.z = b.z + turtle.point.z + + if b.name == 'minecraft:bedrock' then + if b.y > bedrock then + bedrock = b.y + end + end + end + + Util.filterInplace(blocks, function(b) + if b.y >= 0 or + (b.action == 'liquid_fuel' and b.y <= bedrock) then + return false + + elseif b.y >= bedrock then + b.action = dictionary:get(b.name, b.metadata) or 'mine' + + if ignores[b.action] then + return false + end + + local key = b.name .. ':' .. b.metadata + if not counts[key] then + counts[key] = { + displayName = key, + name = b.name, + damage = b.metadata, + count = 1 + } + else + counts[key].count = counts[key].count + 1 + end + return true + end + end) + + turtle.select(1) + + local dirty = true + + local function display() + if dirty then + page.grid:draw() + page:sync() + end + dirty = false + end + + page.grid:setValues(counts) + page.grid:draw() + display() + + status('mining') + + local i = #blocks + Point.eachClosest(turtle.point, blocks, function(b) + if turtle.isAborted() then + return + end + + page.grid.nextBlock = b.displayName + + -- Get the action again in case the user has ignored via UI + b.action = dictionary:get(b.name, b.metadata) or 'mine' + if b.action == 'suck' or b.action == 'mine' then + if b.action == 'suck' then + local pt = turtle.moveAgainst(b) + collectDrops(turtle.getAction(pt.direction).suck) + end + checkSpace() + local s, m + if b.y == bedrock then + s, m = turtle.digDownAt(b) + else + s, m = turtle.digAt(b) + end + if not s then + page.statusBar:setValue('status', m) + page.statusBar:draw() + page:sync() + os.sleep(5) + end + dirty = true + elseif b.action == 'liquid_fuel' then + if turtle.getFuelLevel() < (MAX_FUEL - 1000) then + if turtle.placeAt(b, 'minecraft:bucket:0') then + turtle.refuel() + turtle.select(1) + dirty = true + end + end + end + local key = b.name .. ':' .. b.metadata + counts[key].count = counts[key].count - 1 + i = i - 1 + display() + end) +end + +local function mineChunk() + local topDown = turtle.point.y > -mining.home.y / 2 + local y = topDown and -8 or -mining.home.y + 8 + local inc = topDown and + function() y = y - 16 end or + function() y = y + 16 end + + while true do + status('scanning') + turtle.select(1) + turtle._goto({ x = mining.x + 8, z = mining.z + 8, y = y }) + scan() + if turtle.isAborted() then + status('aborting') + return false + end + if turtle.getFuelLevel() < LOW_FUEL then + refuel() + local veryMinFuel = Point.turtleDistance(turtle.point, { x = 0, y = 0, z = 0}) + 512 + if turtle.getFuelLevel() < veryMinFuel then + page.statusBar:setValue('Not enough fuel to continue') + page.statusBar:draw() + page:sync() + return false + end + end + inc() + + if y > 0 or y < -mining.home.y then + break + end + end + + return true +end + +local function addTrash() + local slots = turtle.getFilledSlots() + + for _,slot in pairs(slots) do + local e = dictionary:get(slot.name, slot.damage) + if not e or e ~= 'retain' then + dictionary:ignore(slot.name, slot.damage) + end + end + + dictionary:write() +end + +-- Startup logic +if not Util.getOptions(options, args) then + return +end + +-- in plethora code, we can override initialize with a scanner version +turtle.initialize = function() + if turtle.isEquipped('modem') ~= 'right' then + equip('right', 'computercraft:advanced_modem') + end + + equip('left', 'minecraft:diamond_pickaxe') + + local function verify(item) + if not turtle.has(item) then + error('Missing: ' .. item) + end + end + + local items = { 'minecraft:bucket', 'plethora:module' } + for _,v in pairs(items) do + verify(v) + end + + --os.sleep(5) + local pt = GPS.getPoint(2) or error('GPS not found') + equip('left', 'plethora:module') + local facing = peripheral.call('left', 'getBlockMeta', 0, 0, 0).state.facing + pt.heading = Point.facings[facing].heading + turtle.setPoint(pt, true) + equip('left', 'minecraft:diamond_pickaxe') +end + +local function main() + repeat + if not mineChunk() then + return + end + Util.writeTable(PROGRESS_FILE, mining) + until not nextChunk() +end + +Event.addRoutine(function() + turtle.run(function() + turtle.reset() + + if not fs.exists(DICTIONARY_FILE) or options.setTrash.value then + print('Add blocks to ignore, press enter when ready') + read() + addTrash() + end + + ejectTrash() + + turtle.initialize { + right = 'computercraft:advanced_modem', + left = 'minecraft:diamond_pickaxe', + required = { + 'minecraft:bucket', + 'plethora:module', + }, + GPS = true, + minFuel = 100, + -- searchFor = 'ironchest:iron_shulker_box_white' + } + + turtle.setMoveCallback(function() + page.statusBar:setValue('fuel', Util.toBytes(turtle.getFuelLevel())) + page.statusBar:draw() + page:sync() + end) + + mining = Util.readTable(PROGRESS_FILE) or { + diameter = 1, + chunkIndex = 0, + x = 0, z = 0, + chunks = options.chunks.value, + home = Point.copy(turtle.point), + heading = turtle.point.heading, -- always using east for now + } + + -- use coordinates relative to initial starting point + turtle.setPoint({ + x = turtle.point.x - mining.home.x, + y = turtle.point.y - mining.home.y, + z = turtle.point.z - mining.home.z, + }) + + if not fs.exists(PROGRESS_FILE) then + Util.writeTable(PROGRESS_FILE, mining) + end + + turtle.setPolicy(turtle.policies.digAttack) + turtle.setDigPolicy(turtle.digPolicies.turtleSafe) + turtle.setMovementStrategy('goto') + status('mining') + + local s, m = pcall(main) + + status(s and 'finished' or 'error') + turtle._goto({ x = 0, y = 0, z = 0 }) + turtle.reset() + + if not s and m then + _G.printError(m) + end + + Event.exitPullEvents() + end) +end) + +UI:setPage(page) +UI:pullEvents() +UI.term:reset() diff --git a/etc/apps/opus-apps.db b/etc/apps/opus-apps.db index ee5ea7d..8f0ccc4 100644 --- a/etc/apps/opus-apps.db +++ b/etc/apps/opus-apps.db @@ -5,14 +5,20 @@ icon = " \0305 \030c \0305 \030 \ \030d \030c \0305 \030c \0308 \030d\031f\"\ \0308\031f.\030 \031 \0308\031f.\030 \031 ", + iconExt = "\030 \031f\030f\031f\128\0305\135\030c\031c\128\128\0305\031f\139\0307\149\0308\0317\143\0307\128\ +\030 \031f\030c\031f\145\031c\128\030d\132\136\030c\128\0307\149\0318\143\133\ +\030 \031f\030f\031f\128\0317\143\031f\128\128\0317\143\031f\128\128\128", run = "Turtles.lua", }, [ "381e3298b2b8f6caeb2208b57d805ada38402f0b" ] = { + title = "Scripts", category = "Apps", icon = "\0300\0317if\031 \0307 \ \0300\0317turt\ \0300\0317retu", - title = "Scripts", + iconExt = "\0300\0317if\140\140\140\ +\0300\0317\140\031fthen\ +\0300\0317else\140", run = "Script.lua", }, [ "7ef35cac539f84722b0a988caee03b2df734c56a" ] = { @@ -21,6 +27,9 @@ icon = "\030 \0310=\0300 \030 XX\0300\031f \030 \ \030 \031f \0300 \030 \ \030 \031f \0310o \031f \0310o\031f ", + iconExt = "\031e\139\0318\151\151\151\151\151\149\ +\030 \031 \0308\031f\136\136\136\136\030f\0318\135\ +\030 \031 \030f\0317\130\030 \031 \030f\0317\130", run = "Appstore.lua", }, [ "4486006f811b88cacd5f211fd579717e29b600cd" ] = { @@ -67,16 +76,15 @@ \031e\\/\031 \0319c", run = "vnc.lua", }, - [ "8d59207c8a84153b3e9f035cc3b6ec7a23671323" ] = { - title = "Micropaint", - category = "Apps", - icon = "\030 \031f \030f \ -\030 \031f^ \0300 \030f \ -\030 \031fv \0300 \030 ", - run = "http://pastebin.com/raw/tMRzJXx2", - requires = "advancedComputer", - }, --]] + [ "a0365977708b7387ee9ce2c13e5820e6e11732cb" ] = { + title = "Pain", + category = "Apps", + icon = "\030 \031f\0307\031f\159\030 \159\030 \ +\030 \031f\0308\031f\135\0307\0318\144\140\030f\0317\159\143\031c\139\0302\135\030f\0312\157\ +\030 \031f\030f\0318\143\133\0312\136\0302\031f\159\159\143\131\030f\0312\132", + run = "http://pastebin.com/raw/wJQ7jav0", + }, [ "9e092dda4f0e27d0c7686ddd00272079e678b6e6" ] = { title = "Storage", category = "Apps", @@ -92,6 +100,9 @@ icon = "\030 \031f \031b \031foo \ \030 \031f \030e\031b \030 \031f/\ \030 \031b \030e \030 \031f\\", + iconExt = "\030 \031f\030f\031f\128\030e\143\030f\031e\144\031f\128\0304\149\0307\0314\131\131\030f\149\ +\030 \031f\030e\031f\129\031e\128\128\030f\148\0304\031f\149\0307\0318\140\140\030f\0314\149\ +\030 \031f\030f\031e\139\030e\128\030f\159\129\0314\130\131\131\129", run = "recorder.lua", }, [ "131f0b008f44298812221d120d982940609be781" ] = { @@ -131,6 +142,9 @@ icon = "\0301\031f \0309 \030c \030b \030e \030c \0306 \ \030 \031f \ \030 \031f \0300 \0310 ", + iconExt = "\030 \031f\030f\0319\144\030d\031f\159\030b\159\030f\0311\144\031b\144\030c\031f\159\030f\0311\144\ +\030 \031f\030f\0311\130\031b\129\0319\130\031e\130\0310\144\031d\129\0316\129\ +\030 \031f\030f\0310\136\140\140\030 ", run = "https://gist.github.com/LDDestroier/c7528d95bc0103545c2a/raw", }, [ "d78f28759f255a0db76604ee560b87c4715a0da5" ] = { @@ -139,23 +153,37 @@ icon = " \031bskch\ \0303\031f \030d \ \030d\031f ", + iconExt = "\030 \031f\0308\031f\151\0313\140\140\140\030f\0318\148\ +\030 \031f\030b\031f\149\0318\130\131\129\030f\031b\149\ +\030 \031f\030f\0318\138\0308\031b\130\131\129\030f\0318\133", run = "http://pastebin.com/raw/Mm5hd97E", }, [ "58ec8d6e36e346d9f42eb43935652e3e58e2c829" ] = { + title = "Mwm", category = "Apps", icon = "\030f\031f \0304 \ \030f\031dshell]\0304\0314 \ \0304\031f ", - title = "Mwm", + iconExt = "\030 \031f\0305\031f\155\030f\128\031d\152\140\030d\031f\151\030f\128\128\0304\0314\128\ +\030 \031f\030f\0315\152\129\030d\031f\141\030f\031d\153\030d\031f\149\030f\031d\131\148\0304\0314\128\ +\030 \031f\0304\031f\131\131\131\131\131\131\131\030e\0314\131", run = "mwm.lua usr/config/mwm", }, [ "8d1b0a73bedc0dc492377c2f6ab880940b97ec6e" ] = { + title = "Treefarm", icon = "\030 \031f \0305 \030 \030d \030 \ \0305\031f \030d \030 \030d \0305 \030d \ \030 \031f \030c \030 \0304 \030 \030c \030 ", category = "Apps", - title = "Treefarm", run = "treefarm.lua", requires = "turtle", }, + [ "01c933b2a36ad8ed2d54089cb2903039046c1216" ] = { + title = "Enchat", + icon = "\030e\031f\151\030f\031e\156\0311\140\0314\140\0315\140\031d\140\031b\140\031a\132\ +\030f\0314\128\030e\031f\132\030f\031e\132\0318nchat\ +\030f\031e\138\141\0311\140\0314\140\0315\132\0317v\03183\031a\132", + category = "Apps", + run = "https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua", + }, }