1
0
mirror of https://github.com/kepler155c/opus synced 2024-12-24 23:50:26 +00:00

refactor + cleanup

This commit is contained in:
kepler155c@gmail.com 2017-10-27 20:24:48 -04:00
parent cac15722b8
commit 1b9450017d
12 changed files with 371 additions and 430 deletions

View File

@ -1,14 +1,14 @@
--- A light implementation of Binary heaps data structure. --- A light implementation of Binary heaps data structure.
-- While running a search, some search algorithms (Astar, Dijkstra, Jump Point Search) have to maintains -- While running a search, some search algorithms (Astar, Dijkstra, Jump Point Search) have to maintains
-- a list of nodes called __open list__. Retrieve from this list the lowest cost node can be quite slow, -- a list of nodes called __open list__. Retrieve from this list the lowest cost node can be quite slow,
-- as it normally requires to skim through the full set of nodes stored in this list. This becomes a real -- as it normally requires to skim through the full set of nodes stored in this list. This becomes a real
-- problem especially when dozens of nodes are being processed (on large maps). -- problem especially when dozens of nodes are being processed (on large maps).
-- --
-- The current module implements a <a href="http://www.policyalmanac.org/games/binaryHeaps.htm">binary heap</a> -- The current module implements a <a href="http://www.policyalmanac.org/games/binaryHeaps.htm">binary heap</a>
-- data structure, from which the search algorithm will instantiate an open list, and cache the nodes being -- data structure, from which the search algorithm will instantiate an open list, and cache the nodes being
-- examined during a search. As such, retrieving the lower-cost node is faster and globally makes the search end -- examined during a search. As such, retrieving the lower-cost node is faster and globally makes the search end
-- up quickly. -- up quickly.
-- --
-- This module is internally used by the library on purpose. -- This module is internally used by the library on purpose.
-- It should normally not be used explicitely, yet it remains fully accessible. -- It should normally not be used explicitely, yet it remains fully accessible.
-- --
@ -23,7 +23,7 @@ if (...) then
-- Dependency -- Dependency
local Utils = require((...):gsub('%.bheap$','.utils')) local Utils = require((...):gsub('%.bheap$','.utils'))
-- Local reference -- Local reference
local floor = math.floor local floor = math.floor
@ -40,7 +40,7 @@ if (...) then
else pIndex = (index-1)/2 else pIndex = (index-1)/2
end end
if not heap._sort(heap._heap[pIndex], heap._heap[index]) then if not heap._sort(heap._heap[pIndex], heap._heap[index]) then
heap._heap[pIndex], heap._heap[index] = heap._heap[pIndex], heap._heap[index] =
heap._heap[index], heap._heap[pIndex] heap._heap[index], heap._heap[pIndex]
percolate_up(heap, pIndex) percolate_up(heap, pIndex)
end end
@ -89,7 +89,7 @@ if (...) then
-- @class function -- @class function
-- @treturn bool __true__ of no item is queued in the heap, __false__ otherwise -- @treturn bool __true__ of no item is queued in the heap, __false__ otherwise
-- @usage -- @usage
-- if myHeap:empty() then -- if myHeap:empty() then
-- print('Heap is empty!') -- print('Heap is empty!')
-- end -- end
function heap:empty() function heap:empty()
@ -129,7 +129,7 @@ if (...) then
-- @class function -- @class function
-- @treturn value a value previously pushed into the heap -- @treturn value a value previously pushed into the heap
-- @usage -- @usage
-- while not myHeap:empty() do -- while not myHeap:empty() do
-- local lowestValue = myHeap:pop() -- local lowestValue = myHeap:pop()
-- ... -- ...
-- end -- end
@ -148,18 +148,18 @@ if (...) then
end end
--- Restores the `heap` property. --- Restores the `heap` property.
-- Reorders the `heap` with respect to the comparison function being used. -- Reorders the `heap` with respect to the comparison function being used.
-- When given argument __item__ (a value existing in the `heap`), will sort from that very item in the `heap`. -- When given argument __item__ (a value existing in the `heap`), will sort from that very item in the `heap`.
-- Otherwise, the whole `heap` will be cheacked. -- Otherwise, the whole `heap` will be cheacked.
-- @class function -- @class function
-- @tparam[opt] value item the modified value -- @tparam[opt] value item the modified value
-- @treturn heap self (the calling `heap` itself, can be chained) -- @treturn heap self (the calling `heap` itself, can be chained)
-- @usage myHeap:heapify() -- @usage myHeap:heapify()
function heap:heapify(item) function heap:heapify(item)
if self._size == 0 then return end if self._size == 0 then return end
if item then if item then
local i = Utils.indexOf(self._heap,item) local i = Utils.indexOf(self._heap,item)
if i then if i then
percolate_down(self, i) percolate_down(self, i)
percolate_up(self, i) percolate_up(self, i)
end end

View File

@ -7,59 +7,26 @@
-- made with regards of their `f` cost. From a given node being examined, the `pathfinder` will expand the search -- made with regards of their `f` cost. From a given node being examined, the `pathfinder` will expand the search
-- to the next neighbouring node having the lowest `f` cost. See `core.bheap` for more details. -- to the next neighbouring node having the lowest `f` cost. See `core.bheap` for more details.
-- --
if (...) then if (...) then
--- The `Node` class.<br/>
-- This class is callable.
-- Therefore,_ <code>Node(...)</code> _acts as a shortcut to_ <code>Node:new(...)</code>.
-- @type Node
local Node = {} local Node = {}
Node.__index = Node Node.__index = Node
--- Inits a new `node`
-- @class function
-- @tparam int x the x-coordinate of the node on the collision map
-- @tparam int y the y-coordinate of the node on the collision map
-- @treturn node a new `node`
-- @usage local node = Node(3,4)
function Node:new(x,y,z) function Node:new(x,y,z)
return setmetatable({_x = x, _y = y, _z = z }, Node) return setmetatable({x = x, y = y, z = z }, Node)
end end
-- Enables the use of operator '<' to compare nodes. -- Enables the use of operator '<' to compare nodes.
-- Will be used to sort a collection of nodes in a binary heap on the basis of their F-cost -- Will be used to sort a collection of nodes in a binary heap on the basis of their F-cost
function Node.__lt(A,B) return (A._f < B._f) end function Node.__lt(A,B) return (A._f < B._f) end
--- Returns x-coordinate of a `node` function Node:getX() return self.x end
-- @class function function Node:getY() return self.y end
-- @treturn number the x-coordinate of the `node` function Node:getZ() return self.z end
-- @usage local x = node:getX()
function Node:getX() return self._x end
--- Returns y-coordinate of a `node`
-- @class function
-- @treturn number the y-coordinate of the `node`
-- @usage local y = node:getY()
function Node:getY() return self._y end
function Node:getZ() return self._z end
--- Returns x and y coordinates of a `node`
-- @class function
-- @treturn number the x-coordinate of the `node`
-- @treturn number the y-coordinate of the `node`
-- @usage local x, y = node:getPos()
function Node:getPos() return self._x, self._y, self._z end
--- Clears temporary cached attributes of a `node`. --- Clears temporary cached attributes of a `node`.
-- Deletes the attributes cached within a given node after a pathfinding call. -- Deletes the attributes cached within a given node after a pathfinding call.
-- This function is internally used by the search algorithms, so you should not use it explicitely. -- This function is internally used by the search algorithms, so you should not use it explicitely.
-- @class function
-- @treturn node self (the calling `node` itself, can be chained)
-- @usage
-- local thisNode = Node(1,2)
-- thisNode:reset()
function Node:reset() function Node:reset()
self._g, self._h, self._f = nil, nil, nil self._g, self._h, self._f = nil, nil, nil
self._opened, self._closed, self._parent = nil, nil, nil self._opened, self._closed, self._parent = nil, nil, nil

