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

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

import com.hypixel.hytale.server.core.modules.entity.component.CollisionResultComponent;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.player.ClientTeleport;
import com.hypixel.hytale.protocol.ModelTransform;
import com.hypixel.hytale.server.core.util.PositionUtil;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.vector.Location;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.RefChangeSystem;

public class TeleportSystems
{
    public static class MoveSystem extends RefChangeSystem<EntityStore, Teleport>
    {
        @Nonnull
        private final ComponentType<EntityStore, Teleport> teleportComponentType;
        @Nonnull
        private final ComponentType<EntityStore, TransformComponent> transformComponentType;
        @Nonnull
        private final ComponentType<EntityStore, HeadRotation> headRotationComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public MoveSystem() {
            this.teleportComponentType = Teleport.getComponentType();
            this.transformComponentType = TransformComponent.getComponentType();
            this.headRotationComponentType = HeadRotation.getComponentType();
            this.query = (Query<EntityStore>)Query.and(this.teleportComponentType, this.transformComponentType, Query.not((Query<Object>)PlayerRef.getComponentType()));
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, Teleport> componentType() {
            return this.teleportComponentType;
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport teleport, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final TransformComponent transformComponent = commandBuffer.getComponent(ref, this.transformComponentType);
            assert transformComponent != null;
            transformComponent.teleportPosition(teleport.getPosition());
            transformComponent.teleportRotation(teleport.getRotation());
            final HeadRotation headRotationComponent = commandBuffer.getComponent(ref, this.headRotationComponentType);
            if (headRotationComponent != null) {
                headRotationComponent.teleportRotation(teleport.getRotation());
            }
            final World targetWorld = teleport.getWorld();
            if (targetWorld != null && !targetWorld.equals(store.getExternalData().getWorld())) {
                commandBuffer.run(s -> {
                    final Holder<EntityStore> holder = s.removeEntity(ref, RemoveReason.UNLOAD);
                    targetWorld.execute(() -> targetWorld.getEntityStore().getStore().addEntity(holder, AddReason.LOAD));
                    return;
                });
            }
            commandBuffer.removeComponent(ref, this.teleportComponentType);
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final Teleport oldComponent, @Nonnull final Teleport newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
    }
    
    public static class PlayerMoveSystem extends RefChangeSystem<EntityStore, Teleport>
    {
        @Nonnull
        private final ComponentType<EntityStore, Teleport> teleportComponentType;
        @Nonnull
        private final ComponentType<EntityStore, TransformComponent> transformComponentType;
        @Nonnull
        private final ComponentType<EntityStore, HeadRotation> headRotationComponentType;
        @Nonnull
        private final ComponentType<EntityStore, PlayerRef> playerRefComponentType;
        @Nonnull
        private final ComponentType<EntityStore, Player> playerComponentType;
        @Nonnull
        private final ComponentType<EntityStore, PendingTeleport> pendingTeleportComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public PlayerMoveSystem() {
            this.teleportComponentType = Teleport.getComponentType();
            this.transformComponentType = TransformComponent.getComponentType();
            this.headRotationComponentType = HeadRotation.getComponentType();
            this.playerRefComponentType = PlayerRef.getComponentType();
            this.playerComponentType = Player.getComponentType();
            this.pendingTeleportComponentType = PendingTeleport.getComponentType();
            this.query = (Query<EntityStore>)Query.and(this.teleportComponentType, this.playerRefComponentType, this.transformComponentType, this.playerComponentType);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, Teleport> componentType() {
            return this.teleportComponentType;
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport teleport, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final World targetWorld = teleport.getWorld();
            if (targetWorld == null || targetWorld.equals(store.getExternalData().getWorld())) {
                this.teleportToPosition(ref, teleport, commandBuffer);
            }
            else {
                this.teleportToWorld(ref, teleport, commandBuffer, targetWorld);
            }
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final Teleport oldComponent, @Nonnull final Teleport newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        private void teleportToWorld(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport teleport, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final World targetWorld) {
            final PlayerRef playerRefComponent = commandBuffer.getComponent(ref, this.playerRefComponentType);
            assert playerRefComponent != null;
            commandBuffer.removeComponent(ref, this.teleportComponentType);
            final TransformComponent transformComponent = commandBuffer.getComponent(ref, this.transformComponentType);
            final String originWorldName = commandBuffer.getExternalData().getWorld().getName();
            final Location origin = new Location(originWorldName, transformComponent.getTransform().clone());
            final Location destination = new Location(targetWorld.getName(), teleport.getPosition().clone(), teleport.getRotation().clone());
            commandBuffer.run(s -> {
                final TeleportRecord teleportRecord = s.ensureAndGetComponent(ref, TeleportRecord.getComponentType());
                teleportRecord.setLastTeleport(new TeleportRecord.Entry(origin, destination, java.lang.System.nanoTime()));
                playerRefComponent.removeFromStore();
                targetWorld.addPlayer(playerRefComponent, new Transform(teleport.getPosition(), teleport.getRotation()));
            });
        }
        
        private void teleportToPosition(@Nonnull final Ref<EntityStore> ref, @Nonnull final Teleport teleport, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final TransformComponent transformComponent = commandBuffer.getComponent(ref, this.transformComponentType);
            assert transformComponent != null;
            final PlayerRef playerRefComponent = commandBuffer.getComponent(ref, this.playerRefComponentType);
            assert playerRefComponent != null;
            final Player playerComponent = commandBuffer.getComponent(ref, this.playerComponentType);
            assert playerComponent != null;
            final PendingTeleport pendingTeleportComponent = commandBuffer.ensureAndGetComponent(ref, this.pendingTeleportComponentType);
            final Vector3d teleportPosition = teleport.getPosition();
            final Vector3f teleportRotation = teleport.getRotation();
            transformComponent.teleportPosition(teleportPosition);
            transformComponent.teleportRotation(teleportRotation);
            final HeadRotation headRotationComponent = commandBuffer.getComponent(ref, this.headRotationComponentType);
            if (headRotationComponent != null) {
                final Vector3f teleportHeadRotation = teleport.getHeadRotation();
                headRotationComponent.teleportRotation((teleportHeadRotation != null) ? teleportHeadRotation : teleportRotation);
            }
            final TeleportRecord teleportHistory = commandBuffer.ensureAndGetComponent(ref, TeleportRecord.getComponentType());
            final World world = commandBuffer.getExternalData().getWorld();
            final Location origin = new Location(world.getName(), teleportPosition.clone(), teleportRotation.clone());
            final Location destination = new Location(world.getName(), teleportPosition.clone(), teleportRotation.clone());
            teleportHistory.setLastTeleport(new TeleportRecord.Entry(origin, destination, java.lang.System.nanoTime()));
            playerComponent.getWindowManager().validateWindows(ref, commandBuffer);
            final int id = pendingTeleportComponent.queueTeleport(teleport);
            final ClientTeleport teleportPacket = new ClientTeleport((byte)id, new ModelTransform(PositionUtil.toPositionPacket(transformComponent.getPosition()), PositionUtil.toDirectionPacket(transformComponent.getRotation()), (headRotationComponent != null) ? PositionUtil.toDirectionPacket(headRotationComponent.getRotation()) : PositionUtil.toDirectionPacket(transformComponent.getRotation())), teleport.isResetVelocity());
            playerRefComponent.getPacketHandler().write(teleportPacket);
            commandBuffer.removeComponent(ref, this.teleportComponentType);
        }
    }
    
    public static class PlayerMoveCompleteSystem extends RefChangeSystem<EntityStore, PendingTeleport>
    {
        @Nonnull
        private final ComponentType<EntityStore, PendingTeleport> pendingComponentType;
        @Nonnull
        private final ComponentType<EntityStore, Player> playerComponentType;
        @Nonnull
        private final ComponentType<EntityStore, TransformComponent> transformComponentType;
        @Nonnull
        private final ComponentType<EntityStore, CollisionResultComponent> collisionResultComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public PlayerMoveCompleteSystem() {
            this.pendingComponentType = PendingTeleport.getComponentType();
            this.playerComponentType = Player.getComponentType();
            this.transformComponentType = TransformComponent.getComponentType();
            this.collisionResultComponentType = CollisionResultComponent.getComponentType();
            this.query = (Query<EntityStore>)Query.and(this.playerComponentType, this.transformComponentType);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, PendingTeleport> componentType() {
            return this.pendingComponentType;
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final PendingTeleport component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final PendingTeleport oldComponent, @Nonnull final PendingTeleport newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final PendingTeleport component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Player playerComponent = commandBuffer.getComponent(ref, this.playerComponentType);
            assert playerComponent != null;
            final TransformComponent transformComponent = commandBuffer.getComponent(ref, this.transformComponentType);
            assert transformComponent != null;
            final CollisionResultComponent collisionResultComponent = commandBuffer.getComponent(ref, this.collisionResultComponentType);
            if (collisionResultComponent != null) {
                collisionResultComponent.getCollisionStartPosition().assign(transformComponent.getPosition());
            }
            playerComponent.moveTo(ref, component.getPosition().x, component.getPosition().y, component.getPosition().z, commandBuffer);
        }
    }
}
