package net.minecraft.server.level;

import org.apache.logging.log4j.LogManager;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket;
import net.minecraft.network.protocol.game.ClientboundSoundPacket;
import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.network.protocol.game.ClientboundSetCameraPacket;
import net.minecraft.network.protocol.game.ClientboundResourcePackPacket;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.network.protocol.game.ServerboundClientInformationPacket;
import net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.stats.RecipeBook;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.protocol.game.ClientboundPlayerLookAtPacket;
import net.minecraft.commands.arguments.EntityAnchorArgument;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.network.protocol.game.ClientboundChatPacket;
import net.minecraft.network.chat.ChatType;
import java.util.function.Consumer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Recipe;
import java.util.Collection;
import net.minecraft.network.protocol.game.ClientboundContainerClosePacket;
import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket;
import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket;
import net.minecraft.core.NonNullList;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.world.inventory.ResultSlot;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.item.Item;
import net.minecraft.network.protocol.game.ClientboundOpenBookPacket;
import net.minecraft.world.item.WrittenBookItem;
import net.minecraft.world.item.Items;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.inventory.HorseInventoryMenu;
import net.minecraft.network.protocol.game.ClientboundHorseScreenOpenPacket;
import net.minecraft.world.Container;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.TranslatableComponent;
import java.util.OptionalInt;
import net.minecraft.world.MenuProvider;
import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.network.protocol.game.ClientboundAnimatePacket;
import net.minecraft.util.Unit;
import com.mojang.datafixers.util.Either;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.server.players.PlayerList;
import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.damagesource.EntityDamageSource;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.network.chat.Component;
import net.minecraft.stats.Stat;
import net.minecraft.stats.Stats;
import net.minecraft.world.scores.Score;
import net.minecraft.world.scores.Team;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.CrashReport;
import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket;
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
import net.minecraft.network.protocol.game.ClientboundSetHealthPacket;
import net.minecraft.world.item.ComplexItem;
import java.util.Iterator;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import net.minecraft.world.item.ServerItemCooldowns;
import net.minecraft.world.item.ItemCooldowns;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundPlayerCombatPacket;
import net.minecraft.world.item.ItemStack;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.BlockPos;
import java.util.Random;
import net.minecraft.util.Mth;
import net.minecraft.world.level.GameType;
import net.minecraft.Util;
import com.google.common.collect.Lists;
import net.minecraft.world.level.Level;
import com.mojang.authlib.GameProfile;
import net.minecraft.core.SectionPos;
import javax.annotation.Nullable;
import net.minecraft.world.phys.Vec3;
import net.minecraft.stats.ServerRecipeBook;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.ChatVisiblity;
import net.minecraft.stats.ServerStatsCounter;
import net.minecraft.server.PlayerAdvancements;
import java.util.List;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.inventory.ContainerListener;
import net.minecraft.world.entity.player.Player;

public class ServerPlayer extends Player implements ContainerListener {
    private static final Logger LOGGER;
    private String language;
    public ServerGamePacketListenerImpl connection;
    public final MinecraftServer server;
    public final ServerPlayerGameMode gameMode;
    private final List<Integer> entitiesToRemove;
    private final PlayerAdvancements advancements;
    private final ServerStatsCounter stats;
    private float lastRecordedHealthAndAbsorption;
    private int lastRecordedFoodLevel;
    private int lastRecordedAirLevel;
    private int lastRecordedArmor;
    private int lastRecordedLevel;
    private int lastRecordedExperience;
    private float lastSentHealth;
    private int lastSentFood;
    private boolean lastFoodSaturationZero;
    private int lastSentExp;
    private int spawnInvulnerableTime;
    private ChatVisiblity chatVisibility;
    private boolean canChatColor;
    private long lastActionTime;
    private Entity camera;
    private boolean isChangingDimension;
    private boolean seenCredits;
    private final ServerRecipeBook recipeBook;
    private Vec3 levitationStartPos;
    private int levitationStartTime;
    private boolean disconnected;
    @Nullable
    private Vec3 enteredNetherPosition;
    private SectionPos lastSectionPos;
    private int containerCounter;
    public boolean ignoreSlotUpdateHack;
    public int latency;
    public boolean wonGame;
    
    public ServerPlayer(final MinecraftServer minecraftServer, final ServerLevel xd, final GameProfile gameProfile, final ServerPlayerGameMode xf) {
        super(xd, gameProfile);
        this.language = "en_US";
        this.entitiesToRemove = Lists.newLinkedList();
        this.lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
        this.lastRecordedFoodLevel = Integer.MIN_VALUE;
        this.lastRecordedAirLevel = Integer.MIN_VALUE;
        this.lastRecordedArmor = Integer.MIN_VALUE;
        this.lastRecordedLevel = Integer.MIN_VALUE;
        this.lastRecordedExperience = Integer.MIN_VALUE;
        this.lastSentHealth = -1.0E8f;
        this.lastSentFood = -99999999;
        this.lastFoodSaturationZero = true;
        this.lastSentExp = -99999999;
        this.spawnInvulnerableTime = 60;
        this.canChatColor = true;
        this.lastActionTime = Util.getMillis();
        this.lastSectionPos = SectionPos.of(0, 0, 0);
        xf.player = this;
        this.gameMode = xf;
        this.server = minecraftServer;
        this.recipeBook = new ServerRecipeBook(minecraftServer.getRecipeManager());
        this.stats = minecraftServer.getPlayerList().getPlayerStats(this);
        this.advancements = minecraftServer.getPlayerList().getPlayerAdvancements(this);
        this.maxUpStep = 1.0f;
        this.fudgeSpawnLocation(xd);
    }
    
