Implement physics + pathfinding over slabs

This commit is contained in:
Tom
2020-10-12 22:13:02 -07:00
parent 5120b2dd9a
commit 1240aefc38
4 changed files with 102 additions and 21 deletions

View File

@ -51,6 +51,62 @@ var (
block.AndesiteStairs, block.AndesiteStairs,
block.RedNetherBrickStairs, block.RedNetherBrickStairs,
block.PolishedAndesiteStairs, 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) safeWalkBlocks = make(map[world.BlockStatus]struct{}, 128)
@ -116,3 +172,8 @@ func AirLikeBlock(bID world.BlockStatus) bool {
func IsLadder(bID world.BlockStatus) bool { func IsLadder(bID world.BlockStatus) bool {
return uint32(bID) >= block.Ladder.MinStateID && uint32(bID) <= block.Ladder.MaxStateID 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
}

View File

@ -64,6 +64,11 @@ func StairsDirection(bStateID world.BlockStatus) Direction {
return Direction(((uint32(bStateID) - block.ByID[b].MinStateID) / 20) & 0x3) 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. // Movement represents a single type of movement in a path.
type Movement uint8 type Movement uint8

View File

@ -4,7 +4,6 @@ package path
import ( import (
"math" "math"
"math/rand" "math/rand"
"strings"
"time" "time"
"github.com/Tnze/go-mc/bot/world" "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 { type Tile struct {
Nav *Nav Nav *Nav
HalfBlock bool
Movement Movement Movement Movement
Pos V3 Pos V3
BlockStatus world.BlockStatus 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) 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) // fmt.Printf("%v-%v: Trying (%v) %v: possible=%v\n", t.Movement, t.Pos, pos, m, possible)
if possible { if possible {
bStateID := t.Nav.World.GetBlockStatus(pos.X, pos.Y, pos.Z)
possibles = append(possibles, Tile{ possibles = append(possibles, Tile{
Nav: t.Nav, Nav: t.Nav,
Movement: m, Movement: m,
Pos: pos, 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: case AscendNorth, AscendSouth, AscendEast, AscendWest:
var ( var (
b = block.ByID[block.StateID[uint32(t.BlockStatus)]] b = block.ByID[block.StateID[uint32(t.BlockStatus)]]
isStairs = strings.HasSuffix(b.Name, "_stairs") _, isStairs = stairs[b.ID]
maybeStuck = runTime < 1250*time.Millisecond _, isSlab = slabs[b.ID]
dist2 = math.Sqrt(deltaPos.X*deltaPos.X + deltaPos.Z*deltaPos.Z) 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 out.Jump = dist2 < 1.75 && deltaPos.Y < -0.81
// Special logic for stairs: Try to go towards the downwards edge initially. switch {
if isStairs && dist2 > (0.9*0.9) && deltaPos.Y < 0 { case isStairs:
if x, _, z := StairsDirection(t.BlockStatus).Offset(); dist2 > (0.9*0.9) && deltaPos.Y < 0 { // Special logic for stairs: Try to go towards the downwards edge initially.
pos.X += (0.49 * float64(x)) if dist2 > (0.9*0.9) && deltaPos.Y < 0 {
pos.Z += (0.49 * float64(z)) 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) at = math.Atan2(-pos.X+float64(t.Pos.X)+0.5, -pos.Z+float64(t.Pos.Z)+0.5)
out = Inputs{ out = Inputs{
ThrottleX: math.Sin(at), ThrottleX: math.Sin(at),
ThrottleZ: math.Cos(at), ThrottleZ: math.Cos(at),
Yaw: math.NaN(), Yaw: math.NaN(),
Jump: out.Jump && !maybeStuck, 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. // 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.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
} }

View File

@ -215,7 +215,7 @@ func (s *State) tickPosition(w World) {
if s.onGround || (s.Vel.Y != newVel.Y && s.Vel.Y < 0) { if s.onGround || (s.Vel.Y != newVel.Y && s.Vel.Y < 0) {
bb := s.BB() bb := s.BB()
//fmt.Printf("Player pos = %0.2f, %0.2f, %0.2f\n", bb.X.Min, bb.Y.Min, bb.Z.Min) //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 := s.Vel
outVel.Y = stepHeight outVel.Y = stepHeight
@ -243,7 +243,7 @@ func (s *State) tickPosition(w World) {
oldMove := newVel.X*newVel.X + newVel.Z*newVel.Z oldMove := newVel.X*newVel.X + newVel.Z*newVel.Z
newMove := outVel.X*outVel.X + outVel.Z*outVel.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) { if oldMove >= newMove || outVel.Y <= (0.000002-stepHeight) {
// fmt.Println("nope") // fmt.Println("nope")
} else { } else {