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

package com.hypixel.hytale.server.flock.corecomponents;

import com.hypixel.hytale.server.core.modules.physics.util.PhysicsMath;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.npc.movement.Steering;
import javax.annotation.Nullable;
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.BuilderBodyMotionBase;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.flock.corecomponents.builders.BuilderBodyMotionFlock;
import com.hypixel.hytale.server.npc.movement.GroupSteeringAccumulator;
import com.hypixel.hytale.server.core.entity.group.EntityGroup;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.flock.FlockMembership;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.npc.corecomponents.BodyMotionBase;

public class BodyMotionFlock extends BodyMotionBase
{
    private static final ComponentType<EntityStore, FlockMembership> FLOCK_MEMBERSHIP_COMPONENT_TYPE;
    private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
    private static final ComponentType<EntityStore, EntityGroup> ENTITY_GROUP_COMPONENT_TYPE;
    protected final GroupSteeringAccumulator groupSteeringAccumulator;
    
    public BodyMotionFlock(@Nonnull final BuilderBodyMotionFlock builderBodyMotionFlock) {
        super(builderBodyMotionFlock);
        this.groupSteeringAccumulator = new GroupSteeringAccumulator();
    }
    
    @Override
    public boolean computeSteering(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, @Nullable final InfoProvider sensorInfo, final double dt, @Nonnull final Steering desiredSteering, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final FlockMembership flockMembership = componentAccessor.getComponent(ref, BodyMotionFlock.FLOCK_MEMBERSHIP_COMPONENT_TYPE);
        final Ref<EntityStore> flockReference = (flockMembership != null) ? flockMembership.getFlockRef() : null;
        if (flockReference == null || !flockReference.isValid()) {
            return false;
        }
        final EntityGroup entityGroup = componentAccessor.getComponent(flockReference, BodyMotionFlock.ENTITY_GROUP_COMPONENT_TYPE);
        final Vector3d componentSelector = role.getActiveMotionController().getComponentSelector();
        this.groupSteeringAccumulator.setComponentSelector(componentSelector);
        this.groupSteeringAccumulator.setMaxRange(role.getFlockInfluenceRange());
        this.groupSteeringAccumulator.begin(ref, componentAccessor);
        entityGroup.forEachMemberExcludingSelf((iGroupEntity, _entity, _groupSteeringAccumulator, _store) -> _groupSteeringAccumulator.processEntity(iGroupEntity, _store), ref, this.groupSteeringAccumulator, componentAccessor);
        this.groupSteeringAccumulator.end();
        final double weightCohesion = 1.0;
        final double weightSeparation = 1.0;
        final Ref<EntityStore> leaderRef = entityGroup.getLeaderRef();
        if (!leaderRef.isValid()) {
            return false;
        }
        final Vector3d sumOfPositions = this.groupSteeringAccumulator.getSumOfPositions();
        final Vector3d sumOfVelocities = this.groupSteeringAccumulator.getSumOfVelocities();
        final Vector3d sumOfDistances = this.groupSteeringAccumulator.getSumOfDistances();
        final TransformComponent leaderTransformComponent = componentAccessor.getComponent(leaderRef, BodyMotionFlock.TRANSFORM_COMPONENT_TYPE);
        assert leaderTransformComponent != null;
        final Vector3d position = leaderTransformComponent.getPosition();
        final Vector3d toLeader = new Vector3d(position.getX(), position.getY(), position.getZ());
        if (sumOfVelocities.squaredLength() > 1.0E-4) {
            desiredSteering.setYaw(PhysicsMath.headingFromDirection(sumOfVelocities.getX(), sumOfVelocities.getZ()));
        }
        else {
            final TransformComponent parentEntityTransformComponent = componentAccessor.getComponent(ref, BodyMotionFlock.TRANSFORM_COMPONENT_TYPE);
            assert parentEntityTransformComponent != null;
            desiredSteering.setYaw(parentEntityTransformComponent.getRotation().getYaw());
        }
        sumOfPositions.subtract(position.getX(), position.getY(), position.getZ()).scale(componentSelector);
        if (sumOfPositions.squaredLength() > 1.0E-4) {
            sumOfPositions.normalize().scale(weightCohesion);
        }
        else {
            sumOfPositions.assign(0.0);
        }
        if (sumOfDistances.squaredLength() > 1.0E-4) {
            sumOfDistances.normalize().scale(-weightSeparation);
        }
        else {
            sumOfDistances.assign(0.0);
        }
        toLeader.subtract(position.getX(), position.getY(), position.getZ()).scale(componentSelector);
        toLeader.normalize().scale(0.5);
        sumOfPositions.add(sumOfDistances).add(toLeader);
        if (sumOfPositions.squaredLength() > 1.0E-4) {
            sumOfPositions.normalize();
        }
        else {
            sumOfPositions.assign(0.0);
        }
        desiredSteering.setTranslation(sumOfPositions);
        return true;
    }
    
    static {
        FLOCK_MEMBERSHIP_COMPONENT_TYPE = FlockMembership.getComponentType();
        TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
        ENTITY_GROUP_COMPONENT_TYPE = EntityGroup.getComponentType();
    }
}
