Files
fabled-hearts/src/main/java/me/sashegdev/fabled_hearts/ai/EllieSleepGoal.java
T

180 lines
6.0 KiB
Java

package me.sashegdev.fabled_hearts.ai;
import me.sashegdev.fabled_hearts.entity.ellie.EllieEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.pathfinder.Node;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.phys.Vec3;
import java.util.EnumSet;
public class EllieSleepGoal extends Goal {
private final EllieEntity ellie;
private final int searchRadius;
private BlockPos bedPos;
private int sleepTimer;
private boolean claimed;
private static final int MAX_SLEEP_TICKS = 6000;
private static final double REACH_DIST_SQR = 1.8 * 1.8;
public EllieSleepGoal(EllieEntity ellie, int searchRadius) {
this.ellie = ellie;
this.searchRadius = searchRadius;
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
}
@Override
public boolean canUse() {
if (ellie.isSleeping()) return false;
if (!ellie.level().isNight() && !ellie.isTired()) return false;
bedPos = findBed();
return bedPos != null;
}
private BlockPos findBed() {
BlockPos stored = ellie.getBedPos();
if (stored != null && isFreeBed(stored) && ellie.distanceToSqr(Vec3.atCenterOf(stored)) < 50 * 50) {
return stored;
}
return findNearestBed();
}
@Override
public void start() {
claimed = false;
if (bedPos != null) {
ellie.getNavigation().moveTo(bedPos.getX() + 0.5, bedPos.getY(), bedPos.getZ() + 0.5, 0.6);
}
}
@Override
public void tick() {
if (bedPos == null) return;
BlockState currentState = ellie.level().getBlockState(bedPos);
if (!(currentState.getBlock() instanceof BedBlock)) {
bedPos = null;
return;
}
tryOpenDoor();
double distSqr = ellie.distanceToSqr(Vec3.atCenterOf(bedPos));
if (distSqr < REACH_DIST_SQR) {
ellie.getNavigation().stop();
if (!claimed) {
claimed = ellie.occupyBed(bedPos);
}
if (claimed && !ellie.isSleeping()) {
ellie.setBedSleepPos(bedPos);
}
if (ellie.isSleeping()) {
sleepTimer++;
}
} else {
if (ellie.getNavigation().isDone()) {
ellie.getNavigation().moveTo(bedPos.getX() + 0.5, bedPos.getY(), bedPos.getZ() + 0.5, 0.6);
}
}
}
private void tryOpenDoor() {
Path path = ellie.getNavigation().getPath();
BlockPos entityPos = ellie.blockPosition();
if (path != null) {
for (int i = 0; i < Math.min(4, path.getNodeCount()); i++) {
Node node = path.getNode(i);
BlockPos checkPos = new BlockPos(node.x, node.y, node.z);
if (checkPos.distSqr(entityPos) > 9) break;
BlockState state = ellie.level().getBlockState(checkPos);
if (state.getBlock() instanceof DoorBlock) {
if (!state.getValue(DoorBlock.OPEN)) {
ellie.level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
}
return;
}
}
}
for (int i = 0; i < 3; i++) {
BlockPos checkPos = entityPos.relative(ellie.getDirection(), i);
BlockState state = ellie.level().getBlockState(checkPos);
if (state.getBlock() instanceof DoorBlock) {
if (!state.getValue(DoorBlock.OPEN)) {
ellie.level().setBlock(checkPos, state.setValue(DoorBlock.OPEN, true), 3);
}
return;
}
}
}
@Override
public void stop() {
if (ellie.isSleeping()) {
ellie.wakeUp();
}
sleepTimer = 0;
bedPos = null;
claimed = false;
}
@Override
public boolean canContinueToUse() {
if (bedPos != null) {
BlockState state = ellie.level().getBlockState(bedPos);
if (!state.isBed(ellie.level(), bedPos, null)) return false;
}
if (ellie.isSleeping()) {
if (sleepTimer >= MAX_SLEEP_TICKS) return false;
if (ellie.level().isDay()) return false;
if (ellie.hurtTime > 10) return false;
if (ellie.distanceToSqr(Vec3.atCenterOf(bedPos)) > 16.0) return false;
return true;
}
if (bedPos == null) return false;
if (ellie.hurtTime > 10) return false;
if (ellie.level().isDay() && !ellie.isTired()) return false;
if (!ellie.level().isNight() && !ellie.isTired()) return false;
return true;
}
private BlockPos findNearestBed() {
BlockPos entityPos = ellie.blockPosition();
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
BlockPos nearest = null;
double nearestDist = Double.MAX_VALUE;
for (int x = -searchRadius; x <= searchRadius; x++) {
for (int z = -searchRadius; z <= searchRadius; z++) {
for (int y = -2; y <= 2; y++) {
mutable.set(entityPos.getX() + x, entityPos.getY() + y, entityPos.getZ() + z);
if (isFreeBed(mutable)) {
double dist = entityPos.distSqr(mutable);
if (dist < nearestDist) {
nearestDist = dist;
nearest = mutable.immutable();
}
}
}
}
}
return nearest;
}
private boolean isFreeBed(BlockPos pos) {
BlockState state = ellie.level().getBlockState(pos);
if (!(state.getBlock() instanceof BedBlock)) return false;
if (state.getValue(BedBlock.OCCUPIED)) return false;
return true;
}
}