/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.ImmutableList * com.google.common.collect.ImmutableList$Builder * com.google.common.collect.Lists * com.google.common.collect.Sets * com.mojang.logging.LogUtils * com.mojang.serialization.Codec * it.unimi.dsi.fastutil.doubles.DoubleList * it.unimi.dsi.fastutil.doubles.DoubleListIterator * it.unimi.dsi.fastutil.floats.FloatArraySet * it.unimi.dsi.fastutil.floats.FloatArrays * it.unimi.dsi.fastutil.longs.LongOpenHashSet * it.unimi.dsi.fastutil.longs.LongSet * it.unimi.dsi.fastutil.objects.Object2DoubleArrayMap * it.unimi.dsi.fastutil.objects.Object2DoubleMap * it.unimi.dsi.fastutil.objects.ObjectArrayList * org.jetbrains.annotations.Contract * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.world.entity; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import it.unimi.dsi.fastutil.doubles.DoubleList; import it.unimi.dsi.fastutil.doubles.DoubleListIterator; import it.unimi.dsi.fastutil.floats.FloatArraySet; import it.unimi.dsi.fastutil.floats.FloatArrays; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.Object2DoubleArrayMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.stream.Stream; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.commands.CommandSource; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.RegistryAccess; import net.minecraft.core.SectionPos; import net.minecraft.core.UUIDUtil; import net.minecraft.core.Vec3i; import net.minecraft.core.component.DataComponentGetter; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.BlockParticleOption; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; import net.minecraft.network.protocol.game.VecDeltaCodec; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SyncedDataHolder; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.TicketType; import net.minecraft.server.permissions.PermissionSet; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.BlockTags; import net.minecraft.tags.DamageTypeTags; import net.minecraft.tags.EntityTypeTags; import net.minecraft.tags.FluidTags; import net.minecraft.tags.TagKey; import net.minecraft.util.ARGB; import net.minecraft.util.BlockUtil; import net.minecraft.util.Mth; import net.minecraft.util.ProblemReporter; import net.minecraft.util.RandomSource; import net.minecraft.util.Util; import net.minecraft.util.debug.DebugEntityBlockIntersection; import net.minecraft.util.debug.DebugSubscriptions; import net.minecraft.util.debug.DebugValueSource; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.Nameable; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSources; import net.minecraft.world.entity.EntityAttachment; import net.minecraft.world.entity.EntityAttachments; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.InsideBlockEffectApplier; import net.minecraft.world.entity.InterpolationHandler; import net.minecraft.world.entity.ItemOwner; import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.LightningBolt; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.PositionMoveRotation; import net.minecraft.world.entity.Relative; import net.minecraft.world.entity.SlotAccess; import net.minecraft.world.entity.SlotProvider; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.ProjectileDeflection; import net.minecraft.world.entity.vehicle.AbstractBoat; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.enchantment.EnchantmentEffectComponents; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.equipment.Equippable; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.HoneyBlock; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Portal; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.entity.EntityAccess; import net.minecraft.world.level.entity.EntityInLevelCallback; import net.minecraft.world.level.gameevent.DynamicGameEventListener; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.level.portal.PortalShape; import net.minecraft.world.level.portal.TeleportTransition; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.ScoreHolder; import net.minecraft.world.scores.Team; import net.minecraft.world.waypoints.WaypointTransmitter; import org.jetbrains.annotations.Contract; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public abstract class Entity implements Nameable, EntityAccess, ScoreHolder, SyncedDataHolder, DataComponentGetter, ItemOwner, SlotProvider, DebugValueSource { private static final Logger LOGGER = LogUtils.getLogger(); public static final String TAG_ID = "id"; public static final String TAG_UUID = "UUID"; public static final String TAG_PASSENGERS = "Passengers"; public static final String TAG_DATA = "data"; public static final String TAG_POS = "Pos"; public static final String TAG_MOTION = "Motion"; public static final String TAG_ROTATION = "Rotation"; public static final String TAG_PORTAL_COOLDOWN = "PortalCooldown"; public static final String TAG_NO_GRAVITY = "NoGravity"; public static final String TAG_AIR = "Air"; public static final String TAG_ON_GROUND = "OnGround"; public static final String TAG_FALL_DISTANCE = "fall_distance"; public static final String TAG_FIRE = "Fire"; public static final String TAG_SILENT = "Silent"; public static final String TAG_GLOWING = "Glowing"; public static final String TAG_INVULNERABLE = "Invulnerable"; public static final String TAG_CUSTOM_NAME = "CustomName"; private static final AtomicInteger ENTITY_COUNTER = new AtomicInteger(); public static final int CONTENTS_SLOT_INDEX = 0; public static final int BOARDING_COOLDOWN = 60; public static final int TOTAL_AIR_SUPPLY = 300; public static final int MAX_ENTITY_TAG_COUNT = 1024; private static final Codec> TAG_LIST_CODEC = Codec.STRING.sizeLimitedListOf(1024); public static final float DELTA_AFFECTED_BY_BLOCKS_BELOW_0_2 = 0.2f; public static final double DELTA_AFFECTED_BY_BLOCKS_BELOW_0_5 = 0.500001; public static final double DELTA_AFFECTED_BY_BLOCKS_BELOW_1_0 = 0.999999; public static final int BASE_TICKS_REQUIRED_TO_FREEZE = 140; public static final int FREEZE_HURT_FREQUENCY = 40; public static final int BASE_SAFE_FALL_DISTANCE = 3; private static final AABB INITIAL_AABB = new AABB(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); private static final double WATER_FLOW_SCALE = 0.014; private static final double LAVA_FAST_FLOW_SCALE = 0.007; private static final double LAVA_SLOW_FLOW_SCALE = 0.0023333333333333335; private static final int MAX_BLOCK_ITERATIONS_ALONG_TRAVEL_PER_TICK = 16; private static final double MAX_MOVEMENT_RESETTING_TRACE_DISTANCE = 8.0; private static double viewScale = 1.0; private final EntityType type; private boolean requiresPrecisePosition; private int id = ENTITY_COUNTER.incrementAndGet(); public boolean blocksBuilding; private ImmutableList passengers = ImmutableList.of(); protected int boardingCooldown; private @Nullable Entity vehicle; private Level level; public double xo; public double yo; public double zo; private Vec3 position; private BlockPos blockPosition; private ChunkPos chunkPosition; private Vec3 deltaMovement = Vec3.ZERO; private float yRot; private float xRot; public float yRotO; public float xRotO; private AABB bb = INITIAL_AABB; private boolean onGround; public boolean horizontalCollision; public boolean verticalCollision; public boolean verticalCollisionBelow; public boolean minorHorizontalCollision; public boolean hurtMarked; protected Vec3 stuckSpeedMultiplier = Vec3.ZERO; private @Nullable RemovalReason removalReason; public static final float DEFAULT_BB_WIDTH = 0.6f; public static final float DEFAULT_BB_HEIGHT = 1.8f; public float moveDist; public float flyDist; public double fallDistance; private float nextStep = 1.0f; public double xOld; public double yOld; public double zOld; public boolean noPhysics; protected final RandomSource random = RandomSource.create(); public int tickCount; private int remainingFireTicks; protected boolean wasTouchingWater; protected Object2DoubleMap> fluidHeight = new Object2DoubleArrayMap(2); protected boolean wasEyeInWater; private final Set> fluidOnEyes = new HashSet>(); public int invulnerableTime; protected boolean firstTick = true; protected final SynchedEntityData entityData; protected static final EntityDataAccessor DATA_SHARED_FLAGS_ID = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BYTE); protected static final int FLAG_ONFIRE = 0; private static final int FLAG_SHIFT_KEY_DOWN = 1; private static final int FLAG_SPRINTING = 3; private static final int FLAG_SWIMMING = 4; private static final int FLAG_INVISIBLE = 5; protected static final int FLAG_GLOWING = 6; protected static final int FLAG_FALL_FLYING = 7; private static final EntityDataAccessor DATA_AIR_SUPPLY_ID = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT); private static final EntityDataAccessor> DATA_CUSTOM_NAME = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.OPTIONAL_COMPONENT); private static final EntityDataAccessor DATA_CUSTOM_NAME_VISIBLE = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_SILENT = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_NO_GRAVITY = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); protected static final EntityDataAccessor DATA_POSE = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.POSE); private static final EntityDataAccessor DATA_TICKS_FROZEN = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT); private EntityInLevelCallback levelCallback = EntityInLevelCallback.NULL; private final VecDeltaCodec packetPositionCodec = new VecDeltaCodec(); public boolean needsSync; public @Nullable PortalProcessor portalProcess; private int portalCooldown; private boolean invulnerable; protected UUID uuid = Mth.createInsecureUUID(this.random); protected String stringUUID = this.uuid.toString(); private boolean hasGlowingTag; private final Set tags = Sets.newHashSet(); private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0}; private long pistonDeltasGameTime; private EntityDimensions dimensions; private float eyeHeight; public boolean isInPowderSnow; public boolean wasInPowderSnow; public Optional mainSupportingBlockPos = Optional.empty(); private boolean onGroundNoBlocks = false; private float crystalSoundIntensity; private int lastCrystalSoundPlayTick; private boolean hasVisualFire; private Vec3 lastKnownSpeed = Vec3.ZERO; private @Nullable Vec3 lastKnownPosition; private @Nullable BlockState inBlockState = null; public static final int MAX_MOVEMENTS_HANDELED_PER_TICK = 100; private final ArrayDeque movementThisTick = new ArrayDeque(100); private final List finalMovementsThisTick = new ObjectArrayList(); private final LongSet visitedBlocks = new LongOpenHashSet(); private final InsideBlockEffectApplier.StepBasedCollector insideEffectCollector = new InsideBlockEffectApplier.StepBasedCollector(); private CustomData customData = CustomData.EMPTY; public Entity(EntityType type, Level level) { this.type = type; this.level = level; this.dimensions = type.getDimensions(); this.position = Vec3.ZERO; this.blockPosition = BlockPos.ZERO; this.chunkPosition = ChunkPos.ZERO; SynchedEntityData.Builder entityDataBuilder = new SynchedEntityData.Builder(this); entityDataBuilder.define(DATA_SHARED_FLAGS_ID, (byte)0); entityDataBuilder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply()); entityDataBuilder.define(DATA_CUSTOM_NAME_VISIBLE, false); entityDataBuilder.define(DATA_CUSTOM_NAME, Optional.empty()); entityDataBuilder.define(DATA_SILENT, false); entityDataBuilder.define(DATA_NO_GRAVITY, false); entityDataBuilder.define(DATA_POSE, Pose.STANDING); entityDataBuilder.define(DATA_TICKS_FROZEN, 0); this.defineSynchedData(entityDataBuilder); this.entityData = entityDataBuilder.build(); this.setPos(0.0, 0.0, 0.0); this.eyeHeight = this.dimensions.eyeHeight(); } public boolean isColliding(BlockPos pos, BlockState state) { VoxelShape movedBlockShape = state.getCollisionShape(this.level(), pos, CollisionContext.of(this)).move(pos); return Shapes.joinIsNotEmpty(movedBlockShape, Shapes.create(this.getBoundingBox()), BooleanOp.AND); } public int getTeamColor() { PlayerTeam team = this.getTeam(); if (team != null && ((Team)team).getColor().getColor() != null) { return ((Team)team).getColor().getColor(); } return 0xFFFFFF; } public boolean isSpectator() { return false; } public boolean canInteractWithLevel() { return this.isAlive() && !this.isRemoved() && !this.isSpectator(); } public final void unRide() { if (this.isVehicle()) { this.ejectPassengers(); } if (this.isPassenger()) { this.stopRiding(); } } public void syncPacketPositionCodec(double x, double y, double z) { this.packetPositionCodec.setBase(new Vec3(x, y, z)); } public VecDeltaCodec getPositionCodec() { return this.packetPositionCodec; } public EntityType getType() { return this.type; } public boolean getRequiresPrecisePosition() { return this.requiresPrecisePosition; } public void setRequiresPrecisePosition(boolean requiresPrecisePosition) { this.requiresPrecisePosition = requiresPrecisePosition; } @Override public int getId() { return this.id; } public void setId(int id) { this.id = id; } public Set getTags() { return this.tags; } public boolean addTag(String tag) { if (this.tags.size() >= 1024) { return false; } return this.tags.add(tag); } public boolean removeTag(String tag) { return this.tags.remove(tag); } public void kill(ServerLevel level) { this.remove(RemovalReason.KILLED); this.gameEvent(GameEvent.ENTITY_DIE); } public final void discard() { this.remove(RemovalReason.DISCARDED); } protected abstract void defineSynchedData(SynchedEntityData.Builder var1); public SynchedEntityData getEntityData() { return this.entityData; } public boolean equals(Object obj) { if (obj instanceof Entity) { return ((Entity)obj).id == this.id; } return false; } public int hashCode() { return this.id; } public void remove(RemovalReason reason) { this.setRemoved(reason); } public void onClientRemoval() { } public void onRemoval(RemovalReason reason) { } public void setPose(Pose pose) { this.entityData.set(DATA_POSE, pose); } public Pose getPose() { return this.entityData.get(DATA_POSE); } public boolean hasPose(Pose pose) { return this.getPose() == pose; } public boolean closerThan(Entity other, double distance) { return this.position().closerThan(other.position(), distance); } public boolean closerThan(Entity other, double distanceXZ, double distanceY) { double dx = other.getX() - this.getX(); double dy = other.getY() - this.getY(); double dz = other.getZ() - this.getZ(); return Mth.lengthSquared(dx, dz) < Mth.square(distanceXZ) && Mth.square(dy) < Mth.square(distanceY); } protected void setRot(float yRot, float xRot) { this.setYRot(yRot % 360.0f); this.setXRot(xRot % 360.0f); } public final void setPos(Vec3 pos) { this.setPos(pos.x(), pos.y(), pos.z()); } public void setPos(double x, double y, double z) { this.setPosRaw(x, y, z); this.setBoundingBox(this.makeBoundingBox()); } protected final AABB makeBoundingBox() { return this.makeBoundingBox(this.position); } protected AABB makeBoundingBox(Vec3 position) { return this.dimensions.makeBoundingBox(position); } protected void reapplyPosition() { this.lastKnownPosition = null; this.setPos(this.position.x, this.position.y, this.position.z); } public void turn(double xo, double yo) { float xDelta = (float)yo * 0.15f; float yDelta = (float)xo * 0.15f; this.setXRot(this.getXRot() + xDelta); this.setYRot(this.getYRot() + yDelta); this.setXRot(Mth.clamp(this.getXRot(), -90.0f, 90.0f)); this.xRotO += xDelta; this.yRotO += yDelta; this.xRotO = Mth.clamp(this.xRotO, -90.0f, 90.0f); if (this.vehicle != null) { this.vehicle.onPassengerTurned(this); } } public void updateDataBeforeSync() { } public void tick() { this.baseTick(); } public void baseTick() { ServerLevel serverLevel; ProfilerFiller profiler = Profiler.get(); profiler.push("entityBaseTick"); this.computeSpeed(); this.inBlockState = null; if (this.isPassenger() && this.getVehicle().isRemoved()) { this.stopRiding(); } if (this.boardingCooldown > 0) { --this.boardingCooldown; } this.handlePortal(); if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } this.wasInPowderSnow = this.isInPowderSnow; this.isInPowderSnow = false; this.updateInWaterStateAndDoFluidPushing(); this.updateFluidOnEyes(); this.updateSwimming(); Level level = this.level(); if (level instanceof ServerLevel) { serverLevel = (ServerLevel)level; if (this.remainingFireTicks > 0) { if (this.fireImmune()) { this.clearFire(); } else { if (this.remainingFireTicks % 20 == 0 && !this.isInLava()) { this.hurtServer(serverLevel, this.damageSources().onFire(), 1.0f); } this.setRemainingFireTicks(this.remainingFireTicks - 1); } } } else { this.clearFire(); } if (this.isInLava()) { this.fallDistance *= 0.5; } this.checkBelowWorld(); if (!this.level().isClientSide()) { this.setSharedFlagOnFire(this.remainingFireTicks > 0); } this.firstTick = false; level = this.level(); if (level instanceof ServerLevel) { serverLevel = (ServerLevel)level; if (this instanceof Leashable) { Leashable.tickLeash(serverLevel, (Entity)((Object)((Leashable)((Object)this)))); } } profiler.pop(); } protected void computeSpeed() { if (this.lastKnownPosition == null) { this.lastKnownPosition = this.position(); } this.lastKnownSpeed = this.position().subtract(this.lastKnownPosition); this.lastKnownPosition = this.position(); } public void setSharedFlagOnFire(boolean value) { this.setSharedFlag(0, value || this.hasVisualFire); } public void checkBelowWorld() { if (this.getY() < (double)(this.level().getMinY() - 64)) { this.onBelowWorld(); } } public void setPortalCooldown() { this.portalCooldown = this.getDimensionChangingDelay(); } public void setPortalCooldown(int portalCooldown) { this.portalCooldown = portalCooldown; } public int getPortalCooldown() { return this.portalCooldown; } public boolean isOnPortalCooldown() { return this.portalCooldown > 0; } protected void processPortalCooldown() { if (this.isOnPortalCooldown()) { --this.portalCooldown; } } public void lavaIgnite() { if (this.fireImmune()) { return; } this.igniteForSeconds(15.0f); } public void lavaHurt() { ServerLevel serverLevel; if (this.fireImmune()) { return; } Level level = this.level(); if (level instanceof ServerLevel && this.hurtServer(serverLevel = (ServerLevel)level, this.damageSources().lava(), 4.0f) && this.shouldPlayLavaHurtSound() && !this.isSilent()) { serverLevel.playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.GENERIC_BURN, this.getSoundSource(), 0.4f, 2.0f + this.random.nextFloat() * 0.4f); } } protected boolean shouldPlayLavaHurtSound() { return true; } public final void igniteForSeconds(float numberOfSeconds) { this.igniteForTicks(Mth.floor(numberOfSeconds * 20.0f)); } public void igniteForTicks(int numberOfTicks) { if (this.remainingFireTicks < numberOfTicks) { this.setRemainingFireTicks(numberOfTicks); } this.clearFreeze(); } public void setRemainingFireTicks(int remainingTicks) { this.remainingFireTicks = remainingTicks; } public int getRemainingFireTicks() { return this.remainingFireTicks; } public void clearFire() { this.setRemainingFireTicks(Math.min(0, this.getRemainingFireTicks())); } protected void onBelowWorld() { this.discard(); } public boolean isFree(double xa, double ya, double za) { return this.isFree(this.getBoundingBox().move(xa, ya, za)); } private boolean isFree(AABB box) { return this.level().noCollision(this, box) && !this.level().containsAnyLiquid(box); } public void setOnGround(boolean onGround) { this.onGround = onGround; this.checkSupportingBlock(onGround, null); } public void setOnGroundWithMovement(boolean onGround, Vec3 movement) { this.setOnGroundWithMovement(onGround, this.horizontalCollision, movement); } public void setOnGroundWithMovement(boolean onGround, boolean horizontalCollision, Vec3 movement) { this.onGround = onGround; this.horizontalCollision = horizontalCollision; this.checkSupportingBlock(onGround, movement); } public boolean isSupportedBy(BlockPos pos) { return this.mainSupportingBlockPos.isPresent() && this.mainSupportingBlockPos.get().equals(pos); } protected void checkSupportingBlock(boolean onGround, @Nullable Vec3 movement) { if (onGround) { AABB boundingBox = this.getBoundingBox(); AABB testArea = new AABB(boundingBox.minX, boundingBox.minY - 1.0E-6, boundingBox.minZ, boundingBox.maxX, boundingBox.minY, boundingBox.maxZ); Optional supportingBlock = this.level.findSupportingBlock(this, testArea); if (supportingBlock.isPresent() || this.onGroundNoBlocks) { this.mainSupportingBlockPos = supportingBlock; } else if (movement != null) { AABB onGroundCollisionTestArea = testArea.move(-movement.x, 0.0, -movement.z); supportingBlock = this.level.findSupportingBlock(this, onGroundCollisionTestArea); this.mainSupportingBlockPos = supportingBlock; } this.onGroundNoBlocks = supportingBlock.isEmpty(); } else { this.onGroundNoBlocks = false; if (this.mainSupportingBlockPos.isPresent()) { this.mainSupportingBlockPos = Optional.empty(); } } } public boolean onGround() { return this.onGround; } public void move(MoverType moverType, Vec3 delta) { MovementEmission emission; Vec3 movement; double movementLength; if (this.noPhysics) { this.setPos(this.getX() + delta.x, this.getY() + delta.y, this.getZ() + delta.z); this.horizontalCollision = false; this.verticalCollision = false; this.verticalCollisionBelow = false; this.minorHorizontalCollision = false; return; } if (moverType == MoverType.PISTON && (delta = this.limitPistonMovement(delta)).equals(Vec3.ZERO)) { return; } ProfilerFiller profiler = Profiler.get(); profiler.push("move"); if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7) { if (moverType != MoverType.PISTON) { delta = delta.multiply(this.stuckSpeedMultiplier); } this.stuckSpeedMultiplier = Vec3.ZERO; this.setDeltaMovement(Vec3.ZERO); } if ((movementLength = (movement = this.collide(delta = this.maybeBackOffFromEdge(delta, moverType))).lengthSqr()) > 1.0E-7 || delta.lengthSqr() - movementLength < 1.0E-7) { if (this.fallDistance != 0.0 && movementLength >= 1.0) { double checkDistance = Math.min(movement.length(), 8.0); Vec3 checkTo = this.position().add(movement.normalize().scale(checkDistance)); BlockHitResult hitResult = this.level().clip(new ClipContext(this.position(), checkTo, ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this)); if (hitResult.getType() != HitResult.Type.MISS) { this.resetFallDistance(); } } Vec3 pos = this.position(); Vec3 newPosition = pos.add(movement); this.addMovementThisTick(new Movement(pos, newPosition, delta)); this.setPos(newPosition); } profiler.pop(); profiler.push("rest"); boolean xCollision = !Mth.equal(delta.x, movement.x); boolean zCollision = !Mth.equal(delta.z, movement.z); boolean bl = this.horizontalCollision = xCollision || zCollision; if (Math.abs(delta.y) > 0.0 || this.isLocalInstanceAuthoritative()) { this.verticalCollision = delta.y != movement.y; this.verticalCollisionBelow = this.verticalCollision && delta.y < 0.0; this.setOnGroundWithMovement(this.verticalCollisionBelow, this.horizontalCollision, movement); } this.minorHorizontalCollision = this.horizontalCollision ? this.isHorizontalCollisionMinor(movement) : false; BlockPos effectPos = this.getOnPosLegacy(); BlockState effectState = this.level().getBlockState(effectPos); if (this.isLocalInstanceAuthoritative()) { this.checkFallDamage(movement.y, this.onGround(), effectState, effectPos); } if (this.isRemoved()) { profiler.pop(); return; } if (this.horizontalCollision) { Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(xCollision ? 0.0 : vec3.x, vec3.y, zCollision ? 0.0 : vec3.z); } if (this.canSimulateMovement()) { Block onBlock = effectState.getBlock(); if (delta.y != movement.y) { onBlock.updateEntityMovementAfterFallOn(this.level(), this); } } if ((!this.level().isClientSide() || this.isLocalInstanceAuthoritative()) && (emission = this.getMovementEmission()).emitsAnything() && !this.isPassenger()) { this.applyMovementEmissionAndPlaySound(emission, movement, effectPos, effectState); } float blockSpeedFactor = this.getBlockSpeedFactor(); this.setDeltaMovement(this.getDeltaMovement().multiply(blockSpeedFactor, 1.0, blockSpeedFactor)); profiler.pop(); } private void applyMovementEmissionAndPlaySound(MovementEmission emission, Vec3 clippedMovement, BlockPos effectPos, BlockState effectState) { float moveDistScale = 0.6f; float movedDistance = (float)(clippedMovement.length() * (double)0.6f); float horizontalMovedDistance = (float)(clippedMovement.horizontalDistance() * (double)0.6f); BlockPos supportingPos = this.getOnPos(); BlockState supportingState = this.level().getBlockState(supportingPos); boolean climbing = this.isStateClimbable(supportingState); this.moveDist += climbing ? movedDistance : horizontalMovedDistance; this.flyDist += movedDistance; if (this.moveDist > this.nextStep && !supportingState.isAir()) { boolean onlyEffectStateEmittions = supportingPos.equals(effectPos); boolean producedSideEffects = this.vibrationAndSoundEffectsFromBlock(effectPos, effectState, emission.emitsSounds(), onlyEffectStateEmittions, clippedMovement); if (!onlyEffectStateEmittions) { producedSideEffects |= this.vibrationAndSoundEffectsFromBlock(supportingPos, supportingState, false, emission.emitsEvents(), clippedMovement); } if (producedSideEffects) { this.nextStep = this.nextStep(); } else if (this.isInWater()) { this.nextStep = this.nextStep(); if (emission.emitsSounds()) { this.waterSwimSound(); } if (emission.emitsEvents()) { this.gameEvent(GameEvent.SWIM); } } } else if (supportingState.isAir()) { this.processFlappingMovement(); } } protected void applyEffectsFromBlocks() { this.finalMovementsThisTick.clear(); this.finalMovementsThisTick.addAll(this.movementThisTick); this.movementThisTick.clear(); if (this.finalMovementsThisTick.isEmpty()) { this.finalMovementsThisTick.add(new Movement(this.oldPosition(), this.position())); } else if (this.finalMovementsThisTick.getLast().to.distanceToSqr(this.position()) > 9.999999439624929E-11) { this.finalMovementsThisTick.add(new Movement(this.finalMovementsThisTick.getLast().to, this.position())); } this.applyEffectsFromBlocks(this.finalMovementsThisTick); } private void addMovementThisTick(Movement movement) { if (this.movementThisTick.size() >= 100) { Movement first = this.movementThisTick.removeFirst(); Movement second = this.movementThisTick.removeFirst(); Movement combined = new Movement(first.from(), second.to()); this.movementThisTick.addFirst(combined); } this.movementThisTick.add(movement); } public void removeLatestMovementRecording() { if (!this.movementThisTick.isEmpty()) { this.movementThisTick.removeLast(); } } protected void clearMovementThisTick() { this.movementThisTick.clear(); } public void applyEffectsFromBlocks(Vec3 from, Vec3 to) { this.applyEffectsFromBlocks(List.of(new Movement(from, to))); } private void applyEffectsFromBlocks(List movements) { boolean wasIgnitedThisTick; if (!this.isAffectedByBlocks()) { return; } if (this.onGround()) { BlockPos effectPos = this.getOnPosLegacy(); BlockState effectState = this.level().getBlockState(effectPos); effectState.getBlock().stepOn(this.level(), effectPos, effectState, this); } boolean wasOnFire = this.isOnFire(); boolean wasFreezing = this.isFreezing(); int previousRemainingFireTicks = this.getRemainingFireTicks(); this.checkInsideBlocks(movements, this.insideEffectCollector); this.insideEffectCollector.applyAndClear(this); if (this.isInRain()) { this.clearFire(); } if (wasOnFire && !this.isOnFire() || wasFreezing && !this.isFreezing()) { this.playEntityOnFireExtinguishedSound(); } boolean bl = wasIgnitedThisTick = this.getRemainingFireTicks() > previousRemainingFireTicks; if (!(this.level().isClientSide() || this.isOnFire() || wasIgnitedThisTick)) { this.setRemainingFireTicks(-this.getFireImmuneTicks()); } } protected boolean isAffectedByBlocks() { return !this.isRemoved() && !this.noPhysics; } private boolean isStateClimbable(BlockState state) { return state.is(BlockTags.CLIMBABLE) || state.is(Blocks.POWDER_SNOW); } private boolean vibrationAndSoundEffectsFromBlock(BlockPos pos, BlockState blockState, boolean shouldSound, boolean shouldVibrate, Vec3 clippedMovement) { if (blockState.isAir()) { return false; } boolean isClimbable = this.isStateClimbable(blockState); if ((this.onGround() || isClimbable || this.isCrouching() && clippedMovement.y == 0.0 || this.isOnRails()) && !this.isSwimming()) { if (shouldSound) { this.walkingStepSound(pos, blockState); } if (shouldVibrate) { this.level().gameEvent(GameEvent.STEP, this.position(), GameEvent.Context.of(this, blockState)); } return true; } return false; } protected boolean isHorizontalCollisionMinor(Vec3 movement) { return false; } protected void playEntityOnFireExtinguishedSound() { if (!this.level.isClientSide()) { this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.GENERIC_EXTINGUISH_FIRE, this.getSoundSource(), 0.7f, 1.6f + (this.random.nextFloat() - this.random.nextFloat()) * 0.4f); } } public void extinguishFire() { if (this.isOnFire()) { this.playEntityOnFireExtinguishedSound(); } this.clearFire(); } protected void processFlappingMovement() { if (this.isFlapping()) { this.onFlap(); if (this.getMovementEmission().emitsEvents()) { this.gameEvent(GameEvent.FLAP); } } } @Deprecated public BlockPos getOnPosLegacy() { return this.getOnPos(0.2f); } public BlockPos getBlockPosBelowThatAffectsMyMovement() { return this.getOnPos(0.500001f); } public BlockPos getOnPos() { return this.getOnPos(1.0E-5f); } protected BlockPos getOnPos(float offset) { if (this.mainSupportingBlockPos.isPresent()) { BlockPos getOnPos = this.mainSupportingBlockPos.get(); if (offset > 1.0E-5f) { BlockState belowState = this.level().getBlockState(getOnPos); if ((double)offset <= 0.5 && belowState.is(BlockTags.FENCES) || belowState.is(BlockTags.WALLS) || belowState.getBlock() instanceof FenceGateBlock) { return getOnPos; } return getOnPos.atY(Mth.floor(this.position.y - (double)offset)); } return getOnPos; } int xTruncated = Mth.floor(this.position.x); int yTruncatedBelow = Mth.floor(this.position.y - (double)offset); int zTruncated = Mth.floor(this.position.z); return new BlockPos(xTruncated, yTruncatedBelow, zTruncated); } protected float getBlockJumpFactor() { float jumpFactorHere = this.level().getBlockState(this.blockPosition()).getBlock().getJumpFactor(); float jumpFactorBelow = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getJumpFactor(); return (double)jumpFactorHere == 1.0 ? jumpFactorBelow : jumpFactorHere; } protected float getBlockSpeedFactor() { BlockState state = this.level().getBlockState(this.blockPosition()); float speedFactorHere = state.getBlock().getSpeedFactor(); if (state.is(Blocks.WATER) || state.is(Blocks.BUBBLE_COLUMN)) { return speedFactorHere; } return (double)speedFactorHere == 1.0 ? this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getSpeedFactor() : speedFactorHere; } protected Vec3 maybeBackOffFromEdge(Vec3 delta, MoverType moverType) { return delta; } protected Vec3 limitPistonMovement(Vec3 vec) { if (vec.lengthSqr() <= 1.0E-7) { return vec; } long currentGameTime = this.level().getGameTime(); if (currentGameTime != this.pistonDeltasGameTime) { Arrays.fill(this.pistonDeltas, 0.0); this.pistonDeltasGameTime = currentGameTime; } if (vec.x != 0.0) { double xa = this.applyPistonMovementRestriction(Direction.Axis.X, vec.x); return Math.abs(xa) <= (double)1.0E-5f ? Vec3.ZERO : new Vec3(xa, 0.0, 0.0); } if (vec.y != 0.0) { double ya = this.applyPistonMovementRestriction(Direction.Axis.Y, vec.y); return Math.abs(ya) <= (double)1.0E-5f ? Vec3.ZERO : new Vec3(0.0, ya, 0.0); } if (vec.z != 0.0) { double za = this.applyPistonMovementRestriction(Direction.Axis.Z, vec.z); return Math.abs(za) <= (double)1.0E-5f ? Vec3.ZERO : new Vec3(0.0, 0.0, za); } return Vec3.ZERO; } private double applyPistonMovementRestriction(Direction.Axis axis, double amount) { int ordinal = axis.ordinal(); double min = Mth.clamp(amount + this.pistonDeltas[ordinal], -0.51, 0.51); amount = min - this.pistonDeltas[ordinal]; this.pistonDeltas[ordinal] = min; return amount; } public double getAvailableSpaceBelow(double maxDistance) { AABB aabb = this.getBoundingBox(); AABB below = aabb.setMinY(aabb.minY - maxDistance).setMaxY(aabb.minY); List colliders = Entity.collectAllColliders(this, this.level, below); if (colliders.isEmpty()) { return maxDistance; } return -Shapes.collide(Direction.Axis.Y, aabb, colliders, -maxDistance); } private Vec3 collide(Vec3 movement) { boolean onGroundAfterCollision; AABB aabb = this.getBoundingBox(); List entityColliders = this.level().getEntityCollisions(this, aabb.expandTowards(movement)); Vec3 movementStep = movement.lengthSqr() == 0.0 ? movement : Entity.collideBoundingBox(this, movement, aabb, this.level(), entityColliders); boolean xCollision = movement.x != movementStep.x; boolean yCollision = movement.y != movementStep.y; boolean zCollision = movement.z != movementStep.z; boolean bl = onGroundAfterCollision = yCollision && movement.y < 0.0; if (this.maxUpStep() > 0.0f && (onGroundAfterCollision || this.onGround()) && (xCollision || zCollision)) { float[] candidateStepUpHeights; AABB groundedAABB = onGroundAfterCollision ? aabb.move(0.0, movementStep.y, 0.0) : aabb; AABB stepUpAABB = groundedAABB.expandTowards(movement.x, this.maxUpStep(), movement.z); if (!onGroundAfterCollision) { stepUpAABB = stepUpAABB.expandTowards(0.0, -1.0E-5f, 0.0); } List colliders = Entity.collectColliders(this, this.level, entityColliders, stepUpAABB); float stepHeightToSkip = (float)movementStep.y; for (float candidateStepUpHeight : candidateStepUpHeights = Entity.collectCandidateStepUpHeights(groundedAABB, colliders, this.maxUpStep(), stepHeightToSkip)) { Vec3 stepFromGround = Entity.collideWithShapes(new Vec3(movement.x, candidateStepUpHeight, movement.z), groundedAABB, colliders); if (!(stepFromGround.horizontalDistanceSqr() > movementStep.horizontalDistanceSqr())) continue; double distanceToGround = aabb.minY - groundedAABB.minY; return stepFromGround.subtract(0.0, distanceToGround, 0.0); } } return movementStep; } private static float[] collectCandidateStepUpHeights(AABB boundingBox, List colliders, float maxStepHeight, float stepHeightToSkip) { FloatArraySet candidates = new FloatArraySet(4); block0: for (VoxelShape collider : colliders) { DoubleList coords = collider.getCoords(Direction.Axis.Y); DoubleListIterator doubleListIterator = coords.iterator(); while (doubleListIterator.hasNext()) { double coord = (Double)doubleListIterator.next(); float relativeCoord = (float)(coord - boundingBox.minY); if (relativeCoord < 0.0f || relativeCoord == stepHeightToSkip) continue; if (relativeCoord > maxStepHeight) continue block0; candidates.add(relativeCoord); } } float[] sortedCandidates = candidates.toFloatArray(); FloatArrays.unstableSort((float[])sortedCandidates); return sortedCandidates; } public static Vec3 collideBoundingBox(@Nullable Entity source, Vec3 movement, AABB boundingBox, Level level, List entityColliders) { List colliders = Entity.collectColliders(source, level, entityColliders, boundingBox.expandTowards(movement)); return Entity.collideWithShapes(movement, boundingBox, colliders); } public static List collectAllColliders(@Nullable Entity source, Level level, AABB boundingBox) { List entityColliders = level.getEntityCollisions(source, boundingBox); return Entity.collectColliders(source, level, entityColliders, boundingBox); } private static List collectColliders(@Nullable Entity source, Level level, List entityColliders, AABB boundingBox) { boolean isEntityInsideCloseToBorder; ImmutableList.Builder colliders = ImmutableList.builderWithExpectedSize((int)(entityColliders.size() + 1)); if (!entityColliders.isEmpty()) { colliders.addAll(entityColliders); } WorldBorder worldBorder = level.getWorldBorder(); boolean bl = isEntityInsideCloseToBorder = source != null && worldBorder.isInsideCloseToBorder(source, boundingBox); if (isEntityInsideCloseToBorder) { colliders.add((Object)worldBorder.getCollisionShape()); } colliders.addAll(level.getBlockCollisions(source, boundingBox)); return colliders.build(); } private static Vec3 collideWithShapes(Vec3 movement, AABB boundingBox, List shapes) { if (shapes.isEmpty()) { return movement; } Vec3 resolvedMovement = Vec3.ZERO; for (Direction.Axis axis : Direction.axisStepOrder(movement)) { double axisMovement = movement.get(axis); if (axisMovement == 0.0) continue; double collision = Shapes.collide(axis, boundingBox.move(resolvedMovement), shapes, axisMovement); resolvedMovement = resolvedMovement.with(axis, collision); } return resolvedMovement; } protected float nextStep() { return (int)this.moveDist + 1; } protected SoundEvent getSwimSound() { return SoundEvents.GENERIC_SWIM; } protected SoundEvent getSwimSplashSound() { return SoundEvents.GENERIC_SPLASH; } protected SoundEvent getSwimHighSpeedSplashSound() { return SoundEvents.GENERIC_SPLASH; } private void checkInsideBlocks(List movements, InsideBlockEffectApplier.StepBasedCollector effectCollector) { if (!this.isAffectedByBlocks()) { return; } LongSet visitedBlocks = this.visitedBlocks; for (Movement movement : movements) { Vec3 pos = movement.from; Vec3 delta = movement.to().subtract(movement.from()); int maxMovementIterations = 16; if (movement.axisDependentOriginalMovement().isPresent() && delta.lengthSqr() > 0.0) { for (Direction.Axis axis : Direction.axisStepOrder(movement.axisDependentOriginalMovement().get())) { double axisMove = delta.get(axis); if (axisMove == 0.0) continue; Vec3 to = pos.relative(axis.getPositive(), axisMove); maxMovementIterations -= this.checkInsideBlocks(pos, to, effectCollector, visitedBlocks, maxMovementIterations); pos = to; } } else { maxMovementIterations -= this.checkInsideBlocks(movement.from(), movement.to(), effectCollector, visitedBlocks, 16); } if (maxMovementIterations > 0) continue; this.checkInsideBlocks(movement.to(), movement.to(), effectCollector, visitedBlocks, 1); } visitedBlocks.clear(); } private int checkInsideBlocks(Vec3 from, Vec3 to, InsideBlockEffectApplier.StepBasedCollector effectCollector, LongSet visitedBlocks, int maxMovementIterations) { ServerLevel serverLevel; AABB deflatedBoundingBoxAtTarget = this.makeBoundingBox(to).deflate(1.0E-5f); boolean movedFar = from.distanceToSqr(to) > Mth.square(0.9999900000002526); Level level = this.level; boolean debugEntityBlockIntersections = level instanceof ServerLevel && (serverLevel = (ServerLevel)level).getServer().debugSubscribers().hasAnySubscriberFor(DebugSubscriptions.ENTITY_BLOCK_INTERSECTIONS); AtomicInteger iterations = new AtomicInteger(); BlockGetter.forEachBlockIntersectedBetween(from, to, deflatedBoundingBoxAtTarget, (blockIntersection, iteration) -> { if (!this.isAlive()) { return false; } if (iteration >= maxMovementIterations) { return false; } iterations.set(iteration); BlockState state = this.level().getBlockState(blockIntersection); if (state.isAir()) { if (debugEntityBlockIntersections) { this.debugBlockIntersection((ServerLevel)this.level(), blockIntersection.immutable(), false, false); } return true; } VoxelShape intersectShape = state.getEntityInsideCollisionShape(this.level(), blockIntersection, this); boolean insideBlock = intersectShape == Shapes.block() || this.collidedWithShapeMovingFrom(from, to, intersectShape.move(new Vec3(blockIntersection)).toAabbs()); boolean insideFluid = this.collidedWithFluid(state.getFluidState(), blockIntersection, from, to); if (!insideBlock && !insideFluid || !visitedBlocks.add(blockIntersection.asLong())) { return true; } if (insideBlock) { try { boolean isPrecise = movedFar || deflatedBoundingBoxAtTarget.intersects(blockIntersection); effectCollector.advanceStep(iteration); state.entityInside(this.level(), blockIntersection, this, effectCollector, isPrecise); this.onInsideBlock(state); } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, "Colliding entity with block"); CrashReportCategory category = report.addCategory("Block being collided with"); CrashReportCategory.populateBlockDetails(category, this.level(), blockIntersection, state); CrashReportCategory entityCategory = report.addCategory("Entity being checked for collision"); this.fillCrashReportCategory(entityCategory); throw new ReportedException(report); } } if (insideFluid) { effectCollector.advanceStep(iteration); state.getFluidState().entityInside(this.level(), blockIntersection, this, effectCollector); } if (debugEntityBlockIntersections) { this.debugBlockIntersection((ServerLevel)this.level(), blockIntersection.immutable(), insideBlock, insideFluid); } return true; }); return iterations.get() + 1; } private void debugBlockIntersection(ServerLevel level, BlockPos pos, boolean insideBlock, boolean insideFluid) { DebugEntityBlockIntersection type = insideFluid ? DebugEntityBlockIntersection.IN_FLUID : (insideBlock ? DebugEntityBlockIntersection.IN_BLOCK : DebugEntityBlockIntersection.IN_AIR); level.debugSynchronizers().sendBlockValue(pos, DebugSubscriptions.ENTITY_BLOCK_INTERSECTIONS, type); } public boolean collidedWithFluid(FluidState fluidState, BlockPos blockPos, Vec3 from, Vec3 to) { AABB fluidAABB = fluidState.getAABB(this.level(), blockPos); return fluidAABB != null && this.collidedWithShapeMovingFrom(from, to, List.of(fluidAABB)); } public boolean collidedWithShapeMovingFrom(Vec3 from, Vec3 to, List aabbs) { AABB boundingBoxAtFrom = this.makeBoundingBox(from); Vec3 travelVector = to.subtract(from); return boundingBoxAtFrom.collidedAlongVector(travelVector, aabbs); } protected void onInsideBlock(BlockState state) { } public BlockPos adjustSpawnLocation(ServerLevel level, BlockPos spawnSuggestion) { BlockPos spawnBlockPos = level.getRespawnData().pos(); Vec3 spawnPos = spawnBlockPos.getCenter(); int spawnHeight = level.getChunkAt(spawnBlockPos).getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, spawnBlockPos.getX(), spawnBlockPos.getZ()) + 1; return BlockPos.containing(spawnPos.x, spawnHeight, spawnPos.z); } public void gameEvent(Holder event, @Nullable Entity sourceEntity) { this.level().gameEvent(sourceEntity, event, this.position); } public void gameEvent(Holder event) { this.gameEvent(event, this); } private void walkingStepSound(BlockPos onPos, BlockState onState) { this.playStepSound(onPos, onState); if (this.shouldPlayAmethystStepSound(onState)) { this.playAmethystStepSound(); } } protected void waterSwimSound() { Entity entity = Objects.requireNonNullElse(this.getControllingPassenger(), this); float volumeModifier = entity == this ? 0.35f : 0.4f; Vec3 deltaMovement = entity.getDeltaMovement(); float speed = Math.min(1.0f, (float)Math.sqrt(deltaMovement.x * deltaMovement.x * (double)0.2f + deltaMovement.y * deltaMovement.y + deltaMovement.z * deltaMovement.z * (double)0.2f) * volumeModifier); this.playSwimSound(speed); } protected BlockPos getPrimaryStepSoundBlockPos(BlockPos affectingPos) { BlockPos abovePos = affectingPos.above(); BlockState aboveState = this.level().getBlockState(abovePos); if (aboveState.is(BlockTags.INSIDE_STEP_SOUND_BLOCKS) || aboveState.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS)) { return abovePos; } return affectingPos; } protected void playCombinationStepSounds(BlockState primaryStepSound, BlockState secondaryStepSound) { SoundType primaryStepSoundType = primaryStepSound.getSoundType(); this.playSound(primaryStepSoundType.getStepSound(), primaryStepSoundType.getVolume() * 0.15f, primaryStepSoundType.getPitch()); this.playMuffledStepSound(secondaryStepSound); } protected void playMuffledStepSound(BlockState blockState) { SoundType secondaryStepSoundType = blockState.getSoundType(); this.playSound(secondaryStepSoundType.getStepSound(), secondaryStepSoundType.getVolume() * 0.05f, secondaryStepSoundType.getPitch() * 0.8f); } protected void playStepSound(BlockPos pos, BlockState blockState) { SoundType soundType = blockState.getSoundType(); this.playSound(soundType.getStepSound(), soundType.getVolume() * 0.15f, soundType.getPitch()); } private boolean shouldPlayAmethystStepSound(BlockState affectingState) { return affectingState.is(BlockTags.CRYSTAL_SOUND_BLOCKS) && this.tickCount >= this.lastCrystalSoundPlayTick + 20; } private void playAmethystStepSound() { this.crystalSoundIntensity *= (float)Math.pow(0.997, this.tickCount - this.lastCrystalSoundPlayTick); this.crystalSoundIntensity = Math.min(1.0f, this.crystalSoundIntensity + 0.07f); float pitch = 0.5f + this.crystalSoundIntensity * this.random.nextFloat() * 1.2f; float volume = 0.1f + this.crystalSoundIntensity * 1.2f; this.playSound(SoundEvents.AMETHYST_BLOCK_CHIME, volume, pitch); this.lastCrystalSoundPlayTick = this.tickCount; } protected void playSwimSound(float volume) { this.playSound(this.getSwimSound(), volume, 1.0f + (this.random.nextFloat() - this.random.nextFloat()) * 0.4f); } protected void onFlap() { } protected boolean isFlapping() { return false; } public void playSound(SoundEvent sound, float volume, float pitch) { if (!this.isSilent()) { this.level().playSound(null, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), volume, pitch); } } public void playSound(SoundEvent sound) { if (!this.isSilent()) { this.playSound(sound, 1.0f, 1.0f); } } public boolean isSilent() { return this.entityData.get(DATA_SILENT); } public void setSilent(boolean silent) { this.entityData.set(DATA_SILENT, silent); } public boolean isNoGravity() { return this.entityData.get(DATA_NO_GRAVITY); } public void setNoGravity(boolean noGravity) { this.entityData.set(DATA_NO_GRAVITY, noGravity); } protected double getDefaultGravity() { return 0.0; } public final double getGravity() { return this.isNoGravity() ? 0.0 : this.getDefaultGravity(); } protected void applyGravity() { double gravity = this.getGravity(); if (gravity != 0.0) { this.setDeltaMovement(this.getDeltaMovement().add(0.0, -gravity, 0.0)); } } protected MovementEmission getMovementEmission() { return MovementEmission.ALL; } public boolean dampensVibrations() { return false; } public final void doCheckFallDamage(double xa, double ya, double za, boolean onGround) { if (this.touchingUnloadedChunk()) { return; } this.checkSupportingBlock(onGround, new Vec3(xa, ya, za)); BlockPos pos = this.getOnPosLegacy(); BlockState state = this.level().getBlockState(pos); this.checkFallDamage(ya, onGround, state, pos); } protected void checkFallDamage(double ya, boolean onGround, BlockState onState, BlockPos pos) { if (!this.isInWater() && ya < 0.0) { this.fallDistance -= (double)((float)ya); } if (onGround) { if (this.fallDistance > 0.0) { onState.getBlock().fallOn(this.level(), onState, pos, this, this.fallDistance); this.level().gameEvent(GameEvent.HIT_GROUND, this.position, GameEvent.Context.of(this, this.mainSupportingBlockPos.map(blockPos -> this.level().getBlockState((BlockPos)blockPos)).orElse(onState))); } this.resetFallDistance(); } } public boolean fireImmune() { return this.getType().fireImmune(); } public boolean causeFallDamage(double fallDistance, float damageModifier, DamageSource damageSource) { if (this.type.is(EntityTypeTags.FALL_DAMAGE_IMMUNE)) { return false; } this.propagateFallToPassengers(fallDistance, damageModifier, damageSource); return false; } protected void propagateFallToPassengers(double fallDistance, float damageModifier, DamageSource damageSource) { if (this.isVehicle()) { for (Entity passenger : this.getPassengers()) { passenger.causeFallDamage(fallDistance, damageModifier, damageSource); } } } public boolean isInWater() { return this.wasTouchingWater; } boolean isInRain() { BlockPos pos = this.blockPosition(); return this.level().isRainingAt(pos) || this.level().isRainingAt(BlockPos.containing(pos.getX(), this.getBoundingBox().maxY, pos.getZ())); } public boolean isInWaterOrRain() { return this.isInWater() || this.isInRain(); } public boolean isInLiquid() { return this.isInWater() || this.isInLava(); } public boolean isUnderWater() { return this.wasEyeInWater && this.isInWater(); } public boolean isInShallowWater() { return this.isInWater() && !this.isUnderWater(); } public boolean isInClouds() { if (ARGB.alpha(this.level.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_COLOR, this.position())) == 0) { return false; } float cloudBottom = this.level.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_HEIGHT, this.position()).floatValue(); if (this.getY() + (double)this.getBbHeight() < (double)cloudBottom) { return false; } float cloudTop = cloudBottom + 4.0f; return this.getY() <= (double)cloudTop; } public void updateSwimming() { if (this.isSwimming()) { this.setSwimming(this.isSprinting() && this.isInWater() && !this.isPassenger()); } else { this.setSwimming(this.isSprinting() && this.isUnderWater() && !this.isPassenger() && this.level().getFluidState(this.blockPosition).is(FluidTags.WATER)); } } protected boolean updateInWaterStateAndDoFluidPushing() { this.fluidHeight.clear(); this.updateInWaterStateAndDoWaterCurrentPushing(); double lavaFlowScale = this.level.environmentAttributes().getDimensionValue(EnvironmentAttributes.FAST_LAVA) != false ? 0.007 : 0.0023333333333333335; boolean isInLava = this.updateFluidHeightAndDoFluidPushing(FluidTags.LAVA, lavaFlowScale); return this.isInWater() || isInLava; } void updateInWaterStateAndDoWaterCurrentPushing() { AbstractBoat boat; Entity entity = this.getVehicle(); if (entity instanceof AbstractBoat && !(boat = (AbstractBoat)entity).isUnderWater()) { this.wasTouchingWater = false; } else if (this.updateFluidHeightAndDoFluidPushing(FluidTags.WATER, 0.014)) { if (!this.wasTouchingWater && !this.firstTick) { this.doWaterSplashEffect(); } this.resetFallDistance(); this.wasTouchingWater = true; } else { this.wasTouchingWater = false; } } private void updateFluidOnEyes() { AbstractBoat boat; this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER); this.fluidOnEyes.clear(); double eyeY = this.getEyeY(); Entity vehicle = this.getVehicle(); if (vehicle instanceof AbstractBoat && !(boat = (AbstractBoat)vehicle).isUnderWater() && boat.getBoundingBox().maxY >= eyeY && boat.getBoundingBox().minY <= eyeY) { return; } BlockPos pos = BlockPos.containing(this.getX(), eyeY, this.getZ()); FluidState fluidState = this.level().getFluidState(pos); double blockFluidHeight = (float)pos.getY() + fluidState.getHeight(this.level(), pos); if (blockFluidHeight > eyeY) { fluidState.getTags().forEach(this.fluidOnEyes::add); } } protected void doWaterSplashEffect() { double zo; double xo; Entity entity = Objects.requireNonNullElse(this.getControllingPassenger(), this); float volumeModifier = entity == this ? 0.2f : 0.9f; Vec3 movement = entity.getDeltaMovement(); float speed = Math.min(1.0f, (float)Math.sqrt(movement.x * movement.x * (double)0.2f + movement.y * movement.y + movement.z * movement.z * (double)0.2f) * volumeModifier); if (speed < 0.25f) { this.playSound(this.getSwimSplashSound(), speed, 1.0f + (this.random.nextFloat() - this.random.nextFloat()) * 0.4f); } else { this.playSound(this.getSwimHighSpeedSplashSound(), speed, 1.0f + (this.random.nextFloat() - this.random.nextFloat()) * 0.4f); } float yt = Mth.floor(this.getY()); int i = 0; while ((float)i < 1.0f + this.dimensions.width() * 20.0f) { xo = (this.random.nextDouble() * 2.0 - 1.0) * (double)this.dimensions.width(); zo = (this.random.nextDouble() * 2.0 - 1.0) * (double)this.dimensions.width(); this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + xo, yt + 1.0f, this.getZ() + zo, movement.x, movement.y - this.random.nextDouble() * (double)0.2f, movement.z); ++i; } i = 0; while ((float)i < 1.0f + this.dimensions.width() * 20.0f) { xo = (this.random.nextDouble() * 2.0 - 1.0) * (double)this.dimensions.width(); zo = (this.random.nextDouble() * 2.0 - 1.0) * (double)this.dimensions.width(); this.level().addParticle(ParticleTypes.SPLASH, this.getX() + xo, yt + 1.0f, this.getZ() + zo, movement.x, movement.y, movement.z); ++i; } this.gameEvent(GameEvent.SPLASH); } @Deprecated protected BlockState getBlockStateOnLegacy() { return this.level().getBlockState(this.getOnPosLegacy()); } public BlockState getBlockStateOn() { return this.level().getBlockState(this.getOnPos()); } public boolean canSpawnSprintParticle() { return this.isSprinting() && !this.isInWater() && !this.isSpectator() && !this.isCrouching() && !this.isInLava() && this.isAlive(); } protected void spawnSprintParticle() { BlockPos pos = this.getOnPosLegacy(); BlockState blockState = this.level().getBlockState(pos); if (blockState.getRenderShape() != RenderShape.INVISIBLE) { Vec3 movement = this.getDeltaMovement(); BlockPos entityPosition = this.blockPosition(); double x = this.getX() + (this.random.nextDouble() - 0.5) * (double)this.dimensions.width(); double z = this.getZ() + (this.random.nextDouble() - 0.5) * (double)this.dimensions.width(); if (entityPosition.getX() != pos.getX()) { x = Mth.clamp(x, (double)pos.getX(), (double)pos.getX() + 1.0); } if (entityPosition.getZ() != pos.getZ()) { z = Mth.clamp(z, (double)pos.getZ(), (double)pos.getZ() + 1.0); } this.level().addParticle(new BlockParticleOption(ParticleTypes.BLOCK, blockState), x, this.getY() + 0.1, z, movement.x * -4.0, 1.5, movement.z * -4.0); } } public boolean isEyeInFluid(TagKey type) { return this.fluidOnEyes.contains(type); } public boolean isInLava() { return !this.firstTick && this.fluidHeight.getDouble(FluidTags.LAVA) > 0.0; } public void moveRelative(float speed, Vec3 input) { Vec3 delta = Entity.getInputVector(input, speed, this.getYRot()); this.setDeltaMovement(this.getDeltaMovement().add(delta)); } protected static Vec3 getInputVector(Vec3 input, float speed, float yRot) { double length = input.lengthSqr(); if (length < 1.0E-7) { return Vec3.ZERO; } Vec3 movement = (length > 1.0 ? input.normalize() : input).scale(speed); float sin = Mth.sin(yRot * ((float)Math.PI / 180)); float cos = Mth.cos(yRot * ((float)Math.PI / 180)); return new Vec3(movement.x * (double)cos - movement.z * (double)sin, movement.y, movement.z * (double)cos + movement.x * (double)sin); } @Deprecated public float getLightLevelDependentMagicValue() { if (this.level().hasChunkAt(this.getBlockX(), this.getBlockZ())) { return this.level().getLightLevelDependentMagicValue(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())); } return 0.0f; } public void absSnapTo(double x, double y, double z, float yRot, float xRot) { this.absSnapTo(x, y, z); this.absSnapRotationTo(yRot, xRot); } public void absSnapRotationTo(float yRot, float xRot) { this.setYRot(yRot % 360.0f); this.setXRot(Mth.clamp(xRot, -90.0f, 90.0f) % 360.0f); this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); } public void absSnapTo(double x, double y, double z) { double cx = Mth.clamp(x, -3.0E7, 3.0E7); double cz = Mth.clamp(z, -3.0E7, 3.0E7); this.xo = cx; this.yo = y; this.zo = cz; this.setPos(cx, y, cz); } public void snapTo(Vec3 pos) { this.snapTo(pos.x, pos.y, pos.z); } public void snapTo(double x, double y, double z) { this.snapTo(x, y, z, this.getYRot(), this.getXRot()); } public void snapTo(BlockPos spawnPos, float yRot, float xRot) { this.snapTo(spawnPos.getBottomCenter(), yRot, xRot); } public void snapTo(Vec3 spawnPos, float yRot, float xRot) { this.snapTo(spawnPos.x, spawnPos.y, spawnPos.z, yRot, xRot); } public void snapTo(double x, double y, double z, float yRot, float xRot) { this.setPosRaw(x, y, z); this.setYRot(yRot); this.setXRot(xRot); this.setOldPosAndRot(); this.reapplyPosition(); } public final void setOldPosAndRot() { this.setOldPos(); this.setOldRot(); } public final void setOldPosAndRot(Vec3 position, float yRot, float xRot) { this.setOldPos(position); this.setOldRot(yRot, xRot); } protected void setOldPos() { this.setOldPos(this.position); } public void setOldRot() { this.setOldRot(this.getYRot(), this.getXRot()); } private void setOldPos(Vec3 position) { this.xo = this.xOld = position.x; this.yo = this.yOld = position.y; this.zo = this.zOld = position.z; } private void setOldRot(float yRot, float xRot) { this.yRotO = yRot; this.xRotO = xRot; } public final Vec3 oldPosition() { return new Vec3(this.xOld, this.yOld, this.zOld); } public float distanceTo(Entity entity) { float xd = (float)(this.getX() - entity.getX()); float yd = (float)(this.getY() - entity.getY()); float zd = (float)(this.getZ() - entity.getZ()); return Mth.sqrt(xd * xd + yd * yd + zd * zd); } public double distanceToSqr(double x2, double y2, double z2) { double xd = this.getX() - x2; double yd = this.getY() - y2; double zd = this.getZ() - z2; return xd * xd + yd * yd + zd * zd; } public double distanceToSqr(Entity entity) { return this.distanceToSqr(entity.position()); } public double distanceToSqr(Vec3 pos) { double xd = this.getX() - pos.x; double yd = this.getY() - pos.y; double zd = this.getZ() - pos.z; return xd * xd + yd * yd + zd * zd; } public void playerTouch(Player player) { } public void push(Entity entity) { double za; if (this.isPassengerOfSameVehicle(entity)) { return; } if (entity.noPhysics || this.noPhysics) { return; } double xa = entity.getX() - this.getX(); double dd = Mth.absMax(xa, za = entity.getZ() - this.getZ()); if (dd >= (double)0.01f) { dd = Math.sqrt(dd); xa /= dd; za /= dd; double pow = 1.0 / dd; if (pow > 1.0) { pow = 1.0; } xa *= pow; za *= pow; xa *= (double)0.05f; za *= (double)0.05f; if (!this.isVehicle() && this.isPushable()) { this.push(-xa, 0.0, -za); } if (!entity.isVehicle() && entity.isPushable()) { entity.push(xa, 0.0, za); } } } public void push(Vec3 impulse) { if (impulse.isFinite()) { this.push(impulse.x, impulse.y, impulse.z); } } public void push(double xa, double ya, double za) { if (Double.isFinite(xa) && Double.isFinite(ya) && Double.isFinite(za)) { this.setDeltaMovement(this.getDeltaMovement().add(xa, ya, za)); this.needsSync = true; } } protected void markHurt() { this.hurtMarked = true; } @Deprecated public final void hurt(DamageSource source, float damage) { Level level = this.level; if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; this.hurtServer(serverLevel, source, damage); } } @Deprecated public final boolean hurtOrSimulate(DamageSource source, float damage) { Level level = this.level; if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; return this.hurtServer(serverLevel, source, damage); } return this.hurtClient(source); } public abstract boolean hurtServer(ServerLevel var1, DamageSource var2, float var3); public boolean hurtClient(DamageSource source) { return false; } public final Vec3 getViewVector(float a) { return this.calculateViewVector(this.getViewXRot(a), this.getViewYRot(a)); } public Direction getNearestViewDirection() { return Direction.getApproximateNearest(this.getViewVector(1.0f)); } public float getViewXRot(float a) { return this.getXRot(a); } public float getViewYRot(float a) { return this.getYRot(a); } public float getXRot(float partialTicks) { if (partialTicks == 1.0f) { return this.getXRot(); } return Mth.lerp(partialTicks, this.xRotO, this.getXRot()); } public float getYRot(float partialTicks) { if (partialTicks == 1.0f) { return this.getYRot(); } return Mth.rotLerp(partialTicks, this.yRotO, this.getYRot()); } public final Vec3 calculateViewVector(float xRot, float yRot) { float realXRot = xRot * ((float)Math.PI / 180); float realYRot = -yRot * ((float)Math.PI / 180); float yCos = Mth.cos(realYRot); float ySin = Mth.sin(realYRot); float xCos = Mth.cos(realXRot); float xSin = Mth.sin(realXRot); return new Vec3(ySin * xCos, -xSin, yCos * xCos); } public final Vec3 getUpVector(float a) { return this.calculateUpVector(this.getViewXRot(a), this.getViewYRot(a)); } protected final Vec3 calculateUpVector(float xRot, float yRot) { return this.calculateViewVector(xRot - 90.0f, yRot); } public final Vec3 getEyePosition() { return new Vec3(this.getX(), this.getEyeY(), this.getZ()); } public final Vec3 getEyePosition(float partialTickTime) { double x = Mth.lerp((double)partialTickTime, this.xo, this.getX()); double y = Mth.lerp((double)partialTickTime, this.yo, this.getY()) + (double)this.getEyeHeight(); double z = Mth.lerp((double)partialTickTime, this.zo, this.getZ()); return new Vec3(x, y, z); } public Vec3 getLightProbePosition(float partialTickTime) { return this.getEyePosition(partialTickTime); } public final Vec3 getPosition(float partialTickTime) { double endX = Mth.lerp((double)partialTickTime, this.xo, this.getX()); double endY = Mth.lerp((double)partialTickTime, this.yo, this.getY()); double endZ = Mth.lerp((double)partialTickTime, this.zo, this.getZ()); return new Vec3(endX, endY, endZ); } public HitResult pick(double range, float a, boolean withLiquids) { Vec3 from = this.getEyePosition(a); Vec3 viewVector = this.getViewVector(a); Vec3 to = from.add(viewVector.x * range, viewVector.y * range, viewVector.z * range); return this.level().clip(new ClipContext(from, to, ClipContext.Block.OUTLINE, withLiquids ? ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, this)); } public boolean canBeHitByProjectile() { return this.isAlive() && this.isPickable(); } public boolean isPickable() { return false; } public boolean isPushable() { return false; } public void awardKillScore(Entity victim, DamageSource killingBlow) { if (victim instanceof ServerPlayer) { CriteriaTriggers.ENTITY_KILLED_PLAYER.trigger((ServerPlayer)victim, this, killingBlow); } } public boolean shouldRender(double camX, double camY, double camZ) { double xd = this.getX() - camX; double yd = this.getY() - camY; double zd = this.getZ() - camZ; double distance = xd * xd + yd * yd + zd * zd; return this.shouldRenderAtSqrDistance(distance); } public boolean shouldRenderAtSqrDistance(double distance) { double size = this.getBoundingBox().getSize(); if (Double.isNaN(size)) { size = 1.0; } return distance < (size *= 64.0 * viewScale) * size; } public boolean saveAsPassenger(ValueOutput output) { if (this.removalReason != null && !this.removalReason.shouldSave()) { return false; } String id = this.getEncodeId(); if (id == null) { return false; } output.putString(TAG_ID, id); this.saveWithoutId(output); return true; } public boolean save(ValueOutput output) { if (this.isPassenger()) { return false; } return this.saveAsPassenger(output); } public void saveWithoutId(ValueOutput output) { try { int ticksFrozen; if (this.vehicle != null) { output.store(TAG_POS, Vec3.CODEC, new Vec3(this.vehicle.getX(), this.getY(), this.vehicle.getZ())); } else { output.store(TAG_POS, Vec3.CODEC, this.position()); } output.store(TAG_MOTION, Vec3.CODEC, this.getDeltaMovement()); output.store(TAG_ROTATION, Vec2.CODEC, new Vec2(this.getYRot(), this.getXRot())); output.putDouble(TAG_FALL_DISTANCE, this.fallDistance); output.putShort(TAG_FIRE, (short)this.remainingFireTicks); output.putShort(TAG_AIR, (short)this.getAirSupply()); output.putBoolean(TAG_ON_GROUND, this.onGround()); output.putBoolean(TAG_INVULNERABLE, this.invulnerable); output.putInt(TAG_PORTAL_COOLDOWN, this.portalCooldown); output.store(TAG_UUID, UUIDUtil.CODEC, this.getUUID()); output.storeNullable(TAG_CUSTOM_NAME, ComponentSerialization.CODEC, this.getCustomName()); if (this.isCustomNameVisible()) { output.putBoolean("CustomNameVisible", this.isCustomNameVisible()); } if (this.isSilent()) { output.putBoolean(TAG_SILENT, this.isSilent()); } if (this.isNoGravity()) { output.putBoolean(TAG_NO_GRAVITY, this.isNoGravity()); } if (this.hasGlowingTag) { output.putBoolean(TAG_GLOWING, true); } if ((ticksFrozen = this.getTicksFrozen()) > 0) { output.putInt("TicksFrozen", this.getTicksFrozen()); } if (this.hasVisualFire) { output.putBoolean("HasVisualFire", this.hasVisualFire); } if (!this.tags.isEmpty()) { output.store("Tags", TAG_LIST_CODEC, List.copyOf(this.tags)); } if (!this.customData.isEmpty()) { output.store(TAG_DATA, CustomData.CODEC, this.customData); } this.addAdditionalSaveData(output); if (this.isVehicle()) { ValueOutput.ValueOutputList passengersList = output.childrenList(TAG_PASSENGERS); for (Entity passenger : this.getPassengers()) { ValueOutput passengerOutput; if (passenger.saveAsPassenger(passengerOutput = passengersList.addChild())) continue; passengersList.discardLast(); } if (passengersList.isEmpty()) { output.discard(TAG_PASSENGERS); } } } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, "Saving entity NBT"); CrashReportCategory category = report.addCategory("Entity being saved"); this.fillCrashReportCategory(category); throw new ReportedException(report); } } public void load(ValueInput input) { try { Vec3 pos = input.read(TAG_POS, Vec3.CODEC).orElse(Vec3.ZERO); Vec3 motion = input.read(TAG_MOTION, Vec3.CODEC).orElse(Vec3.ZERO); Vec2 rotation = input.read(TAG_ROTATION, Vec2.CODEC).orElse(Vec2.ZERO); this.setDeltaMovement(Math.abs(motion.x) > 10.0 ? 0.0 : motion.x, Math.abs(motion.y) > 10.0 ? 0.0 : motion.y, Math.abs(motion.z) > 10.0 ? 0.0 : motion.z); this.needsSync = true; double maxHorizontalPosition = 3.0000512E7; this.setPosRaw(Mth.clamp(pos.x, -3.0000512E7, 3.0000512E7), Mth.clamp(pos.y, -2.0E7, 2.0E7), Mth.clamp(pos.z, -3.0000512E7, 3.0000512E7)); this.setYRot(rotation.x); this.setXRot(rotation.y); this.setOldPosAndRot(); this.setYHeadRot(this.getYRot()); this.setYBodyRot(this.getYRot()); this.fallDistance = input.getDoubleOr(TAG_FALL_DISTANCE, 0.0); this.remainingFireTicks = input.getShortOr(TAG_FIRE, (short)0); this.setAirSupply(input.getIntOr(TAG_AIR, this.getMaxAirSupply())); this.onGround = input.getBooleanOr(TAG_ON_GROUND, false); this.invulnerable = input.getBooleanOr(TAG_INVULNERABLE, false); this.portalCooldown = input.getIntOr(TAG_PORTAL_COOLDOWN, 0); input.read(TAG_UUID, UUIDUtil.CODEC).ifPresent(id -> { this.uuid = id; this.stringUUID = this.uuid.toString(); }); if (!(Double.isFinite(this.getX()) && Double.isFinite(this.getY()) && Double.isFinite(this.getZ()))) { throw new IllegalStateException("Entity has invalid position"); } if (!Double.isFinite(this.getYRot()) || !Double.isFinite(this.getXRot())) { throw new IllegalStateException("Entity has invalid rotation"); } this.reapplyPosition(); this.setRot(this.getYRot(), this.getXRot()); this.setCustomName(input.read(TAG_CUSTOM_NAME, ComponentSerialization.CODEC).orElse(null)); this.setCustomNameVisible(input.getBooleanOr("CustomNameVisible", false)); this.setSilent(input.getBooleanOr(TAG_SILENT, false)); this.setNoGravity(input.getBooleanOr(TAG_NO_GRAVITY, false)); this.setGlowingTag(input.getBooleanOr(TAG_GLOWING, false)); this.setTicksFrozen(input.getIntOr("TicksFrozen", 0)); this.hasVisualFire = input.getBooleanOr("HasVisualFire", false); this.customData = input.read(TAG_DATA, CustomData.CODEC).orElse(CustomData.EMPTY); this.tags.clear(); input.read("Tags", TAG_LIST_CODEC).ifPresent(this.tags::addAll); this.readAdditionalSaveData(input); if (this.repositionEntityAfterLoad()) { this.reapplyPosition(); } } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, "Loading entity NBT"); CrashReportCategory category = report.addCategory("Entity being loaded"); this.fillCrashReportCategory(category); throw new ReportedException(report); } } protected boolean repositionEntityAfterLoad() { return true; } protected final @Nullable String getEncodeId() { EntityType type = this.getType(); Identifier key = EntityType.getKey(type); return !type.canSerialize() ? null : key.toString(); } protected abstract void readAdditionalSaveData(ValueInput var1); protected abstract void addAdditionalSaveData(ValueOutput var1); public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemLike resource) { return this.spawnAtLocation(level, new ItemStack(resource), 0.0f); } public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemStack itemStack) { return this.spawnAtLocation(level, itemStack, 0.0f); } public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemStack itemStack, Vec3 offset) { if (itemStack.isEmpty()) { return null; } ItemEntity entity = new ItemEntity(level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, itemStack); entity.setDefaultPickUpDelay(); level.addFreshEntity(entity); return entity; } public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemStack itemStack, float offset) { return this.spawnAtLocation(level, itemStack, new Vec3(0.0, offset, 0.0)); } public boolean isAlive() { return !this.isRemoved(); } public boolean isInWall() { if (this.noPhysics) { return false; } float checkWidth = this.dimensions.width() * 0.8f; AABB eyeBb = AABB.ofSize(this.getEyePosition(), checkWidth, 1.0E-6, checkWidth); return BlockPos.betweenClosedStream(eyeBb).anyMatch(pos -> { BlockState state = this.level().getBlockState((BlockPos)pos); return !state.isAir() && state.isSuffocating(this.level(), (BlockPos)pos) && Shapes.joinIsNotEmpty(state.getCollisionShape(this.level(), (BlockPos)pos).move((Vec3i)pos), Shapes.create(eyeBb), BooleanOp.AND); }); } public InteractionResult interact(Player player, InteractionHand hand) { ItemStack heldItem; Object mobsToLeash; LivingEntity le; Entity entity; Leashable leashable; Entity entity2; if (!this.level().isClientSide() && player.isSecondaryUseActive() && (entity2 = this) instanceof Leashable && (leashable = (Leashable)((Object)entity2)).canBeLeashed() && this.isAlive() && (!((entity = this) instanceof LivingEntity) || !(le = (LivingEntity)entity).isBaby()) && !(mobsToLeash = Leashable.leashableInArea(this, l -> l.getLeashHolder() == player)).isEmpty()) { boolean anyLeashed = false; Iterator iterator = mobsToLeash.iterator(); while (iterator.hasNext()) { Leashable mob = (Leashable)iterator.next(); if (!mob.canHaveALeashAttachedTo(this)) continue; mob.setLeashedTo(this, true); anyLeashed = true; } if (anyLeashed) { this.level().gameEvent(GameEvent.ENTITY_ACTION, this.blockPosition(), GameEvent.Context.of(player)); this.playSound(SoundEvents.LEAD_TIED); return InteractionResult.SUCCESS_SERVER.withoutItem(); } } if ((heldItem = player.getItemInHand(hand)).is(Items.SHEARS) && this.shearOffAllLeashConnections(player)) { heldItem.hurtAndBreak(1, (LivingEntity)player, hand); return InteractionResult.SUCCESS; } mobsToLeash = this; if (mobsToLeash instanceof Mob) { Mob target = (Mob)mobsToLeash; if (heldItem.is(Items.SHEARS) && target.canShearEquipment(player) && !player.isSecondaryUseActive() && this.attemptToShearEquipment(player, hand, heldItem, target)) { return InteractionResult.SUCCESS; } } if (this.isAlive() && (mobsToLeash = this) instanceof Leashable) { Leashable leashable2 = (Leashable)mobsToLeash; if (leashable2.getLeashHolder() == player) { if (!this.level().isClientSide()) { if (player.hasInfiniteMaterials()) { leashable2.removeLeash(); } else { leashable2.dropLeash(); } this.gameEvent(GameEvent.ENTITY_INTERACT, player); this.playSound(SoundEvents.LEAD_UNTIED); } return InteractionResult.SUCCESS.withoutItem(); } ItemStack itemStack = player.getItemInHand(hand); if (itemStack.is(Items.LEAD) && !(leashable2.getLeashHolder() instanceof Player)) { if (this.level().isClientSide()) { return InteractionResult.CONSUME; } if (leashable2.canHaveALeashAttachedTo(player)) { if (leashable2.isLeashed()) { leashable2.dropLeash(); } leashable2.setLeashedTo(player, true); this.playSound(SoundEvents.LEAD_TIED); itemStack.shrink(1); return InteractionResult.SUCCESS_SERVER; } } } return InteractionResult.PASS; } public boolean shearOffAllLeashConnections(@Nullable Player player) { Level level; boolean dropped = this.dropAllLeashConnections(player); if (dropped && (level = this.level()) instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; serverLevel.playSound(null, this.blockPosition(), SoundEvents.SHEARS_SNIP, player != null ? player.getSoundSource() : this.getSoundSource()); } return dropped; } public boolean dropAllLeashConnections(@Nullable Player player) { Leashable leashableThis; List leashables = Leashable.leashableLeashedTo(this); boolean dropped = !leashables.isEmpty(); Entity entity = this; if (entity instanceof Leashable && (leashableThis = (Leashable)((Object)entity)).isLeashed()) { leashableThis.dropLeash(); dropped = true; } for (Leashable leashable : leashables) { leashable.dropLeash(); } if (dropped) { this.gameEvent(GameEvent.SHEAR, player); return true; } return false; } private boolean attemptToShearEquipment(Player player, InteractionHand hand, ItemStack heldItem, Mob target) { for (EquipmentSlot slot : EquipmentSlot.VALUES) { ItemStack itemStack = target.getItemBySlot(slot); Equippable equippable = itemStack.get(DataComponents.EQUIPPABLE); if (equippable == null || !equippable.canBeSheared() || EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE) && !player.isCreative()) continue; heldItem.hurtAndBreak(1, (LivingEntity)player, hand.asEquipmentSlot()); Vec3 equipmentSpawnOffset = this.dimensions.attachments().getAverage(EntityAttachment.PASSENGER); target.setItemSlotAndDropWhenKilled(slot, ItemStack.EMPTY); this.gameEvent(GameEvent.SHEAR, player); this.playSound(equippable.shearingSound().value()); Level level = this.level(); if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; this.spawnAtLocation(serverLevel, itemStack, equipmentSpawnOffset); CriteriaTriggers.PLAYER_SHEARED_EQUIPMENT.trigger((ServerPlayer)player, itemStack, target); } return true; } return false; } public boolean canCollideWith(Entity entity) { return entity.canBeCollidedWith(this) && !this.isPassengerOfSameVehicle(entity); } public boolean canBeCollidedWith(@Nullable Entity other) { return false; } public void rideTick() { this.setDeltaMovement(Vec3.ZERO); this.tick(); if (!this.isPassenger()) { return; } this.getVehicle().positionRider(this); } public final void positionRider(Entity passenger) { if (!this.hasPassenger(passenger)) { return; } this.positionRider(passenger, Entity::setPos); } protected void positionRider(Entity passenger, MoveFunction moveFunction) { Vec3 position = this.getPassengerRidingPosition(passenger); Vec3 offset = passenger.getVehicleAttachmentPoint(this); moveFunction.accept(passenger, position.x - offset.x, position.y - offset.y, position.z - offset.z); } public void onPassengerTurned(Entity passenger) { } public Vec3 getVehicleAttachmentPoint(Entity vehicle) { return this.getAttachments().get(EntityAttachment.VEHICLE, 0, this.yRot); } public Vec3 getPassengerRidingPosition(Entity passenger) { return this.position().add(this.getPassengerAttachmentPoint(passenger, this.dimensions, 1.0f)); } protected Vec3 getPassengerAttachmentPoint(Entity passenger, EntityDimensions dimensions, float scale) { return Entity.getDefaultPassengerAttachmentPoint(this, passenger, dimensions.attachments()); } protected static Vec3 getDefaultPassengerAttachmentPoint(Entity vehicle, Entity passenger, EntityAttachments attachments) { int passengerIndex = vehicle.getPassengers().indexOf(passenger); return attachments.getClamped(EntityAttachment.PASSENGER, passengerIndex, vehicle.yRot); } public final boolean startRiding(Entity entity) { return this.startRiding(entity, false, true); } public boolean showVehicleHealth() { return this instanceof LivingEntity; } public boolean startRiding(Entity entityToRide, boolean force, boolean sendEventAndTriggers) { if (entityToRide == this.vehicle) { return false; } if (!entityToRide.couldAcceptPassenger()) { return false; } if (!this.level().isClientSide() && !entityToRide.type.canSerialize()) { return false; } Entity vehicleEntity = entityToRide; while (vehicleEntity.vehicle != null) { if (vehicleEntity.vehicle == this) { return false; } vehicleEntity = vehicleEntity.vehicle; } if (!(force || this.canRide(entityToRide) && entityToRide.canAddPassenger(this))) { return false; } if (this.isPassenger()) { this.stopRiding(); } this.setPose(Pose.STANDING); this.vehicle = entityToRide; this.vehicle.addPassenger(this); if (sendEventAndTriggers) { this.level().gameEvent(this, GameEvent.ENTITY_MOUNT, this.vehicle.position); entityToRide.getIndirectPassengersStream().filter(e -> e instanceof ServerPlayer).forEach(player -> CriteriaTriggers.START_RIDING_TRIGGER.trigger((ServerPlayer)player)); } return true; } protected boolean canRide(Entity vehicle) { return !this.isShiftKeyDown() && this.boardingCooldown <= 0; } public void ejectPassengers() { for (int i = this.passengers.size() - 1; i >= 0; --i) { ((Entity)this.passengers.get(i)).stopRiding(); } } public void removeVehicle() { if (this.vehicle != null) { Entity oldVehicle = this.vehicle; this.vehicle = null; oldVehicle.removePassenger(this); RemovalReason removalReason = this.getRemovalReason(); if (removalReason == null || removalReason.shouldDestroy()) { this.level().gameEvent(this, GameEvent.ENTITY_DISMOUNT, oldVehicle.position); } } } public void stopRiding() { this.removeVehicle(); } protected void addPassenger(Entity passenger) { if (passenger.getVehicle() != this) { throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)"); } if (this.passengers.isEmpty()) { this.passengers = ImmutableList.of((Object)passenger); } else { ArrayList newPassengers = Lists.newArrayList(this.passengers); if (!this.level().isClientSide() && passenger instanceof Player && !(this.getFirstPassenger() instanceof Player)) { newPassengers.add(0, passenger); } else { newPassengers.add(passenger); } this.passengers = ImmutableList.copyOf((Collection)newPassengers); } } protected void removePassenger(Entity passenger) { if (passenger.getVehicle() == this) { throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); } this.passengers = this.passengers.size() == 1 && this.passengers.get(0) == passenger ? ImmutableList.of() : (ImmutableList)this.passengers.stream().filter(p -> p != passenger).collect(ImmutableList.toImmutableList()); passenger.boardingCooldown = 60; } protected boolean canAddPassenger(Entity passenger) { return this.passengers.isEmpty(); } protected boolean couldAcceptPassenger() { return true; } public final boolean isInterpolating() { return this.getInterpolation() != null && this.getInterpolation().hasActiveInterpolation(); } public final void moveOrInterpolateTo(Vec3 position, float yRot, float xRot) { this.moveOrInterpolateTo(Optional.of(position), Optional.of(Float.valueOf(yRot)), Optional.of(Float.valueOf(xRot))); } public final void moveOrInterpolateTo(float yRot, float xRot) { this.moveOrInterpolateTo(Optional.empty(), Optional.of(Float.valueOf(yRot)), Optional.of(Float.valueOf(xRot))); } public final void moveOrInterpolateTo(Vec3 position) { this.moveOrInterpolateTo(Optional.of(position), Optional.empty(), Optional.empty()); } public final void moveOrInterpolateTo(Optional position, Optional yRot, Optional xRot) { InterpolationHandler interpolationHandler = this.getInterpolation(); if (interpolationHandler != null) { interpolationHandler.interpolateTo(position.orElse(interpolationHandler.position()), yRot.orElse(Float.valueOf(interpolationHandler.yRot())).floatValue(), xRot.orElse(Float.valueOf(interpolationHandler.xRot())).floatValue()); } else { position.ifPresent(this::setPos); yRot.ifPresent(y -> this.setYRot(y.floatValue() % 360.0f)); xRot.ifPresent(x -> this.setXRot(x.floatValue() % 360.0f)); } } public @Nullable InterpolationHandler getInterpolation() { return null; } public void lerpHeadTo(float yRot, int steps) { this.setYHeadRot(yRot); } public float getPickRadius() { return 0.0f; } public Vec3 getLookAngle() { return this.calculateViewVector(this.getXRot(), this.getYRot()); } public Vec3 getHeadLookAngle() { return this.calculateViewVector(this.getXRot(), this.getYHeadRot()); } public Vec3 getHandHoldingItemAngle(Item item) { Entity entity = this; if (entity instanceof Player) { Player player = (Player)entity; boolean itemOnlyInOffhand = player.getOffhandItem().is(item) && !player.getMainHandItem().is(item); HumanoidArm itemArm = itemOnlyInOffhand ? player.getMainArm().getOpposite() : player.getMainArm(); return this.calculateViewVector(0.0f, this.getYRot() + (float)(itemArm == HumanoidArm.RIGHT ? 80 : -80)).scale(0.5); } return Vec3.ZERO; } public Vec2 getRotationVector() { return new Vec2(this.getXRot(), this.getYRot()); } public Vec3 getForward() { return Vec3.directionFromRotation(this.getRotationVector()); } public void setAsInsidePortal(Portal portal, BlockPos pos) { if (this.isOnPortalCooldown()) { this.setPortalCooldown(); return; } if (this.portalProcess == null || !this.portalProcess.isSamePortal(portal)) { this.portalProcess = new PortalProcessor(portal, pos.immutable()); } else if (!this.portalProcess.isInsidePortalThisTick()) { this.portalProcess.updateEntryPosition(pos.immutable()); this.portalProcess.setAsInsidePortalThisTick(true); } } protected void handlePortal() { Level level = this.level(); if (!(level instanceof ServerLevel)) { return; } ServerLevel level2 = (ServerLevel)level; this.processPortalCooldown(); if (this.portalProcess == null) { return; } if (this.portalProcess.processPortalTeleportation(level2, this, this.canUsePortal(false))) { ServerLevel newLevel; ProfilerFiller profiler = Profiler.get(); profiler.push("portal"); this.setPortalCooldown(); TeleportTransition teleportTransition = this.portalProcess.getPortalDestination(level2, this); if (teleportTransition != null && level2.isAllowedToEnterPortal(newLevel = teleportTransition.newLevel()) && (newLevel.dimension() == level2.dimension() || this.canTeleport(level2, newLevel))) { this.teleport(teleportTransition); } profiler.pop(); } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } } public int getDimensionChangingDelay() { Entity firstPassenger = this.getFirstPassenger(); return firstPassenger instanceof ServerPlayer ? firstPassenger.getDimensionChangingDelay() : 300; } public void lerpMotion(Vec3 movement) { this.setDeltaMovement(movement); } public void handleDamageEvent(DamageSource source) { } public void handleEntityEvent(byte id) { switch (id) { case 53: { HoneyBlock.showSlideParticles(this); } } } public void animateHurt(float direction) { } public boolean isOnFire() { boolean isClientSide = this.level() != null && this.level().isClientSide(); return !this.fireImmune() && (this.remainingFireTicks > 0 || isClientSide && this.getSharedFlag(0)); } public boolean isPassenger() { return this.getVehicle() != null; } public boolean isVehicle() { return !this.passengers.isEmpty(); } public boolean dismountsUnderwater() { return this.getType().is(EntityTypeTags.DISMOUNTS_UNDERWATER); } public boolean canControlVehicle() { return !this.getType().is(EntityTypeTags.NON_CONTROLLING_RIDER); } public void setShiftKeyDown(boolean shiftKeyDown) { this.setSharedFlag(1, shiftKeyDown); } public boolean isShiftKeyDown() { return this.getSharedFlag(1); } public boolean isSteppingCarefully() { return this.isShiftKeyDown(); } public boolean isSuppressingBounce() { return this.isShiftKeyDown(); } public boolean isDiscrete() { return this.isShiftKeyDown(); } public boolean isDescending() { return this.isShiftKeyDown(); } public boolean isCrouching() { return this.hasPose(Pose.CROUCHING); } public boolean isSprinting() { return this.getSharedFlag(3); } public void setSprinting(boolean isSprinting) { this.setSharedFlag(3, isSprinting); } public boolean isSwimming() { return this.getSharedFlag(4); } public boolean isVisuallySwimming() { return this.hasPose(Pose.SWIMMING); } public boolean isVisuallyCrawling() { return this.isVisuallySwimming() && !this.isInWater(); } public void setSwimming(boolean swimming) { this.setSharedFlag(4, swimming); } public final boolean hasGlowingTag() { return this.hasGlowingTag; } public final void setGlowingTag(boolean value) { this.hasGlowingTag = value; this.setSharedFlag(6, this.isCurrentlyGlowing()); } public boolean isCurrentlyGlowing() { if (this.level().isClientSide()) { return this.getSharedFlag(6); } return this.hasGlowingTag; } public boolean isInvisible() { return this.getSharedFlag(5); } public boolean isInvisibleTo(Player player) { if (player.isSpectator()) { return false; } PlayerTeam team = this.getTeam(); if (team != null && player != null && player.getTeam() == team && ((Team)team).canSeeFriendlyInvisibles()) { return false; } return this.isInvisible(); } public boolean isOnRails() { return false; } public void updateDynamicGameEventListener(BiConsumer, ServerLevel> action) { } public @Nullable PlayerTeam getTeam() { return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName()); } public final boolean isAlliedTo(@Nullable Entity other) { if (other == null) { return false; } return this == other || this.considersEntityAsAlly(other) || other.considersEntityAsAlly(this); } protected boolean considersEntityAsAlly(Entity other) { return this.isAlliedTo(other.getTeam()); } public boolean isAlliedTo(@Nullable Team other) { if (this.getTeam() != null) { return this.getTeam().isAlliedTo(other); } return false; } public void setInvisible(boolean invisible) { this.setSharedFlag(5, invisible); } protected boolean getSharedFlag(int flag) { return (this.entityData.get(DATA_SHARED_FLAGS_ID) & 1 << flag) != 0; } protected void setSharedFlag(int flag, boolean value) { byte currentValue = this.entityData.get(DATA_SHARED_FLAGS_ID); if (value) { this.entityData.set(DATA_SHARED_FLAGS_ID, (byte)(currentValue | 1 << flag)); } else { this.entityData.set(DATA_SHARED_FLAGS_ID, (byte)(currentValue & ~(1 << flag))); } } public int getMaxAirSupply() { return 300; } public int getAirSupply() { return this.entityData.get(DATA_AIR_SUPPLY_ID); } public void setAirSupply(int supply) { this.entityData.set(DATA_AIR_SUPPLY_ID, supply); } public void clearFreeze() { this.setTicksFrozen(0); } public int getTicksFrozen() { return this.entityData.get(DATA_TICKS_FROZEN); } public void setTicksFrozen(int ticks) { this.entityData.set(DATA_TICKS_FROZEN, ticks); } public float getPercentFrozen() { int ticksToFreeze = this.getTicksRequiredToFreeze(); return (float)Math.min(this.getTicksFrozen(), ticksToFreeze) / (float)ticksToFreeze; } public boolean isFullyFrozen() { return this.getTicksFrozen() >= this.getTicksRequiredToFreeze(); } public int getTicksRequiredToFreeze() { return 140; } public void thunderHit(ServerLevel level, LightningBolt lightningBolt) { this.setRemainingFireTicks(this.remainingFireTicks + 1); if (this.remainingFireTicks == 0) { this.igniteForSeconds(8.0f); } this.hurtServer(level, this.damageSources().lightningBolt(), 5.0f); } public void onAboveBubbleColumn(boolean dragDown, BlockPos pos) { Entity.handleOnAboveBubbleColumn(this, dragDown, pos); } protected static void handleOnAboveBubbleColumn(Entity entity, boolean dragDown, BlockPos pos) { Vec3 movement = entity.getDeltaMovement(); double yd = dragDown ? Math.max(-0.9, movement.y - 0.03) : Math.min(1.8, movement.y + 0.1); entity.setDeltaMovement(movement.x, yd, movement.z); Entity.sendBubbleColumnParticles(entity.level, pos); } protected static void sendBubbleColumnParticles(Level level, BlockPos pos) { if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; for (int i = 0; i < 2; ++i) { serverLevel.sendParticles(ParticleTypes.SPLASH, (double)pos.getX() + level.random.nextDouble(), pos.getY() + 1, (double)pos.getZ() + level.random.nextDouble(), 1, 0.0, 0.0, 0.0, 1.0); serverLevel.sendParticles(ParticleTypes.BUBBLE, (double)pos.getX() + level.random.nextDouble(), pos.getY() + 1, (double)pos.getZ() + level.random.nextDouble(), 1, 0.0, 0.01, 0.0, 0.2); } } } public void onInsideBubbleColumn(boolean dragDown) { Entity.handleOnInsideBubbleColumn(this, dragDown); } protected static void handleOnInsideBubbleColumn(Entity entity, boolean dragDown) { Vec3 movement = entity.getDeltaMovement(); double yd = dragDown ? Math.max(-0.3, movement.y - 0.03) : Math.min(0.7, movement.y + 0.06); entity.setDeltaMovement(movement.x, yd, movement.z); entity.resetFallDistance(); } public boolean killedEntity(ServerLevel level, LivingEntity entity, DamageSource source) { return true; } public void checkFallDistanceAccumulation() { if (this.getDeltaMovement().y() > -0.5 && this.fallDistance > 1.0) { this.fallDistance = 1.0; } } public void resetFallDistance() { this.fallDistance = 0.0; } protected void moveTowardsClosestSpace(double x, double y, double z) { BlockPos pos = BlockPos.containing(x, y, z); Vec3 delta = new Vec3(x - (double)pos.getX(), y - (double)pos.getY(), z - (double)pos.getZ()); BlockPos.MutableBlockPos neighborPos = new BlockPos.MutableBlockPos(); Direction closestDirection = Direction.UP; double closest = Double.MAX_VALUE; for (Direction direction : new Direction[]{Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, Direction.UP}) { double orientedDelta; neighborPos.setWithOffset((Vec3i)pos, direction); if (this.level().getBlockState(neighborPos).isCollisionShapeFullBlock(this.level(), neighborPos)) continue; double d = delta.get(direction.getAxis()); double d2 = orientedDelta = direction.getAxisDirection() == Direction.AxisDirection.POSITIVE ? 1.0 - d : d; if (!(orientedDelta < closest)) continue; closest = orientedDelta; closestDirection = direction; } float speed = this.random.nextFloat() * 0.2f + 0.1f; float step = closestDirection.getAxisDirection().getStep(); Vec3 scaledMovement = this.getDeltaMovement().scale(0.75); if (closestDirection.getAxis() == Direction.Axis.X) { this.setDeltaMovement(step * speed, scaledMovement.y, scaledMovement.z); } else if (closestDirection.getAxis() == Direction.Axis.Y) { this.setDeltaMovement(scaledMovement.x, step * speed, scaledMovement.z); } else if (closestDirection.getAxis() == Direction.Axis.Z) { this.setDeltaMovement(scaledMovement.x, scaledMovement.y, step * speed); } } public void makeStuckInBlock(BlockState blockState, Vec3 speedMultiplier) { this.resetFallDistance(); this.stuckSpeedMultiplier = speedMultiplier; } private static Component removeAction(Component component) { MutableComponent result = component.plainCopy().setStyle(component.getStyle().withClickEvent(null)); for (Component s : component.getSiblings()) { result.append(Entity.removeAction(s)); } return result; } @Override public Component getName() { Component customName = this.getCustomName(); if (customName != null) { return Entity.removeAction(customName); } return this.getTypeName(); } protected Component getTypeName() { return this.type.getDescription(); } public boolean is(Entity other) { return this == other; } public float getYHeadRot() { return 0.0f; } public void setYHeadRot(float yHeadRot) { } public void setYBodyRot(float yBodyRot) { } public boolean isAttackable() { return true; } public boolean skipAttackInteraction(Entity source) { return false; } public String toString() { String levelId; String string = levelId = this.level() == null ? "~NULL~" : this.level().toString(); if (this.removalReason != null) { return String.format(Locale.ROOT, "%s['%s'/%d, l='%s', x=%.2f, y=%.2f, z=%.2f, removed=%s]", new Object[]{this.getClass().getSimpleName(), this.getPlainTextName(), this.id, levelId, this.getX(), this.getY(), this.getZ(), this.removalReason}); } return String.format(Locale.ROOT, "%s['%s'/%d, l='%s', x=%.2f, y=%.2f, z=%.2f]", this.getClass().getSimpleName(), this.getPlainTextName(), this.id, levelId, this.getX(), this.getY(), this.getZ()); } protected final boolean isInvulnerableToBase(DamageSource source) { return this.isRemoved() || this.invulnerable && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY) && !source.isCreativePlayer() || source.is(DamageTypeTags.IS_FIRE) && this.fireImmune() || source.is(DamageTypeTags.IS_FALL) && this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE); } public boolean isInvulnerable() { return this.invulnerable; } public void setInvulnerable(boolean invulnerable) { this.invulnerable = invulnerable; } public void copyPosition(Entity target) { this.snapTo(target.getX(), target.getY(), target.getZ(), target.getYRot(), target.getXRot()); } public void restoreFrom(Entity oldEntity) { try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER);){ TagValueOutput entityData = TagValueOutput.createWithContext(reporter, oldEntity.registryAccess()); oldEntity.saveWithoutId(entityData); this.load(TagValueInput.create((ProblemReporter)reporter, (HolderLookup.Provider)this.registryAccess(), entityData.buildResult())); } this.portalCooldown = oldEntity.portalCooldown; this.portalProcess = oldEntity.portalProcess; } public @Nullable Entity teleport(TeleportTransition transition) { boolean otherDimension; ServerLevel serverLevel; block6: { block5: { Level level = this.level(); if (!(level instanceof ServerLevel)) break block5; serverLevel = (ServerLevel)level; if (!this.isRemoved()) break block6; } return null; } ServerLevel newLevel = transition.newLevel(); boolean bl = otherDimension = newLevel.dimension() != serverLevel.dimension(); if (!transition.asPassenger()) { this.stopRiding(); } if (otherDimension) { return this.teleportCrossDimension(serverLevel, newLevel, transition); } return this.teleportSameDimension(serverLevel, transition); } private Entity teleportSameDimension(ServerLevel level, TeleportTransition transition) { for (Entity passenger : this.getPassengers()) { passenger.teleport(this.calculatePassengerTransition(transition, passenger)); } ProfilerFiller profiler = Profiler.get(); profiler.push("teleportSameDimension"); this.teleportSetPosition(PositionMoveRotation.of(transition), transition.relatives()); if (!transition.asPassenger()) { this.sendTeleportTransitionToRidingPlayers(transition); } transition.postTeleportTransition().onTransition(this); profiler.pop(); return this; } private @Nullable Entity teleportCrossDimension(ServerLevel oldLevel, ServerLevel newLevel, TeleportTransition transition) { List oldPassengers = this.getPassengers(); ArrayList newPassengers = new ArrayList(oldPassengers.size()); this.ejectPassengers(); for (Entity passenger : oldPassengers) { Entity newPassenger = passenger.teleport(this.calculatePassengerTransition(transition, passenger)); if (newPassenger == null) continue; newPassengers.add(newPassenger); } ProfilerFiller profiler = Profiler.get(); profiler.push("teleportCrossDimension"); Object newEntity = this.getType().create(newLevel, EntitySpawnReason.DIMENSION_TRAVEL); if (newEntity == null) { profiler.pop(); return null; } ((Entity)newEntity).restoreFrom(this); this.removeAfterChangingDimensions(); ((Entity)newEntity).teleportSetPosition(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); newLevel.addDuringTeleport((Entity)newEntity); for (Entity newPassenger : newPassengers) { newPassenger.startRiding((Entity)newEntity, true, false); } newLevel.resetEmptyTime(); transition.postTeleportTransition().onTransition((Entity)newEntity); this.teleportSpectators(transition, oldLevel); profiler.pop(); return newEntity; } protected void teleportSpectators(TeleportTransition transition, ServerLevel oldLevel) { List players = List.copyOf(oldLevel.players()); for (ServerPlayer serverPlayer : players) { if (serverPlayer.getCamera() != this) continue; serverPlayer.teleport(transition); serverPlayer.setCamera(null); } } private TeleportTransition calculatePassengerTransition(TeleportTransition transition, Entity passenger) { float passengerYRot = transition.yRot() + (transition.relatives().contains((Object)Relative.Y_ROT) ? 0.0f : passenger.getYRot() - this.getYRot()); float passengerXRot = transition.xRot() + (transition.relatives().contains((Object)Relative.X_ROT) ? 0.0f : passenger.getXRot() - this.getXRot()); Vec3 passengerOffset = passenger.position().subtract(this.position()); Vec3 passengerPos = transition.position().add(transition.relatives().contains((Object)Relative.X) ? 0.0 : passengerOffset.x(), transition.relatives().contains((Object)Relative.Y) ? 0.0 : passengerOffset.y(), transition.relatives().contains((Object)Relative.Z) ? 0.0 : passengerOffset.z()); return transition.withPosition(passengerPos).withRotation(passengerYRot, passengerXRot).transitionAsPassenger(); } private void sendTeleportTransitionToRidingPlayers(TeleportTransition transition) { LivingEntity controller = this.getControllingPassenger(); for (Entity passenger : this.getIndirectPassengers()) { if (!(passenger instanceof ServerPlayer)) continue; ServerPlayer player = (ServerPlayer)passenger; if (controller != null && player.getId() == controller.getId()) { player.connection.send(ClientboundTeleportEntityPacket.teleport(this.getId(), PositionMoveRotation.of(transition), transition.relatives(), this.onGround)); continue; } player.connection.send(ClientboundTeleportEntityPacket.teleport(this.getId(), PositionMoveRotation.of(this), Set.of(), this.onGround)); } } public void teleportSetPosition(PositionMoveRotation destination, Set relatives) { this.teleportSetPosition(PositionMoveRotation.of(this), destination, relatives); } public void teleportSetPosition(PositionMoveRotation currentValues, PositionMoveRotation destination, Set relatives) { PositionMoveRotation absoluteDestination = PositionMoveRotation.calculateAbsolute(currentValues, destination, relatives); this.setPosRaw(absoluteDestination.position().x, absoluteDestination.position().y, absoluteDestination.position().z); this.setYRot(absoluteDestination.yRot()); this.setYHeadRot(absoluteDestination.yRot()); this.setXRot(absoluteDestination.xRot()); this.reapplyPosition(); this.setOldPosAndRot(); this.setDeltaMovement(absoluteDestination.deltaMovement()); this.clearMovementThisTick(); } public void forceSetRotation(float yRot, boolean relativeY, float xRot, boolean relativeX) { Set relatives = Relative.rotation(relativeY, relativeX); PositionMoveRotation currentValues = PositionMoveRotation.of(this); PositionMoveRotation destination = currentValues.withRotation(yRot, xRot); PositionMoveRotation absoluteDestination = PositionMoveRotation.calculateAbsolute(currentValues, destination, relatives); this.setYRot(absoluteDestination.yRot()); this.setYHeadRot(absoluteDestination.yRot()); this.setXRot(absoluteDestination.xRot()); this.setOldRot(); } public void placePortalTicket(BlockPos ticketPosition) { Level level = this.level(); if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; serverLevel.getChunkSource().addTicketWithRadius(TicketType.PORTAL, new ChunkPos(ticketPosition), 3); } } protected void removeAfterChangingDimensions() { Object object; this.setRemoved(RemovalReason.CHANGED_DIMENSION); Entity entity = this; if (entity instanceof Leashable) { Leashable leashable = (Leashable)((Object)entity); leashable.removeLeash(); } if ((object = this) instanceof WaypointTransmitter) { WaypointTransmitter waypoint = (WaypointTransmitter)object; object = this.level; if (object instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)object; serverLevel.getWaypointManager().untrackWaypoint(waypoint); } } } public Vec3 getRelativePortalPosition(Direction.Axis axis, BlockUtil.FoundRectangle portalArea) { return PortalShape.getRelativePosition(portalArea, axis, this.position(), this.getDimensions(this.getPose())); } public boolean canUsePortal(boolean ignorePassenger) { return (ignorePassenger || !this.isPassenger()) && this.isAlive(); } public boolean canTeleport(Level from, Level to) { if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { for (Entity passenger : this.getPassengers()) { if (!(passenger instanceof ServerPlayer)) continue; ServerPlayer player = (ServerPlayer)passenger; if (player.seenCredits) continue; return false; } } return true; } public float getBlockExplosionResistance(Explosion explosion, BlockGetter level, BlockPos pos, BlockState block, FluidState fluid, float resistance) { return resistance; } public boolean shouldBlockExplode(Explosion explosion, BlockGetter level, BlockPos pos, BlockState state, float power) { return true; } public int getMaxFallDistance() { return 3; } public boolean isIgnoringBlockTriggers() { return false; } public void fillCrashReportCategory(CrashReportCategory category) { category.setDetail("Entity Type", () -> String.valueOf(EntityType.getKey(this.getType())) + " (" + this.getClass().getCanonicalName() + ")"); category.setDetail("Entity ID", this.id); category.setDetail("Entity Name", () -> this.getPlainTextName()); category.setDetail("Entity's Exact location", String.format(Locale.ROOT, "%.2f, %.2f, %.2f", this.getX(), this.getY(), this.getZ())); category.setDetail("Entity's Block location", CrashReportCategory.formatLocation((LevelHeightAccessor)this.level(), Mth.floor(this.getX()), Mth.floor(this.getY()), Mth.floor(this.getZ()))); Vec3 movement = this.getDeltaMovement(); category.setDetail("Entity's Momentum", String.format(Locale.ROOT, "%.2f, %.2f, %.2f", movement.x, movement.y, movement.z)); category.setDetail("Entity's Passengers", () -> this.getPassengers().toString()); category.setDetail("Entity's Vehicle", () -> String.valueOf(this.getVehicle())); } public boolean displayFireAnimation() { return this.isOnFire() && !this.isSpectator(); } public void setUUID(UUID uuid) { this.uuid = uuid; this.stringUUID = this.uuid.toString(); } @Override public UUID getUUID() { return this.uuid; } public String getStringUUID() { return this.stringUUID; } @Override public String getScoreboardName() { return this.stringUUID; } public boolean isPushedByFluid() { return true; } public static double getViewScale() { return viewScale; } public static void setViewScale(double viewScale) { Entity.viewScale = viewScale; } @Override public Component getDisplayName() { return PlayerTeam.formatNameForTeam(this.getTeam(), this.getName()).withStyle(s -> s.withHoverEvent(this.createHoverEvent()).withInsertion(this.getStringUUID())); } public void setCustomName(@Nullable Component name) { this.entityData.set(DATA_CUSTOM_NAME, Optional.ofNullable(name)); } @Override public @Nullable Component getCustomName() { return this.entityData.get(DATA_CUSTOM_NAME).orElse(null); } @Override public boolean hasCustomName() { return this.entityData.get(DATA_CUSTOM_NAME).isPresent(); } public void setCustomNameVisible(boolean visible) { this.entityData.set(DATA_CUSTOM_NAME_VISIBLE, visible); } public boolean isCustomNameVisible() { return this.entityData.get(DATA_CUSTOM_NAME_VISIBLE); } public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relatives, float newYRot, float newXRot, boolean resetCamera) { Entity newEntity = this.teleport(new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, newYRot, newXRot, relatives, TeleportTransition.DO_NOTHING)); return newEntity != null; } public void dismountTo(double x, double y, double z) { this.teleportTo(x, y, z); } public void teleportTo(double x, double y, double z) { if (!(this.level() instanceof ServerLevel)) { return; } this.snapTo(x, y, z, this.getYRot(), this.getXRot()); this.teleportPassengers(); } private void teleportPassengers() { this.getSelfAndPassengers().forEach(entity -> { for (Entity passenger : entity.passengers) { entity.positionRider(passenger, Entity::snapTo); } }); } public void teleportRelative(double dx, double dy, double dz) { this.teleportTo(this.getX() + dx, this.getY() + dy, this.getZ() + dz); } public boolean shouldShowName() { return this.isCustomNameVisible(); } @Override public void onSyncedDataUpdated(List> updatedItems) { } @Override public void onSyncedDataUpdated(EntityDataAccessor accessor) { if (DATA_POSE.equals(accessor)) { this.refreshDimensions(); } } @Deprecated protected void fixupDimensions() { EntityDimensions newDim; Pose pose = this.getPose(); this.dimensions = newDim = this.getDimensions(pose); this.eyeHeight = newDim.eyeHeight(); } public void refreshDimensions() { boolean isSmall; EntityDimensions newDim; EntityDimensions oldDim = this.dimensions; Pose pose = this.getPose(); this.dimensions = newDim = this.getDimensions(pose); this.eyeHeight = newDim.eyeHeight(); this.reapplyPosition(); boolean bl = isSmall = newDim.width() <= 4.0f && newDim.height() <= 4.0f; if (!(this.level.isClientSide() || this.firstTick || this.noPhysics || !isSmall || !(newDim.width() > oldDim.width()) && !(newDim.height() > oldDim.height()) || this instanceof Player)) { this.fudgePositionAfterSizeChange(oldDim); } } public boolean fudgePositionAfterSizeChange(EntityDimensions previousDimensions) { VoxelShape allowedCentersIgnoringY; Optional freePositionIgnoreVertical; double heightDelta; double widthDelta; EntityDimensions newDimensions = this.getDimensions(this.getPose()); Vec3 oldCenter = this.position().add(0.0, (double)previousDimensions.height() / 2.0, 0.0); VoxelShape allowedCenters = Shapes.create(AABB.ofSize(oldCenter, widthDelta = (double)Math.max(0.0f, newDimensions.width() - previousDimensions.width()) + 1.0E-6, heightDelta = (double)Math.max(0.0f, newDimensions.height() - previousDimensions.height()) + 1.0E-6, widthDelta)); Optional freePosition = this.level.findFreePosition(this, allowedCenters, oldCenter, newDimensions.width(), newDimensions.height(), newDimensions.width()); if (freePosition.isPresent()) { this.setPos(freePosition.get().add(0.0, (double)(-newDimensions.height()) / 2.0, 0.0)); return true; } if (newDimensions.width() > previousDimensions.width() && newDimensions.height() > previousDimensions.height() && (freePositionIgnoreVertical = this.level.findFreePosition(this, allowedCentersIgnoringY = Shapes.create(AABB.ofSize(oldCenter, widthDelta, 1.0E-6, widthDelta)), oldCenter, newDimensions.width(), previousDimensions.height(), newDimensions.width())).isPresent()) { this.setPos(freePositionIgnoreVertical.get().add(0.0, (double)(-previousDimensions.height()) / 2.0 + 1.0E-6, 0.0)); return true; } return false; } public Direction getDirection() { return Direction.fromYRot(this.getYRot()); } public Direction getMotionDirection() { return this.getDirection(); } protected HoverEvent createHoverEvent() { return new HoverEvent.ShowEntity(new HoverEvent.EntityTooltipInfo(this.getType(), this.getUUID(), this.getName())); } public boolean broadcastToPlayer(ServerPlayer player) { return true; } @Override public final AABB getBoundingBox() { return this.bb; } public final void setBoundingBox(AABB bb) { this.bb = bb; } public final float getEyeHeight(Pose pose) { return this.getDimensions(pose).eyeHeight(); } public final float getEyeHeight() { return this.eyeHeight; } @Override public @Nullable SlotAccess getSlot(int slot) { return null; } public InteractionResult interactAt(Player player, Vec3 location, InteractionHand hand) { return InteractionResult.PASS; } public boolean ignoreExplosion(Explosion explosion) { return false; } public void startSeenByPlayer(ServerPlayer player) { } public void stopSeenByPlayer(ServerPlayer player) { } public float rotate(Rotation rotation) { float angle = Mth.wrapDegrees(this.getYRot()); return switch (rotation) { case Rotation.CLOCKWISE_180 -> angle + 180.0f; case Rotation.COUNTERCLOCKWISE_90 -> angle + 270.0f; case Rotation.CLOCKWISE_90 -> angle + 90.0f; default -> angle; }; } public float mirror(Mirror mirror) { float angle = Mth.wrapDegrees(this.getYRot()); return switch (mirror) { case Mirror.FRONT_BACK -> -angle; case Mirror.LEFT_RIGHT -> 180.0f - angle; default -> angle; }; } public ProjectileDeflection deflection(Projectile projectile) { return this.getType().is(EntityTypeTags.DEFLECTS_PROJECTILES) ? ProjectileDeflection.REVERSE : ProjectileDeflection.NONE; } public @Nullable LivingEntity getControllingPassenger() { return null; } public final boolean hasControllingPassenger() { return this.getControllingPassenger() != null; } public final List getPassengers() { return this.passengers; } public @Nullable Entity getFirstPassenger() { return this.passengers.isEmpty() ? null : (Entity)this.passengers.get(0); } public boolean hasPassenger(Entity entity) { return this.passengers.contains((Object)entity); } public boolean hasPassenger(Predicate test) { for (Entity passenger : this.passengers) { if (!test.test(passenger)) continue; return true; } return false; } private Stream getIndirectPassengersStream() { return this.passengers.stream().flatMap(Entity::getSelfAndPassengers); } public Stream getSelfAndPassengers() { return Stream.concat(Stream.of(this), this.getIndirectPassengersStream()); } public Stream getPassengersAndSelf() { return Stream.concat(this.passengers.stream().flatMap(Entity::getPassengersAndSelf), Stream.of(this)); } public Iterable getIndirectPassengers() { return () -> this.getIndirectPassengersStream().iterator(); } public int countPlayerPassengers() { return (int)this.getIndirectPassengersStream().filter(e -> e instanceof Player).count(); } public boolean hasExactlyOnePlayerPassenger() { return this.countPlayerPassengers() == 1; } public Entity getRootVehicle() { Entity result = this; while (result.isPassenger()) { result = result.getVehicle(); } return result; } public boolean isPassengerOfSameVehicle(Entity other) { return this.getRootVehicle() == other.getRootVehicle(); } public boolean hasIndirectPassenger(Entity entity) { if (!entity.isPassenger()) { return false; } Entity ridden = entity.getVehicle(); if (ridden == this) { return true; } return this.hasIndirectPassenger(ridden); } public final boolean isLocalInstanceAuthoritative() { if (this.level.isClientSide()) { return this.isLocalClientAuthoritative(); } return !this.isClientAuthoritative(); } protected boolean isLocalClientAuthoritative() { LivingEntity passenger = this.getControllingPassenger(); return passenger != null && passenger.isLocalClientAuthoritative(); } public boolean isClientAuthoritative() { LivingEntity passenger = this.getControllingPassenger(); return passenger != null && passenger.isClientAuthoritative(); } public boolean canSimulateMovement() { return this.isLocalInstanceAuthoritative(); } public boolean isEffectiveAi() { return this.isLocalInstanceAuthoritative(); } protected static Vec3 getCollisionHorizontalEscapeVector(double colliderWidth, double collidingWidth, float directionDegrees) { double distance = (colliderWidth + collidingWidth + (double)1.0E-5f) / 2.0; float directionX = -Mth.sin(directionDegrees * ((float)Math.PI / 180)); float directionZ = Mth.cos(directionDegrees * ((float)Math.PI / 180)); float scale = Math.max(Math.abs(directionX), Math.abs(directionZ)); return new Vec3((double)directionX * distance / (double)scale, 0.0, (double)directionZ * distance / (double)scale); } public Vec3 getDismountLocationForPassenger(LivingEntity passenger) { return new Vec3(this.getX(), this.getBoundingBox().maxY, this.getZ()); } public @Nullable Entity getVehicle() { return this.vehicle; } public @Nullable Entity getControlledVehicle() { return this.vehicle != null && this.vehicle.getControllingPassenger() == this ? this.vehicle : null; } public PushReaction getPistonPushReaction() { return PushReaction.NORMAL; } public SoundSource getSoundSource() { return SoundSource.NEUTRAL; } protected int getFireImmuneTicks() { return 0; } public CommandSourceStack createCommandSourceStackForNameResolution(ServerLevel level) { return new CommandSourceStack(CommandSource.NULL, this.position(), this.getRotationVector(), level, PermissionSet.NO_PERMISSIONS, this.getPlainTextName(), this.getDisplayName(), level.getServer(), this); } public void lookAt(EntityAnchorArgument.Anchor anchor, Vec3 pos) { Vec3 from = anchor.apply(this); double xd = pos.x - from.x; double yd = pos.y - from.y; double zd = pos.z - from.z; double sd = Math.sqrt(xd * xd + zd * zd); this.setXRot(Mth.wrapDegrees((float)(-(Mth.atan2(yd, sd) * 57.2957763671875)))); this.setYRot(Mth.wrapDegrees((float)(Mth.atan2(zd, xd) * 57.2957763671875) - 90.0f)); this.setYHeadRot(this.getYRot()); this.xRotO = this.getXRot(); this.yRotO = this.getYRot(); } public float getPreciseBodyRotation(float partial) { return Mth.lerp(partial, this.yRotO, this.yRot); } public boolean updateFluidHeightAndDoFluidPushing(TagKey type, double flowScale) { if (this.touchingUnloadedChunk()) { return false; } AABB box = this.getBoundingBox().deflate(0.001); int x0 = Mth.floor(box.minX); int x1 = Mth.ceil(box.maxX); int y0 = Mth.floor(box.minY); int y1 = Mth.ceil(box.maxY); int z0 = Mth.floor(box.minZ); int z1 = Mth.ceil(box.maxZ); double fluidHeight = 0.0; boolean pushedByFluid = this.isPushedByFluid(); boolean inFluid = false; Vec3 current = Vec3.ZERO; int numberOfCurrents = 0; BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); for (int x = x0; x < x1; ++x) { for (int y = y0; y < y1; ++y) { for (int z = z0; z < z1; ++z) { double blockFluidHeight; pos.set(x, y, z); FluidState fluidState = this.level().getFluidState(pos); if (!fluidState.is(type) || !((blockFluidHeight = (double)((float)y + fluidState.getHeight(this.level(), pos))) >= box.minY)) continue; inFluid = true; fluidHeight = Math.max(blockFluidHeight - box.minY, fluidHeight); if (!pushedByFluid) continue; Vec3 flow = fluidState.getFlow(this.level(), pos); if (fluidHeight < 0.4) { flow = flow.scale(fluidHeight); } current = current.add(flow); ++numberOfCurrents; } } } if (current.length() > 0.0) { if (numberOfCurrents > 0) { current = current.scale(1.0 / (double)numberOfCurrents); } if (!(this instanceof Player)) { current = current.normalize(); } Vec3 oldMovement = this.getDeltaMovement(); current = current.scale(flowScale); double min = 0.003; if (Math.abs(oldMovement.x) < 0.003 && Math.abs(oldMovement.z) < 0.003 && current.length() < 0.0045000000000000005) { current = current.normalize().scale(0.0045000000000000005); } this.setDeltaMovement(this.getDeltaMovement().add(current)); } this.fluidHeight.put(type, fluidHeight); return inFluid; } public boolean touchingUnloadedChunk() { AABB box = this.getBoundingBox().inflate(1.0); int x0 = Mth.floor(box.minX); int x1 = Mth.ceil(box.maxX); int z0 = Mth.floor(box.minZ); int z1 = Mth.ceil(box.maxZ); return !this.level().hasChunksAt(x0, z0, x1, z1); } public double getFluidHeight(TagKey type) { return this.fluidHeight.getDouble(type); } public double getFluidJumpThreshold() { return (double)this.getEyeHeight() < 0.4 ? 0.0 : 0.4; } public final float getBbWidth() { return this.dimensions.width(); } public final float getBbHeight() { return this.dimensions.height(); } public Packet getAddEntityPacket(ServerEntity serverEntity) { return new ClientboundAddEntityPacket(this, serverEntity); } public EntityDimensions getDimensions(Pose pose) { return this.type.getDimensions(); } public final EntityAttachments getAttachments() { return this.dimensions.attachments(); } @Override public Vec3 position() { return this.position; } public Vec3 trackingPosition() { return this.position(); } @Override public BlockPos blockPosition() { return this.blockPosition; } public BlockState getInBlockState() { if (this.inBlockState == null) { this.inBlockState = this.level().getBlockState(this.blockPosition()); } return this.inBlockState; } public ChunkPos chunkPosition() { return this.chunkPosition; } public Vec3 getDeltaMovement() { return this.deltaMovement; } public void setDeltaMovement(Vec3 deltaMovement) { if (deltaMovement.isFinite()) { this.deltaMovement = deltaMovement; } } public void addDeltaMovement(Vec3 momentum) { if (momentum.isFinite()) { this.setDeltaMovement(this.getDeltaMovement().add(momentum)); } } public void setDeltaMovement(double xd, double yd, double zd) { this.setDeltaMovement(new Vec3(xd, yd, zd)); } public final int getBlockX() { return this.blockPosition.getX(); } public final double getX() { return this.position.x; } public double getX(double progress) { return this.position.x + (double)this.getBbWidth() * progress; } public double getRandomX(double spread) { return this.getX((2.0 * this.random.nextDouble() - 1.0) * spread); } public final int getBlockY() { return this.blockPosition.getY(); } public final double getY() { return this.position.y; } public double getY(double progress) { return this.position.y + (double)this.getBbHeight() * progress; } public double getRandomY() { return this.getY(this.random.nextDouble()); } public double getEyeY() { return this.position.y + (double)this.eyeHeight; } public final int getBlockZ() { return this.blockPosition.getZ(); } public final double getZ() { return this.position.z; } public double getZ(double progress) { return this.position.z + (double)this.getBbWidth() * progress; } public double getRandomZ(double spread) { return this.getZ((2.0 * this.random.nextDouble() - 1.0) * spread); } public final void setPosRaw(double x, double y, double z) { if (this.position.x != x || this.position.y != y || this.position.z != z) { Level level; this.position = new Vec3(x, y, z); int fx = Mth.floor(x); int fy = Mth.floor(y); int fz = Mth.floor(z); if (fx != this.blockPosition.getX() || fy != this.blockPosition.getY() || fz != this.blockPosition.getZ()) { this.blockPosition = new BlockPos(fx, fy, fz); this.inBlockState = null; if (SectionPos.blockToSectionCoord(fx) != this.chunkPosition.x || SectionPos.blockToSectionCoord(fz) != this.chunkPosition.z) { this.chunkPosition = new ChunkPos(this.blockPosition); } } this.levelCallback.onMove(); if (!this.firstTick && (level = this.level) instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; if (!this.isRemoved()) { ServerPlayer player; WaypointTransmitter waypoint; Entity entity = this; if (entity instanceof WaypointTransmitter && (waypoint = (WaypointTransmitter)((Object)entity)).isTransmittingWaypoint()) { serverLevel.getWaypointManager().updateWaypoint(waypoint); } if ((entity = this) instanceof ServerPlayer && (player = (ServerPlayer)entity).isReceivingWaypoints() && player.connection != null) { serverLevel.getWaypointManager().updatePlayer(player); } } } } } public void checkDespawn() { } public Vec3[] getQuadLeashHolderOffsets() { return Leashable.createQuadLeashOffsets(this, 0.0, 0.5, 0.5, 0.0); } public boolean supportQuadLeashAsHolder() { return false; } public void notifyLeashHolder(Leashable entity) { } public void notifyLeasheeRemoved(Leashable entity) { } public Vec3 getRopeHoldPosition(float partialTickTime) { return this.getPosition(partialTickTime).add(0.0, (double)this.eyeHeight * 0.7, 0.0); } public void recreateFromPacket(ClientboundAddEntityPacket packet) { int entityId = packet.getId(); double x = packet.getX(); double y = packet.getY(); double z = packet.getZ(); this.syncPacketPositionCodec(x, y, z); this.snapTo(x, y, z, packet.getYRot(), packet.getXRot()); this.setId(entityId); this.setUUID(packet.getUUID()); this.setDeltaMovement(packet.getMovement()); } public @Nullable ItemStack getPickResult() { return null; } public void setIsInPowderSnow(boolean isInPowderSnow) { this.isInPowderSnow = isInPowderSnow; } public boolean canFreeze() { return !this.getType().is(EntityTypeTags.FREEZE_IMMUNE_ENTITY_TYPES); } public boolean isFreezing() { return this.getTicksFrozen() > 0; } public float getYRot() { return this.yRot; } @Override public float getVisualRotationYInDegrees() { return this.getYRot(); } public void setYRot(float yRot) { if (!Float.isFinite(yRot)) { Util.logAndPauseIfInIde("Invalid entity rotation: " + yRot + ", discarding."); return; } this.yRot = yRot; } public float getXRot() { return this.xRot; } public void setXRot(float xRot) { if (!Float.isFinite(xRot)) { Util.logAndPauseIfInIde("Invalid entity rotation: " + xRot + ", discarding."); return; } this.xRot = Math.clamp(xRot % 360.0f, -90.0f, 90.0f); } public boolean canSprint() { return false; } public float maxUpStep() { return 0.0f; } public void onExplosionHit(@Nullable Entity explosionCausedBy) { } @Override public final boolean isRemoved() { return this.removalReason != null; } public @Nullable RemovalReason getRemovalReason() { return this.removalReason; } @Override public final void setRemoved(RemovalReason reason) { if (this.removalReason == null) { this.removalReason = reason; } if (this.removalReason.shouldDestroy()) { this.stopRiding(); } this.getPassengers().forEach(Entity::stopRiding); this.levelCallback.onRemove(reason); this.onRemoval(reason); } protected void unsetRemoved() { this.removalReason = null; } @Override public void setLevelCallback(EntityInLevelCallback levelCallback) { this.levelCallback = levelCallback; } @Override public boolean shouldBeSaved() { if (this.removalReason != null && !this.removalReason.shouldSave()) { return false; } if (this.isPassenger()) { return false; } return !this.isVehicle() || !this.hasExactlyOnePlayerPassenger(); } @Override public boolean isAlwaysTicking() { return false; } public boolean mayInteract(ServerLevel level, BlockPos pos) { return true; } public boolean isFlyingVehicle() { return false; } @Override public Level level() { return this.level; } protected void setLevel(Level level) { this.level = level; } public DamageSources damageSources() { return this.level().damageSources(); } public RegistryAccess registryAccess() { return this.level().registryAccess(); } protected void lerpPositionAndRotationStep(int stepsToTarget, double targetX, double targetY, double targetZ, double targetYRot, double targetXRot) { double alpha = 1.0 / (double)stepsToTarget; double x = Mth.lerp(alpha, this.getX(), targetX); double y = Mth.lerp(alpha, this.getY(), targetY); double z = Mth.lerp(alpha, this.getZ(), targetZ); float yRot = (float)Mth.rotLerp(alpha, (double)this.getYRot(), targetYRot); float xRot = (float)Mth.lerp(alpha, (double)this.getXRot(), targetXRot); this.setPos(x, y, z); this.setRot(yRot, xRot); } public RandomSource getRandom() { return this.random; } public Vec3 getKnownMovement() { LivingEntity livingEntity = this.getControllingPassenger(); if (livingEntity instanceof Player) { Player controller = (Player)livingEntity; if (this.isAlive()) { return controller.getKnownMovement(); } } return this.getDeltaMovement(); } public Vec3 getKnownSpeed() { LivingEntity livingEntity = this.getControllingPassenger(); if (livingEntity instanceof Player) { Player controller = (Player)livingEntity; if (this.isAlive()) { return controller.getKnownSpeed(); } } return this.lastKnownSpeed; } public @Nullable ItemStack getWeaponItem() { return null; } public Optional> getLootTable() { return this.type.getDefaultLootTable(); } protected void applyImplicitComponents(DataComponentGetter components) { this.applyImplicitComponentIfPresent(components, DataComponents.CUSTOM_NAME); this.applyImplicitComponentIfPresent(components, DataComponents.CUSTOM_DATA); } public final void applyComponentsFromItemStack(ItemStack stack) { this.applyImplicitComponents(stack.getComponents()); } @Override public @Nullable T get(DataComponentType type) { if (type == DataComponents.CUSTOM_NAME) { return Entity.castComponentValue(type, this.getCustomName()); } if (type == DataComponents.CUSTOM_DATA) { return Entity.castComponentValue(type, this.customData); } return null; } @Contract(value="_,!null->!null;_,_->_") protected static @Nullable T castComponentValue(DataComponentType type, @Nullable Object value) { return (T)value; } public void setComponent(DataComponentType type, T value) { this.applyImplicitComponent(type, value); } protected boolean applyImplicitComponent(DataComponentType type, T value) { if (type == DataComponents.CUSTOM_NAME) { this.setCustomName(Entity.castComponentValue(DataComponents.CUSTOM_NAME, value)); return true; } if (type == DataComponents.CUSTOM_DATA) { this.customData = Entity.castComponentValue(DataComponents.CUSTOM_DATA, value); return true; } return false; } protected boolean applyImplicitComponentIfPresent(DataComponentGetter components, DataComponentType type) { T value = components.get(type); if (value != null) { return this.applyImplicitComponent(type, value); } return false; } public ProblemReporter.PathElement problemPath() { return new EntityPathElement(this); } @Override public void registerDebugValues(ServerLevel level, DebugValueSource.Registration registration) { } public static enum RemovalReason { KILLED(true, false), DISCARDED(true, false), UNLOADED_TO_CHUNK(false, true), UNLOADED_WITH_PLAYER(false, false), CHANGED_DIMENSION(false, false); private final boolean destroy; private final boolean save; private RemovalReason(boolean destroy, boolean save) { this.destroy = destroy; this.save = save; } public boolean shouldDestroy() { return this.destroy; } public boolean shouldSave() { return this.save; } } private record Movement(Vec3 from, Vec3 to, Optional axisDependentOriginalMovement) { public Movement(Vec3 from, Vec3 to, Vec3 axisDependentOriginalMovement) { this(from, to, Optional.of(axisDependentOriginalMovement)); } public Movement(Vec3 from, Vec3 to) { this(from, to, Optional.empty()); } } public static enum MovementEmission { NONE(false, false), SOUNDS(true, false), EVENTS(false, true), ALL(true, true); final boolean sounds; final boolean events; private MovementEmission(boolean sounds, boolean events) { this.sounds = sounds; this.events = events; } public boolean emitsAnything() { return this.events || this.sounds; } public boolean emitsEvents() { return this.events; } public boolean emitsSounds() { return this.sounds; } } @FunctionalInterface public static interface MoveFunction { public void accept(Entity var1, double var2, double var4, double var6); } private record EntityPathElement(Entity entity) implements ProblemReporter.PathElement { @Override public String get() { return this.entity.toString(); } } }