201 lines
5.9 KiB
Java
201 lines
5.9 KiB
Java
package net.minecraft.world.entity.projectile;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.NbtOps;
|
|
import net.minecraft.nbt.Tag;
|
|
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.resources.RegistryOps;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.item.ItemEntity;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
public class EyeOfEnder extends Entity implements ItemSupplier {
|
|
private static final float MIN_CAMERA_DISTANCE_SQUARED = 12.25F;
|
|
private static final EntityDataAccessor<ItemStack> DATA_ITEM_STACK = SynchedEntityData.defineId(EyeOfEnder.class, EntityDataSerializers.ITEM_STACK);
|
|
private double tx;
|
|
private double ty;
|
|
private double tz;
|
|
private int life;
|
|
private boolean surviveAfterDeath;
|
|
|
|
public EyeOfEnder(EntityType<? extends EyeOfEnder> entityType, Level level) {
|
|
super(entityType, level);
|
|
}
|
|
|
|
public EyeOfEnder(Level level, double x, double y, double z) {
|
|
this(EntityType.EYE_OF_ENDER, level);
|
|
this.setPos(x, y, z);
|
|
}
|
|
|
|
public void setItem(ItemStack stack) {
|
|
if (stack.isEmpty()) {
|
|
this.getEntityData().set(DATA_ITEM_STACK, this.getDefaultItem());
|
|
} else {
|
|
this.getEntityData().set(DATA_ITEM_STACK, stack.copyWithCount(1));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getItem() {
|
|
return this.getEntityData().get(DATA_ITEM_STACK);
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData(Builder builder) {
|
|
builder.define(DATA_ITEM_STACK, this.getDefaultItem());
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldRenderAtSqrDistance(double distance) {
|
|
if (this.tickCount < 2 && distance < 12.25) {
|
|
return false;
|
|
} else {
|
|
double d = this.getBoundingBox().getSize() * 4.0;
|
|
if (Double.isNaN(d)) {
|
|
d = 4.0;
|
|
}
|
|
|
|
d *= 64.0;
|
|
return distance < d * d;
|
|
}
|
|
}
|
|
|
|
public void signalTo(BlockPos pos) {
|
|
double d = pos.getX();
|
|
int i = pos.getY();
|
|
double e = pos.getZ();
|
|
double f = d - this.getX();
|
|
double g = e - this.getZ();
|
|
double h = Math.sqrt(f * f + g * g);
|
|
if (h > 12.0) {
|
|
this.tx = this.getX() + f / h * 12.0;
|
|
this.tz = this.getZ() + g / h * 12.0;
|
|
this.ty = this.getY() + 8.0;
|
|
} else {
|
|
this.tx = d;
|
|
this.ty = i;
|
|
this.tz = e;
|
|
}
|
|
|
|
this.life = 0;
|
|
this.surviveAfterDeath = this.random.nextInt(5) > 0;
|
|
}
|
|
|
|
@Override
|
|
public void lerpMotion(double x, double y, double z) {
|
|
this.setDeltaMovement(x, y, z);
|
|
if (this.xRotO == 0.0F && this.yRotO == 0.0F) {
|
|
double d = Math.sqrt(x * x + z * z);
|
|
this.setYRot((float)(Mth.atan2(x, z) * 180.0F / (float)Math.PI));
|
|
this.setXRot((float)(Mth.atan2(y, d) * 180.0F / (float)Math.PI));
|
|
this.yRotO = this.getYRot();
|
|
this.xRotO = this.getXRot();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
Vec3 vec3 = this.getDeltaMovement();
|
|
double d = this.getX() + vec3.x;
|
|
double e = this.getY() + vec3.y;
|
|
double f = this.getZ() + vec3.z;
|
|
double g = vec3.horizontalDistance();
|
|
this.setXRot(Projectile.lerpRotation(this.xRotO, (float)(Mth.atan2(vec3.y, g) * 180.0F / (float)Math.PI)));
|
|
this.setYRot(Projectile.lerpRotation(this.yRotO, (float)(Mth.atan2(vec3.x, vec3.z) * 180.0F / (float)Math.PI)));
|
|
if (!this.level().isClientSide) {
|
|
double h = this.tx - d;
|
|
double i = this.tz - f;
|
|
float j = (float)Math.sqrt(h * h + i * i);
|
|
float k = (float)Mth.atan2(i, h);
|
|
double l = Mth.lerp(0.0025, g, (double)j);
|
|
double m = vec3.y;
|
|
if (j < 1.0F) {
|
|
l *= 0.8;
|
|
m *= 0.8;
|
|
}
|
|
|
|
int n = this.getY() < this.ty ? 1 : -1;
|
|
vec3 = new Vec3(Math.cos(k) * l, m + (n - m) * 0.015F, Math.sin(k) * l);
|
|
this.setDeltaMovement(vec3);
|
|
}
|
|
|
|
float o = 0.25F;
|
|
if (this.isInWater()) {
|
|
for (int p = 0; p < 4; p++) {
|
|
this.level().addParticle(ParticleTypes.BUBBLE, d - vec3.x * 0.25, e - vec3.y * 0.25, f - vec3.z * 0.25, vec3.x, vec3.y, vec3.z);
|
|
}
|
|
} else {
|
|
this.level()
|
|
.addParticle(
|
|
ParticleTypes.PORTAL,
|
|
d - vec3.x * 0.25 + this.random.nextDouble() * 0.6 - 0.3,
|
|
e - vec3.y * 0.25 - 0.5,
|
|
f - vec3.z * 0.25 + this.random.nextDouble() * 0.6 - 0.3,
|
|
vec3.x,
|
|
vec3.y,
|
|
vec3.z
|
|
);
|
|
}
|
|
|
|
if (!this.level().isClientSide) {
|
|
this.setPos(d, e, f);
|
|
this.life++;
|
|
if (this.life > 80 && !this.level().isClientSide) {
|
|
this.playSound(SoundEvents.ENDER_EYE_DEATH, 1.0F, 1.0F);
|
|
this.discard();
|
|
if (this.surviveAfterDeath) {
|
|
this.level().addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), this.getItem()));
|
|
} else {
|
|
this.level().levelEvent(2003, this.blockPosition(), 0);
|
|
}
|
|
}
|
|
} else {
|
|
this.setPos(d, e, f);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag tag) {
|
|
RegistryOps<Tag> registryOps = this.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
tag.store("Item", ItemStack.CODEC, registryOps, this.getItem());
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag tag) {
|
|
RegistryOps<Tag> registryOps = this.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
this.setItem((ItemStack)tag.read("Item", ItemStack.CODEC, registryOps).orElse(this.getDefaultItem()));
|
|
}
|
|
|
|
private ItemStack getDefaultItem() {
|
|
return new ItemStack(Items.ENDER_EYE);
|
|
}
|
|
|
|
@Override
|
|
public float getLightLevelDependentMagicValue() {
|
|
return 1.0F;
|
|
}
|
|
|
|
@Override
|
|
public boolean isAttackable() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
|
|
return false;
|
|
}
|
|
}
|