/// <summary>
        /// Check for bullet collision in the upcoming period.
        /// </summary>
        /// <param name="period">Period to consider, typically Time.fixedDeltaTime</param>
        /// <param name="reverse">Also perform raycast in reverse to detect collisions from rays starting within an object.</param>
        /// <returns>true if a collision is detected, false otherwise.</returns>
        public bool CheckBulletCollision(float period, bool reverse = false)
        {
            //reset our hit variables to default state
            hasPenetrated = true;
            hasDetonated  = false;
            hasRicocheted = false;
            penTicker     = 0;
            currPosition  = transform.position;

            float dist = currentVelocity.magnitude * period;

            bulletRay = new Ray(currPosition, currentVelocity + 0.5f * period * FlightGlobals.getGeeForceAtPosition(transform.position));
            var hitCount = Physics.RaycastNonAlloc(bulletRay, hits, dist, 9076737);

            if (hitCount == hits.Length) // If there's a whole bunch of stuff in the way (unlikely), then we need to increase the size of our hits buffer.
            {
                hits     = Physics.RaycastAll(bulletRay, dist, 9076737);
                hitCount = hits.Length;
            }
            int reverseHitCount = 0;

            if (reverse)
            {
                reverseHitCount = Physics.RaycastNonAlloc(new Ray(currPosition + currentVelocity * period, -currentVelocity), reverseHits, dist, 9076737);
                if (reverseHitCount == reverseHits.Length)
                {
                    reverseHits     = Physics.RaycastAll(new Ray(currPosition + currentVelocity * period, -currentVelocity), dist, 9076737);
                    reverseHitCount = reverseHits.Length;
                }
                for (int i = 0; i < reverseHitCount; ++i)
                {
                    reverseHits[i].distance = dist - reverseHits[i].distance;
                }
            }
            if (hitCount + reverseHitCount > 0)
            {
                var orderedHits = hits.Take(hitCount).Concat(reverseHits.Take(reverseHitCount)).OrderBy(x => x.distance);

                using (var hitsEnu = orderedHits.GetEnumerator())
                {
                    RaycastHit hit;
                    Part       hitPart;
                    KerbalEVA  hitEVA;

                    while (hitsEnu.MoveNext())
                    {
                        if (!hasPenetrated || hasRicocheted || hasDetonated)
                        {
                            return(true);
                        }

                        hit     = hitsEnu.Current;
                        hitPart = null;
                        hitEVA  = null;

                        try
                        {
                            hitPart = hit.collider.gameObject.GetComponentInParent <Part>();
                            hitEVA  = hit.collider.gameObject.GetComponentUpwards <KerbalEVA>();
                        }
                        catch (NullReferenceException e)
                        {
                            Debug.Log("[BDArmory.PooledBullet]:NullReferenceException for Ballistic Hit: " + e.Message);
                            return(true);
                        }

                        if (hitPart != null && ProjectileUtils.IsIgnoredPart(hitPart))
                        {
                            continue;                                                            // Ignore ignored parts.
                        }
                        if (hitEVA != null)
                        {
                            hitPart = hitEVA.part;
                            // relative velocity, separate from the below statement, because the hitpart might be assigned only above
                            if (hitPart.rb != null)
                            {
                                impactVelocity = (currentVelocity * dragVelocityFactor - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f())).magnitude;
                            }
                            else
                            {
                                impactVelocity = currentVelocity.magnitude * dragVelocityFactor;
                            }
                            distanceTraveled += hit.distance;
                            ProjectileUtils.ApplyDamage(hitPart, hit, 1, 1, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team);
                            ExplosiveDetonation(hitPart, hit, bulletRay);
                            KillBullet(); // Kerbals are too thick-headed for penetration...
                            return(true);
                        }

                        if (hitPart != null && hitPart.vessel == sourceVessel)
                        {
                            continue;                                                     //avoid autohit;
                        }
                        Vector3 impactVector = currentVelocity;
                        if (hitPart != null && hitPart.rb != null)
                        {
                            // using relative velocity vector instead of just bullet velocity
                            // since KSP vessels might move faster than bullets
                            impactVector = currentVelocity * dragVelocityFactor - (hitPart.rb.velocity + Krakensbane.GetFrameVelocityV3f());
                        }

                        float hitAngle = Vector3.Angle(impactVector, -hit.normal);

                        if (ProjectileUtils.CheckGroundHit(hitPart, hit, caliber))
                        {
                            ProjectileUtils.CheckBuildingHit(hit, bulletMass, currentVelocity, bulletDmgMult);
                            if (!RicochetScenery(hitAngle))
                            {
                                ExplosiveDetonation(hitPart, hit, bulletRay);
                                KillBullet();
                                distanceTraveled += hit.distance;
                                return(true);
                            }
                            else
                            {
                                DoRicochet(hitPart, hit, hitAngle, hit.distance / dist, period);
                                return(true);
                            }
                        }

                        //Standard Pipeline Hitpoints, Armor and Explosives
                        impactVelocity = impactVector.magnitude;
                        if (massMod != 0)
                        {
                            var ME = hitPart.FindModuleImplementing <ModuleMassAdjust>();
                            if (ME == null)
                            {
                                ME = (ModuleMassAdjust)hitPart.AddModule("ModuleMassAdjust");
                            }
                            ME.massMod  += massMod;
                            ME.duration += BDArmorySettings.WEAPON_FX_DURATION;
                        }
                        if (impulse != 0 && hitPart.rb != null)
                        {
                            hitPart.rb.AddForceAtPosition(impactVector.normalized * impulse, hit.point, ForceMode.Acceleration);
                            ProjectileUtils.ApplyScore(hitPart, sourceVessel, distanceTraveled, 0, bullet.name);
                            break; //impulse rounds shouldn't penetrate/do damage
                        }
                        float anglemultiplier = (float)Math.Cos(Math.PI * hitAngle / 180.0);

                        float thickness         = ProjectileUtils.CalculateThickness(hitPart, anglemultiplier);
                        float penetration       = ProjectileUtils.CalculatePenetration(caliber, bulletMass, impactVelocity, apBulletMod);
                        float penetrationFactor = ProjectileUtils.CalculateArmorPenetration(hitPart, anglemultiplier, hit, penetration, thickness, caliber);
                        if (penetration > thickness)
                        {
                            currentVelocity = currentVelocity * (float)Math.Sqrt(thickness / penetration);
                            if (penTicker > 0)
                            {
                                currentVelocity *= 0.55f;
                            }
                            flightTimeElapsed -= period;
                        }
                        if (penetrationFactor >= 2)
                        {
                            //its not going to bounce if it goes right through
                            hasRicocheted = false;
                        }
                        else
                        {
                            if (RicochetOnPart(hitPart, hit, hitAngle, impactVelocity, hit.distance / dist, period))
                            {
                                hasRicocheted = true;
                            }
                        }

                        if (penetrationFactor > 1 && !hasRicocheted) //fully penetrated continue ballistic damage
                        {
                            hasPenetrated = true;
                            ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team);
                            penTicker += 1;
                            ProjectileUtils.CheckPartForExplosion(hitPart);

                            //Explosive bullets that penetrate should explode shortly after
                            //if penetration is very great, they will have moved on
                            //checking velocity as they would not be able to come out the other side
                            //if (explosive && penetrationFactor < 3 || currentVelocity.magnitude <= 800f)
                            if (explosive)
                            {
                                //move bullet
                                transform.position += (currentVelocity * period) / 3;

                                distanceTraveled += hit.distance;
                                ExplosiveDetonation(hitPart, hit, bulletRay);
                                hasDetonated = true;
                                KillBullet();
                                return(true);
                            }
                        }
                        else if (!hasRicocheted) // explosive bullets that get stopped by armor will explode
                        {
                            if (hitPart.rb != null && hitPart.rb.mass > 0)
                            {
                                float forceAverageMagnitude = impactVelocity * impactVelocity *
                                                              (1f / hit.distance) * (bulletMass - tntMass);

                                float accelerationMagnitude =
                                    forceAverageMagnitude / (hitPart.vessel.GetTotalMass() * 1000);

                                hitPart.rb.AddForceAtPosition(impactVector.normalized * accelerationMagnitude, hit.point, ForceMode.Acceleration);

                                if (BDArmorySettings.DRAW_DEBUG_LABELS)
                                {
                                    Debug.Log("[BDArmory.PooledBullet]: Force Applied " + Math.Round(accelerationMagnitude, 2) + "| Vessel mass in kgs=" + hitPart.vessel.GetTotalMass() * 1000 + "| bullet effective mass =" + (bulletMass - tntMass));
                                }
                            }

                            distanceTraveled += hit.distance;
                            hasPenetrated     = false;
                            ProjectileUtils.ApplyDamage(hitPart, hit, 1, penetrationFactor, caliber, bulletMass, impactVelocity, bulletDmgMult, distanceTraveled, explosive, incendiary, hasRicocheted, sourceVessel, bullet.name, team);
                            ExplosiveDetonation(hitPart, hit, bulletRay);
                            hasDetonated = true;
                            KillBullet();
                            return(true);
                        }

                        /////////////////////////////////////////////////////////////////////////////////
                        // penetrated after a few ticks
                        /////////////////////////////////////////////////////////////////////////////////

                        //penetrating explosive
                        //richochets
                        if ((penTicker >= 2 && explosive) || (hasRicocheted && explosive))
                        {
                            //detonate
                            ExplosiveDetonation(hitPart, hit, bulletRay, airDetonation);
                            distanceTraveled += hit.distance;
                            return(true);
                        }

                        //bullet should not go any further if moving too slowly after hit
                        //smaller caliber rounds would be too deformed to do any further damage
                        if (currentVelocity.magnitude <= 100 && hasPenetrated)
                        {
                            if (BDArmorySettings.DRAW_DEBUG_LABELS)
                            {
                                Debug.Log("[BDArmory.PooledBullet]: Bullet Velocity too low, stopping");
                            }
                            KillBullet();
                            distanceTraveled += hit.distance;
                            return(true);
                        }
                    } //end While
                }     //end enumerator
            }         //end of hits
            return(false);
        }