turtle api

This commit is contained in:
kepler155c
2017-10-31 02:01:14 -04:00
parent d97a9d7468
commit 2526308eb6
6 changed files with 115 additions and 63 deletions

View File

@@ -586,14 +586,13 @@ local function closestEdgePoint(pt, pts, rpt)
return cpt return cpt
end end
function TurtleBuilder:getBuildingCorner() function TurtleBuilder:getBuildingCorner(y)
local pts = { local box = {
{ x = -1, z = -1, y = 0 }, x = -1, ex = self.schematic.width,
{ x = -1, z = self.schematic.length, y = 0 }, y = y, ey = y,
{ x = self.schematic.width, z = -1, y = 0 }, z = -1, ez = self.schematic.length,
{ x = self.schematic.width, z = self.schematic.length, y = 0 },
} }
return closestEdgePoint(self.supplyPoint, pts, turtle.getPoint()) return Point.closestPointInBox(turtle.getPoint(), box)
end end
function TurtleBuilder:gotoSupplyPoint() function TurtleBuilder:gotoSupplyPoint()
@@ -601,7 +600,7 @@ function TurtleBuilder:gotoSupplyPoint()
-- so we don't end up pathfinding through a building -- so we don't end up pathfinding through a building
-- go to the corner closest to the supplies point -- go to the corner closest to the supplies point
-- pathfind the rest of the way -- pathfind the rest of the way
local pt = self:getBuildingCorner() local pt = self:getBuildingCorner(turtle.point.y)
turtle._goto(pt.x, pt.z) turtle._goto(pt.x, pt.z)
turtle.setPolicy('none') turtle.setPolicy('none')
turtle.pathfind(self.supplyPoint) turtle.pathfind(self.supplyPoint)
@@ -1085,7 +1084,6 @@ end
function TurtleBuilder:build() function TurtleBuilder:build()
local direction = 1 local direction = 1
local last = #self.schematic.blocks local last = #self.schematic.blocks
local travelPlane = 0
local minFuel = self.schematic.height + self.schematic.width + self.schematic.length + 100 local minFuel = self.schematic.height + self.schematic.width + self.schematic.length + 100
local throttle = Util.throttle() local throttle = Util.throttle()
@@ -1094,11 +1092,12 @@ function TurtleBuilder:build()
last = 1 last = 1
turtle.setStatus('destroying') turtle.setStatus('destroying')
else else
travelPlane = self:findTravelPlane(self.index)
turtle.setStatus('building') turtle.setStatus('building')
end end
local pt = self:getBuildingCorner() local travelPlane = self:findTravelPlane(self.index)
local pt = self:getBuildingCorner(travelPlane)
turtle.pathfind({ x = pt.x, z = pt.z, y = travelPlane }) turtle.pathfind({ x = pt.x, z = pt.z, y = travelPlane })
turtle.setPolicy('digAttack') turtle.setPolicy('digAttack')
@@ -1210,22 +1209,21 @@ function TurtleBuilder:build()
end end
function TurtleBuilder:begin() function TurtleBuilder:begin()
turtle.reset()
self:dumpInventory()
self:refuel()
self:getTurtleFacing()
if self.loc.x then if self.loc.x then
self.supplyPoint = { self.supplyPoint = {
x = self.loc.x - self.loc.rx - 1, x = self.loc.x - self.loc.rx - 1,
y = self.loc.y - self.loc.ry, y = self.loc.y - self.loc.ry,
z = self.loc.z - self.loc.rz - 1, z = self.loc.z - self.loc.rz - 1,
} }
Point.rotate(self.supplyPoint, self.facing)
else else
self.supplyPoint = { x = -1, y = 0, z = -1 } self.supplyPoint = { x = -1, y = 0, z = -1 }
end end
turtle.reset()
self:dumpInventory()
self:refuel()
self:getTurtleFacing()
Point.rotate(self.supplyPoint, self.facing)
turtle.setPoint(self.supplyPoint) turtle.setPoint(self.supplyPoint)
-- reset piston cache in case wrench was substituted -- reset piston cache in case wrench was substituted

View File

