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.network.syncher.SynchedEntityData.Builder; 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(Builder builder) { builder.define(DATA_BEAM_TARGET, Optional.empty()); builder.define(DATA_SHOW_BOTTOM, true); } @Override public void tick() { this.time++; this.applyEffectsFromBlocks(); 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 tag) { if (this.getBeamTarget() != null) { tag.put("beam_target", NbtUtils.writeBlockPos(this.getBeamTarget())); } tag.putBoolean("ShowBottom", this.showsBottom()); } @Override protected void readAdditionalSaveData(CompoundTag tag) { NbtUtils.readBlockPos(tag, "beam_target").ifPresent(this::setBeamTarget); if (tag.contains("ShowBottom", 1)) { this.setShowBottom(tag.getBoolean("ShowBottom")); } } @Override public boolean isPickable() { return true; } @Override public final boolean hurtClient(DamageSource damageSource) { return this.isInvulnerableToBase(damageSource) ? false : !(damageSource.getEntity() instanceof EnderDragon); } @Override public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { if (this.isInvulnerableToBase(damageSource)) { return false; } else if (damageSource.getEntity() instanceof EnderDragon) { return false; } else { if (!this.isRemoved()) { this.remove(Entity.RemovalReason.KILLED); if (!damageSource.is(DamageTypeTags.IS_EXPLOSION)) { DamageSource damageSource2 = damageSource.getEntity() != null ? this.damageSources().explosion(this, damageSource.getEntity()) : null; level.explode(this, damageSource2, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); } this.onDestroyedBy(level, damageSource); } return true; } } @Override public void kill(ServerLevel level) { this.onDestroyedBy(level, this.damageSources().generic()); super.kill(level); } private void onDestroyedBy(ServerLevel level, DamageSource damageSource) { EndDragonFight endDragonFight = level.getDragonFight(); if (endDragonFight != null) { endDragonFight.onCrystalDestroyed(this, damageSource); } } 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); } }