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