minecraft-src/net/minecraft/world/entity/projectile/EyeOfEnder.java
2025-07-04 03:45:38 +03:00

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;
}
}