    private void fudgeSpawnLocation(final ServerLevel xd) {
        final BlockPos fk3 = xd.getSharedSpawnPos();
        if (xd.dimension.isHasSkyLight() && xd.getLevelData().getGameType() != GameType.ADVENTURE) {
            int integer4 = Math.max(0, this.server.getSpawnRadius(xd));
            final int integer5 = Mth.floor(xd.getWorldBorder().getDistanceToBorder(fk3.getX(), fk3.getZ()));
            if (integer5 < integer4) {
                integer4 = integer5;
            }
            if (integer5 <= 1) {
                integer4 = 1;
            }
            final long long6 = integer4 * 2 + 1;
            final long long7 = long6 * long6;
            final int integer6 = (long7 > 2147483647L) ? Integer.MAX_VALUE : ((int)long7);
            final int integer7 = this.getCoprime(integer6);
            final int integer8 = new Random().nextInt(integer6);
            for (int integer9 = 0; integer9 < integer6; ++integer9) {
                final int integer10 = (integer8 + integer7 * integer9) % integer6;
                final int integer11 = integer10 % (integer4 * 2 + 1);
                final int integer12 = integer10 / (integer4 * 2 + 1);
                final BlockPos fk4 = xd.getDimension().getValidSpawnPosition(fk3.getX() + integer11 - integer4, fk3.getZ() + integer12 - integer4, false);
                if (fk4 != null) {
                    this.moveTo(fk4, 0.0f, 0.0f);
                    if (xd.noCollision(this)) {
                        break;
                    }
                }
            }
        }
        else {
            this.moveTo(fk3, 0.0f, 0.0f);
            while (!xd.noCollision(this) && this.getY() < 255.0) {
                this.setPos(this.getX(), this.getY() + 1.0, this.getZ());
            }
        }
    }
    
    private int getCoprime(final int integer) {
        return (integer <= 16) ? (integer - 1) : 17;
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        if (jt.contains("playerGameType", 99)) {
            if (this.getServer().getForceGameType()) {
                this.gameMode.setGameModeForPlayer(this.getServer().getDefaultGameType());
            }
            else {
                this.gameMode.setGameModeForPlayer(GameType.byId(jt.getInt("playerGameType")));
            }
        }
        if (jt.contains("enteredNetherPosition", 10)) {
            final CompoundTag jt2 = jt.getCompound("enteredNetherPosition");
            this.enteredNetherPosition = new Vec3(jt2.getDouble("x"), jt2.getDouble("y"), jt2.getDouble("z"));
        }
        this.seenCredits = jt.getBoolean("seenCredits");
        if (jt.contains("recipeBook", 10)) {
            this.recipeBook.fromNbt(jt.getCompound("recipeBook"));
        }
        if (this.isSleeping()) {
            this.stopSleeping();
        }
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putInt("playerGameType", this.gameMode.getGameModeForPlayer().getId());
        jt.putBoolean("seenCredits", this.seenCredits);
        if (this.enteredNetherPosition != null) {
            final CompoundTag jt2 = new CompoundTag();
            jt2.putDouble("x", this.enteredNetherPosition.x);
            jt2.putDouble("y", this.enteredNetherPosition.y);
            jt2.putDouble("z", this.enteredNetherPosition.z);
            jt.put("enteredNetherPosition", jt2);
        }
        final Entity akq3 = this.getRootVehicle();
        final Entity akq4 = this.getVehicle();
        if (akq4 != null && akq3 != this && akq3.hasOnePlayerPassenger()) {
            final CompoundTag jt3 = new CompoundTag();
            final CompoundTag jt4 = new CompoundTag();
            akq3.save(jt4);
            jt3.putUUID("Attach", akq4.getUUID());
            jt3.put("Entity", jt4);
            jt.put("RootVehicle", jt3);
        }
        jt.put("recipeBook", this.recipeBook.toNbt());
    }
    
    public void setExperiencePoints(final int integer) {
        final float float3 = (float)this.getXpNeededForNextLevel();
        final float float4 = (float3 - 1.0f) / float3;
        this.experienceProgress = Mth.clamp(integer / float3, 0.0f, float4);
        this.lastSentExp = -1;
    }
    
    public void setExperienceLevels(final int integer) {
        this.experienceLevel = integer;
        this.lastSentExp = -1;
    }
    
    @Override
    public void giveExperienceLevels(final int integer) {
        super.giveExperienceLevels(integer);
        this.lastSentExp = -1;
    }
    
    @Override
    public void onEnchantmentPerformed(final ItemStack ben, final int integer) {
        super.onEnchantmentPerformed(ben, integer);
        this.lastSentExp = -1;
    }
    
    public void initMenu() {
        this.containerMenu.addSlotListener(this);
    }
    
    @Override
    public void onEnterCombat() {
        super.onEnterCombat();
        this.connection.send(new ClientboundPlayerCombatPacket(this.getCombatTracker(), ClientboundPlayerCombatPacket.Event.ENTER_COMBAT));
    }
    
    @Override
    public void onLeaveCombat() {
        super.onLeaveCombat();
        this.connection.send(new ClientboundPlayerCombatPacket(this.getCombatTracker(), ClientboundPlayerCombatPacket.Event.END_COMBAT));
    }
    
    @Override
    protected void onInsideBlock(final BlockState byj) {
        CriteriaTriggers.ENTER_BLOCK.trigger(this, byj);
    }
    
    @Override
    protected ItemCooldowns createItemCooldowns() {
        return new ServerItemCooldowns(this);
    }
    