View File

@ -7,27 +7,18 @@
-- --
if (...) then if (...) then
--- The `Path` class.<br/>
-- This class is callable. local t_remove = table.remove
-- Therefore, <em><code>Path(...)</code></em> acts as a shortcut to <em><code>Path:new(...)</code></em>.
-- @type Path
local Path = {} local Path = {}
Path.__index = Path Path.__index = Path
--- Inits a new `path`.
-- @class function
-- @treturn path a `path`
-- @usage local p = Path()
function Path:new() function Path:new()
return setmetatable({_nodes = {}}, Path) return setmetatable({_nodes = {}}, Path)
end end
--- Iterates on each single `node` along a `path`. At each step of iteration, --- Iterates on each single `node` along a `path`. At each step of iteration,
-- returns the `node` plus a count value. Aliased as @{Path:nodes} -- returns the `node` plus a count value. Aliased as @{Path:nodes}
-- @class function
-- @treturn node a `node`
-- @treturn int the count for the number of nodes
-- @see Path:nodes
-- @usage -- @usage
-- for node, count in p:iter() do -- for node, count in p:iter() do
-- ... -- ...
@ -42,6 +33,32 @@ if (...) then
end end
end end
--- `Path` compression modifier. Given a `path`, eliminates useless nodes to return a lighter `path`
-- consisting of straight moves. Does the opposite of @{Path:fill}
-- @class function
-- @treturn path self (the calling `path` itself, can be chained)
-- @see Path:fill
-- @usage p:filter()
function Path:filter()
local i = 2
local xi,yi,zi,dx,dy,dz, olddx, olddy, olddz
xi,yi,zi = self._nodes[i].x, self._nodes[i].y, self._nodes[i].z
dx, dy,dz = xi - self._nodes[i-1].x, yi-self._nodes[i-1].y, zi-self._nodes[i-1].z
while true do
olddx, olddy, olddz = dx, dy, dz
if self._nodes[i+1] then
i = i+1
xi, yi, zi = self._nodes[i].x, self._nodes[i].y, self._nodes[i].z
dx, dy, dz = xi - self._nodes[i-1].x, yi - self._nodes[i-1].y, zi - self._nodes[i-1].z
if olddx == dx and olddy == dy and olddz == dz then
t_remove(self._nodes, i-1)
i = i - 1
end
else break end
end
return self
end
return setmetatable(Path, return setmetatable(Path,
{__call = function(_,...) {__call = function(_,...)
return Path:new(...) return Path:new(...)

View File

@ -25,18 +25,9 @@ if (...) then
{x = 0, y = 0, z = 1} --[[U]], {x = 0, y = -0, z = -1}, --[[D]] {x = 0, y = 0, z = 1} --[[U]], {x = 0, y = -0, z = -1}, --[[D]]
} }
--- The `Grid` class.<br/>
-- This class is callable.
-- Therefore,_ <code>Grid(...)</code> _acts as a shortcut to_ <code>Grid:new(...)</code>.
-- @type Grid
local Grid = {} local Grid = {}
Grid.__index = Grid Grid.__index = Grid
--- Inits a new `grid`
-- @class function
-- @tparam table Map dimensions
-- or a `string` with line-break chars (<code>\n</code> or <code>\r</code>) as row delimiters.
-- @treturn grid a new `grid` instance
function Grid:new(dim) function Grid:new(dim)
local newGrid = { } local newGrid = { }
newGrid._min_x, newGrid._max_x = dim.x, dim.ex newGrid._min_x, newGrid._max_x = dim.x, dim.ex
@ -49,73 +40,38 @@ if (...) then
return setmetatable(newGrid,Grid) return setmetatable(newGrid,Grid)
end end
--- Checks if `node` at [x,y] is __walkable__.
-- Will check if `node` at location [x,y] both *exists* on the collision map and *is walkable*
-- @class function
-- @tparam int x the x-location of the node
-- @tparam int y the y-location of the node
-- @tparam int z the z-location of the node
--
function Grid:isWalkableAt(x, y, z) function Grid:isWalkableAt(x, y, z)
local node = self:getNodeAt(x,y,z) local node = self:getNodeAt(x,y,z)
return node and node.walkable ~= 1 return node and node.walkable ~= 1
end end
--- Returns the `grid` width.
-- @class function
-- @treturn int the `grid` width
-- @usage print(myGrid:getWidth())
function Grid:getWidth() function Grid:getWidth()
return self._width return self._width
end end
--- Returns the `grid` height.
-- @class function
-- @treturn int the `grid` height
-- @usage print(myGrid:getHeight())
function Grid:getHeight() function Grid:getHeight()
return self._height return self._height
end end
--- Returns the set of nodes.
-- @class function
-- @treturn {{node,...},...} an array of nodes
-- @usage local nodes = myGrid:getNodes()
function Grid:getNodes() function Grid:getNodes()
return self._nodes return self._nodes
end end
--- Returns the `grid` bounds. Returned values corresponds to the upper-left
-- and lower-right coordinates (in tile units) of the actual `grid` instance.
-- @class function
-- @treturn int the upper-left corner x-coordinate
-- @treturn int the upper-left corner y-coordinate
-- @treturn int the lower-right corner x-coordinate
-- @treturn int the lower-right corner y-coordinate
-- @usage local left_x, left_y, right_x, right_y = myGrid:getBounds()
function Grid:getBounds() function Grid:getBounds()
return self._min_x, self._min_y, self._min_z, self._max_x, self._max_y, self._max_z return self._min_x, self._min_y, self._min_z, self._max_x, self._max_y, self._max_z
end end
--- Returns neighbours. The returned value is an array of __walkable__ nodes neighbouring a given `node`. --- Returns neighbours. The returned value is an array of __walkable__ nodes neighbouring a given `node`.
-- @class function
-- @tparam node node a given `node`
-- @tparam[opt] string|int|func walkable the value for walkable locations
-- in the collision map array (see @{Grid:new}).
-- Defaults to __false__ when omitted.
-- @treturn {node,...} an array of nodes neighbouring a given node -- @treturn {node,...} an array of nodes neighbouring a given node
-- @usage
-- local aNode = myGrid:getNodeAt(5,6)
-- local neighbours = myGrid:getNeighbours(aNode, 0, true)
function Grid:getNeighbours(node) function Grid:getNeighbours(node)
local neighbours = {} local neighbours = {}
for i = 1,#straightOffsets do for i = 1,#straightOffsets do
local n = self:getNodeAt( local n = self:getNodeAt(
node._x + straightOffsets[i].x, node.x + straightOffsets[i].x,
node._y + straightOffsets[i].y, node.y + straightOffsets[i].y,
node._z + straightOffsets[i].z node.z + straightOffsets[i].z
) )
if n and self:isWalkableAt(n._x, n._y, n._z) then if n and self:isWalkableAt(n.x, n.y, n.z) then
neighbours[#neighbours+1] = n neighbours[#neighbours+1] = n
end end
end end
@ -123,17 +79,7 @@ if (...) then
return neighbours return neighbours
end end
--- Returns the `node` at location [x,y,z]. function Grid:getNodeAt(x,y,z)
-- @class function
-- @name Grid:getNodeAt
-- @tparam int x the x-coordinate coordinate
-- @tparam int y the y-coordinate coordinate
-- @tparam int z the z-coordinate coordinate
-- @treturn node a `node`
-- @usage local aNode = myGrid:getNodeAt(2,2)
-- Gets the node at location <x,y> on a preprocessed grid
function Grid:getNodeAt(x,y,z)
if not x or not y or not z then return end if not x or not y or not z then return end
if Utils.outOfRange(x,self._min_x,self._max_x) then return end if Utils.outOfRange(x,self._min_x,self._max_x) then return end
if Utils.outOfRange(y,self._min_y,self._max_y) then return end if Utils.outOfRange(y,self._min_y,self._max_y) then return end

View File

@ -28,11 +28,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
--]] --]]
--- The Pathfinder class
--
-- Implementation of the `pathfinder` class.
local _VERSION = "" local _VERSION = ""
local _RELEASEDATE = "" local _RELEASEDATE = ""
@ -49,8 +44,6 @@ if (...) then
--- Finders (search algorithms implemented). Refers to the search algorithms actually implemented in Jumper. --- Finders (search algorithms implemented). Refers to the search algorithms actually implemented in Jumper.
-- <li>[A*](http://en.wikipedia.org/wiki/A*_search_algorithm)</li> -- <li>[A*](http://en.wikipedia.org/wiki/A*_search_algorithm)</li>
-- @finder Finders
-- @see Pathfinder:getFinders
local Finders = { local Finders = {
['ASTAR'] = require (_PATH .. '.search.astar'), ['ASTAR'] = require (_PATH .. '.search.astar'),
} }
@ -62,21 +55,9 @@ if (...) then
-- Performs a traceback from the goal node to the start node -- Performs a traceback from the goal node to the start node
-- Only happens when the path was found -- Only happens when the path was found
--- The `Pathfinder` class.<br/>
-- This class is callable.
-- Therefore,_ <code>Pathfinder(...)</code> _acts as a shortcut to_ <code>Pathfinder:new(...)</code>.
-- @type Pathfinder
local Pathfinder = {} local Pathfinder = {}
Pathfinder.__index = Pathfinder Pathfinder.__index = Pathfinder
--- Inits a new `pathfinder`
-- @class function
-- @tparam grid grid a `grid`
-- @tparam[opt] string finderName the name of the `Finder` (search algorithm) to be used for search.
-- Defaults to `ASTAR` when not given (see @{Pathfinder:getFinders}).
-- @treturn pathfinder a new `pathfinder` instance
-- @usage
-- local finder = Pathfinder:new(myGrid, 'ASTAR')
function Pathfinder:new(heuristic) function Pathfinder:new(heuristic)
local newPathfinder = {} local newPathfinder = {}
setmetatable(newPathfinder, Pathfinder) setmetatable(newPathfinder, Pathfinder)
@ -85,23 +66,13 @@ if (...) then
return newPathfinder return newPathfinder
end end
--- Sets the `grid`. Defines the given `grid` as the one on which the `pathfinder` will perform the search.
-- @class function
-- @tparam grid grid a `grid`
-- @treturn pathfinder self (the calling `pathfinder` itself, can be chained)
-- @usage myFinder:setGrid(myGrid)
function Pathfinder:setGrid(grid) function Pathfinder:setGrid(grid)
self._grid = grid self._grid = grid
return self return self
end end
--- Calculates a `path`. Returns the `path` from location __[startX, startY]__ to location __[endX, endY]__. --- Calculates a `path`. Returns the `path` from start to end location
-- Both locations must exist on the collision map. The starting location can be unwalkable. -- Both locations must exist on the collision map. The starting location can be unwalkable.
-- @class function
-- @tparam int startX the x-coordinate for the starting location
-- @tparam int startY the y-coordinate for the starting location
-- @tparam int endX the x-coordinate for the goal location
-- @tparam int endY the y-coordinate for the goal location
-- @treturn path a path (array of nodes) when found, otherwise nil -- @treturn path a path (array of nodes) when found, otherwise nil
-- @usage local path = myFinder:getPath(1,1,5,5) -- @usage local path = myFinder:getPath(1,1,5,5)
function Pathfinder:getPath(startX, startY, startZ, ih, endX, endY, endZ, oh) function Pathfinder:getPath(startX, startY, startZ, ih, endX, endY, endZ, oh)
@ -112,8 +83,8 @@ if (...) then
return nil return nil
end end
startNode._heading = ih startNode.heading = ih
endNode._heading = oh endNode.heading = oh
assert(startNode, ('Invalid location [%d, %d, %d]'):format(startX, startY, startZ)) assert(startNode, ('Invalid location [%d, %d, %d]'):format(startX, startY, startZ))
assert(endNode and self._grid:isWalkableAt(endX, endY, endZ), assert(endNode and self._grid:isWalkableAt(endX, endY, endZ),

View File

@ -18,7 +18,7 @@ if (...) then
if node._g + mCost < neighbour._g then if node._g + mCost < neighbour._g then
neighbour._parent = node neighbour._parent = node
neighbour._g = node._g + mCost neighbour._g = node._g + mCost
neighbour._heading = heading neighbour.heading = heading
end end
end end
@ -64,10 +64,10 @@ if (...) then
end end
--[[ --[[
printf('x:%d y:%d z:%d g:%d', node._x, node._y, node._z, node._g) printf('x:%d y:%d z:%d g:%d', node.x, node.y, node.z, node._g)
for i = 1,#neighbours do for i = 1,#neighbours do
local n = neighbours[i] local n = neighbours[i]
printf('x:%d y:%d z:%d f:%f g:%f h:%d', n._x, n._y, n._z, n._f, n._g, n._heading or -1) printf('x:%d y:%d z:%d f:%f g:%f h:%d', n.x, n.y, n.z, n._f, n._g, n.heading or -1)
end end
--]] --]]

View File

@ -2,6 +2,40 @@ local Util = require('util')
local Point = { } local Point = { }
Point.facings = {
[ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' },
[ 1 ] = { xd = 0, zd = 1, yd = 0, heading = 1, direction = 'south' },
[ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' },
[ 3 ] = { xd = 0, zd = -1, yd = 0, heading = 3, direction = 'north' },
}
Point.directions = {
[ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' },
[ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' },
}
Point.headings = {
[ 0 ] = Point.facings[0],
[ 1 ] = Point.facings[1],
[ 2 ] = Point.facings[2],
[ 3 ] = Point.facings[3],
[ 4 ] = Point.directions[4],
[ 5 ] = Point.directions[5],
east = Point.facings[0],
south = Point.facings[1],
west = Point.facings[2],
north = Point.facings[3],
up = Point.directions[4],
down = Point.directions[5],
}
Point.EAST = 0
Point.SOUTH = 1
Point.WEST = 2
Point.NORTH = 3
Point.UP = 4
Point.DOWN = 5
function Point.copy(pt) function Point.copy(pt)
return { x = pt.x, y = pt.y, z = pt.z } return { x = pt.x, y = pt.y, z = pt.z }
end end
@ -122,6 +156,10 @@ end
-- given a set of points, find the one taking the least moves -- given a set of points, find the one taking the least moves
function Point.closest(reference, pts) function Point.closest(reference, pts)
if #pts == 1 then
return pts[1]
end
local lpt, lm -- lowest local lpt, lm -- lowest
for _,pt in pairs(pts) do for _,pt in pairs(pts) do
local m = Point.calculateMoves(reference, pt) local m = Point.calculateMoves(reference, pt)
@ -148,21 +186,87 @@ end
function Point.adjacentPoints(pt) function Point.adjacentPoints(pt)
local pts = { } local pts = { }
local headings = { for i = 0, 5 do
[ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' }, local hi = Point.headings[i]
[ 1 ] = { xd = 0, zd = 1, yd = 0, heading = 1, direction = 'south' },
[ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' },
[ 3 ] = { xd = 0, zd = -1, yd = 0, heading = 3, direction = 'north' },
[ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' },
[ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' }
}
for _, hi in pairs(headings) do
table.insert(pts, { x = pt.x + hi.xd, y = pt.y + hi.yd, z = pt.z + hi.zd }) table.insert(pts, { x = pt.x + hi.xd, y = pt.y + hi.yd, z = pt.z + hi.zd })
end end
return pts return pts
end end
-- get the point nearest A that is in the direction of B
function Point.nearestTo(pta, ptb)
local heading
if pta.x < ptb.x then
heading = 0
elseif pta.z < ptb.z then
heading = 1
elseif pta.x > ptb.x then
heading = 2
elseif pta.z > ptb.z then
heading = 3
elseif pta.y < ptb.y then
heading = 4
elseif pta.y > ptb.y then
heading = 5
end
if heading then
return {
x = pta.x + Point.headings[heading].xd,
y = pta.y + Point.headings[heading].yd,
z = pta.z + Point.headings[heading].zd,
}
end
return pta -- error ?
end
function Point.rotate(pt, facing)
local x, z = pt.x, pt.z
if facing == 1 then
pt.x = z
pt.z = -x
elseif facing == 2 then
pt.x = -x
pt.z = -z
elseif facing == 3 then
pt.x = -z
pt.z = x
end
end
function Point.makeBox(pt1, pt2)
return {
x = pt1.x,
y = pt1.y,
z = pt1.z,
ex = pt2.x,
ey = pt2.y,
ez = pt2.z,
}
end
-- expand box to include point
function Point.expandBox(box, pt)
if pt.x < box.x then
box.x = pt.x
elseif pt.x > box.ex then
box.ex = pt.x
end
if pt.y < box.y then
box.y = pt.y
elseif pt.y > box.ey then
box.ey = pt.y
end
if pt.z < box.z then
box.z = pt.z
elseif pt.z > box.ez then
box.ez = pt.z
end
end
function Point.normalizeBox(box) function Point.normalizeBox(box)
return { return {
x = math.min(box.x, box.ex), x = math.min(box.x, box.ex),
@ -183,20 +287,6 @@ function Point.inBox(pt, box)
pt.z <= box.ez pt.z <= box.ez
end end
function Point.rotate(pt, facing)
local x, z = pt.x, pt.z
if facing == 1 then
pt.x = z
pt.z = -x
elseif facing == 2 then
pt.x = -x
pt.z = -z
elseif facing == 3 then
pt.x = -z
pt.z = x
end
end
return Point return Point
--[[ --[[

View File

@ -1,7 +1,7 @@
_G.requireInjector() _G.requireInjector()
local Grid = require ("jumper.grid") local Grid = require('jumper.grid')
local Pathfinder = require ("jumper.pathfinder") local Pathfinder = require('jumper.pathfinder')
local Point = require('point') local Point = require('point')
local Util = require('util') local Util = require('util')
@ -19,74 +19,46 @@ end
-- map shrinks/grows depending upon blocks encountered -- map shrinks/grows depending upon blocks encountered
-- the map will encompass any blocks encountered, the turtle position, and the destination -- the map will encompass any blocks encountered, the turtle position, and the destination
local function mapDimensions(dest, blocks, boundingBox, dests) local function mapDimensions(dest, blocks, boundingBox, dests)
local sx, sz, sy = turtle.point.x, turtle.point.z, turtle.point.y local box = Point.makeBox(turtle.point, turtle.point)
local ex, ez, ey = turtle.point.x, turtle.point.z, turtle.point.y
local function adjust(pt) Point.expandBox(box, dest)
if pt.x < sx then
sx = pt.x
elseif pt.x > ex then
ex = pt.x
end
if pt.y < sy then
sy = pt.y
elseif pt.y > ey then
ey = pt.y
end
if pt.z < sz then
sz = pt.z
elseif pt.z > ez then
ez = pt.z
end
end
adjust(dest)
for _,d in pairs(dests) do for _,d in pairs(dests) do
adjust(d) Point.expandBox(box, d)
end end
for _,b in pairs(blocks) do for _,b in pairs(blocks) do
adjust(b) Point.expandBox(box, b)
end end
-- expand one block out in all directions -- expand one block out in all directions
if boundingBox then if boundingBox then
sx = math.max(sx - 1, boundingBox.x) box.x = math.max(box.x - 1, boundingBox.x)
sz = math.max(sz - 1, boundingBox.z) box.z = math.max(box.z - 1, boundingBox.z)
sy = math.max(sy - 1, boundingBox.y) box.y = math.max(box.y - 1, boundingBox.y)
ex = math.min(ex + 1, boundingBox.ex) box.ex = math.min(box.ex + 1, boundingBox.ex)
ez = math.min(ez + 1, boundingBox.ez) box.ez = math.min(box.ez + 1, boundingBox.ez)
ey = math.min(ey + 1, boundingBox.ey) box.ey = math.min(box.ey + 1, boundingBox.ey)
else else
sx = sx - 1 box.x = box.x - 1
sz = sz - 1 box.z = box.z - 1
sy = sy - 1 box.y = box.y - 1
ex = ex + 1 box.ex = box.ex + 1
ez = ez + 1 box.ez = box.ez + 1
ey = ey + 1 box.ey = box.ey + 1
end end
return { return box
ex = ex,
ez = ez,
ey = ey,
x = sx,
z = sz,
y = sy
}
end end
local function nodeToPoint(node) local function nodeToPoint(node)
return { x = node:getX(), z = node:getZ(), y = node:getY() } return { x = node.x, y = node.y, z = node.z, heading = node.heading }
end end
local heuristic = function(n, node) local function heuristic(n, node)
local m, h = Point.calculateMoves( return Point.calculateMoves(node, n)
{ x = node._x, y = node._y, z = node._z, heading = node._heading }, -- { x = node.x, y = node.y, z = node.z, heading = node.heading },
{ x = n._x, y = n._y, z = n._z, heading = n._heading }) -- { x = n.x, y = n.y, z = n.z, heading = n.heading })
return m, h
end end
local function dimsAreEqual(d1, d2) local function dimsAreEqual(d1, d2)
@ -123,9 +95,6 @@ local function addSensorBlocks(blocks, sblocks)
end end
local function selectDestination(pts, box, grid) local function selectDestination(pts, box, grid)
if #pts == 1 then
return pts[1]
end
while #pts > 0 do while #pts > 0 do
local pt = Point.closest(turtle.point, pts) local pt = Point.closest(turtle.point, pts)
if box and not Point.inBox(pt, box) then if box and not Point.inBox(pt, box) then
@ -143,16 +112,15 @@ local function pathTo(dest, options)
local blocks = options.blocks or turtle.getState().blocks or { } local blocks = options.blocks or turtle.getState().blocks or { }
local dests = options.dest or { dest } -- support alternative destinations local dests = options.dest or { dest } -- support alternative destinations
local box = options.box or turtle.getState().box local box = options.box or turtle.getState().box
local lastDim
local lastDim = nil local grid
local grid = nil
if box then if box then
box = Point.normalizeBox(box) box = Point.normalizeBox(box)
end end
-- Creates a pathfinder object -- Creates a pathfinder object
local myFinder = Pathfinder(heuristic) local finder = Pathfinder(heuristic)
while turtle.point.x ~= dest.x or turtle.point.z ~= dest.z or turtle.point.y ~= dest.y do while turtle.point.x ~= dest.x or turtle.point.z ~= dest.z or turtle.point.y ~= dest.y do
@ -163,7 +131,7 @@ local function pathTo(dest, options)
if not lastDim or not dimsAreEqual(dim, lastDim) then if not lastDim or not dimsAreEqual(dim, lastDim) then
-- Creates a grid object -- Creates a grid object
grid = Grid(dim) grid = Grid(dim)
myFinder:setGrid(grid) finder:setGrid(grid)
lastDim = dim lastDim = dim
end end
@ -173,7 +141,6 @@ local function pathTo(dest, options)
dest = selectDestination(dests, box, grid) dest = selectDestination(dests, box, grid)
if not dest then if not dest then
-- error('failed to reach destination')
return false, 'failed to reach destination' return false, 'failed to reach destination'
end end
if turtle.point.x == dest.x and turtle.point.z == dest.z and turtle.point.y == dest.y then if turtle.point.x == dest.x and turtle.point.z == dest.z and turtle.point.y == dest.y then
@ -185,24 +152,44 @@ local function pathTo(dest, options)
local endPt = dest local endPt = dest
-- Calculates the path, and its length -- Calculates the path, and its length
local path = myFinder:getPath( local path = finder:getPath(
startPt.x, startPt.y, startPt.z, turtle.point.heading, startPt.x, startPt.y, startPt.z, turtle.point.heading,
endPt.x, endPt.y, endPt.z, dest.heading) endPt.x, endPt.y, endPt.z, dest.heading)
if not path then if not path then
Util.removeByValue(dests, dest) Util.removeByValue(dests, dest)
else else
path:filter()
for node in path:nodes() do for node in path:nodes() do
local pt = nodeToPoint(node) local pt = nodeToPoint(node)
if turtle.abort then if turtle.isAborted() then
return false, 'aborted' return false, 'aborted'
end end
--if this is the next to last node
--and we are traveling up or down, then the
--heading for this node should be the heading of the last node
--or, maybe..
--if last node is up or down (or either?)
-- use single turn method so the turtle doesn't turn around -- use single turn method so the turtle doesn't turn around
-- when encountering obstacles -- IS THIS RIGHT ?? -- when encountering obstacles
if not turtle.gotoSingleTurn(pt.x, pt.z, pt.y) then if not turtle.gotoSingleTurn(pt.x, pt.z, pt.y, pt.heading) then
table.insert(blocks, pt) local bpt = Point.nearestTo(turtle.point, pt)
table.insert(blocks, bpt)
-- really need to check if the block we ran into was a turtle.
-- if so, this block should be temporary (1-2 secs)
--local side = turtle.getSide(turtle.point, pt)
--if turtle.isTurtleAtSide(side) then
-- pt.timestamp = os.clock() + ?
--end
-- if dim has not changed, then need to update grid with
-- walkable = nil (after time has elapsed)
--if device.turtlesensorenvironment then --if device.turtlesensorenvironment then
-- addSensorBlocks(blocks, device.turtlesensorenvironment.sonicScan()) -- addSensorBlocks(blocks, device.turtlesensorenvironment.sonicScan())
--end --end

View File

@ -3085,6 +3085,9 @@ function UI.Dialog:setParent()
if not self.width then if not self.width then
self.width = self.parent.width - 11 self.width = self.parent.width - 11
end end
if self.width > self.parent.width then
self.width = self.parent.width
end
self.x = math.floor((self.parent.width - self.width) / 2) + 1 self.x = math.floor((self.parent.width - self.width) / 2) + 1
self.y = math.floor((self.parent.height - self.height) / 2) + 1 self.y = math.floor((self.parent.height - self.height) / 2) + 1
UI.Page.setParent(self) UI.Page.setParent(self)

View File

@ -1,60 +0,0 @@
local turtle = _G.turtle
if not turtle or turtle.enableGPS then
return
end
_G.requireInjector()
local GPS = require('gps')
local Config = require('config')
function turtle.enableGPS(timeout)
if turtle.point.gps then
return turtle.point
end
local pt = GPS.getPointAndHeading(timeout)
if pt then
turtle.setPoint(pt, true)
return turtle.point
end
end
function turtle.gotoGPSHome()
local config = { }
Config.load('gps', config)
if config.home then
if turtle.enableGPS() then
turtle.pathfind(config.home)
end
end
end
function turtle.setGPSHome()
local config = { }
Config.load('gps', config)
if turtle.point.gps then
config.home = turtle.point
Config.update('gps', config)
else
local pt = GPS.getPoint()
if pt then
local originalHeading = turtle.point.heading
local heading = GPS.getHeading()
if heading then
local turns = (turtle.point.heading - originalHeading) % 4
pt.heading = (heading - turns) % 4
config.home = pt
Config.update('gps', config)
pt = GPS.getPoint()
pt.heading = heading
turtle.setPoint(pt, true)
turtle.gotoPoint(config.home)
end
end
end
end

View File

@ -1,8 +1,4 @@
local os = _G.os if not _G.turtle then
local peripheral = _G.peripheral
local turtle = _G.turtle
if not turtle or turtle.getPoint then
return return
end end
@ -13,16 +9,25 @@ local synchronized = require('sync')
local Util = require('util') local Util = require('util')
local Pathing = require('turtle.pathfind') local Pathing = require('turtle.pathfind')
local os = _G.os
local peripheral = _G.peripheral
local turtle = _G.turtle
local function noop() end local function noop() end
local headings = Point.headings
local state = {
status = 'idle',
abort = false,
}
turtle.pathfind = Pathing.pathfind turtle.pathfind = Pathing.pathfind
turtle.point = { x = 0, y = 0, z = 0, heading = 0 } turtle.point = { x = 0, y = 0, z = 0, heading = 0 }
turtle.status = 'idle'
turtle.abort = false
local state = { }
function turtle.getPoint() return turtle.point end function turtle.getPoint() return turtle.point end
function turtle.getState() return state end function turtle.getState() return state end
function turtle.isAborted() return state.abort end
function turtle.getStatus() return state.status end
function turtle.setStatus(s) state.status = s end
local function _defaultMove(action) local function _defaultMove(action)
while not action.move() do while not action.move() do
@ -45,15 +50,13 @@ function turtle.setPoint(pt, isGPS)
end end
function turtle.resetState() function turtle.resetState()
--turtle.abort = false -- should be part of state state.abort = false
--turtle.status = 'idle' -- should be part of state state.status = 'idle'
state.attackPolicy = noop state.attackPolicy = noop
state.digPolicy = noop state.digPolicy = noop
state.movePolicy = _defaultMove state.movePolicy = _defaultMove
state.moveCallback = noop state.moveCallback = noop
Pathing.reset() Pathing.reset()
turtle.abort = false
return true return true
end end
@ -63,11 +66,8 @@ function turtle.reset()
turtle.point.z = 0 turtle.point.z = 0
turtle.point.heading = 0 -- should be facing turtle.point.heading = 0 -- should be facing
turtle.point.gps = false turtle.point.gps = false
turtle.abort = false -- should be part of state
--turtle.status = 'idle' -- should be part of state
turtle.resetState() turtle.resetState()
return true return true
end end
@ -126,31 +126,7 @@ function turtle.getAction(direction)
return actions[direction] return actions[direction]
end end
-- [[ Heading data ]] --
local headings = {
[ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' },
[ 1 ] = { xd = 0, zd = 1, yd = 0, heading = 1, direction = 'south' },
[ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' },
[ 3 ] = { xd = 0, zd = -1, yd = 0, heading = 3, direction = 'north' },
[ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' },
[ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' }
}
local namedHeadings = {
east = headings[0],
south = headings[1],
west = headings[2],
north = headings[3],
up = headings[4],
down = headings[5]
}
function turtle.getHeadings() return headings end
function turtle.getHeadingInfo(heading) function turtle.getHeadingInfo(heading)
if heading and type(heading) == 'string' then
return namedHeadings[heading]
end
heading = heading or turtle.point.heading heading = heading or turtle.point.heading
return headings[heading] return headings[heading]
end end
@ -307,13 +283,13 @@ turtle.movePolicies = {
if action.side == 'back' then if action.side == 'back' then
return false return false
end end
local oldStatus = turtle.status local oldStatus = state.status
print('assured move: stuck') print('assured move: stuck')
turtle.status = 'stuck' state.status = 'stuck'
repeat repeat
os.sleep(1) os.sleep(1)
until _defaultMove(action) until _defaultMove(action)
turtle.status = oldStatus state.status = oldStatus
end end
return true return true
end, end,
@ -381,18 +357,17 @@ function turtle.turnAround()
return turtle.point return turtle.point
end end
-- combine with setHeading
function turtle.setNamedHeading(headingName)
local headingInfo = namedHeadings[headingName]
if headingInfo then
return turtle.setHeading(headingInfo.heading)
end
return false, 'Invalid heading'
end
function turtle.setHeading(heading) function turtle.setHeading(heading)
if not heading then if not heading then
return return false, 'Invalid heading'
end
if type(heading) == 'string' then
local hi = headings[heading]
if not hi then
return false, 'Invalid heading'
end
heading = hi.heading
end end
heading = heading % 4 heading = heading % 4
@ -484,7 +459,6 @@ function turtle.back()
end end
function turtle.moveTowardsX(dx) function turtle.moveTowardsX(dx)
local direction = dx - turtle.point.x local direction = dx - turtle.point.x
local move local move
@ -508,7 +482,6 @@ function turtle.moveTowardsX(dx)
end end
function turtle.moveTowardsZ(dz) function turtle.moveTowardsZ(dz)
local direction = dz - turtle.point.z local direction = dz - turtle.point.z
local move local move
@ -534,7 +507,6 @@ end
-- [[ go ]] -- -- [[ go ]] --
-- 1 turn goto (going backwards if possible) -- 1 turn goto (going backwards if possible)
function turtle.gotoSingleTurn(dx, dz, dy, dh) function turtle.gotoSingleTurn(dx, dz, dy, dh)
dy = dy or turtle.point.y dy = dy or turtle.point.y
local function gx() local function gx()
@ -593,7 +565,6 @@ function turtle.gotoSingleTurn(dx, dz, dy, dh)
end end
local function gotoEx(dx, dz, dy) local function gotoEx(dx, dz, dy)
-- determine the heading to ensure the least amount of turns -- determine the heading to ensure the least amount of turns
-- first check is 1 turn needed - remaining require 2 turns -- first check is 1 turn needed - remaining require 2 turns
if turtle.point.heading == 0 and turtle.point.x <= dx or if turtle.point.heading == 0 and turtle.point.x <= dx or
@ -628,7 +599,6 @@ end
-- fallback goto - will turn around if was previously moving backwards -- fallback goto - will turn around if was previously moving backwards
local function gotoMultiTurn(dx, dz, dy) local function gotoMultiTurn(dx, dz, dy)
if gotoEx(dx, dz, dy) then if gotoEx(dx, dz, dy) then
return true return true
end end
@ -659,18 +629,18 @@ local function gotoMultiTurn(dx, dz, dy)
end end
function turtle.gotoPoint(pt) function turtle.gotoPoint(pt)
return turtle.goto(pt.x, pt.z, pt.y, pt.heading) return turtle._goto(pt.x, pt.z, pt.y, pt.heading)
end end
-- go backwards - turning around if necessary to fight mobs / break blocks -- go backwards - turning around if necessary to fight mobs / break blocks
function turtle.goback() function turtle.goback()
local hi = headings[turtle.point.heading] local hi = headings[turtle.point.heading]
return turtle.goto(turtle.point.x - hi.xd, turtle.point.z - hi.zd, turtle.point.y, turtle.point.heading) return turtle._goto(turtle.point.x - hi.xd, turtle.point.z - hi.zd, turtle.point.y, turtle.point.heading)
end end
function turtle.gotoYfirst(pt) function turtle.gotoYfirst(pt)
if turtle.gotoY(pt.y) then if turtle._gotoY(pt.y) then
if turtle.goto(pt.x, pt.z, nil, pt.heading) then if turtle._goto(pt.x, pt.z, nil, pt.heading) then
turtle.setHeading(pt.heading) turtle.setHeading(pt.heading)
return true return true
end end
@ -678,7 +648,7 @@ function turtle.gotoYfirst(pt)
end end
function turtle.gotoYlast(pt) function turtle.gotoYlast(pt)
if turtle.goto(pt.x, pt.z, nil, pt.heading) then if turtle._goto(pt.x, pt.z, nil, pt.heading) then
if turtle.gotoY(pt.y) then if turtle.gotoY(pt.y) then
turtle.setHeading(pt.heading) turtle.setHeading(pt.heading)
return true return true
@ -686,7 +656,7 @@ function turtle.gotoYlast(pt)
end end
end end
function turtle.goto(dx, dz, dy, dh) function turtle._goto(dx, dz, dy, dh)
if not turtle.gotoSingleTurn(dx, dz, dy, dh) then if not turtle.gotoSingleTurn(dx, dz, dy, dh) then
if not gotoMultiTurn(dx, dz, dy) then if not gotoMultiTurn(dx, dz, dy) then
return false return false
@ -697,7 +667,7 @@ function turtle.goto(dx, dz, dy, dh)
end end
-- avoid lint errors -- avoid lint errors
turtle._goto = turtle.goto turtle['goto'] = turtle._goto
function turtle.gotoX(dx) function turtle.gotoX(dx)
turtle.headTowardsX(dx) turtle.headTowardsX(dx)
@ -738,7 +708,6 @@ end
-- [[ Slot management ]] -- -- [[ Slot management ]] --
function turtle.getSlot(indexOrId, slots) function turtle.getSlot(indexOrId, slots)
if type(indexOrId) == 'string' then if type(indexOrId) == 'string' then
slots = slots or turtle.getInventory() slots = slots or turtle.getInventory()
local _,c = string.gsub(indexOrId, ':', '') local _,c = string.gsub(indexOrId, ':', '')
@ -774,7 +743,6 @@ function turtle.getSlot(indexOrId, slots)
end end
function turtle.select(indexOrId) function turtle.select(indexOrId)
if type(indexOrId) == 'number' then if type(indexOrId) == 'number' then
return turtle.native.select(indexOrId) return turtle.native.select(indexOrId)
end end
@ -925,7 +893,6 @@ function turtle.getItemCount(idOrName)
end end
function turtle.equip(side, item) function turtle.equip(side, item)
if item then if item then
if not turtle.select(item) then if not turtle.select(item) then
return false, 'Unable to equip ' .. item return false, 'Unable to equip ' .. item
@ -938,6 +905,7 @@ function turtle.equip(side, item)
return turtle.equipRight() return turtle.equipRight()
end end
-- [[ ]] --
function turtle.run(fn, ...) function turtle.run(fn, ...)
local args = { ... } local args = { ... }
local s, m local s, m
@ -947,25 +915,22 @@ function turtle.run(fn, ...)
end end
synchronized(turtle, function() synchronized(turtle, function()
turtle.abort = false
turtle.status = 'busy'
turtle.resetState() turtle.resetState()
s, m = pcall(function() fn(unpack(args)) end) s, m = pcall(function() fn(unpack(args)) end)
turtle.abort = false turtle.resetState()
turtle.status = 'idle'
if not s and m then if not s and m then
printError(m) _G.printError(m)
end end
end) end)
return s, m return s, m
end end
function turtle.abortAction() function turtle.abort(abort)
--if turtle.status ~= 'idle' then state.abort = abort
turtle.abort = true if abort then
os.queueEvent('turtle_abort') os.queueEvent('turtle_abort')
--end end
end end
-- [[ Pathing ]] -- -- [[ Pathing ]] --
@ -989,9 +954,7 @@ function turtle.faceAgainst(pt, options) -- 4 sided
options = options or { } options = options or { }
options.dest = { } options.dest = { }
for i = 0, 3 do for hi in pairs(Point.facings) do
local hi = turtle.getHeadingInfo(i)
table.insert(options.dest, { table.insert(options.dest, {
x = pt.x + hi.xd, x = pt.x + hi.xd,
z = pt.z + hi.zd, z = pt.z + hi.zd,
@ -1104,10 +1067,14 @@ local function _actionUpAt(action, pt, ...)
end end
end end
local function _actionXXXAt(action, pt, dir, ...) local function _actionPlaceAt(action, pt, name, dir, facing)
local reversed = if not dir then
return _actionAt(action, pt, name)
end
local reversed =
{ [0] = 2, [1] = 3, [2] = 0, [3] = 1, [4] = 5, [5] = 4, } { [0] = 2, [1] = 3, [2] = 0, [3] = 1, [4] = 5, [5] = 4, }
dir = reversed[dir] dir = reversed[headings[dir].heading]
local apt = { x = pt.x + headings[dir].xd, local apt = { x = pt.x + headings[dir].xd,
y = pt.y + headings[dir].yd, y = pt.y + headings[dir].yd,
z = pt.z + headings[dir].zd, } z = pt.z + headings[dir].zd, }
@ -1118,55 +1085,108 @@ local function _actionXXXAt(action, pt, dir, ...)
apt.heading = (dir + 2) % 4 apt.heading = (dir + 2) % 4
direction = 'forward' direction = 'forward'
elseif dir == 4 then elseif dir == 4 then
apt.heading = pt.heading apt.heading = facing
direction = 'down' direction = 'down'
elseif dir == 5 then elseif dir == 5 then
apt.heading = pt.heading apt.heading = facing
direction = 'up' direction = 'up'
end end
if turtle.pathfind(apt) then if turtle.pathfind(apt) then
return action[direction](...) return action[direction](name)
end end
end end
function turtle.detectAt(pt) return _actionAt(actionsAt.detect, pt) end function turtle.detectAt(pt) return _actionAt(actionsAt.detect, pt) end
function turtle.detectDownAt(pt) return _actionDownAt(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.detectForwardAt(pt) return _actionForwardAt(actionsAt.detect, pt) end
function turtle.detectUpAt(pt) return _actionUpAt(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.digAt(pt) return _actionAt(actionsAt.dig, pt) end
function turtle.digDownAt(pt) return _actionDownAt(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.digForwardAt(pt) return _actionForwardAt(actionsAt.dig, pt) end
function turtle.digUpAt(pt) return _actionUpAt(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.attackAt(pt) return _actionAt(actionsAt.attack, pt) end
function turtle.attackDownAt(pt) return _actionDownAt(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.attackForwardAt(pt) return _actionForwardAt(actionsAt.attack, pt) end
function turtle.attackUpAt(pt) return _actionUpAt(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.placeAt(pt, arg, dir) return _actionPlaceAt(actionsAt.place, pt, arg, dir) end
function turtle.placeDownAt(pt, arg) return _actionDownAt(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.placeForwardAt(pt, arg) return _actionForwardAt(actionsAt.place, pt, arg) end
function turtle.placeUpAt(pt, arg) return _actionUpAt(actionsAt.place, pt, arg) end function turtle.placeUpAt(pt, arg) return _actionUpAt(actionsAt.place, pt, arg) end
function turtle.placeXXXAt(pt, dir, arg) return _actionXXXAt(actionsAt.place, pt, dir, arg) end
function turtle.dropAt(pt, ...) return _actionAt(actionsAt.drop, pt, ...) end function turtle.dropAt(pt, ...) return _actionAt(actionsAt.drop, pt, ...) end
function turtle.dropDownAt(pt, ...) return _actionDownAt(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.dropForwardAt(pt, ...) return _actionForwardAt(actionsAt.drop, pt, ...) end
function turtle.dropUpAt(pt, ...) return _actionUpAt(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 or 64) end function turtle.suckAt(pt, qty) return _actionAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckDownAt(pt, qty) return _actionDownAt(actionsAt.suck, pt, qty or 64) end function turtle.suckDownAt(pt, qty) return _actionDownAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckForwardAt(pt, qty) return _actionForwardAt(actionsAt.suck, pt, qty or 64) end function turtle.suckForwardAt(pt, qty) return _actionForwardAt(actionsAt.suck, pt, qty or 64) end
function turtle.suckUpAt(pt, qty) return _actionUpAt(actionsAt.suck, pt, qty or 64) end function turtle.suckUpAt(pt, qty) return _actionUpAt(actionsAt.suck, pt, qty or 64) end
function turtle.compareAt(pt) return _actionAt(actionsAt.compare, pt) end function turtle.compareAt(pt) return _actionAt(actionsAt.compare, pt) end
function turtle.compareDownAt(pt) return _actionDownAt(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.compareForwardAt(pt) return _actionForwardAt(actionsAt.compare, pt) end
function turtle.compareUpAt(pt) return _actionUpAt(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.inspectAt(pt) return _actionAt(actionsAt.inspect, pt) end
function turtle.inspectDownAt(pt) return _actionDownAt(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.inspectForwardAt(pt) return _actionForwardAt(actionsAt.inspect, pt) end
function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end function turtle.inspectUpAt(pt) return _actionUpAt(actionsAt.inspect, pt) end
-- [[ GPS ]] --
local GPS = require('gps')
local Config = require('config')
function turtle.enableGPS(timeout)
--if turtle.point.gps then
-- return turtle.point
--end
local pt = GPS.getPointAndHeading(timeout)
if pt then
turtle.setPoint(pt, true)
return turtle.point
end
end
function turtle.gotoGPSHome()
local config = { }
Config.load('gps', config)
if config.home then
if turtle.enableGPS() then
turtle.pathfind(config.home)
end
end
end
function turtle.setGPSHome()
local config = { }
Config.load('gps', config)
if turtle.point.gps then
config.home = turtle.point
Config.update('gps', config)
else
local pt = GPS.getPoint()
if pt then
local originalHeading = turtle.point.heading
local heading = GPS.getHeading()
if heading then
local turns = (turtle.point.heading - originalHeading) % 4
pt.heading = (heading - turns) % 4
config.home = pt
Config.update('gps', config)
pt = GPS.getPoint()
pt.heading = heading
turtle.setPoint(pt, true)
turtle.gotoPoint(config.home)
end
end
end
end

View File

@ -90,7 +90,7 @@ local function snmpConnection(socket)
} }
if turtle then if turtle then
info.fuel = turtle.getFuelLevel() info.fuel = turtle.getFuelLevel()
info.status = turtle.status info.status = turtle.getStatus()
end end
socket:write(info) socket:write(info)
end end
@ -144,7 +144,7 @@ local function sendInfo()
info.uptime = math.floor(os.clock()) info.uptime = math.floor(os.clock())
if turtle then if turtle then
info.fuel = turtle.getFuelLevel() info.fuel = turtle.getFuelLevel()
info.status = turtle.status info.status = turtle.getStatus()
info.point = turtle.point info.point = turtle.point
info.inventory = turtle.getInventory() info.inventory = turtle.getInventory()
info.slotIndex = turtle.getSelectedSlot() info.slotIndex = turtle.getSelectedSlot()
@ -166,7 +166,7 @@ Event.onInterval(10, function()
end) end)
Event.on('turtle_response', function() Event.on('turtle_response', function()
if turtle.status ~= info.status or if turtle.getStatus() ~= info.status or
turtle.fuel ~= info.fuel then turtle.fuel ~= info.fuel then
sendInfo() sendInfo()
end end