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

package com.hypixel.hytale.builtin.deployables;

import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.SoundUtil;
import com.hypixel.hytale.protocol.SoundCategory;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.universe.world.PlayerUtil;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.entities.PlayAnimation;
import javax.annotation.Nullable;
import com.hypixel.hytale.protocol.AnimationSlot;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatValue;
import java.util.Iterator;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.StaticModifier;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.Modifier;
import com.hypixel.hytale.server.core.modules.entitystats.asset.EntityStatType;
import java.util.Map;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.builtin.deployables.component.DeployableOwnerComponent;
import java.time.temporal.TemporalAmount;
import java.time.Duration;
import com.hypixel.hytale.server.core.modules.time.TimeResource;
import com.hypixel.hytale.server.core.modules.entity.DespawnComponent;
import com.hypixel.hytale.server.core.modules.entity.hitboxcollision.HitboxCollision;
import com.hypixel.hytale.server.core.modules.entity.hitboxcollision.HitboxCollisionConfig;
import com.hypixel.hytale.server.core.modules.entity.component.Invulnerable;
import com.hypixel.hytale.server.core.modules.entityui.UIComponentList;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox;
import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import java.util.UUID;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.builtin.deployables.component.DeployableComponent;
import com.hypixel.hytale.server.core.modules.entity.component.AudioComponent;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.builtin.deployables.config.DeployableConfig;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.CommandBuffer;

public class DeployablesUtils
{
    private static final String DEPLOYABLE_MAX_STAT_MODIFIER = "DEPLOYABLE_MAX";
    
