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);
 | |
| 		}
 | |
| 	}
 | |
| }
 |