package net.minecraft.world.entity.monster.warden; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.OptionalInt; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; public class WardenSpawnTracker { public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( ExtraCodecs.NON_NEGATIVE_INT.fieldOf("ticks_since_last_warning").orElse(0).forGetter(wardenSpawnTracker -> wardenSpawnTracker.ticksSinceLastWarning), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("warning_level").orElse(0).forGetter(wardenSpawnTracker -> wardenSpawnTracker.warningLevel), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("cooldown_ticks").orElse(0).forGetter(wardenSpawnTracker -> wardenSpawnTracker.cooldownTicks) ) .apply(instance, WardenSpawnTracker::new) ); public static final int MAX_WARNING_LEVEL = 4; private static final double PLAYER_SEARCH_RADIUS = 16.0; private static final int WARNING_CHECK_DIAMETER = 48; private static final int DECREASE_WARNING_LEVEL_EVERY_INTERVAL = 12000; private static final int WARNING_LEVEL_INCREASE_COOLDOWN = 200; private int ticksSinceLastWarning; private int warningLevel; private int cooldownTicks; public WardenSpawnTracker(int ticksSinceLastWarning, int warningLevel, int cooldownTicks) { this.ticksSinceLastWarning = ticksSinceLastWarning; this.warningLevel = warningLevel; this.cooldownTicks = cooldownTicks; } public WardenSpawnTracker() { this(0, 0, 0); } public void tick() { if (this.ticksSinceLastWarning >= 12000) { this.decreaseWarningLevel(); this.ticksSinceLastWarning = 0; } else { this.ticksSinceLastWarning++; } if (this.cooldownTicks > 0) { this.cooldownTicks--; } } public void reset() { this.ticksSinceLastWarning = 0; this.warningLevel = 0; this.cooldownTicks = 0; } public static OptionalInt tryWarn(ServerLevel level, BlockPos pos, ServerPlayer player) { if (hasNearbyWarden(level, pos)) { return OptionalInt.empty(); } else { List list = getNearbyPlayers(level, pos); if (!list.contains(player)) { list.add(player); } if (list.stream().anyMatch(serverPlayer -> (Boolean)serverPlayer.getWardenSpawnTracker().map(WardenSpawnTracker::onCooldown).orElse(false))) { return OptionalInt.empty(); } else { Optional optional = list.stream() .flatMap(serverPlayer -> serverPlayer.getWardenSpawnTracker().stream()) .max(Comparator.comparingInt(WardenSpawnTracker::getWarningLevel)); if (optional.isPresent()) { WardenSpawnTracker wardenSpawnTracker = (WardenSpawnTracker)optional.get(); wardenSpawnTracker.increaseWarningLevel(); list.forEach(serverPlayer -> serverPlayer.getWardenSpawnTracker().ifPresent(wardenSpawnTracker2 -> wardenSpawnTracker2.copyData(wardenSpawnTracker))); return OptionalInt.of(wardenSpawnTracker.warningLevel); } else { return OptionalInt.empty(); } } } } private boolean onCooldown() { return this.cooldownTicks > 0; } private static boolean hasNearbyWarden(ServerLevel level, BlockPos pos) { AABB aABB = AABB.ofSize(Vec3.atCenterOf(pos), 48.0, 48.0, 48.0); return !level.getEntitiesOfClass(Warden.class, aABB).isEmpty(); } private static List getNearbyPlayers(ServerLevel level, BlockPos pos) { Vec3 vec3 = Vec3.atCenterOf(pos); return level.getPlayers(serverPlayer -> !serverPlayer.isSpectator() && serverPlayer.position().closerThan(vec3, 16.0) && serverPlayer.isAlive()); } private void increaseWarningLevel() { if (!this.onCooldown()) { this.ticksSinceLastWarning = 0; this.cooldownTicks = 200; this.setWarningLevel(this.getWarningLevel() + 1); } } private void decreaseWarningLevel() { this.setWarningLevel(this.getWarningLevel() - 1); } public void setWarningLevel(int warningLevel) { this.warningLevel = Mth.clamp(warningLevel, 0, 4); } public int getWarningLevel() { return this.warningLevel; } private void copyData(WardenSpawnTracker other) { this.warningLevel = other.warningLevel; this.cooldownTicks = other.cooldownTicks; this.ticksSinceLastWarning = other.ticksSinceLastWarning; } }