    @Nonnull
    public static Ref<EntityStore> spawnDeployable(@Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final Store<EntityStore> store, @Nonnull final DeployableConfig config, @Nonnull final Ref<EntityStore> deployerRef, @Nonnull final Vector3f position, @Nonnull final Vector3f rotation, @Nonnull final String spawnFace) {
        final Holder<EntityStore> holder = EntityStore.REGISTRY.newHolder();
        final Vector3d spawnPos = new Vector3d(position.x, position.y, position.z);
        final Model model = config.getModel();
        final AudioComponent audioComponent = new AudioComponent();
        if (config.getAmbientSoundEventIndex() != 0) {
            audioComponent.addSound(config.getAmbientSoundEventIndex());
        }
        holder.addComponent(DeployableComponent.getComponentType(), new DeployableComponent());
        holder.addComponent(TransformComponent.getComponentType(), new TransformComponent());
        holder.addComponent(HeadRotation.getComponentType(), new HeadRotation(Vector3f.FORWARD));
        holder.addComponent(UUIDComponent.getComponentType(), new UUIDComponent(UUID.randomUUID()));
        holder.addComponent(EntityStatMap.getComponentType(), new EntityStatMap());
        holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model));
        holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference()));
        holder.addComponent(BoundingBox.getComponentType(), new BoundingBox(model.getBoundingBox()));
        holder.addComponent(AudioComponent.getComponentType(), audioComponent);
        holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId()));
        holder.ensureComponent(DeployableComponent.getComponentType());
        holder.ensureComponent(EntityModule.get().getVisibleComponentType());
        holder.ensureComponent(EntityStore.REGISTRY.getNonSerializedComponentType());
        final UIComponentList uiCompList = holder.ensureAndGetComponent(UIComponentList.getComponentType());
        uiCompList.update();
        if (config.getInvulnerable()) {
            holder.ensureComponent(Invulnerable.getComponentType());
        }
        final int hitboxCollisionConfigIndex = config.getHitboxCollisionConfigIndex();
        if (hitboxCollisionConfigIndex != -1) {
            final HitboxCollisionConfig hitboxCollisionAsset = HitboxCollisionConfig.getAssetMap().getAsset(hitboxCollisionConfigIndex);
            holder.addComponent(HitboxCollision.getComponentType(), new HitboxCollision(hitboxCollisionAsset));
        }
        final long liveDuration = config.getLiveDurationInMillis();
        if (liveDuration > 0L) {
            holder.addComponent(DespawnComponent.getComponentType(), new DespawnComponent(store.getResource(TimeResource.getResourceType()).getNow().plus((TemporalAmount)Duration.ofMillis(liveDuration))));
        }
        final EntityStatMap entityStatMapComponent = holder.ensureAndGetComponent(EntityStatMap.getComponentType());
        entityStatMapComponent.update();
        populateStats(config, entityStatMapComponent);
        final DeployableComponent deployableComponent = holder.ensureAndGetComponent(DeployableComponent.getComponentType());
        deployableComponent.init(deployerRef, store, config, store.getResource(TimeResource.getResourceType()).getNow(), spawnFace);
        final TransformComponent transformComponent = holder.ensureAndGetComponent(TransformComponent.getComponentType());
        transformComponent.setRotation(rotation);
        transformComponent.setPosition(new Vector3d(spawnPos));
        final HeadRotation headRotationComponent = holder.ensureAndGetComponent(HeadRotation.getComponentType());
        headRotationComponent.setRotation(rotation);
        commandBuffer.ensureComponent(deployerRef, DeployableOwnerComponent.getComponentType());
        return commandBuffer.addEntity(holder, AddReason.SPAWN);
    }
    
    static void populateStats(@Nonnull final DeployableConfig config, @Nonnull final EntityStatMap entityStatMapComponent) {
        final Map<String, DeployableConfig.StatConfig> stats = config.getStatValues();
        if (stats == null) {
            return;
        }
        for (final Map.Entry<String, DeployableConfig.StatConfig> statEntry : stats.entrySet()) {
            final DeployableConfig.StatConfig statConfig = statEntry.getValue();
            final int statIndex = EntityStatType.getAssetMap().getIndex(statEntry.getKey());
            final EntityStatValue stat = entityStatMapComponent.get(statIndex);
            if (stat == null) {
                continue;
            }
            final EntityStatType asset = EntityStatType.getAssetMap().getAsset(statIndex);
            final StaticModifier modifier = new StaticModifier(Modifier.ModifierTarget.MAX, StaticModifier.CalculationType.ADDITIVE, statConfig.getMax() - asset.getMax());
            entityStatMapComponent.putModifier(statIndex, "DEPLOYABLE_MAX", modifier);
            final float initialValue = statConfig.getInitial();
            if (initialValue == Float.MAX_VALUE) {
                entityStatMapComponent.maximizeStatValue(statIndex);
            }
            else {
                entityStatMapComponent.setStatValue(statIndex, initialValue);
            }
        }
    }
    
    public static void playAnimation(@Nonnull final Store<EntityStore> store, final int networkId, @Nonnull final Ref<EntityStore> ref, @Nonnull final DeployableConfig config, @Nonnull final AnimationSlot animationSlot, @Nullable final String itemAnimationsId, @Nonnull final String animationId) {
        final Model model = config.getModel();
        if (animationSlot != AnimationSlot.Action && model != null && !model.getAnimationSetMap().containsKey(animationId)) {
            return;
        }
        final PlayAnimation animationPacket = new PlayAnimation(networkId, itemAnimationsId, animationId, animationSlot);
        PlayerUtil.forEachPlayerThatCanSeeEntity(ref, (playerRef, playerRefComponent, ca) -> playerRefComponent.getPacketHandler().write(animationPacket), store);
    }
    
    public static void stopAnimation(@Nonnull final Store<EntityStore> store, final int networkId, @Nonnull final Ref<EntityStore> ref, @Nonnull final AnimationSlot animationSlot) {
        final PlayAnimation animationPacket = new PlayAnimation(networkId, null, null, animationSlot);
        PlayerUtil.forEachPlayerThatCanSeeEntity(ref, (playerRef, playerRefComponent, ca) -> playerRefComponent.getPacketHandler().write(animationPacket), store);
    }
    
    public static void playSoundEventsAtEntity(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor, final int localIndex, final int worldIndex, @Nonnull final Vector3d pos) {
        final Player targetPlayerComponent = componentAccessor.getComponent(ref, Player.getComponentType());
        if (localIndex != 0 && targetPlayerComponent != null) {
            SoundUtil.playSoundEvent2d(ref, localIndex, SoundCategory.SFX, componentAccessor);
        }
        if (worldIndex != 0) {
            SoundUtil.playSoundEvent3d(worldIndex, SoundCategory.SFX, pos, componentAccessor);
        }
    }
}
