package net.minecraft.world.entity.ai.goal; import com.google.common.collect.Lists; import java.util.EnumSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.BooleanSupplier; import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.PoiTypeTags; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; import net.minecraft.world.entity.ai.util.DefaultRandomPos; import net.minecraft.world.entity.ai.util.GoalUtils; import net.minecraft.world.entity.ai.util.LandRandomPos; import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.pathfinder.Node; import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.Vec3; public class MoveThroughVillageGoal extends Goal { protected final PathfinderMob mob; private final double speedModifier; @Nullable private Path path; private BlockPos poiPos; private final boolean onlyAtNight; private final List visited = Lists.newArrayList(); private final int distanceToPoi; private final BooleanSupplier canDealWithDoors; public MoveThroughVillageGoal(PathfinderMob p_25582_, double p_25583_, boolean p_25584_, int p_25585_, BooleanSupplier p_25586_) { this.mob = p_25582_; this.speedModifier = p_25583_; this.onlyAtNight = p_25584_; this.distanceToPoi = p_25585_; this.canDealWithDoors = p_25586_; this.setFlags(EnumSet.of(Goal.Flag.MOVE)); if (!GoalUtils.hasGroundPathNavigation(p_25582_)) { throw new IllegalArgumentException("Unsupported mob for MoveThroughVillageGoal"); } } @Override public boolean canUse() { if (!GoalUtils.hasGroundPathNavigation(this.mob)) { return false; } else { this.updateVisited(); if (this.onlyAtNight && this.mob.level().isBrightOutside()) { return false; } else { ServerLevel serverlevel = (ServerLevel)this.mob.level(); BlockPos blockpos = this.mob.blockPosition(); if (!serverlevel.isCloseToVillage(blockpos, 6)) { return false; } else { Vec3 vec3 = LandRandomPos.getPos( this.mob, 15, 7, p_217751_ -> { if (!serverlevel.isVillage(p_217751_)) { return Double.NEGATIVE_INFINITY; } else { Optional optional1 = serverlevel.getPoiManager() .find( p_217758_ -> p_217758_.is(PoiTypeTags.VILLAGE), this::hasNotVisited, p_217751_, 10, PoiManager.Occupancy.IS_OCCUPIED ); return optional1.map(p_217754_ -> -p_217754_.distSqr(blockpos)).orElse(Double.NEGATIVE_INFINITY); } } ); if (vec3 == null) { return false; } else { Optional optional = serverlevel.getPoiManager() .find( p_217756_ -> p_217756_.is(PoiTypeTags.VILLAGE), this::hasNotVisited, BlockPos.containing(vec3), 10, PoiManager.Occupancy.IS_OCCUPIED ); if (optional.isEmpty()) { return false; } else { this.poiPos = optional.get().immutable(); GroundPathNavigation groundpathnavigation = (GroundPathNavigation)this.mob.getNavigation(); groundpathnavigation.setCanOpenDoors(this.canDealWithDoors.getAsBoolean()); this.path = groundpathnavigation.createPath(this.poiPos, 0); groundpathnavigation.setCanOpenDoors(true); if (this.path == null) { Vec3 vec31 = DefaultRandomPos.getPosTowards(this.mob, 10, 7, Vec3.atBottomCenterOf(this.poiPos), (float) (Math.PI / 2)); if (vec31 == null) { return false; } groundpathnavigation.setCanOpenDoors(this.canDealWithDoors.getAsBoolean()); this.path = this.mob.getNavigation().createPath(vec31.x, vec31.y, vec31.z, 0); groundpathnavigation.setCanOpenDoors(true); if (this.path == null) { return false; } } for (int i = 0; i < this.path.getNodeCount(); i++) { Node node = this.path.getNode(i); BlockPos blockpos1 = new BlockPos(node.x, node.y + 1, node.z); if (DoorBlock.isWoodenDoor(this.mob.level(), blockpos1)) { this.path = this.mob.getNavigation().createPath(node.x, node.y, node.z, 0); break; } } return this.path != null; } } } } } } @Override public boolean canContinueToUse() { return this.mob.getNavigation().isDone() ? false : !this.poiPos.closerToCenterThan(this.mob.position(), this.mob.getBbWidth() + this.distanceToPoi); } @Override public void start() { this.mob.getNavigation().moveTo(this.path, this.speedModifier); } @Override public void stop() { if (this.mob.getNavigation().isDone() || this.poiPos.closerToCenterThan(this.mob.position(), this.distanceToPoi)) { this.visited.add(this.poiPos); } } private boolean hasNotVisited(BlockPos p_25593_) { for (BlockPos blockpos : this.visited) { if (Objects.equals(p_25593_, blockpos)) { return false; } } return true; } private void updateVisited() { if (this.visited.size() > 15) { this.visited.remove(0); } } }