Implement physics + pathfinding over slabs
This commit is contained in:
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,14 +149,17 @@ 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]
|
||||||
|
_, isSlab = slabs[b.ID]
|
||||||
maybeStuck = runTime < 1250*time.Millisecond
|
maybeStuck = runTime < 1250*time.Millisecond
|
||||||
dist2 = math.Sqrt(deltaPos.X*deltaPos.X + deltaPos.Z*deltaPos.Z)
|
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
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isStairs:
|
||||||
// Special logic for stairs: Try to go towards the downwards edge initially.
|
// Special logic for stairs: Try to go towards the downwards edge initially.
|
||||||
if isStairs && dist2 > (0.9*0.9) && deltaPos.Y < 0 {
|
if dist2 > (0.9*0.9) && deltaPos.Y < 0 {
|
||||||
if x, _, z := StairsDirection(t.BlockStatus).Offset(); 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.X += (0.49 * float64(x))
|
||||||
pos.Z += (0.49 * float64(z))
|
pos.Z += (0.49 * float64(z))
|
||||||
@ -168,6 +173,10 @@ func (t Tile) Inputs(pos, deltaPos, vel Point, runTime time.Duration) Inputs {
|
|||||||
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.
|
||||||
if dist2 < 1 && deltaPos.Y < 0 && vel.Y == 0 {
|
if dist2 < 1 && deltaPos.Y < 0 && vel.Y == 0 {
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Reference in New Issue
Block a user