From 9aca96cc3e2daadaa0d38517e4d4b03fa72a80df Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Tue, 12 Sep 2017 23:04:44 -0400 Subject: [PATCH] treefarm + turtle improvements + cleanup --- sys/apis/event.lua | 6 +- sys/apis/point.lua | 73 +- sys/apis/process.lua | 121 - sys/apis/require.lua | 58 - sys/apis/turtle/craft.lua | 166 ++ sys/apis/turtle/level.lua | 160 ++ sys/{extensions => apis/turtle}/pathfind.lua | 89 +- sys/apis/ui.lua | 2 +- sys/apis/util.lua | 9 + sys/apps/Pim.lua | 107 - sys/apps/chestManager.lua | 149 +- sys/apps/refinedManager.lua | 535 ----- sys/apps/treefarm.lua | 708 ++++++ sys/autorun/gps.lua | 17 +- sys/etc/recipes.db | 2146 ++++++++++++++++++ sys/etc/scripts/follow | 2 +- sys/etc/scripts/moveTo | 2 +- sys/extensions/scheduler.lua | 86 - sys/extensions/tgps.lua | 18 +- sys/extensions/tl3.lua | 358 ++- sys/services/gpshost.lua | 30 +- 21 files changed, 3652 insertions(+), 1190 deletions(-) delete mode 100644 sys/apis/process.lua delete mode 100644 sys/apis/require.lua create mode 100644 sys/apis/turtle/craft.lua create mode 100644 sys/apis/turtle/level.lua rename sys/{extensions => apis/turtle}/pathfind.lua (74%) delete mode 100644 sys/apps/Pim.lua delete mode 100644 sys/apps/refinedManager.lua create mode 100644 sys/apps/treefarm.lua create mode 100644 sys/etc/recipes.db delete mode 100644 sys/extensions/scheduler.lua diff --git a/sys/apis/event.lua b/sys/apis/event.lua index 427d84b..dc09f86 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -1,5 +1,3 @@ -local Util = require('util') - local Event = { uid = 1, -- unique id for handlers routines = { }, -- coroutines @@ -26,7 +24,7 @@ end function Routine:resume(event, ...) if not self.co then - error('Cannot resume a dead routine\n' .. Util.tostring(self)) + error('Cannot resume a dead routine') end if not self.filter or self.filter == event or event == "terminate" then @@ -41,7 +39,7 @@ function Routine:resume(event, ...) end if not s and event ~= 'terminate' then - error('\n' .. (m or 'Error processing event') .. '\n' .. Util.tostring(self)) + error('\n' .. (m or 'Error processing event')) end return s, m diff --git a/sys/apis/point.lua b/sys/apis/point.lua index b50c1f3..3076d02 100644 --- a/sys/apis/point.lua +++ b/sys/apis/point.lua @@ -1,3 +1,5 @@ +local Util = require('util') + local Point = { } function Point.copy(pt) @@ -10,6 +12,14 @@ function Point.same(pta, ptb) pta.z == ptb.z end +function Point.above(pt) + return { x = pt.x, y = pt.y + 1, z = pt.z, heading = pt.heading } +end + +function Point.below(pt) + return { x = pt.x, y = pt.y - 1, z = pt.z, heading = pt.heading } +end + function Point.subtract(a, b) a.x = a.x - b.x a.y = a.y - b.y @@ -123,30 +133,17 @@ function Point.closest(reference, pts) return lpt end --- find the closest block --- * favor same plane --- * going backwards only if the dest is above or below -function Point.closest2(reference, pts) - local lpt, lm -- lowest - for _,pt in pairs(pts) do - local m = Point.turtleDistance(reference, pt) - local h = Point.calculateHeading(reference, pt) - local t = Point.calculateTurns(reference.heading, h) - if pt.y ~= reference.y then -- try and stay on same plane - m = m + .01 - end - if t ~= 2 or pt.y == reference.y then - m = m + t - if t > 0 then - m = m + .01 - end - end - if not lm or m < lm then - lpt = pt - lm = m +function Point.eachClosest(spt, ipts, fn) + + local pts = Util.shallowCopy(ipts) + while #pts > 0 do + local pt = Point.closest(spt, pts) + local r = fn(pt) + if r then + return r end + Util.removeByValue(pts, pt) end - return lpt end function Point.adjacentPoints(pt) @@ -159,26 +156,28 @@ function Point.adjacentPoints(pt) return pts end -return Point - ---[[ -function Point.toBox(pt, width, length, height) - return { ax = pt.x, - ay = pt.y, - az = pt.z, - bx = pt.x + width - 1, - by = pt.y + height - 1, - bz = pt.z + length - 1 - } +function Point.normalizeBox(box) + return { + x = math.min(box.x, box.ex), + y = math.min(box.y, box.ey), + z = math.min(box.z, box.ez), + ex = math.max(box.x, box.ex), + ey = math.max(box.y, box.ey), + ez = math.max(box.z, box.ez), + } end function Point.inBox(pt, box) - return pt.x >= box.ax and - pt.z >= box.az and - pt.x <= box.bx and - pt.z <= box.bz + return pt.x >= box.x and + pt.y >= box.y and + pt.z >= box.z and + pt.x <= box.ex and + pt.z <= box.ez end +return Point + +--[[ Box = { } function Box.contain(boundingBox, containedBox) diff --git a/sys/apis/process.lua b/sys/apis/process.lua deleted file mode 100644 index 8bb60e9..0000000 --- a/sys/apis/process.lua +++ /dev/null @@ -1,121 +0,0 @@ -local Util = require('util') - -local Process = { } - -function Process:init(args) - self.args = { } - self.uid = 0 - self.threads = { } - Util.merge(self, args) - self.name = self.name or 'Thread:' .. self.uid -end - -function Process:isDead() - return coroutine.status(self.co) == 'dead' -end - -function Process:terminate() - print('terminating ' .. self.name) - self:resume('terminate') -end - -function Process:threadEvent(...) - - for _,key in pairs(Util.keys(self.threads)) do - local thread = self.threads[key] - if thread then - thread:resume(...) - end - end -end - -function Process:addThread(fn, ...) - return self:newThread(nil, fn, ...) -end - --- deprecated -function Process:newThread(name, fn, ...) - - self.uid = self.uid + 1 - - local thread = { } - setmetatable(thread, { __index = Process }) - thread:init({ - fn = fn, - name = name, - uid = self.uid, - }) - - local args = { ... } - thread.co = coroutine.create(function() - - local s, m = pcall(function() fn(unpack(args)) end) - if not s and m then - if m == 'Terminated' then - --printError(thread.name .. ' terminated') - else - printError(m) - end - end - ---print('thread died ' .. thread.name) - self.threads[thread.uid] = nil - - thread:threadEvent('terminate') - - return s, m - end) - - self.threads[thread.uid] = thread - - thread:resume() - - return thread -end - -function Process:resume(event, ...) - - -- threads get a chance to process the event regardless of the main process filter - self:threadEvent(event, ...) - - if not self.filter or self.filter == event or event == "terminate" then - local ok, result = coroutine.resume(self.co, event, ...) - if ok then - self.filter = result - end - return ok, result - end - - return true, self.filter -end - --- confusing... - --- pull either one event if no filter or until event matches filter --- or until terminated (regardless of filter) -function Process:pullEvent(filter) - while true do - local e = { os.pullEventRaw() } - self:threadEvent(unpack(e)) - - if not filter or e[1] == filter or e[1] == 'terminate' then - return unpack(e) - end - end -end - --- pull events until either the filter is matched or terminated -function Process:pullEvents(filter) - while true do - local e = { os.pullEventRaw() } - self:threadEvent(unpack(e)) - if (filter and e[1] == filter) or e[1] == 'terminate' then - return unpack(e) - end - end -end - -local process = { } -setmetatable(process, { __index = Process }) -process:init({ name = 'Main', co = coroutine.running() }) -return process diff --git a/sys/apis/require.lua b/sys/apis/require.lua deleted file mode 100644 index 116d236..0000000 --- a/sys/apis/require.lua +++ /dev/null @@ -1,58 +0,0 @@ -local function resolveFile(filename, dir, lua_path) - - local ch = string.sub(filename, 1, 1) - if ch == "/" then - return filename - end - - if dir then - local path = fs.combine(dir, filename) - if fs.exists(path) and not fs.isDir(path) then - return path - end - end - - if lua_path then - for dir in string.gmatch(lua_path, "[^:]+") do - local path = fs.combine(dir, filename) - if fs.exists(path) and not fs.isDir(path) then - return path - end - end - end -end - -local modules = { } - -return function(filename) - - local dir = DIR - if not dir and shell and type(shell.dir) == 'function' then - dir = shell.dir() - end - - local fname = resolveFile(filename:gsub('%.', '/') .. '.lua', - dir or '', LUA_PATH or '/sys/apis') - - if not fname or not fs.exists(fname) then - error('Unable to load: ' .. filename, 2) - end - - local rname = fname:gsub('%/', '.'):gsub('%.lua', '') - - local module = modules[rname] - if not module then - - local f, err = loadfile(fname) - if not f then - error(err) - end - setfenv(f, getfenv(1)) - - module = f(rname) - - modules[rname] = module - end - - return module -end diff --git a/sys/apis/turtle/craft.lua b/sys/apis/turtle/craft.lua new file mode 100644 index 0000000..6c63d29 --- /dev/null +++ b/sys/apis/turtle/craft.lua @@ -0,0 +1,166 @@ +local itemDB = require('itemDB') +local Util = require('util') + +local Craft = { } + +local function clearGrid(chestProvider) + for i = 1, 16 do + local count = turtle.getItemCount(i) + if count > 0 then + chestProvider:insert(i, count) + if turtle.getItemCount(i) ~= 0 then + return false + end + end + end + return true +end + +local function splitKey(key) + local t = Util.split(key, '(.-):') + local item = { } + if #t[#t] > 2 then + item.nbtHash = table.remove(t) + end + item.damage = tonumber(table.remove(t)) + item.name = table.concat(t, ':') + return item +end + +local function getItemCount(items, key) + local item = splitKey(key) + for _,v in pairs(items) do + if v.name == item.name and + v.damage == item.damage and + v.nbtHash == item.nbtHash then + return v.count + end + end + return 0 +end + +local function turtleCraft(recipe, qty, chestProvider) + + clearGrid(chestProvider) + + for k,v in pairs(recipe.ingredients) do + local item = splitKey(v) + chestProvider:provide({ id = item.name, dmg = item.damage, nbt_hash = item.nbtHash }, qty, k) + if turtle.getItemCount(k) == 0 then -- ~= qty then + -- FIX: ingredients cannot be stacked + return false + end + end + + return turtle.craft() +end + +function Craft.craftRecipe(recipe, count, chestProvider) + + local items = chestProvider:listItems() + + local function sumItems(items) + -- produces { ['minecraft:planks:0'] = 8 } + local t = {} + for _,item in pairs(items) do + t[item] = (t[item] or 0) + 1 + end + return t + end + + count = math.ceil(count / recipe.count) + + local maxCount = recipe.maxCount or math.floor(64 / recipe.count) + local summedItems = sumItems(recipe.ingredients) + + for key,icount in pairs(summedItems) do + local itemCount = getItemCount(items, key) + if itemCount < icount * count then + local irecipe = Craft.recipes[key] + if irecipe then +Util.print('Crafting %d %s', icount * count - itemCount, key) + if not Craft.craftRecipe(irecipe, + icount * count - itemCount, + chestProvider) then + turtle.select(1) + return + end + end + end + end + repeat + if not turtleCraft(recipe, math.min(count, maxCount), chestProvider) then + turtle.select(1) + return false + end + count = count - maxCount + until count <= 0 + + turtle.select(1) + return true +end + +-- given a certain quantity, return how many of those can be crafted +function Craft.getCraftableAmount(recipe, count, items) + + local function sumItems(recipe, items, summedItems, count) + + local canCraft = 0 + + for i = 1, count do + for _,item in pairs(recipe.ingredients) do + local summedItem = summedItems[item] or getItemCount(items, item) + + local irecipe = Craft.recipes[item] + if irecipe and summedItem <= 0 then + summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) + end + if summedItem <= 0 then + return canCraft + end + summedItems[item] = summedItem - 1 + end + canCraft = canCraft + recipe.count + end + + return canCraft + end + + return sumItems(recipe, items, { }, math.ceil(count / recipe.count)) +end + +function Craft.canCraft(item, count, items) + return Craft.getCraftableAmount(Craft.recipes[item], count, items) == count +end + +function Craft.setRecipes(recipes) + Craft.recipes = recipes +end + +function Craft.getCraftableAmountTest() + local results = { } + Craft.setRecipes(Util.readTable('sys/etc/recipes.db')) + + local items = { + { name = 'minecraft:planks', damage = 0, count = 5 }, + { name = 'minecraft:log', damage = 0, count = 2 }, + } + results[1] = { item = 'chest', expected = 1, got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) } + + items = { + { name = 'minecraft:log', damage = 0, count = 1 }, + { name = 'minecraft:coal', damage = 1, count = 1 }, + } + results[2] = { item = 'torch', expected = 4, got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) } + + return results +end + +function Craft.craftRecipeTest(name, count) + local ChestProvider = require('chestProvider18') + local chestProvider = ChestProvider({ wrapSide = 'top', direction = 'down' }) + Craft.setRecipes(Util.readTable('usr/etc/recipes.db')) + return { Craft.craftRecipe(Craft.recipes[name], count, chestProvider) } +end + +return Craft diff --git a/sys/apis/turtle/level.lua b/sys/apis/turtle/level.lua new file mode 100644 index 0000000..1901cbe --- /dev/null +++ b/sys/apis/turtle/level.lua @@ -0,0 +1,160 @@ +local Point = require('point') +local Util = require('util') + +local checkedNodes = { } +local nodes = { } +local box = { } +local oldCallback + +local function toKey(pt) + return table.concat({ pt.x, pt.y, pt.z }, ':') +end + +local function addNode(node) + + for i = 0, 5 do + local hi = turtle.getHeadingInfo(i) + local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd } + + if Point.inBox(testNode, box) then + local key = toKey(testNode) + if not checkedNodes[key] then + nodes[key] = testNode + end + end + end +end + +local function dig(action) + + local directions = { + top = 'up', + bottom = 'down', + } + + -- convert to up, down, north, south, east, west + local direction = directions[action.side] or + turtle.getHeadingInfo(turtle.point.heading).direction + + local hi = turtle.getHeadingInfo(direction) + local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd } + if Point.inBox(node, box) then + + local key = toKey(node) + checkedNodes[key] = true + nodes[key] = nil + + if action.dig() then + addNode(node) + repeat until not action.dig() -- sand, etc + return true + end + end +end + +local function move(action) + if action == 'turn' then + dig(turtle.getAction('forward')) + elseif action == 'up' then + dig(turtle.getAction('up')) + elseif action == 'down' then + dig(turtle.getAction('down')) + elseif action == 'back' then + dig(turtle.getAction('up')) + dig(turtle.getAction('down')) + end + + if oldCallback then + oldCallback(action) + end +end + +-- find the closest block +-- * favor same plane +-- * going backwards only if the dest is above or below +function closestPoint(reference, pts) + local lpt, lm -- lowest + for _,pt in pairs(pts) do + local m = Point.turtleDistance(reference, pt) + local h = Point.calculateHeading(reference, pt) + local t = Point.calculateTurns(reference.heading, h) + if pt.y ~= reference.y then -- try and stay on same plane + m = m + .01 + end + if t ~= 2 or pt.y == reference.y then + m = m + t + if t > 0 then + m = m + .01 + end + end + if not lm or m < lm then + lpt = pt + lm = m + end + end + return lpt +end + +local function getAdjacentPoint(pt) + local t = { } + table.insert(t, pt) + for i = 0, 5 do + local hi = turtle.getHeadingInfo(i) + local heading + if i < 4 then + heading = (hi.heading + 2) % 4 + end + table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading }) + end + + return closestPoint(turtle.getPoint(), t) +end + +return function(startPt, endPt, firstPt, verbose) + + checkedNodes = { } + nodes = { } + box = { } + + box.x = math.min(startPt.x, endPt.x) + box.y = math.min(startPt.y, endPt.y) + box.z = math.min(startPt.z, endPt.z) + box.ex = math.max(startPt.x, endPt.x) + box.ey = math.max(startPt.y, endPt.y) + box.ez = math.max(startPt.z, endPt.z) + + turtle.pathfind(firstPt) + + turtle.setPolicy("attack", { dig = dig }, "assuredMove") + + oldCallback = turtle.getMoveCallback() + turtle.setMoveCallback(move) + + repeat + local key = toKey(turtle.point) + + checkedNodes[key] = true + nodes[key] = nil + + dig(turtle.getAction('down')) + dig(turtle.getAction('up')) + dig(turtle.getAction('forward')) + + if verbose then + print(string.format('%d nodes remaining', Util.size(nodes))) + end + + if Util.size(nodes) == 0 then + break + end + + local node = closestPoint(turtle.point, nodes) + node = getAdjacentPoint(node) + if not turtle.gotoPoint(node) then + break + end + until turtle.abort + + turtle.resetState() + turtle.setMoveCallback(oldCallback) +end diff --git a/sys/extensions/pathfind.lua b/sys/apis/turtle/pathfind.lua similarity index 74% rename from sys/extensions/pathfind.lua rename to sys/apis/turtle/pathfind.lua index bb0f3e4..78307a8 100644 --- a/sys/extensions/pathfind.lua +++ b/sys/apis/turtle/pathfind.lua @@ -1,22 +1,19 @@ -if not turtle or turtle.pathfind then - return -end - requireInjector(getfenv(1)) local Grid = require ("jumper.grid") local Pathfinder = require ("jumper.pathfinder") local Point = require('point') +local Util = require('util') local WALKABLE = 0 local function createMap(dim) local map = { } - for z = 0, dim.ez do + for z = 1, dim.ez do local row = {} - for x = 0, dim.ex do + for x = 1, dim.ex do local col = { } - for y = 0, dim.ey do + for y = 1, dim.ey do table.insert(col, WALKABLE) end table.insert(row, col) @@ -65,12 +62,21 @@ local function mapDimensions(dest, blocks, boundingBox) end -- expand one block out in all directions - sx = math.max(sx - 1, boundingBox.sx) - sz = math.max(sz - 1, boundingBox.sz) - sy = math.max(sy - 1, boundingBox.sy) - ex = math.min(ex + 1, boundingBox.ex) - ez = math.min(ez + 1, boundingBox.ez) - ey = math.min(ey + 1, boundingBox.ey) + if boundingBox then + sx = math.max(sx - 1, boundingBox.x) + sz = math.max(sz - 1, boundingBox.z) + sy = math.max(sy - 1, boundingBox.y) + ex = math.min(ex + 1, boundingBox.ex) + ez = math.min(ez + 1, boundingBox.ez) + ey = math.min(ey + 1, boundingBox.ey) + else + sx = sx - 1 + sz = sz - 1 + sy = sy - 1 + ex = ex + 1 + ez = ez + 1 + ey = ey + 1 + end return { ex = ex - sx + 1, @@ -138,22 +144,14 @@ local function addSensorBlocks(blocks, sblocks) end end -local function pathTo(dest, blocks, maxRadius) +local function pathTo(dest, options) - blocks = blocks or { } - maxRadius = maxRadius or 1000000 + local blocks = options.blocks or { } + local allDests = options.dest or { } -- support alternative destinations local lastDim = nil local map = nil local grid = nil - local boundingBox = { - sx = math.min(turtle.point.x, dest.x) - maxRadius, - sy = math.min(turtle.point.y, dest.y) - maxRadius, - sz = math.min(turtle.point.z, dest.z) - maxRadius, - ex = math.max(turtle.point.x, dest.x) + maxRadius, - ey = math.max(turtle.point.y, dest.y) + maxRadius, - ez = math.max(turtle.point.z, dest.z) + maxRadius, - } -- Creates a pathfinder object local myFinder = Pathfinder(grid, 'ASTAR', walkable) @@ -164,7 +162,7 @@ local function pathTo(dest, blocks, maxRadius) while turtle.point.x ~= dest.x or turtle.point.z ~= dest.z or turtle.point.y ~= dest.y do -- map expands as we encounter obstacles - local dim = mapDimensions(dest, blocks, boundingBox) + local dim = mapDimensions(dest, blocks, options.box) -- reuse map if possible if not lastDim or not dimsAreEqual(dim, lastDim) then @@ -189,23 +187,33 @@ local function pathTo(dest, blocks, maxRadius) local path = myFinder:getPath(startPt.x, startPt.y, startPt.z, turtle.point.heading, endPt.x, endPt.y, endPt.z, dest.heading) if not path then - return false, 'failed to recalculate' - end + Util.removeByValue(allDests, dest) + dest = Point.closest(turtle.point, allDests) - for node, count in path:nodes() do - local pt = nodeToPoint(dim, node) - - if turtle.abort then - return false, 'aborted' + if not dest then + return false, 'failed to recalculate' end + else - -- use single turn method so the turtle doesn't turn around when encountering obstacles - if not turtle.gotoSingleTurn(pt.x, pt.z, pt.y) then + for node, count in path:nodes() do + local pt = nodeToPoint(dim, node) + + if turtle.abort then + return false, 'aborted' + end + + -- use single turn method so the turtle doesn't turn around + -- when encountering obstacles -- IS THIS RIGHT ?? + if not turtle.gotoSingleTurn(pt.x, pt.z, pt.y, node.heading) then table.insert(blocks, pt) + if #allDests > 0 then + dest = Point.closest(turtle.point, allDests) + end --if device.turtlesensorenvironment then -- addSensorBlocks(blocks, device.turtlesensorenvironment.sonicScan()) --end - break + break + end end end end @@ -213,12 +221,13 @@ local function pathTo(dest, blocks, maxRadius) if dest.heading then turtle.setHeading(dest.heading) end - return true + return dest end -turtle.pathfind = function(dest, blocks, maxRadius) - if not blocks and turtle.gotoPoint(dest) then - return true +return function(dest, options) + options = options or { } + if not options.blocks and turtle.gotoPoint(dest) then + return dest end - return pathTo(dest, blocks, maxRadius) + return pathTo(dest, options) end diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 8836e93..8fe9571 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -343,7 +343,7 @@ function Manager:click(button, x, y) if button == 1 then local c = os.clock() - if self.doubleClickTimer and (c - self.doubleClickTimer < 1.5) and + if self.doubleClickTimer and (c - self.doubleClickTimer < 1.9) and self.doubleClickX == x and self.doubleClickY == y and self.doubleClickElement == clickEvent.element then button = 3 diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 0d3a4db..d282767 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -243,6 +243,15 @@ function Util.size(list) return 0 end +function Util.removeByValue(t, e) + for k,v in pairs(t) do + if v == e then + table.remove(t, k) + break + end + end +end + function Util.each(list, func) for index, value in pairs(list) do func(value, index, list) diff --git a/sys/apps/Pim.lua b/sys/apps/Pim.lua deleted file mode 100644 index f8591e6..0000000 --- a/sys/apps/Pim.lua +++ /dev/null @@ -1,107 +0,0 @@ -requireInjector(getfenv(1)) - -local Config = require('config') -local Event = require('event') -local UI = require('ui') -local Util = require('util') - -multishell.setTitle(multishell.getCurrent(), 'PIM') - -local inventory = { } -local mode = 'sync' - -if not device.pim then - error('PIM not attached') -end - -local page = UI.Page({ - menu = UI.Menu({ - centered = true, - y = 2, - menuItems = { - { prompt = 'Learn', event = 'learn', help = '' }, - }, - }), - statusBar = UI.StatusBar({ - columns = { - { 'Status', 'status', UI.term.width - 7 }, - { 'Mode', 'mode', 7 } - } - }), - accelerators = { - q = 'quit', - }, -}) - -local function learn() - if device.pim.getInventorySize() > 0 then - local stacks = device.pim.getAllStacks(false) - Config.update('pim', stacks) - mode = 'sync' - page.statusBar:setValue('status', 'Learned inventory') - end - page.statusBar:setValue('mode', mode) - page.statusBar:draw() -end - -function page:eventHandler(event) - - if event.type == 'learn' then - mode = 'learn' - learn() - elseif event.type == 'quit' then - Event.exitPullEvents() - end - - return UI.Page.eventHandler(self, event) -end - -local function inInventory(s) - for _,i in pairs(inventory) do - if i.id == s.id then - return true - end - end -end - -local function pimWatcher() - local playerOn = false - - while true do - if device.pim.getInventorySize() > 0 and not playerOn then - playerOn = true - - if mode == 'learn' then - learn() - - else - local stacks = device.pim.getAllStacks(false) - for k,stack in pairs(stacks) do - if not inInventory(stack) then - device.pim.pushItem('down', k, stack.qty) - end - end - page.statusBar:setValue('status', 'Synchronized') - page.statusBar:draw() - end - - elseif device.pim.getInventorySize() == 0 and playerOn then - page.statusBar:setValue('status', 'No player') - page.statusBar:draw() - playerOn = false - end - os.sleep(1) - end -end - -Config.load('pim', inventory) - -if Util.empty(inventory) then - mode = 'learn' -end -page.statusBar:setValue('mode', mode) - -UI:setPage(page) - -Event.pullEvents(pimWatcher) -UI.term:reset() diff --git a/sys/apps/chestManager.lua b/sys/apps/chestManager.lua index f065b7c..32b883a 100644 --- a/sys/apps/chestManager.lua +++ b/sys/apps/chestManager.lua @@ -2,6 +2,7 @@ requireInjector(getfenv(1)) local ChestProvider = require('chestProvider18') local Config = require('config') +local Craft = require('turtle.craft') local Event = require('event') local itemDB = require('itemDB') local Peripheral = require('peripheral') @@ -34,13 +35,15 @@ local chestProvider = ChestProvider({ direction = 'west', wrapSide = 'back' }) local turtleChestProvider = ChestProvider({ direction = 'up', wrapSide = 'bottom' }) local RESOURCE_FILE = 'usr/etc/resources.db' -local RECIPES_FILE = 'usr/etc/recipes.db' +local RECIPES_FILE = 'sys/etc/recipes.db' local jobListGrid local craftingPaused = false local recipes = Util.readTable(RECIPES_FILE) or { } local resources = Util.readTable(RESOURCE_FILE) or { } +Craft.setRecipes(recipes) + for _,r in pairs(resources) do r.maxDamage = nil r.displayName = nil @@ -70,6 +73,17 @@ local function getItem(items, inItem, ignoreDamage) end end +local function splitKey(key) + local t = Util.split(key, '(.-):') + local item = { } + if #t[#t] > 2 then + item.nbtHash = table.remove(t) + end + item.damage = tonumber(table.remove(t)) + item.name = table.concat(t, ':') + return item +end + local function getItemQuantity(items, item) item = getItem(items, item) if item then @@ -114,7 +128,8 @@ local function mergeResources(t) end end - for _,v in pairs(recipes) do + for k in pairs(recipes) do + local v = splitKey(k) local item = getItem(t, v) if not item then item = Util.shallowCopy(v) @@ -149,8 +164,8 @@ end local function sumItems3(ingredients, items, summedItems, count) local canCraft = 0 - for _,item in pairs(ingredients) do - local key = uniqueKey(item) + for _,key in pairs(ingredients) do + local item = splitKey(key) local summedItem = summedItems[key] if not summedItem then summedItem = Util.shallowCopy(item) @@ -167,52 +182,6 @@ local function sumItems3(ingredients, items, summedItems, count) end end -local function sumItems2(ingredients, items, summedItems, count) - - local canCraft = 0 - - for i = 1, count do - for _,item in pairs(ingredients) do - local key = uniqueKey(item) - local summedItem = summedItems[key] - if not summedItem then - summedItem = Util.shallowCopy(item) - summedItem.recipe = recipes[key] - summedItem.count = getItemQuantity(items, summedItem) - summedItems[key] = summedItem - end - if summedItem.recipe and summedItem.count <= 0 then - summedItem.count = sumItems2(summedItem.recipe.ingredients, items, summedItems, 1) - end - if summedItem.count <= 0 then - return canCraft - end - summedItem.count = summedItem.count - item.count - end - canCraft = canCraft + 1 - end - - return canCraft -end - -local function sumItems(items) - local t = {} - - for _,item in pairs(items) do - local key = uniqueKey(item) - local summedItem = t[key] - if summedItem then - summedItem.count = summedItem.count + item.count - else - summedItem = Util.shallowCopy(item) - summedItem.recipe = recipes[key] - t[key] = summedItem - end - end - - return t -end - local function isGridClear() for i = 1, 16 do if turtle.getItemCount(i) ~= 0 then @@ -235,32 +204,6 @@ local function clearGrid() return true end -local function turtleCraft(recipe, originalItem, qty) - - for k,v in pairs(recipe.ingredients) do - - chestProvider:provide({ id = v.name, dmg = v.damage, nbt_hash = v.nbtHash }, v.count * qty, k) - if turtle.getItemCount(k) ~= v.count * qty then - clearGrid() - originalItem.status = v.name .. ' (extract failed)' - return false - end - end - - if not turtle.craft() then - clearGrid() - return false - end - - --for k,ingredient in pairs(recipe.ingredients) do - -- local item = getItem(items, ingredient) - -- item.count = item.count - ingredient.count - --end - - clearGrid() - return true -end - local function addCraftingRequest(item, craftList, count) local key = uniqueKey(item) local request = craftList[key] @@ -272,64 +215,30 @@ local function addCraftingRequest(item, craftList, count) request.count = request.count + count end -local function craftRecipe(recipe, items, originalItem, count) - - local maxCount = recipe.maxCount - - if not maxCount then -- temporary - local cItem = itemDB:get(itemDB:makeKey(recipe)) - if cItem then - maxCount = cItem.maxCount - else - maxCount = 1 - end - end - - local summedItems = sumItems(recipe.ingredients) - for key,ingredient in pairs(summedItems) do - local details = getItemDetails(items, ingredient) - maxCount = math.min(details.maxCount, maxCount) - if details.count < ingredient.count * count then - if ingredient.recipe then - if not craftRecipe(ingredient.recipe, items, originalItem, ingredient.count * count - details.count) then - return - end - end - end - end - repeat - if not turtleCraft(recipe, originalItem, math.min(count, maxCount)) then - return false - end - count = count - maxCount - until count < 0 - - return true -end - local function craftItem(recipe, items, originalItem, craftList, count) if craftingPaused or not device.workbench or not isGridClear() then return end - count = math.ceil(count / recipe.count) - - local toCraft = sumItems2(recipe.ingredients, items, { }, count) + local toCraft = Craft.getCraftableAmount(recipe, count, items) if toCraft > 0 then - craftRecipe(recipe, items, originalItem, toCraft) + Craft.craftRecipe(recipe, toCraft, chestProvider) + clearGrid() items = chestProvider:listItems() end count = count - toCraft - local summedItems = { } - sumItems3(recipe.ingredients, items, summedItems, count) + if count > 0 then + local summedItems = { } + sumItems3(recipe.ingredients, items, summedItems, math.ceil(count / recipe.count)) - for key,ingredient in pairs(summedItems) do - if not ingredient.recipe and ingredient.count < 0 then - addCraftingRequest(ingredient, craftList, -ingredient.count) + for key,ingredient in pairs(summedItems) do + if not ingredient.recipe and ingredient.count < 0 then + addCraftingRequest(ingredient, craftList, -ingredient.count) + end end end end diff --git a/sys/apps/refinedManager.lua b/sys/apps/refinedManager.lua deleted file mode 100644 index c0b21a8..0000000 --- a/sys/apps/refinedManager.lua +++ /dev/null @@ -1,535 +0,0 @@ -requireInjector(getfenv(1)) - -local Peripheral = require('peripheral') -local RefinedProvider = require('refinedProvider') -local Terminal = require('terminal') -local UI = require('ui') -local Util = require('util') - -local controller = RefinedProvider() -if not controller:isValid() then - error('Refined storage controller not found') -end - -multishell.setTitle(multishell.getCurrent(), 'Storage Manager') - -function getItem(items, inItem, ignoreDamage) - for _,item in pairs(items) do - if item.name == inItem.name then - if ignoreDamage then - return item - elseif item.damage == inItem.damage and item.nbtHash == inItem.nbtHash then - return item - end - end - end -end - -local function uniqueKey(item) - return table.concat({ item.name, item.damage, item.nbtHash }, ':') -end - -function mergeResources(t) - local resources = Util.readTable('resource.limits') or { } - - for _,v in pairs(resources) do - v.low = tonumber(v.low) -- backwards compatibility - local item = getItem(t, v) - if item then - item.low = v.low - item.auto = v.auto - item.ignoreDamage = v.ignoreDamage - item.rsControl = v.rsControl - item.rsDevice = v.rsDevice - item.rsSide = v.rsSide - else - v.count = 0 - table.insert(t, v) - end - end - - for _,v in pairs(t) do - v.lname = v.displayName:lower() - end -end - -function filterItems(t, filter) - if filter then - local r = {} - filter = filter:lower() - for k,v in pairs(t) do - if string.find(v.lname, filter) then - table.insert(r, v) - end - end - return r - end - return t -end - -function craftItems(itemList, allItems) - - for _,item in pairs(itemList) do - local cItem = getItem(allItems, item) - - if controller:isCrafting(item) then - item.status = '(crafting)' - elseif item.rsControl then - item.status = 'Activated' - elseif not cItem then - item.status = '(no recipe)' - else - - local count = item.count - while count >= 1 do -- try to request smaller quantities until successful - local s, m = pcall(function() - item.status = '(no recipe)' - if not controller:craft(cItem, count) then - item.status = '(missing ingredients)' - error('failed') - end - item.status = '(crafting)' - end) - if s then - break -- successfully requested crafting - end - count = math.floor(count / 2) - end - end - end -end - -function getAutocraftItems() - local t = Util.readTable('resource.limits') or { } - local itemList = { } - - for _,res in pairs(t) do - - if res.auto then - res.count = 4 -- this could be higher to increase autocrafting speed - table.insert(itemList, res) - end - end - return itemList -end - -local function getItemWithQty(items, res, ignoreDamage) - - local item = getItem(items, res, ignoreDamage) - - if item then - - if ignoreDamage then - local count = 0 - - for _,v in pairs(items) do - if item.name == v.name and item.nbtHash == v.nbtHash then - if item.maxDamage > 0 or item.damage == v.damage then - count = count + v.count - end - end - end - - item.count = count - end - end - - return item -end - -function watchResources(items) - - local itemList = { } - - local t = Util.readTable('resource.limits') or { } - for k, res in pairs(t) do - res.low = tonumber(res.low) -- backwards compatibility - local item = getItemWithQty(items, res, res.ignoreDamage) - if not item then - item = { - damage = res.damage, - nbtHash = res.nbtHash, - name = res.name, - displayName = res.displayName, - count = 0 - } - end - - if res.low and item.count < res.low then - if res.ignoreDamage then - item.damage = 0 - end - table.insert(itemList, { - damage = item.damage, - nbtHash = item.nbtHash, - count = res.low - item.count, - name = item.name, - displayName = item.displayName, - status = '', - rsControl = res.rsControl, - }) - end - - if res.rsControl and res.rsDevice and res.rsSide then - pcall(function() - device[res.rsDevice].setOutput(res.rsSide, item.count < res.low) - end) - end - end - - return itemList -end - -itemPage = UI.Page { - backgroundColor = colors.lightGray, - titleBar = UI.TitleBar { - title = 'Limit Resource', - previousPage = true, - event = 'form_cancel', - backgroundColor = colors.green - }, - displayName = UI.Window { - x = 5, y = 2, width = UI.term.width - 10, height = 3, - }, - form = UI.Form { - x = 4, y = 4, height = 10, rex = -4, - [1] = UI.TextEntry { - width = 7, - backgroundColor = colors.gray, - backgroundFocusColor = colors.gray, - formLabel = 'Min', formKey = 'low', help = 'Craft if below min' - }, - [2] = UI.Chooser { - width = 7, - formLabel = 'Autocraft', formKey = 'auto', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Craft until out of ingredients' - }, - [3] = UI.Chooser { - width = 7, - formLabel = 'Ignore Dmg', formKey = 'ignoreDamage', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Ignore damage of item' - }, - [4] = UI.Chooser { - width = 7, - formLabel = 'RS Control', formKey = 'rsControl', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Control via redstone' - }, - [5] = UI.Chooser { - width = 25, - formLabel = 'RS Device', formKey = 'rsDevice', - --choices = devices, - help = 'Redstone Device' - }, - [6] = UI.Chooser { - width = 10, - formLabel = 'RS Side', formKey = 'rsSide', - --nochoice = 'No', - choices = { - { name = 'up', value = 'up' }, - { name = 'down', value = 'down' }, - { name = 'east', value = 'east' }, - { name = 'north', value = 'north' }, - { name = 'west', value = 'west' }, - { name = 'south', value = 'south' }, - }, - help = 'Output side' - }, - }, - statusBar = UI.StatusBar { } -} - -function itemPage.displayName:draw() - local item = self.parent.item - local str = string.format('Name: %s\nDamage: %d', item.displayName, item.damage) - if item.nbtHash then - str = str .. string.format('\nNBT: %s\n', item.nbtHash) - end - self:setCursorPos(1, 1) - self:print(str) -end - -function itemPage:enable(item) - self.item = item - - self.form:setValues(item) - self.titleBar.title = item.name - - local devices = self.form[5].choices - Util.clear(devices) - for _,device in pairs(device) do - if device.setOutput then - table.insert(devices, { name = device.name, value = device.name }) - end - end - - if Util.size(devices) == 0 then - table.insert(devices, { name = 'None found', values = '' }) - end - - UI.Page.enable(self) - self:focusFirst() -end - -function itemPage:eventHandler(event) - if event.type == 'form_cancel' then - UI:setPreviousPage() - - elseif event.type == 'focus_change' then - self.statusBar:setStatus(event.focused.help) - self.statusBar:draw() - - elseif event.type == 'form_complete' then - local values = self.form.values - local t = Util.readTable('resource.limits') or { } - local keys = { 'name', 'displayName', 'auto', 'low', 'damage', - 'maxDamage', 'nbtHash', 'ignoreDamage', - 'rsControl', 'rsDevice', 'rsSide', } - - local filtered = { } - for _,key in pairs(keys) do - filtered[key] = values[key] - end - filtered.low = tonumber(filtered.low) - - filtered.ignoreDamage = filtered.ignoreDamage == true - filtered.auto = filtered.auto == true - filtered.rsControl = filtered.rsControl == true - - if filtered.ignoreDamage then - filtered.damage = 0 - end - - t[uniqueKey(filtered)] = filtered - Util.writeTable('resource.limits', t) - - UI:setPreviousPage() - else - return UI.Page.eventHandler(self, event) - end - return true -end - -listingPage = UI.Page { - menuBar = UI.MenuBar { - buttons = { - { text = 'Forget', event = 'forget' }, - }, - }, - grid = UI.Grid { - y = 2, height = UI.term.height - 2, - columns = { - { heading = 'Name', key = 'displayName', width = UI.term.width - 14 }, - { heading = 'Qty', key = 'count', width = 5 }, - { heading = 'Min', key = 'low', width = 4 }, - }, - sortColumn = 'lname', - }, - statusBar = UI.StatusBar { - backgroundColor = colors.gray, - width = UI.term.width, - filterText = UI.Text { - x = 2, width = 6, - value = 'Filter', - }, - filter = UI.TextEntry { - x = 9, rex = -12, - limit = 50, - }, - refresh = UI.Button { - rx = -9, width = 8, - text = 'Refresh', - event = 'refresh', - }, - }, - accelerators = { - r = 'refresh', - q = 'quit', - } -} - -function listingPage.grid:getRowTextColor(row, selected) - if row.is_craftable then -- not implemented - return colors.yellow - end - return UI.Grid:getRowTextColor(row, selected) -end - -function listingPage.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - row.count = Util.toBytes(row.count) - if row.low then - row.low = Util.toBytes(row.low) - end - return row -end - -function listingPage.statusBar:draw() - return UI.Window.draw(self) -end - -function listingPage.statusBar.filter:eventHandler(event) - if event.type == 'mouse_rightclick' then - self.value = '' - self:draw() - local page = UI:getCurrentPage() - page.filter = nil - page:applyFilter() - page.grid:draw() - page:setFocus(self) - end - return UI.TextEntry.eventHandler(self, event) -end - -function listingPage:eventHandler(event) - if event.type == 'quit' then - UI:exitPullEvents() - - elseif event.type == 'grid_select' then - local selected = event.selected - UI:setPage('item', selected) - - elseif event.type == 'refresh' then - self:refresh() - self.grid:draw() - self.statusBar.filter:focus() - - elseif event.type == 'forget' then - local item = self.grid:getSelected() - if item then - - local resources = Util.readTable('resource.limits') or { } - resources[uniqueKey(item)] = nil - Util.writeTable('resource.limits', resources) - - self.statusBar:timedStatus('Forgot: ' .. item.name, 3) - self:refresh() - self.grid:draw() - end - - elseif event.type == 'text_change' then - self.filter = event.text - if #self.filter == 0 then - self.filter = nil - end - self:applyFilter() - self.grid:draw() - self.statusBar.filter:focus() - - else - UI.Page.eventHandler(self, event) - end - return true -end - -function listingPage:enable() - self:refresh() - self:setFocus(self.statusBar.filter) - UI.Page.enable(self) -end - -function listingPage:refresh() - self.allItems = controller:listItems() - mergeResources(self.allItems) - self:applyFilter() -end - -function listingPage:applyFilter() - local t = filterItems(self.allItems, self.filter) - self.grid:setValues(t) -end - -local function jobMonitor(jobList) - - local mon = Peripheral.getByType('monitor') - - if mon then - mon = UI.Device({ - device = device.monitor, - textScale = .5, - }) - else - mon = UI.Device({ - device = Terminal.getNullTerm(term.current()) - }) - end - - jobListGrid = UI.Grid { - parent = mon, - sortColumn = 'displayName', - columns = { - { heading = 'Qty', key = 'count', width = 6 }, - { heading = 'Crafting', key = 'displayName', width = mon.width / 2 - 10 }, - { heading = 'Status', key = 'status', width = mon.width - 10 }, - }, - } - - return jobListGrid -end - -UI:setPages({ - listing = listingPage, - item = itemPage, -}) - -UI:setPage(listingPage) -listingPage:setFocus(listingPage.statusBar.filter) - -local jobListGrid = jobMonitor() -jobListGrid:draw() -jobListGrid:sync() - -function craftingThread() - - while true do - os.sleep(5) - - --pcall(function() - - local items = controller:listItems() - - if not controller:isOnline() then - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'Power failure') - jobListGrid:sync() - - elseif Util.size(items) == 0 then - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system') - jobListGrid:sync() - - else - local itemList = watchResources(items) - jobListGrid:setValues(itemList) - jobListGrid:draw() - jobListGrid:sync() - craftItems(itemList, items) - --jobListGrid:update() - jobListGrid:draw() - jobListGrid:sync() - - itemList = getAutocraftItems() -- autocrafted items don't show on job monitor - craftItems(itemList, items) - end - --end) - end -end - -UI:pullEvents(craftingThread) - -UI.term:reset() -jobListGrid.parent:reset() diff --git a/sys/apps/treefarm.lua b/sys/apps/treefarm.lua new file mode 100644 index 0000000..5ddedf3 --- /dev/null +++ b/sys/apps/treefarm.lua @@ -0,0 +1,708 @@ +requireInjector(getfenv(1)) + +--[[ + Requirements: + Place turtle against an oak tree or oak sapling + Area around turtle must be flat and can only be dirt or grass + (9 blocks in each direction from turtle) + Turtle must have: crafting table, chest + Turtle must have a pick equipped on the left side + + Optional: + Add additional sapling types that can grow with a single sapling + + Notes: + If the turtle does not get any saplings from the initial tree, place + down another sapling in front of the turtle. + + The program will be able to survive server restarts as long as it has + created the cobble line. If the program is stopped before that time, + place the turtle in the original position before restarting the program. +]]-- + +local ChestProvider = require('chestProvider18') +local Craft = require('turtle.craft') +local Level = require('turtle.level') +local Point = require('point') +local Util = require('util') + +local FUEL_BASE = 0 +local FUEL_DIRE = FUEL_BASE + 10 +local FUEL_GOOD = FUEL_BASE + 2000 + +local MIN_CHARCOAL = 24 +local MAX_SAPLINGS = 32 + +local GRID_WIDTH = 8 +local GRID_LENGTH = 10 +local GRID = { + TL = { x = 8, y = 0, z = -8 }, + TR = { x = 8, y = 0, z = 8 }, + BL = { x = -10, y = 0, z = -8 }, + BR = { x = -10, y = 0, z = 8 }, +} + +local HOME_PT = { x = 0, y = 0, z = 0, heading = 0 } + +local DIG_BLACKLIST = { + [ 'minecraft:furnace' ] = true, + [ 'minecraft:lit_furnace' ] = true, + [ 'minecraft:chest' ] = true, +} + +local COBBLESTONE = 'minecraft:cobblestone:0' +local CHARCOAL = 'minecraft:coal:1' +local OAK_LOG = 'minecraft:log:0' +local OAK_PLANK = 'minecraft:planks:0' +local CHEST = 'minecraft:chest:0' +local FURNACE = 'minecraft:furnace:0' +local SAPLING = 'minecraft:sapling:0' +local STONE = 'minecraft:stone:0' +local TORCH = 'minecraft:torch:0' +local DIRT = 'minecraft:dirt:0' +local APPLE = 'minecraft:apple:0' +local STICK = 'minecraft:stick:0' + +local ALL_SAPLINGS = { + SAPLING +} + +local state = Util.readTable('usr/config/treefarm') or { + trees = { + { x = 1, y = 0, z = 0 } + } +} + +local clock = os.clock() +local recipes = Util.readTable('sys/etc/recipes.db') or { } + +Craft.setRecipes(recipes) + +local function inspect(fn) + local s, item = fn() + if s and item then + return item.name .. ':' .. item.metadata + end + return 'minecraft:air:0' +end + +local function setState(key, value) + state[key] = value + Util.writeTable('usr/config/treefarm', state) +end + +local function refuel() + if turtle.getFuelLevel() < FUEL_GOOD then + local charcoal = turtle.getItemCount(CHARCOAL) + if charcoal > 1 then + turtle.refuel(CHARCOAL, math.min(charcoal - 1, MIN_CHARCOAL / 2)) + print('fuel: ' .. turtle.getFuelLevel()) + end + end + return true +end + +local function safePlaceBlock(item) + + if turtle.placeUp(item) then + return true + end + + local s, m = turtle.inspectUp() + if s and not DIG_BLACKLIST[m.name] then + turtle.digUp() + return turtle.placeUp(item) + end + + turtle.forward() + return turtle.placeUp(item) +end + +local function craftItem(item, qty) + + local success + + if safePlaceBlock(CHEST) then + + if turtle.equip('left', 'minecraft:crafting_table') then + + local chestProvider = ChestProvider({ + wrapSide = 'top', + direction = 'down', + }) + if not chestProvider:isValid() then + print('invalid chestProvider') + read() + end + -- turtle.emptyInventory(turtle.dropUp) + + Util.print('Crafting %d %s', (qty or 1), item) + success = Craft.craftRecipe(recipes[item], qty or 1, chestProvider) + + repeat until not turtle.suckUp() + end + turtle.equip('left', 'minecraft:diamond_pickaxe') + turtle.digUp() + end + + return success +end + +local function cook(item, count, result, fuel, fuelCount) + + setState('cooking', true) + + fuel = fuel or CHARCOAL + fuelCount = fuelCount or math.ceil(count / 8) + Util.print('Making %d %s', count, result) + + turtle.dropForwardAt(state.furnace, fuel, fuelCount) + turtle.dropDownAt(state.furnace, item, count) + + count = count + turtle.getItemCount(result) + turtle.select(1) + turtle.pathfind(Point.below(state.furnace)) + repeat + os.sleep(1) + turtle.suckUp() + until turtle.getItemCount(result) >= count + + setState('cooking') +end + +local function makeSingleCharcoal() + + local slots = turtle.getSummedInventory() + + if not state.furnace or + slots[CHARCOAL] or + not slots[OAK_LOG] or + slots[OAK_LOG].count < 2 then + return true + end + + turtle.faceAgainst(state.furnace) + if craftItem(OAK_PLANK) then + cook(OAK_LOG, 1, CHARCOAL, OAK_PLANK, 1) + turtle.refuel(OAK_PLANK) + end + + return true +end + +local function makeCharcoal() + + local slots = turtle.getSummedInventory() + + if not state.furnace or + not slots[CHARCOAL] or + slots[CHARCOAL].count >= MIN_CHARCOAL then + return true + end + + local function getLogSlot(slots) + local maxslot = { count = 0 } + for k,slot in pairs(slots) do + if string.match(k, 'minecraft:log') then + if slot.count > maxslot.count then + maxslot = slot + end + end + end + return maxslot + end + + repeat + local slots = turtle.getSummedInventory() + local charcoal = slots[CHARCOAL].count + local slot = getLogSlot(slots) + + if slot.count < 8 then + break + end + + local toCook = math.min(charcoal, math.floor(slot.count / 8)) + toCook = math.min(toCook, math.floor((MIN_CHARCOAL + 8 - charcoal) / 8)) + toCook = toCook * 8 + + cook(slot.key, toCook, CHARCOAL) + + until charcoal + toCook >= MIN_CHARCOAL + + return true +end + +local function emptyFurnace() + if state.cooking then + + print('Emptying furnace') + + turtle.suckDownAt(state.furnace) + turtle.suckForwardAt(state.furnace) + turtle.suckUpAt(state.furnace) + setState('cooking') + end +end + +local function getCobblestone(count) + + local slots = turtle.getSummedInventory() + + if not slots[COBBLESTONE] or slots[COBBLESTONE].count < count then + + print('Collecting cobblestone') + + slots[COBBLESTONE] = true + slots[DIRT] = true + + local pt = Point.copy(GRID.BR) + pt.x = GRID.BR.x + 2 + pt.z = GRID.BR.z - 2 + + turtle.pathfind(pt) + + repeat + turtle.select(1) + turtle.digDown() + turtle.down() + for i = 1, 3 do + if inspect(turtle.inspect) == STONE then + turtle.dig() + end + turtle.turnRight() + end + + for item in pairs(turtle.getSummedInventory()) do + if not slots[item] then + turtle.drop(item) + end + end + + until turtle.getItemCount(COBBLESTONE) >= count + + turtle.gotoPoint(pt) + turtle.placeDown(DIRT) + + turtle.drop(DIRT) + end +end + +local function createFurnace() + + if not state.furnace then + if turtle.getFuelLevel() < FUEL_BASE + 100 then + return true -- try again later + end + print('Adding a furnace') + getCobblestone(8) + + if craftItem(FURNACE) then + turtle.drop(COBBLESTONE) + local furnacePt = { x = GRID.BL.x + 2, y = 1, z = GRID.BL.z + 2 } + turtle.placeAt(furnacePt, FURNACE) + setState('furnace', furnacePt) + end + end +end + +local function createPerimeter() + + if not state.perimeter then + if not state.furnace or + turtle.getFuelLevel() < FUEL_BASE + 500 or + turtle.getItemCount(OAK_LOG) == 0 or + not craftItem(OAK_PLANK, 2) then + return true + end + + print('Creating a perimeter') + + getCobblestone(GRID_WIDTH * 2 + 1) + cook(COBBLESTONE, 2, STONE, OAK_PLANK, 2) + turtle.refuel(OAK_PLANK) + + turtle.pathfind(GRID.BL) + turtle.digDown() + turtle.placeDown(STONE) + + turtle.setMoveCallback(function() + local target = COBBLESTONE + if math.abs(turtle.point.x) == GRID_LENGTH and + math.abs(turtle.point.z) == GRID_WIDTH then + target = STONE + end + + if inspect(turtle.inspectDown) ~= target then + turtle.digDown() + turtle.placeDown(target) + end + end) + + turtle.pathfind(GRID.BR) + + turtle.clearMoveCallback() + turtle.drop(COBBLESTONE) + turtle.drop(DIRT) + + setState('perimeter', true) + end +end + +local function createChests() + if state.chest_1 then + return false + end + if state.perimeter and + turtle.getFuelLevel() > FUEL_BASE + 100 and + Craft.canCraft(CHEST, 4, turtle.getSummedInventory()) then + + print('Adding storage') + if craftItem(CHEST, 4) then + + local pt = Point.copy(GRID.BL) + pt.x = pt.x + 1 + pt.y = pt.y - 1 + + for i = 1, 2 do + pt.z = pt.z + 1 + + turtle.digDownAt(pt) + turtle.placeDown(CHEST) + + pt.z = pt.z + 1 + + turtle.digDownAt(pt) + turtle.placeDown(CHEST) + + setState('chest_' .. i, Util.shallowCopy(pt)) + + pt.z = pt.z + 1 + end + turtle.drop(DIRT) + turtle.refuel(OAK_PLANK) + end + end + return true +end + +local function dropOffItems() + + if state.chest_1 then + local slots = turtle.getSummedInventory() + + if state.chest_1 and + slots[CHARCOAL] and + slots[CHARCOAL].count >= MIN_CHARCOAL and + (turtle.getItemCount('minecraft:log') > 0 or + turtle.getItemCount('minecraft:log2') > 0) then + + print('Storing logs') + turtle.pathfind(state.chest_1) + turtle.dropDown('minecraft:log') + turtle.dropDown('minecraft:log2') + end + + if slots[APPLE] then + print('Storing apples') + turtle.dropDownAt(state.chest_2, APPLE) + end + end + + return true +end + +local function eatSaplings() + + local slots = turtle.getSummedInventory() + + for _, sapling in pairs(ALL_SAPLINGS) do + if slots[sapling] and slots[sapling].count > MAX_SAPLINGS then + turtle.refuel(sapling, slots[sapling].count - MAX_SAPLINGS) + end + end + return true +end + +local function placeTorches() + if state.torches then + return + end + + if Craft.canCraft(TORCH, 4, turtle.getSummedInventory()) and + turtle.getFuelLevel() > 100 then + + print('Placing torches') + + if craftItem(TORCH, 4) then + local pts = { } + for x = -4, 4, 8 do + for z = -4, 4, 8 do + table.insert(pts, { x = x, y = 0, z = z }) + end + end + Point.eachClosest(turtle.point, pts, function(pt) + turtle.placeAt(pt, TORCH) + end) + turtle.refuel(STICK) + turtle.refuel(OAK_PLANK) + setState('torches', true) + end + end + + return true +end + +local function randomSapling() + + local sapling = SAPLING + + if #state.trees > 1 then + ALL_SAPLINGS = { } + + local slots = turtle.getFilledSlots() + for _, slot in pairs(slots) do + if slot.name == 'minecraft:sapling' then + table.insert(ALL_SAPLINGS, slot.key) + end + end + sapling = ALL_SAPLINGS[math.random(1, #ALL_SAPLINGS)] + end + + return sapling +end + +local function fellTree(pt) + + local function desparateRefuel(min) + if turtle.getFuelLevel() < min then + local logs = turtle.getItemCount(OAK_LOG) + if logs > 0 then + if craftItem(OAK_PLANK, math.min(8, logs * 4)) then + turtle.refuel(OAK_PLANK) + print('fuel: ' .. turtle.getFuelLevel()) + end + end + end + end + + turtle.setMoveCallback(function() desparateRefuel(FUEL_DIRE) end) + + desparateRefuel(FUEL_DIRE) + + if turtle.digUpAt(Point.above(pt)) then + Level( + { x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 }, + { x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) }, + Point.above(pt)) + end + + desparateRefuel(FUEL_BASE + 100) + turtle.clearMoveCallback() + turtle.setPolicy("attack") + + return true +end + +local function fell() + + local pts = Util.shallowCopy(state.trees) + + local pt = table.remove(pts, math.random(1, #pts)) + if not turtle.faceAgainst(pt) or + not string.match(inspect(turtle.inspect), 'minecraft:log') then + return true + end + + print('Chopping') + + local fuel = turtle.getFuelLevel() + table.insert(pts, 1, pt) + + Point.eachClosest(turtle.point, pts, function(pt) + if turtle.faceAgainst(pt) and + string.match(inspect(turtle.inspect), 'minecraft:log') then + turtle.dig() + fellTree(pt) + end + turtle.placeAt(pt, randomSapling()) + end) + + print('Used ' .. (fuel - turtle.getFuelLevel()) .. ' fuel') + return true +end + +local function moreTrees() + + if #state.trees > 1 then + return + end + + if not state.chest_1 or turtle.getItemCount(SAPLING) < 9 then + return true + end + + print('Adding more trees') + + local singleTree = state.trees[1] + + state.trees = { } + for x = -2, 2, 2 do + for z = -2, 2, 2 do + table.insert(state.trees, { x = x, y = 0, z = z }) + end + end + + turtle.digAt(singleTree) + fellTree(singleTree) + + setState('trees', state.trees) + + Point.eachClosest(turtle.point, state.trees, function(pt) + turtle.placeDownAt(pt, randomSapling()) + end) +end + +function getTurtleFacing(block) + local directions = { + [5] = 2, + [3] = 3, + [4] = 0, + [2] = 1, + } + + if not safePlaceBlock(block) then + error('unable to place chest above') + end + local _, bi = turtle.inspectUp() + turtle.digUp() + return directions[bi.metadata] +end + +function saveTurtleFacing() + if not state.facing then + setState('facing', getTurtleFacing(CHEST)) + end +end + +local function findGround() + print('Locating ground level') + turtle.setPoint(HOME_PT) + + while true do + local s, block = turtle.inspectDown() + + if not s then block = { name = 'minecraft:air', metadata = 0 } end + b = block.name .. ':' .. block.metadata + + if b == 'minecraft:dirt:0' or + b == 'minecraft:grass:0' or + block.name == 'minecraft:chest' then + break + end + + if b == COBBLESTONE or b == STONE then + error('lost') + end + + if b == TORCH or b == FURNACE then + turtle.forward() + else + turtle.digDown() + turtle.down() + end + + if turtle.point.y < -20 then + error('lost') + end + end + turtle.setPoint(HOME_PT) +end + +local function findHome() + + if not state.perimeter then + return + end + + print('Determining location') + + turtle.point.heading = getTurtleFacing(CHEST) + turtle.setHeading(state.facing) + turtle.point.heading = 0 + + local pt = Point.copy(turtle.point) + + while inspect(turtle.inspectDown) ~= COBBLESTONE do + pt.x = pt.x - 1 + turtle.pathfind(pt) + if pt.x < -16 then + error('lost') + end + end + while inspect(turtle.inspectDown) == COBBLESTONE do + pt.z = pt.z - 1 + turtle.pathfind(pt) + if pt.z < -16 then + error('lost') + end + end + + turtle.setPoint({ + x = -(GRID_LENGTH), + y = 0, + z = -GRID_WIDTH, + heading = turtle.point.heading + }) +end + +local function updateClock() + + local ONE_HOUR = 50 + + if os.clock() - clock > ONE_HOUR then + clock = os.clock() + else + print('sleeping for ' .. math.floor(ONE_HOUR - (os.clock() - clock))) + os.sleep(ONE_HOUR - (os.clock() - clock)) + clock = os.clock() + end + + return true +end + +local tasks = { + { desc = 'Finding ground', fn = findGround }, + { desc = 'Determine facing', fn = saveTurtleFacing }, + { desc = 'Finding home', fn = findHome }, + { desc = 'Adding trees', fn = moreTrees }, + { desc = 'Chopping', fn = fell }, + { desc = 'Snacking', fn = eatSaplings }, + { desc = 'Creating chest', fn = createChests }, + { desc = 'Creating furnace', fn = createFurnace }, + { desc = 'Emptying furnace', fn = emptyFurnace }, + { desc = 'Making charcoal', fn = makeSingleCharcoal }, + { desc = 'Making charcoal', fn = makeCharcoal }, + { desc = 'Creating perimeter', fn = createPerimeter }, + { desc = 'Placing torches', fn = placeTorches }, + { desc = 'Refueling', fn = refuel }, + { desc = 'Dropping off items', fn = dropOffItems }, + { desc = 'Condensing', fn = turtle.condense }, + { desc = 'Sleeping', fn = updateClock }, +} + +turtle.run(function() + + turtle.setPolicy("attack") + + while not turtle.abort do + print('fuel: ' .. turtle.getFuelLevel()) + for _,task in ipairs(Util.shallowCopy(tasks)) do + --print(task.desc) + turtle.status = task.desc + turtle.select(1) + if not task.fn() then + Util.filterInplace(tasks, function(v) return v.fn ~= task.fn end) + end + end + end +end) diff --git a/sys/autorun/gps.lua b/sys/autorun/gps.lua index 5c2617a..7872c86 100644 --- a/sys/autorun/gps.lua +++ b/sys/autorun/gps.lua @@ -1,17 +1,16 @@ if turtle and device.wireless_modem then local s, m = turtle.run(function() - local homePt = turtle.loadLocation('gpsHome') - if homePt then + requireInjector(getfenv(1)) - requireInjector(getfenv(1)) + local Config = require('config') + local config = { + destructive = false, + } + Config.load('gps', config) - local Config = require('config') - local config = { - destructive = false, - } - Config.load('gps', config) + if config.home then local s = turtle.enableGPS(2) if not s then @@ -30,7 +29,7 @@ if turtle and device.wireless_modem then turtle.setPolicy('turtleSafe') end - if not turtle.pathfind(homePt) then + if not turtle.pathfind(config.home) then error('Failed to return home') end end diff --git a/sys/etc/recipes.db b/sys/etc/recipes.db new file mode 100644 index 0000000..c34f765 --- /dev/null +++ b/sys/etc/recipes.db @@ -0,0 +1,2146 @@ +{ + [ "minecraft:wool:4" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:11", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:stained_glass:9" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:6", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:trapdoor:0" ] = { + count = 2, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:dark_oak_fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:5", + "minecraft:stick:0", + "minecraft:planks:5", + [ 5 ] = "minecraft:planks:5", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:5", + }, + }, + [ "minecraft:dye:8" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:15", + [ 6 ] = "minecraft:dye:0", + }, + }, + [ "minecraft:carpet:4" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:4", + [ 6 ] = "minecraft:wool:4", + }, + }, + [ "minecraft:stained_glass:1" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:14", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:wooden_pressure_plate:0" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:hay_block:0" ] = { + count = 1, + ingredients = { + "minecraft:wheat:0", + "minecraft:wheat:0", + "minecraft:wheat:0", + [ 5 ] = "minecraft:wheat:0", + [ 6 ] = "minecraft:wheat:0", + [ 7 ] = "minecraft:wheat:0", + [ 9 ] = "minecraft:wheat:0", + [ 10 ] = "minecraft:wheat:0", + [ 11 ] = "minecraft:wheat:0", + }, + }, + [ "minecraft:stained_hardened_clay:13" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:2", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_glass_pane:11" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:11", + "minecraft:stained_glass:11", + "minecraft:stained_glass:11", + [ 5 ] = "minecraft:stained_glass:11", + [ 6 ] = "minecraft:stained_glass:11", + [ 7 ] = "minecraft:stained_glass:11", + }, + }, + [ "minecraft:dye:10" ] = { + count = 2, + ingredients = { + "minecraft:dye:15", + "minecraft:dye:2", + }, + }, + [ "minecraft:birch_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:planks:2", + [ 9 ] = "minecraft:planks:2", + [ 10 ] = "minecraft:planks:2", + [ 11 ] = "minecraft:planks:2", + [ 5 ] = "minecraft:planks:2", + [ 6 ] = "minecraft:planks:2", + }, + }, + [ "minecraft:carpet:12" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:12", + [ 6 ] = "minecraft:wool:12", + }, + }, + [ "minecraft:birch_fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:2", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:2", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:acacia_fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:4", + "minecraft:stick:0", + "minecraft:planks:4", + [ 5 ] = "minecraft:planks:4", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:4", + }, + }, + [ "minecraft:diamond_block:0" ] = { + count = 1, + ingredients = { + "minecraft:diamond:0", + "minecraft:diamond:0", + "minecraft:diamond:0", + [ 5 ] = "minecraft:diamond:0", + [ 6 ] = "minecraft:diamond:0", + [ 7 ] = "minecraft:diamond:0", + [ 9 ] = "minecraft:diamond:0", + [ 10 ] = "minecraft:diamond:0", + [ 11 ] = "minecraft:diamond:0", + }, + }, + [ "extrautils2:compressednetherrack:3" ] = { + count = 9, + ingredients = { + [ 6 ] = "extrautils2:compressednetherrack:4", + }, + }, + [ "minecraft:stone:1" ] = { + count = 1, + ingredients = { + "minecraft:stone:3", + "minecraft:quartz:0", + }, + }, + [ "minecraft:wooden_slab:2" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:planks:2", + [ 7 ] = "minecraft:planks:2", + [ 5 ] = "minecraft:planks:2", + }, + }, + [ "minecraft:stained_hardened_clay:14" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:1", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_glass_pane:6" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:6", + "minecraft:stained_glass:6", + "minecraft:stained_glass:6", + [ 5 ] = "minecraft:stained_glass:6", + [ 6 ] = "minecraft:stained_glass:6", + [ 7 ] = "minecraft:stained_glass:6", + }, + }, + [ "minecraft:carpet:9" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:9", + [ 6 ] = "minecraft:wool:9", + }, + }, + [ "minecraft:carpet:0" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:glass_pane:0" ] = { + count = 16, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:glass:0", + [ 7 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:pumpkin_seeds:0" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:pumpkin:0", + }, + }, + [ "minecraft:stone_slab:4" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:brick_block:0", + [ 7 ] = "minecraft:brick_block:0", + [ 5 ] = "minecraft:brick_block:0", + }, + }, + [ "minecraft:carpet:10" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:10", + [ 6 ] = "minecraft:wool:10", + }, + }, + [ "minecraft:prismarine:2" ] = { + count = 1, + ingredients = { + "minecraft:prismarine_shard:0", + "minecraft:prismarine_shard:0", + "minecraft:prismarine_shard:0", + [ 5 ] = "minecraft:prismarine_shard:0", + [ 6 ] = "minecraft:dye:0", + [ 7 ] = "minecraft:prismarine_shard:0", + [ 9 ] = "minecraft:prismarine_shard:0", + [ 10 ] = "minecraft:prismarine_shard:0", + [ 11 ] = "minecraft:prismarine_shard:0", + }, + }, + [ "minecraft:stained_glass_pane:1" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:1", + "minecraft:stained_glass:1", + "minecraft:stained_glass:1", + [ 5 ] = "minecraft:stained_glass:1", + [ 6 ] = "minecraft:stained_glass:1", + [ 7 ] = "minecraft:stained_glass:1", + }, + }, + [ "minecraft:cobblestone_wall:0" ] = { + count = 6, + ingredients = { + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 6 ] = "minecraft:cobblestone:0", + [ 7 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:wooden_button:0" ] = { + count = 1, + ingredients = { + [ 6 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:book:0" ] = { + count = 1, + ingredients = { + "minecraft:paper:0", + "minecraft:paper:0", + "minecraft:paper:0", + [ 5 ] = "minecraft:leather:0", + }, + }, + [ "minecraft:stone_pressure_plate:0" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:stone:0", + [ 6 ] = "minecraft:stone:0", + }, + }, + [ "minecraft:planks:4" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log2:0", + }, + }, + [ "minecraft:stone_slab:7" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:quartz_block:0", + [ 7 ] = "minecraft:quartz_block:0", + [ 5 ] = "minecraft:quartz_block:0", + }, + }, + [ "minecraft:sandstone:1" ] = { + count = 1, + ingredients = { + [ 2 ] = "minecraft:stone_slab:1", + [ 6 ] = "minecraft:stone_slab:1", + }, + }, + [ "minecraft:stonebrick:0" ] = { + count = 4, + ingredients = { + "minecraft:stone:0", + "minecraft:stone:0", + [ 5 ] = "minecraft:stone:0", + [ 6 ] = "minecraft:stone:0", + }, + }, + [ "minecraft:furnace:0" ] = { + count = 1, + ingredients = { + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 7 ] = "minecraft:cobblestone:0", + [ 9 ] = "minecraft:cobblestone:0", + [ 10 ] = "minecraft:cobblestone:0", + [ 11 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:dye:5" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:1", + [ 6 ] = "minecraft:dye:4", + }, + }, + [ "minecraft:stone_brick_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:stonebrick:0", + [ 9 ] = "minecraft:stonebrick:0", + [ 10 ] = "minecraft:stonebrick:0", + [ 11 ] = "minecraft:stonebrick:0", + [ 5 ] = "minecraft:stonebrick:0", + [ 6 ] = "minecraft:stonebrick:0", + }, + }, + [ "minecraft:banner:0" ] = { + count = 1, + ingredients = { + "minecraft:wool:15", + "minecraft:wool:15", + "minecraft:wool:15", + [ 5 ] = "minecraft:wool:15", + [ 6 ] = "minecraft:wool:15", + [ 7 ] = "minecraft:wool:15", + [ 10 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:stained_glass:10" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:5", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:sign:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:light_weighted_pressure_plate:0" ] = { + count = 1, + ingredients = { + "minecraft:gold_ingot:0", + "minecraft:gold_ingot:0", + }, + }, + [ "minecraft:flower_pot:0" ] = { + count = 1, + ingredients = { + "minecraft:brick:0", + [ 6 ] = "minecraft:brick:0", + [ 3 ] = "minecraft:brick:0", + }, + }, + [ "minecraft:wooden_door:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 9 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:wool:0" ] = { + count = 1, + ingredients = { + "minecraft:string:0", + "minecraft:string:0", + [ 5 ] = "minecraft:string:0", + [ 6 ] = "minecraft:string:0", + }, + }, + [ "minecraft:carpet:2" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:2", + [ 6 ] = "minecraft:wool:2", + }, + }, + [ "minecraft:comparator:0" ] = { + count = 1, + ingredients = { + [ 7 ] = "minecraft:redstone_torch:0", + [ 2 ] = "minecraft:redstone_torch:0", + [ 10 ] = "minecraft:stone:0", + [ 11 ] = "minecraft:stone:0", + [ 5 ] = "minecraft:redstone_torch:0", + [ 6 ] = "minecraft:quartz:0", + [ 9 ] = "minecraft:stone:0", + }, + }, + [ "minecraft:acacia_fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:4", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:4", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:stained_glass_pane:3" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:3", + "minecraft:stained_glass:3", + "minecraft:stained_glass:3", + [ 5 ] = "minecraft:stained_glass:3", + [ 6 ] = "minecraft:stained_glass:3", + [ 7 ] = "minecraft:stained_glass:3", + }, + }, + [ "minecraft:stained_glass:3" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:12", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:stick:0" ] = { + count = 4, + ingredients = { + [ 2 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:stained_glass_pane:0" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:0", + "minecraft:stained_glass:0", + "minecraft:stained_glass:0", + [ 5 ] = "minecraft:stained_glass:0", + [ 6 ] = "minecraft:stained_glass:0", + [ 7 ] = "minecraft:stained_glass:0", + }, + }, + [ "minecraft:wool:6" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:9", + }, + }, + [ "minecraft:stonebrick:3" ] = { + count = 1, + ingredients = { + [ 2 ] = "minecraft:stone_slab:5", + [ 6 ] = "minecraft:stone_slab:5", + }, + }, + [ "minecraft:emerald_block:0" ] = { + count = 1, + ingredients = { + "minecraft:emerald:0", + "minecraft:emerald:0", + "minecraft:emerald:0", + [ 5 ] = "minecraft:emerald:0", + [ 6 ] = "minecraft:emerald:0", + [ 7 ] = "minecraft:emerald:0", + [ 9 ] = "minecraft:emerald:0", + [ 10 ] = "minecraft:emerald:0", + [ 11 ] = "minecraft:emerald:0", + }, + }, + [ "minecraft:heavy_weighted_pressure_plate:0" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:planks:3" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log:3", + }, + }, + [ "minecraft:wool:13" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:2", + }, + }, + [ "minecraft:noteblock:0" ] = { + count = 1, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:redstone:0", + [ 7 ] = "minecraft:planks:0", + [ 9 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:planks:0", + [ 11 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:sea_lantern:0" ] = { + count = 1, + ingredients = { + "minecraft:prismarine_shard:0", + "minecraft:prismarine_crystals:0", + "minecraft:prismarine_shard:0", + [ 5 ] = "minecraft:prismarine_crystals:0", + [ 6 ] = "minecraft:prismarine_crystals:0", + [ 7 ] = "minecraft:prismarine_crystals:0", + [ 9 ] = "minecraft:prismarine_shard:0", + [ 10 ] = "minecraft:prismarine_crystals:0", + [ 11 ] = "minecraft:prismarine_shard:0", + }, + }, + [ "minecraft:dye:9" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:1", + [ 6 ] = "minecraft:dye:15", + }, + }, + [ "minecraft:spruce_door:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:1", + "minecraft:planks:1", + [ 9 ] = "minecraft:planks:1", + [ 10 ] = "minecraft:planks:1", + [ 5 ] = "minecraft:planks:1", + [ 6 ] = "minecraft:planks:1", + }, + }, + [ "minecraft:stained_glass:15" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:0", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:stained_hardened_clay:5" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:10", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_glass:12" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:3", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:crafting_table:0" ] = { + count = 1, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:stained_hardened_clay:8" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:7", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:oak_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:planks:0", + [ 9 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:planks:0", + [ 11 ] = "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:wool:11" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:4", + }, + }, + [ "minecraft:stained_glass_pane:15" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:15", + "minecraft:stained_glass:15", + "minecraft:stained_glass:15", + [ 5 ] = "minecraft:stained_glass:15", + [ 6 ] = "minecraft:stained_glass:15", + [ 7 ] = "minecraft:stained_glass:15", + }, + }, + [ "minecraft:stained_glass:2" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:13", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:lever:0" ] = { + count = 1, + ingredients = { + [ 2 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:carpet:13" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:13", + [ 6 ] = "minecraft:wool:13", + }, + }, + [ "minecraft:glowstone:0" ] = { + count = 1, + ingredients = { + "minecraft:glowstone_dust:0", + "minecraft:glowstone_dust:0", + [ 5 ] = "minecraft:glowstone_dust:0", + [ 6 ] = "minecraft:glowstone_dust:0", + }, + }, + [ "minecraft:bone_block:0" ] = { + count = 1, + ingredients = { + "minecraft:dye:15", + "minecraft:dye:15", + "minecraft:dye:15", + [ 5 ] = "minecraft:dye:15", + [ 6 ] = "minecraft:dye:15", + [ 7 ] = "minecraft:dye:15", + [ 9 ] = "minecraft:dye:15", + [ 10 ] = "minecraft:dye:15", + [ 11 ] = "minecraft:dye:15", + }, + }, + [ "minecraft:stained_hardened_clay:3" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:12", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:nether_brick_fence:0" ] = { + count = 6, + ingredients = { + "minecraft:nether_brick:0", + "minecraft:nether_brick:0", + "minecraft:nether_brick:0", + [ 5 ] = "minecraft:nether_brick:0", + [ 6 ] = "minecraft:nether_brick:0", + [ 7 ] = "minecraft:nether_brick:0", + }, + }, + [ "minecraft:planks:0" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log:0", + }, + }, + [ "minecraft:dispenser:0" ] = { + count = 1, + ingredients = { + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 6 ] = "minecraft:bow:0", + [ 7 ] = "minecraft:cobblestone:0", + [ 9 ] = "minecraft:cobblestone:0", + [ 10 ] = "minecraft:redstone:0", + [ 11 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:redstone_lamp:0" ] = { + count = 1, + ingredients = { + [ 7 ] = "minecraft:redstone:0", + [ 2 ] = "minecraft:redstone:0", + [ 10 ] = "minecraft:redstone:0", + [ 5 ] = "minecraft:redstone:0", + [ 6 ] = "minecraft:glowstone:0", + }, + }, + [ "minecraft:redstone_torch:0" ] = { + count = 1, + ingredients = { + [ 2 ] = "minecraft:redstone:0", + [ 6 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:wool:15" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:0", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:planks:2" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log:2", + }, + }, + [ "minecraft:iron_trapdoor:0" ] = { + count = 1, + ingredients = { + "minecraft:iron_ingot:0", + "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:wool:7" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:8", + }, + }, + [ "minecraft:stained_glass:14" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:1", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:jungle_fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:3", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:3", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:red_sandstone:2" ] = { + count = 4, + ingredients = { + "minecraft:red_sandstone:0", + "minecraft:red_sandstone:0", + [ 5 ] = "minecraft:red_sandstone:0", + [ 6 ] = "minecraft:red_sandstone:0", + }, + }, + [ "minecraft:anvil:0" ] = { + count = 1, + ingredients = { + "minecraft:iron_block:0", + "minecraft:iron_block:0", + "minecraft:iron_block:0", + [ 9 ] = "minecraft:iron_ingot:0", + [ 10 ] = "minecraft:iron_ingot:0", + [ 11 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:string:0" ] = { + count = 2, + ingredients = { + "harvestcraft:cottonItem:0", + "harvestcraft:cottonItem:0", + [ 5 ] = "harvestcraft:cottonItem:0", + }, + }, + [ "minecraft:carpet:8" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:8", + [ 6 ] = "minecraft:wool:8", + }, + }, + [ "minecraft:wooden_slab:1" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:planks:1", + [ 7 ] = "minecraft:planks:1", + [ 5 ] = "minecraft:planks:1", + }, + }, + [ "minecraft:chest:0" ] = { + count = 1, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:planks:0", + [ 9 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:planks:0", + [ 11 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:quartz_block:0" ] = { + count = 1, + ingredients = { + "minecraft:quartz:0", + "minecraft:quartz:0", + [ 5 ] = "minecraft:quartz:0", + [ 6 ] = "minecraft:quartz:0", + }, + }, + [ "minecraft:ladder:0" ] = { + count = 3, + ingredients = { + "minecraft:stick:0", + [ 7 ] = "minecraft:stick:0", + [ 9 ] = "minecraft:stick:0", + [ 3 ] = "minecraft:stick:0", + [ 11 ] = "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:trapped_chest:0" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:chest:0", + [ 6 ] = "minecraft:tripwire_hook:0", + }, + }, + [ "minecraft:dark_oak_fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:5", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:5", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:stained_glass:7" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:8", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:stained_hardened_clay:7" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:8", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_hardened_clay:9" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:6", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:wool:14" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:1", + }, + }, + [ "minecraft:wool:5" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:10", + }, + }, + [ "minecraft:quartz_block:1" ] = { + count = 1, + ingredients = { + [ 2 ] = "minecraft:stone_slab:7", + [ 6 ] = "minecraft:stone_slab:7", + }, + }, + [ "minecraft:acacia_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:planks:4", + [ 9 ] = "minecraft:planks:4", + [ 10 ] = "minecraft:planks:4", + [ 11 ] = "minecraft:planks:4", + [ 5 ] = "minecraft:planks:4", + [ 6 ] = "minecraft:planks:4", + }, + }, + [ "minecraft:netherrack:0" ] = { + count = 9, + ingredients = { + [ 6 ] = "extrautils2:compressednetherrack:0", + }, + }, + [ "minecraft:stained_hardened_clay:1" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:14", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:red_sandstone:0" ] = { + count = 1, + ingredients = { + "minecraft:sand:1", + "minecraft:sand:1", + [ 5 ] = "minecraft:sand:1", + [ 6 ] = "minecraft:sand:1", + }, + }, + [ "minecraft:dirt:1" ] = { + count = 4, + ingredients = { + "minecraft:dirt:0", + "minecraft:gravel:0", + [ 5 ] = "minecraft:gravel:0", + [ 6 ] = "minecraft:dirt:0", + }, + }, + [ "minecraft:dropper:0" ] = { + count = 1, + ingredients = { + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 7 ] = "minecraft:cobblestone:0", + [ 9 ] = "minecraft:cobblestone:0", + [ 10 ] = "minecraft:redstone:0", + [ 11 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:bow:0" ] = { + count = 1, + ingredients = { + "minecraft:string:0", + "minecraft:stick:0", + [ 9 ] = "minecraft:string:0", + [ 7 ] = "minecraft:stick:0", + [ 5 ] = "minecraft:string:0", + [ 10 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:bed:0" ] = { + count = 1, + ingredients = { + "minecraft:wool:14", + "minecraft:wool:14", + "minecraft:wool:14", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:jungle_fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:3", + "minecraft:stick:0", + "minecraft:planks:3", + [ 5 ] = "minecraft:planks:3", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:3", + }, + }, + [ "minecraft:cauldron:0" ] = { + count = 1, + ingredients = { + "minecraft:iron_ingot:0", + [ 7 ] = "minecraft:iron_ingot:0", + [ 9 ] = "minecraft:iron_ingot:0", + [ 10 ] = "minecraft:iron_ingot:0", + [ 11 ] = "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 3 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:prismarine:1" ] = { + count = 1, + ingredients = { + "minecraft:prismarine_shard:0", + "minecraft:prismarine_shard:0", + "minecraft:prismarine_shard:0", + [ 5 ] = "minecraft:prismarine_shard:0", + [ 6 ] = "minecraft:prismarine_shard:0", + [ 7 ] = "minecraft:prismarine_shard:0", + [ 9 ] = "minecraft:prismarine_shard:0", + [ 10 ] = "minecraft:prismarine_shard:0", + [ 11 ] = "minecraft:prismarine_shard:0", + }, + }, + [ "minecraft:redstone_block:0" ] = { + count = 1, + ingredients = { + "minecraft:redstone:0", + "minecraft:redstone:0", + "minecraft:redstone:0", + [ 5 ] = "minecraft:redstone:0", + [ 6 ] = "minecraft:redstone:0", + [ 7 ] = "minecraft:redstone:0", + [ 9 ] = "minecraft:redstone:0", + [ 10 ] = "minecraft:redstone:0", + [ 11 ] = "minecraft:redstone:0", + }, + }, + [ "minecraft:wool:8" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:wool:0", + [ 6 ] = "minecraft:dye:7", + }, + }, + [ "minecraft:dark_oak_door:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:5", + "minecraft:planks:5", + [ 6 ] = "minecraft:planks:5", + [ 10 ] = "minecraft:planks:5", + [ 5 ] = "minecraft:planks:5", + [ 9 ] = "minecraft:planks:5", + }, + }, + [ "minecraft:stained_hardened_clay:15" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:0", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:dye:14" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:1", + [ 6 ] = "minecraft:dye:11", + }, + }, + [ "minecraft:planks:1" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log:1", + }, + }, + [ "minecraft:iron_bars:0" ] = { + count = 16, + ingredients = { + "minecraft:iron_ingot:0", + "minecraft:iron_ingot:0", + "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:iron_ingot:0", + [ 7 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:stained_glass_pane:7" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:7", + "minecraft:stained_glass:7", + "minecraft:stained_glass:7", + [ 5 ] = "minecraft:stained_glass:7", + [ 6 ] = "minecraft:stained_glass:7", + [ 7 ] = "minecraft:stained_glass:7", + }, + }, + [ "minecraft:carpet:5" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:5", + [ 6 ] = "minecraft:wool:5", + }, + }, + [ "minecraft:carpet:3" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:3", + [ 6 ] = "minecraft:wool:3", + }, + }, + [ "minecraft:detector_rail:0" ] = { + count = 6, + ingredients = { + "minecraft:iron_ingot:0", + [ 7 ] = "minecraft:iron_ingot:0", + [ 9 ] = "minecraft:iron_ingot:0", + [ 10 ] = "minecraft:redstone:0", + [ 11 ] = "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:stone_pressure_plate:0", + [ 3 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:stained_glass_pane:9" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:9", + "minecraft:stained_glass:9", + "minecraft:stained_glass:9", + [ 5 ] = "minecraft:stained_glass:9", + [ 6 ] = "minecraft:stained_glass:9", + [ 7 ] = "minecraft:stained_glass:9", + }, + }, + [ "minecraft:end_bricks:0" ] = { + count = 4, + ingredients = { + "minecraft:end_stone:0", + "minecraft:end_stone:0", + [ 5 ] = "minecraft:end_stone:0", + [ 6 ] = "minecraft:end_stone:0", + }, + }, + [ "minecraft:stone_button:0" ] = { + count = 1, + ingredients = { + [ 6 ] = "minecraft:stone:0", + }, + }, + [ "minecraft:stained_glass_pane:12" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:12", + "minecraft:stained_glass:12", + "minecraft:stained_glass:12", + [ 5 ] = "minecraft:stained_glass:12", + [ 6 ] = "minecraft:stained_glass:12", + [ 7 ] = "minecraft:stained_glass:12", + }, + }, + [ "minecraft:stained_glass_pane:10" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:10", + "minecraft:stained_glass:10", + "minecraft:stained_glass:10", + [ 5 ] = "minecraft:stained_glass:10", + [ 6 ] = "minecraft:stained_glass:10", + [ 7 ] = "minecraft:stained_glass:10", + }, + }, + [ "extrautils2:compressednetherrack:1" ] = { + count = 9, + ingredients = { + [ 6 ] = "extrautils2:compressednetherrack:2", + }, + }, + [ "minecraft:stained_glass:8" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:7", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:planks:5" ] = { + count = 4, + ingredients = { + [ 6 ] = "minecraft:log2:1", + }, + }, + [ "minecraft:wool:10" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:5", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:stained_glass:5" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:10", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:iron_block:0" ] = { + count = 1, + ingredients = { + "minecraft:iron_ingot:0", + "minecraft:iron_ingot:0", + "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:iron_ingot:0", + [ 7 ] = "minecraft:iron_ingot:0", + [ 9 ] = "minecraft:iron_ingot:0", + [ 10 ] = "minecraft:iron_ingot:0", + [ 11 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:torch:0" ] = { + count = 4, + ingredients = { + [ 2 ] = "minecraft:coal:1", + [ 6 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:stone_slab:6" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:nether_brick:0", + [ 7 ] = "minecraft:nether_brick:0", + [ 5 ] = "minecraft:nether_brick:0", + }, + }, + [ "minecraft:stone:6" ] = { + count = 4, + ingredients = { + "minecraft:stone:5", + "minecraft:stone:5", + [ 5 ] = "minecraft:stone:5", + [ 6 ] = "minecraft:stone:5", + }, + }, + [ "minecraft:dye:13" ] = { + count = 3, + ingredients = { + "minecraft:dye:4", + "minecraft:dye:1", + [ 5 ] = "minecraft:dye:9", + }, + }, + [ "minecraft:sugar:0" ] = { + count = 1, + ingredients = { + [ 6 ] = "minecraft:reeds:0", + }, + }, + [ "minecraft:carpet:6" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:6", + [ 6 ] = "minecraft:wool:6", + }, + }, + [ "minecraft:stained_glass:6" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:9", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:stone_slab:5" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:stonebrick:0", + [ 7 ] = "minecraft:stonebrick:0", + [ 5 ] = "minecraft:stonebrick:0", + }, + }, + [ "minecraft:sandstone:0" ] = { + count = 1, + ingredients = { + "minecraft:sand:0", + "minecraft:sand:0", + [ 5 ] = "minecraft:sand:0", + [ 6 ] = "minecraft:sand:0", + }, + }, + [ "minecraft:stained_hardened_clay:12" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:3", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_glass:0" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:15", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:wool:9" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:6", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:stained_glass:11" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:4", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:carpet:11" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:11", + [ 6 ] = "minecraft:wool:11", + }, + }, + [ "minecraft:end_rod:0" ] = { + count = 4, + ingredients = { + [ 2 ] = "minecraft:blaze_rod:0", + [ 6 ] = "minecraft:chorus_fruit_popped:0", + }, + }, + [ "minecraft:carpet:7" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:7", + [ 6 ] = "minecraft:wool:7", + }, + }, + [ "minecraft:wool:2" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:13", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:brick_block:0" ] = { + count = 1, + ingredients = { + "minecraft:brick:0", + "minecraft:brick:0", + [ 5 ] = "minecraft:brick:0", + [ 6 ] = "minecraft:brick:0", + }, + }, + [ "minecraft:ender_chest:0" ] = { + count = 1, + ingredients = { + "minecraft:obsidian:0", + "minecraft:obsidian:0", + "minecraft:obsidian:0", + [ 5 ] = "minecraft:obsidian:0", + [ 6 ] = "minecraft:ender_eye:0", + [ 7 ] = "minecraft:obsidian:0", + [ 9 ] = "minecraft:obsidian:0", + [ 10 ] = "minecraft:obsidian:0", + [ 11 ] = "minecraft:obsidian:0", + }, + }, + [ "minecraft:stained_hardened_clay:11" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:4", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stone_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:cobblestone:0", + [ 9 ] = "minecraft:cobblestone:0", + [ 10 ] = "minecraft:cobblestone:0", + [ 11 ] = "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 6 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:stained_glass_pane:2" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:2", + "minecraft:stained_glass:2", + "minecraft:stained_glass:2", + [ 5 ] = "minecraft:stained_glass:2", + [ 6 ] = "minecraft:stained_glass:2", + [ 7 ] = "minecraft:stained_glass:2", + }, + }, + [ "minecraft:hopper:0" ] = { + count = 1, + ingredients = { + "minecraft:iron_ingot:0", + [ 3 ] = "minecraft:iron_ingot:0", + [ 5 ] = "minecraft:iron_ingot:0", + [ 6 ] = "minecraft:chest:0", + [ 7 ] = "minecraft:iron_ingot:0", + [ 10 ] = "minecraft:iron_ingot:0", + }, + }, + [ "minecraft:stained_glass_pane:13" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:13", + "minecraft:stained_glass:13", + "minecraft:stained_glass:13", + [ 5 ] = "minecraft:stained_glass:13", + [ 6 ] = "minecraft:stained_glass:13", + [ 7 ] = "minecraft:stained_glass:13", + }, + }, + [ "extrautils2:compressednetherrack:2" ] = { + count = 9, + ingredients = { + [ 6 ] = "extrautils2:compressednetherrack:3", + }, + }, + [ "minecraft:wool:12" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:3", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:birch_door:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:2", + "minecraft:planks:2", + [ 9 ] = "minecraft:planks:2", + [ 10 ] = "minecraft:planks:2", + [ 5 ] = "minecraft:planks:2", + [ 6 ] = "minecraft:planks:2", + }, + }, + [ "minecraft:nether_brick_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:nether_brick:0", + [ 9 ] = "minecraft:nether_brick:0", + [ 10 ] = "minecraft:nether_brick:0", + [ 11 ] = "minecraft:nether_brick:0", + [ 5 ] = "minecraft:nether_brick:0", + [ 6 ] = "minecraft:nether_brick:0", + }, + }, + [ "minecraft:sandstone_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:sandstone:0", + [ 9 ] = "minecraft:sandstone:0", + [ 10 ] = "minecraft:sandstone:0", + [ 11 ] = "minecraft:sandstone:0", + [ 5 ] = "minecraft:sandstone:0", + [ 6 ] = "minecraft:sandstone:0", + }, + }, + [ "minecraft:prismarine:0" ] = { + count = 1, + ingredients = { + "minecraft:prismarine_shard:0", + "minecraft:prismarine_shard:0", + [ 5 ] = "minecraft:prismarine_shard:0", + [ 6 ] = "minecraft:prismarine_shard:0", + }, + }, + [ "minecraft:stone:5" ] = { + count = 2, + ingredients = { + "minecraft:stone:3", + "minecraft:cobblestone:0", + }, + }, + [ "minecraft:stained_glass_pane:8" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:8", + "minecraft:stained_glass:8", + "minecraft:stained_glass:8", + [ 5 ] = "minecraft:stained_glass:8", + [ 6 ] = "minecraft:stained_glass:8", + [ 7 ] = "minecraft:stained_glass:8", + }, + }, + [ "minecraft:gold_block:0" ] = { + count = 1, + ingredients = { + "minecraft:gold_ingot:0", + "minecraft:gold_ingot:0", + "minecraft:gold_ingot:0", + [ 5 ] = "minecraft:gold_ingot:0", + [ 6 ] = "minecraft:gold_ingot:0", + [ 7 ] = "minecraft:gold_ingot:0", + [ 9 ] = "minecraft:gold_ingot:0", + [ 10 ] = "minecraft:gold_ingot:0", + [ 11 ] = "minecraft:gold_ingot:0", + }, + }, + [ "minecraft:stained_glass:13" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:2", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:stone_slab:3" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:cobblestone:0", + [ 7 ] = "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + }, + }, + [ "minecraft:stained_hardened_clay:0" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:15", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:wooden_slab:4" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:planks:4", + [ 7 ] = "minecraft:planks:4", + [ 5 ] = "minecraft:planks:4", + }, + }, + [ "minecraft:dye:6" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:2", + [ 6 ] = "minecraft:dye:4", + }, + }, + [ "minecraft:carpet:14" ] = { + count = 3, + ingredients = { + "minecraft:wool:14", + "minecraft:wool:14", + }, + }, + [ "minecraft:spruce_fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:1", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:1", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "minecraft:stone_slab:1" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:sandstone:0", + [ 7 ] = "minecraft:sandstone:0", + [ 5 ] = "minecraft:sandstone:0", + }, + }, + [ "minecraft:spruce_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:planks:1", + [ 9 ] = "minecraft:planks:1", + [ 10 ] = "minecraft:planks:1", + [ 11 ] = "minecraft:planks:1", + [ 5 ] = "minecraft:planks:1", + [ 6 ] = "minecraft:planks:1", + }, + }, + [ "minecraft:quartz_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:quartz_block:0", + [ 9 ] = "minecraft:quartz_block:0", + [ 10 ] = "minecraft:quartz_block:0", + [ 11 ] = "minecraft:quartz_block:0", + [ 5 ] = "minecraft:quartz_block:0", + [ 6 ] = "minecraft:quartz_block:0", + }, + }, + [ "minecraft:ender_eye:0" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:blaze_powder:0", + [ 6 ] = "minecraft:ender_pearl:0", + }, + }, + [ "minecraft:fence_gate:0" ] = { + count = 1, + ingredients = { + "minecraft:stick:0", + "minecraft:planks:0", + "minecraft:stick:0", + [ 5 ] = "minecraft:stick:0", + [ 6 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:stick:0", + }, + }, + [ "extrautils2:compressednetherrack:0" ] = { + count = 9, + ingredients = { + [ 6 ] = "extrautils2:compressednetherrack:1", + }, + }, + [ "minecraft:coal_block:0" ] = { + count = 1, + ingredients = { + "minecraft:coal:0", + "minecraft:coal:0", + "minecraft:coal:0", + [ 5 ] = "minecraft:coal:0", + [ 6 ] = "minecraft:coal:0", + [ 7 ] = "minecraft:coal:0", + [ 9 ] = "minecraft:coal:0", + [ 10 ] = "minecraft:coal:0", + [ 11 ] = "minecraft:coal:0", + }, + }, + [ "minecraft:enchanting_table:0" ] = { + count = 1, + ingredients = { + [ 7 ] = "minecraft:diamond:0", + [ 2 ] = "minecraft:book:0", + [ 10 ] = "minecraft:obsidian:0", + [ 11 ] = "minecraft:obsidian:0", + [ 5 ] = "minecraft:diamond:0", + [ 6 ] = "minecraft:obsidian:0", + [ 9 ] = "minecraft:obsidian:0", + }, + }, + [ "minecraft:lapis_block:0" ] = { + count = 1, + ingredients = { + "minecraft:dye:4", + "minecraft:dye:4", + "minecraft:dye:4", + [ 5 ] = "minecraft:dye:4", + [ 6 ] = "minecraft:dye:4", + [ 7 ] = "minecraft:dye:4", + [ 9 ] = "minecraft:dye:4", + [ 10 ] = "minecraft:dye:4", + [ 11 ] = "minecraft:dye:4", + }, + }, + [ "minecraft:quartz_block:2" ] = { + count = 2, + ingredients = { + [ 2 ] = "minecraft:quartz_block:0", + [ 6 ] = "minecraft:quartz_block:0", + }, + }, + [ "minecraft:stone:4" ] = { + count = 4, + ingredients = { + "minecraft:stone:3", + "minecraft:stone:3", + [ 5 ] = "minecraft:stone:3", + [ 6 ] = "minecraft:stone:3", + }, + }, + [ "minecraft:dye:12" ] = { + count = 2, + ingredients = { + [ 5 ] = "minecraft:dye:4", + [ 6 ] = "minecraft:dye:15", + }, + }, + [ "minecraft:birch_fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:2", + "minecraft:stick:0", + "minecraft:planks:2", + [ 5 ] = "minecraft:planks:2", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:2", + }, + }, + [ "minecraft:dark_oak_stairs:0" ] = { + count = 8, + ingredients = { + "minecraft:planks:5", + [ 9 ] = "minecraft:planks:5", + [ 10 ] = "minecraft:planks:5", + [ 11 ] = "minecraft:planks:5", + [ 5 ] = "minecraft:planks:5", + [ 6 ] = "minecraft:planks:5", + }, + }, + [ "minecraft:stone_slab:0" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:stone:0", + [ 7 ] = "minecraft:stone:0", + [ 5 ] = "minecraft:stone:0", + }, + }, + [ "minecraft:wooden_slab:0" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:planks:0", + [ 7 ] = "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:stone:3" ] = { + count = 2, + ingredients = { + "minecraft:quartz:0", + "minecraft:cobblestone:0", + [ 5 ] = "minecraft:cobblestone:0", + [ 6 ] = "minecraft:quartz:0", + }, + }, + [ "minecraft:stained_glass:4" ] = { + count = 8, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:dye:11", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:glass:0", + [ 10 ] = "minecraft:glass:0", + [ 11 ] = "minecraft:glass:0", + }, + }, + [ "minecraft:wool:3" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:12", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:carpet:15" ] = { + count = 3, + ingredients = { + [ 5 ] = "minecraft:wool:15", + [ 6 ] = "minecraft:wool:15", + }, + }, + [ "minecraft:bookshelf:0" ] = { + count = 1, + ingredients = { + "minecraft:planks:0", + "minecraft:planks:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:book:0", + [ 6 ] = "minecraft:book:0", + [ 7 ] = "minecraft:book:0", + [ 9 ] = "minecraft:planks:0", + [ 10 ] = "minecraft:planks:0", + [ 11 ] = "minecraft:planks:0", + }, + }, + [ "minecraft:stained_hardened_clay:4" ] = { + count = 8, + ingredients = { + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + "minecraft:hardened_clay:0", + [ 5 ] = "minecraft:hardened_clay:0", + [ 6 ] = "minecraft:dye:11", + [ 7 ] = "minecraft:hardened_clay:0", + [ 9 ] = "minecraft:hardened_clay:0", + [ 10 ] = "minecraft:hardened_clay:0", + [ 11 ] = "minecraft:hardened_clay:0", + }, + }, + [ "minecraft:stained_glass_pane:4" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:4", + "minecraft:stained_glass:4", + "minecraft:stained_glass:4", + [ 5 ] = "minecraft:stained_glass:4", + [ 6 ] = "minecraft:stained_glass:4", + [ 7 ] = "minecraft:stained_glass:4", + }, + }, + [ "minecraft:wooden_slab:5" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:planks:5", + [ 7 ] = "minecraft:planks:5", + [ 5 ] = "minecraft:planks:5", + }, + }, + [ "minecraft:stained_glass_pane:5" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:5", + "minecraft:stained_glass:5", + "minecraft:stained_glass:5", + [ 5 ] = "minecraft:stained_glass:5", + [ 6 ] = "minecraft:stained_glass:5", + [ 7 ] = "minecraft:stained_glass:5", + }, + }, + [ "minecraft:dye:7" ] = { + count = 3, + ingredients = { + "minecraft:dye:15", + "minecraft:dye:15", + [ 5 ] = "minecraft:dye:0", + }, + }, + [ "minecraft:tnt:0" ] = { + count = 1, + ingredients = { + "minecraft:gunpowder:0", + "minecraft:sand:0", + "minecraft:gunpowder:0", + [ 5 ] = "minecraft:sand:0", + [ 6 ] = "minecraft:gunpowder:0", + [ 7 ] = "minecraft:sand:0", + [ 9 ] = "minecraft:gunpowder:0", + [ 10 ] = "minecraft:sand:0", + [ 11 ] = "minecraft:gunpowder:0", + }, + }, + [ "minecraft:nether_brick:0" ] = { + count = 1, + ingredients = { + "minecraft:netherbrick:0", + "minecraft:netherbrick:0", + [ 5 ] = "minecraft:netherbrick:0", + [ 6 ] = "minecraft:netherbrick:0", + }, + }, + [ "minecraft:paper:0" ] = { + count = 3, + ingredients = { + "minecraft:reeds:0", + "minecraft:reeds:0", + "minecraft:reeds:0", + }, + }, + [ "minecraft:spruce_fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:1", + "minecraft:stick:0", + "minecraft:planks:1", + [ 5 ] = "minecraft:planks:1", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:1", + }, + }, + [ "minecraft:stained_glass_pane:14" ] = { + count = 16, + ingredients = { + "minecraft:stained_glass:14", + "minecraft:stained_glass:14", + "minecraft:stained_glass:14", + [ 5 ] = "minecraft:stained_glass:14", + [ 6 ] = "minecraft:stained_glass:14", + [ 7 ] = "minecraft:stained_glass:14", + }, + }, + [ "minecraft:mossy_cobblestone:0" ] = { + count = 1, + ingredients = { + "minecraft:cobblestone:0", + "minecraft:vine:0", + }, + }, + [ "minecraft:snow_layer:0" ] = { + count = 6, + ingredients = { + [ 6 ] = "minecraft:snow:0", + [ 7 ] = "minecraft:snow:0", + [ 5 ] = "minecraft:snow:0", + }, + }, + [ "minecraft:wool:1" ] = { + count = 1, + ingredients = { + [ 5 ] = "minecraft:dye:14", + [ 6 ] = "minecraft:wool:0", + }, + }, + [ "minecraft:beacon:0" ] = { + count = 1, + ingredients = { + "minecraft:glass:0", + "minecraft:glass:0", + "minecraft:glass:0", + [ 5 ] = "minecraft:glass:0", + [ 6 ] = "minecraft:nether_star:0", + [ 7 ] = "minecraft:glass:0", + [ 9 ] = "minecraft:obsidian:0", + [ 10 ] = "minecraft:obsidian:0", + [ 11 ] = "minecraft:obsidian:0", + }, + }, + [ "minecraft:sandstone:2" ] = { + count = 4, + ingredients = { + "minecraft:sandstone:0", + "minecraft:sandstone:0", + [ 5 ] = "minecraft:sandstone:0", + [ 6 ] = "minecraft:sandstone:0", + }, + }, + [ "minecraft:fence:0" ] = { + count = 3, + ingredients = { + "minecraft:planks:0", + "minecraft:stick:0", + "minecraft:planks:0", + [ 5 ] = "minecraft:planks:0", + [ 6 ] = "minecraft:stick:0", + [ 7 ] = "minecraft:planks:0", + }, + }, +} \ No newline at end of file diff --git a/sys/etc/scripts/follow b/sys/etc/scripts/follow index 115ca1d..769b643 100644 --- a/sys/etc/scripts/follow +++ b/sys/etc/scripts/follow @@ -46,7 +46,7 @@ local function follow(id) addBlocks(pt) addBlocks({ x = pt.x, z = pt.z, y = pt.y + 1 }) - if turtle.pathfind(cpt, blocks) then + if turtle.pathfind(cpt, { blocks = blocks }) then turtle.headTowards(pt) end following = false diff --git a/sys/etc/scripts/moveTo b/sys/etc/scripts/moveTo index 53c05e3..deb7be5 100644 --- a/sys/etc/scripts/moveTo +++ b/sys/etc/scripts/moveTo @@ -23,7 +23,7 @@ turtle.run(function() error('turtle: No GPS response') end - if not turtle.pathfind(pt, nil, 64) then + if not turtle.pathfind(pt) then error('Unable to go to location') end end) diff --git a/sys/extensions/scheduler.lua b/sys/extensions/scheduler.lua deleted file mode 100644 index 6669228..0000000 --- a/sys/extensions/scheduler.lua +++ /dev/null @@ -1,86 +0,0 @@ -if not turtle or turtle.abortAction then - return -end - -requireInjector(getfenv(1)) - -local Util = require('util') - -local Scheduler = { - uid = 0, - queue = { }, - idle = true, -} - -function turtle.abortAction() - if turtle.status ~= 'idle' then - turtle.abort = true - os.queueEvent('turtle_abort') - end - Util.clear(Scheduler.queue) - os.queueEvent('turtle_ticket', 0, true) -end - -local function getTicket(fn, ...) - Scheduler.uid = Scheduler.uid + 1 - - if Scheduler.idle then - Scheduler.idle = false - turtle.status = 'busy' - os.queueEvent('turtle_ticket', Scheduler.uid) - else - table.insert(Scheduler.queue, Scheduler.uid) - end - - return Scheduler.uid -end - -local function releaseTicket(id) - for k,v in ipairs(Scheduler.queue) do - if v == id then - table.remove(Scheduler.queue, k) - return - end - end - local id = table.remove(Scheduler.queue, 1) - if id then - os.queueEvent('turtle_ticket', id) - else - Scheduler.idle = true - turtle.status = 'idle' - end -end - -function turtle.run(fn, ...) - local ticketId = getTicket() - - if type(fn) == 'string' then - fn = turtle[fn] - end - while true do - local e, id, abort = os.pullEventRaw('turtle_ticket') - if e == 'terminate' then - releaseTicket(ticketId) - os.queueEvent('turtle_response') - error('Terminated') - end - if abort then - -- the function was queued, but the queue was cleared - os.queueEvent('turtle_response') - return false, 'aborted' - end - if id == ticketId then - turtle.abort = false - turtle.resetState() - local args = { ... } - local s, m = pcall(function() fn(unpack(args)) end) - turtle.abort = false - releaseTicket(ticketId) - os.queueEvent('turtle_response') - if not s and m then - printError(m) - end - return s, m - end - end -end diff --git a/sys/extensions/tgps.lua b/sys/extensions/tgps.lua index f257236..b2767cb 100644 --- a/sys/extensions/tgps.lua +++ b/sys/extensions/tgps.lua @@ -3,7 +3,9 @@ if not turtle or turtle.enableGPS then end requireInjector(getfenv(1)) -local GPS = require('gps') + +local GPS = require('gps') +local Config = require('config') function turtle.enableGPS(timeout) if turtle.point.gps then @@ -18,17 +20,23 @@ function turtle.enableGPS(timeout) end function turtle.gotoGPSHome() - local homePt = turtle.loadLocation('gpsHome') - if homePt then + local config = { } + Config.load('gps', config) + + if config.home then if turtle.enableGPS() then - turtle.pathfind(homePt) + turtle.pathfind(config.home) end end end function turtle.setGPSHome() + local config = { } + Config.load('gps', config) + if turtle.enableGPS() then - turtle.storeLocation('gpsHome', turtle.point) + config.home = turtle.point + Config.update('gps', config) turtle.gotoPoint(turtle.point) end end diff --git a/sys/extensions/tl3.lua b/sys/extensions/tl3.lua index 9166384..1b72525 100644 --- a/sys/extensions/tl3.lua +++ b/sys/extensions/tl3.lua @@ -4,7 +4,10 @@ end requireInjector(getfenv(1)) -local Util = require('util') +local Point = require('point') +local synchronized = require('sync') +local Util = require('util') +turtle.pathfind = require('turtle.pathfind') local function noop() end @@ -147,6 +150,29 @@ function turtle.getHeadingInfo(heading) end -- [[ Basic turtle actions ]] -- +local function inventoryAction(fn, name, qty) + local slots = turtle.getFilledSlots() + local s + for _,slot in pairs(slots) do + if slot.key == name or slot.name == name then + turtle.native.select(slot.index) + if not qty then + s = fn() + else + s = fn(math.min(qty, slot.count)) + qty = qty - slot.count + if qty < 0 then + break + end + end + end + end + if not s then + return false, 'No items found' + end + return s +end + local function _attack(action) if action.attack() then repeat until not action.attack() @@ -193,25 +219,24 @@ function turtle.place(slot) return _place(actions.forward, slot) end function turtle.placeUp(slot) return _place(actions.up, slot) end function turtle.placeDown(slot) return _place(actions.down, slot) end -local function _drop(action, count, indexOrId) - - if indexOrId then - local slot = turtle.getSlot(indexOrId) - if not slot or slot.qty == 0 then - return false, 'No items to drop' - end - turtle.select(slot.index) +local function _drop(action, qtyOrName, qty) + if not qtyOrName or type(qtyOrName) == 'number' then + return action.drop(qtyOrName) end - if not count then - return action.drop() -- wtf - end - return action.drop(count) + return inventoryAction(action.drop, qtyOrName, qty) end function turtle.drop(count, slot) return _drop(actions.forward, count, slot) end function turtle.dropUp(count, slot) return _drop(actions.up, count, slot) end function turtle.dropDown(count, slot) return _drop(actions.down, count, slot) end +function turtle.refuel(qtyOrName, qty) + if not qtyOrName or type(qtyOrName) == 'number' then + return turtle.native.refuel(qtyOrName) + end + return inventoryAction(turtle.native.refuel, qtyOrName, qty) +end + --[[ function turtle.dig() return state.dig(actions.forward) end function turtle.digUp() return state.dig(actions.up) end @@ -277,7 +302,7 @@ turtle.movePolicies = { return false end local oldStatus = turtle.status - print('stuck') + print('assured move: stuck') turtle.status = 'stuck' repeat os.sleep(1) @@ -328,6 +353,7 @@ function turtle.setDigPolicy(policy) state.digPolicy = policy end function turtle.setAttackPolicy(policy) state.attackPolicy = policy end function turtle.setMoveCallback(cb) state.moveCallback = cb end function turtle.clearMoveCallback() state.moveCallback = noop end +function turtle.getMoveCallback() return state.moveCallback end -- [[ Locations ]] -- function turtle.getLocation(name) @@ -751,31 +777,47 @@ function turtle.getSlot(indexOrId, slots) local detail = turtle.getItemDetail(indexOrId) if detail then return { + name = detail.name, + damage = detail.damage, + count = detail.count, + key = detail.name .. ':' .. detail.damage, + + index = indexOrId, + + -- deprecate qty = detail.count, dmg = detail.damage, id = detail.name, iddmg = detail.name .. ':' .. detail.damage, - index = indexOrId, } end return { - qty = 0, + qty = 0, -- deprecate + count = 0, index = indexOrId, } end -function turtle.selectSlot(indexOrId) +function turtle.select(indexOrId) + + if type(indexOrId) == 'number' then + return turtle.native.select(indexOrId) + end local s = turtle.getSlot(indexOrId) if s then - turtle.select(s.index) + turtle.native.select(s.index) return s end return false, 'Inventory does not contain item' end +function turtle.selectSlot(indexOrId) -- deprecated + return turtle.select(indexOrId) +end + function turtle.getInventory(slots) slots = slots or { } for i = 1, 16 do @@ -784,11 +826,38 @@ function turtle.getInventory(slots) return slots end +function turtle.getSummedInventory() + local slots = turtle.getFilledSlots() + local t = { } + for _,slot in pairs(slots) do + local entry = t[slot.iddmg] + if not entry then + entry = { + count = 0, + damage = slot.damage, + name = slot.name, + key = slot.key, + + -- deprecate + qty = 0, + dmg = slot.dmg, + id = slot.id, + iddmg = slot.iddmg, + } + t[slot.iddmg] = entry + end + entry.qty = entry.qty + slot.qty + entry.count = entry.qty + end + return t +end + function turtle.emptyInventory(dropAction) dropAction = dropAction or turtle.drop for i = 1, 16 do turtle.emptySlot(i, dropAction) end + turtle.select(1) end function turtle.emptySlot(slot, dropAction) @@ -857,28 +926,243 @@ function turtle.selectSlotWithQuantity(qty, startSlot) end end -function turtle.condense(startSlot) - startSlot = startSlot or 1 - local aslots = turtle.getInventory() - - for _,slot in ipairs(aslots) do - if slot.qty < 64 then - for i = slot.index + 1, 16 do - local fslot = aslots[i] - if fslot.qty > 0 then - if slot.qty == 0 or slot.iddmg == fslot.iddmg then - turtle.select(fslot.index) - turtle.transferTo(slot.index, 64) - local transferred = turtle.getItemCount(slot.index) - slot.qty - slot.qty = slot.qty + transferred - fslot.qty = fslot.qty - transferred - slot.iddmg = fslot.iddmg - if slot.qty == 64 then - break - end +function turtle.condense() + local slots = turtle.getInventory() + + for i = 16, 1, -1 do + if slots[i].count > 0 then + for j = 1, i - 1 do + if slots[j].count == 0 or slots[i].key == slots[j].key then + turtle.select(i) + turtle.transferTo(j, 64) + local transferred = slots[i].qty - turtle.getItemCount(i) + slots[j].count = slots[j].count + transferred + slots[i].count = slots[i].count - transferred + slots[j].key = slots[i].key + if slots[i].count == 0 then + break end end end end end + return true end + +function turtle.getItemCount(idOrName) + if type(idOrName) == 'number' then + return turtle.native.getItemCount(idOrName) + end + local slots = turtle.getFilledSlots() + local count = 0 + for _,slot in pairs(slots) do + if slot.iddmg == idOrName or slot.name == idOrName then + count = count + slot.qty + end + end + return count +end + +function turtle.equip(side, item) + + if item then + if not turtle.select(item) then + return false, 'Unable to equip ' .. item + end + end + + if side == 'left' then + return turtle.equipLeft() + end + return turtle.equipRight() +end + +function turtle.run(fn, ...) + local args = { ... } + local s, m + + if type(fn) == 'string' then + fn = turtle[fn] + end + + synchronized(turtle, function() + turtle.abort = false + turtle.status = 'busy' + turtle.resetState() + s, m = pcall(function() fn(unpack(args)) end) + turtle.abort = false + turtle.status = 'idle' + if not s and m then + printError(m) + end + end) + + return s, m +end + +function turtle.abortAction() + if turtle.status ~= 'idle' then + turtle.abort = true + os.queueEvent('turtle_abort') + end +end + +-- [[ Pathing ]] -- +function turtle.faceAgainst(pt) -- 4 sided + + local pts = { } + + for i = 0, 3 do + local hi = turtle.getHeadingInfo(i) + + table.insert(pts, { + x = pt.x + hi.xd, + z = pt.z + hi.zd, + y = pt.y + hi.yd, + heading = (hi.heading + 2) % 4, + }) + end + + return turtle.pathfind(Point.closest(turtle.point, pts), { dest = pts }) +end + +function turtle.moveAgainst(pt) -- 6 sided + + local pts = { } + + for i = 0, 5 do + local hi = turtle.getHeadingInfo(i) + local heading, direction + if i < 4 then + heading = (hi.heading + 2) % 4 + direction = 'forward' + elseif i == 4 then + direction = 'down' + elseif i == 5 then + direction = 'up' + end + + table.insert(pts, { + x = pt.x + hi.xd, + z = pt.z + hi.zd, + y = pt.y + hi.yd, + direction = direction, + heading = heading, + }) + end + + return turtle.pathfind(Point.closest(turtle.point, pts), { dest = pts }) +end + +local actionsAt = { + detect = { + up = turtle.detectUp, + down = turtle.detectDown, + forward = turtle.detect, + }, + dig = { + up = turtle.digUp, + down = turtle.digDown, + forward = turtle.dig, + }, + move = { + up = turtle.moveUp, + down = turtle.moveDown, + forward = turtle.move, + }, + attack = { + up = turtle.attackUp, + down = turtle.attackDown, + forward = turtle.attack, + }, + place = { + up = turtle.placeUp, + down = turtle.placeDown, + forward = turtle.place, + }, + drop = { + up = turtle.dropUp, + down = turtle.dropDown, + forward = turtle.drop, + }, + suck = { + up = turtle.suckUp, + down = turtle.suckDown, + forward = turtle.suck, + }, + compare = { + up = turtle.compareUp, + down = turtle.compareDown, + forward = turtle.compare, + }, + inspect = { + up = turtle.inspectUp, + down = turtle.inspectDown, + forward = turtle.inspect, + }, +} + +local function _actionAt(action, pt, ...) + local pt = turtle.moveAgainst(pt) + if pt then + return action[pt.direction](...) + end +end + +function _actionDownAt(action, pt, ...) + if turtle.pathfind(Point.above(pt)) then + return action.down(...) + end +end + +function _actionForwardAt(action, pt, ...) + if turtle.faceAgainst(pt) then + return action.forward(...) + end +end + +function _actionUpAt(action, pt, ...) + if turtle.pathfind(Point.below(pt)) then + return action.up(...) + end +end + +function turtle.detectAt(pt) return _actionAt(actionsAt.detect, pt) end +function turtle.detectDownAt(pt) return _actionDownAt(actionsAt.detect, pt) end +function turtle.detectForwardAt(pt) return _actionForwardAt(actionsAt.detect, pt) end +function turtle.detectUpAt(pt) return _actionUpAt(actionsAt.detect, pt) end + +function turtle.digAt(pt) return _actionAt(actionsAt.dig, pt) end +function turtle.digDownAt(pt) return _actionDownAt(actionsAt.dig, pt) end +function turtle.digForwardAt(pt) return _actionForwardAt(actionsAt.dig, pt) end +function turtle.digUpAt(pt) return _actionUpAt(actionsAt.dig, pt) end + +function turtle.attackAt(pt) return _actionAt(actionsAt.attack, pt) end +function turtle.attackDownAt(pt) return _actionDownAt(actionsAt.attack, pt) end +function turtle.attackForwardAt(pt) return _actionForwardAt(actionsAt.attack, pt) end +function turtle.attackUpAt(pt) return _actionUpAt(actionsAt.attack, pt) end + +function turtle.placeAt(pt, arg) return _actionAt(actionsAt.place, pt, arg) end +function turtle.placeDownAt(pt, arg) return _actionDownAt(actionsAt.place, pt, arg) end +function turtle.placeForwardAt(pt, arg) return _actionForwardAt(actionsAt.place, pt, arg) end +function turtle.placeUpAt(pt, arg) return _actionUpAt(actionsAt.place, pt, arg) end + +function turtle.dropAt(pt, ...) return _actionAt(actionsAt.drop, pt, ...) end +function turtle.dropDownAt(pt, ...) return _actionDownAt(actionsAt.drop, pt, ...) end +function turtle.dropForwardAt(pt, ...) return _actionForwardAt(actionsAt.drop, pt, ...) end +function turtle.dropUpAt(pt, ...) return _actionUpAt(actionsAt.drop, pt, ...) end + +function turtle.suckAt(pt, qty) return _actionAt(actionsAt.suck, pt, qty) end +function turtle.suckDownAt(pt, qty) return _actionDownAt(actionsAt.suck, pt, qty) end +function turtle.suckForwardAt(pt, qty) return _actionForwardAt(actionsAt.suck, pt, qty) end +function turtle.suckUpAt(pt, qty) return _actionUpAt(actionsAt.suck, pt, qty) end + +function turtle.compareAt(pt) return _actionAt(actionsAt.compare, pt) end +function turtle.compareDownAt(pt) return _actionDownAt(actionsAt.compare, pt) end +function turtle.compareForwardAt(pt) return _actionForwardAt(actionsAt.compare, pt) end +function turtle.compareUpAt(pt) return _actionUpAt(actionsAt.compare, pt) end + +function turtle.inspectAt(pt) return _actionAt(actionsAt.inspect, pt) end +function turtle.inspectDownAt(pt) return _actionDownAt(actionsAt.inspect, pt) end +function turtle.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end +function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end diff --git a/sys/services/gpshost.lua b/sys/services/gpshost.lua index e4e1a62..47020ce 100644 --- a/sys/services/gpshost.lua +++ b/sys/services/gpshost.lua @@ -2,41 +2,15 @@ if device.wireless_modem then requireInjector(getfenv(1)) local Config = require('config') - local config = { - host = false, - auto = false, - x = 0, - y = 0, - z = 0, - } + local config = { } Config.load('gps', config) if config.host then multishell.setTitle(multishell.getCurrent(), 'GPS Daemon') - if config.auto then - local GPS = require('gps') - local pt - - for i = 1, 3 do - pt = GPS.getPoint(10, true) - if pt then - break - end - end - - if not pt then - error('Unable to get GPS coordinates') - end - - config.x = pt.x - config.y = pt.y - config.z = pt.z - end - - os.run(getfenv(1), '/rom/programs/gps', 'host', config.x, config.y, config.z) + os.run(getfenv(1), '/rom/programs/gps', 'host', config.host.x, config.host.y, config.host.z) print('GPS daemon stopped') end