176 lines
6.3 KiB
Java
176 lines
6.3 KiB
Java
package net.minecraft.world.level.block.entity;
|
|
|
|
import java.util.List;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.particles.ColorParticleOption;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.tags.EntityTypeTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.effect.MobEffectInstance;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.AABB;
|
|
import org.apache.commons.lang3.mutable.MutableInt;
|
|
|
|
public class BellBlockEntity extends BlockEntity {
|
|
private static final int DURATION = 50;
|
|
private static final int GLOW_DURATION = 60;
|
|
private static final int MIN_TICKS_BETWEEN_SEARCHES = 60;
|
|
private static final int MAX_RESONATION_TICKS = 40;
|
|
private static final int TICKS_BEFORE_RESONATION = 5;
|
|
private static final int SEARCH_RADIUS = 48;
|
|
private static final int HEAR_BELL_RADIUS = 32;
|
|
private static final int HIGHLIGHT_RAIDERS_RADIUS = 48;
|
|
private long lastRingTimestamp;
|
|
/**
|
|
* How many ticks the bell has been ringing.
|
|
*/
|
|
public int ticks;
|
|
public boolean shaking;
|
|
public Direction clickDirection;
|
|
private List<LivingEntity> nearbyEntities;
|
|
private boolean resonating;
|
|
/**
|
|
* A tick counter before raiders are revealed. At {@link #TICKS_BEFORE_RESONATION} ticks, the resonation sound is played, and at {@link #MAX_RESONATION_TICKS}, nearby raiders are revealed.
|
|
*/
|
|
private int resonationTicks;
|
|
|
|
public BellBlockEntity(BlockPos pos, BlockState blockState) {
|
|
super(BlockEntityType.BELL, pos, blockState);
|
|
}
|
|
|
|
@Override
|
|
public boolean triggerEvent(int id, int type) {
|
|
if (id == 1) {
|
|
this.updateEntities();
|
|
this.resonationTicks = 0;
|
|
this.clickDirection = Direction.from3DDataValue(type);
|
|
this.ticks = 0;
|
|
this.shaking = true;
|
|
return true;
|
|
} else {
|
|
return super.triggerEvent(id, type);
|
|
}
|
|
}
|
|
|
|
private static void tick(Level level, BlockPos pos, BlockState state, BellBlockEntity blockEntity, BellBlockEntity.ResonationEndAction resonationEndAction) {
|
|
if (blockEntity.shaking) {
|
|
blockEntity.ticks++;
|
|
}
|
|
|
|
if (blockEntity.ticks >= 50) {
|
|
blockEntity.shaking = false;
|
|
blockEntity.ticks = 0;
|
|
}
|
|
|
|
if (blockEntity.ticks >= 5 && blockEntity.resonationTicks == 0 && areRaidersNearby(pos, blockEntity.nearbyEntities)) {
|
|
blockEntity.resonating = true;
|
|
level.playSound(null, pos, SoundEvents.BELL_RESONATE, SoundSource.BLOCKS, 1.0F, 1.0F);
|
|
}
|
|
|
|
if (blockEntity.resonating) {
|
|
if (blockEntity.resonationTicks < 40) {
|
|
blockEntity.resonationTicks++;
|
|
} else {
|
|
resonationEndAction.run(level, pos, blockEntity.nearbyEntities);
|
|
blockEntity.resonating = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void clientTick(Level level, BlockPos pos, BlockState state, BellBlockEntity blockEntity) {
|
|
tick(level, pos, state, blockEntity, BellBlockEntity::showBellParticles);
|
|
}
|
|
|
|
public static void serverTick(Level level, BlockPos pos, BlockState state, BellBlockEntity blockEntity) {
|
|
tick(level, pos, state, blockEntity, BellBlockEntity::makeRaidersGlow);
|
|
}
|
|
|
|
public void onHit(Direction direction) {
|
|
BlockPos blockPos = this.getBlockPos();
|
|
this.clickDirection = direction;
|
|
if (this.shaking) {
|
|
this.ticks = 0;
|
|
} else {
|
|
this.shaking = true;
|
|
}
|
|
|
|
this.level.blockEvent(blockPos, this.getBlockState().getBlock(), 1, direction.get3DDataValue());
|
|
}
|
|
|
|
private void updateEntities() {
|
|
BlockPos blockPos = this.getBlockPos();
|
|
if (this.level.getGameTime() > this.lastRingTimestamp + 60L || this.nearbyEntities == null) {
|
|
this.lastRingTimestamp = this.level.getGameTime();
|
|
AABB aABB = new AABB(blockPos).inflate(48.0);
|
|
this.nearbyEntities = this.level.getEntitiesOfClass(LivingEntity.class, aABB);
|
|
}
|
|
|
|
if (!this.level.isClientSide) {
|
|
for (LivingEntity livingEntity : this.nearbyEntities) {
|
|
if (livingEntity.isAlive() && !livingEntity.isRemoved() && blockPos.closerToCenterThan(livingEntity.position(), 32.0)) {
|
|
livingEntity.getBrain().setMemory(MemoryModuleType.HEARD_BELL_TIME, this.level.getGameTime());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean areRaidersNearby(BlockPos pos, List<LivingEntity> raiders) {
|
|
for (LivingEntity livingEntity : raiders) {
|
|
if (livingEntity.isAlive()
|
|
&& !livingEntity.isRemoved()
|
|
&& pos.closerToCenterThan(livingEntity.position(), 32.0)
|
|
&& livingEntity.getType().is(EntityTypeTags.RAIDERS)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void makeRaidersGlow(Level level, BlockPos pos, List<LivingEntity> raiders) {
|
|
raiders.stream().filter(livingEntity -> isRaiderWithinRange(pos, livingEntity)).forEach(BellBlockEntity::glow);
|
|
}
|
|
|
|
private static void showBellParticles(Level level, BlockPos pos, List<LivingEntity> raiders) {
|
|
MutableInt mutableInt = new MutableInt(16700985);
|
|
int i = (int)raiders.stream().filter(livingEntity -> pos.closerToCenterThan(livingEntity.position(), 48.0)).count();
|
|
raiders.stream()
|
|
.filter(livingEntity -> isRaiderWithinRange(pos, livingEntity))
|
|
.forEach(
|
|
livingEntity -> {
|
|
float f = 1.0F;
|
|
double d = Math.sqrt(
|
|
(livingEntity.getX() - pos.getX()) * (livingEntity.getX() - pos.getX()) + (livingEntity.getZ() - pos.getZ()) * (livingEntity.getZ() - pos.getZ())
|
|
);
|
|
double e = pos.getX() + 0.5F + 1.0 / d * (livingEntity.getX() - pos.getX());
|
|
double g = pos.getZ() + 0.5F + 1.0 / d * (livingEntity.getZ() - pos.getZ());
|
|
int j = Mth.clamp((i - 21) / -2, 3, 15);
|
|
|
|
for (int k = 0; k < j; k++) {
|
|
int l = mutableInt.addAndGet(5);
|
|
level.addParticle(ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, l), e, pos.getY() + 0.5F, g, 0.0, 0.0, 0.0);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
private static boolean isRaiderWithinRange(BlockPos pos, LivingEntity raider) {
|
|
return raider.isAlive() && !raider.isRemoved() && pos.closerToCenterThan(raider.position(), 48.0) && raider.getType().is(EntityTypeTags.RAIDERS);
|
|
}
|
|
|
|
private static void glow(LivingEntity entity) {
|
|
entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60));
|
|
}
|
|
|
|
@FunctionalInterface
|
|
interface ResonationEndAction {
|
|
void run(Level level, BlockPos blockPos, List<LivingEntity> list);
|
|
}
|
|
}
|