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

238 lines
7.4 KiB
Java

package net.minecraft.world.entity.projectile;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Relative;
import net.minecraft.world.entity.monster.Endermite;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.portal.TeleportTransition;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class ThrownEnderpearl extends ThrowableItemProjectile {
private long ticketTimer = 0L;
public ThrownEnderpearl(EntityType<? extends ThrownEnderpearl> entityType, Level level) {
super(entityType, level);
}
public ThrownEnderpearl(Level level, LivingEntity owner, ItemStack item) {
super(EntityType.ENDER_PEARL, owner, level, item);
}
@Override
protected Item getDefaultItem() {
return Items.ENDER_PEARL;
}
@Override
protected void setOwnerThroughUUID(@Nullable UUID uuid) {
this.deregisterFromCurrentOwner();
super.setOwnerThroughUUID(uuid);
this.registerToCurrentOwner();
}
@Override
public void setOwner(@Nullable Entity owner) {
this.deregisterFromCurrentOwner();
super.setOwner(owner);
this.registerToCurrentOwner();
}
private void deregisterFromCurrentOwner() {
if (this.getOwner() instanceof ServerPlayer serverPlayer) {
serverPlayer.deregisterEnderPearl(this);
}
}
private void registerToCurrentOwner() {
if (this.getOwner() instanceof ServerPlayer serverPlayer) {
serverPlayer.registerEnderPearl(this);
}
}
@Nullable
@Override
protected Entity findOwner(UUID entityUuid) {
if (this.level() instanceof ServerLevel serverLevel) {
Entity entity = super.findOwner(entityUuid);
if (entity != null) {
return entity;
} else {
for (ServerLevel serverLevel2 : serverLevel.getServer().getAllLevels()) {
if (serverLevel2 != serverLevel) {
entity = serverLevel2.getEntity(entityUuid);
if (entity != null) {
return entity;
}
}
}
return null;
}
} else {
return null;
}
}
@Override
protected void onHitEntity(EntityHitResult result) {
super.onHitEntity(result);
result.getEntity().hurt(this.damageSources().thrown(this, this.getOwner()), 0.0F);
}
@Override
protected void onHit(HitResult result) {
super.onHit(result);
for (int i = 0; i < 32; i++) {
this.level()
.addParticle(
ParticleTypes.PORTAL, this.getX(), this.getY() + this.random.nextDouble() * 2.0, this.getZ(), this.random.nextGaussian(), 0.0, this.random.nextGaussian()
);
}
if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved()) {
Entity entity = this.getOwner();
if (entity != null && isAllowedToTeleportOwner(entity, serverLevel)) {
Vec3 vec3 = this.oldPosition();
if (entity instanceof ServerPlayer serverPlayer) {
if (serverPlayer.connection.isAcceptingMessages()) {
if (this.random.nextFloat() < 0.05F && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
Endermite endermite = EntityType.ENDERMITE.create(serverLevel, EntitySpawnReason.TRIGGERED);
if (endermite != null) {
endermite.snapTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot());
serverLevel.addFreshEntity(endermite);
}
}
if (this.isOnPortalCooldown()) {
entity.setPortalCooldown();
}
ServerPlayer serverPlayer2 = serverPlayer.teleport(
new TeleportTransition(serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING)
);
if (serverPlayer2 != null) {
serverPlayer2.resetFallDistance();
serverPlayer2.resetCurrentImpulseContext();
serverPlayer2.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl(), 5.0F);
}
this.playSound(serverLevel, vec3);
}
} else {
Entity entity2 = entity.teleport(
new TeleportTransition(serverLevel, vec3, entity.getDeltaMovement(), entity.getYRot(), entity.getXRot(), TeleportTransition.DO_NOTHING)
);
if (entity2 != null) {
entity2.resetFallDistance();
}
this.playSound(serverLevel, vec3);
}
this.discard();
} else {
this.discard();
}
}
}
private static boolean isAllowedToTeleportOwner(Entity entity, Level level) {
if (entity.level().dimension() == level.dimension()) {
return !(entity instanceof LivingEntity livingEntity) ? entity.isAlive() : livingEntity.isAlive() && !livingEntity.isSleeping();
} else {
return entity.canUsePortal(true);
}
}
@Override
public void tick() {
int i = SectionPos.blockToSectionCoord(this.position().x());
int j = SectionPos.blockToSectionCoord(this.position().z());
Entity entity = this.getOwner();
if (entity instanceof ServerPlayer serverPlayer
&& !entity.isAlive()
&& serverPlayer.serverLevel().getGameRules().getBoolean(GameRules.RULE_ENDER_PEARLS_VANISH_ON_DEATH)) {
this.discard();
} else {
super.tick();
}
if (this.isAlive()) {
BlockPos blockPos = BlockPos.containing(this.position());
if ((--this.ticketTimer <= 0L || i != SectionPos.blockToSectionCoord(blockPos.getX()) || j != SectionPos.blockToSectionCoord(blockPos.getZ()))
&& entity instanceof ServerPlayer serverPlayer2) {
this.ticketTimer = serverPlayer2.registerAndUpdateEnderPearlTicket(this);
}
}
}
private void playSound(Level level, Vec3 pos) {
level.playSound(null, pos.x, pos.y, pos.z, SoundEvents.PLAYER_TELEPORT, SoundSource.PLAYERS);
}
@Nullable
@Override
public Entity teleport(TeleportTransition teleportTransition) {
Entity entity = super.teleport(teleportTransition);
if (entity != null) {
entity.placePortalTicket(BlockPos.containing(entity.position()));
}
return entity;
}
@Override
public boolean canTeleport(Level fromLevel, Level toLevel) {
return fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD && this.getOwner() instanceof ServerPlayer serverPlayer
? super.canTeleport(fromLevel, toLevel) && serverPlayer.seenCredits
: super.canTeleport(fromLevel, toLevel);
}
@Override
protected void onInsideBlock(BlockState state) {
super.onInsideBlock(state);
if (state.is(Blocks.END_GATEWAY) && this.getOwner() instanceof ServerPlayer serverPlayer) {
serverPlayer.onInsideBlock(state);
}
}
@Override
public void onRemoval(Entity.RemovalReason reason) {
if (reason != Entity.RemovalReason.UNLOADED_WITH_PLAYER) {
this.deregisterFromCurrentOwner();
}
super.onRemoval(reason);
}
@Override
public void onAboveBubbleColumn(boolean downwards, BlockPos pos) {
Entity.handleOnAboveBubbleColumn(this, downwards, pos);
}
@Override
public void onInsideBubbleColumn(boolean downwards) {
Entity.handleOnInsideBubbleColumn(this, downwards);
}
}