// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.entity.player;

import java.lang.invoke.CallSite;
import java.lang.reflect.UndeclaredThrowableException;
import java.lang.invoke.MethodHandle;
import java.lang.runtime.SwitchBootstraps;
import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandles;
import com.hypixel.hytale.component.system.EcsEvent;
import com.hypixel.hytale.server.core.modules.entity.damage.event.KillFeedEvent;
import com.hypixel.hytale.component.system.EntityEventSystem;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.system.RefChangeSystem;
import com.hypixel.hytale.server.core.universe.world.PlayerUtil;
import com.hypixel.hytale.server.core.universe.world.WorldConfig;
import com.hypixel.hytale.server.core.entity.entities.player.data.UniqueItemUsagesComponent;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
import com.hypixel.hytale.component.system.QuerySystem;
import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Transform;
import java.util.Iterator;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.server.core.asset.type.particle.config.WorldParticle;
import it.unimi.dsi.fastutil.objects.ObjectList;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.asset.type.gameplay.SpawnConfig;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData;
import com.hypixel.hytale.server.core.io.PacketHandler;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.ParticleUtil;
import java.util.List;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.component.spatial.SpatialResource;
import com.hypixel.hytale.server.core.entity.entities.player.pages.CustomUIPage;
import com.hypixel.hytale.server.core.entity.entities.player.pages.RespawnPage;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.entity.Entity;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
import com.hypixel.hytale.protocol.packets.player.SetBlockPlacementOverride;
import com.hypixel.hytale.protocol.packets.inventory.SetActiveSlot;
import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolsSetSoundSet;
import com.hypixel.hytale.component.ComponentAccessor;
import java.util.Objects;
import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.server.core.entity.entities.player.movement.MovementManager;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.asset.type.gameplay.PlayerConfig;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.inventory.Inventory;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.entities.EntityUpdates;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent;
import com.hypixel.hytale.server.core.util.PositionUtil;
import com.hypixel.hytale.protocol.ModelTransform;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.protocol.ItemArmorSlot;
import java.util.Arrays;
import com.hypixel.hytale.protocol.Equipment;
import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import com.hypixel.hytale.server.core.modules.projectile.component.PredictedProjectile;
import com.hypixel.hytale.server.core.entity.nameplate.Nameplate;
import com.hypixel.hytale.server.core.modules.entity.component.RespondToHit;
import com.hypixel.hytale.server.core.modules.entity.component.Invulnerable;
import com.hypixel.hytale.server.core.modules.entity.component.Intangible;
import com.hypixel.hytale.protocol.ComponentUpdateType;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.modules.entity.component.Interactable;
import com.hypixel.hytale.protocol.ComponentUpdate;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.protocol.EntityUpdate;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.RefSystem;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;

public class PlayerSystems
{
    @Nonnull
    public static final HytaleLogger LOGGER;
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    public static class PlayerSpawnedSystem extends RefSystem<EntityStore>
    {
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return Player.getComponentType();
        }
        
