363 lines
8.6 KiB
Go
363 lines
8.6 KiB
Go
package path
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/Tnze/go-mc/bot/world"
|
|
"github.com/Tnze/go-mc/data/block"
|
|
)
|
|
|
|
// Cardinal directions.
|
|
type Direction uint8
|
|
|
|
func (d Direction) Offset() (x, y, z int) {
|
|
switch d {
|
|
case North:
|
|
return 0, 0, -1
|
|
case South:
|
|
return 0, 0, 1
|
|
case East:
|
|
return 1, 0, 0
|
|
case West:
|
|
return -1, 0, 0
|
|
}
|
|
panic(fmt.Sprintf("unknown direction value: %v", d))
|
|
}
|
|
|
|
func (d Direction) Offset2x() (x, y, z int) {
|
|
x, y, z = d.Offset()
|
|
return x + x, y + y, z + z
|
|
}
|
|
|
|
func (d Direction) String() string {
|
|
switch d {
|
|
case North:
|
|
return "north"
|
|
case South:
|
|
return "south"
|
|
case East:
|
|
return "east"
|
|
case West:
|
|
return "west"
|
|
}
|
|
return fmt.Sprintf("Direction?<%d>", int(d))
|
|
}
|
|
|
|
// Valid direction values.
|
|
const (
|
|
North Direction = iota
|
|
South
|
|
West
|
|
East
|
|
)
|
|
|
|
func LadderDirection(bStateID world.BlockStatus) Direction {
|
|
return Direction(((uint32(bStateID) - block.Ladder.MinStateID) & 0xE) >> 1)
|
|
}
|
|
|
|
func ChestDirection(bStateID world.BlockStatus) Direction {
|
|
return Direction(((uint32(bStateID) - block.Chest.MinStateID) / 6) & 0x3)
|
|
}
|
|
|
|
func StairsDirection(bStateID world.BlockStatus) Direction {
|
|
b := block.StateID[uint32(bStateID)]
|
|
return Direction(((uint32(bStateID) - block.ByID[b].MinStateID) / 20) & 0x3)
|
|
}
|
|
|
|
func SlabIsBottom(bStateID world.BlockStatus) bool {
|
|
b := block.StateID[uint32(bStateID)]
|
|
return ((uint32(bStateID)-block.ByID[b].MinStateID)&0xE)>>1 == 1
|
|
}
|
|
|
|
// Movement represents a single type of movement in a path.
|
|
type Movement uint8
|
|
|
|
var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, TraverseWest,
|
|
TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast,
|
|
DropNorth, DropSouth, DropEast, DropWest,
|
|
Drop2North, Drop2South, Drop2East, Drop2West,
|
|
AscendNorth, AscendSouth, AscendEast, AscendWest,
|
|
DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest,
|
|
AscendLadder,
|
|
JumpCrossNorth, JumpCrossSouth, JumpCrossEast, JumpCrossWest,
|
|
}
|
|
|
|
// Valid movement values.
|
|
const (
|
|
Waypoint Movement = iota
|
|
TraverseNorth
|
|
TraverseSouth
|
|
TraverseEast
|
|
TraverseWest
|
|
TraverseNorthEast
|
|
TraverseNorthWest
|
|
TraverseSouthEast
|
|
TraverseSouthWest
|
|
DropNorth
|
|
DropSouth
|
|
DropEast
|
|
DropWest
|
|
Drop2North
|
|
Drop2South
|
|
Drop2East
|
|
Drop2West
|
|
AscendNorth
|
|
AscendSouth
|
|
AscendEast
|
|
AscendWest
|
|
DescendLadder
|
|
DescendLadderNorth
|
|
DescendLadderSouth
|
|
DescendLadderEast
|
|
DescendLadderWest
|
|
AscendLadder
|
|
JumpCrossEast
|
|
JumpCrossWest
|
|
JumpCrossNorth
|
|
JumpCrossSouth
|
|
)
|
|
|
|
func (m Movement) Possible(nav *Nav, x, y, z int, from V3, previous Movement) bool {
|
|
switch m {
|
|
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
|
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
|
return false
|
|
}
|
|
b1, b2 := nav.World.GetBlockStatus(x, y+1, z), nav.World.GetBlockStatus(x, y+2, z)
|
|
u1, u2 := AirLikeBlock(b1) || IsLadder(b1), AirLikeBlock(b2) || IsLadder(b2)
|
|
return u1 && u2
|
|
|
|
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
|
|
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
|
return false
|
|
}
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z)) {
|
|
return false
|
|
}
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(from.X, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(from.X, y+2, z)) {
|
|
return false
|
|
}
|
|
return AirLikeBlock(nav.World.GetBlockStatus(x, y+1, from.Z)) && AirLikeBlock(nav.World.GetBlockStatus(x, y+2, from.Z))
|
|
|
|
case Drop2North, Drop2South, Drop2East, Drop2West:
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+4, z)) {
|
|
return false
|
|
}
|
|
fallthrough
|
|
|
|
case DropNorth, DropSouth, DropEast, DropWest:
|
|
for amt := 0; amt < 3; amt++ {
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+amt+1, z)) {
|
|
return false
|
|
}
|
|
}
|
|
return SteppableBlock(nav.World.GetBlockStatus(x, y, z))
|
|
|
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z)) {
|
|
return false
|
|
}
|
|
return SteppableBlock(nav.World.GetBlockStatus(x, y, z)) &&
|
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+1, from.Z)) &&
|
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+2, from.Z))
|
|
|
|
case DescendLadder, AscendLadder:
|
|
if bID := nav.World.GetBlockStatus(x, y+1, z); !AirLikeBlock(bID) && !IsLadder(bID) {
|
|
return false
|
|
}
|
|
return IsLadder(nav.World.GetBlockStatus(x, y, z))
|
|
|
|
case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest:
|
|
for amt := 0; amt < 2; amt++ {
|
|
if bID := nav.World.GetBlockStatus(x, y+amt+1, z); !AirLikeBlock(bID) && !IsLadder(bID) {
|
|
return false
|
|
}
|
|
}
|
|
return IsLadder(nav.World.GetBlockStatus(x, y, z))
|
|
|
|
case JumpCrossEast, JumpCrossWest, JumpCrossNorth, JumpCrossSouth:
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+3, z)) {
|
|
return false
|
|
}
|
|
midX, midZ := (from.X+x)/2, (from.Z+z)/2
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(midX, y+1, midZ)) || !AirLikeBlock(nav.World.GetBlockStatus(midX, y+2, midZ)) || !AirLikeBlock(nav.World.GetBlockStatus(midX, y+3, midZ)) {
|
|
return false
|
|
}
|
|
if !AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+3, from.Z)) {
|
|
return false
|
|
}
|
|
return SteppableBlock(nav.World.GetBlockStatus(x, y, z))
|
|
|
|
default:
|
|
panic(m)
|
|
}
|
|
}
|
|
|
|
func (m Movement) Offset() (x, y, z int) {
|
|
switch m {
|
|
case Waypoint:
|
|
return 0, 0, 0
|
|
case TraverseNorth:
|
|
return North.Offset()
|
|
case TraverseSouth:
|
|
return South.Offset()
|
|
case TraverseEast:
|
|
return East.Offset()
|
|
case TraverseWest:
|
|
return West.Offset()
|
|
|
|
case JumpCrossEast:
|
|
return East.Offset2x()
|
|
case JumpCrossWest:
|
|
return West.Offset2x()
|
|
case JumpCrossNorth:
|
|
return North.Offset2x()
|
|
case JumpCrossSouth:
|
|
return South.Offset2x()
|
|
|
|
case AscendLadder:
|
|
return 0, 1, 0
|
|
case DescendLadder:
|
|
return 0, -1, 0
|
|
case DropNorth, DescendLadderNorth:
|
|
return 0, -1, -1
|
|
case DropSouth, DescendLadderSouth:
|
|
return 0, -1, 1
|
|
case DropEast, DescendLadderEast:
|
|
return 1, -1, 0
|
|
case DropWest, DescendLadderWest:
|
|
return -1, -1, 0
|
|
case AscendNorth:
|
|
return 0, 1, -1
|
|
case AscendSouth:
|
|
return 0, 1, 1
|
|
case AscendEast:
|
|
return 1, 1, 0
|
|
case AscendWest:
|
|
return -1, 1, 0
|
|
|
|
case TraverseNorthWest:
|
|
return -1, 0, -1
|
|
case TraverseNorthEast:
|
|
return 1, 0, -1
|
|
case TraverseSouthWest:
|
|
return -1, 0, 1
|
|
case TraverseSouthEast:
|
|
return 1, 0, 1
|
|
|
|
case Drop2North:
|
|
return 0, -2, -1
|
|
case Drop2South:
|
|
return 0, -2, 1
|
|
case Drop2East:
|
|
return 1, -2, 0
|
|
case Drop2West:
|
|
return -1, -2, 0
|
|
|
|
default:
|
|
panic(m)
|
|
}
|
|
}
|
|
|
|
func (m Movement) BaseCost() float64 {
|
|
switch m {
|
|
case Waypoint:
|
|
return 0
|
|
case TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
|
return 2
|
|
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
|
|
return 2.5
|
|
|
|
case DropNorth, DropSouth, DropEast, DropWest, Drop2North, Drop2South, Drop2East, Drop2West:
|
|
return 4
|
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
|
return 4
|
|
case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest:
|
|
return 1.5
|
|
case DescendLadder:
|
|
return 1
|
|
case AscendLadder:
|
|
return 3
|
|
|
|
case JumpCrossEast, JumpCrossWest, JumpCrossNorth, JumpCrossSouth:
|
|
return 5.5
|
|
default:
|
|
panic(m)
|
|
}
|
|
}
|
|
|
|
func (m Movement) String() string {
|
|
switch m {
|
|
case Waypoint:
|
|
return "waypoint"
|
|
case TraverseNorth:
|
|
return "traverse-north"
|
|
case TraverseSouth:
|
|
return "traverse-south"
|
|
case TraverseEast:
|
|
return "traverse-east"
|
|
case TraverseWest:
|
|
return "traverse-west"
|
|
|
|
case DropNorth:
|
|
return "drop-north"
|
|
case DropSouth:
|
|
return "drop-south"
|
|
case DropEast:
|
|
return "drop-east"
|
|
case DropWest:
|
|
return "drop-west"
|
|
case Drop2North:
|
|
return "drop-2-north"
|
|
case Drop2South:
|
|
return "drop-2-south"
|
|
case Drop2East:
|
|
return "drop-2-east"
|
|
case Drop2West:
|
|
return "drop-2-west"
|
|
|
|
case AscendNorth:
|
|
return "jump-north"
|
|
case AscendSouth:
|
|
return "jump-south"
|
|
case AscendEast:
|
|
return "jump-east"
|
|
case AscendWest:
|
|
return "jump-west"
|
|
|
|
case TraverseNorthWest:
|
|
return "traverse-northwest"
|
|
case TraverseNorthEast:
|
|
return "traverse-northeast"
|
|
case TraverseSouthWest:
|
|
return "traverse-southwest"
|
|
case TraverseSouthEast:
|
|
return "traverse-southeast"
|
|
|
|
case DescendLadder:
|
|
return "descend-ladder"
|
|
case DescendLadderNorth:
|
|
return "descend-ladder-north"
|
|
case DescendLadderSouth:
|
|
return "descend-ladder-south"
|
|
case DescendLadderEast:
|
|
return "descend-ladder-east"
|
|
case DescendLadderWest:
|
|
return "descend-ladder-west"
|
|
|
|
case AscendLadder:
|
|
return "ascend-ladder"
|
|
|
|
case JumpCrossEast:
|
|
return "jump-crossing-east"
|
|
case JumpCrossWest:
|
|
return "jump-crossing-west"
|
|
case JumpCrossNorth:
|
|
return "jump-crossing-north"
|
|
case JumpCrossSouth:
|
|
return "jump-crossing-south"
|
|
default:
|
|
panic(m)
|
|
}
|
|
}
|