@@ -2,7 +2,9 @@ local Util = require('util')
local turtle = _G.turtle local turtle = _G.turtle
local Craft = { } local Craft = {
recipes = Util.readTable('usr/etc/recipes.db') or { },
}
local function clearGrid(inventoryAdapter) local function clearGrid(inventoryAdapter)
for i = 1, 16 do for i = 1, 16 do
@@ -41,7 +43,6 @@ local function getItemCount(items, key)
end end
local function turtleCraft(recipe, qty, inventoryAdapter) local function turtleCraft(recipe, qty, inventoryAdapter)
clearGrid(inventoryAdapter) clearGrid(inventoryAdapter)
for k,v in pairs(recipe.ingredients) do for k,v in pairs(recipe.ingredients) do
@@ -57,6 +58,12 @@ local function turtleCraft(recipe, qty, inventoryAdapter)
end end
function Craft.craftRecipe(recipe, count, inventoryAdapter) function Craft.craftRecipe(recipe, count, inventoryAdapter)
if type(recipe) == 'string' then
recipe = Craft.recipes[recipe]
if not recipe then
return false, 'No recipe'
end
end
local items = inventoryAdapter:listItems() local items = inventoryAdapter:listItems()
@@ -103,18 +110,16 @@ end
-- given a certain quantity, return how many of those can be crafted -- given a certain quantity, return how many of those can be crafted
function Craft.getCraftableAmount(recipe, count, items, missing) function Craft.getCraftableAmount(recipe, count, items, missing)
local function sumItems(recipe, summedItems, count)
local function sumItems(recipe, items, summedItems, count)
local canCraft = 0 local canCraft = 0
for i = 1, count do for _ = 1, count do
for _,item in pairs(recipe.ingredients) do for _,item in pairs(recipe.ingredients) do
local summedItem = summedItems[item] or getItemCount(items, item) local summedItem = summedItems[item] or getItemCount(items, item)
local irecipe = Craft.recipes[item] local irecipe = Craft.recipes[item]
if irecipe and summedItem <= 0 then if irecipe and summedItem <= 0 then
summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) summedItem = summedItem + sumItems(irecipe, summedItems, 1)
end end
if summedItem <= 0 then if summedItem <= 0 then
if missing then if missing then
@@ -130,7 +135,7 @@ function Craft.getCraftableAmount(recipe, count, items, missing)
return canCraft return canCraft
end end
return sumItems(recipe, items, { }, math.ceil(count / recipe.count), missing) return sumItems(recipe, { }, math.ceil(count / recipe.count))
end end
function Craft.canCraft(item, count, items) function Craft.canCraft(item, count, items)
@@ -149,13 +154,15 @@ function Craft.getCraftableAmountTest()
{ name = 'minecraft:planks', damage = 0, count = 5 }, { name = 'minecraft:planks', damage = 0, count = 5 },
{ name = 'minecraft:log', damage = 0, count = 2 }, { name = 'minecraft:log', damage = 0, count = 2 },
} }
results[1] = { item = 'chest', expected = 1, got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) } results[1] = { item = 'chest', expected = 1,
got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) }
items = { items = {
{ name = 'minecraft:log', damage = 0, count = 1 }, { name = 'minecraft:log', damage = 0, count = 1 },
{ name = 'minecraft:coal', damage = 1, 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) } results[2] = { item = 'torch', expected = 4,
got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) }
return results return results
end end

64
apis/turtle/crafting.lua Normal file
View File

@@ -0,0 +1,64 @@
local Adapter = require('inventoryAdapter')
local Craft = require('turtle.craft')
local turtle = _G.turtle
local CRAFTING_TABLE = 'minecraft:crafting_table'
local function clearGrid(inventory)
for i = 1, 16 do
local count = turtle.getItemCount(i)
if count > 0 then
inventory:insert(i, count)
if turtle.getItemCount(i) ~= 0 then
return false
end
end
end
return true
end
function turtle.craftItem(item, count, inventoryInfo)
local success
local inventory = Adapter.wrap(inventoryInfo)
if not inventory then
return false, 'Invalid inventory'
end
local equipped, side
if not turtle.isEquipped('workbench') then
local modemSide = turtle.isEquipped('modem') or 'right'
local osides = { left = 'right', right = 'left' }
side = osides[modemSide]
if not turtle.select(CRAFTING_TABLE) then
clearGrid(inventory)
if not turtle.selectOpenSlot() then
return false, 'Inventory is full'
end
if not inventory:provide({ name = CRAFTING_TABLE, damage = 0 }, 1) then
return false, 'Missing crafting table'
end
end
local slot = turtle.select(CRAFTING_TABLE)
turtle.equip(side, CRAFTING_TABLE)
equipped = turtle.getItemDetail(slot)
end
success = Craft.craftRecipe(item, count or 1, inventory)
if equipped then
turtle.selectOpenSlot()
inventory:provide({ name = equipped.name, damage = equipped.damage }, 1)
turtle.equip(side, equipped.name .. ':' .. equipped.damage)
end
return success
end
function turtle.canCraft(item, count, items)
return Craft.canCraft(item, count, items)
end
return true

View File

@@ -113,7 +113,7 @@ local function getAdjacentPoint(pt)
return closestPoint(turtle.getPoint(), t) return closestPoint(turtle.getPoint(), t)
end end
return function(startPt, endPt, firstPt, verbose) function turtle.level(startPt, endPt, firstPt, verbose)
checkedNodes = { } checkedNodes = { }
nodes = { } nodes = { }
box = { } box = { }
@@ -166,3 +166,5 @@ return function(startPt, endPt, firstPt, verbose)
turtle.resetState() turtle.resetState()
turtle.setMoveCallback(oldCallback) turtle.setMoveCallback(oldCallback)
end end
return true

View File