        @Override
        public void onEntityAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            sendPlayerSelf(ref, store);
        }
        
        @Override
        public void onEntityRemove(@Nonnull final Ref<EntityStore> ref, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Deprecated
        public static void sendPlayerSelf(@Nonnull final Ref<EntityStore> viewerRef, @Nonnull final Store<EntityStore> store) {
            final EntityTrackerSystems.EntityViewer entityViewerComponent = store.getComponent(viewerRef, EntityTrackerSystems.EntityViewer.getComponentType());
            if (entityViewerComponent == null) {
                throw new IllegalArgumentException("Viewer is missing EntityViewer component");
            }
            final NetworkId networkIdComponent = store.getComponent(viewerRef, NetworkId.getComponentType());
            if (networkIdComponent == null) {
                throw new IllegalArgumentException("Viewer is missing NetworkId component");
            }
            final Player playerComponent = store.getComponent(viewerRef, Player.getComponentType());
            if (playerComponent == null) {
                throw new IllegalArgumentException("Viewer is missing Player component");
            }
            final EntityUpdate entityUpdate = new EntityUpdate();
            entityUpdate.networkId = networkIdComponent.getId();
            final ObjectArrayList<ComponentUpdate> list = new ObjectArrayList<ComponentUpdate>();
            final Archetype<EntityStore> viewerArchetype = store.getArchetype(viewerRef);
            if (viewerArchetype.contains(Interactable.getComponentType())) {
                final ComponentUpdate update = new ComponentUpdate();
                update.type = ComponentUpdateType.Interactable;
                list.add(update);
            }
            if (viewerArchetype.contains(Intangible.getComponentType())) {
                final ComponentUpdate update = new ComponentUpdate();
                update.type = ComponentUpdateType.Intangible;
                list.add(update);
            }
            if (viewerArchetype.contains(Invulnerable.getComponentType())) {
                final ComponentUpdate update = new ComponentUpdate();
                update.type = ComponentUpdateType.Invulnerable;
                list.add(update);
            }
            if (viewerArchetype.contains(RespondToHit.getComponentType())) {
                final ComponentUpdate update = new ComponentUpdate();
                update.type = ComponentUpdateType.RespondToHit;
                list.add(update);
            }
            final Nameplate nameplateComponent = store.getComponent(viewerRef, Nameplate.getComponentType());
            if (nameplateComponent != null) {
                final ComponentUpdate update2 = new ComponentUpdate();
                update2.type = ComponentUpdateType.Nameplate;
                update2.nameplate = new com.hypixel.hytale.protocol.Nameplate();
                update2.nameplate.text = nameplateComponent.getText();
                list.add(update2);
            }
            final PredictedProjectile predictionComponent = store.getComponent(viewerRef, PredictedProjectile.getComponentType());
            if (predictionComponent != null) {
                final ComponentUpdate update3 = new ComponentUpdate();
                update3.type = ComponentUpdateType.Prediction;
                update3.predictionId = predictionComponent.getUuid();
                list.add(update3);
            }
            final ModelComponent modelComponent = store.getComponent(viewerRef, ModelComponent.getComponentType());
            ComponentUpdate update4 = new ComponentUpdate();
            update4.type = ComponentUpdateType.Model;
            update4.model = ((modelComponent != null) ? modelComponent.getModel().toPacket() : null);
            final EntityScaleComponent entityScaleComponent = store.getComponent(viewerRef, EntityScaleComponent.getComponentType());
            if (entityScaleComponent != null) {
                update4.entityScale = entityScaleComponent.getScale();
            }
            list.add(update4);
            update4 = new ComponentUpdate();
            update4.type = ComponentUpdateType.PlayerSkin;
            final PlayerSkinComponent playerSkinComponent = store.getComponent(viewerRef, PlayerSkinComponent.getComponentType());
            update4.skin = ((playerSkinComponent != null) ? playerSkinComponent.getPlayerSkin() : null);
            list.add(update4);
            final Inventory inventory = playerComponent.getInventory();
            final ComponentUpdate update5 = new ComponentUpdate();
            update5.type = ComponentUpdateType.Equipment;
            update5.equipment = new Equipment();
            final ItemContainer armor = inventory.getArmor();
            Arrays.fill(update5.equipment.armorIds = new String[armor.getCapacity()], "");
            armor.forEachWithMeta((slot, itemStack, armorIds) -> armorIds[slot] = itemStack.getItemId(), update5.equipment.armorIds);
            final PlayerSettings playerSettingsComponent = store.getComponent(viewerRef, PlayerSettings.getComponentType());
            if (playerSettingsComponent != null) {
                final PlayerConfig.ArmorVisibilityOption armorVisibilityOption = store.getExternalData().getWorld().getGameplayConfig().getPlayerConfig().getArmorVisibilityOption();
                if (armorVisibilityOption.canHideHelmet() && playerSettingsComponent.hideHelmet()) {
                    update5.equipment.armorIds[ItemArmorSlot.Head.ordinal()] = "";
                }
                if (armorVisibilityOption.canHideCuirass() && playerSettingsComponent.hideCuirass()) {
                    update5.equipment.armorIds[ItemArmorSlot.Chest.ordinal()] = "";
                }
                if (armorVisibilityOption.canHideGauntlets() && playerSettingsComponent.hideGauntlets()) {
                    update5.equipment.armorIds[ItemArmorSlot.Hands.ordinal()] = "";
                }
                if (armorVisibilityOption.canHidePants() && playerSettingsComponent.hidePants()) {
                    update5.equipment.armorIds[ItemArmorSlot.Legs.ordinal()] = "";
                }
            }
            final ItemStack itemInHand = inventory.getItemInHand();
            update5.equipment.rightHandItemId = ((itemInHand != null) ? itemInHand.getItemId() : "Empty");
            final ItemStack utilityItem = inventory.getUtilityItem();
            update5.equipment.leftHandItemId = ((utilityItem != null) ? utilityItem.getItemId() : "Empty");
            list.add(update5);
            final TransformComponent transformComponent = store.getComponent(viewerRef, TransformComponent.getComponentType());
            final HeadRotation headRotationComponent = store.getComponent(viewerRef, HeadRotation.getComponentType());
            if (transformComponent != null && headRotationComponent != null) {
                final ComponentUpdate update6 = new ComponentUpdate();
                update6.type = ComponentUpdateType.Transform;
                update6.transform = new ModelTransform();
                update6.transform.position = PositionUtil.toPositionPacket(transformComponent.getPosition());
                update6.transform.bodyOrientation = PositionUtil.toDirectionPacket(transformComponent.getRotation());
                update6.transform.lookOrientation = PositionUtil.toDirectionPacket(headRotationComponent.getRotation());
                list.add(update6);
            }
            final EffectControllerComponent effectControllerComponent = store.getComponent(viewerRef, EffectControllerComponent.getComponentType());
            if (effectControllerComponent != null) {
                final ComponentUpdate update7 = new ComponentUpdate();
                update7.type = ComponentUpdateType.EntityEffects;
                update7.entityEffectUpdates = effectControllerComponent.createInitUpdates();
                list.add(update7);
            }
            final EntityStatMap statMapComponent = store.getComponent(viewerRef, EntityStatMap.getComponentType());
            if (statMapComponent != null) {
                final ComponentUpdate update8 = new ComponentUpdate();
                update8.type = ComponentUpdateType.EntityStats;
                update8.entityStatUpdates = statMapComponent.createInitUpdate(true);
                list.add(update8);
            }
            entityUpdate.updates = list.toArray(ComponentUpdate[]::new);
            entityViewerComponent.packetReceiver.writeNoCache(new EntityUpdates(null, new EntityUpdate[] { entityUpdate }));
        }
    }
    
    public static class PlayerAddedSystem extends RefSystem<EntityStore>
    {
        @Nonnull
        private static final Message MESSAGE_SERVER_GENERAL_KILLED_BY_UNKNOWN;
        @Nonnull
        private final Set<Dependency<EntityStore>> dependencies;
        @Nonnull
        private final Query<EntityStore> query;
        
        public PlayerAddedSystem(@Nonnull final ComponentType<EntityStore, MovementManager> movementManagerComponentType) {
            this.dependencies = (Set<Dependency<EntityStore>>)Set.of(new SystemDependency(Order.AFTER, PlayerSpawnedSystem.class));
            this.query = (Query<EntityStore>)Query.and(Player.getComponentType(), PlayerRef.getComponentType(), movementManagerComponentType);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return this.dependencies;
        }
        
        @Override
        public void onEntityAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final World world = commandBuffer.getExternalData().getWorld();
            final Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType());
            assert playerComponent != null;
            final PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
            assert playerRefComponent != null;
            final MovementManager movementManagerComponent = commandBuffer.getComponent(ref, MovementManager.getComponentType());
            assert movementManagerComponent != null;
            if (commandBuffer.getComponent(ref, DisplayNameComponent.getComponentType()) == null) {
                final Message displayName = Message.raw(playerRefComponent.getUsername());
                commandBuffer.putComponent(ref, DisplayNameComponent.getComponentType(), new DisplayNameComponent(displayName));
            }
            playerComponent.setLastSpawnTimeNanos(java.lang.System.nanoTime());
            final PacketHandler playerConnection = playerRefComponent.getPacketHandler();
            Objects.requireNonNull(world, "world");
            Objects.requireNonNull(playerComponent.getPlayerConfigData(), "data");
            final PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName());
            Player.initGameMode(ref, commandBuffer);
            playerConnection.writeNoCache(new BuilderToolsSetSoundSet(world.getGameplayConfig().getCreativePlaySoundSetIndex()));
            playerComponent.sendInventory();
            final Inventory playerInventory = playerComponent.getInventory();
            playerConnection.writeNoCache(new SetActiveSlot(-1, playerInventory.getActiveHotbarSlot()));
            playerConnection.writeNoCache(new SetActiveSlot(-5, playerInventory.getActiveUtilitySlot()));
            playerConnection.writeNoCache(new SetActiveSlot(-8, playerInventory.getActiveToolsSlot()));
            if (playerInventory.containsBrokenItem()) {
                playerComponent.sendMessage(Message.translation("server.general.repair.itemBrokenOnRespawn").color("#ff5555"));
            }
            playerConnection.writeNoCache(new SetBlockPlacementOverride(playerComponent.isOverrideBlockPlacementRestrictions()));
            final DeathComponent deathComponent = commandBuffer.getComponent(ref, DeathComponent.getComponentType());
            if (deathComponent != null) {
                Message pendingDeathMessage = deathComponent.getDeathMessage();
                if (pendingDeathMessage == null) {
                    Entity.LOGGER.at(Level.SEVERE).withCause(new Throwable()).log("Player wasn't alive but didn't have a pending death message?");
                    pendingDeathMessage = PlayerAddedSystem.MESSAGE_SERVER_GENERAL_KILLED_BY_UNKNOWN;
                }
                final RespawnPage respawnPage = new RespawnPage(playerRefComponent, pendingDeathMessage, deathComponent.displayDataOnDeathScreen(), deathComponent.getDeathItemLoss());
                playerComponent.getPageManager().openCustomPage(ref, store, respawnPage);
            }
            final TransformComponent transform = commandBuffer.getComponent(ref, TransformComponent.getComponentType());
            final GameplayConfig gameplayConfig = world.getGameplayConfig();
            final SpawnConfig spawnConfig = gameplayConfig.getSpawnConfig();
            if (transform != null) {
                final Vector3d position = transform.getPosition();
                final SpatialResource<Ref<EntityStore>, EntityStore> playerSpatialResource = commandBuffer.getResource(EntityModule.get().getPlayerSpatialResourceType());
                final ObjectList<Ref<EntityStore>> results = SpatialResource.getThreadLocalReferenceList();
                playerSpatialResource.getSpatialStructure().collect(position, 75.0, results);
                results.add(ref);
                if (playerComponent.isFirstSpawn()) {
                    WorldParticle[] firstSpawnParticles = spawnConfig.getFirstSpawnParticles();
                    if (firstSpawnParticles == null) {
                        firstSpawnParticles = spawnConfig.getSpawnParticles();
                    }
                    if (firstSpawnParticles != null) {
                        ParticleUtil.spawnParticleEffects(firstSpawnParticles, position, null, results, commandBuffer);
                    }
                }
                else {
                    final WorldParticle[] spawnParticles = spawnConfig.getSpawnParticles();
                    if (spawnParticles != null) {
                        ParticleUtil.spawnParticleEffects(spawnParticles, position, null, results, commandBuffer);
                    }
                }
            }
            playerConnection.tryFlush();
            perWorldData.setFirstSpawn(false);
        }
        
        @Override
        public void onEntityRemove(@Nonnull final Ref<EntityStore> ref, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType());
            assert playerComponent != null;
            playerComponent.getWindowManager().closeAllWindows(ref, commandBuffer);
        }
        
        static {
            MESSAGE_SERVER_GENERAL_KILLED_BY_UNKNOWN = Message.translation("server.general.killedByUnknown");
        }
    }
    
    public static class ProcessPlayerInput extends EntityTickingSystem<EntityStore>
    {
        @Nonnull
        private final Query<EntityStore> query;
        
        public ProcessPlayerInput() {
            this.query = (Query<EntityStore>)Query.and(Player.getComponentType(), PlayerInput.getComponentType(), TransformComponent.getComponentType());
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final PlayerInput playerInputComponent = archetypeChunk.getComponent(index, PlayerInput.getComponentType());
            assert playerInputComponent != null;
            final List<PlayerInput.InputUpdate> movementUpdateQueue = playerInputComponent.getMovementUpdateQueue();
            for (final PlayerInput.InputUpdate entry : movementUpdateQueue) {
                entry.apply(commandBuffer, archetypeChunk, index);
            }
            movementUpdateQueue.clear();
        }
    }
    
    public static class UpdatePlayerRef extends EntityTickingSystem<EntityStore>
    {
        @Nonnull
        private final Query<EntityStore> query;
        
        public UpdatePlayerRef() {
            this.query = (Query<EntityStore>)Query.and(PlayerRef.getComponentType(), TransformComponent.getComponentType(), HeadRotation.getComponentType());
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final World world = commandBuffer.getExternalData().getWorld();
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType());
            assert transformComponent != null;
            final Transform transform = transformComponent.getTransform();
            final HeadRotation headRotationComponent = archetypeChunk.getComponent(index, HeadRotation.getComponentType());
            assert headRotationComponent != null;
            final Vector3f headRotation = headRotationComponent.getRotation();
            final PlayerRef playerRefComponent = archetypeChunk.getComponent(index, PlayerRef.getComponentType());
            assert playerRefComponent != null;
            playerRefComponent.updatePosition(world, transform, headRotation);
        }
    }
    
    public static class BlockPausedMovementSystem implements RunWhenPausedSystem<EntityStore>, QuerySystem<EntityStore>
    {
        @Nonnull
        private final Query<EntityStore> query;
        
        public BlockPausedMovementSystem() {
            this.query = (Query<EntityStore>)Query.and(Player.getComponentType(), PlayerInput.getComponentType(), TransformComponent.getComponentType(), HeadRotation.getComponentType());
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            store.forEachChunk(systemIndex, BlockPausedMovementSystem::onTick);
        }
        
        private static void onTick(@Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            for (int index = 0; index < archetypeChunk.size(); ++index) {
                final PlayerInput playerInputComponent = archetypeChunk.getComponent(index, PlayerInput.getComponentType());
                assert playerInputComponent != null;
                boolean shouldTeleport = false;
                final TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType());
                assert transformComponent != null;
                final HeadRotation headRotationComponent = archetypeChunk.getComponent(index, HeadRotation.getComponentType());
                assert headRotationComponent != null;
                final List<PlayerInput.InputUpdate> movementUpdateQueue = playerInputComponent.getMovementUpdateQueue();
                for (PlayerInput.InputUpdate obj : movementUpdateQueue) {
                    final PlayerInput.InputUpdate entry = obj;
                    Objects.requireNonNull(obj);
                    final PlayerInput.SetHead setHead = (PlayerInput.SetHead)obj;
                    switch (/* invokedynamic(!) */ProcyonInvokeDynamicHelper_1.invoke(setHead, false)) {
                        case 0: {
                            final PlayerInput.AbsoluteMovement abs = (PlayerInput.AbsoluteMovement)setHead;
                            shouldTeleport = (transformComponent.getPosition().distanceSquaredTo(abs.getX(), abs.getY(), abs.getZ()) > 0.009999999776482582);
                            continue;
                        }
                        case 1: {
                            final PlayerInput.RelativeMovement rel = (PlayerInput.RelativeMovement)setHead;
                            final Vector3d position = transformComponent.getPosition();
                            shouldTeleport = (transformComponent.getPosition().distanceSquaredTo(position.x + rel.getX(), position.y + rel.getY(), position.z + rel.getZ()) > 0.009999999776482582);
                            continue;
                        }
                        case 2: {
                            final PlayerInput.SetHead head = setHead;
                            shouldTeleport = (headRotationComponent.getRotation().distanceSquaredTo(head.direction().pitch, head.direction().yaw, head.direction().roll) > 0.01f);
                            continue;
                        }
                    }
                }
                movementUpdateQueue.clear();
                if (shouldTeleport) {
                    final Teleport teleport = Teleport.createExact(transformComponent.getPosition(), transformComponent.getRotation(), headRotationComponent.getRotation()).withoutVelocityReset();
                    final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
                    commandBuffer.addComponent(ref, Teleport.getComponentType(), teleport);
                }
            }
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        // This helper class was generated by Procyon to approximate the behavior of an
        // 'invokedynamic' instruction that it doesn't know how to interpret.
        private static final class ProcyonInvokeDynamicHelper_1
        {
            private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
            private static MethodHandle handle;
            private static volatile int fence;
            
            private static MethodHandle handle() {
                final MethodHandle handle = ProcyonInvokeDynamicHelper_1.handle;
                if (handle != null)
                    return handle;
                return ProcyonInvokeDynamicHelper_1.ensureHandle();
            }
            
            private static MethodHandle ensureHandle() {
                ProcyonInvokeDynamicHelper_1.fence = 0;
                MethodHandle handle = ProcyonInvokeDynamicHelper_1.handle;
                if (handle == null) {
                    MethodHandles.Lookup lookup = ProcyonInvokeDynamicHelper_1.LOOKUP;
                    try {
                        handle = ((CallSite)SwitchBootstraps.typeSwitch(lookup, "typeSwitch", MethodType.methodType(int.class, Object.class, int.class), PlayerInput.AbsoluteMovement.class, PlayerInput.RelativeMovement.class, PlayerInput.SetHead.class)).dynamicInvoker();
                    }
                    catch (Throwable t) {
                        throw new UndeclaredThrowableException(t);
                    }
                    ProcyonInvokeDynamicHelper_1.fence = 1;
                    ProcyonInvokeDynamicHelper_1.handle = handle;
                    ProcyonInvokeDynamicHelper_1.fence = 0;
                }
                return handle;
            }
            
            private static int invoke(Object p0, int p1) {
                try {
                    return ProcyonInvokeDynamicHelper_1.handle().invokeExact(p0, p1);
                }
                catch (Throwable t) {
                    throw new UndeclaredThrowableException(t);
                }
            }
        }
    }
    
    public static class EnsurePlayerInput extends HolderSystem<EntityStore>
    {
        @Override
        public Query<EntityStore> getQuery() {
            return PlayerRef.getComponentType();
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            holder.ensureComponent(PlayerInput.getComponentType());
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
            holder.removeComponent(PlayerInput.getComponentType());
        }
    }
    
    public static class EnsureEffectControllerSystem extends HolderSystem<EntityStore>
    {
        @Override
        public Query<EntityStore> getQuery() {
            return PlayerRef.getComponentType();
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            holder.ensureComponent(EffectControllerComponent.getComponentType());
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
    }
    
    public static class EnsureUniqueItemUsagesSystem extends HolderSystem<EntityStore>
    {
        @Override
        public Query<EntityStore> getQuery() {
            return (Query<EntityStore>)Query.and(PlayerRef.getComponentType(), Query.not((Query<Object>)UniqueItemUsagesComponent.getComponentType()));
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            holder.ensureComponent(UniqueItemUsagesComponent.getComponentType());
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
    }
    
    public static class PlayerRemovedSystem extends HolderSystem<EntityStore>
    {
        @Override
        public Query<EntityStore> getQuery() {
            return (Query<EntityStore>)Query.and(PlayerRef.getComponentType(), Player.getComponentType(), TransformComponent.getComponentType(), HeadRotation.getComponentType(), DisplayNameComponent.getComponentType());
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
            final World world = store.getExternalData().getWorld();
            final PlayerRef playerRefComponent = holder.getComponent(PlayerRef.getComponentType());
            assert playerRefComponent != null;
            final Player playerComponent = holder.getComponent(Player.getComponentType());
            assert playerComponent != null;
            final TransformComponent transformComponent = holder.getComponent(TransformComponent.getComponentType());
            assert transformComponent != null;
            final HeadRotation headRotationComponent = holder.getComponent(HeadRotation.getComponentType());
            assert headRotationComponent != null;
            final DisplayNameComponent displayNameComponent = holder.getComponent(DisplayNameComponent.getComponentType());
            assert displayNameComponent != null;
            final Message displayName = displayNameComponent.getDisplayName();
            PlayerSystems.LOGGER.at(Level.INFO).log("Removing player '%s%s' from world '%s' (%s)", (Object)playerRefComponent.getUsername(), (displayName != null) ? (" (" + displayName.getAnsiMessage()) : "", (Object)world.getName(), (Object)playerRefComponent.getUuid());
            playerComponent.getPlayerConfigData().getPerWorldData(world.getName()).setLastPosition(new Transform(transformComponent.getPosition().clone(), headRotationComponent.getRotation().clone()));
            playerRefComponent.getPacketHandler().setQueuePackets(false);
            playerRefComponent.getPacketHandler().tryFlush();
            final WorldConfig worldConfig = world.getWorldConfig();
            PlayerUtil.broadcastMessageToPlayers(playerRefComponent.getUuid(), Message.translation("server.general.playerLeftWorld").param("username", playerRefComponent.getUsername()).param("world", (worldConfig.getDisplayName() != null) ? worldConfig.getDisplayName() : WorldConfig.formatDisplayName(world.getName())), store);
        }
    }
    
    public static class NameplateRefSystem extends RefSystem<EntityStore>
    {
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return (Query<EntityStore>)Archetype.of(Player.getComponentType(), DisplayNameComponent.getComponentType());
        }
        
        @Override
        public void onEntityAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final DisplayNameComponent displayNameComponent = commandBuffer.getComponent(ref, DisplayNameComponent.getComponentType());
            assert displayNameComponent != null;
            if (commandBuffer.getComponent(ref, Nameplate.getComponentType()) != null) {
                return;
            }
            final String displayName = (displayNameComponent.getDisplayName() != null) ? displayNameComponent.getDisplayName().getAnsiMessage() : "";
            final Nameplate nameplateComponent = new Nameplate(displayName);
            commandBuffer.putComponent(ref, Nameplate.getComponentType(), nameplateComponent);
        }
        
        @Override
        public void onEntityRemove(@Nonnull final Ref<EntityStore> ref, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
    }
    
    public static class NameplateRefChangeSystem extends RefChangeSystem<EntityStore, DisplayNameComponent>
    {
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return Player.getComponentType();
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, DisplayNameComponent> componentType() {
            return DisplayNameComponent.getComponentType();
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final DisplayNameComponent component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText((component.getDisplayName() != null) ? component.getDisplayName().getAnsiMessage() : "");
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final DisplayNameComponent oldComponent, @Nonnull final DisplayNameComponent newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText((newComponent.getDisplayName() != null) ? newComponent.getDisplayName().getAnsiMessage() : "");
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final DisplayNameComponent component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText("");
        }
    }
    
    public static class KillFeedKillerEventSystem extends EntityEventSystem<EntityStore, KillFeedEvent.KillerMessage>
    {
        @Nonnull
        private final ComponentType<EntityStore, PlayerRef> playerRefComponentType;
        
        public KillFeedKillerEventSystem() {
            super(KillFeedEvent.KillerMessage.class);
            this.playerRefComponentType = PlayerRef.getComponentType();
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final KillFeedEvent.KillerMessage event) {
            final DisplayNameComponent displayNameComponent = archetypeChunk.getComponent(index, DisplayNameComponent.getComponentType());
            Message displayName;
            if (displayNameComponent != null) {
                displayName = displayNameComponent.getDisplayName();
            }
            else {
                final PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType);
                assert playerRefComponent != null;
                displayName = Message.raw(playerRefComponent.getUsername());
            }
            event.setMessage(displayName);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.playerRefComponentType;
        }
    }
    
    public static class KillFeedDecedentEventSystem extends EntityEventSystem<EntityStore, KillFeedEvent.DecedentMessage>
    {
        @Nonnull
        private final ComponentType<EntityStore, PlayerRef> playerRefComponentType;
        
        public KillFeedDecedentEventSystem() {
            super(KillFeedEvent.DecedentMessage.class);
            this.playerRefComponentType = PlayerRef.getComponentType();
        }
        
        @Override
        public void handle(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final KillFeedEvent.DecedentMessage event) {
            final DisplayNameComponent displayNameComponent = archetypeChunk.getComponent(index, DisplayNameComponent.getComponentType());
            Message displayName;
            if (displayNameComponent != null) {
                displayName = displayNameComponent.getDisplayName();
            }
            else {
                final PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType);
                assert playerRefComponent != null;
                displayName = Message.raw(playerRefComponent.getUsername());
            }
            event.setMessage(displayName);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.playerRefComponentType;
        }
    }
}
