package net.minecraft.world.entity.boss.enderdragon; import java.util.Optional; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseFireBlock; import net.minecraft.world.level.dimension.end.EndDragonFight; import org.jetbrains.annotations.Nullable; public class EndCrystal extends Entity { private static final EntityDataAccessor> DATA_BEAM_TARGET = SynchedEntityData.defineId( EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS ); private static final EntityDataAccessor DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN); public int time; public EndCrystal(EntityType entityType, Level level) { super(entityType, level); this.blocksBuilding = true; this.time = this.random.nextInt(100000); } public EndCrystal(Level level, double x, double y, double z) { this(EntityType.END_CRYSTAL, level); this.setPos(x, y, z); } @Override protected Entity.MovementEmission getMovementEmission() { return Entity.MovementEmission.NONE; } @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(DATA_BEAM_TARGET, Optional.empty()); builder.define(DATA_SHOW_BOTTOM, true); } @Override public void tick() { this.time++; this.checkInsideBlocks(); this.handlePortal(); if (this.level() instanceof ServerLevel) { BlockPos blockPos = this.blockPosition(); if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockPos).isAir()) { this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos)); } } } @Override protected void addAdditionalSaveData(CompoundTag compound) { if (this.getBeamTarget() != null) { compound.put("beam_target", NbtUtils.writeBlockPos(this.getBeamTarget())); } compound.putBoolean("ShowBottom", this.showsBottom()); } @Override protected void readAdditionalSaveData(CompoundTag compound) { NbtUtils.readBlockPos(compound, "beam_target").ifPresent(this::setBeamTarget); if (compound.contains("ShowBottom", 1)) { this.setShowBottom(compound.getBoolean("ShowBottom")); } } @Override public boolean isPickable() { return true; } @Override public boolean hurt(DamageSource source, float amount) { if (this.isInvulnerableTo(source)) { return false; } else if (source.getEntity() instanceof EnderDragon) { return false; } else { if (!this.isRemoved() && !this.level().isClientSide) { this.remove(Entity.RemovalReason.KILLED); if (!source.is(DamageTypeTags.IS_EXPLOSION)) { DamageSource damageSource = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null; this.level().explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); } this.onDestroyedBy(source); } return true; } } @Override public void kill() { this.onDestroyedBy(this.damageSources().generic()); super.kill(); } private void onDestroyedBy(DamageSource source) { if (this.level() instanceof ServerLevel) { EndDragonFight endDragonFight = ((ServerLevel)this.level()).getDragonFight(); if (endDragonFight != null) { endDragonFight.onCrystalDestroyed(this, source); } } } public void setBeamTarget(@Nullable BlockPos beamTarget) { this.getEntityData().set(DATA_BEAM_TARGET, Optional.ofNullable(beamTarget)); } @Nullable public BlockPos getBeamTarget() { return (BlockPos)this.getEntityData().get(DATA_BEAM_TARGET).orElse(null); } public void setShowBottom(boolean showBottom) { this.getEntityData().set(DATA_SHOW_BOTTOM, showBottom); } public boolean showsBottom() { return this.getEntityData().get(DATA_SHOW_BOTTOM); } @Override public boolean shouldRenderAtSqrDistance(double distance) { return super.shouldRenderAtSqrDistance(distance) || this.getBeamTarget() != null; } @Override public ItemStack getPickResult() { return new ItemStack(Items.END_CRYSTAL); } }