155 lines
5.5 KiB
Java
155 lines
5.5 KiB
Java
package net.minecraft.world.entity.ai.util;
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import java.util.function.Predicate;
|
|
import java.util.function.Supplier;
|
|
import java.util.function.ToDoubleFunction;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.entity.PathfinderMob;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class RandomPos {
|
|
private static final int RANDOM_POS_ATTEMPTS = 10;
|
|
|
|
/**
|
|
* Gets a random position within a certain distance.
|
|
*/
|
|
public static BlockPos generateRandomDirection(RandomSource random, int horizontalDistance, int verticalDistance) {
|
|
int i = random.nextInt(2 * horizontalDistance + 1) - horizontalDistance;
|
|
int j = random.nextInt(2 * verticalDistance + 1) - verticalDistance;
|
|
int k = random.nextInt(2 * horizontalDistance + 1) - horizontalDistance;
|
|
return new BlockPos(i, j, k);
|
|
}
|
|
|
|
/**
|
|
* @return a random (x, y, z) coordinate by picking a point (x, z), adding a random angle, up to a difference of {@code maxAngleDelta}. The y position is randomly chosen from the range {@code [y - yRange, y + yRange]}. Will be {@code null} if the chosen coordinate is outside a distance of {@code maxHorizontalDistance} from the origin.
|
|
*
|
|
* @param maxHorizontalDifference The maximum value in x and z, in absolute value, that could be returned.
|
|
* @param yRange The range plus or minus the y position to be chosen
|
|
* @param y The target y position
|
|
* @param x The x offset to the target position
|
|
* @param z The z offset to the target position
|
|
* @param maxAngleDelta The maximum variance of the returned angle, from the base angle being a vector from (0, 0) to (x, z).
|
|
*/
|
|
@Nullable
|
|
public static BlockPos generateRandomDirectionWithinRadians(
|
|
RandomSource random, int maxHorizontalDifference, int yRange, int y, double x, double z, double maxAngleDelta
|
|
) {
|
|
double d = Mth.atan2(z, x) - (float) (Math.PI / 2);
|
|
double e = d + (2.0F * random.nextFloat() - 1.0F) * maxAngleDelta;
|
|
double f = Math.sqrt(random.nextDouble()) * Mth.SQRT_OF_TWO * maxHorizontalDifference;
|
|
double g = -f * Math.sin(e);
|
|
double h = f * Math.cos(e);
|
|
if (!(Math.abs(g) > maxHorizontalDifference) && !(Math.abs(h) > maxHorizontalDifference)) {
|
|
int i = random.nextInt(2 * yRange + 1) - yRange + y;
|
|
return BlockPos.containing(g, i, h);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the highest above position that is within the provided conditions
|
|
*/
|
|
@VisibleForTesting
|
|
public static BlockPos moveUpOutOfSolid(BlockPos pos, int maxY, Predicate<BlockPos> posPredicate) {
|
|
if (!posPredicate.test(pos)) {
|
|
return pos;
|
|
} else {
|
|
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable().move(Direction.UP);
|
|
|
|
while (mutableBlockPos.getY() <= maxY && posPredicate.test(mutableBlockPos)) {
|
|
mutableBlockPos.move(Direction.UP);
|
|
}
|
|
|
|
return mutableBlockPos.immutable();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds a position above based on the conditions.
|
|
*
|
|
* After it finds the position once, it will continue to move up until aboveSolidAmount is reached or the position is no longer valid
|
|
*/
|
|
@VisibleForTesting
|
|
public static BlockPos moveUpToAboveSolid(BlockPos pos, int aboveSolidAmount, int maxY, Predicate<BlockPos> posPredicate) {
|
|
if (aboveSolidAmount < 0) {
|
|
throw new IllegalArgumentException("aboveSolidAmount was " + aboveSolidAmount + ", expected >= 0");
|
|
} else if (!posPredicate.test(pos)) {
|
|
return pos;
|
|
} else {
|
|
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable().move(Direction.UP);
|
|
|
|
while (mutableBlockPos.getY() <= maxY && posPredicate.test(mutableBlockPos)) {
|
|
mutableBlockPos.move(Direction.UP);
|
|
}
|
|
|
|
int i = mutableBlockPos.getY();
|
|
|
|
while (mutableBlockPos.getY() <= maxY && mutableBlockPos.getY() - i < aboveSolidAmount) {
|
|
mutableBlockPos.move(Direction.UP);
|
|
if (posPredicate.test(mutableBlockPos)) {
|
|
mutableBlockPos.move(Direction.DOWN);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return mutableBlockPos.immutable();
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public static Vec3 generateRandomPos(PathfinderMob mob, Supplier<BlockPos> posSupplier) {
|
|
return generateRandomPos(posSupplier, mob::getWalkTargetValue);
|
|
}
|
|
|
|
/**
|
|
* Tries 10 times to maximize the return value of the position to double function based on the supplied position
|
|
*/
|
|
@Nullable
|
|
public static Vec3 generateRandomPos(Supplier<BlockPos> posSupplier, ToDoubleFunction<BlockPos> toDoubleFunction) {
|
|
double d = Double.NEGATIVE_INFINITY;
|
|
BlockPos blockPos = null;
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
BlockPos blockPos2 = (BlockPos)posSupplier.get();
|
|
if (blockPos2 != null) {
|
|
double e = toDoubleFunction.applyAsDouble(blockPos2);
|
|
if (e > d) {
|
|
d = e;
|
|
blockPos = blockPos2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return blockPos != null ? Vec3.atBottomCenterOf(blockPos) : null;
|
|
}
|
|
|
|
/**
|
|
* @return a random position within range, only if the mob is currently restricted
|
|
*/
|
|
public static BlockPos generateRandomPosTowardDirection(PathfinderMob mob, int range, RandomSource random, BlockPos pos) {
|
|
int i = pos.getX();
|
|
int j = pos.getZ();
|
|
if (mob.hasRestriction() && range > 1) {
|
|
BlockPos blockPos = mob.getRestrictCenter();
|
|
if (mob.getX() > blockPos.getX()) {
|
|
i -= random.nextInt(range / 2);
|
|
} else {
|
|
i += random.nextInt(range / 2);
|
|
}
|
|
|
|
if (mob.getZ() > blockPos.getZ()) {
|
|
j -= random.nextInt(range / 2);
|
|
} else {
|
|
j += random.nextInt(range / 2);
|
|
}
|
|
}
|
|
|
|
return BlockPos.containing(i + mob.getX(), pos.getY() + mob.getY(), j + mob.getZ());
|
|
}
|
|
}
|