minecraft-src/net/minecraft/world/entity/player/Player.java
2025-07-04 02:00:41 +03:00

2223 lines
68 KiB
Java

package net.minecraft.world.entity.player;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.math.IntMath;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
import com.mojang.logging.LogUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Predicate;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.GlobalPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stat;
import net.minecraft.stats.Stats;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.DamageTypeTags;
import net.minecraft.tags.EntityTypeTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.util.Mth;
import net.minecraft.util.Unit;
import net.minecraft.world.Container;
import net.minecraft.world.Difficulty;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffectUtil;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
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.LivingEntity;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.SlotAccess;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder;
import net.minecraft.world.entity.animal.Parrot;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.world.entity.boss.EnderDragonPart;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.warden.WardenSpawnTracker;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.entity.projectile.ProjectileDeflection;
import net.minecraft.world.food.FoodData;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ClickAction;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.PlayerEnderChestContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemCooldowns;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ProjectileWeaponItem;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
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.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseCommandBlock;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gameevent.GameEvent.Context;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.Team;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
public abstract class Player extends LivingEntity {
private static final Logger LOGGER = LogUtils.getLogger();
public static final HumanoidArm DEFAULT_MAIN_HAND = HumanoidArm.RIGHT;
public static final int DEFAULT_MODEL_CUSTOMIZATION = 0;
public static final int MAX_HEALTH = 20;
public static final int SLEEP_DURATION = 100;
public static final int WAKE_UP_DURATION = 10;
public static final int ENDER_SLOT_OFFSET = 200;
public static final int HELD_ITEM_SLOT = 499;
public static final int CRAFTING_SLOT_OFFSET = 500;
public static final float DEFAULT_BLOCK_INTERACTION_RANGE = 4.5F;
public static final float DEFAULT_ENTITY_INTERACTION_RANGE = 3.0F;
public static final float CROUCH_BB_HEIGHT = 1.5F;
public static final float SWIMMING_BB_WIDTH = 0.6F;
public static final float SWIMMING_BB_HEIGHT = 0.6F;
public static final float DEFAULT_EYE_HEIGHT = 1.62F;
private static final int CURRENT_IMPULSE_CONTEXT_RESET_GRACE_TIME_TICKS = 40;
public static final Vec3 DEFAULT_VEHICLE_ATTACHMENT = new Vec3(0.0, 0.6, 0.0);
public static final EntityDimensions STANDING_DIMENSIONS = EntityDimensions.scalable(0.6F, 1.8F)
.withEyeHeight(1.62F)
.withAttachments(EntityAttachments.builder().attach(EntityAttachment.VEHICLE, DEFAULT_VEHICLE_ATTACHMENT));
private static final Map<Pose, EntityDimensions> POSES = ImmutableMap.<Pose, EntityDimensions>builder()
.put(Pose.STANDING, STANDING_DIMENSIONS)
.put(Pose.SLEEPING, SLEEPING_DIMENSIONS)
.put(Pose.FALL_FLYING, EntityDimensions.scalable(0.6F, 0.6F).withEyeHeight(0.4F))
.put(Pose.SWIMMING, EntityDimensions.scalable(0.6F, 0.6F).withEyeHeight(0.4F))
.put(Pose.SPIN_ATTACK, EntityDimensions.scalable(0.6F, 0.6F).withEyeHeight(0.4F))
.put(
Pose.CROUCHING,
EntityDimensions.scalable(0.6F, 1.5F)
.withEyeHeight(1.27F)
.withAttachments(EntityAttachments.builder().attach(EntityAttachment.VEHICLE, DEFAULT_VEHICLE_ATTACHMENT))
)
.put(Pose.DYING, EntityDimensions.fixed(0.2F, 0.2F).withEyeHeight(1.62F))
.build();
private static final EntityDataAccessor<Float> DATA_PLAYER_ABSORPTION_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Integer> DATA_SCORE_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.INT);
protected static final EntityDataAccessor<Byte> DATA_PLAYER_MODE_CUSTOMISATION = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE);
protected static final EntityDataAccessor<Byte> DATA_PLAYER_MAIN_HAND = SynchedEntityData.defineId(Player.class, EntityDataSerializers.BYTE);
protected static final EntityDataAccessor<CompoundTag> DATA_SHOULDER_LEFT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
protected static final EntityDataAccessor<CompoundTag> DATA_SHOULDER_RIGHT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
private long timeEntitySatOnShoulder;
final Inventory inventory = new Inventory(this);
protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer();
public final InventoryMenu inventoryMenu;
public AbstractContainerMenu containerMenu;
protected FoodData foodData = new FoodData();
protected int jumpTriggerTime;
public float oBob;
public float bob;
public int takeXpDelay;
public double xCloakO;
public double yCloakO;
public double zCloakO;
public double xCloak;
public double yCloak;
public double zCloak;
private int sleepCounter;
protected boolean wasUnderwater;
private final Abilities abilities = new Abilities();
public int experienceLevel;
public int totalExperience;
public float experienceProgress;
protected int enchantmentSeed;
protected final float defaultFlySpeed = 0.02F;
private int lastLevelUpTime;
/**
* The player's unique game profile
*/
private final GameProfile gameProfile;
private boolean reducedDebugInfo;
private ItemStack lastItemInMainHand = ItemStack.EMPTY;
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
@Nullable
public FishingHook fishing;
protected float hurtDir;
@Nullable
public Vec3 currentImpulseImpactPos;
@Nullable
public Entity currentExplosionCause;
private boolean ignoreFallDamageFromCurrentImpulse;
private int currentImpulseContextResetGraceTime;
public Player(Level level, BlockPos pos, float yRot, GameProfile gameProfile) {
super(EntityType.PLAYER, level);
this.setUUID(gameProfile.getId());
this.gameProfile = gameProfile;
this.inventoryMenu = new InventoryMenu(this.inventory, !level.isClientSide, this);
this.containerMenu = this.inventoryMenu;
this.moveTo(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, yRot, 0.0F);
this.rotOffs = 180.0F;
}
public boolean blockActionRestricted(Level level, BlockPos pos, GameType gameMode) {
if (!gameMode.isBlockPlacingRestricted()) {
return false;
} else if (gameMode == GameType.SPECTATOR) {
return true;
} else if (this.mayBuild()) {
return false;
} else {
ItemStack itemStack = this.getMainHandItem();
return itemStack.isEmpty() || !itemStack.canBreakBlockInAdventureMode(new BlockInWorld(level, pos, false));
}
}
public static Builder createAttributes() {
return LivingEntity.createLivingAttributes()
.add(Attributes.ATTACK_DAMAGE, 1.0)
.add(Attributes.MOVEMENT_SPEED, 0.1F)
.add(Attributes.ATTACK_SPEED)
.add(Attributes.LUCK)
.add(Attributes.BLOCK_INTERACTION_RANGE, 4.5)
.add(Attributes.ENTITY_INTERACTION_RANGE, 3.0)
.add(Attributes.BLOCK_BREAK_SPEED)
.add(Attributes.SUBMERGED_MINING_SPEED)
.add(Attributes.SNEAKING_SPEED)
.add(Attributes.MINING_EFFICIENCY)
.add(Attributes.SWEEPING_DAMAGE_RATIO);
}
@Override
protected void defineSynchedData(net.minecraft.network.syncher.SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(DATA_PLAYER_ABSORPTION_ID, 0.0F);
builder.define(DATA_SCORE_ID, 0);
builder.define(DATA_PLAYER_MODE_CUSTOMISATION, (byte)0);
builder.define(DATA_PLAYER_MAIN_HAND, (byte)DEFAULT_MAIN_HAND.getId());
builder.define(DATA_SHOULDER_LEFT, new CompoundTag());
builder.define(DATA_SHOULDER_RIGHT, new CompoundTag());
}
@Override
public void tick() {
this.noPhysics = this.isSpectator();
if (this.isSpectator()) {
this.setOnGround(false);
}
if (this.takeXpDelay > 0) {
this.takeXpDelay--;
}
if (this.isSleeping()) {
this.sleepCounter++;
if (this.sleepCounter > 100) {
this.sleepCounter = 100;
}
if (!this.level().isClientSide && this.level().isDay()) {
this.stopSleepInBed(false, true);
}
} else if (this.sleepCounter > 0) {
this.sleepCounter++;
if (this.sleepCounter >= 110) {
this.sleepCounter = 0;
}
}
this.updateIsUnderwater();
super.tick();
if (!this.level().isClientSide && this.containerMenu != null && !this.containerMenu.stillValid(this)) {
this.closeContainer();
this.containerMenu = this.inventoryMenu;
}
this.moveCloak();
if (this instanceof ServerPlayer serverPlayer) {
this.foodData.tick(serverPlayer);
this.awardStat(Stats.PLAY_TIME);
this.awardStat(Stats.TOTAL_WORLD_TIME);
if (this.isAlive()) {
this.awardStat(Stats.TIME_SINCE_DEATH);
}
if (this.isDiscrete()) {
this.awardStat(Stats.CROUCH_TIME);
}
if (!this.isSleeping()) {
this.awardStat(Stats.TIME_SINCE_REST);
}
}
int i = 29999999;
double d = Mth.clamp(this.getX(), -2.9999999E7, 2.9999999E7);
double e = Mth.clamp(this.getZ(), -2.9999999E7, 2.9999999E7);
if (d != this.getX() || e != this.getZ()) {
this.setPos(d, this.getY(), e);
}
this.attackStrengthTicker++;
ItemStack itemStack = this.getMainHandItem();
if (!ItemStack.matches(this.lastItemInMainHand, itemStack)) {
if (!ItemStack.isSameItem(this.lastItemInMainHand, itemStack)) {
this.resetAttackStrengthTicker();
}
this.lastItemInMainHand = itemStack.copy();
}
if (!this.isEyeInFluid(FluidTags.WATER) && this.isEquipped(Items.TURTLE_HELMET)) {
this.turtleHelmetTick();
}
this.cooldowns.tick();
this.updatePlayerPose();
if (this.currentImpulseContextResetGraceTime > 0) {
this.currentImpulseContextResetGraceTime--;
}
}
@Override
protected float getMaxHeadRotationRelativeToBody() {
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
}
public boolean isSecondaryUseActive() {
return this.isShiftKeyDown();
}
protected boolean wantsToStopRiding() {
return this.isShiftKeyDown();
}
protected boolean isStayingOnGroundSurface() {
return this.isShiftKeyDown();
}
protected boolean updateIsUnderwater() {
this.wasUnderwater = this.isEyeInFluid(FluidTags.WATER);
return this.wasUnderwater;
}
@Override
public void onAboveBubbleCol(boolean downwards) {
if (!this.getAbilities().flying) {
super.onAboveBubbleCol(downwards);
}
}
@Override
public void onInsideBubbleColumn(boolean downwards) {
if (!this.getAbilities().flying) {
super.onInsideBubbleColumn(downwards);
}
}
private void turtleHelmetTick() {
this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true));
}
private boolean isEquipped(Item item) {
for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
ItemStack itemStack = this.getItemBySlot(equipmentSlot);
Equippable equippable = itemStack.get(DataComponents.EQUIPPABLE);
if (itemStack.is(item) && equippable != null && equippable.slot() == equipmentSlot) {
return true;
}
}
return false;
}
protected ItemCooldowns createItemCooldowns() {
return new ItemCooldowns();
}
private void moveCloak() {
this.xCloakO = this.xCloak;
this.yCloakO = this.yCloak;
this.zCloakO = this.zCloak;
double d = this.getX() - this.xCloak;
double e = this.getY() - this.yCloak;
double f = this.getZ() - this.zCloak;
double g = 10.0;
if (d > 10.0) {
this.xCloak = this.getX();
this.xCloakO = this.xCloak;
}
if (f > 10.0) {
this.zCloak = this.getZ();
this.zCloakO = this.zCloak;
}
if (e > 10.0) {
this.yCloak = this.getY();
this.yCloakO = this.yCloak;
}
if (d < -10.0) {
this.xCloak = this.getX();
this.xCloakO = this.xCloak;
}
if (f < -10.0) {
this.zCloak = this.getZ();
this.zCloakO = this.zCloak;
}
if (e < -10.0) {
this.yCloak = this.getY();
this.yCloakO = this.yCloak;
}
this.xCloak += d * 0.25;
this.zCloak += f * 0.25;
this.yCloak += e * 0.25;
}
protected void updatePlayerPose() {
if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) {
Pose pose;
if (this.isFallFlying()) {
pose = Pose.FALL_FLYING;
} else if (this.isSleeping()) {
pose = Pose.SLEEPING;
} else if (this.isSwimming()) {
pose = Pose.SWIMMING;
} else if (this.isAutoSpinAttack()) {
pose = Pose.SPIN_ATTACK;
} else if (this.isShiftKeyDown() && !this.abilities.flying) {
pose = Pose.CROUCHING;
} else {
pose = Pose.STANDING;
}
Pose pose2;
if (this.isSpectator() || this.isPassenger() || this.canPlayerFitWithinBlocksAndEntitiesWhen(pose)) {
pose2 = pose;
} else if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)) {
pose2 = Pose.CROUCHING;
} else {
pose2 = Pose.SWIMMING;
}
this.setPose(pose2);
}
}
protected boolean canPlayerFitWithinBlocksAndEntitiesWhen(Pose pose) {
return this.level().noCollision(this, this.getDimensions(pose).makeBoundingBox(this.position()).deflate(1.0E-7));
}
@Override
protected SoundEvent getSwimSound() {
return SoundEvents.PLAYER_SWIM;
}
@Override
protected SoundEvent getSwimSplashSound() {
return SoundEvents.PLAYER_SPLASH;
}
@Override
protected SoundEvent getSwimHighSpeedSplashSound() {
return SoundEvents.PLAYER_SPLASH_HIGH_SPEED;
}
@Override
public int getDimensionChangingDelay() {
return 10;
}
@Override
public void playSound(SoundEvent sound, float volume, float pitch) {
this.level().playSound(this, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), volume, pitch);
}
public void playNotifySound(SoundEvent sound, SoundSource source, float volume, float pitch) {
}
@Override
public SoundSource getSoundSource() {
return SoundSource.PLAYERS;
}
@Override
protected int getFireImmuneTicks() {
return 20;
}
@Override
public void handleEntityEvent(byte id) {
if (id == 9) {
this.completeUsingItem();
} else if (id == 23) {
this.reducedDebugInfo = false;
} else if (id == 22) {
this.reducedDebugInfo = true;
} else {
super.handleEntityEvent(id);
}
}
/**
* Sets the current crafting inventory back to the 2x2 square.
*/
protected void closeContainer() {
this.containerMenu = this.inventoryMenu;
}
protected void doCloseContainer() {
}
@Override
public void rideTick() {
if (!this.level().isClientSide && this.wantsToStopRiding() && this.isPassenger()) {
this.stopRiding();
this.setShiftKeyDown(false);
} else {
super.rideTick();
this.oBob = this.bob;
this.bob = 0.0F;
}
}
@Override
protected void serverAiStep() {
super.serverAiStep();
this.updateSwingTime();
this.yHeadRot = this.getYRot();
}
@Override
public void aiStep() {
if (this.jumpTriggerTime > 0) {
this.jumpTriggerTime--;
}
this.tickRegeneration();
this.inventory.tick();
this.oBob = this.bob;
if (this.abilities.flying && !this.isPassenger()) {
this.resetFallDistance();
}
super.aiStep();
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
float f;
if (this.onGround() && !this.isDeadOrDying() && !this.isSwimming()) {
f = Math.min(0.1F, (float)this.getDeltaMovement().horizontalDistance());
} else {
f = 0.0F;
}
this.bob = this.bob + (f - this.bob) * 0.4F;
if (this.getHealth() > 0.0F && !this.isSpectator()) {
AABB aABB;
if (this.isPassenger() && !this.getVehicle().isRemoved()) {
aABB = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0);
} else {
aABB = this.getBoundingBox().inflate(1.0, 0.5, 1.0);
}
List<Entity> list = this.level().getEntities(this, aABB);
List<Entity> list2 = Lists.<Entity>newArrayList();
for (Entity entity : list) {
if (entity.getType() == EntityType.EXPERIENCE_ORB) {
list2.add(entity);
} else if (!entity.isRemoved()) {
this.touch(entity);
}
}
if (!list2.isEmpty()) {
this.touch(Util.getRandom(list2, this.random));
}
}
this.playShoulderEntityAmbientSound(this.getShoulderEntityLeft());
this.playShoulderEntityAmbientSound(this.getShoulderEntityRight());
if (!this.level().isClientSide && (this.fallDistance > 0.5F || this.isInWater()) || this.abilities.flying || this.isSleeping() || this.isInPowderSnow) {
this.removeEntitiesOnShoulder();
}
}
protected void tickRegeneration() {
}
private void playShoulderEntityAmbientSound(@Nullable CompoundTag entityCompound) {
if (entityCompound != null && (!entityCompound.contains("Silent") || !entityCompound.getBoolean("Silent")) && this.level().random.nextInt(200) == 0) {
String string = entityCompound.getString("id");
EntityType.byString(string)
.filter(entityType -> entityType == EntityType.PARROT)
.ifPresent(
entityType -> {
if (!Parrot.imitateNearbyMobs(this.level(), this)) {
this.level()
.playSound(
null,
this.getX(),
this.getY(),
this.getZ(),
Parrot.getAmbient(this.level(), this.level().random),
this.getSoundSource(),
1.0F,
Parrot.getPitch(this.level().random)
);
}
}
);
}
}
private void touch(Entity entity) {
entity.playerTouch(this);
}
public int getScore() {
return this.entityData.get(DATA_SCORE_ID);
}
/**
* Set player's score
*/
public void setScore(int score) {
this.entityData.set(DATA_SCORE_ID, score);
}
/**
* Add to player's score
*/
public void increaseScore(int score) {
int i = this.getScore();
this.entityData.set(DATA_SCORE_ID, i + score);
}
/**
* Starts the attack used by the Riptide enchantment.
*/
public void startAutoSpinAttack(int ticks, float damage, ItemStack itemStack) {
this.autoSpinAttackTicks = ticks;
this.autoSpinAttackDmg = damage;
this.autoSpinAttackItemStack = itemStack;
if (!this.level().isClientSide) {
this.removeEntitiesOnShoulder();
this.setLivingEntityFlag(4, true);
}
}
@NotNull
@Override
public ItemStack getWeaponItem() {
return this.isAutoSpinAttack() && this.autoSpinAttackItemStack != null ? this.autoSpinAttackItemStack : super.getWeaponItem();
}
@Override
public void die(DamageSource damageSource) {
super.die(damageSource);
this.reapplyPosition();
if (!this.isSpectator() && this.level() instanceof ServerLevel serverLevel) {
this.dropAllDeathLoot(serverLevel, damageSource);
}
if (damageSource != null) {
this.setDeltaMovement(
-Mth.cos((this.getHurtDir() + this.getYRot()) * (float) (Math.PI / 180.0)) * 0.1F,
0.1F,
-Mth.sin((this.getHurtDir() + this.getYRot()) * (float) (Math.PI / 180.0)) * 0.1F
);
} else {
this.setDeltaMovement(0.0, 0.1, 0.0);
}
this.awardStat(Stats.DEATHS);
this.resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_DEATH));
this.resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_REST));
this.clearFire();
this.setSharedFlagOnFire(false);
this.setLastDeathLocation(Optional.of(GlobalPos.of(this.level().dimension(), this.blockPosition())));
}
@Override
protected void dropEquipment(ServerLevel serverLevel) {
super.dropEquipment(serverLevel);
if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY)) {
this.destroyVanishingCursedItems();
this.inventory.dropAll();
}
}
protected void destroyVanishingCursedItems() {
for (int i = 0; i < this.inventory.getContainerSize(); i++) {
ItemStack itemStack = this.inventory.getItem(i);
if (!itemStack.isEmpty() && EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) {
this.inventory.removeItemNoUpdate(i);
}
}
}
@Override
protected SoundEvent getHurtSound(DamageSource damageSource) {
return damageSource.type().effects().sound();
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.PLAYER_DEATH;
}
public void handleCreativeModeItemDrop(ItemStack itemStack) {
}
/**
* Drops an item into the world.
*/
@Nullable
public ItemEntity drop(ItemStack itemStack, boolean includeThrowerName) {
return this.drop(itemStack, false, includeThrowerName);
}
/**
* Creates and drops the provided item. Depending on the dropAround, it will drop the item around the player, instead of dropping the item from where the player is pointing at. Likewise, if includeThrowerName is true, the dropped item entity will have the thrower set as the player.
*/
@Nullable
public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean includeThrowerName) {
if (!droppedItem.isEmpty() && this.level().isClientSide) {
this.swing(InteractionHand.MAIN_HAND);
}
return null;
}
public float getDestroySpeed(BlockState state) {
float f = this.inventory.getDestroySpeed(state);
if (f > 1.0F) {
f += (float)this.getAttributeValue(Attributes.MINING_EFFICIENCY);
}
if (MobEffectUtil.hasDigSpeed(this)) {
f *= 1.0F + (MobEffectUtil.getDigSpeedAmplification(this) + 1) * 0.2F;
}
if (this.hasEffect(MobEffects.DIG_SLOWDOWN)) {
float g = switch (this.getEffect(MobEffects.DIG_SLOWDOWN).getAmplifier()) {
case 0 -> 0.3F;
case 1 -> 0.09F;
case 2 -> 0.0027F;
default -> 8.1E-4F;
};
f *= g;
}
f *= (float)this.getAttributeValue(Attributes.BLOCK_BREAK_SPEED);
if (this.isEyeInFluid(FluidTags.WATER)) {
f *= (float)this.getAttribute(Attributes.SUBMERGED_MINING_SPEED).getValue();
}
if (!this.onGround()) {
f /= 5.0F;
}
return f;
}
public boolean hasCorrectToolForDrops(BlockState state) {
return !state.requiresCorrectToolForDrops() || this.inventory.getSelected().isCorrectToolForDrops(state);
}
@Override
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
this.setUUID(this.gameProfile.getId());
ListTag listTag = compound.getList("Inventory", 10);
this.inventory.load(listTag);
this.inventory.selected = compound.getInt("SelectedItemSlot");
this.sleepCounter = compound.getShort("SleepTimer");
this.experienceProgress = compound.getFloat("XpP");
this.experienceLevel = compound.getInt("XpLevel");
this.totalExperience = compound.getInt("XpTotal");
this.enchantmentSeed = compound.getInt("XpSeed");
if (this.enchantmentSeed == 0) {
this.enchantmentSeed = this.random.nextInt();
}
this.setScore(compound.getInt("Score"));
this.foodData.readAdditionalSaveData(compound);
this.abilities.loadSaveData(compound);
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.abilities.getWalkingSpeed());
if (compound.contains("EnderItems", 9)) {
this.enderChestInventory.fromTag(compound.getList("EnderItems", 10), this.registryAccess());
}
if (compound.contains("ShoulderEntityLeft", 10)) {
this.setShoulderEntityLeft(compound.getCompound("ShoulderEntityLeft"));
}
if (compound.contains("ShoulderEntityRight", 10)) {
this.setShoulderEntityRight(compound.getCompound("ShoulderEntityRight"));
}
if (compound.contains("LastDeathLocation", 10)) {
this.setLastDeathLocation(GlobalPos.CODEC.parse(NbtOps.INSTANCE, compound.get("LastDeathLocation")).resultOrPartial(LOGGER::error));
}
if (compound.contains("current_explosion_impact_pos", 9)) {
Vec3.CODEC
.parse(NbtOps.INSTANCE, compound.get("current_explosion_impact_pos"))
.resultOrPartial(LOGGER::error)
.ifPresent(vec3 -> this.currentImpulseImpactPos = vec3);
}
this.ignoreFallDamageFromCurrentImpulse = compound.getBoolean("ignore_fall_damage_from_current_explosion");
this.currentImpulseContextResetGraceTime = compound.getInt("current_impulse_context_reset_grace_time");
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
NbtUtils.addCurrentDataVersion(compound);
compound.put("Inventory", this.inventory.save(new ListTag()));
compound.putInt("SelectedItemSlot", this.inventory.selected);
compound.putShort("SleepTimer", (short)this.sleepCounter);
compound.putFloat("XpP", this.experienceProgress);
compound.putInt("XpLevel", this.experienceLevel);
compound.putInt("XpTotal", this.totalExperience);
compound.putInt("XpSeed", this.enchantmentSeed);
compound.putInt("Score", this.getScore());
this.foodData.addAdditionalSaveData(compound);
this.abilities.addSaveData(compound);
compound.put("EnderItems", this.enderChestInventory.createTag(this.registryAccess()));
if (!this.getShoulderEntityLeft().isEmpty()) {
compound.put("ShoulderEntityLeft", this.getShoulderEntityLeft());
}
if (!this.getShoulderEntityRight().isEmpty()) {
compound.put("ShoulderEntityRight", this.getShoulderEntityRight());
}
this.getLastDeathLocation()
.flatMap(globalPos -> GlobalPos.CODEC.encodeStart(NbtOps.INSTANCE, globalPos).resultOrPartial(LOGGER::error))
.ifPresent(tag -> compound.put("LastDeathLocation", tag));
if (this.currentImpulseImpactPos != null) {
compound.put("current_explosion_impact_pos", Vec3.CODEC.encodeStart(NbtOps.INSTANCE, this.currentImpulseImpactPos).getOrThrow());
}
compound.putBoolean("ignore_fall_damage_from_current_explosion", this.ignoreFallDamageFromCurrentImpulse);
compound.putInt("current_impulse_context_reset_grace_time", this.currentImpulseContextResetGraceTime);
}
@Override
public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) {
if (super.isInvulnerableTo(serverLevel, damageSource)) {
return true;
} else if (damageSource.is(DamageTypeTags.IS_DROWNING)) {
return !serverLevel.getGameRules().getBoolean(GameRules.RULE_DROWNING_DAMAGE);
} else if (damageSource.is(DamageTypeTags.IS_FALL)) {
return !serverLevel.getGameRules().getBoolean(GameRules.RULE_FALL_DAMAGE);
} else if (damageSource.is(DamageTypeTags.IS_FIRE)) {
return !serverLevel.getGameRules().getBoolean(GameRules.RULE_FIRE_DAMAGE);
} else {
return damageSource.is(DamageTypeTags.IS_FREEZING) ? !serverLevel.getGameRules().getBoolean(GameRules.RULE_FREEZE_DAMAGE) : false;
}
}
@Override
public boolean hurtServer(ServerLevel serverLevel, DamageSource damageSource, float f) {
if (this.isInvulnerableTo(serverLevel, damageSource)) {
return false;
} else if (this.abilities.invulnerable && !damageSource.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) {
return false;
} else {
this.noActionTime = 0;
if (this.isDeadOrDying()) {
return false;
} else {
this.removeEntitiesOnShoulder();
if (damageSource.scalesWithDifficulty()) {
if (serverLevel.getDifficulty() == Difficulty.PEACEFUL) {
f = 0.0F;
}
if (serverLevel.getDifficulty() == Difficulty.EASY) {
f = Math.min(f / 2.0F + 1.0F, f);
}
if (serverLevel.getDifficulty() == Difficulty.HARD) {
f = f * 3.0F / 2.0F;
}
}
return f == 0.0F ? false : super.hurtServer(serverLevel, damageSource, f);
}
}
}
@Override
protected void blockUsingShield(LivingEntity attacker) {
super.blockUsingShield(attacker);
ItemStack itemStack = this.getItemBlockingWith();
if (attacker.canDisableShield() && itemStack != null) {
this.disableShield(itemStack);
}
}
@Override
public boolean canBeSeenAsEnemy() {
return !this.getAbilities().invulnerable && super.canBeSeenAsEnemy();
}
public boolean canHarmPlayer(Player other) {
Team team = this.getTeam();
Team team2 = other.getTeam();
if (team == null) {
return true;
} else {
return !team.isAlliedTo(team2) ? true : team.isAllowFriendlyFire();
}
}
@Override
protected void hurtArmor(DamageSource damageSource, float damageAmount) {
this.doHurtEquipment(damageSource, damageAmount, new EquipmentSlot[]{EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD});
}
@Override
protected void hurtHelmet(DamageSource damageSource, float damageAmount) {
this.doHurtEquipment(damageSource, damageAmount, new EquipmentSlot[]{EquipmentSlot.HEAD});
}
@Override
protected void hurtCurrentlyUsedShield(float damageAmount) {
if (this.useItem.is(Items.SHIELD)) {
if (!this.level().isClientSide) {
this.awardStat(Stats.ITEM_USED.get(this.useItem.getItem()));
}
if (damageAmount >= 3.0F) {
int i = 1 + Mth.floor(damageAmount);
InteractionHand interactionHand = this.getUsedItemHand();
this.useItem.hurtAndBreak(i, this, getSlotForHand(interactionHand));
if (this.useItem.isEmpty()) {
if (interactionHand == InteractionHand.MAIN_HAND) {
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
} else {
this.setItemSlot(EquipmentSlot.OFFHAND, ItemStack.EMPTY);
}
this.useItem = ItemStack.EMPTY;
this.playSound(SoundEvents.SHIELD_BREAK, 0.8F, 0.8F + this.level().random.nextFloat() * 0.4F);
}
}
}
}
@Override
protected void actuallyHurt(ServerLevel serverLevel, DamageSource damageSource, float f) {
if (!this.isInvulnerableTo(serverLevel, damageSource)) {
f = this.getDamageAfterArmorAbsorb(damageSource, f);
f = this.getDamageAfterMagicAbsorb(damageSource, f);
float var8 = Math.max(f - this.getAbsorptionAmount(), 0.0F);
this.setAbsorptionAmount(this.getAbsorptionAmount() - (f - var8));
float h = f - var8;
if (h > 0.0F && h < 3.4028235E37F) {
this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(h * 10.0F));
}
if (var8 != 0.0F) {
this.causeFoodExhaustion(damageSource.getFoodExhaustion());
this.getCombatTracker().recordDamage(damageSource, var8);
this.setHealth(this.getHealth() - var8);
if (var8 < 3.4028235E37F) {
this.awardStat(Stats.DAMAGE_TAKEN, Math.round(var8 * 10.0F));
}
this.gameEvent(GameEvent.ENTITY_DAMAGE);
}
}
}
public boolean isTextFilteringEnabled() {
return false;
}
public void openTextEdit(SignBlockEntity signEntity, boolean isFrontText) {
}
public void openMinecartCommandBlock(BaseCommandBlock commandEntity) {
}
public void openCommandBlock(CommandBlockEntity commandBlockEntity) {
}
public void openStructureBlock(StructureBlockEntity structureEntity) {
}
public void openJigsawBlock(JigsawBlockEntity jigsawBlockEntity) {
}
public void openHorseInventory(AbstractHorse horse, Container inventory) {
}
public OptionalInt openMenu(@Nullable MenuProvider menu) {
return OptionalInt.empty();
}
public void sendMerchantOffers(int containerId, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) {
}
public void openItemGui(ItemStack stack, InteractionHand hand) {
}
public InteractionResult interactOn(Entity entityToInteractOn, InteractionHand hand) {
if (this.isSpectator()) {
if (entityToInteractOn instanceof MenuProvider) {
this.openMenu((MenuProvider)entityToInteractOn);
}
return InteractionResult.PASS;
} else {
ItemStack itemStack = this.getItemInHand(hand);
ItemStack itemStack2 = itemStack.copy();
InteractionResult interactionResult = entityToInteractOn.interact(this, hand);
if (interactionResult.consumesAction()) {
if (this.abilities.instabuild && itemStack == this.getItemInHand(hand) && itemStack.getCount() < itemStack2.getCount()) {
itemStack.setCount(itemStack2.getCount());
}
return interactionResult;
} else {
if (!itemStack.isEmpty() && entityToInteractOn instanceof LivingEntity) {
if (this.abilities.instabuild) {
itemStack = itemStack2;
}
InteractionResult interactionResult2 = itemStack.interactLivingEntity(this, (LivingEntity)entityToInteractOn, hand);
if (interactionResult2.consumesAction()) {
this.level().gameEvent(GameEvent.ENTITY_INTERACT, entityToInteractOn.position(), Context.of(this));
if (itemStack.isEmpty() && !this.abilities.instabuild) {
this.setItemInHand(hand, ItemStack.EMPTY);
}
return interactionResult2;
}
}
return InteractionResult.PASS;
}
}
}
@Override
public void removeVehicle() {
super.removeVehicle();
this.boardingCooldown = 0;
}
@Override
protected boolean isImmobile() {
return super.isImmobile() || this.isSleeping();
}
@Override
public boolean isAffectedByFluids() {
return !this.abilities.flying;
}
@Override
protected Vec3 maybeBackOffFromEdge(Vec3 vec, MoverType mover) {
float f = this.maxUpStep();
if (!this.abilities.flying
&& !(vec.y > 0.0)
&& (mover == MoverType.SELF || mover == MoverType.PLAYER)
&& this.isStayingOnGroundSurface()
&& this.isAboveGround(f)) {
double d = vec.x;
double e = vec.z;
double g = 0.05;
double h = Math.signum(d) * 0.05;
double i;
for (i = Math.signum(e) * 0.05; d != 0.0 && this.canFallAtLeast(d, 0.0, f); d -= h) {
if (Math.abs(d) <= 0.05) {
d = 0.0;
break;
}
}
while (e != 0.0 && this.canFallAtLeast(0.0, e, f)) {
if (Math.abs(e) <= 0.05) {
e = 0.0;
break;
}
e -= i;
}
while (d != 0.0 && e != 0.0 && this.canFallAtLeast(d, e, f)) {
if (Math.abs(d) <= 0.05) {
d = 0.0;
} else {
d -= h;
}
if (Math.abs(e) <= 0.05) {
e = 0.0;
} else {
e -= i;
}
}
return new Vec3(d, vec.y, e);
} else {
return vec;
}
}
private boolean isAboveGround(float maxUpStep) {
return this.onGround() || this.fallDistance < maxUpStep && !this.canFallAtLeast(0.0, 0.0, maxUpStep - this.fallDistance);
}
private boolean canFallAtLeast(double x, double z, float distance) {
AABB aABB = this.getBoundingBox();
return this.level().noCollision(this, new AABB(aABB.minX + x, aABB.minY - distance - 1.0E-5F, aABB.minZ + z, aABB.maxX + x, aABB.minY, aABB.maxZ + z));
}
/**
* Attacks for the player the targeted entity with the currently equipped item. The equipped item has hitEntity called on it. Args: targetEntity
*/
public void attack(Entity target) {
if (target.isAttackable()) {
if (!target.skipAttackInteraction(this)) {
float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE);
ItemStack itemStack = this.getWeaponItem();
DamageSource damageSource = (DamageSource)Optional.ofNullable(itemStack.getItem().getDamageSource(this)).orElse(this.damageSources().playerAttack(this));
float g = this.getEnchantedDamage(target, f, damageSource) - f;
float h = this.getAttackStrengthScale(0.5F);
f *= 0.2F + h * h * 0.8F;
g *= h;
this.resetAttackStrengthTicker();
if (target.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE)
&& target instanceof Projectile projectile
&& projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource());
} else {
if (f > 0.0F || g > 0.0F) {
boolean bl = h > 0.9F;
boolean bl2;
if (this.isSprinting() && bl) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F);
bl2 = true;
} else {
bl2 = false;
}
f += itemStack.getItem().getAttackDamageBonus(target, f, damageSource);
boolean bl3 = bl
&& this.fallDistance > 0.0F
&& !this.onGround()
&& !this.onClimbable()
&& !this.isInWater()
&& !this.hasEffect(MobEffects.BLINDNESS)
&& !this.isPassenger()
&& target instanceof LivingEntity
&& !this.isSprinting();
if (bl3) {
f *= 1.5F;
}
float i = f + g;
boolean bl4 = false;
if (bl && !bl3 && !bl2 && this.onGround()) {
double d = this.getKnownMovement().horizontalDistanceSqr();
double e = this.getSpeed() * 2.5;
if (d < Mth.square(e) && this.getItemInHand(InteractionHand.MAIN_HAND).is(ItemTags.SWORDS)) {
bl4 = true;
}
}
float j = 0.0F;
if (target instanceof LivingEntity livingEntity) {
j = livingEntity.getHealth();
}
Vec3 vec3 = target.getDeltaMovement();
boolean bl5 = target.hurtOrSimulate(damageSource, i);
if (bl5) {
float k = this.getKnockback(target, damageSource) + (bl2 ? 1.0F : 0.0F);
if (k > 0.0F) {
if (target instanceof LivingEntity livingEntity2) {
livingEntity2.knockback(k * 0.5F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)));
} else {
target.push(-Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)) * k * 0.5F, 0.1, Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) * k * 0.5F);
}
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6));
this.setSprinting(false);
}
if (bl4) {
float l = 1.0F + (float)this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * f;
for (LivingEntity livingEntity3 : this.level().getEntitiesOfClass(LivingEntity.class, target.getBoundingBox().inflate(1.0, 0.25, 1.0))) {
if (livingEntity3 != this
&& livingEntity3 != target
&& !this.isAlliedTo(livingEntity3)
&& (!(livingEntity3 instanceof ArmorStand) || !((ArmorStand)livingEntity3).isMarker())
&& this.distanceToSqr(livingEntity3) < 9.0) {
float m = this.getEnchantedDamage(livingEntity3, l, damageSource) * h;
livingEntity3.knockback(0.4F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)));
livingEntity3.hurt(damageSource, m);
if (this.level() instanceof ServerLevel serverLevel) {
EnchantmentHelper.doPostAttackEffects(serverLevel, livingEntity3, damageSource);
}
}
}
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, this.getSoundSource(), 1.0F, 1.0F);
this.sweepAttack();
}
if (target instanceof ServerPlayer && target.hurtMarked) {
((ServerPlayer)target).connection.send(new ClientboundSetEntityMotionPacket(target));
target.hurtMarked = false;
target.setDeltaMovement(vec3);
}
if (bl3) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.getSoundSource(), 1.0F, 1.0F);
this.crit(target);
}
if (!bl3 && !bl4) {
if (bl) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.getSoundSource(), 1.0F, 1.0F);
} else {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_WEAK, this.getSoundSource(), 1.0F, 1.0F);
}
}
if (g > 0.0F) {
this.magicCrit(target);
}
this.setLastHurtMob(target);
Entity entity = target;
if (target instanceof EnderDragonPart) {
entity = ((EnderDragonPart)target).parentMob;
}
boolean bl6 = false;
if (this.level() instanceof ServerLevel serverLevel2) {
if (entity instanceof LivingEntity livingEntity3x) {
bl6 = itemStack.hurtEnemy(livingEntity3x, this);
}
EnchantmentHelper.doPostAttackEffects(serverLevel2, target, damageSource);
}
if (!this.level().isClientSide && !itemStack.isEmpty() && entity instanceof LivingEntity) {
if (bl6) {
itemStack.postHurtEnemy((LivingEntity)entity, this);
}
if (itemStack.isEmpty()) {
if (itemStack == this.getMainHandItem()) {
this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY);
} else {
this.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
}
}
}
if (target instanceof LivingEntity) {
float n = j - ((LivingEntity)target).getHealth();
this.awardStat(Stats.DAMAGE_DEALT, Math.round(n * 10.0F));
if (this.level() instanceof ServerLevel && n > 2.0F) {
int o = (int)(n * 0.5);
((ServerLevel)this.level()).sendParticles(ParticleTypes.DAMAGE_INDICATOR, target.getX(), target.getY(0.5), target.getZ(), o, 0.1, 0.0, 0.1, 0.2);
}
}
this.causeFoodExhaustion(0.1F);
} else {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F);
}
}
}
}
}
}
protected float getEnchantedDamage(Entity entity, float damage, DamageSource damageSource) {
return damage;
}
@Override
protected void doAutoAttackOnTouch(LivingEntity target) {
this.attack(target);
}
public void disableShield(ItemStack itemStack) {
this.getCooldowns().addCooldown(itemStack, 100);
this.stopUsingItem();
this.level().broadcastEntityEvent(this, (byte)30);
}
/**
* Called when the entity is dealt a critical hit.
*/
public void crit(Entity entityHit) {
}
/**
* Called when the entity hit is dealt extra melee damage due to an enchantment.
*/
public void magicCrit(Entity entityHit) {
}
public void sweepAttack() {
double d = -Mth.sin(this.getYRot() * (float) (Math.PI / 180.0));
double e = Mth.cos(this.getYRot() * (float) (Math.PI / 180.0));
if (this.level() instanceof ServerLevel) {
((ServerLevel)this.level()).sendParticles(ParticleTypes.SWEEP_ATTACK, this.getX() + d, this.getY(0.5), this.getZ() + e, 0, d, 0.0, e, 0.0);
}
}
public void respawn() {
}
@Override
public void remove(Entity.RemovalReason reason) {
super.remove(reason);
this.inventoryMenu.removed(this);
if (this.containerMenu != null && this.hasContainerOpen()) {
this.doCloseContainer();
}
}
/**
* Returns whether this is a {@link net.minecraft.client.player.LocalPlayer}.
*/
public boolean isLocalPlayer() {
return false;
}
/**
* Returns the GameProfile for this player
*/
public GameProfile getGameProfile() {
return this.gameProfile;
}
public Inventory getInventory() {
return this.inventory;
}
public Abilities getAbilities() {
return this.abilities;
}
@Override
public boolean hasInfiniteMaterials() {
return this.abilities.instabuild;
}
public void updateTutorialInventoryAction(ItemStack carried, ItemStack clicked, ClickAction action) {
}
public boolean hasContainerOpen() {
return this.containerMenu != this.inventoryMenu;
}
public boolean canDropItems() {
return true;
}
public Either<Player.BedSleepingProblem, Unit> startSleepInBed(BlockPos bedPos) {
this.startSleeping(bedPos);
this.sleepCounter = 0;
return Either.right(Unit.INSTANCE);
}
public void stopSleepInBed(boolean wakeImmediately, boolean updateLevelForSleepingPlayers) {
super.stopSleeping();
if (this.level() instanceof ServerLevel && updateLevelForSleepingPlayers) {
((ServerLevel)this.level()).updateSleepingPlayerList();
}
this.sleepCounter = wakeImmediately ? 0 : 100;
}
@Override
public void stopSleeping() {
this.stopSleepInBed(true, true);
}
/**
* Returns whether the player is asleep and the screen has fully faded.
*/
public boolean isSleepingLongEnough() {
return this.isSleeping() && this.sleepCounter >= 100;
}
public int getSleepTimer() {
return this.sleepCounter;
}
public void displayClientMessage(Component chatComponent, boolean actionBar) {
}
public void awardStat(ResourceLocation statKey) {
this.awardStat(Stats.CUSTOM.get(statKey));
}
public void awardStat(ResourceLocation stat, int increment) {
this.awardStat(Stats.CUSTOM.get(stat), increment);
}
/**
* Add a stat once
*/
public void awardStat(Stat<?> stat) {
this.awardStat(stat, 1);
}
/**
* Adds a value to a statistic field.
*/
public void awardStat(Stat<?> stat, int increment) {
}
public void resetStat(Stat<?> stat) {
}
public int awardRecipes(Collection<RecipeHolder<?>> recipes) {
return 0;
}
public void triggerRecipeCrafted(RecipeHolder<?> recipe, List<ItemStack> items) {
}
public void awardRecipesByKey(List<ResourceKey<Recipe<?>>> recipes) {
}
public int resetRecipes(Collection<RecipeHolder<?>> recipes) {
return 0;
}
@Override
public void travel(Vec3 travelVector) {
if (this.isPassenger()) {
super.travel(travelVector);
} else {
if (this.isSwimming()) {
double d = this.getLookAngle().y;
double e = d < -0.2 ? 0.085 : 0.06;
if (d <= 0.0 || this.jumping || !this.level().getFluidState(BlockPos.containing(this.getX(), this.getY() + 1.0 - 0.1, this.getZ())).isEmpty()) {
Vec3 vec3 = this.getDeltaMovement();
this.setDeltaMovement(vec3.add(0.0, (d - vec3.y) * e, 0.0));
}
}
if (this.getAbilities().flying) {
double d = this.getDeltaMovement().y;
super.travel(travelVector);
this.setDeltaMovement(this.getDeltaMovement().with(Direction.Axis.Y, d * 0.6));
} else {
super.travel(travelVector);
}
}
}
@Override
protected boolean canGlide() {
return !this.abilities.flying && super.canGlide();
}
@Override
public void updateSwimming() {
if (this.abilities.flying) {
this.setSwimming(false);
} else {
super.updateSwimming();
}
}
protected boolean freeAt(BlockPos pos) {
return !this.level().getBlockState(pos).isSuffocating(this.level(), pos);
}
@Override
public float getSpeed() {
return (float)this.getAttributeValue(Attributes.MOVEMENT_SPEED);
}
@Override
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
if (this.abilities.mayfly) {
return false;
} else {
if (fallDistance >= 2.0F) {
this.awardStat(Stats.FALL_ONE_CM, (int)Math.round(fallDistance * 100.0));
}
boolean bl = this.currentImpulseImpactPos != null && this.ignoreFallDamageFromCurrentImpulse;
float f;
if (bl) {
f = Math.min(fallDistance, (float)(this.currentImpulseImpactPos.y - this.getY()));
boolean bl2 = f <= 0.0F;
if (bl2) {
this.resetCurrentImpulseContext();
} else {
this.tryResetCurrentImpulseContext();
}
} else {
f = fallDistance;
}
if (f > 0.0F && super.causeFallDamage(f, multiplier, source)) {
this.resetCurrentImpulseContext();
return true;
} else {
return false;
}
}
}
public boolean tryToStartFallFlying() {
if (!this.isFallFlying() && this.canGlide() && !this.isInWater()) {
this.startFallFlying();
return true;
} else {
return false;
}
}
public void startFallFlying() {
this.setSharedFlag(7, true);
}
public void stopFallFlying() {
this.setSharedFlag(7, true);
this.setSharedFlag(7, false);
}
@Override
protected void doWaterSplashEffect() {
if (!this.isSpectator()) {
super.doWaterSplashEffect();
}
}
@Override
protected void playStepSound(BlockPos pos, BlockState state) {
if (this.isInWater()) {
this.waterSwimSound();
this.playMuffledStepSound(state);
} else {
BlockPos blockPos = this.getPrimaryStepSoundBlockPos(pos);
if (!pos.equals(blockPos)) {
BlockState blockState = this.level().getBlockState(blockPos);
if (blockState.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS)) {
this.playCombinationStepSounds(blockState, state);
} else {
super.playStepSound(blockPos, blockState);
}
} else {
super.playStepSound(pos, state);
}
}
}
@Override
public LivingEntity.Fallsounds getFallSounds() {
return new LivingEntity.Fallsounds(SoundEvents.PLAYER_SMALL_FALL, SoundEvents.PLAYER_BIG_FALL);
}
@Override
public boolean killedEntity(ServerLevel level, LivingEntity entity) {
this.awardStat(Stats.ENTITY_KILLED.get(entity.getType()));
return true;
}
@Override
public void makeStuckInBlock(BlockState state, Vec3 motionMultiplier) {
if (!this.abilities.flying) {
super.makeStuckInBlock(state, motionMultiplier);
}
this.tryResetCurrentImpulseContext();
}
public void giveExperiencePoints(int xpPoints) {
this.increaseScore(xpPoints);
this.experienceProgress = this.experienceProgress + (float)xpPoints / this.getXpNeededForNextLevel();
this.totalExperience = Mth.clamp(this.totalExperience + xpPoints, 0, Integer.MAX_VALUE);
while (this.experienceProgress < 0.0F) {
float f = this.experienceProgress * this.getXpNeededForNextLevel();
if (this.experienceLevel > 0) {
this.giveExperienceLevels(-1);
this.experienceProgress = 1.0F + f / this.getXpNeededForNextLevel();
} else {
this.giveExperienceLevels(-1);
this.experienceProgress = 0.0F;
}
}
while (this.experienceProgress >= 1.0F) {
this.experienceProgress = (this.experienceProgress - 1.0F) * this.getXpNeededForNextLevel();
this.giveExperienceLevels(1);
this.experienceProgress = this.experienceProgress / this.getXpNeededForNextLevel();
}
}
public int getEnchantmentSeed() {
return this.enchantmentSeed;
}
public void onEnchantmentPerformed(ItemStack enchantedItem, int levelCost) {
this.experienceLevel -= levelCost;
if (this.experienceLevel < 0) {
this.experienceLevel = 0;
this.experienceProgress = 0.0F;
this.totalExperience = 0;
}
this.enchantmentSeed = this.random.nextInt();
}
/**
* Add experience levels to this player.
*/
public void giveExperienceLevels(int levels) {
this.experienceLevel = IntMath.saturatedAdd(this.experienceLevel, levels);
if (this.experienceLevel < 0) {
this.experienceLevel = 0;
this.experienceProgress = 0.0F;
this.totalExperience = 0;
}
if (levels > 0 && this.experienceLevel % 5 == 0 && this.lastLevelUpTime < this.tickCount - 100.0F) {
float f = this.experienceLevel > 30 ? 1.0F : this.experienceLevel / 30.0F;
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), f * 0.75F, 1.0F);
this.lastLevelUpTime = this.tickCount;
}
}
/**
* This method returns the cap amount of experience that the experience bar can hold. With each level, the experience cap on the player's experience bar is raised by 10.
*/
public int getXpNeededForNextLevel() {
if (this.experienceLevel >= 30) {
return 112 + (this.experienceLevel - 30) * 9;
} else {
return this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2;
}
}
/**
* Increases exhaustion level by the supplied amount.
*/
public void causeFoodExhaustion(float exhaustion) {
if (!this.abilities.invulnerable) {
if (!this.level().isClientSide) {
this.foodData.addExhaustion(exhaustion);
}
}
}
public Optional<WardenSpawnTracker> getWardenSpawnTracker() {
return Optional.empty();
}
/**
* Returns the player's FoodStats object.
*/
public FoodData getFoodData() {
return this.foodData;
}
public boolean canEat(boolean canAlwaysEat) {
return this.abilities.invulnerable || canAlwaysEat || this.foodData.needsFood();
}
/**
* Checks if the player's health is not full and not zero.
*/
public boolean isHurt() {
return this.getHealth() > 0.0F && this.getHealth() < this.getMaxHealth();
}
public boolean mayBuild() {
return this.abilities.mayBuild;
}
/**
* Returns whether this player can modify the block at a certain location with the given stack.
* <p>
* The position being queried is {@code pos.offset(facing.getOpposite())}.
*
* @return Whether this player may modify the queried location in the current world
* @see ItemStack#canPlaceOn(Block)
* @see ItemStack#canEditBlocks()
* @see PlayerCapabilities#allowEdit
*/
public boolean mayUseItemAt(BlockPos pos, Direction facing, ItemStack stack) {
if (this.abilities.mayBuild) {
return true;
} else {
BlockPos blockPos = pos.relative(facing.getOpposite());
BlockInWorld blockInWorld = new BlockInWorld(this.level(), blockPos, false);
return stack.canPlaceOnBlockInAdventureMode(blockInWorld);
}
}
@Override
protected int getBaseExperienceReward(ServerLevel serverLevel) {
return !serverLevel.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator() ? Math.min(this.experienceLevel * 7, 100) : 0;
}
@Override
protected boolean isAlwaysExperienceDropper() {
return true;
}
@Override
public boolean shouldShowName() {
return true;
}
@Override
protected Entity.MovementEmission getMovementEmission() {
return this.abilities.flying || this.onGround() && this.isDiscrete() ? Entity.MovementEmission.NONE : Entity.MovementEmission.ALL;
}
/**
* Sends the player's abilities to the server (if there is one).
*/
public void onUpdateAbilities() {
}
@Override
public Component getName() {
return Component.literal(this.gameProfile.getName());
}
/**
* Returns the InventoryEnderChest of this player.
*/
public PlayerEnderChestContainer getEnderChestInventory() {
return this.enderChestInventory;
}
@Override
public ItemStack getItemBySlot(EquipmentSlot slot) {
if (slot == EquipmentSlot.MAINHAND) {
return this.inventory.getSelected();
} else if (slot == EquipmentSlot.OFFHAND) {
return (ItemStack)this.inventory.offhand.getFirst();
} else {
return slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR ? this.inventory.armor.get(slot.getIndex()) : ItemStack.EMPTY;
}
}
@Override
protected boolean doesEmitEquipEvent(EquipmentSlot slot) {
return slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR;
}
@Override
public void setItemSlot(EquipmentSlot slot, ItemStack stack) {
this.verifyEquippedItem(stack);
if (slot == EquipmentSlot.MAINHAND) {
this.onEquipItem(slot, this.inventory.items.set(this.inventory.selected, stack), stack);
} else if (slot == EquipmentSlot.OFFHAND) {
this.onEquipItem(slot, this.inventory.offhand.set(0, stack), stack);
} else if (slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
this.onEquipItem(slot, this.inventory.armor.set(slot.getIndex(), stack), stack);
}
}
public boolean addItem(ItemStack stack) {
return this.inventory.add(stack);
}
@Override
public Iterable<ItemStack> getHandSlots() {
return Lists.<ItemStack>newArrayList(this.getMainHandItem(), this.getOffhandItem());
}
@Override
public Iterable<ItemStack> getArmorSlots() {
return this.inventory.armor;
}
@Override
public boolean canUseSlot(EquipmentSlot slot) {
return slot != EquipmentSlot.BODY;
}
public boolean setEntityOnShoulder(CompoundTag entityCompound) {
if (this.isPassenger() || !this.onGround() || this.isInWater() || this.isInPowderSnow) {
return false;
} else if (this.getShoulderEntityLeft().isEmpty()) {
this.setShoulderEntityLeft(entityCompound);
this.timeEntitySatOnShoulder = this.level().getGameTime();
return true;
} else if (this.getShoulderEntityRight().isEmpty()) {
this.setShoulderEntityRight(entityCompound);
this.timeEntitySatOnShoulder = this.level().getGameTime();
return true;
} else {
return false;
}
}
protected void removeEntitiesOnShoulder() {
if (this.timeEntitySatOnShoulder + 20L < this.level().getGameTime()) {
this.respawnEntityOnShoulder(this.getShoulderEntityLeft());
this.setShoulderEntityLeft(new CompoundTag());
this.respawnEntityOnShoulder(this.getShoulderEntityRight());
this.setShoulderEntityRight(new CompoundTag());
}
}
private void respawnEntityOnShoulder(CompoundTag entityCompound) {
if (!this.level().isClientSide && !entityCompound.isEmpty()) {
EntityType.create(entityCompound, this.level(), EntitySpawnReason.LOAD).ifPresent(entity -> {
if (entity instanceof TamableAnimal) {
((TamableAnimal)entity).setOwnerUUID(this.uuid);
}
entity.setPos(this.getX(), this.getY() + 0.7F, this.getZ());
((ServerLevel)this.level()).addWithUUID(entity);
});
}
}
@Override
public abstract boolean isSpectator();
@Override
public boolean canBeHitByProjectile() {
return !this.isSpectator() && super.canBeHitByProjectile();
}
@Override
public boolean isSwimming() {
return !this.abilities.flying && !this.isSpectator() && super.isSwimming();
}
public abstract boolean isCreative();
@Override
public boolean isPushedByFluid() {
return !this.abilities.flying;
}
public Scoreboard getScoreboard() {
return this.level().getScoreboard();
}
@Override
public Component getDisplayName() {
MutableComponent mutableComponent = PlayerTeam.formatNameForTeam(this.getTeam(), this.getName());
return this.decorateDisplayNameComponent(mutableComponent);
}
private MutableComponent decorateDisplayNameComponent(MutableComponent displayName) {
String string = this.getGameProfile().getName();
return displayName.withStyle(
style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/tell " + string + " "))
.withHoverEvent(this.createHoverEvent())
.withInsertion(string)
);
}
@Override
public String getScoreboardName() {
return this.getGameProfile().getName();
}
@Override
protected void internalSetAbsorptionAmount(float absorptionAmount) {
this.getEntityData().set(DATA_PLAYER_ABSORPTION_ID, absorptionAmount);
}
@Override
public float getAbsorptionAmount() {
return this.getEntityData().get(DATA_PLAYER_ABSORPTION_ID);
}
public boolean isModelPartShown(PlayerModelPart part) {
return (this.getEntityData().get(DATA_PLAYER_MODE_CUSTOMISATION) & part.getMask()) == part.getMask();
}
@Override
public SlotAccess getSlot(int slot) {
if (slot == 499) {
return new SlotAccess() {
@Override
public ItemStack get() {
return Player.this.containerMenu.getCarried();
}
@Override
public boolean set(ItemStack carried) {
Player.this.containerMenu.setCarried(carried);
return true;
}
};
} else {
final int i = slot - 500;
if (i >= 0 && i < 4) {
return new SlotAccess() {
@Override
public ItemStack get() {
return Player.this.inventoryMenu.getCraftSlots().getItem(i);
}
@Override
public boolean set(ItemStack carried) {
Player.this.inventoryMenu.getCraftSlots().setItem(i, carried);
Player.this.inventoryMenu.slotsChanged(Player.this.inventory);
return true;
}
};
} else if (slot >= 0 && slot < this.inventory.items.size()) {
return SlotAccess.forContainer(this.inventory, slot);
} else {
int j = slot - 200;
return j >= 0 && j < this.enderChestInventory.getContainerSize() ? SlotAccess.forContainer(this.enderChestInventory, j) : super.getSlot(slot);
}
}
}
/**
* Whether the "reducedDebugInfo" option is active for this player.
*/
public boolean isReducedDebugInfo() {
return this.reducedDebugInfo;
}
public void setReducedDebugInfo(boolean reducedDebugInfo) {
this.reducedDebugInfo = reducedDebugInfo;
}
@Override
public void setRemainingFireTicks(int remainingFireTicks) {
super.setRemainingFireTicks(this.abilities.invulnerable ? Math.min(remainingFireTicks, 1) : remainingFireTicks);
}
@Override
public HumanoidArm getMainArm() {
return this.entityData.get(DATA_PLAYER_MAIN_HAND) == 0 ? HumanoidArm.LEFT : HumanoidArm.RIGHT;
}
public void setMainArm(HumanoidArm hand) {
this.entityData.set(DATA_PLAYER_MAIN_HAND, (byte)(hand == HumanoidArm.LEFT ? 0 : 1));
}
public CompoundTag getShoulderEntityLeft() {
return this.entityData.get(DATA_SHOULDER_LEFT);
}
protected void setShoulderEntityLeft(CompoundTag entityCompound) {
this.entityData.set(DATA_SHOULDER_LEFT, entityCompound);
}
public CompoundTag getShoulderEntityRight() {
return this.entityData.get(DATA_SHOULDER_RIGHT);
}
protected void setShoulderEntityRight(CompoundTag entityCompound) {
this.entityData.set(DATA_SHOULDER_RIGHT, entityCompound);
}
public float getCurrentItemAttackStrengthDelay() {
return (float)(1.0 / this.getAttributeValue(Attributes.ATTACK_SPEED) * 20.0);
}
/**
* Returns the percentage of attack power available based on the cooldown (zero to one).
*/
public float getAttackStrengthScale(float adjustTicks) {
return Mth.clamp((this.attackStrengthTicker + adjustTicks) / this.getCurrentItemAttackStrengthDelay(), 0.0F, 1.0F);
}
public void resetAttackStrengthTicker() {
this.attackStrengthTicker = 0;
}
public ItemCooldowns getCooldowns() {
return this.cooldowns;
}
@Override
protected float getBlockSpeedFactor() {
return !this.abilities.flying && !this.isFallFlying() ? super.getBlockSpeedFactor() : 1.0F;
}
public float getLuck() {
return (float)this.getAttributeValue(Attributes.LUCK);
}
public boolean canUseGameMasterBlocks() {
return this.abilities.instabuild && this.getPermissionLevel() >= 2;
}
protected int getPermissionLevel() {
return 0;
}
public boolean hasPermissions(int i) {
return this.getPermissionLevel() >= i;
}
@Override
public EntityDimensions getDefaultDimensions(Pose pose) {
return (EntityDimensions)POSES.getOrDefault(pose, STANDING_DIMENSIONS);
}
@Override
public ImmutableList<Pose> getDismountPoses() {
return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING);
}
@Override
public ItemStack getProjectile(ItemStack weaponStack) {
if (!(weaponStack.getItem() instanceof ProjectileWeaponItem)) {
return ItemStack.EMPTY;
} else {
Predicate<ItemStack> predicate = ((ProjectileWeaponItem)weaponStack.getItem()).getSupportedHeldProjectiles();
ItemStack itemStack = ProjectileWeaponItem.getHeldProjectile(this, predicate);
if (!itemStack.isEmpty()) {
return itemStack;
} else {
predicate = ((ProjectileWeaponItem)weaponStack.getItem()).getAllSupportedProjectiles();
for (int i = 0; i < this.inventory.getContainerSize(); i++) {
ItemStack itemStack2 = this.inventory.getItem(i);
if (predicate.test(itemStack2)) {
return itemStack2;
}
}
return this.abilities.instabuild ? new ItemStack(Items.ARROW) : ItemStack.EMPTY;
}
}
}
@Override
public Vec3 getRopeHoldPosition(float partialTicks) {
double d = 0.22 * (this.getMainArm() == HumanoidArm.RIGHT ? -1.0 : 1.0);
float f = Mth.lerp(partialTicks * 0.5F, this.getXRot(), this.xRotO) * (float) (Math.PI / 180.0);
float g = Mth.lerp(partialTicks, this.yBodyRotO, this.yBodyRot) * (float) (Math.PI / 180.0);
if (this.isFallFlying() || this.isAutoSpinAttack()) {
Vec3 vec3 = this.getViewVector(partialTicks);
Vec3 vec32 = this.getDeltaMovement();
double e = vec32.horizontalDistanceSqr();
double h = vec3.horizontalDistanceSqr();
float k;
if (e > 0.0 && h > 0.0) {
double i = (vec32.x * vec3.x + vec32.z * vec3.z) / Math.sqrt(e * h);
double j = vec32.x * vec3.z - vec32.z * vec3.x;
k = (float)(Math.signum(j) * Math.acos(i));
} else {
k = 0.0F;
}
return this.getPosition(partialTicks).add(new Vec3(d, -0.11, 0.85).zRot(-k).xRot(-f).yRot(-g));
} else if (this.isVisuallySwimming()) {
return this.getPosition(partialTicks).add(new Vec3(d, 0.2, -0.15).xRot(-f).yRot(-g));
} else {
double l = this.getBoundingBox().getYsize() - 1.0;
double e = this.isCrouching() ? -0.2 : 0.07;
return this.getPosition(partialTicks).add(new Vec3(d, l, e).yRot(-g));
}
}
@Override
public boolean isAlwaysTicking() {
return true;
}
public boolean isScoping() {
return this.isUsingItem() && this.getUseItem().is(Items.SPYGLASS);
}
@Override
public boolean shouldBeSaved() {
return false;
}
public Optional<GlobalPos> getLastDeathLocation() {
return this.lastDeathLocation;
}
public void setLastDeathLocation(Optional<GlobalPos> lastDeathLocation) {
this.lastDeathLocation = lastDeathLocation;
}
@Override
public float getHurtDir() {
return this.hurtDir;
}
@Override
public void animateHurt(float yaw) {
super.animateHurt(yaw);
this.hurtDir = yaw;
}
@Override
public boolean canSprint() {
return true;
}
@Override
protected float getFlyingSpeed() {
if (this.abilities.flying && !this.isPassenger()) {
return this.isSprinting() ? this.abilities.getFlyingSpeed() * 2.0F : this.abilities.getFlyingSpeed();
} else {
return this.isSprinting() ? 0.025999999F : 0.02F;
}
}
public double blockInteractionRange() {
return this.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
}
public double entityInteractionRange() {
return this.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
}
public boolean canInteractWithEntity(Entity entity, double distance) {
return entity.isRemoved() ? false : this.canInteractWithEntity(entity.getBoundingBox(), distance);
}
public boolean canInteractWithEntity(AABB boundingBox, double distance) {
double d = this.entityInteractionRange() + distance;
return boundingBox.distanceToSqr(this.getEyePosition()) < d * d;
}
public boolean canInteractWithBlock(BlockPos pos, double distance) {
double d = this.blockInteractionRange() + distance;
return new AABB(pos).distanceToSqr(this.getEyePosition()) < d * d;
}
public void setIgnoreFallDamageFromCurrentImpulse(boolean ignoreFallDamageFromCurrentImpulse) {
this.ignoreFallDamageFromCurrentImpulse = ignoreFallDamageFromCurrentImpulse;
if (ignoreFallDamageFromCurrentImpulse) {
this.currentImpulseContextResetGraceTime = 40;
} else {
this.currentImpulseContextResetGraceTime = 0;
}
}
public boolean isIgnoringFallDamageFromCurrentImpulse() {
return this.ignoreFallDamageFromCurrentImpulse;
}
public void tryResetCurrentImpulseContext() {
if (this.currentImpulseContextResetGraceTime == 0) {
this.resetCurrentImpulseContext();
}
}
public void resetCurrentImpulseContext() {
this.currentImpulseContextResetGraceTime = 0;
this.currentExplosionCause = null;
this.currentImpulseImpactPos = null;
this.ignoreFallDamageFromCurrentImpulse = false;
}
public boolean shouldRotateWithMinecart() {
return false;
}
@Override
public boolean isControlledByClient() {
return true;
}
public static enum BedSleepingProblem {
NOT_POSSIBLE_HERE,
NOT_POSSIBLE_NOW(Component.translatable("block.minecraft.bed.no_sleep")),
TOO_FAR_AWAY(Component.translatable("block.minecraft.bed.too_far_away")),
OBSTRUCTED(Component.translatable("block.minecraft.bed.obstructed")),
OTHER_PROBLEM,
NOT_SAFE(Component.translatable("block.minecraft.bed.not_safe"));
@Nullable
private final Component message;
private BedSleepingProblem() {
this.message = null;
}
private BedSleepingProblem(final Component message) {
this.message = message;
}
@Nullable
public Component getMessage() {
return this.message;
}
}
}