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

package com.hypixel.hytale.builtin.npccombatactionevaluator.corecomponents;

import com.hypixel.hytale.server.core.entity.InteractionChain;
import com.hypixel.hytale.server.core.modules.interaction.IInteractionSimulationHandler;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.server.core.entity.InteractionContext;
import com.hypixel.hytale.server.npc.interactions.NPCInteractionSimulationHandler;
import com.hypixel.hytale.server.core.modules.physics.util.PhysicsMath;
import com.hypixel.hytale.server.npc.util.NPCPhysicsMath;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.data.Collector;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
import com.hypixel.hytale.protocol.InteractionType;
import com.hypixel.hytale.server.npc.corecomponents.combat.ActionAttack;
import com.hypixel.hytale.server.core.modules.projectile.config.BallisticData;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.data.SingleCollector;
import com.hypixel.hytale.server.npc.util.AimingData;
import com.hypixel.hytale.server.core.modules.interaction.InteractionModule;
import com.hypixel.hytale.server.core.entity.InteractionManager;
import com.hypixel.hytale.server.npc.sensorinfo.parameterproviders.ParameterProvider;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderActionBase;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.npccombatactionevaluator.corecomponents.builders.BuilderActionCombatAbility;
import com.hypixel.hytale.server.npc.sensorinfo.parameterproviders.DoubleParameterProvider;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.builtin.npccombatactionevaluator.evaluator.CombatActionEvaluator;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.npc.corecomponents.ActionBase;

public class ActionCombatAbility extends ActionBase
{
    protected static final ComponentType<EntityStore, CombatActionEvaluator> COMPONENT_TYPE;
    protected static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
    protected static final float POSITIONING_ANGLE_THRESHOLD = 0.08726646f;
    protected final int id;
    protected final int positioningAngleProviderSlot;
    protected final double meleeConeAngle = 0.2617993950843811;
    @Nullable
    protected String attack;
    protected DoubleParameterProvider cachedPositioningAngleProvider;
    protected boolean initialised;
    
    public ActionCombatAbility(@Nonnull final BuilderActionCombatAbility builder, @Nonnull final BuilderSupport builderSupport) {
        super(builder);
        this.id = builderSupport.getNextAttackIndex();
        this.positioningAngleProviderSlot = builderSupport.getParameterSlot("PositioningAngle");
    }
    
