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

219 lines
7.2 KiB
Java

package net.minecraft.world.entity.projectile;
import net.minecraft.nbt.CompoundTag;
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.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
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.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class ThrownTrident extends AbstractArrow {
private static final EntityDataAccessor<Byte> ID_LOYALTY = SynchedEntityData.defineId(ThrownTrident.class, EntityDataSerializers.BYTE);
private static final EntityDataAccessor<Boolean> ID_FOIL = SynchedEntityData.defineId(ThrownTrident.class, EntityDataSerializers.BOOLEAN);
private static final float WATER_INERTIA = 0.99F;
private static final boolean DEFAULT_DEALT_DAMAGE = false;
private boolean dealtDamage = false;
public int clientSideReturnTridentTickCount;
public ThrownTrident(EntityType<? extends ThrownTrident> entityType, Level level) {
super(entityType, level);
}
public ThrownTrident(Level level, LivingEntity shooter, ItemStack pickupItemStack) {
super(EntityType.TRIDENT, shooter, level, pickupItemStack, null);
this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(pickupItemStack));
this.entityData.set(ID_FOIL, pickupItemStack.hasFoil());
}
public ThrownTrident(Level level, double x, double y, double z, ItemStack pickupItemStack) {
super(EntityType.TRIDENT, x, y, z, level, pickupItemStack, pickupItemStack);
this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(pickupItemStack));
this.entityData.set(ID_FOIL, pickupItemStack.hasFoil());
}
@Override
protected void defineSynchedData(Builder builder) {
super.defineSynchedData(builder);
builder.define(ID_LOYALTY, (byte)0);
builder.define(ID_FOIL, false);
}
@Override
public void tick() {
if (this.inGroundTime > 4) {
this.dealtDamage = true;
}
Entity entity = this.getOwner();
int i = this.entityData.get(ID_LOYALTY);
if (i > 0 && (this.dealtDamage || this.isNoPhysics()) && entity != null) {
if (!this.isAcceptibleReturnOwner()) {
if (this.level() instanceof ServerLevel serverLevel && this.pickup == AbstractArrow.Pickup.ALLOWED) {
this.spawnAtLocation(serverLevel, this.getPickupItem(), 0.1F);
}
this.discard();
} else {
if (!(entity instanceof Player) && this.position().distanceTo(entity.getEyePosition()) < entity.getBbWidth() + 1.0) {
this.discard();
return;
}
this.setNoPhysics(true);
Vec3 vec3 = entity.getEyePosition().subtract(this.position());
this.setPosRaw(this.getX(), this.getY() + vec3.y * 0.015 * i, this.getZ());
double d = 0.05 * i;
this.setDeltaMovement(this.getDeltaMovement().scale(0.95).add(vec3.normalize().scale(d)));
if (this.clientSideReturnTridentTickCount == 0) {
this.playSound(SoundEvents.TRIDENT_RETURN, 10.0F, 1.0F);
}
this.clientSideReturnTridentTickCount++;
}
}
super.tick();
}
private boolean isAcceptibleReturnOwner() {
Entity entity = this.getOwner();
return entity == null || !entity.isAlive() ? false : !(entity instanceof ServerPlayer) || !entity.isSpectator();
}
public boolean isFoil() {
return this.entityData.get(ID_FOIL);
}
@Nullable
@Override
protected EntityHitResult findHitEntity(Vec3 startVec, Vec3 endVec) {
return this.dealtDamage ? null : super.findHitEntity(startVec, endVec);
}
@Override
protected void onHitEntity(EntityHitResult result) {
Entity entity = result.getEntity();
float f = 8.0F;
Entity entity2 = this.getOwner();
DamageSource damageSource = this.damageSources().trident(this, (Entity)(entity2 == null ? this : entity2));
if (this.level() instanceof ServerLevel serverLevel) {
f = EnchantmentHelper.modifyDamage(serverLevel, this.getWeaponItem(), entity, damageSource, f);
}
this.dealtDamage = true;
if (entity.hurtOrSimulate(damageSource, f)) {
if (entity.getType() == EntityType.ENDERMAN) {
return;
}
if (this.level() instanceof ServerLevel serverLevel) {
EnchantmentHelper.doPostAttackEffectsWithItemSourceOnBreak(serverLevel, entity, damageSource, this.getWeaponItem(), item -> this.kill(serverLevel));
}
if (entity instanceof LivingEntity livingEntity) {
this.doKnockback(livingEntity, damageSource);
this.doPostHurtEffects(livingEntity);
}
}
this.deflect(ProjectileDeflection.REVERSE, entity, this.getOwner(), false);
this.setDeltaMovement(this.getDeltaMovement().multiply(0.02, 0.2, 0.02));
this.playSound(SoundEvents.TRIDENT_HIT, 1.0F, 1.0F);
}
@Override
protected void hitBlockEnchantmentEffects(ServerLevel level, BlockHitResult hitResult, ItemStack stack) {
Vec3 vec3 = hitResult.getBlockPos().clampLocationWithin(hitResult.getLocation());
EnchantmentHelper.onHitBlock(
level,
stack,
this.getOwner() instanceof LivingEntity livingEntity ? livingEntity : null,
this,
null,
vec3,
level.getBlockState(hitResult.getBlockPos()),
item -> this.kill(level)
);
}
@Override
public ItemStack getWeaponItem() {
return this.getPickupItemStackOrigin();
}
@Override
protected boolean tryPickup(Player player) {
return super.tryPickup(player) || this.isNoPhysics() && this.ownedBy(player) && player.getInventory().add(this.getPickupItem());
}
@Override
protected ItemStack getDefaultPickupItem() {
return new ItemStack(Items.TRIDENT);
}
@Override
protected SoundEvent getDefaultHitGroundSoundEvent() {
return SoundEvents.TRIDENT_HIT_GROUND;
}
@Override
public void playerTouch(Player player) {
if (this.ownedBy(player) || this.getOwner() == null) {
super.playerTouch(player);
}
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.dealtDamage = tag.getBooleanOr("DealtDamage", false);
this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(this.getPickupItemStackOrigin()));
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putBoolean("DealtDamage", this.dealtDamage);
}
private byte getLoyaltyFromItem(ItemStack stack) {
return this.level() instanceof ServerLevel serverLevel
? (byte)Mth.clamp(EnchantmentHelper.getTridentReturnToOwnerAcceleration(serverLevel, stack, this), 0, 127)
: 0;
}
@Override
public void tickDespawn() {
int i = this.entityData.get(ID_LOYALTY);
if (this.pickup != AbstractArrow.Pickup.ALLOWED || i <= 0) {
super.tickDespawn();
}
}
@Override
protected float getWaterInertia() {
return 0.99F;
}
@Override
public boolean shouldRender(double x, double y, double z) {
return true;
}
}