From 797ba13fdd60dbbb4529864c75097a2085148077 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 23 Sep 2020 21:17:37 -0700 Subject: [PATCH] Implement ladders --- bot/path/movement.go | 113 +++++++++++++++++++++++++++++++++++++++---- bot/path/path.go | 13 ++++- bot/phy/phy.go | 26 +++++----- 3 files changed, 130 insertions(+), 22 deletions(-) diff --git a/bot/path/movement.go b/bot/path/movement.go index dd1a0b7..08ef39a 100644 --- a/bot/path/movement.go +++ b/bot/path/movement.go @@ -1,5 +1,55 @@ 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. type Movement uint8 @@ -7,6 +57,7 @@ var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, Traver TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast, DropNorth, DropSouth, DropEast, DropWest, AscendNorth, AscendSouth, AscendEast, AscendWest, + DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest, } // Valid movement values. @@ -28,16 +79,23 @@ const ( AscendSouth AscendEast 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) switch m { case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest: if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) { 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: 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+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: panic(m) } @@ -77,21 +153,23 @@ func (m Movement) Offset() (x, y, z int) { case Waypoint: return 0, 0, 0 case TraverseNorth: - return 0, 0, -1 + return North.Offset() case TraverseSouth: - return 0, 0, 1 + return South.Offset() case TraverseEast: - return 1, 0, 0 + return East.Offset() case TraverseWest: - return -1, 0, 0 + return West.Offset() - case DropNorth: + case DescendLadder: + return 0, -1, 0 + case DropNorth, DescendLadderNorth: return 0, -1, -1 - case DropSouth: + case DropSouth, DescendLadderSouth: return 0, -1, 1 - case DropEast: + case DropEast, DescendLadderEast: return 1, -1, 0 - case DropWest: + case DropWest, DescendLadderWest: return -1, -1, 0 case AscendNorth: return 0, 1, -1 @@ -129,6 +207,10 @@ func (m Movement) BaseCost() float64 { return 2 case AscendNorth, AscendSouth, AscendEast, AscendWest: return 2.25 + case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest: + return 1.5 + case DescendLadder: + return 1.2 default: panic(m) } @@ -173,6 +255,17 @@ func (m Movement) String() string { 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" default: panic(m) } diff --git a/bot/path/path.go b/bot/path/path.go index 841c915..dbee50e 100644 --- a/bot/path/path.go +++ b/bot/path/path.go @@ -80,7 +80,9 @@ func (t Tile) PathNeighbors() []astar.Pather { for _, m := range allMovements { x, y, z := m.Offset() 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{ Nav: t.Nav, Movement: m, @@ -114,3 +116,12 @@ func (t Tile) Inputs(deltaPos, vel Point) Inputs { } 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 +} diff --git a/bot/phy/phy.go b/bot/phy/phy.go index 8679186..8382abe 100644 --- a/bot/phy/phy.go +++ b/bot/phy/phy.go @@ -20,9 +20,10 @@ const ( maxYawChange = 33 maxPitchChange = 11 - stepHeight = 0.6 - minJumpTicks = 14 - ladderMaxSpeed = 0.15 + stepHeight = 0.6 + minJumpTicks = 14 + ladderMaxSpeed = 0.15 + ladderClimbSpeed = 0.2 gravity = 0.08 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.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 return nil } @@ -205,20 +210,19 @@ func (s *State) tickVelocity(input path.Inputs, w World) { s.applyLookInputs(input) 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 s.Vel.Y -= gravity // Drag & friction. s.Vel.Y *= drag s.Vel.X *= 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) {