Code/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java

128 lines
5.8 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
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.HolderLookup;
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.phys.Vec3;
public class SculkCatalystBlockEntity extends BlockEntity implements GameEventListener.Provider<SculkCatalystBlockEntity.CatalystListener> {
private final SculkCatalystBlockEntity.CatalystListener catalystListener;
public SculkCatalystBlockEntity(BlockPos p_222774_, BlockState p_222775_) {
super(BlockEntityType.SCULK_CATALYST, p_222774_, p_222775_);
this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(p_222775_, new BlockPositionSource(p_222774_));
}
public static void serverTick(Level p_222780_, BlockPos p_222781_, BlockState p_222782_, SculkCatalystBlockEntity p_222783_) {
p_222783_.catalystListener.getSculkSpreader().updateCursors(p_222780_, p_222781_, p_222780_.getRandom(), true);
}
@Override
protected void loadAdditional(CompoundTag p_334885_, HolderLookup.Provider p_332157_) {
super.loadAdditional(p_334885_, p_332157_);
this.catalystListener.sculkSpreader.load(p_334885_);
}
@Override
protected void saveAdditional(CompoundTag p_222789_, HolderLookup.Provider p_332461_) {
this.catalystListener.sculkSpreader.save(p_222789_);
super.saveAdditional(p_222789_, p_332461_);
}
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 p_283224_, PositionSource p_283095_) {
this.blockState = p_283224_;
this.positionSource = p_283095_;
this.sculkSpreader = SculkSpreader.createLevelSpreader();
}
@Override
public PositionSource getListenerSource() {
return this.positionSource;
}
@Override
public int getListenerRadius() {
return 8;
}
@Override
public GameEventListener.DeliveryMode getDeliveryMode() {
return GameEventListener.DeliveryMode.BY_DISTANCE;
}
@Override
public boolean handleGameEvent(ServerLevel p_283470_, Holder<GameEvent> p_332335_, GameEvent.Context p_283014_, Vec3 p_282350_) {
if (p_332335_.is(GameEvent.ENTITY_DIE) && p_283014_.sourceEntity() instanceof LivingEntity livingentity) {
if (!livingentity.wasExperienceConsumed()) {
DamageSource damagesource = livingentity.getLastDamageSource();
int i = livingentity.getExperienceReward(p_283470_, Optionull.map(damagesource, DamageSource::getEntity));
if (livingentity.shouldDropExperience() && i > 0) {
this.sculkSpreader.addCursors(BlockPos.containing(p_282350_.relative(Direction.UP, 0.5)), i);
this.tryAwardItSpreadsAdvancement(p_283470_, livingentity);
}
livingentity.skipDropExperience();
this.positionSource
.getPosition(p_283470_)
.ifPresent(p_390969_ -> this.bloom(p_283470_, BlockPos.containing(p_390969_), this.blockState, p_283470_.getRandom()));
}
return true;
} else {
return false;
}
}
@VisibleForTesting
public SculkSpreader getSculkSpreader() {
return this.sculkSpreader;
}
private void bloom(ServerLevel p_281501_, BlockPos p_281448_, BlockState p_281966_, RandomSource p_283606_) {
p_281501_.setBlock(p_281448_, p_281966_.setValue(SculkCatalystBlock.PULSE, true), 3);
p_281501_.scheduleTick(p_281448_, p_281966_.getBlock(), 8);
p_281501_.sendParticles(
ParticleTypes.SCULK_SOUL, p_281448_.getX() + 0.5, p_281448_.getY() + 1.15, p_281448_.getZ() + 0.5, 2, 0.2, 0.0, 0.2, 0.0
);
p_281501_.playSound(null, p_281448_, SoundEvents.SCULK_CATALYST_BLOOM, SoundSource.BLOCKS, 2.0F, 0.6F + p_283606_.nextFloat() * 0.4F);
}
private void tryAwardItSpreadsAdvancement(Level p_281279_, LivingEntity p_281378_) {
if (p_281378_.getLastHurtByMob() instanceof ServerPlayer serverplayer) {
DamageSource damagesource = p_281378_.getLastDamageSource() == null ? p_281279_.damageSources().playerAttack(serverplayer) : p_281378_.getLastDamageSource();
CriteriaTriggers.KILL_MOB_NEAR_SCULK_CATALYST.trigger(serverplayer, p_281378_, damagesource);
}
}
}
}