    @Override
    public void tick() {
        this.gameMode.tick();
        --this.spawnInvulnerableTime;
        if (this.invulnerableTime > 0) {
            --this.invulnerableTime;
        }
        this.containerMenu.broadcastChanges();
        if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
            this.closeContainer();
            this.containerMenu = this.inventoryMenu;
        }
        while (!this.entitiesToRemove.isEmpty()) {
            final int integer2 = Math.min(this.entitiesToRemove.size(), Integer.MAX_VALUE);
            final int[] arr3 = new int[integer2];
            final Iterator<Integer> iterator4 = this.entitiesToRemove.iterator();
            int integer3 = 0;
            while (iterator4.hasNext() && integer3 < integer2) {
                arr3[integer3++] = iterator4.next();
                iterator4.remove();
            }
            this.connection.send(new ClientboundRemoveEntitiesPacket(arr3));
        }
        final Entity akq2 = this.getCamera();
        if (akq2 != this) {
            if (akq2.isAlive()) {
                this.absMoveTo(akq2.getX(), akq2.getY(), akq2.getZ(), akq2.yRot, akq2.xRot);
                this.getLevel().getChunkSource().move(this);
                if (this.wantsToStopRiding()) {
                    this.setCamera(this);
                }
            }
            else {
                this.setCamera(this);
            }
        }
        CriteriaTriggers.TICK.trigger(this);
        if (this.levitationStartPos != null) {
            CriteriaTriggers.LEVITATION.trigger(this, this.levitationStartPos, this.tickCount - this.levitationStartTime);
        }
        this.advancements.flushDirty(this);
    }
    
    public void doTick() {
        try {
            if (!this.isSpectator() || this.level.hasChunkAt(new BlockPos(this))) {
                super.tick();
            }
            for (int integer2 = 0; integer2 < this.inventory.getContainerSize(); ++integer2) {
                final ItemStack ben3 = this.inventory.getItem(integer2);
                if (ben3.getItem().isComplex()) {
                    final Packet<?> lt4 = ((ComplexItem)ben3.getItem()).getUpdatePacket(ben3, this.level, this);
                    if (lt4 != null) {
                        this.connection.send(lt4);
                    }
                }
            }
            if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0f != this.lastFoodSaturationZero) {
                this.connection.send(new ClientboundSetHealthPacket(this.getHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel()));
                this.lastSentHealth = this.getHealth();
                this.lastSentFood = this.foodData.getFoodLevel();
                this.lastFoodSaturationZero = (this.foodData.getSaturationLevel() == 0.0f);
            }
            if (this.getHealth() + this.getAbsorptionAmount() != this.lastRecordedHealthAndAbsorption) {
                this.lastRecordedHealthAndAbsorption = this.getHealth() + this.getAbsorptionAmount();
                this.updateScoreForCriteria(ObjectiveCriteria.HEALTH, Mth.ceil(this.lastRecordedHealthAndAbsorption));
            }
            if (this.foodData.getFoodLevel() != this.lastRecordedFoodLevel) {
                this.lastRecordedFoodLevel = this.foodData.getFoodLevel();
                this.updateScoreForCriteria(ObjectiveCriteria.FOOD, Mth.ceil((float)this.lastRecordedFoodLevel));
            }
            if (this.getAirSupply() != this.lastRecordedAirLevel) {
                this.lastRecordedAirLevel = this.getAirSupply();
                this.updateScoreForCriteria(ObjectiveCriteria.AIR, Mth.ceil((float)this.lastRecordedAirLevel));
            }
            if (this.getArmorValue() != this.lastRecordedArmor) {
                this.lastRecordedArmor = this.getArmorValue();
                this.updateScoreForCriteria(ObjectiveCriteria.ARMOR, Mth.ceil((float)this.lastRecordedArmor));
            }
            if (this.totalExperience != this.lastRecordedExperience) {
                this.lastRecordedExperience = this.totalExperience;
                this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float)this.lastRecordedExperience));
            }
            if (this.experienceLevel != this.lastRecordedLevel) {
                this.lastRecordedLevel = this.experienceLevel;
                this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float)this.lastRecordedLevel));
            }
            if (this.totalExperience != this.lastSentExp) {
                this.lastSentExp = this.totalExperience;
                this.connection.send(new ClientboundSetExperiencePacket(this.experienceProgress, this.totalExperience, this.experienceLevel));
            }
            if (this.tickCount % 20 == 0) {
                CriteriaTriggers.LOCATION.trigger(this);
            }
        }
        catch (Throwable throwable2) {
            final CrashReport h3 = CrashReport.forThrowable(throwable2, "Ticking player");
            final CrashReportCategory i4 = h3.addCategory("Player being ticked");
            this.fillCrashReportCategory(i4);
            throw new ReportedException(h3);
        }
    }
    
    private void updateScoreForCriteria(final ObjectiveCriteria cwo, final int integer) {
        this.getScoreboard().forAllObjectives(cwo, this.getScoreboardName(), cwk -> cwk.setScore(integer));
    }
    
    @Override
    public void die(final DamageSource ajz) {
        final boolean boolean3 = this.level.getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
        if (boolean3) {
            final Component lf4 = this.getCombatTracker().getDeathMessage();
            this.connection.send(new ClientboundPlayerCombatPacket(this.getCombatTracker(), ClientboundPlayerCombatPacket.Event.ENTITY_DIED, lf4), (future -> {
                if (!future.isSuccess()) {
                    final int integer4 = 256;
                    final String string5 = lf4.getString(256);
                    final Component lf2 = new TranslatableComponent("death.attack.message_too_long", new Object[] { new TextComponent(string5).withStyle(ChatFormatting.YELLOW) });
                    final Component lf3 = new TranslatableComponent("death.attack.even_more_magic", new Object[] { this.getDisplayName() }).withStyle(ln -> ln.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, lf2)));
                    this.connection.send(new ClientboundPlayerCombatPacket(this.getCombatTracker(), ClientboundPlayerCombatPacket.Event.ENTITY_DIED, lf3));
                }
            }));
            final Team cwn5 = this.getTeam();
            if (cwn5 == null || cwn5.getDeathMessageVisibility() == Team.Visibility.ALWAYS) {
                this.server.getPlayerList().broadcastMessage(lf4);
            }
            else if (cwn5.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) {
                this.server.getPlayerList().broadcastToTeam(this, lf4);
            }
            else if (cwn5.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OWN_TEAM) {
                this.server.getPlayerList().broadcastToAllExceptTeam(this, lf4);
            }
        }
        else {
            this.connection.send(new ClientboundPlayerCombatPacket(this.getCombatTracker(), ClientboundPlayerCombatPacket.Event.ENTITY_DIED));
        }
        this.removeEntitiesOnShoulder();
        if (!this.isSpectator()) {
            this.dropAllDeathLoot(ajz);
        }
        this.getScoreboard().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this.getScoreboardName(), Score::increment);
        final LivingEntity akz4 = this.getKillCredit();
        if (akz4 != null) {
            this.awardStat(Stats.ENTITY_KILLED_BY.get(akz4.getType()));
            akz4.awardKillScore(this, this.deathScore, ajz);
            this.createWitherRose(akz4);
        }
        this.level.broadcastEntityEvent(this, (byte)3);
        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.setSharedFlag(0, false);
        this.getCombatTracker().recheckStatus();
    }
    
    @Override
    public void awardKillScore(final Entity akq, final int integer, final DamageSource ajz) {
        if (akq == this) {
            return;
        }
        super.awardKillScore(akq, integer, ajz);
        this.increaseScore(integer);
        final String string5 = this.getScoreboardName();
        final String string6 = akq.getScoreboardName();
        this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, string5, Score::increment);
        if (akq instanceof Player) {
            this.awardStat(Stats.PLAYER_KILLS);
            this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, string5, Score::increment);
        }
        else {
            this.awardStat(Stats.MOB_KILLS);
        }
        this.handleTeamKill(string5, string6, ObjectiveCriteria.TEAM_KILL);
        this.handleTeamKill(string6, string5, ObjectiveCriteria.KILLED_BY_TEAM);
        CriteriaTriggers.PLAYER_KILLED_ENTITY.trigger(this, akq, ajz);
    }
    
    private void handleTeamKill(final String string1, final String string2, final ObjectiveCriteria[] arr) {
        final PlayerTeam cwj5 = this.getScoreboard().getPlayersTeam(string2);
        if (cwj5 != null) {
            final int integer6 = cwj5.getColor().getId();
            if (integer6 >= 0 && integer6 < arr.length) {
                this.getScoreboard().forAllObjectives(arr[integer6], string1, Score::increment);
            }
        }
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        final boolean boolean4 = this.server.isDedicatedServer() && this.isPvpAllowed() && "fall".equals(ajz.msgId);
        if (!boolean4 && this.spawnInvulnerableTime > 0 && ajz != DamageSource.OUT_OF_WORLD) {
            return false;
        }
        if (ajz instanceof EntityDamageSource) {
            final Entity akq5 = ajz.getEntity();
            if (akq5 instanceof Player && !this.canHarmPlayer((Player)akq5)) {
                return false;
            }
            if (akq5 instanceof AbstractArrow) {
                final AbstractArrow ayn6 = (AbstractArrow)akq5;
                final Entity akq6 = ayn6.getOwner();
                if (akq6 instanceof Player && !this.canHarmPlayer((Player)akq6)) {
                    return false;
                }
            }
        }
        return super.hurt(ajz, float2);
    }
    
    @Override
    public boolean canHarmPlayer(final Player ayj) {
        return this.isPvpAllowed() && super.canHarmPlayer(ayj);
    }
    
    private boolean isPvpAllowed() {
        return this.server.isPvpAllowed();
    }
    
    @Nullable
    @Override
    public Entity changeDimension(final DimensionType cbi) {
        this.isChangingDimension = true;
        final DimensionType cbi2 = this.dimension;
        if (cbi2 == DimensionType.THE_END && cbi == DimensionType.OVERWORLD) {
            this.unRide();
            this.getLevel().removePlayerImmediately(this);
            if (!this.wonGame) {
                this.wonGame = true;
                this.connection.send(new ClientboundGameEventPacket(4, this.seenCredits ? 0.0f : 1.0f));
                this.seenCredits = true;
            }
            return this;
        }
        final ServerLevel xd4 = this.server.getLevel(cbi2);
        this.dimension = cbi;
        final ServerLevel xd5 = this.server.getLevel(cbi);
        final LevelData crm6 = xd5.getLevelData();
        this.connection.send(new ClientboundRespawnPacket(cbi, LevelData.obfuscateSeed(crm6.getSeed()), crm6.getGeneratorType(), this.gameMode.getGameModeForPlayer()));
        this.connection.send(new ClientboundChangeDifficultyPacket(crm6.getDifficulty(), crm6.isDifficultyLocked()));
        final PlayerList zo7 = this.server.getPlayerList();
        zo7.sendPlayerPermissionLevel(this);
        xd4.removePlayerImmediately(this);
        this.removed = false;
        double double8 = this.getX();
        double double9 = this.getY();
        double double10 = this.getZ();
        float float14 = this.xRot;
        float float15 = this.yRot;
        final double double11 = 8.0;
        final float float16 = float15;
        xd4.getProfiler().push("moving");
        if (cbi2 == DimensionType.OVERWORLD && cbi == DimensionType.NETHER) {
            this.enteredNetherPosition = this.position();
            double8 /= 8.0;
            double10 /= 8.0;
        }
        else if (cbi2 == DimensionType.NETHER && cbi == DimensionType.OVERWORLD) {
            double8 *= 8.0;
            double10 *= 8.0;
        }
        else if (cbi2 == DimensionType.OVERWORLD && cbi == DimensionType.THE_END) {
            final BlockPos fk19 = xd5.getDimensionSpecificSpawn();
            double8 = fk19.getX();
            double9 = fk19.getY();
            double10 = fk19.getZ();
            float15 = 90.0f;
            float14 = 0.0f;
        }
        this.moveTo(double8, double9, double10, float15, float14);
        xd4.getProfiler().pop();
        xd4.getProfiler().push("placing");
        final double double12 = Math.min(-2.9999872E7, xd5.getWorldBorder().getMinX() + 16.0);
        final double double13 = Math.min(-2.9999872E7, xd5.getWorldBorder().getMinZ() + 16.0);
        final double double14 = Math.min(2.9999872E7, xd5.getWorldBorder().getMaxX() - 16.0);
        final double double15 = Math.min(2.9999872E7, xd5.getWorldBorder().getMaxZ() - 16.0);
        double8 = Mth.clamp(double8, double12, double14);
        double10 = Mth.clamp(double10, double13, double15);
        this.moveTo(double8, double9, double10, float15, float14);
        if (cbi == DimensionType.THE_END) {
            final int integer27 = Mth.floor(this.getX());
            final int integer28 = Mth.floor(this.getY()) - 1;
            final int integer29 = Mth.floor(this.getZ());
            final int integer30 = 1;
            final int integer31 = 0;
            for (int integer32 = -2; integer32 <= 2; ++integer32) {
                for (int integer33 = -2; integer33 <= 2; ++integer33) {
                    for (int integer34 = -1; integer34 < 3; ++integer34) {
                        final int integer35 = integer27 + integer33 * 1 + integer32 * 0;
                        final int integer36 = integer28 + integer34;
                        final int integer37 = integer29 + integer33 * 0 - integer32 * 1;
                        final boolean boolean38 = integer34 < 0;
                        xd5.setBlockAndUpdate(new BlockPos(integer35, integer36, integer37), boolean38 ? Blocks.OBSIDIAN.defaultBlockState() : Blocks.AIR.defaultBlockState());
                    }
                }
            }
            this.moveTo(integer27, integer28, integer29, float15, 0.0f);
            this.setDeltaMovement(Vec3.ZERO);
        }
        else if (!xd5.getPortalForcer().findAndMoveToPortal(this, float16)) {
            xd5.getPortalForcer().createPortal(this);
            xd5.getPortalForcer().findAndMoveToPortal(this, float16);
        }
        xd4.getProfiler().pop();
        this.setLevel(xd5);
        xd5.addDuringPortalTeleport(this);
        this.triggerDimensionChangeTriggers(xd4);
        this.connection.teleport(this.getX(), this.getY(), this.getZ(), float15, float14);
        this.gameMode.setLevel(xd5);
        this.connection.send(new ClientboundPlayerAbilitiesPacket(this.abilities));
        zo7.sendLevelInfo(this, xd5);
        zo7.sendAllPlayerInfo(this);
        for (final MobEffectInstance akk28 : this.getActiveEffects()) {
            this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), akk28));
        }
        this.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false));
        this.lastSentExp = -1;
        this.lastSentHealth = -1.0f;
        this.lastSentFood = -1;
        return this;
    }
    
    private void triggerDimensionChangeTriggers(final ServerLevel xd) {
        final DimensionType cbi3 = xd.dimension.getType();
        final DimensionType cbi4 = this.level.dimension.getType();
        CriteriaTriggers.CHANGED_DIMENSION.trigger(this, cbi3, cbi4);
        if (cbi3 == DimensionType.NETHER && cbi4 == DimensionType.OVERWORLD && this.enteredNetherPosition != null) {
            CriteriaTriggers.NETHER_TRAVEL.trigger(this, this.enteredNetherPosition);
        }
        if (cbi4 != DimensionType.NETHER) {
            this.enteredNetherPosition = null;
        }
    }
    
    @Override
    public boolean broadcastToPlayer(final ServerPlayer xe) {
        if (xe.isSpectator()) {
            return this.getCamera() == this;
        }
        return !this.isSpectator() && super.broadcastToPlayer(xe);
    }
    
    private void broadcast(final BlockEntity bwl) {
        if (bwl != null) {
            final ClientboundBlockEntityDataPacket mh3 = bwl.getUpdatePacket();
            if (mh3 != null) {
                this.connection.send(mh3);
            }
        }
    }
    
    @Override
    public void take(final Entity akq, final int integer) {
        super.take(akq, integer);
        this.containerMenu.broadcastChanges();
    }
    
    @Override
    public Either<BedSleepingProblem, Unit> startSleepInBed(final BlockPos fk) {
        return (Either<BedSleepingProblem, Unit>)super.startSleepInBed(fk).ifRight(aca -> {
            this.awardStat(Stats.SLEEP_IN_BED);
            CriteriaTriggers.SLEPT_IN_BED.trigger(this);
        });
    }
    
    @Override
    public void stopSleepInBed(final boolean boolean1, final boolean boolean2) {
        if (this.isSleeping()) {
            this.getLevel().getChunkSource().broadcastAndSend(this, new ClientboundAnimatePacket(this, 2));
        }
        super.stopSleepInBed(boolean1, boolean2);
        if (this.connection != null) {
            this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.yRot, this.xRot);
        }
    }
    
    @Override
    public boolean startRiding(final Entity akq, final boolean boolean2) {
        final Entity akq2 = this.getVehicle();
        if (!super.startRiding(akq, boolean2)) {
            return false;
        }
        final Entity akq3 = this.getVehicle();
        if (akq3 != akq2 && this.connection != null) {
            this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.yRot, this.xRot);
        }
        return true;
    }
    
    @Override
    public void stopRiding() {
        final Entity akq2 = this.getVehicle();
        super.stopRiding();
        final Entity akq3 = this.getVehicle();
        if (akq3 != akq2 && this.connection != null) {
            this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.yRot, this.xRot);
        }
    }
    
    @Override
    public boolean isInvulnerableTo(final DamageSource ajz) {
        return super.isInvulnerableTo(ajz) || this.isChangingDimension() || (this.abilities.invulnerable && ajz == DamageSource.WITHER);
    }
    
    @Override
    protected void checkFallDamage(final double double1, final boolean boolean2, final BlockState byj, final BlockPos fk) {
    }
    
    @Override
    protected void onChangedBlock(final BlockPos fk) {
        if (!this.isSpectator()) {
            super.onChangedBlock(fk);
        }
    }
    
    public void doCheckFallDamage(final double double1, final boolean boolean2) {
        final BlockPos fk5 = this.getOnPos();
        if (!this.level.hasChunkAt(fk5)) {
            return;
        }
        final BlockState byj6 = this.level.getBlockState(fk5);
        super.checkFallDamage(double1, boolean2, byj6, fk5);
    }
    
    @Override
    public void openTextEdit(final SignBlockEntity bxh) {
        bxh.setAllowedPlayerEditor(this);
        this.connection.send(new ClientboundOpenSignEditorPacket(bxh.getBlockPos()));
    }
    
    private void nextContainerCounter() {
        this.containerCounter = this.containerCounter % 100 + 1;
    }
    
    @Override
    public OptionalInt openMenu(@Nullable final MenuProvider ajo) {
        if (ajo == null) {
            return OptionalInt.empty();
        }
        if (this.containerMenu != this.inventoryMenu) {
            this.closeContainer();
        }
        this.nextContainerCounter();
        final AbstractContainerMenu ban3 = ajo.createMenu(this.containerCounter, this.inventory, this);
        if (ban3 == null) {
            if (this.isSpectator()) {
                this.displayClientMessage(new TranslatableComponent("container.spectatorCantOpen", new Object[0]).withStyle(ChatFormatting.RED), true);
            }
            return OptionalInt.empty();
        }
        this.connection.send(new ClientboundOpenScreenPacket(ban3.containerId, ban3.getType(), ajo.getDisplayName()));
        ban3.addSlotListener(this);
        this.containerMenu = ban3;
        return OptionalInt.of(this.containerCounter);
    }
    
    @Override
    public void sendMerchantOffers(final int integer1, final MerchantOffers bja, final int integer3, final int integer4, final boolean boolean5, final boolean boolean6) {
        this.connection.send(new ClientboundMerchantOffersPacket(integer1, bja, integer3, integer4, boolean5, boolean6));
    }
    
    @Override
    public void openHorseInventory(final AbstractHorse aue, final Container aje) {
        if (this.containerMenu != this.inventoryMenu) {
            this.closeContainer();
        }
        this.nextContainerCounter();
        this.connection.send(new ClientboundHorseScreenOpenPacket(this.containerCounter, aje.getContainerSize(), aue.getId()));
        (this.containerMenu = new HorseInventoryMenu(this.containerCounter, this.inventory, aje, aue)).addSlotListener(this);
    }
    
    @Override
    public void openItemGui(final ItemStack ben, final InteractionHand ajk) {
        final Item bei4 = ben.getItem();
        if (bei4 == Items.WRITTEN_BOOK) {
            if (WrittenBookItem.resolveBookComponents(ben, this.createCommandSourceStack(), this)) {
                this.containerMenu.broadcastChanges();
            }
            this.connection.send(new ClientboundOpenBookPacket(ajk));
        }
    }
    
    @Override
    public void openCommandBlock(final CommandBlockEntity bwq) {
        bwq.setSendToClient(true);
        this.broadcast(bwq);
    }
    
    @Override
    public void slotChanged(final AbstractContainerMenu ban, final int integer, final ItemStack ben) {
        if (ban.getSlot(integer) instanceof ResultSlot) {
            return;
        }
        if (ban == this.inventoryMenu) {
            CriteriaTriggers.INVENTORY_CHANGED.trigger(this, this.inventory);
        }
        if (this.ignoreSlotUpdateHack) {
            return;
        }
        this.connection.send(new ClientboundContainerSetSlotPacket(ban.containerId, integer, ben));
    }
    
    public void refreshContainer(final AbstractContainerMenu ban) {
        this.refreshContainer(ban, ban.getItems());
    }
    
    @Override
    public void refreshContainer(final AbstractContainerMenu ban, final NonNullList<ItemStack> fy) {
        this.connection.send(new ClientboundContainerSetContentPacket(ban.containerId, fy));
        this.connection.send(new ClientboundContainerSetSlotPacket(-1, -1, this.inventory.getCarried()));
    }
    
    @Override
    public void setContainerData(final AbstractContainerMenu ban, final int integer2, final int integer3) {
        this.connection.send(new ClientboundContainerSetDataPacket(ban.containerId, integer2, integer3));
    }
    
    public void closeContainer() {
        this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
        this.doCloseContainer();
    }
    
    public void broadcastCarriedItem() {
        if (this.ignoreSlotUpdateHack) {
            return;
        }
        this.connection.send(new ClientboundContainerSetSlotPacket(-1, -1, this.inventory.getCarried()));
    }
    
    public void doCloseContainer() {
        this.containerMenu.removed(this);
        this.containerMenu = this.inventoryMenu;
    }
    
    public void setPlayerInput(final float float1, final float float2, final boolean boolean3, final boolean boolean4) {
        if (this.isPassenger()) {
            if (float1 >= -1.0f && float1 <= 1.0f) {
                this.xxa = float1;
            }
            if (float2 >= -1.0f && float2 <= 1.0f) {
                this.zza = float2;
            }
            this.jumping = boolean3;
            this.setShiftKeyDown(boolean4);
        }
    }
    
    @Override
    public void awardStat(final Stat<?> aao, final int integer) {
        this.stats.increment(this, aao, integer);
        this.getScoreboard().forAllObjectives(aao, this.getScoreboardName(), cwk -> cwk.add(integer));
    }
    
    @Override
    public void resetStat(final Stat<?> aao) {
        this.stats.setValue(this, aao, 0);
        this.getScoreboard().forAllObjectives(aao, this.getScoreboardName(), Score::reset);
    }
    
    @Override
    public int awardRecipes(final Collection<Recipe<?>> collection) {
        return this.recipeBook.addRecipes(collection, this);
    }
    
    @Override
    public void awardRecipesByKey(final ResourceLocation[] arr) {
        final List<Recipe<?>> list3 = Lists.newArrayList();
        for (final ResourceLocation sm7 : arr) {
            this.server.getRecipeManager().byKey(sm7).ifPresent(list3::add);
        }
        this.awardRecipes(list3);
    }
    
    @Override
    public int resetRecipes(final Collection<Recipe<?>> collection) {
        return this.recipeBook.removeRecipes(collection, this);
    }
    
    @Override
    public void giveExperiencePoints(final int integer) {
        super.giveExperiencePoints(integer);
        this.lastSentExp = -1;
    }
    
    public void disconnect() {
        this.disconnected = true;
        this.ejectPassengers();
        if (this.isSleeping()) {
            this.stopSleepInBed(true, false);
        }
    }
    
    public boolean hasDisconnected() {
        return this.disconnected;
    }
    
    public void resetSentInfo() {
        this.lastSentHealth = -1.0E8f;
    }
    
    @Override
    public void displayClientMessage(final Component lf, final boolean boolean2) {
        this.connection.send(new ClientboundChatPacket(lf, boolean2 ? ChatType.GAME_INFO : ChatType.CHAT));
    }
    
    @Override
    protected void completeUsingItem() {
        if (!this.useItem.isEmpty() && this.isUsingItem()) {
            this.connection.send(new ClientboundEntityEventPacket(this, (byte)9));
            super.completeUsingItem();
        }
    }
    
    @Override
    public void lookAt(final EntityAnchorArgument.Anchor a, final Vec3 cvl) {
        super.lookAt(a, cvl);
        this.connection.send(new ClientboundPlayerLookAtPacket(a, cvl.x, cvl.y, cvl.z));
    }
    
    public void lookAt(final EntityAnchorArgument.Anchor a1, final Entity akq, final EntityAnchorArgument.Anchor a3) {
        final Vec3 cvl5 = a3.apply(akq);
        super.lookAt(a1, cvl5);
        this.connection.send(new ClientboundPlayerLookAtPacket(a1, akq, a3));
    }
    
    public void restoreFrom(final ServerPlayer xe, final boolean boolean2) {
        if (boolean2) {
            this.inventory.replaceWith(xe.inventory);
            this.setHealth(xe.getHealth());
            this.foodData = xe.foodData;
            this.experienceLevel = xe.experienceLevel;
            this.totalExperience = xe.totalExperience;
            this.experienceProgress = xe.experienceProgress;
            this.setScore(xe.getScore());
            this.portalEntranceBlock = xe.portalEntranceBlock;
            this.portalEntranceOffset = xe.portalEntranceOffset;
            this.portalEntranceForwards = xe.portalEntranceForwards;
        }
        else if (this.level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || xe.isSpectator()) {
            this.inventory.replaceWith(xe.inventory);
            this.experienceLevel = xe.experienceLevel;
            this.totalExperience = xe.totalExperience;
            this.experienceProgress = xe.experienceProgress;
            this.setScore(xe.getScore());
        }
        this.enchantmentSeed = xe.enchantmentSeed;
        this.enderChestInventory = xe.enderChestInventory;
        this.getEntityData().<Byte>set(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION, (Byte)xe.getEntityData().<T>get((EntityDataAccessor<T>)ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION));
        this.lastSentExp = -1;
        this.lastSentHealth = -1.0f;
        this.lastSentFood = -1;
        this.recipeBook.copyOverData(xe.recipeBook);
        this.entitiesToRemove.addAll(xe.entitiesToRemove);
        this.seenCredits = xe.seenCredits;
        this.enteredNetherPosition = xe.enteredNetherPosition;
        this.setShoulderEntityLeft(xe.getShoulderEntityLeft());
        this.setShoulderEntityRight(xe.getShoulderEntityRight());
    }
    
    @Override
    protected void onEffectAdded(final MobEffectInstance akk) {
        super.onEffectAdded(akk);
        this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), akk));
        if (akk.getEffect() == MobEffects.LEVITATION) {
            this.levitationStartTime = this.tickCount;
            this.levitationStartPos = this.position();
        }
        CriteriaTriggers.EFFECTS_CHANGED.trigger(this);
    }
    
    @Override
    protected void onEffectUpdated(final MobEffectInstance akk, final boolean boolean2) {
        super.onEffectUpdated(akk, boolean2);
        this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), akk));
        CriteriaTriggers.EFFECTS_CHANGED.trigger(this);
    }
    
    @Override
    protected void onEffectRemoved(final MobEffectInstance akk) {
        super.onEffectRemoved(akk);
        this.connection.send(new ClientboundRemoveMobEffectPacket(this.getId(), akk.getEffect()));
        if (akk.getEffect() == MobEffects.LEVITATION) {
            this.levitationStartPos = null;
        }
        CriteriaTriggers.EFFECTS_CHANGED.trigger(this);
    }
    
    @Override
    public void teleportTo(final double double1, final double double2, final double double3) {
        this.connection.teleport(double1, double2, double3, this.yRot, this.xRot);
    }
    
    @Override
    public void forceMove(final double double1, final double double2, final double double3) {
        this.connection.teleport(double1, double2, double3, this.yRot, this.xRot);
        this.connection.resetPosition();
    }
    
    @Override
    public void crit(final Entity akq) {
        this.getLevel().getChunkSource().broadcastAndSend(this, new ClientboundAnimatePacket(akq, 4));
    }
    
    @Override
    public void magicCrit(final Entity akq) {
        this.getLevel().getChunkSource().broadcastAndSend(this, new ClientboundAnimatePacket(akq, 5));
    }
    
    @Override
    public void onUpdateAbilities() {
        if (this.connection == null) {
            return;
        }
        this.connection.send(new ClientboundPlayerAbilitiesPacket(this.abilities));
        this.updateInvisibilityStatus();
    }
    
    public ServerLevel getLevel() {
        return (ServerLevel)this.level;
    }
    
    @Override
    public void setGameMode(final GameType bjt) {
        this.gameMode.setGameModeForPlayer(bjt);
        this.connection.send(new ClientboundGameEventPacket(3, (float)bjt.getId()));
        if (bjt == GameType.SPECTATOR) {
            this.removeEntitiesOnShoulder();
            this.stopRiding();
        }
        else {
            this.setCamera(this);
        }
        this.onUpdateAbilities();
        this.updateEffectVisibility();
    }
    
    @Override
    public boolean isSpectator() {
        return this.gameMode.getGameModeForPlayer() == GameType.SPECTATOR;
    }
    
    @Override
    public boolean isCreative() {
        return this.gameMode.getGameModeForPlayer() == GameType.CREATIVE;
    }
    
    @Override
    public void sendMessage(final Component lf) {
        this.sendMessage(lf, ChatType.SYSTEM);
    }
    
    public void sendMessage(final Component lf, final ChatType ld) {
        this.connection.send(new ClientboundChatPacket(lf, ld), (future -> {
            if (!future.isSuccess() && (ld == ChatType.GAME_INFO || ld == ChatType.SYSTEM)) {
                final int integer5 = 256;
                final String string6 = lf.getString(256);
                final Component lf2 = new TextComponent(string6).withStyle(ChatFormatting.YELLOW);
                this.connection.send(new ClientboundChatPacket(new TranslatableComponent("multiplayer.message_not_delivered", new Object[] { lf2 }).withStyle(ChatFormatting.RED), ChatType.SYSTEM));
            }
        }));
    }
    
    public String getIpAddress() {
        String string2 = this.connection.connection.getRemoteAddress().toString();
        string2 = string2.substring(string2.indexOf("/") + 1);
        string2 = string2.substring(0, string2.indexOf(":"));
        return string2;
    }
    
    public void updateOptions(final ServerboundClientInformationPacket pr) {
        this.language = pr.getLanguage();
        this.chatVisibility = pr.getChatVisibility();
        this.canChatColor = pr.getChatColors();
        this.getEntityData().<Byte>set(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION, (byte)pr.getModelCustomisation());
        this.getEntityData().<Byte>set(ServerPlayer.DATA_PLAYER_MAIN_HAND, (byte)((pr.getMainHand() != HumanoidArm.LEFT) ? 1 : 0));
    }
    
    public ChatVisiblity getChatVisibility() {
        return this.chatVisibility;
    }
    
    public void sendTexturePack(final String string1, final String string2) {
        this.connection.send(new ClientboundResourcePackPacket(string1, string2));
    }
    
    @Override
    protected int getPermissionLevel() {
        return this.server.getProfilePermissions(this.getGameProfile());
    }
    
    public void resetLastActionTime() {
        this.lastActionTime = Util.getMillis();
    }
    
    public ServerStatsCounter getStats() {
        return this.stats;
    }
    
    public ServerRecipeBook getRecipeBook() {
        return this.recipeBook;
    }
    
    public void sendRemoveEntity(final Entity akq) {
        if (akq instanceof Player) {
            this.connection.send(new ClientboundRemoveEntitiesPacket(new int[] { akq.getId() }));
        }
        else {
            this.entitiesToRemove.add(akq.getId());
        }
    }
    
    public void cancelRemoveEntity(final Entity akq) {
        this.entitiesToRemove.remove(akq.getId());
    }
    
    @Override
    protected void updateInvisibilityStatus() {
        if (this.isSpectator()) {
            this.removeEffectParticles();
            this.setInvisible(true);
        }
        else {
            super.updateInvisibilityStatus();
        }
    }
    
    public Entity getCamera() {
        return (this.camera == null) ? this : this.camera;
    }
    
    public void setCamera(final Entity akq) {
        final Entity akq2 = this.getCamera();
        this.camera = ((akq == null) ? this : akq);
        if (akq2 != this.camera) {
            this.connection.send(new ClientboundSetCameraPacket(this.camera));
            this.teleportTo(this.camera.getX(), this.camera.getY(), this.camera.getZ());
        }
    }
    
    @Override
    protected void processDimensionDelay() {
        if (this.changingDimensionDelay > 0 && !this.isChangingDimension) {
            --this.changingDimensionDelay;
        }
    }
    
    @Override
    public void attack(final Entity akq) {
        if (this.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) {
            this.setCamera(akq);
        }
        else {
            super.attack(akq);
        }
    }
    
    public long getLastActionTime() {
        return this.lastActionTime;
    }
    
    @Nullable
    public Component getTabListDisplayName() {
        return null;
    }
    
    @Override
    public void swing(final InteractionHand ajk) {
        super.swing(ajk);
        this.resetAttackStrengthTicker();
    }
    
    public boolean isChangingDimension() {
        return this.isChangingDimension;
    }
    
    public void hasChangedDimension() {
        this.isChangingDimension = false;
    }
    
    public PlayerAdvancements getAdvancements() {
        return this.advancements;
    }
    
    public void teleportTo(final ServerLevel xd, final double double2, final double double3, final double double4, final float float5, final float float6) {
        this.setCamera(this);
        this.stopRiding();
        if (xd == this.level) {
            this.connection.teleport(double2, double3, double4, float5, float6);
        }
        else {
            final ServerLevel xd2 = this.getLevel();
            this.dimension = xd.dimension.getType();
            final LevelData crm12 = xd.getLevelData();
            this.connection.send(new ClientboundRespawnPacket(this.dimension, LevelData.obfuscateSeed(crm12.getSeed()), crm12.getGeneratorType(), this.gameMode.getGameModeForPlayer()));
            this.connection.send(new ClientboundChangeDifficultyPacket(crm12.getDifficulty(), crm12.isDifficultyLocked()));
            this.server.getPlayerList().sendPlayerPermissionLevel(this);
            xd2.removePlayerImmediately(this);
            this.removed = false;
            this.moveTo(double2, double3, double4, float5, float6);
            this.setLevel(xd);
            xd.addDuringCommandTeleport(this);
            this.triggerDimensionChangeTriggers(xd2);
            this.connection.teleport(double2, double3, double4, float5, float6);
            this.gameMode.setLevel(xd);
            this.server.getPlayerList().sendLevelInfo(this, xd);
            this.server.getPlayerList().sendAllPlayerInfo(this);
        }
    }
    
    public void trackChunk(final ChunkPos bjh, final Packet<?> lt2, final Packet<?> lt3) {
        this.connection.send(lt3);
        this.connection.send(lt2);
    }
    
    public void untrackChunk(final ChunkPos bjh) {
        if (this.isAlive()) {
            this.connection.send(new ClientboundForgetLevelChunkPacket(bjh.x, bjh.z));
        }
    }
    
    public SectionPos getLastSectionPos() {
        return this.lastSectionPos;
    }
    
    public void setLastSectionPos(final SectionPos gd) {
        this.lastSectionPos = gd;
    }
    
    @Override
    public void playNotifySound(final SoundEvent aah, final SoundSource aaj, final float float3, final float float4) {
        this.connection.send(new ClientboundSoundPacket(aah, aaj, this.getX(), this.getY(), this.getZ(), float3, float4));
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddPlayerPacket(this);
    }
    
    @Override
    public ItemEntity drop(final ItemStack ben, final boolean boolean2, final boolean boolean3) {
        final ItemEntity awb5 = super.drop(ben, boolean2, boolean3);
        if (awb5 == null) {
            return null;
        }
        this.level.addFreshEntity(awb5);
        final ItemStack ben2 = awb5.getItem();
        if (boolean3) {
            if (!ben2.isEmpty()) {
                this.awardStat(Stats.ITEM_DROPPED.get(ben2.getItem()), ben.getCount());
            }
            this.awardStat(Stats.DROP);
        }
        return awb5;
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
