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

package com.hypixel.hytale.builtin.mounts;

import com.hypixel.hytale.server.core.entity.entities.player.movement.MovementManager;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.interaction.DismountNPC;
import com.hypixel.hytale.server.npc.systems.RoleChangeSystem;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.builtin.mounts.interactions.SeatingInteraction;
import com.hypixel.hytale.builtin.mounts.interactions.MountInteraction;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.builtin.mounts.interactions.SpawnMinecartInteraction;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.builtin.mounts.commands.MountCommand;
import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
import com.hypixel.hytale.server.core.io.handlers.SubPacketHandler;
import com.hypixel.hytale.server.core.io.handlers.IPacketHandler;
import java.util.function.Function;
import com.hypixel.hytale.server.core.io.ServerManager;
import com.hypixel.hytale.component.system.ISystem;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import java.util.function.Supplier;
import com.hypixel.hytale.builtin.mounts.npc.builders.BuilderActionMount;
import com.hypixel.hytale.server.npc.NPCPlugin;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.builtin.mounts.minecart.MinecartComponent;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;

public class MountPlugin extends JavaPlugin
{
    private static MountPlugin instance;
    private ComponentType<ChunkStore, BlockMountComponent> blockMountComponentType;
    private ComponentType<EntityStore, NPCMountComponent> mountComponentType;
    private ComponentType<EntityStore, MountedComponent> mountedComponentType;
    private ComponentType<EntityStore, MountedByComponent> mountedByComponentType;
    private ComponentType<EntityStore, MinecartComponent> minecartComponentType;
    
    public static MountPlugin getInstance() {
        return MountPlugin.instance;
    }
    
    public MountPlugin(@Nonnull final JavaPluginInit init) {
        super(init);
    }
    
    public ComponentType<EntityStore, NPCMountComponent> getMountComponentType() {
        return this.mountComponentType;
    }
    
    public ComponentType<EntityStore, MountedComponent> getMountedComponentType() {
        return this.mountedComponentType;
    }
    
    public ComponentType<EntityStore, MountedByComponent> getMountedByComponentType() {
        return this.mountedByComponentType;
    }
    
    public ComponentType<EntityStore, MinecartComponent> getMinecartComponentType() {
        return this.minecartComponentType;
    }
    
    @Override
    protected void setup() {
        MountPlugin.instance = this;
        this.blockMountComponentType = this.getChunkStoreRegistry().registerComponent(BlockMountComponent.class, BlockMountComponent::new);
        NPCPlugin.get().registerCoreComponentType("Mount", (Supplier<Builder<Object>>)BuilderActionMount::new);
        this.mountComponentType = this.getEntityStoreRegistry().registerComponent(NPCMountComponent.class, "Mount", NPCMountComponent.CODEC);
        this.mountedComponentType = this.getEntityStoreRegistry().registerComponent(MountedComponent.class, () -> {
            throw new UnsupportedOperationException("Mounted component cannot be default constructed");
        });
        this.mountedByComponentType = this.getEntityStoreRegistry().registerComponent(MountedByComponent.class, MountedByComponent::new);
        this.minecartComponentType = this.getEntityStoreRegistry().registerComponent(MinecartComponent.class, "Minecart", MinecartComponent.CODEC);
        this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.OnAdd(this.mountComponentType));
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new NPCMountSystems.DismountOnPlayerDeath());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new NPCMountSystems.DismountOnMountDeath());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.TrackerUpdate());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new MountSystems.TrackerRemove());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.RemoveMountedBy());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.RemoveMounted());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new MountSystems.TeleportMountedEntity());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new MountSystems.MountedEntityDeath());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new MountSystems.PlayerMount());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.HandleMountInput());
        this.getEntityStoreRegistry().registerSystem((ISystem<EntityStore>)new MountSystems.TrackedMounted());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.EnsureMinecartComponents());
        this.getEntityStoreRegistry().registerSystem(new MountSystems.OnMinecartHit());
        this.getChunkStoreRegistry().registerSystem(new MountSystems.RemoveBlockSeat());
        ServerManager.get().registerSubPacketHandlers((Function<IPacketHandler, SubPacketHandler>)MountGamePacketHandler::new);
        this.getEventRegistry().register(PlayerDisconnectEvent.class, MountPlugin::onPlayerDisconnect);
        this.getCommandRegistry().registerCommand(new MountCommand());
        Interaction.CODEC.register("SpawnMinecart", SpawnMinecartInteraction.class, SpawnMinecartInteraction.CODEC);
        Interaction.CODEC.register("Mount", MountInteraction.class, MountInteraction.CODEC);
        Interaction.CODEC.register("Seating", SeatingInteraction.class, SeatingInteraction.CODEC);
    }
    
    public ComponentType<ChunkStore, BlockMountComponent> getBlockMountComponentType() {
        return this.blockMountComponentType;
    }
    
    private static void onPlayerDisconnect(@Nonnull final PlayerDisconnectEvent event) {
        final PlayerRef playerRef = event.getPlayerRef();
        final Ref<EntityStore> ref = playerRef.getReference();
        if (ref == null) {
            return;
        }
        final Store<EntityStore> store = ref.getStore();
        final World world = store.getExternalData().getWorld();
        world.execute(() -> {
            if (!(!ref.isValid())) {
                final Player playerComponent = store.getComponent(ref, Player.getComponentType());
                if (playerComponent != null) {
                    checkDismountNpc(store, playerComponent);
                }
            }
        });
    }
    
    public static void checkDismountNpc(@Nonnull final ComponentAccessor<EntityStore> store, @Nonnull final Player playerComponent) {
        final int mountEntityId = playerComponent.getMountEntityId();
        if (mountEntityId == 0) {
            return;
        }
        dismountNpc(store, mountEntityId);
    }
    
    public static void dismountNpc(@Nonnull final ComponentAccessor<EntityStore> store, final int mountEntityId) {
        final Ref<EntityStore> entityReference = store.getExternalData().getRefFromNetworkId(mountEntityId);
        if (entityReference == null || !entityReference.isValid()) {
            return;
        }
        final NPCMountComponent mountComponent = store.getComponent(entityReference, NPCMountComponent.getComponentType());
        assert mountComponent != null;
        resetOriginalMountRole(entityReference, store, mountComponent);
        final PlayerRef ownerPlayerRef = mountComponent.getOwnerPlayerRef();
        if (ownerPlayerRef != null) {
            resetOriginalPlayerMovementSettings(ownerPlayerRef, store);
        }
    }
    
    private static void resetOriginalMountRole(@Nonnull final Ref<EntityStore> entityReference, @Nonnull final ComponentAccessor<EntityStore> store, @Nonnull final NPCMountComponent mountComponent) {
        final NPCEntity npcComponent = store.getComponent(entityReference, NPCEntity.getComponentType());
        assert npcComponent != null;
        RoleChangeSystem.requestRoleChange(entityReference, npcComponent.getRole(), mountComponent.getOriginalRoleIndex(), false, "Idle", null, store);
        store.removeComponent(entityReference, NPCMountComponent.getComponentType());
    }
    
    public static void resetOriginalPlayerMovementSettings(@Nonnull final PlayerRef playerRef, @Nonnull final ComponentAccessor<EntityStore> store) {
        final Ref<EntityStore> reference = playerRef.getReference();
        if (reference == null) {
            return;
        }
        playerRef.getPacketHandler().write(new DismountNPC());
        final MovementManager movementManagerComponent = store.getComponent(reference, MovementManager.getComponentType());
        assert movementManagerComponent != null;
        movementManagerComponent.resetDefaultsAndUpdate(reference, store);
    }
}
