forked from Minestom/Minestom
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new navigator generator & follower
- Loading branch information
1 parent
4a6641e
commit d1624c2
Showing
7 changed files
with
233 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
src/main/java/net/minestom/server/entity/pathfinding/followers/NoPhysicsNodeFollower.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package net.minestom.server.entity.pathfinding.followers; | ||
|
||
import net.minestom.server.coordinate.Point; | ||
import net.minestom.server.coordinate.Pos; | ||
import net.minestom.server.coordinate.Vec; | ||
import net.minestom.server.entity.Entity; | ||
import net.minestom.server.entity.LivingEntity; | ||
import net.minestom.server.entity.attribute.Attribute; | ||
import net.minestom.server.utils.position.PositionUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public class NoPhysicsNodeFollower implements NodeFollower { | ||
private final Entity entity; | ||
|
||
public NoPhysicsNodeFollower(@NotNull Entity entity) { | ||
this.entity = entity; | ||
} | ||
|
||
/** | ||
* Used to move the entity toward {@code direction} in the X and Z axis | ||
* Gravity is still applied but the entity will not attempt to jump | ||
* Also update the yaw/pitch of the entity to look along 'direction' | ||
* | ||
* @param direction the targeted position | ||
* @param speed define how far the entity will move | ||
*/ | ||
public void moveTowards(@NotNull Point direction, double speed, @NotNull Point lookAt) { | ||
final Pos position = entity.getPosition(); | ||
final double dx = direction.x() - position.x(); | ||
final double dy = direction.y() - position.y(); | ||
final double dz = direction.z() - position.z(); | ||
|
||
if (dy > 0 && entity.isOnGround()) jump(4f); | ||
|
||
final double dxLook = lookAt.x() - position.x(); | ||
final double dyLook = lookAt.y() - position.y(); | ||
final double dzLook = lookAt.z() - position.z(); | ||
|
||
// the purpose of these few lines is to slow down entities when they reach their destination | ||
final double distSquared = dx * dx + dy * dy + dz * dz; | ||
if (speed > distSquared) { | ||
speed = distSquared; | ||
} | ||
|
||
final double radians = Math.atan2(dz, dx); | ||
final double speedX = Math.cos(radians) * speed; | ||
final double speedZ = Math.sin(radians) * speed; | ||
final float yaw = PositionUtils.getLookYaw(dxLook, dzLook); | ||
final float pitch = PositionUtils.getLookPitch(dxLook, dyLook, dzLook); | ||
|
||
var newPosition = position.add(speedX, 0, speedZ); | ||
this.entity.refreshPosition(newPosition.withView(yaw, pitch)); | ||
} | ||
|
||
@Override | ||
public void jump(@Nullable Point point, @Nullable Point target) { | ||
if (entity.isOnGround()) { | ||
jump(4f); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isAtPoint(@NotNull Point point) { | ||
return entity.getPosition().sameBlock(point); | ||
} | ||
|
||
public void jump(float height) { | ||
this.entity.setVelocity(new Vec(0, height * 2.5f, 0)); | ||
} | ||
|
||
@Override | ||
public double movementSpeed() { | ||
if (entity instanceof LivingEntity living) { | ||
return living.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(); | ||
} | ||
|
||
return 0.1f; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
...in/java/net/minestom/server/entity/pathfinding/generators/PreciseGroundNodeGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package net.minestom.server.entity.pathfinding.generators; | ||
|
||
import net.minestom.server.collision.BoundingBox; | ||
import net.minestom.server.collision.CollisionUtils; | ||
import net.minestom.server.collision.PhysicsResult; | ||
import net.minestom.server.coordinate.Point; | ||
import net.minestom.server.coordinate.Pos; | ||
import net.minestom.server.coordinate.Vec; | ||
import net.minestom.server.entity.pathfinding.PNode; | ||
import net.minestom.server.instance.Instance; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.OptionalDouble; | ||
import java.util.Set; | ||
|
||
public class PreciseGroundNodeGenerator implements NodeGenerator { | ||
private PNode tempNode = null; | ||
private final static int MAX_FALL_DISTANCE = 5; | ||
|
||
@Override | ||
public @NotNull Collection<? extends PNode> getWalkable(@NotNull Instance instance, @NotNull Set<PNode> visited, @NotNull PNode current, @NotNull Point goal, @NotNull BoundingBox boundingBox) { | ||
Collection<PNode> nearby = new ArrayList<>(); | ||
tempNode = new PNode(0, 0, 0, 0, 0, current); | ||
|
||
int stepSize = (int) Math.max(Math.floor(boundingBox.width() / 2), 1); | ||
if (stepSize < 1) stepSize = 1; | ||
|
||
for (int x = -stepSize; x <= stepSize; ++x) { | ||
for (int z = -stepSize; z <= stepSize; ++z) { | ||
if (x == 0 && z == 0) continue; | ||
double cost = Math.sqrt(x * x + z * z) * 0.98; | ||
|
||
double floorPointX = current.blockX() + 0.5 + x; | ||
double floorPointY = current.y(); | ||
double floorPointZ = current.blockZ() + 0.5 + z; | ||
|
||
var optionalFloorPointY = gravitySnap(instance, floorPointX, floorPointY, floorPointZ, boundingBox, MAX_FALL_DISTANCE); | ||
if (optionalFloorPointY.isEmpty()) continue; | ||
floorPointY = optionalFloorPointY.getAsDouble(); | ||
|
||
var floorPoint = new Vec(floorPointX, floorPointY, floorPointZ); | ||
var nodeWalk = createWalk(instance, floorPoint, boundingBox, cost, current, goal, visited); | ||
|
||
if (nodeWalk != null && !visited.contains(nodeWalk)) nearby.add(nodeWalk); | ||
|
||
for (int i = 1; i <= 1; ++i) { | ||
Point jumpPoint = new Vec(current.blockX() + 0.5 + x, current.y() + i, current.blockZ() + 0.5 + z); | ||
OptionalDouble jumpPointY = gravitySnap(instance, jumpPoint.x(), jumpPoint.y(), jumpPoint.z(), boundingBox, MAX_FALL_DISTANCE); | ||
if (jumpPointY.isEmpty()) continue; | ||
jumpPoint = jumpPoint.withY(jumpPointY.getAsDouble()); | ||
|
||
if (!floorPoint.sameBlock(jumpPoint)) { | ||
var nodeJump = createJump(instance, jumpPoint, boundingBox, cost + 0.8, current, goal, visited); | ||
if (nodeJump != null && !visited.contains(nodeJump)) nearby.add(nodeJump); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return nearby; | ||
} | ||
|
||
@Override | ||
public boolean hasGravitySnap() { | ||
return true; | ||
} | ||
|
||
private PNode createWalk(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set<PNode> closed) { | ||
var snapped = gravitySnap(instance, point.x(), point.y(), point.z(), boundingBox, MAX_FALL_DISTANCE); | ||
|
||
if (snapped.isPresent()) { | ||
var snappedPoint = new Vec(point.x(), snapped.getAsDouble(), point.z()); | ||
|
||
var n = newNode(start, cost, snappedPoint, goal); | ||
if (closed.contains(n)) { | ||
return null; | ||
} | ||
|
||
if (Math.abs(snappedPoint.y() - start.y()) > Vec.EPSILON && snappedPoint.y() < start.y()) { | ||
if (start.y() - snappedPoint.y() > MAX_FALL_DISTANCE) { | ||
return null; | ||
} | ||
if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), snappedPoint.withY(start.y()), boundingBox)) { | ||
return null; | ||
} | ||
n.setType(PNode.NodeType.FALL); | ||
} else { | ||
if (!canMoveTowards(instance, new Vec(start.x(), start.y(), start.z()), snappedPoint, boundingBox)) { | ||
return null; | ||
} | ||
} | ||
|
||
return n; | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
private PNode createJump(Instance instance, Point point, BoundingBox boundingBox, double cost, PNode start, Point goal, Set<PNode> closed) { | ||
if (Math.abs(point.y() - start.y()) < Vec.EPSILON) return null; | ||
if (point.y() - start.y() > 2) return null; | ||
if (point.blockX() != start.blockX() && point.blockZ() != start.blockZ()) return null; | ||
|
||
var n = newNode(start, cost, point, goal); | ||
if (closed.contains(n)) return null; | ||
|
||
if (pointInvalid(instance, point, boundingBox)) return null; | ||
if (pointInvalid(instance, new Vec(start.x(), start.y() + 1, start.z()), boundingBox)) return null; | ||
|
||
n.setType(PNode.NodeType.JUMP); | ||
return n; | ||
} | ||
|
||
private PNode newNode(PNode current, double cost, Point point, Point goal) { | ||
tempNode.setG(current.g() + cost); | ||
tempNode.setH(heuristic(point, goal)); | ||
tempNode.setPoint(point.x(), point.y(), point.z()); | ||
|
||
var newNode = tempNode; | ||
tempNode = new PNode(0, 0, 0, 0, 0, PNode.NodeType.WALK, current); | ||
|
||
return newNode; | ||
} | ||
|
||
@Override | ||
public @NotNull OptionalDouble gravitySnap(@NotNull Instance instance, double pointOrgX, double pointOrgY, double pointOrgZ, @NotNull BoundingBox boundingBox, double maxFall) { | ||
double pointX = (int) Math.floor(pointOrgX) + 0.5; | ||
double pointZ = (int) Math.floor(pointOrgZ) + 0.5; | ||
var res= CollisionUtils.handlePhysics(instance, boundingBox, new Pos(pointX, pointOrgY, pointZ), new Vec(0, -MAX_FALL_DISTANCE, 0), null, true); | ||
return OptionalDouble.of(res.newPosition().y()); | ||
} | ||
|
||
@Override | ||
public boolean canMoveTowards(@NotNull Instance instance, @NotNull Point startOrg, @NotNull Point endOrg, @NotNull BoundingBox boundingBox) { | ||
var end = endOrg.add(0, Vec.EPSILON, 0); | ||
var start = startOrg.add(0, Vec.EPSILON, 0); | ||
|
||
Point diff = end.sub(start); | ||
PhysicsResult res = CollisionUtils.handlePhysics(instance, instance.getChunkAt(start), boundingBox, Pos.fromPoint(start), Vec.fromPoint(diff), null, false); | ||
return !res.collisionZ() && !res.collisionY() && !res.collisionX(); | ||
} | ||
} |