Implement ladders
This commit is contained in:
@ -1,5 +1,55 @@
|
|||||||
package path
|
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) 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)
|
||||||
|
}
|
||||||
|
|
||||||
// Movement represents a single type of movement in a path.
|
// Movement represents a single type of movement in a path.
|
||||||
type Movement uint8
|
type Movement uint8
|
||||||
|
|
||||||
@ -7,6 +57,7 @@ var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, Traver
|
|||||||
TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast,
|
TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast,
|
||||||
DropNorth, DropSouth, DropEast, DropWest,
|
DropNorth, DropSouth, DropEast, DropWest,
|
||||||
AscendNorth, AscendSouth, AscendEast, AscendWest,
|
AscendNorth, AscendSouth, AscendEast, AscendWest,
|
||||||
|
DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid movement values.
|
// Valid movement values.
|
||||||
@ -28,16 +79,23 @@ const (
|
|||||||
AscendSouth
|
AscendSouth
|
||||||
AscendEast
|
AscendEast
|
||||||
AscendWest
|
AscendWest
|
||||||
|
DescendLadder
|
||||||
|
DescendLadderNorth
|
||||||
|
DescendLadderSouth
|
||||||
|
DescendLadderEast
|
||||||
|
DescendLadderWest
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m Movement) Possible(nav *Nav, x, y, z int, from V3) bool {
|
func (m Movement) Possible(nav *Nav, x, y, z int, from V3, previous Movement) bool {
|
||||||
// fmt.Printf("%s.Possible(%d,%d,%d)\n", m, x, y, z)
|
// fmt.Printf("%s.Possible(%d,%d,%d)\n", m, x, y, z)
|
||||||
switch m {
|
switch m {
|
||||||
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
||||||
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) && AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z))
|
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:
|
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
|
||||||
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
||||||
@ -67,6 +125,24 @@ func (m Movement) Possible(nav *Nav, x, y, z int, from V3) bool {
|
|||||||
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+1, from.Z)) &&
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+1, from.Z)) &&
|
||||||
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+2, from.Z))
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+2, from.Z))
|
||||||
|
|
||||||
|
case DescendLadder:
|
||||||
|
if bID := nav.World.GetBlockStatus(x, y+1, z); !AirLikeBlock(bID) && !IsLadder(bID) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
bID := nav.World.GetBlockStatus(x, y, z)
|
||||||
|
fmt.Println(bID, IsLadder(bID))
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bID := nav.World.GetBlockStatus(x, y, z)
|
||||||
|
fmt.Println(bID, IsLadder(bID))
|
||||||
|
return IsLadder(nav.World.GetBlockStatus(x, y, z))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
@ -77,21 +153,23 @@ func (m Movement) Offset() (x, y, z int) {
|
|||||||
case Waypoint:
|
case Waypoint:
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
case TraverseNorth:
|
case TraverseNorth:
|
||||||
return 0, 0, -1
|
return North.Offset()
|
||||||
case TraverseSouth:
|
case TraverseSouth:
|
||||||
return 0, 0, 1
|
return South.Offset()
|
||||||
case TraverseEast:
|
case TraverseEast:
|
||||||
return 1, 0, 0
|
return East.Offset()
|
||||||
case TraverseWest:
|
case TraverseWest:
|
||||||
return -1, 0, 0
|
return West.Offset()
|
||||||
|
|
||||||
case DropNorth:
|
case DescendLadder:
|
||||||
|
return 0, -1, 0
|
||||||
|
case DropNorth, DescendLadderNorth:
|
||||||
return 0, -1, -1
|
return 0, -1, -1
|
||||||
case DropSouth:
|
case DropSouth, DescendLadderSouth:
|
||||||
return 0, -1, 1
|
return 0, -1, 1
|
||||||
case DropEast:
|
case DropEast, DescendLadderEast:
|
||||||
return 1, -1, 0
|
return 1, -1, 0
|
||||||
case DropWest:
|
case DropWest, DescendLadderWest:
|
||||||
return -1, -1, 0
|
return -1, -1, 0
|
||||||
case AscendNorth:
|
case AscendNorth:
|
||||||
return 0, 1, -1
|
return 0, 1, -1
|
||||||
@ -129,6 +207,10 @@ func (m Movement) BaseCost() float64 {
|
|||||||
return 2
|
return 2
|
||||||
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
||||||
return 2.25
|
return 2.25
|
||||||
|
case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest:
|
||||||
|
return 1.5
|
||||||
|
case DescendLadder:
|
||||||
|
return 1.2
|
||||||
default:
|
default:
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
@ -173,6 +255,17 @@ func (m Movement) String() string {
|
|||||||
return "traverse-southwest"
|
return "traverse-southwest"
|
||||||
case TraverseSouthEast:
|
case TraverseSouthEast:
|
||||||
return "traverse-southeast"
|
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"
|
||||||
default:
|
default:
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,9 @@ func (t Tile) PathNeighbors() []astar.Pather {
|
|||||||
for _, m := range allMovements {
|
for _, m := range allMovements {
|
||||||
x, y, z := m.Offset()
|
x, y, z := m.Offset()
|
||||||
pos := V3{X: t.Pos.X + x, Y: t.Pos.Y + y, Z: t.Pos.Z + z}
|
pos := V3{X: t.Pos.X + x, Y: t.Pos.Y + y, Z: t.Pos.Z + z}
|
||||||
if m.Possible(t.Nav, pos.X, pos.Y, pos.Z, t.Pos) {
|
possible := m.Possible(t.Nav, pos.X, pos.Y, pos.Z, t.Pos, t.Movement)
|
||||||
|
// fmt.Printf("%v-%v: Trying (%v) %v: possible=%v\n", t.Movement, t.Pos, pos, m, possible)
|
||||||
|
if possible {
|
||||||
possibles = append(possibles, Tile{
|
possibles = append(possibles, Tile{
|
||||||
Nav: t.Nav,
|
Nav: t.Nav,
|
||||||
Movement: m,
|
Movement: m,
|
||||||
@ -114,3 +116,12 @@ func (t Tile) Inputs(deltaPos, vel Point) Inputs {
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Tile) IsComplete(d Point) bool {
|
||||||
|
switch t.Movement {
|
||||||
|
case DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderWest, DescendLadderEast, DropNorth, DropSouth, DropEast, DropWest:
|
||||||
|
return (d.X*d.X+d.Z*d.Z) < (0.1*0.1*0.13) && d.Y <= 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
return (d.X*d.X+d.Z*d.Z) < (0.18*0.18) && d.Y >= -0.01 && d.Y <= 0.08
|
||||||
|
}
|
||||||
|
@ -20,9 +20,10 @@ const (
|
|||||||
maxYawChange = 33
|
maxYawChange = 33
|
||||||
maxPitchChange = 11
|
maxPitchChange = 11
|
||||||
|
|
||||||
stepHeight = 0.6
|
stepHeight = 0.6
|
||||||
minJumpTicks = 14
|
minJumpTicks = 14
|
||||||
ladderMaxSpeed = 0.15
|
ladderMaxSpeed = 0.15
|
||||||
|
ladderClimbSpeed = 0.2
|
||||||
|
|
||||||
gravity = 0.08
|
gravity = 0.08
|
||||||
drag = 0.98
|
drag = 0.98
|
||||||
@ -152,6 +153,10 @@ func (s *State) Tick(input path.Inputs, w World) error {
|
|||||||
s.collision.vertical = newVel.Y != s.Vel.Y
|
s.collision.vertical = newVel.Y != s.Vel.Y
|
||||||
s.onGround = s.collision.vertical && s.Vel.Y < 0
|
s.onGround = s.collision.vertical && s.Vel.Y < 0
|
||||||
|
|
||||||
|
if path.IsLadder(w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))) && s.collision.horizontal {
|
||||||
|
newVel.Y = ladderClimbSpeed
|
||||||
|
}
|
||||||
|
|
||||||
s.Vel = newVel
|
s.Vel = newVel
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -205,20 +210,19 @@ func (s *State) tickVelocity(input path.Inputs, w World) {
|
|||||||
s.applyLookInputs(input)
|
s.applyLookInputs(input)
|
||||||
s.applyPosInputs(input, acceleration, inertia)
|
s.applyPosInputs(input, acceleration, inertia)
|
||||||
|
|
||||||
|
lower := w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))
|
||||||
|
if path.IsLadder(lower) {
|
||||||
|
s.Vel.X = math.Min(math.Max(-ladderMaxSpeed, s.Vel.X), ladderMaxSpeed)
|
||||||
|
s.Vel.Z = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Z), ladderMaxSpeed)
|
||||||
|
s.Vel.Y = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Y), ladderMaxSpeed)
|
||||||
|
}
|
||||||
|
|
||||||
// Gravity
|
// Gravity
|
||||||
s.Vel.Y -= gravity
|
s.Vel.Y -= gravity
|
||||||
// Drag & friction.
|
// Drag & friction.
|
||||||
s.Vel.Y *= drag
|
s.Vel.Y *= drag
|
||||||
s.Vel.X *= inertia
|
s.Vel.X *= inertia
|
||||||
s.Vel.Z *= inertia
|
s.Vel.Z *= inertia
|
||||||
|
|
||||||
lower := w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))
|
|
||||||
if path.IsLadder(lower) {
|
|
||||||
s.Vel.X = math.Min(math.Max(-ladderMaxSpeed, s.Vel.X), ladderMaxSpeed)
|
|
||||||
s.Vel.Z = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Z), ladderMaxSpeed)
|
|
||||||
s.Vel.Y = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Y), ladderMaxSpeed)
|
|
||||||
fmt.Println(s.Vel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) computeCollision(bb, query AABB, w World) (outBB AABB, outVel path.Point) {
|
func (s *State) computeCollision(bb, query AABB, w World) (outBB AABB, outVel path.Point) {
|
||||||
|
Reference in New Issue
Block a user