From 1240aefc38f609ee6f0fe01e2b1fec3e72441790 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 12 Oct 2020 22:13:02 -0700 Subject: [PATCH] Implement physics + pathfinding over slabs --- bot/path/blocks.go | 61 ++++++++++++++++++++++++++++++++++++++++++++ bot/path/movement.go | 5 ++++ bot/path/path.go | 53 ++++++++++++++++++++++++-------------- bot/phy/phy.go | 4 +-- 4 files changed, 102 insertions(+), 21 deletions(-) diff --git a/bot/path/blocks.go b/bot/path/blocks.go index d2143fa..5339b2e 100644 --- a/bot/path/blocks.go +++ b/bot/path/blocks.go @@ -51,6 +51,62 @@ var ( block.AndesiteStairs, block.RedNetherBrickStairs, block.PolishedAndesiteStairs, + block.OakSlab, + block.AcaciaSlab, + block.DarkOakSlab, + block.RedSandstoneSlab, + block.PolishedGraniteSlab, + block.SmoothRedSandstoneSlab, + block.MossyStoneBrickSlab, + block.PolishedDioriteSlab, + block.MossyCobblestoneSlab, + block.EndStoneBrickSlab, + block.StoneSlab, + block.SmoothSandstoneSlab, + block.SmoothQuartzSlab, + block.GraniteSlab, + block.AndesiteSlab, + block.RedNetherBrickSlab, + block.PolishedAndesiteSlab, + } + + slabs = map[block.ID]struct{}{ + block.OakSlab.ID: struct{}{}, + block.AcaciaSlab.ID: struct{}{}, + block.DarkOakSlab.ID: struct{}{}, + block.RedSandstoneSlab.ID: struct{}{}, + block.PolishedGraniteSlab.ID: struct{}{}, + block.SmoothRedSandstoneSlab.ID: struct{}{}, + block.MossyStoneBrickSlab.ID: struct{}{}, + block.PolishedDioriteSlab.ID: struct{}{}, + block.MossyCobblestoneSlab.ID: struct{}{}, + block.EndStoneBrickSlab.ID: struct{}{}, + block.StoneSlab.ID: struct{}{}, + block.SmoothSandstoneSlab.ID: struct{}{}, + block.SmoothQuartzSlab.ID: struct{}{}, + block.GraniteSlab.ID: struct{}{}, + block.AndesiteSlab.ID: struct{}{}, + block.RedNetherBrickSlab.ID: struct{}{}, + block.PolishedAndesiteSlab.ID: struct{}{}, + } + stairs = map[block.ID]struct{}{ + block.OakStairs.ID: struct{}{}, + block.AcaciaStairs.ID: struct{}{}, + block.DarkOakStairs.ID: struct{}{}, + block.RedSandstoneStairs.ID: struct{}{}, + block.PolishedGraniteStairs.ID: struct{}{}, + block.SmoothRedSandstoneStairs.ID: struct{}{}, + block.MossyStoneBrickStairs.ID: struct{}{}, + block.PolishedDioriteStairs.ID: struct{}{}, + block.MossyCobblestoneStairs.ID: struct{}{}, + block.EndStoneBrickStairs.ID: struct{}{}, + block.StoneStairs.ID: struct{}{}, + block.SmoothSandstoneStairs.ID: struct{}{}, + block.SmoothQuartzStairs.ID: struct{}{}, + block.GraniteStairs.ID: struct{}{}, + block.AndesiteStairs.ID: struct{}{}, + block.RedNetherBrickStairs.ID: struct{}{}, + block.PolishedAndesiteStairs.ID: struct{}{}, } safeWalkBlocks = make(map[world.BlockStatus]struct{}, 128) @@ -116,3 +172,8 @@ func AirLikeBlock(bID world.BlockStatus) bool { func IsLadder(bID world.BlockStatus) bool { return uint32(bID) >= block.Ladder.MinStateID && uint32(bID) <= block.Ladder.MaxStateID } + +func IsSlab(bID world.BlockStatus) bool { + _, isSlab := slabs[block.StateID[uint32(bID)]] + return isSlab +} diff --git a/bot/path/movement.go b/bot/path/movement.go index 1fb20ef..a2edcc8 100644 --- a/bot/path/movement.go +++ b/bot/path/movement.go @@ -64,6 +64,11 @@ func StairsDirection(bStateID world.BlockStatus) Direction { 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 diff --git a/bot/path/path.go b/bot/path/path.go index e2b14cc..6c615b1 100644 --- a/bot/path/path.go +++ b/bot/path/path.go @@ -4,7 +4,6 @@ package path import ( "math" "math/rand" - "strings" "time" "github.com/Tnze/go-mc/bot/world" @@ -51,6 +50,7 @@ func (n *Nav) Path() (path []astar.Pather, distance float64, found bool) { type Tile struct { Nav *Nav + HalfBlock bool Movement Movement Pos V3 BlockStatus world.BlockStatus @@ -89,11 +89,13 @@ func (t Tile) PathNeighbors() []astar.Pather { 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 { + bStateID := t.Nav.World.GetBlockStatus(pos.X, pos.Y, pos.Z) possibles = append(possibles, Tile{ Nav: t.Nav, Movement: m, Pos: pos, - BlockStatus: t.Nav.World.GetBlockStatus(pos.X, pos.Y, pos.Z), + BlockStatus: bStateID, + HalfBlock: IsSlab(bStateID) && SlabIsBottom(bStateID), }) } } @@ -146,27 +148,34 @@ func (t Tile) Inputs(pos, deltaPos, vel Point, runTime time.Duration) Inputs { case AscendNorth, AscendSouth, AscendEast, AscendWest: var ( - b = block.ByID[block.StateID[uint32(t.BlockStatus)]] - isStairs = strings.HasSuffix(b.Name, "_stairs") - maybeStuck = runTime < 1250*time.Millisecond - dist2 = math.Sqrt(deltaPos.X*deltaPos.X + deltaPos.Z*deltaPos.Z) + b = block.ByID[block.StateID[uint32(t.BlockStatus)]] + _, isStairs = stairs[b.ID] + _, isSlab = slabs[b.ID] + maybeStuck = runTime < 1250*time.Millisecond + dist2 = math.Sqrt(deltaPos.X*deltaPos.X + deltaPos.Z*deltaPos.Z) ) out.Jump = dist2 < 1.75 && deltaPos.Y < -0.81 - // Special logic for stairs: Try to go towards the downwards edge initially. - if isStairs && dist2 > (0.9*0.9) && deltaPos.Y < 0 { - if x, _, z := StairsDirection(t.BlockStatus).Offset(); dist2 > (0.9*0.9) && deltaPos.Y < 0 { - pos.X += (0.49 * float64(x)) - pos.Z += (0.49 * float64(z)) - } + switch { + case isStairs: + // Special logic for stairs: Try to go towards the downwards edge initially. + if dist2 > (0.9*0.9) && deltaPos.Y < 0 { + if x, _, z := StairsDirection(t.BlockStatus).Offset(); dist2 > (0.9*0.9) && deltaPos.Y < 0 { + pos.X += (0.49 * float64(x)) + pos.Z += (0.49 * float64(z)) + } - at = math.Atan2(-pos.X+float64(t.Pos.X)+0.5, -pos.Z+float64(t.Pos.Z)+0.5) - out = Inputs{ - ThrottleX: math.Sin(at), - ThrottleZ: math.Cos(at), - Yaw: math.NaN(), - Jump: out.Jump && !maybeStuck, + at = math.Atan2(-pos.X+float64(t.Pos.X)+0.5, -pos.Z+float64(t.Pos.Z)+0.5) + out = Inputs{ + ThrottleX: math.Sin(at), + ThrottleZ: math.Cos(at), + Yaw: math.NaN(), + Jump: out.Jump && !maybeStuck, + } } + // We dont need to jump for slabs, so only jump if we get stuck. + case isSlab: + out.Jump = out.Jump && !maybeStuck } // Turn off the throttle if we get stuck on the jump. @@ -192,5 +201,11 @@ func (t Tile) IsComplete(d Point) bool { return (d.X*d.X+d.Z*d.Z) < (0.22*0.22) && d.Y >= -0.065 } - return (d.X*d.X+d.Z*d.Z) < (0.18*0.18) && d.Y >= -0.065 && d.Y <= 0.08 + yLowerCutoff := -0.065 + if t.HalfBlock { + yLowerCutoff -= 0.5 + } + + // fmt.Println(t.HalfBlock, d.Y, d.Y >= yLowerCutoff, d.Y <= 0.08) + return (d.X*d.X+d.Z*d.Z) < (0.18*0.18) && d.Y >= yLowerCutoff && d.Y <= 0.08 } diff --git a/bot/phy/phy.go b/bot/phy/phy.go index 31e205a..5517e9d 100644 --- a/bot/phy/phy.go +++ b/bot/phy/phy.go @@ -215,7 +215,7 @@ func (s *State) tickPosition(w World) { if s.onGround || (s.Vel.Y != newVel.Y && s.Vel.Y < 0) { bb := s.BB() //fmt.Printf("Player pos = %0.2f, %0.2f, %0.2f\n", bb.X.Min, bb.Y.Min, bb.Z.Min) - surroundings := s.surroundings(bb.Offset(s.Vel.X, stepHeight, s.Vel.Y), w) + surroundings := s.surroundings(bb.Offset(s.Vel.X, stepHeight, s.Vel.Z), w) outVel := s.Vel outVel.Y = stepHeight @@ -243,7 +243,7 @@ func (s *State) tickPosition(w World) { oldMove := newVel.X*newVel.X + newVel.Z*newVel.Z newMove := outVel.X*outVel.X + outVel.Z*outVel.Z - // fmt.Printf("oldMove = %0.2f, newMove = %0.2f\n", oldMove*1000, newMove*1000) + // fmt.Printf("oldMove/newmove = %v, (%0.2f >= %0.6f) = %v\n", oldMove >= newMove, outVel.Y, 0.000002-stepHeight, outVel.Y <= (0.000002-stepHeight)) if oldMove >= newMove || outVel.Y <= (0.000002-stepHeight) { // fmt.Println("nope") } else {