minecraft-src/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
2025-07-04 03:15:13 +03:00

126 lines
5.1 KiB
Java

package net.minecraft.world.level.block.entity;
import com.google.common.annotations.VisibleForTesting;
import net.minecraft.Optionull;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SculkCatalystBlock;
import net.minecraft.world.level.block.SculkSpreader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.BlockPositionSource;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gameevent.GameEventListener;
import net.minecraft.world.level.gameevent.PositionSource;
import net.minecraft.world.level.gameevent.GameEvent.Context;
import net.minecraft.world.level.gameevent.GameEventListener.DeliveryMode;
import net.minecraft.world.level.gameevent.GameEventListener.Provider;
import net.minecraft.world.phys.Vec3;
public class SculkCatalystBlockEntity extends BlockEntity implements Provider<SculkCatalystBlockEntity.CatalystListener> {
private final SculkCatalystBlockEntity.CatalystListener catalystListener;
public SculkCatalystBlockEntity(BlockPos pos, BlockState blockState) {
super(BlockEntityType.SCULK_CATALYST, pos, blockState);
this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(blockState, new BlockPositionSource(pos));
}
public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) {
sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true);
}
@Override
protected void loadAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.catalystListener.sculkSpreader.load(tag);
}
@Override
protected void saveAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
this.catalystListener.sculkSpreader.save(tag);
super.saveAdditional(tag, registries);
}
public SculkCatalystBlockEntity.CatalystListener getListener() {
return this.catalystListener;
}
public static class CatalystListener implements GameEventListener {
public static final int PULSE_TICKS = 8;
final SculkSpreader sculkSpreader;
private final BlockState blockState;
private final PositionSource positionSource;
public CatalystListener(BlockState blockState, PositionSource positionSource) {
this.blockState = blockState;
this.positionSource = positionSource;
this.sculkSpreader = SculkSpreader.createLevelSpreader();
}
@Override
public PositionSource getListenerSource() {
return this.positionSource;
}
@Override
public int getListenerRadius() {
return 8;
}
@Override
public DeliveryMode getDeliveryMode() {
return DeliveryMode.BY_DISTANCE;
}
@Override
public boolean handleGameEvent(ServerLevel level, Holder<GameEvent> gameEvent, Context context, Vec3 pos) {
if (gameEvent.is(GameEvent.ENTITY_DIE) && context.sourceEntity() instanceof LivingEntity livingEntity) {
if (!livingEntity.wasExperienceConsumed()) {
DamageSource damageSource = livingEntity.getLastDamageSource();
int i = livingEntity.getExperienceReward(level, Optionull.map(damageSource, DamageSource::getEntity));
if (livingEntity.shouldDropExperience() && i > 0) {
this.sculkSpreader.addCursors(BlockPos.containing(pos.relative(Direction.UP, 0.5)), i);
this.tryAwardItSpreadsAdvancement(level, livingEntity);
}
livingEntity.skipDropExperience();
this.positionSource.getPosition(level).ifPresent(vec3 -> this.bloom(level, BlockPos.containing(vec3), this.blockState, level.getRandom()));
}
return true;
} else {
return false;
}
}
@VisibleForTesting
public SculkSpreader getSculkSpreader() {
return this.sculkSpreader;
}
private void bloom(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
level.setBlock(pos, state.setValue(SculkCatalystBlock.PULSE, true), 3);
level.scheduleTick(pos, state.getBlock(), 8);
level.sendParticles(ParticleTypes.SCULK_SOUL, pos.getX() + 0.5, pos.getY() + 1.15, pos.getZ() + 0.5, 2, 0.2, 0.0, 0.2, 0.0);
level.playSound(null, pos, SoundEvents.SCULK_CATALYST_BLOOM, SoundSource.BLOCKS, 2.0F, 0.6F + random.nextFloat() * 0.4F);
}
private void tryAwardItSpreadsAdvancement(Level level, LivingEntity entity) {
if (entity.getLastHurtByMob() instanceof ServerPlayer serverPlayer) {
DamageSource damageSource = entity.getLastDamageSource() == null ? level.damageSources().playerAttack(serverPlayer) : entity.getLastDamageSource();
CriteriaTriggers.KILL_MOB_NEAR_SCULK_CATALYST.trigger(serverPlayer, entity, damageSource);
}
}
}
}