@@ -251,17 +251,18 @@ local levelScript = [[
requireInjector(getfenv(1)) requireInjector(getfenv(1))
local Level = require('turtle.level')
local Util = require('util') local Util = require('util')
local s, m = turtle.run(function() local s, m = turtle.run(function()
turtle.addFeatures('level')
turtle.setStatus('Leveling') turtle.setStatus('Leveling')
if turtle.enableGPS() then if turtle.enableGPS() then
local pt = Util.shallowCopy(turtle.point) local pt = Util.shallowCopy(turtle.point)
local s, m = pcall(function() local s, m = pcall(function()
Level(data.startPt, data.endPt, data.firstPt) turtle.level(data.startPt, data.endPt, data.firstPt)
end) end)
turtle.pathfind(pt) turtle.pathfind(pt)

View File

@@ -6,7 +6,7 @@ _G.requireInjector()
Area around turtle must be flat and can only be dirt or grass Area around turtle must be flat and can only be dirt or grass
(10 blocks in each direction from turtle) (10 blocks in each direction from turtle)
Turtle must have: crafting table, chest Turtle must have: crafting table, chest
Turtle must have a pick equipped on the left side Turtle must have a pick equipped
Optional: Optional:
Add additional sapling types that can grow with a single sapling Add additional sapling types that can grow with a single sapling
@@ -20,12 +20,8 @@ _G.requireInjector()
place the turtle in the original position before restarting the program. place the turtle in the original position before restarting the program.
]]-- ]]--
local ChestAdapter = require('chestAdapter18') local Point = require('point')
local Craft = require('turtle.craft') local Util = require('util')
local Level = require('turtle.level')
local Pathing = require('turtle.pathfind')
local Point = require('point')
local Util = require('util')
local os = _G.os local os = _G.os
local read = _G.read local read = _G.read
@@ -80,9 +76,6 @@ local state = Util.readTable('usr/config/treefarm') or {
} }
local clock = os.clock() local clock = os.clock()
local recipes = Util.readTable('usr/etc/recipes.db') or { }
Craft.setRecipes(recipes)
local function inspect(fn) local function inspect(fn)
local s, item = fn() local s, item = fn()
@@ -125,28 +118,17 @@ local function safePlaceBlock(item)
end end
local function craftItem(item, qty) local function craftItem(item, qty)
local success local success
if safePlaceBlock(CHEST) then if safePlaceBlock(CHEST) then
if turtle.equip('left', 'minecraft:crafting_table') then Util.print('Crafting %d %s', (qty or 1), item)
success = turtle.craftItem(item, qty or 1, {
local chestAdapter = ChestAdapter({
wrapSide = 'top', wrapSide = 'top',
direction = 'down', direction = 'down',
}) })
if not chestAdapter:isValid() then repeat until not turtle.suckUp()
print('invalid chestAdapter')
read()
end
Util.print('Crafting %d %s', (qty or 1), item)
success = Craft.craftRecipe(recipes[item], qty or 1, chestAdapter)
repeat until not turtle.suckUp()
end
turtle.equip('left', 'minecraft:diamond_pickaxe')
turtle.digUp() turtle.digUp()
end end
@@ -360,7 +342,7 @@ local function createChests()
end end
if state.perimeter and if state.perimeter and
turtle.getFuelLevel() > FUEL_GOOD and turtle.getFuelLevel() > FUEL_GOOD and
Craft.canCraft(CHEST, 4, turtle.getSummedInventory()) then turtle.canCraft(CHEST, 4, turtle.getSummedInventory()) then
print('Adding storage') print('Adding storage')
if craftItem(CHEST, 4) then if craftItem(CHEST, 4) then
@@ -435,7 +417,7 @@ local function placeTorches()
end end
if turtle.getFuelLevel() > 100 and if turtle.getFuelLevel() > 100 and
Craft.canCraft(TORCH, 4, turtle.getSummedInventory()) then turtle.canCraft(TORCH, 4, turtle.getSummedInventory()) then
print('Placing torches') print('Placing torches')
@@ -498,7 +480,7 @@ local function fellTree(pt)
desperateRefuel(FUEL_DIRE) desperateRefuel(FUEL_DIRE)
if turtle.digUpAt(Point.above(pt)) then if turtle.digUpAt(Point.above(pt)) then
Level( turtle.level(
{ x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 }, { x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 },
{ x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) }, { x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) },
Point.above(pt)) Point.above(pt))
@@ -638,10 +620,7 @@ local function findHome()
end end
print('Determining location') print('Determining location')
turtle.point.heading = (getTurtleFacing(CHEST) - state.facing) % 4
turtle.point.heading = getTurtleFacing(CHEST)
turtle.setHeading(state.facing)
turtle.point.heading = 0
local pt = Point.copy(turtle.point) local pt = Point.copy(turtle.point)
@@ -668,7 +647,7 @@ local function findHome()
}) })
-- when pathfinding - don't leave this box -- when pathfinding - don't leave this box
Pathing.setBox({ turtle.setPathingBox({
x = GRID.TL.x, x = GRID.TL.x,
y = GRID.TL.y, y = GRID.TL.y,
z = GRID.TL.z, z = GRID.TL.z,
@@ -730,6 +709,7 @@ local tasks = {
local s, m = turtle.run(function() local s, m = turtle.run(function()
turtle.addFeatures('level', 'crafting')
turtle.setPolicy("attack") turtle.setPolicy("attack")
while not turtle.isAborted() do while not turtle.isAborted() do