/* * 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 DATA_PLAYER_ABSORPTION_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.FLOAT); private static final EntityDataAccessor DATA_SCORE_ID = SynchedEntityData.defineId(Player.class, EntityDataSerializers.INT); private static final EntityDataAccessor DATA_SHOULDER_PARROT_LEFT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.OPTIONAL_UNSIGNED_INT); private static final EntityDataAccessor 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 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)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 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) { } 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 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 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> recipes) { return 0; } public void triggerRecipeCrafted(RecipeHolder recipe, List itemStacks) { } public void awardRecipesByKey(List>> recipeIds) { } public int resetRecipes(Collection> 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 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 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 variant) { return variant.map(v -> OptionalInt.of(v.getId())).orElse(OptionalInt.empty()); } private static Optional convertParrotVariant(OptionalInt variant) { if (variant.isPresent()) { return Optional.of(Parrot.Variant.byId(variant.getAsInt())); } return Optional.empty(); } public void setShoulderParrotLeft(Optional variant) { this.entityData.set(DATA_SHOULDER_PARROT_LEFT, Player.convertParrotVariant(variant)); } public Optional getShoulderParrotLeft() { return Player.convertParrotVariant(this.entityData.get(DATA_SHOULDER_PARROT_LEFT)); } public void setShoulderParrotRight(Optional variant) { this.entityData.set(DATA_SHOULDER_PARROT_RIGHT, Player.convertParrotVariant(variant)); } public Optional 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 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 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 getLastDeathLocation() { return this.lastDeathLocation; } public void setLastDeathLocation(Optional 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")); } }