    @Override
    public boolean canExecute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, @Nullable final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
        if (!this.initialised) {
            if (sensorInfo != null) {
                final ParameterProvider parameterProvider = sensorInfo.getParameterProvider(this.positioningAngleProviderSlot);
                if (parameterProvider instanceof final DoubleParameterProvider doubleParameterProvider) {
                    this.cachedPositioningAngleProvider = doubleParameterProvider;
                }
            }
            this.initialised = true;
        }
        if (!super.canExecute(ref, role, sensorInfo, dt, store)) {
            return false;
        }
        final CombatActionEvaluator combatActionEvaluator = ref.getStore().getComponent(ref, ActionCombatAbility.COMPONENT_TYPE);
        return combatActionEvaluator != null && combatActionEvaluator.getCurrentAttack() != null;
    }
    
    @Override
    public boolean execute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, @Nullable final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
        final CombatActionEvaluator combatActionEvaluatorComponent = store.getComponent(ref, ActionCombatAbility.COMPONENT_TYPE);
        assert combatActionEvaluatorComponent != null;
        final InteractionManager interactionManagerComponent = store.getComponent(ref, InteractionModule.get().getInteractionManagerComponent());
        assert interactionManagerComponent != null;
        final AimingData aimingDataInfo = (sensorInfo != null) ? sensorInfo.getPassedExtraInfo(AimingData.class) : null;
        final AimingData aimingData = (aimingDataInfo != null && aimingDataInfo.isClaimedBy(this.id)) ? aimingDataInfo : null;
        final boolean requireAiming = combatActionEvaluatorComponent.requiresAiming();
        final String nextAttack = combatActionEvaluatorComponent.getCurrentAttack();
        if (!nextAttack.equals(this.attack)) {
            this.attack = nextAttack;
            if (requireAiming && aimingData != null) {
                final SingleCollector<BallisticData> collector = ActionAttack.THREAD_LOCAL_COLLECTOR.get();
                interactionManagerComponent.walkChain(ref, collector, InteractionType.Primary, RootInteraction.getAssetMap().getAsset(this.attack), store);
                final BallisticData ballisticData = collector.getResult();
                if (ballisticData != null) {
                    aimingData.requireBallistic(ballisticData);
                    aimingData.setUseFlatTrajectory(true);
                }
                else {
                    final double chargeDistance = combatActionEvaluatorComponent.getChargeDistance();
                    if (chargeDistance > 0.0) {
                        aimingData.setChargeDistance(chargeDistance);
                        aimingData.setDesiredHitAngle(0.2617993950843811);
                    }
                    aimingData.requireCloseCombat();
                }
                return false;
            }
        }
        final TransformComponent transformComponent = store.getComponent(ref, ActionCombatAbility.TRANSFORM_COMPONENT_TYPE);
        assert transformComponent != null;
        final HeadRotation headRotationComponent = store.getComponent(ref, HeadRotation.getComponentType());
        assert headRotationComponent != null;
        final Vector3f rotation = (aimingData != null && aimingData.getChargeDistance() > 0.0) ? transformComponent.getRotation() : headRotationComponent.getRotation();
        if (aimingData != null && !aimingData.isOnTarget(rotation.getYaw(), rotation.getPitch(), 0.2617993950843811)) {
            aimingData.clearSolution();
            return false;
        }
        final Ref<EntityStore> target = (aimingData != null) ? aimingData.getTarget() : null;
        if (requireAiming && (target == null || !role.getPositionCache().hasLineOfSight(ref, target, store))) {
            if (aimingData != null) {
                aimingData.clearSolution();
            }
            return false;
        }
        if (combatActionEvaluatorComponent.shouldPositionFirst()) {
            double positioningAngle = Double.MAX_VALUE;
            if (this.cachedPositioningAngleProvider != null) {
                positioningAngle = this.cachedPositioningAngleProvider.getDoubleParameter();
            }
            if (positioningAngle != Double.MAX_VALUE) {
                if (target == null) {
                    return false;
                }
                final TransformComponent targetTransformComponent = store.getComponent(target, ActionCombatAbility.TRANSFORM_COMPONENT_TYPE);
                assert targetTransformComponent != null;
                final Vector3d targetPosition = targetTransformComponent.getPosition();
                final float selfYaw = NPCPhysicsMath.lookatHeading(transformComponent.getPosition(), targetPosition, transformComponent.getRotation().getYaw());
                final float difference = PhysicsMath.normalizeTurnAngle(targetTransformComponent.getRotation().getYaw() - selfYaw - (float)positioningAngle);
                if (Math.abs(difference) > 0.08726646f) {
                    return false;
                }
            }
        }
        final boolean damageFriendlies = combatActionEvaluatorComponent.shouldDamageFriendlies();
        if (!damageFriendlies && target != null && role.getPositionCache().isFriendlyBlockingLineOfSight(ref, target, store)) {
            aimingData.clearSolution();
            return false;
        }
        final IInteractionSimulationHandler interactionSimulationHandler = interactionManagerComponent.getInteractionSimulationHandler();
        if (interactionSimulationHandler instanceof final NPCInteractionSimulationHandler npcInteractionSimulationHandler) {
            npcInteractionSimulationHandler.requestChargeTime(combatActionEvaluatorComponent.getChargeFor());
        }
        final InteractionType interactionType = combatActionEvaluatorComponent.getCurrentInteractionType();
        final InteractionContext context = InteractionContext.forInteraction(interactionManagerComponent, ref, interactionType, store);
        context.setInteractionVarsGetter(combatActionEvaluatorComponent.getCurrentInteractionVarsGetter());
        final InteractionChain chain = interactionManagerComponent.initChain(interactionType, context, RootInteraction.getRootInteractionOrUnknown(this.attack), false);
        interactionManagerComponent.queueExecuteChain(chain);
        role.getCombatSupport().setExecutingAttack(chain, damageFriendlies, 0.0);
        if (aimingData != null) {
            aimingData.setHaveAttacked(true);
        }
        combatActionEvaluatorComponent.completeCurrentAction(false, true);
        this.attack = null;
        return true;
    }
    
    @Override
    public void activate(final Role role, @Nullable final InfoProvider infoProvider) {
        super.activate(role, infoProvider);
        if (infoProvider == null) {
            return;
        }
        final AimingData aimingData = infoProvider.getPassedExtraInfo(AimingData.class);
        if (aimingData != null) {
            aimingData.tryClaim(this.id);
        }
    }
    
    @Override
    public void deactivate(final Role role, @Nullable final InfoProvider infoProvider) {
        super.deactivate(role, infoProvider);
        if (infoProvider == null) {
            return;
        }
        final AimingData aimingData = infoProvider.getPassedExtraInfo(AimingData.class);
        if (aimingData != null) {
            aimingData.release();
        }
    }
    
    static {
        COMPONENT_TYPE = CombatActionEvaluator.getComponentType();
        TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
    }
}
