public override bool Execute(float dt)
    {
        if (Entity.Target.Value != null)
        {
            var diff = Entity.Target.Value.Position - Entity.Position;
            if (_predictShots)
            {
                var targetHullData    = Entity.ItemManager.GetData(Entity.Target.Value.Hull) as HullData;
                var targetVelocity    = float3(Entity.Target.Value.Velocity.x, 0, Entity.Target.Value.Velocity.y);
                var predictedPosition = AetheriaMath.FirstOrderIntercept(
                    Entity.Position, float3.zero, _shotSpeed,
                    Entity.Target.Value.Position, targetVelocity
                    );
                predictedPosition.y  = Entity.Zone.GetHeight(predictedPosition.xz) + targetHullData.GridOffset;
                Entity.LookDirection = normalize(predictedPosition - Entity.Position);
            }
            else
            {
                Entity.LookDirection = normalize(diff);
            }
            var dist = length(diff);

            foreach (var x in _weapons)
            {
                var data = x.Data as WeaponData;
                var fire = dot(
                    x.Direction,
                    Entity.LookDirection) > .99f;
                if (x.Evaluate(data.Range) > dist && fire)
                {
                    x.Activate();
                }
                else if (x.Firing)
                {
                    x.Deactivate();
                }
            }
        }
        else
        {
            foreach (var x in _weapons)
            {
                if (x.Firing)
                {
                    x.Deactivate();
                }
            }
            Entity.Target.Value = Entity.VisibleEnemies.FirstOrDefault(e => e is Ship);
        }
        return(true);
    }
    void Update()
    {
        if (SourceEntity == null)
        {
            return;
        }

        var t = transform;

        if (_active)
        {
            if (TargetPosition == null && !Target)
            {
                StartCoroutine(FadeOut());
                return;
            }
            var position = (float3)t.position;

            var targetPosition = TargetPosition?.Invoke() ?? Target.position;
            _targetVelocity         = lerp(_targetVelocity, targetPosition - _previousTargetPosition, saturate(Time.deltaTime * 5));
            _previousTargetPosition = targetPosition;
            targetPosition          = AetheriaMath.FirstOrderIntercept(position, float3.zero, TopSpeed, targetPosition, _targetVelocity);

            var diff       = targetPosition - transform.position;
            var targetDist = diff.magnitude;
            var sourceDist = length(StartPosition.xz - position.xz);

            if (sourceDist > Range || dot(diff, Velocity) < 0)
            {
                StartCoroutine(FadeOut());
                if (HitEffect != null)
                {
                    var ht = HitEffect.Instantiate <Transform>();
                    ht.position = t.position;
                }
                return;
            }
            _prevDist = targetDist;

            var targetDistFlat = diff.Flatland().magnitude;
            var curveLerp      = 1 - targetDistFlat / (sourceDist + targetDistFlat);
            var dir            = diff.normalized;
            var right          = cross(dir, float3(0, 1, 0));
            var up             = cross(dir, right);

            if (Children > 0 && SplitTime < curveLerp)
            {
                for (int i = 0; i < Children; i++)
                {
                    var child = ChildProjectile.Instantiate <GuidedProjectile>();
                    child.transform.position = t.position;
                    child.StartPosition      = StartPosition;
                    var randomDirection     = normalize(Random.insideUnitCircle);
                    var perpendicularRandom = randomDirection.x * right + randomDirection.y * up;
                    child.Velocity      = normalize(lerp(perpendicularRandom, dir, SplitSeparationForwardness)) * length(Velocity) * SplitSeparationVelocity;
                    child.Range         = Range;
                    child.Damage        = Damage / Children;
                    child.Penetration   = Penetration;
                    child.Spread        = Spread;
                    child.DamageType    = DamageType;
                    child.Source        = Source;
                    child.Target        = Target;
                    child.SourceEntity  = SourceEntity;
                    child.GuidanceCurve = GuidanceCurve;
                    child.LiftCurve     = LiftCurve;
                    child.ThrustCurve   = ThrustCurve;
                    child.Thrust        = Thrust;
                    child.TopSpeed      = TopSpeed;
                    child.Frequency     = Frequency;
                    child.Thrust        = Thrust;
                }
                StartCoroutine(Kill());
                if (HitEffect != null)
                {
                    var ht = HitEffect.Instantiate <Transform>();
                    ht.position = t.position;
                }
            }

            var dodge = normalize(lerp(
                                      normalize(right * noise(Time.time * Frequency + _phase) + up * noise(Time.time * Frequency + (100 + _phase))),
                                      Vector3.up, LiftCurve.Evaluate(curveLerp)));
            var desired     = Vector3.Slerp(dodge, dir, GuidanceCurve.Evaluate(curveLerp)).normalized *TopSpeed;
            var thrustCurve = ThrustCurve.Evaluate(curveLerp);
            var thrust      = Thrust * thrustCurve;
            var c           = Color.white * thrustCurve;
            c.a = 1;
            Particles.startColor = c;
            Velocity            += (desired - Velocity).normalized * (thrust * Time.deltaTime);
        }

        if (_alive)
        {
            var ray = new Ray(t.position, Velocity);
            foreach (var hit in Physics.RaycastAll(ray, Velocity.magnitude * Time.deltaTime, 1 | (1 << 17)))
            {
                var shield = hit.collider.GetComponent <ShieldManager>();
                if (shield)
                {
                    if (!(shield.Entity.Shield != null && shield.Entity.Shield.Item.Active.Value && shield.Entity.Shield.CanTakeHit(DamageType, Damage)))
                    {
                        continue;
                    }
                    if (shield.Entity != SourceEntity)
                    {
                        shield.Entity.Shield.TakeHit(DamageType, Damage);
                        shield.ShowHit(hit.point, sqrt(Damage));
                    }
                }
                var hull = hit.collider.GetComponent <HullCollider>();
                if (hull && !(hull.Entity.Shield != null && hull.Entity.Shield.Item.Active.Value && hull.Entity.Shield.CanTakeHit(DamageType, Damage)))
                {
                    if (hull.Entity != SourceEntity)
                    {
                        hull.SendHit(Damage, Penetration, Spread, DamageType, SourceEntity, hit.textureCoord, transform.forward);
                        transform.position = hit.point;
                        StartCoroutine(Kill());
                    }
                }
                else// if (hit.transform.gameObject.layer == 1)
                {
                    StartCoroutine(Kill());
                    return;
                }

                if (HitEffect != null)
                {
                    var ht = HitEffect.Instantiate <Transform>();
                    ht.SetParent(hit.collider.transform);
                    ht.position = hit.point;
                    return;
                }
            }

            t.position += Velocity * Time.deltaTime;
        }
    }