219 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity.projectile;
 | |
| 
 | |
| 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.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.level.storage.ValueInput;
 | |
| import net.minecraft.world.level.storage.ValueOutput;
 | |
| 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(SynchedEntityData.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
 | |
| 	protected void readAdditionalSaveData(ValueInput input) {
 | |
| 		super.readAdditionalSaveData(input);
 | |
| 		this.dealtDamage = input.getBooleanOr("DealtDamage", false);
 | |
| 		this.entityData.set(ID_LOYALTY, this.getLoyaltyFromItem(this.getPickupItemStackOrigin()));
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 		super.addAdditionalSaveData(output);
 | |
| 		output.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;
 | |
| 	}
 | |
| }
 |