public void Execute(Entity entity, int index, [ReadOnly] ref ArmHoldingTag tag, ref ArmComponent armComponent, [ReadOnly] ref Translation translation)
        {
            float  tmpDistance   = float.MaxValue;
            float  range         = 50.0f;
            float  maxThrowRange = range * range;
            Entity closestCan    = Entity.Null;

            armComponent.reachingTimer -= deltaTime / armComponent.reachDuration;

            if (armComponent.targetCan == Entity.Null)
            {
                // Find nearest target can to fire at.
                var targetEntities = EntitiesBucketedByIndex.GetValuesForKey(index);
                targetEntities.Reset();
                while (targetEntities.MoveNext())
                {
                    var         te        = targetEntities.Current;
                    Translation targetPos = translationsFromEntity[te];
                    float       distSq    = math.distancesq(translation.Value, targetPos.Value);
                    if ((distSq < maxThrowRange) && (distSq < tmpDistance))
                    {
                        tmpDistance = distSq;
                        closestCan  = te;
                    }
                }

                if (closestCan != Entity.Null)
                {
                    armComponent.targetCan = closestCan;
                }
            }

            if (armComponent.targetCan != Entity.Null)
            {
                ecb.AddComponent(index, armComponent.targetCan, new ReservedTag());
                ecb.RemoveComponent <ArmHoldingTag>(index, entity);
                ecb.AddComponent(index, entity, new ArmThrowingTag());
            }

            if (armComponent.heldRock != Entity.Null)
            {
                //Hand matrix is set in the animation system, here we tell the rock where we want it to reposition.
                RockHeldComponent heldComponent = rockHeldCompsFromEntity[armComponent.heldRock];
                heldComponent.rockInHandPosition =
                    armComponent.handMatrix.MultiplyPoint3x4(armComponent.heldRockOffset);
            }
        }
        public void Execute(Entity entity, int index, ref ArmComponent armComponent,
                            [ReadOnly] ref Translation translation, [ReadOnly] ref Rotation rotation)
        {
            float  armBoneLength   = armComponent.armBoneLength;
            float3 handUp          = armComponent.handUp;
            float  armBendStrength = armComponent.armBendStrength;

            Matrix4x4[] matrices = new Matrix4x4[17];

            DynamicBuffer <ArmChainsBuffer>    armChainsBuffer    = armChainsBufferLookup[entity];
            DynamicBuffer <FingerChainsBuffer> fingerChainsBuffer = fingerChainsBufferLookup[entity];
            DynamicBuffer <ThumbChainsBuffer>  thumbChainsBuffer  = thumbChainsBufferLookup[entity];

            ///////////////////////////
            // Resting position for hand
            float time = worldTime + armComponent.timeOffset;

            // solve the arm IK chain first
            float3 anchor = translation.Value;

            //float3 anchor = new float3();
            FABRIK.SolveViaBuffer(armChainsBuffer.Reinterpret <float3>(), armBoneLength, anchor, armComponent.handTarget, handUp * armBendStrength);

            Quaternion q = rotation.Value;
            float3     transformRight = math.normalize(math.mul(q, directions.right));

            // figure out our current "hand vectors" from our arm orientation
            float3 handForward = math.normalize(util.Last(armChainsBuffer.Reinterpret <float3>(), 0) - util.Last(armChainsBuffer.Reinterpret <float3>(), 1));

            handUp = math.normalize(math.cross(handForward, transformRight));
            float3 handRight = math.cross(handUp, handForward);

            // create handspace-to-worldspace matrix
            armComponent.handMatrix = Matrix4x4.TRS(util.Last(armChainsBuffer.Reinterpret <float3>(), 0), Quaternion.LookRotation(handForward, handUp), directions.one);

            // how much are our fingers gripping?
            // (during a reach, this is based on the reach timer)
            float fingerGrabT = armComponent.savedGrabT;

            if (armComponent.heldRock != Entity.Null)
            {
                //Translation heldRockTrans = translationsFromEntity[armComponent.heldRock];
                fingerGrabT = 1.0f; //When holding the rock, we're fully gripped.

                var held = new RockHeldComponent();
                held.rockInHandPosition = armComponent.handMatrix.MultiplyPoint3x4(armComponent.heldRockOffset);
                ecb.AddComponent(index, armComponent.heldRock, held);
                //   armComponent.lastIntendedRockPos =
            }

            // create rendering matrices for arm bones
            util.UpdateMatrices(matrices, armChainsBuffer.Reinterpret <float3>(), 0, armComponent.armBoneThickness, handUp);
            int matrixIndex = armChainsBuffer.Reinterpret <float3>().Length - 1;

            // next:  fingers
            float3 handPos = util.Last(armChainsBuffer.Reinterpret <float3>(), 0);
            // fingers spread out during a throw
            float openPalm = throwCurve.Evaluate(armComponent.throwTimer);

            //TODO add these to arm component?
            float fingerXOffset = -0.12f;
            float fingerSpacing = 0.08f;

            float[] fingerBoneLengths  = { 0.2f, 0.22f, 0.2f, 0.16f };
            float[] fingerThicknesses  = { 0.05f, 0.05f, 0.05f, 0.05f };
            float   fingerBendStrength = 0.2f;

            for (int i = 0; i < 4; i++)
            {
                float3 handRightTemp = handRight * (fingerXOffset + i * fingerSpacing);

                // find knuckle position for this finger
                float3 fingerPos = handPos + handRightTemp;

                // find resting position for this fingertip
                float3 fingerTarget = fingerPos + handForward * (.5f - .1f * fingerGrabT);

                // spooky finger wiggling while we're idle
                fingerTarget += handUp * Mathf.Sin((time + i * .2f) * 3f) * .2f * (1f - fingerGrabT);

                // if we're gripping, move this fingertip onto the surface of our rock
                float3 rockFingerDelta = fingerTarget - armComponent.lastIntendedRockPos;
                float3 rockFingerPos   = armComponent.lastIntendedRockPos + math.normalize(rockFingerDelta) * (armComponent.lastIntendedRockSize * .5f + fingerThicknesses[i]);
                fingerTarget = math.lerp(fingerTarget, rockFingerPos, fingerGrabT);

                // apply finger-spreading during throw animation
                fingerTarget += (handUp * .3f + handForward * .1f + handRight * (i - 1.5f) * .1f) * openPalm;

                // solve this finger's IK chain
                // FABRIK.Solve(fingerChains[i],fingerBoneLengths[i],fingerPos,fingerTarget,handUp*fingerBendStrength);
                int startIdx = i * 4;
                int stopIdx  = startIdx + 4;
                FABRIK.SolveViaBufferSliced(fingerChainsBuffer.Reinterpret <float3>(), fingerBoneLengths[i], fingerPos, fingerTarget, handUp * fingerBendStrength, startIdx, stopIdx);

                // update this finger's rendering matrices
                util.UpdateMatricesSliced(matrices, fingerChainsBuffer.Reinterpret <float3>(), matrixIndex, fingerThicknesses[i], handUp, startIdx, stopIdx);
                matrixIndex += 4 - 1;
            }

            // the thumb is pretty much the same as the fingers
            // (but pointing in a strange direction)
            float thumbXOffset      = -0.05f;
            float thumbThickness    = 0.06f;
            float thumbBendStrength = 0.1f;
            float thumbBoneLength   = 0.13f;

            float3 thumbPos    = handPos + handRight * thumbXOffset;
            float3 thumbTarget = thumbPos - handRight * .15f + handForward * (.2f + .1f * fingerGrabT) - handUp * .1f;

            thumbTarget += handRight * Mathf.Sin(time * 3f + .5f) * .1f * (1f - fingerGrabT);
            // thumb bends away from the palm, instead of "upward" like the fingers
            float3 thumbBendHint = (-handRight - handForward * .5f);

            float3 rockThumbDelta = thumbTarget - armComponent.lastIntendedRockPos;
            float3 rockThumbPos   = armComponent.lastIntendedRockPos + math.normalize(rockThumbDelta) * (armComponent.lastIntendedRockSize * .5f);

            thumbTarget = math.lerp(thumbTarget, rockThumbPos, fingerGrabT);

            FABRIK.SolveViaBuffer(thumbChainsBuffer.Reinterpret <float3>(), thumbBoneLength, thumbPos, thumbTarget, thumbBendHint * thumbBendStrength);
            util.UpdateMatrices(matrices, thumbChainsBuffer.Reinterpret <float3>(), matrixIndex, thumbThickness, thumbBendHint);

            DynamicBuffer <ArmMatrixBuffer> buffer = matrixBufferLookup[entity];

            buffer.Clear();
            for (int i = 0; i < matrices.Length; i++)
            {
                buffer.Add(new ArmMatrixBuffer()
                {
                    Value = matrices[i]
                });
            }
        }