Fix door stuck nudge, double door pairing/priority, and shelter findShelter Y-scan
This commit is contained in:
@@ -6,6 +6,7 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.DoorHingeSide;
|
||||
import net.minecraft.world.level.pathfinder.Node;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -15,7 +16,7 @@ import java.util.EnumSet;
|
||||
public class EllieDoorInteractGoal extends Goal {
|
||||
private static final int CLOSE_DELAY = 25;
|
||||
private static final double CLOSE_DIST_SQ = 2.0 * 2.0;
|
||||
private static final double STUCK_DELTA = 0.005;
|
||||
private static final int STUCK_TICK_LIMIT = 40;
|
||||
|
||||
private final EllieEntity ellie;
|
||||
private BlockPos doorPos;
|
||||
@@ -24,7 +25,7 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
private int closeTimer;
|
||||
private Vec3 doorStuckPos;
|
||||
private int doorStuckTicks;
|
||||
private boolean stuckNudgeCw;
|
||||
private boolean lastNudgeWasCw;
|
||||
|
||||
public EllieDoorInteractGoal(EllieEntity ellie) {
|
||||
this.ellie = ellie;
|
||||
@@ -57,7 +58,7 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
hasPassed = true;
|
||||
closeTimer = CLOSE_DELAY;
|
||||
} else {
|
||||
checkStuck();
|
||||
checkDoorStuck();
|
||||
}
|
||||
} else if (--closeTimer <= 0) {
|
||||
closeDoor(doorPos);
|
||||
@@ -87,40 +88,39 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
|
||||
hasPassed = false;
|
||||
closeTimer = 0;
|
||||
doorStuckPos = null;
|
||||
doorStuckTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStuck() {
|
||||
private void checkDoorStuck() {
|
||||
Vec3 current = ellie.position();
|
||||
if (doorStuckPos != null) {
|
||||
if (current.distanceToSqr(doorStuckPos) < STUCK_DELTA) {
|
||||
doorStuckTicks++;
|
||||
if (doorStuckTicks > 40) {
|
||||
nudgeDoor();
|
||||
doorStuckTicks = 0;
|
||||
}
|
||||
} else {
|
||||
if (doorStuckPos != null && current.distanceToSqr(doorStuckPos) < 0.005) {
|
||||
doorStuckTicks++;
|
||||
if (doorStuckTicks > STUCK_TICK_LIMIT) {
|
||||
nudgeFromDoor();
|
||||
doorStuckTicks = 0;
|
||||
}
|
||||
} else {
|
||||
doorStuckTicks = 0;
|
||||
}
|
||||
doorStuckPos = current;
|
||||
}
|
||||
|
||||
private void nudgeDoor() {
|
||||
private void nudgeFromDoor() {
|
||||
BlockState state = ellie.level().getBlockState(doorPos);
|
||||
if (!(state.getBlock() instanceof DoorBlock)) return;
|
||||
|
||||
Direction facing = state.getValue(DoorBlock.FACING);
|
||||
Direction nudgeDir = stuckNudgeCw
|
||||
? facing.getClockWise()
|
||||
: facing.getCounterClockWise();
|
||||
stuckNudgeCw = !stuckNudgeCw;
|
||||
Direction nudgeDir = lastNudgeWasCw ? facing.getCounterClockWise() : facing.getClockWise();
|
||||
lastNudgeWasCw = !lastNudgeWasCw;
|
||||
|
||||
ellie.setPos(
|
||||
ellie.getX() + nudgeDir.getStepX() * 0.2,
|
||||
ellie.getY(),
|
||||
ellie.getZ() + nudgeDir.getStepZ() * 0.2
|
||||
);
|
||||
double nx = nudgeDir.getStepX() * 0.125;
|
||||
double nz = nudgeDir.getStepZ() * 0.125;
|
||||
ellie.setPos(ellie.getX() + nx, ellie.getY(), ellie.getZ() + nz);
|
||||
|
||||
Vec3 ahead = Vec3.atBottomCenterOf(doorPos.relative(facing));
|
||||
ellie.getNavigation().moveTo(ahead.x, ahead.y, ahead.z, 0.6);
|
||||
}
|
||||
|
||||
private void openDoor(BlockPos pos, BlockState state) {
|
||||
@@ -149,19 +149,20 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
if (door != null) return door;
|
||||
}
|
||||
}
|
||||
|
||||
BlockPos center = ellie.blockPosition();
|
||||
BlockPos singleDoor = null;
|
||||
for (int dx = -2; dx <= 2; dx++) {
|
||||
for (int dz = -2; dz <= 2; dz++) {
|
||||
for (int dy = -1; dy <= 1; dy++) {
|
||||
BlockPos checkPos = center.offset(dx, dy, dz);
|
||||
if (!checkForDoor(checkPos)) continue;
|
||||
BlockState state = ellie.level().getBlockState(checkPos);
|
||||
if (findPairedDoor(checkPos, state) != null) {
|
||||
return checkPos;
|
||||
}
|
||||
if (singleDoor == null) {
|
||||
singleDoor = checkPos;
|
||||
if (checkForDoor(checkPos)) {
|
||||
if (isDoubleDoor(checkPos)) {
|
||||
return checkPos;
|
||||
}
|
||||
if (singleDoor == null) {
|
||||
singleDoor = checkPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,6 +170,11 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
return singleDoor;
|
||||
}
|
||||
|
||||
private boolean isDoubleDoor(BlockPos pos) {
|
||||
BlockState state = ellie.level().getBlockState(pos);
|
||||
return findPairedDoor(pos, state) != null;
|
||||
}
|
||||
|
||||
private BlockPos resolveDoor(BlockPos pos) {
|
||||
if (checkForDoor(pos)) return pos;
|
||||
if (checkForDoor(pos.above())) return pos.above();
|
||||
@@ -188,12 +194,13 @@ public class EllieDoorInteractGoal extends Goal {
|
||||
|
||||
private BlockPos findPairedDoor(BlockPos pos, BlockState state) {
|
||||
Direction facing = state.getValue(DoorBlock.FACING);
|
||||
DoorHingeSide hinge = state.getValue(DoorBlock.HINGE);
|
||||
for (Direction adj : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos adjPos = pos.relative(adj);
|
||||
BlockState adjState = ellie.level().getBlockState(adjPos);
|
||||
if (adjState.getBlock() instanceof DoorBlock) {
|
||||
Direction adjFacing = adjState.getValue(DoorBlock.FACING);
|
||||
if (adjFacing == facing.getOpposite()) {
|
||||
if (adjState.getValue(DoorBlock.FACING) == facing
|
||||
&& adjState.getValue(DoorBlock.HINGE) != hinge) {
|
||||
return adjPos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class ShelterGoal extends Goal {
|
||||
private final EllieEntity ellie;
|
||||
private BlockPos shelterPos;
|
||||
private static final int SEARCH_RADIUS = 12;
|
||||
private static final double REACH_DIST_SQR = 1.5 * 1.5;
|
||||
private static final double REACH_DIST_SQR = 0.75 * 0.75;
|
||||
|
||||
public ShelterGoal(EllieEntity ellie) {
|
||||
this.ellie = ellie;
|
||||
@@ -23,8 +23,7 @@ public class ShelterGoal extends Goal {
|
||||
if (ellie.tickCount < 20) return false;
|
||||
if (ellie.isSleeping()) return false;
|
||||
if (!ellie.level().isRaining() && !ellie.level().isThundering()) return false;
|
||||
if (!ellie.isInRain()) return false;
|
||||
return true;
|
||||
return ellie.level().isRainingAt(ellie.blockPosition().above());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,10 +37,23 @@ public class ShelterGoal extends Goal {
|
||||
@Override
|
||||
public void tick() {
|
||||
if (shelterPos == null) return;
|
||||
Vec3 target = new Vec3(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5);
|
||||
if (ellie.distanceToSqr(target) < REACH_DIST_SQR) {
|
||||
|
||||
if (!ellie.level().isRainingAt(ellie.blockPosition().above())) {
|
||||
ellie.getNavigation().stop();
|
||||
} else if (ellie.getNavigation().isDone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 target = new Vec3(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5);
|
||||
|
||||
if (ellie.distanceToSqr(target) < REACH_DIST_SQR && ellie.getNavigation().isDone()) {
|
||||
BlockPos deeper = findDeeperShelter();
|
||||
if (deeper != null) {
|
||||
shelterPos = deeper;
|
||||
target = new Vec3(shelterPos.getX() + 0.5, shelterPos.getY(), shelterPos.getZ() + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
if (ellie.getNavigation().isDone()) {
|
||||
ellie.getNavigation().moveTo(target.x, target.y, target.z, 0.6);
|
||||
}
|
||||
}
|
||||
@@ -64,15 +76,15 @@ public class ShelterGoal extends Goal {
|
||||
BlockPos nearest = null;
|
||||
double nearestDist = Double.MAX_VALUE;
|
||||
|
||||
for (int x = -SEARCH_RADIUS; x <= SEARCH_RADIUS; x++) {
|
||||
for (int z = -SEARCH_RADIUS; z <= SEARCH_RADIUS; z++) {
|
||||
for (int dy = 2; dy >= -4; dy--) {
|
||||
mutable.set(entityPos.getX() + x, entityPos.getY() + dy, entityPos.getZ() + z);
|
||||
for (int dx = -SEARCH_RADIUS; dx <= SEARCH_RADIUS; dx++) {
|
||||
for (int dz = -SEARCH_RADIUS; dz <= SEARCH_RADIUS; dz++) {
|
||||
for (int dy = 1; dy >= -4; dy--) {
|
||||
mutable.set(entityPos.getX() + dx, entityPos.getY() + dy, entityPos.getZ() + dz);
|
||||
BlockPos standPos = mutable.above();
|
||||
if (!ellie.level().isRainingAt(standPos)
|
||||
&& ellie.level().getBlockState(standPos).isAir()
|
||||
&& !ellie.level().getBlockState(mutable).isAir()) {
|
||||
double dist = entityPos.distSqr(mutable);
|
||||
if (ellie.level().isEmptyBlock(standPos)
|
||||
&& !ellie.level().getBlockState(mutable).isAir()
|
||||
&& !ellie.level().isRainingAt(standPos)) {
|
||||
double dist = entityPos.distSqr(standPos);
|
||||
if (dist < nearestDist) {
|
||||
nearestDist = dist;
|
||||
nearest = standPos;
|
||||
@@ -84,4 +96,28 @@ public class ShelterGoal extends Goal {
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private BlockPos findDeeperShelter() {
|
||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
BlockPos best = null;
|
||||
double bestScore = 0;
|
||||
|
||||
for (int dx = -2; dx <= 2; dx++) {
|
||||
for (int dz = -2; dz <= 2; dz++) {
|
||||
if (dx == 0 && dz == 0) continue;
|
||||
mutable.set(shelterPos.getX() + dx, shelterPos.getY(), shelterPos.getZ() + dz);
|
||||
BlockPos standPos = mutable.below();
|
||||
if (ellie.level().isEmptyBlock(mutable)
|
||||
&& !ellie.level().getBlockState(standPos).isAir()
|
||||
&& !ellie.level().isRainingAt(mutable)) {
|
||||
double score = Math.abs(dx) + Math.abs(dz);
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
best = mutable.immutable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user