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

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

import com.hypixel.hytale.component.Resource;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData;
import com.hypixel.hytale.component.system.tick.ArchetypeTickingSystem;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.server.core.entity.EntityUtils;
import java.util.logging.Level;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.StoreSystem;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;

public class PlayerSavingSystems
{
    @Nonnull
    private static final HytaleLogger LOGGER;
    private static final float PLAYER_SAVE_INTERVAL_SECONDS = 10.0f;
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    public static class WorldRemovedSystem extends StoreSystem<EntityStore>
    {
        @Nonnull
        private final ComponentType<EntityStore, Player> playerComponentType;
        @Nonnull
        private final ComponentType<EntityStore, PlayerRef> refComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        static final /* synthetic */ boolean $assertionsDisabled;
        
        public WorldRemovedSystem(@Nonnull final ComponentType<EntityStore, Player> playerComponentType) {
            this.playerComponentType = playerComponentType;
            this.refComponentType = PlayerRef.getComponentType();
            this.query = (Query<EntityStore>)Query.and(playerComponentType, this.refComponentType);
        }
        
        @Override
        public void onSystemAddedToStore(@Nonnull final Store<EntityStore> store) {
        }
        
        @Override
        public void onSystemRemovedFromStore(@Nonnull final Store<EntityStore> store) {
            if (store.getExternalData().getWorld().getWorldConfig().isSavingPlayers()) {
                PlayerSavingSystems.LOGGER.at(Level.INFO).log("Saving Players...");
            }
            else {
                PlayerSavingSystems.LOGGER.at(Level.INFO).log("Disconnecting Players...");
            }
            store.forEachEntityParallel(this.query, (index, archetypeChunk, commandBuffer) -> {
                final Player playerComponent = archetypeChunk.getComponent(index, this.playerComponentType);
                if (!WorldRemovedSystem.$assertionsDisabled && playerComponent == null) {
                    throw new AssertionError();
                }
                else {
                    final PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.refComponentType);
                    if (!WorldRemovedSystem.$assertionsDisabled && playerRefComponent == null) {
                        throw new AssertionError();
                    }
                    else {
                        final World world = commandBuffer.getExternalData().getWorld();
                        if (world.getWorldConfig().isSavingPlayers()) {
                            playerComponent.saveConfig(world, EntityUtils.toHolder(index, archetypeChunk));
                        }
                        playerRefComponent.getPacketHandler().disconnect("Stopping world!");
                    }
                }
            });
        }
    }
    
    public static class TickingSystem extends EntityTickingSystem<EntityStore> implements RunWhenPausedSystem<EntityStore>
    {
        @Nonnull
        private final ResourceType<EntityStore, SaveDataResource> dataResourceType;
        @Nonnull
        private final ComponentType<EntityStore, Player> playerComponentType;
        @Nonnull
        private final ComponentType<EntityStore, TransformComponent> transformComponentType;
        @Nonnull
        private final ComponentType<EntityStore, HeadRotation> headRotationComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public TickingSystem(@Nonnull final ComponentType<EntityStore, Player> playerComponentType) {
            this.dataResourceType = this.registerResource(SaveDataResource.class, SaveDataResource::new);
            this.playerComponentType = playerComponentType;
            this.transformComponentType = TransformComponent.getComponentType();
            this.headRotationComponentType = HeadRotation.getComponentType();
            this.query = (Query<EntityStore>)Archetype.of(playerComponentType, this.transformComponentType, this.headRotationComponentType);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        @Override
        public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
            final World world = store.getExternalData().getWorld();
            if (!world.getWorldConfig().isSavingPlayers()) {
                return;
            }
            final SaveDataResource saveDataResource;
            final SaveDataResource data = saveDataResource = store.getResource(this.dataResourceType);
            saveDataResource.delay -= dt;
            if (data.delay <= 0.0f) {
                data.delay = 10.0f;
                store.tick(this, dt, systemIndex);
            }
        }
        
        @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 Player playerComponent = archetypeChunk.getComponent(index, this.playerComponentType);
            assert playerComponent != null;
            final TransformComponent transformComponent = archetypeChunk.getComponent(index, this.transformComponentType);
            assert transformComponent != null;
            final HeadRotation headRotationComponent = archetypeChunk.getComponent(index, this.headRotationComponentType);
            assert headRotationComponent != null;
            final PlayerConfigData data = playerComponent.getPlayerConfigData();
            final Vector3d position = transformComponent.getPosition();
            final Vector3f rotation = headRotationComponent.getRotation();
            final Vector3d lastSavedPosition = data.lastSavedPosition;
            final Vector3f lastSavedRotation = data.lastSavedRotation;
            if (!lastSavedPosition.equals(position) || !lastSavedRotation.equals(rotation) || data.consumeHasChanged() || playerComponent.getInventory().consumeNeedsSaving()) {
                lastSavedPosition.assign(position);
                lastSavedRotation.assign(rotation);
                playerComponent.saveConfig(store.getExternalData().getWorld(), EntityUtils.toHolder(index, archetypeChunk));
            }
        }
    }
    
    public static class SaveDataResource implements Resource<EntityStore>
    {
        private float delay;
        
        public SaveDataResource() {
            this.delay = 10.0f;
        }
        
        @Nonnull
        @Override
        public Resource<EntityStore> clone() {
            final SaveDataResource data = new SaveDataResource();
            data.delay = this.delay;
            return data;
        }
    }
}
