2025-11-24 22:52:51 +03:00

1974 lines
75 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.google.common.base.MoreObjects
* com.google.common.collect.ImmutableList
* com.google.common.collect.Lists
* com.google.common.math.IntMath
* com.mojang.authlib.GameProfile
* com.mojang.datafixers.util.Either
* org.jspecify.annotations.Nullable
*/
package net.minecraft.world.entity.player;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.math.IntMath;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.GlobalPos;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
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.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dialog.Dialog;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.permissions.PermissionSet;
import net.minecraft.server.permissions.Permissions;
import net.minecraft.server.players.NameAndId;
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.util.Util;
import net.minecraft.world.Container;
import net.minecraft.world.Difficulty;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemStackWithSlot;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.attribute.EnvironmentAttributes;
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.Avatar;
import net.minecraft.world.entity.ContainerUser;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityEquipment;
import net.minecraft.world.entity.EntityReference;
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.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
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.player.Abilities;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.PlayerEquipment;
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.entity.vehicle.MinecartCommandBlock;
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.component.BlocksAttacks;
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.GameType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.level.block.entity.ContainerOpenersCounter;
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.entity.TestBlockEntity;
import net.minecraft.world.level.block.entity.TestInstanceBlockEntity;
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.gamerules.GameRules;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Team;
import org.jspecify.annotations.Nullable;
public abstract class Player
extends Avatar
implements ContainerUser {
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;
private static final int CURRENT_IMPULSE_CONTEXT_RESET_GRACE_TIME_TICKS = 40;
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);
private static final EntityDataAccessor<OptionalInt> DATA_SHOULDER_PARROT_LEFT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.OPTIONAL_UNSIGNED_INT);
private static final EntityDataAccessor<OptionalInt> DATA_SHOULDER_PARROT_RIGHT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.OPTIONAL_UNSIGNED_INT);
public static final int CLIENT_LOADED_TIMEOUT_TIME = 60;
private static final short DEFAULT_SLEEP_TIMER = 0;
private static final float DEFAULT_EXPERIENCE_PROGRESS = 0.0f;
private static final int DEFAULT_EXPERIENCE_LEVEL = 0;
private static final int DEFAULT_TOTAL_EXPERIENCE = 0;
private static final int NO_ENCHANTMENT_SEED = 0;
private static final int DEFAULT_SELECTED_SLOT = 0;
private static final int DEFAULT_SCORE = 0;
private static final boolean DEFAULT_IGNORE_FALL_DAMAGE_FROM_CURRENT_IMPULSE = false;
private static final int DEFAULT_CURRENT_IMPULSE_CONTEXT_RESET_GRACE_TIME = 0;
private final Inventory inventory;
protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer();
public final InventoryMenu inventoryMenu;
public AbstractContainerMenu containerMenu;
protected FoodData foodData = new FoodData();
protected int jumpTriggerTime;
private boolean clientLoaded = false;
protected int clientLoadedTimeoutTimer = 60;
public int takeXpDelay;
private int sleepCounter = 0;
protected boolean wasUnderwater;
private final Abilities abilities = new Abilities();
public int experienceLevel = 0;
public int totalExperience = 0;
public float experienceProgress = 0.0f;
protected int enchantmentSeed = 0;
protected final float defaultFlySpeed = 0.02f;
private int lastLevelUpTime;
private final GameProfile gameProfile;
private boolean reducedDebugInfo;
private ItemStack lastItemInMainHand = ItemStack.EMPTY;
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
public @Nullable FishingHook fishing;
protected float hurtDir;
public @Nullable Vec3 currentImpulseImpactPos;
public @Nullable Entity currentExplosionCause;
private boolean ignoreFallDamageFromCurrentImpulse = false;
private int currentImpulseContextResetGraceTime = 0;
public Player(Level level, GameProfile gameProfile) {
super((EntityType<? extends LivingEntity>)EntityType.PLAYER, level);
this.setUUID(gameProfile.id());
this.gameProfile = gameProfile;
this.inventory = new Inventory(this, this.equipment);
this.inventoryMenu = new InventoryMenu(this.inventory, !level.isClientSide(), this);
this.containerMenu = this.inventoryMenu;
}
@Override
protected EntityEquipment createEquipment() {
return new PlayerEquipment(this);
}
public boolean blockActionRestricted(Level level, BlockPos pos, GameType gameType) {
if (!gameType.isBlockPlacingRestricted()) {
return false;
}
if (gameType == GameType.SPECTATOR) {
return true;
}
if (this.mayBuild()) {
return false;
}
ItemStack itemStack = this.getMainHandItem();
return itemStack.isEmpty() || !itemStack.canBreakBlockInAdventureMode(new BlockInWorld(level, pos, false));
}
public static AttributeSupplier.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).add(Attributes.WAYPOINT_TRANSMIT_RANGE, 6.0E7).add(Attributes.WAYPOINT_RECEIVE_RANGE, 6.0E7);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder entityData) {
super.defineSynchedData(entityData);
entityData.define(DATA_PLAYER_ABSORPTION_ID, Float.valueOf(0.0f));
entityData.define(DATA_SCORE_ID, 0);
entityData.define(DATA_SHOULDER_PARROT_LEFT, OptionalInt.empty());
entityData.define(DATA_SHOULDER_PARROT_RIGHT, OptionalInt.empty());
}
@Override
public void tick() {
this.noPhysics = this.isSpectator();
if (this.isSpectator() || this.isPassenger()) {
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().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, this.position()).canSleep(this.level())) {
this.stopSleepInBed(false, true);
}
} else if (this.sleepCounter > 0) {
++this.sleepCounter;
if (this.sleepCounter >= 110) {
this.sleepCounter = 0;
}
}
this.updateIsUnderwater();
super.tick();
int maxPositionOffset = 29999999;
double nx = Mth.clamp(this.getX(), -2.9999999E7, 2.9999999E7);
double nz = Mth.clamp(this.getZ(), -2.9999999E7, 2.9999999E7);
if (nx != this.getX() || nz != this.getZ()) {
this.setPos(nx, this.getY(), nz);
}
++this.attackStrengthTicker;
++this.itemSwapTicker;
ItemStack mainHandItemStack = this.getMainHandItem();
if (!ItemStack.matches(this.lastItemInMainHand, mainHandItemStack)) {
if (!ItemStack.isSameItem(this.lastItemInMainHand, mainHandItemStack)) {
this.resetAttackStrengthTicker();
}
this.lastItemInMainHand = mainHandItemStack.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() {
if (this.isBlocking()) {
return 15.0f;
}
return 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 onAboveBubbleColumn(boolean dragDown, BlockPos pos) {
if (!this.getAbilities().flying) {
super.onAboveBubbleColumn(dragDown, pos);
}
}
@Override
public void onInsideBubbleColumn(boolean dragDown) {
if (!this.getAbilities().flying) {
super.onInsideBubbleColumn(dragDown);
}
}
private void turtleHelmetTick() {
this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true));
}
private boolean isEquipped(Item item) {
for (EquipmentSlot slot : EquipmentSlot.VALUES) {
ItemStack itemStack = this.getItemBySlot(slot);
Equippable equippable = itemStack.get(DataComponents.EQUIPPABLE);
if (!itemStack.is(item) || equippable == null || equippable.slot() != slot) continue;
return true;
}
return false;
}
protected ItemCooldowns createItemCooldowns() {
return new ItemCooldowns();
}
protected void updatePlayerPose() {
if (!this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) {
return;
}
Pose desiredPose = this.getDesiredPose();
Pose actualPose = this.isSpectator() || this.isPassenger() || this.canPlayerFitWithinBlocksAndEntitiesWhen(desiredPose) ? desiredPose : (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING) ? Pose.CROUCHING : Pose.SWIMMING);
this.setPose(actualPose);
}
private Pose getDesiredPose() {
if (this.isSleeping()) {
return Pose.SLEEPING;
}
if (this.isSwimming()) {
return Pose.SWIMMING;
}
if (this.isFallFlying()) {
return Pose.FALL_FLYING;
}
if (this.isAutoSpinAttack()) {
return Pose.SPIN_ATTACK;
}
if (this.isShiftKeyDown() && !this.abilities.flying) {
return Pose.CROUCHING;
}
return Pose.STANDING;
}
protected boolean canPlayerFitWithinBlocksAndEntitiesWhen(Pose newPose) {
return this.level().noCollision(this, this.getDimensions(newPose).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((Entity)this, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), volume, pitch);
}
public void playNotifySound(SoundEvent sound, SoundSource soundSource, 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.setReducedDebugInfo(false);
} else if (id == 22) {
this.setReducedDebugInfo(true);
} else {
super.handleEntityEvent(id);
}
}
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);
return;
}
super.rideTick();
}
@Override
public void aiStep() {
if (this.jumpTriggerTime > 0) {
--this.jumpTriggerTime;
}
this.tickRegeneration();
this.inventory.tick();
if (this.abilities.flying && !this.isPassenger()) {
this.resetFallDistance();
}
super.aiStep();
this.updateSwingTime();
this.yHeadRot = this.getYRot();
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
if (this.getHealth() > 0.0f && !this.isSpectator()) {
AABB pickupArea = this.isPassenger() && !this.getVehicle().isRemoved() ? this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0) : this.getBoundingBox().inflate(1.0, 0.5, 1.0);
List<Entity> entities = this.level().getEntities(this, pickupArea);
ArrayList orbs = Lists.newArrayList();
for (Entity entity : entities) {
if (entity.getType() == EntityType.EXPERIENCE_ORB) {
orbs.add(entity);
continue;
}
if (entity.isRemoved()) continue;
this.touch(entity);
}
if (!orbs.isEmpty()) {
this.touch((Entity)Util.getRandom(orbs, this.random));
}
}
this.handleShoulderEntities();
}
protected void tickRegeneration() {
}
public void handleShoulderEntities() {
}
protected void removeEntitiesOnShoulder() {
}
private void touch(Entity entity) {
entity.playerTouch(this);
}
public int getScore() {
return this.entityData.get(DATA_SCORE_ID);
}
public void setScore(int value) {
this.entityData.set(DATA_SCORE_ID, value);
}
public void increaseScore(int amount) {
int score = this.getScore();
this.entityData.set(DATA_SCORE_ID, score + amount);
}
public void startAutoSpinAttack(int activationTicks, float dmg, ItemStack itemStackUsed) {
this.autoSpinAttackTicks = activationTicks;
this.autoSpinAttackDmg = dmg;
this.autoSpinAttackItemStack = itemStackUsed;
if (!this.level().isClientSide()) {
this.removeEntitiesOnShoulder();
this.setLivingEntityFlag(4, true);
}
}
@Override
public ItemStack getWeaponItem() {
if (this.isAutoSpinAttack() && this.autoSpinAttackItemStack != null) {
return this.autoSpinAttackItemStack;
}
return super.getWeaponItem();
}
@Override
public void die(DamageSource source) {
Level level;
super.die(source);
this.reapplyPosition();
if (!this.isSpectator() && (level = this.level()) instanceof ServerLevel) {
ServerLevel level2 = (ServerLevel)level;
this.dropAllDeathLoot(level2, source);
}
if (source != null) {
this.setDeltaMovement(-Mth.cos((this.getHurtDir() + this.getYRot()) * ((float)Math.PI / 180)) * 0.1f, 0.1f, -Mth.sin((this.getHurtDir() + this.getYRot()) * ((float)Math.PI / 180)) * 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 level) {
super.dropEquipment(level);
if (!level.getGameRules().get(GameRules.KEEP_INVENTORY).booleanValue()) {
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)) continue;
this.inventory.removeItemNoUpdate(i);
}
}
@Override
protected SoundEvent getHurtSound(DamageSource source) {
return source.type().effects().sound();
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.PLAYER_DEATH;
}
public void handleCreativeModeItemDrop(ItemStack stack) {
}
public @Nullable ItemEntity drop(ItemStack itemStack, boolean thrownFromHand) {
return this.drop(itemStack, false, thrownFromHand);
}
public float getDestroySpeed(BlockState state) {
float speed = this.inventory.getSelectedItem().getDestroySpeed(state);
if (speed > 1.0f) {
speed += (float)this.getAttributeValue(Attributes.MINING_EFFICIENCY);
}
if (MobEffectUtil.hasDigSpeed(this)) {
speed *= 1.0f + (float)(MobEffectUtil.getDigSpeedAmplification(this) + 1) * 0.2f;
}
if (this.hasEffect(MobEffects.MINING_FATIGUE)) {
float scale = switch (this.getEffect(MobEffects.MINING_FATIGUE).getAmplifier()) {
case 0 -> 0.3f;
case 1 -> 0.09f;
case 2 -> 0.0027f;
default -> 8.1E-4f;
};
speed *= scale;
}
speed *= (float)this.getAttributeValue(Attributes.BLOCK_BREAK_SPEED);
if (this.isEyeInFluid(FluidTags.WATER)) {
speed *= (float)this.getAttribute(Attributes.SUBMERGED_MINING_SPEED).getValue();
}
if (!this.onGround()) {
speed /= 5.0f;
}
return speed;
}
public boolean hasCorrectToolForDrops(BlockState state) {
return !state.requiresCorrectToolForDrops() || this.inventory.getSelectedItem().isCorrectToolForDrops(state);
}
@Override
protected void readAdditionalSaveData(ValueInput input) {
super.readAdditionalSaveData(input);
this.setUUID(this.gameProfile.id());
this.inventory.load(input.listOrEmpty("Inventory", ItemStackWithSlot.CODEC));
this.inventory.setSelectedSlot(input.getIntOr("SelectedItemSlot", 0));
this.sleepCounter = input.getShortOr("SleepTimer", (short)0);
this.experienceProgress = input.getFloatOr("XpP", 0.0f);
this.experienceLevel = input.getIntOr("XpLevel", 0);
this.totalExperience = input.getIntOr("XpTotal", 0);
this.enchantmentSeed = input.getIntOr("XpSeed", 0);
if (this.enchantmentSeed == 0) {
this.enchantmentSeed = this.random.nextInt();
}
this.setScore(input.getIntOr("Score", 0));
this.foodData.readAdditionalSaveData(input);
input.read("abilities", Abilities.Packed.CODEC).ifPresent(this.abilities::apply);
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.abilities.getWalkingSpeed());
this.enderChestInventory.fromSlots(input.listOrEmpty("EnderItems", ItemStackWithSlot.CODEC));
this.setLastDeathLocation(input.read("LastDeathLocation", GlobalPos.CODEC));
this.currentImpulseImpactPos = input.read("current_explosion_impact_pos", Vec3.CODEC).orElse(null);
this.ignoreFallDamageFromCurrentImpulse = input.getBooleanOr("ignore_fall_damage_from_current_explosion", false);
this.currentImpulseContextResetGraceTime = input.getIntOr("current_impulse_context_reset_grace_time", 0);
}
@Override
protected void addAdditionalSaveData(ValueOutput output) {
super.addAdditionalSaveData(output);
NbtUtils.addCurrentDataVersion(output);
this.inventory.save(output.list("Inventory", ItemStackWithSlot.CODEC));
output.putInt("SelectedItemSlot", this.inventory.getSelectedSlot());
output.putShort("SleepTimer", (short)this.sleepCounter);
output.putFloat("XpP", this.experienceProgress);
output.putInt("XpLevel", this.experienceLevel);
output.putInt("XpTotal", this.totalExperience);
output.putInt("XpSeed", this.enchantmentSeed);
output.putInt("Score", this.getScore());
this.foodData.addAdditionalSaveData(output);
output.store("abilities", Abilities.Packed.CODEC, this.abilities.pack());
this.enderChestInventory.storeAsSlots(output.list("EnderItems", ItemStackWithSlot.CODEC));
this.lastDeathLocation.ifPresent(pos -> output.store("LastDeathLocation", GlobalPos.CODEC, pos));
output.storeNullable("current_explosion_impact_pos", Vec3.CODEC, this.currentImpulseImpactPos);
output.putBoolean("ignore_fall_damage_from_current_explosion", this.ignoreFallDamageFromCurrentImpulse);
output.putInt("current_impulse_context_reset_grace_time", this.currentImpulseContextResetGraceTime);
}
@Override
public boolean isInvulnerableTo(ServerLevel level, DamageSource source) {
if (super.isInvulnerableTo(level, source)) {
return true;
}
if (source.is(DamageTypeTags.IS_DROWNING)) {
return level.getGameRules().get(GameRules.DROWNING_DAMAGE) == false;
}
if (source.is(DamageTypeTags.IS_FALL)) {
return level.getGameRules().get(GameRules.FALL_DAMAGE) == false;
}
if (source.is(DamageTypeTags.IS_FIRE)) {
return level.getGameRules().get(GameRules.FIRE_DAMAGE) == false;
}
if (source.is(DamageTypeTags.IS_FREEZING)) {
return level.getGameRules().get(GameRules.FREEZE_DAMAGE) == false;
}
return false;
}
@Override
public boolean hurtServer(ServerLevel level, DamageSource source, float damage) {
if (this.isInvulnerableTo(level, source)) {
return false;
}
if (this.abilities.invulnerable && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) {
return false;
}
this.noActionTime = 0;
if (this.isDeadOrDying()) {
return false;
}
this.removeEntitiesOnShoulder();
if (source.scalesWithDifficulty()) {
if (level.getDifficulty() == Difficulty.PEACEFUL) {
damage = 0.0f;
}
if (level.getDifficulty() == Difficulty.EASY) {
damage = Math.min(damage / 2.0f + 1.0f, damage);
}
if (level.getDifficulty() == Difficulty.HARD) {
damage = damage * 3.0f / 2.0f;
}
}
if (damage == 0.0f) {
return false;
}
return super.hurtServer(level, source, damage);
}
@Override
protected void blockUsingItem(ServerLevel level, LivingEntity attacker) {
super.blockUsingItem(level, attacker);
ItemStack itemBlockingWith = this.getItemBlockingWith();
BlocksAttacks blocksAttacks = itemBlockingWith != null ? itemBlockingWith.get(DataComponents.BLOCKS_ATTACKS) : null;
float secondsToDisableBlocking = attacker.getSecondsToDisableBlocking();
if (secondsToDisableBlocking > 0.0f && blocksAttacks != null) {
blocksAttacks.disable(level, this, secondsToDisableBlocking, itemBlockingWith);
}
}
@Override
public boolean canBeSeenAsEnemy() {
return !this.getAbilities().invulnerable && super.canBeSeenAsEnemy();
}
public boolean canHarmPlayer(Player target) {
PlayerTeam team = this.getTeam();
PlayerTeam otherTeam = target.getTeam();
if (team == null) {
return true;
}
if (!team.isAlliedTo(otherTeam)) {
return true;
}
return ((Team)team).isAllowFriendlyFire();
}
@Override
protected void hurtArmor(DamageSource damageSource, float damage) {
this.doHurtEquipment(damageSource, damage, EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD);
}
@Override
protected void hurtHelmet(DamageSource damageSource, float damage) {
this.doHurtEquipment(damageSource, damage, EquipmentSlot.HEAD);
}
@Override
protected void actuallyHurt(ServerLevel level, DamageSource source, float dmg) {
if (this.isInvulnerableTo(level, source)) {
return;
}
dmg = this.getDamageAfterArmorAbsorb(source, dmg);
float originalDamage = dmg = this.getDamageAfterMagicAbsorb(source, dmg);
dmg = Math.max(dmg - this.getAbsorptionAmount(), 0.0f);
this.setAbsorptionAmount(this.getAbsorptionAmount() - (originalDamage - dmg));
float absorbedDamage = originalDamage - dmg;
if (absorbedDamage > 0.0f && absorbedDamage < 3.4028235E37f) {
this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(absorbedDamage * 10.0f));
}
if (dmg == 0.0f) {
return;
}
this.causeFoodExhaustion(source.getFoodExhaustion());
this.getCombatTracker().recordDamage(source, dmg);
this.setHealth(this.getHealth() - dmg);
if (dmg < 3.4028235E37f) {
this.awardStat(Stats.DAMAGE_TAKEN, Math.round(dmg * 10.0f));
}
this.gameEvent(GameEvent.ENTITY_DAMAGE);
}
public boolean isTextFilteringEnabled() {
return false;
}
public void openTextEdit(SignBlockEntity sign, boolean isFrontText) {
}
public void openMinecartCommandBlock(MinecartCommandBlock commandBlock) {
}
public void openCommandBlock(CommandBlockEntity commandBlock) {
}
public void openStructureBlock(StructureBlockEntity structureBlock) {
}
public void openTestBlock(TestBlockEntity testBlock) {
}
public void openTestInstanceBlock(TestInstanceBlockEntity testInstanceBlock) {
}
public void openJigsawBlock(JigsawBlockEntity jigsawBlock) {
}
public void openHorseInventory(AbstractHorse horse, Container container) {
}
public OptionalInt openMenu(@Nullable MenuProvider provider) {
return OptionalInt.empty();
}
public void openDialog(Holder<Dialog> dialog) {
}
public void sendMerchantOffers(int containerId, MerchantOffers offers, int merchantLevel, int merchantXp, boolean showProgressBar, boolean canRestock) {
}
public void openItemGui(ItemStack itemStack, InteractionHand hand) {
}
public InteractionResult interactOn(Entity entity, InteractionHand hand) {
if (this.isSpectator()) {
if (entity instanceof MenuProvider) {
this.openMenu((MenuProvider)((Object)entity));
}
return InteractionResult.PASS;
}
ItemStack itemStack = this.getItemInHand(hand);
ItemStack itemStackClone = itemStack.copy();
InteractionResult interact = entity.interact(this, hand);
if (interact.consumesAction()) {
if (this.hasInfiniteMaterials() && itemStack == this.getItemInHand(hand) && itemStack.getCount() < itemStackClone.getCount()) {
itemStack.setCount(itemStackClone.getCount());
}
return interact;
}
if (!itemStack.isEmpty() && entity instanceof LivingEntity) {
InteractionResult interactionResult;
if (this.hasInfiniteMaterials()) {
itemStack = itemStackClone;
}
if ((interactionResult = itemStack.interactLivingEntity(this, (LivingEntity)entity, hand)).consumesAction()) {
this.level().gameEvent(GameEvent.ENTITY_INTERACT, entity.position(), GameEvent.Context.of(this));
if (itemStack.isEmpty() && !this.hasInfiniteMaterials()) {
this.setItemInHand(hand, ItemStack.EMPTY);
}
return interactionResult;
}
}
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 delta, MoverType moverType) {
double deltaX;
float maxDownStep = this.maxUpStep();
if (this.abilities.flying || delta.y > 0.0 || moverType != MoverType.SELF && moverType != MoverType.PLAYER || !this.isStayingOnGroundSurface() || !this.isAboveGround(maxDownStep)) {
return delta;
}
double deltaZ = delta.z;
double step = 0.05;
double stepX = Math.signum(deltaX) * 0.05;
double stepZ = Math.signum(deltaZ) * 0.05;
for (deltaX = delta.x; deltaX != 0.0 && this.canFallAtLeast(deltaX, 0.0, maxDownStep); deltaX -= stepX) {
if (!(Math.abs(deltaX) <= 0.05)) continue;
deltaX = 0.0;
break;
}
while (deltaZ != 0.0 && this.canFallAtLeast(0.0, deltaZ, maxDownStep)) {
if (Math.abs(deltaZ) <= 0.05) {
deltaZ = 0.0;
break;
}
deltaZ -= stepZ;
}
while (deltaX != 0.0 && deltaZ != 0.0 && this.canFallAtLeast(deltaX, deltaZ, maxDownStep)) {
deltaX = Math.abs(deltaX) <= 0.05 ? 0.0 : (deltaX -= stepX);
if (Math.abs(deltaZ) <= 0.05) {
deltaZ = 0.0;
continue;
}
deltaZ -= stepZ;
}
return new Vec3(deltaX, delta.y, deltaZ);
}
private boolean isAboveGround(float maxDownStep) {
return this.onGround() || this.fallDistance < (double)maxDownStep && !this.canFallAtLeast(0.0, 0.0, (double)maxDownStep - this.fallDistance);
}
private boolean canFallAtLeast(double deltaX, double deltaZ, double minHeight) {
AABB boundingBox = this.getBoundingBox();
return this.level().noCollision(this, new AABB(boundingBox.minX + 1.0E-7 + deltaX, boundingBox.minY - minHeight - 1.0E-7, boundingBox.minZ + 1.0E-7 + deltaZ, boundingBox.maxX - 1.0E-7 + deltaX, boundingBox.minY, boundingBox.maxZ - 1.0E-7 + deltaZ));
}
public void attack(Entity entity) {
if (this.cannotAttack(entity)) {
return;
}
float baseDamage = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE);
ItemStack attackingItemStack = this.getWeaponItem();
DamageSource damageSource = this.createAttackSource(attackingItemStack);
float attackStrengthScale = this.getAttackStrengthScale(0.5f);
float magicBoost = attackStrengthScale * (this.getEnchantedDamage(entity, baseDamage, damageSource) - baseDamage);
baseDamage *= this.baseDamageScaleFactor();
this.onAttack();
if (this.deflectProjectile(entity)) {
return;
}
if (baseDamage > 0.0f || magicBoost > 0.0f) {
boolean criticalAttack;
boolean knockbackAttack;
boolean fullStrengthAttack;
boolean bl = fullStrengthAttack = attackStrengthScale > 0.9f;
if (this.isSprinting() && fullStrengthAttack) {
this.makeSound(SoundEvents.PLAYER_ATTACK_KNOCKBACK);
knockbackAttack = true;
} else {
knockbackAttack = false;
}
baseDamage += attackingItemStack.getItem().getAttackDamageBonus(entity, baseDamage, damageSource);
boolean bl2 = criticalAttack = fullStrengthAttack && this.canCriticalAttack(entity);
if (criticalAttack) {
baseDamage *= 1.5f;
}
float totalDamage = baseDamage + magicBoost;
boolean sweepAttack = this.isSweepAttack(fullStrengthAttack, criticalAttack, knockbackAttack);
float oldLivingEntityHealth = 0.0f;
if (entity instanceof LivingEntity) {
LivingEntity livingTarget = (LivingEntity)entity;
oldLivingEntityHealth = livingTarget.getHealth();
}
Vec3 oldMovement = entity.getDeltaMovement();
boolean wasHurt = entity.hurtOrSimulate(damageSource, totalDamage);
if (wasHurt) {
this.causeExtraKnockback(entity, this.getKnockback(entity, damageSource) + (knockbackAttack ? 0.5f : 0.0f), oldMovement);
if (sweepAttack) {
this.doSweepAttack(entity, baseDamage, damageSource, attackStrengthScale);
}
this.attackVisualEffects(entity, criticalAttack, sweepAttack, fullStrengthAttack, magicBoost);
this.setLastHurtMob(entity);
this.itemAttackInteraction(entity, attackingItemStack, damageSource, true);
this.damageStatsAndHearts(entity, oldLivingEntityHealth);
this.causeFoodExhaustion(0.1f);
} else {
this.playServerSideSound(SoundEvents.PLAYER_ATTACK_NODAMAGE);
}
}
this.lungeForwardMaybe();
}
private void playServerSideSound(SoundEvent sound) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), 1.0f, 1.0f);
}
private DamageSource createAttackSource(ItemStack attackingItemStack) {
return attackingItemStack.getDamageSource(this, () -> this.damageSources().playerAttack(this));
}
private boolean cannotAttack(Entity entity) {
if (!entity.isAttackable()) {
return true;
}
return entity.skipAttackInteraction(this);
}
private boolean deflectProjectile(Entity entity) {
Projectile projectile;
if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile && (projectile = (Projectile)entity).deflect(ProjectileDeflection.AIM_DEFLECT, this, EntityReference.of(this), true)) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource());
return true;
}
return false;
}
private boolean canCriticalAttack(Entity entity) {
return this.fallDistance > 0.0 && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.isMobilityRestricted() && !this.isPassenger() && entity instanceof LivingEntity && !this.isSprinting();
}
private boolean isSweepAttack(boolean fullStrengthAttack, boolean criticalAttack, boolean knockbackAttack) {
double maxSpeedForSweepAttack;
double approximateSpeedSq;
if (fullStrengthAttack && !criticalAttack && !knockbackAttack && this.onGround() && (approximateSpeedSq = this.getKnownMovement().horizontalDistanceSqr()) < Mth.square(maxSpeedForSweepAttack = (double)this.getSpeed() * 2.5)) {
return this.getItemInHand(InteractionHand.MAIN_HAND).is(ItemTags.SWORDS);
}
return false;
}
private void attackVisualEffects(Entity entity, boolean criticalAttack, boolean sweepAttack, boolean fullStrengthAttack, float magicBoost) {
if (criticalAttack) {
this.playServerSideSound(SoundEvents.PLAYER_ATTACK_CRIT);
this.crit(entity);
}
if (!criticalAttack && !sweepAttack) {
this.playServerSideSound(fullStrengthAttack ? SoundEvents.PLAYER_ATTACK_STRONG : SoundEvents.PLAYER_ATTACK_WEAK);
}
if (magicBoost > 0.0f) {
this.magicCrit(entity);
}
}
private void damageStatsAndHearts(Entity entity, float oldLivingEntityHealth) {
if (entity instanceof LivingEntity) {
float actualDamage = oldLivingEntityHealth - ((LivingEntity)entity).getHealth();
this.awardStat(Stats.DAMAGE_DEALT, Math.round(actualDamage * 10.0f));
if (this.level() instanceof ServerLevel && actualDamage > 2.0f) {
int count = (int)((double)actualDamage * 0.5);
((ServerLevel)this.level()).sendParticles(ParticleTypes.DAMAGE_INDICATOR, entity.getX(), entity.getY(0.5), entity.getZ(), count, 0.1, 0.0, 0.1, 0.2);
}
}
}
private void itemAttackInteraction(Entity entity, ItemStack attackingItemStack, DamageSource damageSource, boolean applyToTarget) {
Entity hurtTarget = entity;
if (entity instanceof EnderDragonPart) {
hurtTarget = ((EnderDragonPart)entity).parentMob;
}
boolean itemHurtEnemy = false;
Level level = this.level();
if (level instanceof ServerLevel) {
ServerLevel serverLevel = (ServerLevel)level;
if (hurtTarget instanceof LivingEntity) {
LivingEntity livingTarget = (LivingEntity)hurtTarget;
itemHurtEnemy = attackingItemStack.hurtEnemy(livingTarget, this);
}
if (applyToTarget) {
EnchantmentHelper.doPostAttackEffectsWithItemSource(serverLevel, entity, damageSource, attackingItemStack);
}
}
if (!this.level().isClientSide() && !attackingItemStack.isEmpty() && hurtTarget instanceof LivingEntity) {
if (itemHurtEnemy) {
attackingItemStack.postHurtEnemy((LivingEntity)hurtTarget, this);
}
if (attackingItemStack.isEmpty()) {
if (attackingItemStack == this.getMainHandItem()) {
this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY);
} else {
this.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
}
}
}
}
@Override
public void causeExtraKnockback(Entity entity, float knockbackAmount, Vec3 oldMovement) {
if (knockbackAmount > 0.0f) {
if (entity instanceof LivingEntity) {
LivingEntity livingTarget = (LivingEntity)entity;
livingTarget.knockback(knockbackAmount, Mth.sin(this.getYRot() * ((float)Math.PI / 180)), -Mth.cos(this.getYRot() * ((float)Math.PI / 180)));
} else {
entity.push(-Mth.sin(this.getYRot() * ((float)Math.PI / 180)) * knockbackAmount, 0.1, Mth.cos(this.getYRot() * ((float)Math.PI / 180)) * knockbackAmount);
}
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6));
this.setSprinting(false);
}
if (entity instanceof ServerPlayer && entity.hurtMarked) {
((ServerPlayer)entity).connection.send(new ClientboundSetEntityMotionPacket(entity));
entity.hurtMarked = false;
entity.setDeltaMovement(oldMovement);
}
}
@Override
public float getVoicePitch() {
return 1.0f;
}
private void doSweepAttack(Entity entity, float baseDamage, DamageSource damageSource, float attackStrengthScale) {
this.playServerSideSound(SoundEvents.PLAYER_ATTACK_SWEEP);
Level level = this.level();
if (!(level instanceof ServerLevel)) {
return;
}
ServerLevel serverLevel = (ServerLevel)level;
float sweepDamage = 1.0f + (float)this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * baseDamage;
List<LivingEntity> nearbyEntities = this.level().getEntitiesOfClass(LivingEntity.class, entity.getBoundingBox().inflate(1.0, 0.25, 1.0));
for (LivingEntity nearby : nearbyEntities) {
float enchantedDamage;
ArmorStand armorStand;
if (nearby == this || nearby == entity || this.isAlliedTo(nearby) || nearby instanceof ArmorStand && (armorStand = (ArmorStand)nearby).isMarker() || !(this.distanceToSqr(nearby) < 9.0) || !nearby.hurtServer(serverLevel, damageSource, enchantedDamage = this.getEnchantedDamage(nearby, sweepDamage, damageSource) * attackStrengthScale)) continue;
nearby.knockback(0.4f, Mth.sin(this.getYRot() * ((float)Math.PI / 180)), -Mth.cos(this.getYRot() * ((float)Math.PI / 180)));
EnchantmentHelper.doPostAttackEffects(serverLevel, nearby, damageSource);
}
double dx = -Mth.sin(this.getYRot() * ((float)Math.PI / 180));
double dz = Mth.cos(this.getYRot() * ((float)Math.PI / 180));
serverLevel.sendParticles(ParticleTypes.SWEEP_ATTACK, this.getX() + dx, this.getY(0.5), this.getZ() + dz, 0, dx, 0.0, dz, 0.0);
}
protected float getEnchantedDamage(Entity entity, float dmg, DamageSource damageSource) {
return dmg;
}
@Override
protected void doAutoAttackOnTouch(LivingEntity entity) {
this.attack(entity);
}
public void crit(Entity entity) {
}
private float baseDamageScaleFactor() {
float attackStrengthScale = this.getAttackStrengthScale(0.5f);
return 0.2f + attackStrengthScale * attackStrengthScale * 0.8f;
}
@Override
public boolean stabAttack(EquipmentSlot slot, Entity target, float baseDamage, boolean dealsDamage, boolean dealsKnockback, boolean dismounts) {
boolean wasHurt;
if (this.cannotAttack(target)) {
return false;
}
ItemStack weaponItem = this.getItemBySlot(slot);
DamageSource damageSource = this.createAttackSource(weaponItem);
float magicBoost = this.getAttackStrengthScale(0.5f) * (this.getEnchantedDamage(target, baseDamage, damageSource) - baseDamage);
baseDamage *= this.baseDamageScaleFactor();
if (dealsKnockback && this.deflectProjectile(target)) {
return true;
}
float totalDamage = dealsDamage ? baseDamage + magicBoost : 0.0f;
float oldLivingEntityHealth = 0.0f;
if (target instanceof LivingEntity) {
LivingEntity livingTarget = (LivingEntity)target;
oldLivingEntityHealth = livingTarget.getHealth();
}
Vec3 oldMovement = target.getDeltaMovement();
boolean bl = wasHurt = dealsDamage && target.hurtOrSimulate(damageSource, totalDamage);
if (dealsKnockback) {
this.causeExtraKnockback(target, 0.4f + this.getKnockback(target, damageSource), oldMovement);
}
boolean dismounted = false;
if (dismounts && target.isPassenger()) {
dismounted = true;
target.stopRiding();
}
if (!(wasHurt || dealsKnockback || dismounted)) {
return false;
}
this.attackVisualEffects(target, false, false, dealsDamage, magicBoost);
this.setLastHurtMob(target);
this.itemAttackInteraction(target, weaponItem, damageSource, wasHurt);
this.damageStatsAndHearts(target, oldLivingEntityHealth);
this.causeFoodExhaustion(0.1f);
return true;
}
public void magicCrit(Entity entity) {
}
@Override
public void remove(Entity.RemovalReason reason) {
super.remove(reason);
this.inventoryMenu.removed(this);
if (this.hasContainerOpen()) {
this.doCloseContainer();
}
}
@Override
public boolean isClientAuthoritative() {
return true;
}
@Override
protected boolean isLocalClientAuthoritative() {
return this.isLocalPlayer();
}
public boolean isLocalPlayer() {
return false;
}
@Override
public boolean canSimulateMovement() {
return !this.level().isClientSide() || this.isLocalPlayer();
}
@Override
public boolean isEffectiveAi() {
return !this.level().isClientSide() || this.isLocalPlayer();
}
public GameProfile getGameProfile() {
return this.gameProfile;
}
public NameAndId nameAndId() {
return new NameAndId(this.gameProfile);
}
public Inventory getInventory() {
return this.inventory;
}
public Abilities getAbilities() {
return this.abilities;
}
@Override
public boolean hasInfiniteMaterials() {
return this.abilities.instabuild;
}
public boolean preventsBlockDrops() {
return this.abilities.instabuild;
}
public void updateTutorialInventoryAction(ItemStack itemCarried, ItemStack itemInSlot, ClickAction clickAction) {
}
public boolean hasContainerOpen() {
return this.containerMenu != this.inventoryMenu;
}
public boolean canDropItems() {
return true;
}
public Either<BedSleepingProblem, Unit> startSleepInBed(BlockPos pos) {
this.startSleeping(pos);
this.sleepCounter = 0;
return Either.right((Object)((Object)Unit.INSTANCE));
}
public void stopSleepInBed(boolean forcefulWakeUp, boolean updateLevelList) {
super.stopSleeping();
if (this.level() instanceof ServerLevel && updateLevelList) {
((ServerLevel)this.level()).updateSleepingPlayerList();
}
this.sleepCounter = forcefulWakeUp ? 0 : 100;
}
@Override
public void stopSleeping() {
this.stopSleepInBed(true, true);
}
public boolean isSleepingLongEnough() {
return this.isSleeping() && this.sleepCounter >= 100;
}
public int getSleepTimer() {
return this.sleepCounter;
}
public void displayClientMessage(Component component, boolean overlayMessage) {
}
public void awardStat(Identifier location) {
this.awardStat(Stats.CUSTOM.get(location));
}
public void awardStat(Identifier location, int count) {
this.awardStat(Stats.CUSTOM.get(location), count);
}
public void awardStat(Stat<?> stat) {
this.awardStat(stat, 1);
}
public void awardStat(Stat<?> stat, int count) {
}
public void resetStat(Stat<?> stat) {
}
public int awardRecipes(Collection<RecipeHolder<?>> recipes) {
return 0;
}
public void triggerRecipeCrafted(RecipeHolder<?> recipe, List<ItemStack> itemStacks) {
}
public void awardRecipesByKey(List<ResourceKey<Recipe<?>>> recipeIds) {
}
public int resetRecipes(Collection<RecipeHolder<?>> recipe) {
return 0;
}
@Override
public void travel(Vec3 input) {
if (this.isPassenger()) {
super.travel(input);
return;
}
if (this.isSwimming()) {
double multiplier;
double lookAngleY = this.getLookAngle().y;
double d = multiplier = lookAngleY < -0.2 ? 0.085 : 0.06;
if (lookAngleY <= 0.0 || this.jumping || !this.level().getFluidState(BlockPos.containing(this.getX(), this.getY() + 1.0 - 0.1, this.getZ())).isEmpty()) {
Vec3 movement = this.getDeltaMovement();
this.setDeltaMovement(movement.add(0.0, (lookAngleY - movement.y) * multiplier, 0.0));
}
}
if (this.getAbilities().flying) {
double originalMovementY = this.getDeltaMovement().y;
super.travel(input);
this.setDeltaMovement(this.getDeltaMovement().with(Direction.Axis.Y, originalMovementY * 0.6));
} else {
super.travel(input);
}
}
@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(double fallDistance, float damageModifier, DamageSource damageSource) {
double effectiveFallDistance;
boolean hasRelativeFallDamageResistance;
if (this.abilities.mayfly) {
return false;
}
if (fallDistance >= 2.0) {
this.awardStat(Stats.FALL_ONE_CM, (int)Math.round(fallDistance * 100.0));
}
boolean bl = hasRelativeFallDamageResistance = this.currentImpulseImpactPos != null && this.ignoreFallDamageFromCurrentImpulse;
if (hasRelativeFallDamageResistance) {
boolean hasLandedAboveCurrentImpulseImpactPosY;
effectiveFallDistance = Math.min(fallDistance, this.currentImpulseImpactPos.y - this.getY());
boolean bl2 = hasLandedAboveCurrentImpulseImpactPosY = effectiveFallDistance <= 0.0;
if (hasLandedAboveCurrentImpulseImpactPosY) {
this.resetCurrentImpulseContext();
} else {
this.tryResetCurrentImpulseContext();
}
} else {
effectiveFallDistance = fallDistance;
}
if (effectiveFallDistance > 0.0 && super.causeFallDamage(effectiveFallDistance, damageModifier, damageSource)) {
this.resetCurrentImpulseContext();
return true;
}
this.propagateFallToPassengers(fallDistance, damageModifier, damageSource);
return false;
}
public boolean tryToStartFallFlying() {
if (!this.isFallFlying() && this.canGlide() && !this.isInWater()) {
this.startFallFlying();
return true;
}
return false;
}
public void startFallFlying() {
this.setSharedFlag(7, true);
}
@Override
protected void doWaterSplashEffect() {
if (!this.isSpectator()) {
super.doWaterSplashEffect();
}
}
@Override
protected void playStepSound(BlockPos onPos, BlockState onState) {
if (this.isInWater()) {
this.waterSwimSound();
this.playMuffledStepSound(onState);
} else {
BlockPos primaryStepSoundPos = this.getPrimaryStepSoundBlockPos(onPos);
if (!onPos.equals(primaryStepSoundPos)) {
BlockState primaryStepState = this.level().getBlockState(primaryStepSoundPos);
if (primaryStepState.is(BlockTags.COMBINATION_STEP_SOUND_BLOCKS)) {
this.playCombinationStepSounds(primaryStepState, onState);
} else {
super.playStepSound(primaryStepSoundPos, primaryStepState);
}
} else {
super.playStepSound(onPos, onState);
}
}
}
@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, DamageSource source) {
this.awardStat(Stats.ENTITY_KILLED.get(entity.getType()));
return true;
}
@Override
public void makeStuckInBlock(BlockState blockState, Vec3 speedMultiplier) {
if (!this.abilities.flying) {
super.makeStuckInBlock(blockState, speedMultiplier);
}
this.tryResetCurrentImpulseContext();
}
public void giveExperiencePoints(int i) {
this.increaseScore(i);
this.experienceProgress += (float)i / (float)this.getXpNeededForNextLevel();
this.totalExperience = Mth.clamp(this.totalExperience + i, 0, Integer.MAX_VALUE);
while (this.experienceProgress < 0.0f) {
float remaining = this.experienceProgress * (float)this.getXpNeededForNextLevel();
if (this.experienceLevel > 0) {
this.giveExperienceLevels(-1);
this.experienceProgress = 1.0f + remaining / (float)this.getXpNeededForNextLevel();
continue;
}
this.giveExperienceLevels(-1);
this.experienceProgress = 0.0f;
}
while (this.experienceProgress >= 1.0f) {
this.experienceProgress = (this.experienceProgress - 1.0f) * (float)this.getXpNeededForNextLevel();
this.giveExperienceLevels(1);
this.experienceProgress /= (float)this.getXpNeededForNextLevel();
}
}
public int getEnchantmentSeed() {
return this.enchantmentSeed;
}
public void onEnchantmentPerformed(ItemStack itemStack, int enchantmentCost) {
this.experienceLevel -= enchantmentCost;
if (this.experienceLevel < 0) {
this.experienceLevel = 0;
this.experienceProgress = 0.0f;
this.totalExperience = 0;
}
this.enchantmentSeed = this.random.nextInt();
}
public void giveExperienceLevels(int amount) {
this.experienceLevel = IntMath.saturatedAdd((int)this.experienceLevel, (int)amount);
if (this.experienceLevel < 0) {
this.experienceLevel = 0;
this.experienceProgress = 0.0f;
this.totalExperience = 0;
}
if (amount > 0 && this.experienceLevel % 5 == 0 && (float)this.lastLevelUpTime < (float)this.tickCount - 100.0f) {
float vol = this.experienceLevel > 30 ? 1.0f : (float)this.experienceLevel / 30.0f;
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), vol * 0.75f, 1.0f);
this.lastLevelUpTime = this.tickCount;
}
}
public int getXpNeededForNextLevel() {
if (this.experienceLevel >= 30) {
return 112 + (this.experienceLevel - 30) * 9;
}
if (this.experienceLevel >= 15) {
return 37 + (this.experienceLevel - 15) * 5;
}
return 7 + this.experienceLevel * 2;
}
public void causeFoodExhaustion(float amount) {
if (this.abilities.invulnerable) {
return;
}
if (!this.level().isClientSide()) {
this.foodData.addExhaustion(amount);
}
}
@Override
public void lungeForwardMaybe() {
if (this.hasEnoughFoodToDoExhaustiveManoeuvres()) {
super.lungeForwardMaybe();
}
}
protected boolean hasEnoughFoodToDoExhaustiveManoeuvres() {
return this.getFoodData().hasEnoughFood() || this.getAbilities().mayfly;
}
public Optional<WardenSpawnTracker> getWardenSpawnTracker() {
return Optional.empty();
}
public FoodData getFoodData() {
return this.foodData;
}
public boolean canEat(boolean canAlwaysEat) {
return this.abilities.invulnerable || canAlwaysEat || this.foodData.needsFood();
}
public boolean isHurt() {
return this.getHealth() > 0.0f && this.getHealth() < this.getMaxHealth();
}
public boolean mayBuild() {
return this.abilities.mayBuild;
}
public boolean mayUseItemAt(BlockPos pos, Direction direction, ItemStack itemStack) {
if (this.abilities.mayBuild) {
return true;
}
BlockPos target = pos.relative(direction.getOpposite());
BlockInWorld block = new BlockInWorld(this.level(), target, false);
return itemStack.canPlaceOnBlockInAdventureMode(block);
}
@Override
protected int getBaseExperienceReward(ServerLevel level) {
if (level.getGameRules().get(GameRules.KEEP_INVENTORY).booleanValue() || this.isSpectator()) {
return 0;
}
return Math.min(this.experienceLevel * 7, 100);
}
@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.ALL : Entity.MovementEmission.NONE;
}
public void onUpdateAbilities() {
}
@Override
public Component getName() {
return Component.literal(this.gameProfile.name());
}
@Override
public String getPlainTextName() {
return this.gameProfile.name();
}
public PlayerEnderChestContainer getEnderChestInventory() {
return this.enderChestInventory;
}
@Override
protected boolean doesEmitEquipEvent(EquipmentSlot slot) {
return slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR;
}
public boolean addItem(ItemStack itemStack) {
return this.inventory.add(itemStack);
}
public abstract @Nullable GameType gameMode();
@Override
public boolean isSpectator() {
return this.gameMode() == GameType.SPECTATOR;
}
@Override
public boolean canBeHitByProjectile() {
return !this.isSpectator() && super.canBeHitByProjectile();
}
@Override
public boolean isSwimming() {
return !this.abilities.flying && !this.isSpectator() && super.isSwimming();
}
public boolean isCreative() {
return this.gameMode() == GameType.CREATIVE;
}
@Override
public boolean isPushedByFluid() {
return !this.abilities.flying;
}
@Override
public Component getDisplayName() {
MutableComponent result = PlayerTeam.formatNameForTeam(this.getTeam(), this.getName());
return this.decorateDisplayNameComponent(result);
}
private MutableComponent decorateDisplayNameComponent(MutableComponent nameComponent) {
String name = this.getGameProfile().name();
return nameComponent.withStyle(s -> s.withClickEvent(new ClickEvent.SuggestCommand("/tell " + name + " ")).withHoverEvent(this.createHoverEvent()).withInsertion(name));
}
@Override
public String getScoreboardName() {
return this.getGameProfile().name();
}
@Override
protected void internalSetAbsorptionAmount(float absorptionAmount) {
this.getEntityData().set(DATA_PLAYER_ABSORPTION_ID, Float.valueOf(absorptionAmount));
}
@Override
public float getAbsorptionAmount() {
return this.getEntityData().get(DATA_PLAYER_ABSORPTION_ID).floatValue();
}
@Override
public @Nullable SlotAccess getSlot(int slot) {
if (slot == 499) {
return new SlotAccess(){
@Override
public ItemStack get() {
return Player.this.containerMenu.getCarried();
}
@Override
public boolean set(ItemStack itemStack) {
Player.this.containerMenu.setCarried(itemStack);
return true;
}
};
}
final int craftSlot = slot - 500;
if (craftSlot >= 0 && craftSlot < 4) {
return new SlotAccess(){
@Override
public ItemStack get() {
return Player.this.inventoryMenu.getCraftSlots().getItem(craftSlot);
}
@Override
public boolean set(ItemStack itemStack) {
Player.this.inventoryMenu.getCraftSlots().setItem(craftSlot, itemStack);
Player.this.inventoryMenu.slotsChanged(Player.this.inventory);
return true;
}
};
}
if (slot >= 0 && slot < this.inventory.getNonEquipmentItems().size()) {
return this.inventory.getSlot(slot);
}
int enderSlot = slot - 200;
if (enderSlot >= 0 && enderSlot < this.enderChestInventory.getContainerSize()) {
return this.enderChestInventory.getSlot(enderSlot);
}
return super.getSlot(slot);
}
public boolean isReducedDebugInfo() {
return this.reducedDebugInfo;
}
public void setReducedDebugInfo(boolean reducedDebugInfo) {
this.reducedDebugInfo = reducedDebugInfo;
}
@Override
public void setRemainingFireTicks(int remainingTicks) {
super.setRemainingFireTicks(this.abilities.invulnerable ? Math.min(remainingTicks, 1) : remainingTicks);
}
protected static Optional<Parrot.Variant> extractParrotVariant(CompoundTag tag) {
EntityType entityType;
if (!tag.isEmpty() && (entityType = (EntityType)tag.read("id", EntityType.CODEC).orElse(null)) == EntityType.PARROT) {
return tag.read("Variant", Parrot.Variant.LEGACY_CODEC);
}
return Optional.empty();
}
protected static OptionalInt convertParrotVariant(Optional<Parrot.Variant> variant) {
return variant.map(v -> OptionalInt.of(v.getId())).orElse(OptionalInt.empty());
}
private static Optional<Parrot.Variant> convertParrotVariant(OptionalInt variant) {
if (variant.isPresent()) {
return Optional.of(Parrot.Variant.byId(variant.getAsInt()));
}
return Optional.empty();
}
public void setShoulderParrotLeft(Optional<Parrot.Variant> variant) {
this.entityData.set(DATA_SHOULDER_PARROT_LEFT, Player.convertParrotVariant(variant));
}
public Optional<Parrot.Variant> getShoulderParrotLeft() {
return Player.convertParrotVariant(this.entityData.get(DATA_SHOULDER_PARROT_LEFT));
}
public void setShoulderParrotRight(Optional<Parrot.Variant> variant) {
this.entityData.set(DATA_SHOULDER_PARROT_RIGHT, Player.convertParrotVariant(variant));
}
public Optional<Parrot.Variant> getShoulderParrotRight() {
return Player.convertParrotVariant(this.entityData.get(DATA_SHOULDER_PARROT_RIGHT));
}
public float getCurrentItemAttackStrengthDelay() {
return (float)(1.0 / this.getAttributeValue(Attributes.ATTACK_SPEED) * 20.0);
}
public boolean cannotAttackWithItem(ItemStack itemStack, int tolerance) {
float requiredStrength = itemStack.getOrDefault(DataComponents.MINIMUM_ATTACK_CHARGE, Float.valueOf(0.0f)).floatValue();
float optimisticStrength = (float)(this.attackStrengthTicker + tolerance) / this.getCurrentItemAttackStrengthDelay();
return requiredStrength > 0.0f && optimisticStrength < requiredStrength;
}
public float getAttackStrengthScale(float a) {
return Mth.clamp(((float)this.attackStrengthTicker + a) / this.getCurrentItemAttackStrengthDelay(), 0.0f, 1.0f);
}
public float getItemSwapScale(float a) {
return Mth.clamp(((float)this.itemSwapTicker + a) / this.getCurrentItemAttackStrengthDelay(), 0.0f, 1.0f);
}
public void resetAttackStrengthTicker() {
this.attackStrengthTicker = 0;
this.itemSwapTicker = 0;
}
@Override
public void onAttack() {
this.resetOnlyAttackStrengthTicker();
super.onAttack();
}
public void resetOnlyAttackStrengthTicker() {
this.attackStrengthTicker = 0;
}
public ItemCooldowns getCooldowns() {
return this.cooldowns;
}
@Override
protected float getBlockSpeedFactor() {
return this.abilities.flying || this.isFallFlying() ? 1.0f : super.getBlockSpeedFactor();
}
@Override
public float getLuck() {
return (float)this.getAttributeValue(Attributes.LUCK);
}
public boolean canUseGameMasterBlocks() {
return this.abilities.instabuild && this.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER);
}
public PermissionSet permissions() {
return PermissionSet.NO_PERMISSIONS;
}
@Override
public ImmutableList<Pose> getDismountPoses() {
return ImmutableList.of((Object)Pose.STANDING, (Object)Pose.CROUCHING, (Object)Pose.SWIMMING);
}
@Override
public ItemStack getProjectile(ItemStack heldWeapon) {
if (!(heldWeapon.getItem() instanceof ProjectileWeaponItem)) {
return ItemStack.EMPTY;
}
Predicate<ItemStack> supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles();
ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedProjectiles);
if (!heldProjectile.isEmpty()) {
return heldProjectile;
}
supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles();
for (int i = 0; i < this.inventory.getContainerSize(); ++i) {
ItemStack itemStack = this.inventory.getItem(i);
if (!supportedProjectiles.test(itemStack)) continue;
return itemStack;
}
return this.hasInfiniteMaterials() ? new ItemStack(Items.ARROW) : ItemStack.EMPTY;
}
@Override
public Vec3 getRopeHoldPosition(float partialTickTime) {
double xOff = 0.22 * (this.getMainArm() == HumanoidArm.RIGHT ? -1.0 : 1.0);
float xRot = Mth.lerp(partialTickTime * 0.5f, this.getXRot(), this.xRotO) * ((float)Math.PI / 180);
float yRot = Mth.lerp(partialTickTime, this.yBodyRotO, this.yBodyRot) * ((float)Math.PI / 180);
if (this.isFallFlying() || this.isAutoSpinAttack()) {
float zRot;
Vec3 lookAngle = this.getViewVector(partialTickTime);
Vec3 movement = this.getDeltaMovement();
double speedLen = movement.horizontalDistanceSqr();
double lookLen = lookAngle.horizontalDistanceSqr();
if (speedLen > 0.0 && lookLen > 0.0) {
double dot = (movement.x * lookAngle.x + movement.z * lookAngle.z) / Math.sqrt(speedLen * lookLen);
double sign = movement.x * lookAngle.z - movement.z * lookAngle.x;
zRot = (float)(Math.signum(sign) * Math.acos(dot));
} else {
zRot = 0.0f;
}
return this.getPosition(partialTickTime).add(new Vec3(xOff, -0.11, 0.85).zRot(-zRot).xRot(-xRot).yRot(-yRot));
}
if (this.isVisuallySwimming()) {
return this.getPosition(partialTickTime).add(new Vec3(xOff, 0.2, -0.15).xRot(-xRot).yRot(-yRot));
}
double yOff = this.getBoundingBox().getYsize() - 1.0;
double zOff = this.isCrouching() ? -0.2 : 0.07;
return this.getPosition(partialTickTime).add(new Vec3(xOff, yOff, zOff).yRot(-yRot));
}
@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> pos) {
this.lastDeathLocation = pos;
}
@Override
public float getHurtDir() {
return this.hurtDir;
}
@Override
public void animateHurt(float yaw) {
super.animateHurt(yaw);
this.hurtDir = yaw;
}
public boolean isMobilityRestricted() {
return this.hasEffect(MobEffects.BLINDNESS);
}
@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();
}
return this.isSprinting() ? 0.025999999f : 0.02f;
}
public boolean hasClientLoaded() {
return this.clientLoaded || this.clientLoadedTimeoutTimer <= 0;
}
public void tickClientLoadTimeout() {
if (!this.clientLoaded) {
--this.clientLoadedTimeoutTimer;
}
}
public void setClientLoaded(boolean loaded) {
this.clientLoaded = loaded;
if (!this.clientLoaded) {
this.clientLoadedTimeoutTimer = 60;
}
}
@Override
public boolean hasContainerOpen(ContainerOpenersCounter container, BlockPos blockPos) {
return container.isOwnContainer(this);
}
@Override
public double getContainerInteractionRange() {
return this.blockInteractionRange();
}
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 buffer) {
if (entity.isRemoved()) {
return false;
}
return this.canInteractWithEntity(entity.getBoundingBox(), buffer);
}
public boolean canInteractWithEntity(AABB aabb, double buffer) {
double maxRange = this.entityInteractionRange() + buffer;
return aabb.distanceToSqr(this.getEyePosition()) < maxRange * maxRange;
}
public boolean canInteractWithBlock(BlockPos pos, double buffer) {
double maxRange = this.blockInteractionRange() + buffer;
return new AABB(pos).distanceToSqr(this.getEyePosition()) < maxRange * maxRange;
}
public void setIgnoreFallDamageFromCurrentImpulse(boolean ignoreFallDamage) {
this.ignoreFallDamageFromCurrentImpulse = ignoreFallDamage;
this.currentImpulseContextResetGraceTime = ignoreFallDamage ? 40 : 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 onClimbable() {
if (this.abilities.flying) {
return false;
}
return super.onClimbable();
}
public String debugInfo() {
return MoreObjects.toStringHelper((Object)this).add("name", (Object)this.getPlainTextName()).add("id", this.getId()).add("pos", (Object)this.position()).add("mode", (Object)this.gameMode()).add("permission", (Object)this.permissions()).toString();
}
public record BedSleepingProblem(@Nullable Component message) {
public static final BedSleepingProblem TOO_FAR_AWAY = new BedSleepingProblem(Component.translatable("block.minecraft.bed.too_far_away"));
public static final BedSleepingProblem OBSTRUCTED = new BedSleepingProblem(Component.translatable("block.minecraft.bed.obstructed"));
public static final BedSleepingProblem OTHER_PROBLEM = new BedSleepingProblem(null);
public static final BedSleepingProblem NOT_SAFE = new BedSleepingProblem(Component.translatable("block.minecraft.bed.not_safe"));
}
}