228 lines
6 KiB
Java
228 lines
6 KiB
Java
package net.minecraft.world.level.pathfinder;
|
|
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.network.FriendlyByteBuf;
|
|
import net.minecraft.util.VisibleForDebug;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class Path {
|
|
private final List<Node> nodes;
|
|
@Nullable
|
|
private Path.DebugData debugData;
|
|
private int nextNodeIndex;
|
|
private final BlockPos target;
|
|
private final float distToTarget;
|
|
private final boolean reached;
|
|
|
|
public Path(List<Node> nodes, BlockPos target, boolean reached) {
|
|
this.nodes = nodes;
|
|
this.target = target;
|
|
this.distToTarget = nodes.isEmpty() ? Float.MAX_VALUE : ((Node)this.nodes.get(this.nodes.size() - 1)).distanceManhattan(this.target);
|
|
this.reached = reached;
|
|
}
|
|
|
|
/**
|
|
* Directs this path to the next point in its array
|
|
*/
|
|
public void advance() {
|
|
this.nextNodeIndex++;
|
|
}
|
|
|
|
public boolean notStarted() {
|
|
return this.nextNodeIndex <= 0;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if this path has reached the end
|
|
*/
|
|
public boolean isDone() {
|
|
return this.nextNodeIndex >= this.nodes.size();
|
|
}
|
|
|
|
/**
|
|
* Returns the last {@link net.minecraft.world.level.pathfinder.Node} of the Array.
|
|
*/
|
|
@Nullable
|
|
public Node getEndNode() {
|
|
return !this.nodes.isEmpty() ? (Node)this.nodes.get(this.nodes.size() - 1) : null;
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link net.minecraft.world.level.pathfinder.Node} located at the specified index, usually the current one.
|
|
*/
|
|
public Node getNode(int index) {
|
|
return (Node)this.nodes.get(index);
|
|
}
|
|
|
|
public void truncateNodes(int length) {
|
|
if (this.nodes.size() > length) {
|
|
this.nodes.subList(length, this.nodes.size()).clear();
|
|
}
|
|
}
|
|
|
|
public void replaceNode(int index, Node point) {
|
|
this.nodes.set(index, point);
|
|
}
|
|
|
|
public int getNodeCount() {
|
|
return this.nodes.size();
|
|
}
|
|
|
|
public int getNextNodeIndex() {
|
|
return this.nextNodeIndex;
|
|
}
|
|
|
|
public void setNextNodeIndex(int currentPathIndex) {
|
|
this.nextNodeIndex = currentPathIndex;
|
|
}
|
|
|
|
/**
|
|
* Gets the vector of the {@link net.minecraft.world.level.pathfinder.Node} associated with the given index.
|
|
*/
|
|
public Vec3 getEntityPosAtNode(Entity entity, int index) {
|
|
Node node = (Node)this.nodes.get(index);
|
|
double d = node.x + (int)(entity.getBbWidth() + 1.0F) * 0.5;
|
|
double e = node.y;
|
|
double f = node.z + (int)(entity.getBbWidth() + 1.0F) * 0.5;
|
|
return new Vec3(d, e, f);
|
|
}
|
|
|
|
public BlockPos getNodePos(int index) {
|
|
return ((Node)this.nodes.get(index)).asBlockPos();
|
|
}
|
|
|
|
/**
|
|
* @return the current {@code PathEntity} target node as a {@code Vec3D}
|
|
*/
|
|
public Vec3 getNextEntityPos(Entity entity) {
|
|
return this.getEntityPosAtNode(entity, this.nextNodeIndex);
|
|
}
|
|
|
|
public BlockPos getNextNodePos() {
|
|
return ((Node)this.nodes.get(this.nextNodeIndex)).asBlockPos();
|
|
}
|
|
|
|
public Node getNextNode() {
|
|
return (Node)this.nodes.get(this.nextNodeIndex);
|
|
}
|
|
|
|
@Nullable
|
|
public Node getPreviousNode() {
|
|
return this.nextNodeIndex > 0 ? (Node)this.nodes.get(this.nextNodeIndex - 1) : null;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the EntityPath are the same. Non instance related equals.
|
|
*/
|
|
public boolean sameAs(@Nullable Path pathentity) {
|
|
if (pathentity == null) {
|
|
return false;
|
|
} else if (pathentity.nodes.size() != this.nodes.size()) {
|
|
return false;
|
|
} else {
|
|
for (int i = 0; i < this.nodes.size(); i++) {
|
|
Node node = (Node)this.nodes.get(i);
|
|
Node node2 = (Node)pathentity.nodes.get(i);
|
|
if (node.x != node2.x || node.y != node2.y || node.z != node2.z) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public boolean canReach() {
|
|
return this.reached;
|
|
}
|
|
|
|
@VisibleForDebug
|
|
void setDebug(Node[] openSet, Node[] closedSet, Set<Target> targetNodes) {
|
|
this.debugData = new Path.DebugData(openSet, closedSet, targetNodes);
|
|
}
|
|
|
|
@Nullable
|
|
public Path.DebugData debugData() {
|
|
return this.debugData;
|
|
}
|
|
|
|
public void writeToStream(FriendlyByteBuf buffer) {
|
|
if (this.debugData != null && !this.debugData.targetNodes.isEmpty()) {
|
|
buffer.writeBoolean(this.reached);
|
|
buffer.writeInt(this.nextNodeIndex);
|
|
buffer.writeBlockPos(this.target);
|
|
buffer.writeCollection(this.nodes, (friendlyByteBuf, node) -> node.writeToStream(friendlyByteBuf));
|
|
this.debugData.write(buffer);
|
|
}
|
|
}
|
|
|
|
public static Path createFromStream(FriendlyByteBuf buf) {
|
|
boolean bl = buf.readBoolean();
|
|
int i = buf.readInt();
|
|
BlockPos blockPos = buf.readBlockPos();
|
|
List<Node> list = buf.readList(Node::createFromStream);
|
|
Path.DebugData debugData = Path.DebugData.read(buf);
|
|
Path path = new Path(list, blockPos, bl);
|
|
path.debugData = debugData;
|
|
path.nextNodeIndex = i;
|
|
return path;
|
|
}
|
|
|
|
public String toString() {
|
|
return "Path(length=" + this.nodes.size() + ")";
|
|
}
|
|
|
|
public BlockPos getTarget() {
|
|
return this.target;
|
|
}
|
|
|
|
public float getDistToTarget() {
|
|
return this.distToTarget;
|
|
}
|
|
|
|
static Node[] readNodeArray(FriendlyByteBuf buffer) {
|
|
Node[] nodes = new Node[buffer.readVarInt()];
|
|
|
|
for (int i = 0; i < nodes.length; i++) {
|
|
nodes[i] = Node.createFromStream(buffer);
|
|
}
|
|
|
|
return nodes;
|
|
}
|
|
|
|
static void writeNodeArray(FriendlyByteBuf buffer, Node[] nodeArray) {
|
|
buffer.writeVarInt(nodeArray.length);
|
|
|
|
for (Node node : nodeArray) {
|
|
node.writeToStream(buffer);
|
|
}
|
|
}
|
|
|
|
public Path copy() {
|
|
Path path = new Path(this.nodes, this.target, this.reached);
|
|
path.debugData = this.debugData;
|
|
path.nextNodeIndex = this.nextNodeIndex;
|
|
return path;
|
|
}
|
|
|
|
public record DebugData(Node[] openSet, Node[] closedSet, Set<Target> targetNodes) {
|
|
|
|
public void write(FriendlyByteBuf buffer) {
|
|
buffer.writeCollection(this.targetNodes, (friendlyByteBuf, target) -> target.writeToStream(friendlyByteBuf));
|
|
Path.writeNodeArray(buffer, this.openSet);
|
|
Path.writeNodeArray(buffer, this.closedSet);
|
|
}
|
|
|
|
public static Path.DebugData read(FriendlyByteBuf buffer) {
|
|
HashSet<Target> hashSet = buffer.readCollection(HashSet::new, Target::createFromStream);
|
|
Node[] nodes = Path.readNodeArray(buffer);
|
|
Node[] nodes2 = Path.readNodeArray(buffer);
|
|
return new Path.DebugData(nodes, nodes2, hashSet);
|
|
}
|
|
}
|
|
}
|