AntennaRelay: Made the debug logging during FindNearestRelay more consistent.
AntennaRelay: Made the debug logging during FindNearestRelay more consistent.

--- a/ARConfiguration.cs
+++ b/ARConfiguration.cs
@@ -10,38 +10,59 @@
 
 namespace AntennaRange
 {
+	/// <summary>
+	/// A <see cref="UnityEngine.MonoBehaviour"/> responsible for managing configuration items for AntennaRange.
+	/// </summary>
 	[KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
 	public class ARConfiguration : MonoBehaviour
 	{
+		/// <summary>
+		/// Indicates whether connections require line of sight.
+		/// </summary>
 		public static bool RequireLineOfSight
 		{
 			get;
 			private set;
 		}
 
+		/// <summary>
+		/// A "fudge factor" ratio that pretends planets and moons are slightly smaller than reality to make
+		/// building communication constellations easier.
+		/// </summary>
 		public static double RadiusRatio
 		{
 			get;
 			private set;
 		}
 
+		/// <summary>
+		/// Indicates whether unmanned vessels require a connection for control.
+		/// </summary>
 		public static bool RequireConnectionForControl
 		{
 			get;
 			private set;
 		}
 
+		/// <summary>
+		/// If true, relays will fix their power cost when above nominal range, decreasing data rate instead.
+		/// </summary>
 		public static bool FixedPowerCost
 		{
 			get;
 			private set;
 		}
 
+		/// <summary>
+		/// Indicates whether this AntennaRange will draw pretty lines in map view.
+		/// </summary>
 		public static bool PrettyLines
 		{
 			get;
 			private set;
 		}
+
+#pragma warning disable 1591
 
 		private bool showConfigWindow;
 		private Rect configWindowPos;

--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -25,6 +25,8 @@
 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma warning disable 1591
 
 using KSP;
 using System;

--- a/ARMapRenderer.cs
+++ b/ARMapRenderer.cs
@@ -26,6 +26,8 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#pragma warning disable 1591
+
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -38,6 +40,13 @@
 	{
 		#region Fields
 		private Dictionary<Guid, LineRenderer> vesselLineRenderers;
+		private Dictionary<Guid, bool> vesselFrameCache;
+
+		#pragma warning disable 414
+		private bool dumpBool;
+		private Color lastColor;
+		private Color thisColor;
+		#pragma warning restore 414
 		#endregion
 
 		#region Properties
@@ -50,21 +59,27 @@
 					this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>();
 				}
 
-				if (!this.vesselLineRenderers.ContainsKey(idx))
+				LineRenderer lr;
+
+				if (this.vesselLineRenderers.TryGetValue(idx, out lr))
+				{
+					return lr;
+				}
+				else
 				{
 					GameObject obj = new GameObject();
 					obj.layer = 31;
 
-					LineRenderer lr = obj.AddComponent<LineRenderer>();
-
-					lr.SetColors(Color.green, Color.green);
+					lr = obj.AddComponent<LineRenderer>();
+
+					// lr.SetColors(Color.green, Color.green);
 					lr.material = MapView.OrbitLinesMaterial;
-					lr.SetVertexCount(2);
+					// lr.SetVertexCount(2);
 
 					this.vesselLineRenderers[idx] = lr;
-				}
-
-				return this.vesselLineRenderers[idx];
+
+					return lr;
+				}
 			}
 		}
 		#endregion
@@ -75,6 +90,7 @@
 			if (ARConfiguration.PrettyLines)
 			{
 				this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>();
+				this.vesselFrameCache = new Dictionary<Guid, bool>();
 			}
 		}
 
@@ -101,6 +117,8 @@
 					MapView.MapCamera.Distance
 				);
 
+				this.vesselFrameCache.Clear();
+
 				log.AppendLine("vesselFrameCache cleared.");
 
 				if (FlightGlobals.ready && FlightGlobals.Vessels != null)
@@ -112,6 +130,12 @@
 						if (vessel == null)
 						{
 							log.AppendFormat("Skipping vessel {0} altogether because it is null.\n");
+							continue;
+						}
+
+						if (this.vesselFrameCache.TryGetValue(vessel.id, out dumpBool))
+						{
+							log.AppendFormat("Skipping vessel {0} because it's already been processed this frame.");
 							continue;
 						}
 
@@ -157,76 +181,95 @@
 		}
 		#endregion
 
+		#region Utility
 		private void SetRelayVertices(IAntennaRelay relay)
 		{
-			if (relay == null)
-			{
-				return;
-			}
+			lastColor = default(Color);
 
 			LineRenderer renderer = this[relay.vessel.id];
-
-			Vector3d start;
-			Vector3d end;
-
-			renderer.enabled = true;
-
-			if (!relay.CanTransmit())
-			{
-				renderer.SetColors(Color.red, Color.red);
+			Vector3d start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
+
+			float lineWidth;
+			float d = Screen.height / 2f + 0.01f;
+
+			if (MapView.Draw3DLines)
+			{
+				lineWidth = 0.005859375f * MapView.MapCamera.Distance;
 			}
 			else
 			{
-				if (relay.transmitDistance < relay.nominalTransmitDistance)
-				{
-					renderer.SetColors(Color.green, Color.green);
+				lineWidth = 2f;
+
+				start = MapView.MapCamera.camera.WorldToScreenPoint(start);
+
+				start.z = start.z >= 0f ? d : -d;
+			}
+
+			renderer.SetWidth(lineWidth, lineWidth);
+
+			renderer.SetPosition(0, start);
+
+			int idx = 0;
+
+			while (relay != null)
+			{
+				Vector3d nextPoint;
+
+				renderer.enabled = true;
+
+				if (!relay.CanTransmit())
+				{
+					thisColor = Color.red;
 				}
 				else
 				{
-					renderer.SetColors(Color.yellow, Color.yellow);
-				}
-			}
-
-			start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
-
-			if (relay.KerbinDirect)
-			{
-				end = ScaledSpace.LocalToScaledSpace(AntennaRelay.Kerbin.position);
-			}
-			else
-			{
-				if (relay.targetRelay == null)
-				{
-					return;
-				}
-				end = ScaledSpace.LocalToScaledSpace(relay.targetRelay.vessel.GetWorldPos3D());
-			}
-
-			float lineWidth;
-
-			if (MapView.Draw3DLines)
-			{
-				lineWidth = 0.005859375f * MapView.MapCamera.Distance;
-			}
-			else
-			{
-				lineWidth = 2f;
-
-				start = MapView.MapCamera.camera.WorldToScreenPoint(start);
-				end = MapView.MapCamera.camera.WorldToScreenPoint(end);
-
-				float d = Screen.height / 2f + 0.01f;
-				start.z = start.z >= 0f ? d : -d;
-				end.z = end.z >= 0f ? d : -d;
-			}
-
-			renderer.SetWidth(lineWidth, lineWidth);
-
-			renderer.SetPosition(0, start);
-			renderer.SetPosition(1, end);
-		}
-
-		public void Cleanup()
+					if (relay.transmitDistance < relay.nominalTransmitDistance)
+					{
+						thisColor = Color.green;
+					}
+					else
+					{
+						thisColor = Color.yellow;
+					}
+				}
+
+				if (lastColor != default(Color) && thisColor != lastColor)
+				{
+					break;
+				}
+
+				lastColor = thisColor;
+				renderer.SetColors(thisColor, thisColor);
+
+				this.vesselFrameCache[relay.vessel.id] = true;
+
+				if (relay.KerbinDirect)
+				{
+					nextPoint = ScaledSpace.LocalToScaledSpace(AntennaRelay.Kerbin.position);
+					relay = null;
+				}
+				else
+				{
+					if (relay.targetRelay == null)
+					{
+						return;
+					}
+
+					nextPoint = ScaledSpace.LocalToScaledSpace(relay.targetRelay.vessel.GetWorldPos3D());
+					relay = relay.targetRelay;
+				}
+
+				if (!MapView.Draw3DLines)
+				{
+					nextPoint = MapView.MapCamera.camera.WorldToScreenPoint(nextPoint);
+					nextPoint.z = nextPoint.z >= 0f ? d : -d;
+				}
+
+				renderer.SetPosition(++idx, nextPoint);
+			}
+		}
+
+		private void Cleanup()
 		{
 			if (this.vesselLineRenderers != null && this.vesselLineRenderers.Count > 0)
 			{
@@ -237,8 +280,13 @@
 				}
 				this.vesselLineRenderers.Clear();
 			}
-		}
+
+			if (this.vesselFrameCache != null && this.vesselFrameCache.Count > 0)
+			{
+				this.vesselFrameCache.Clear();
+			}
+		}
+		#endregion
 	}
 }
 
-

--- a/AntennaRange.csproj
+++ b/AntennaRange.csproj
@@ -40,6 +40,7 @@
         <Command type="AfterBuild" command="xcopy /y ${TargetFile} ${ProjectDir}\GameData\AntennaRange\" />
       </CustomCommands>
     </CustomCommands>
+    <DocumentationFile>bin\Release\AntennaRange.xml</DocumentationFile>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -38,6 +38,9 @@
 	/// </summary>
 	public class AntennaRelay
 	{
+		private static readonly System.Diagnostics.Stopwatch searchTimer = new System.Diagnostics.Stopwatch();
+		private const long millisecondsBetweenSearches = 125L;
+
 		// We don't have a Bard, so we'll hide Kerbin here.
 		private static CelestialBody _Kerbin;
 
@@ -57,14 +60,13 @@
 			}
 		}
 
+		private long lastSearch;
+
 		private bool canTransmit;
 
 		private IAntennaRelay nearestRelay;
 		private IAntennaRelay bestOccludedRelay;
 
-		private System.Diagnostics.Stopwatch searchTimer;
-		private long millisecondsBetweenSearches;
-
 		/// <summary>
 		/// The <see cref="AntennaRange.ModuleLimitedDataTransmitter"/> reference underlying this AntennaRelay, as an
 		/// <see cref="AntennaRange.IAntennaRelay"/>
@@ -167,14 +169,20 @@
 		/// <returns>The nearest relay or null, if no relays in range.</returns>
 		private void FindNearestRelay()
 		{
-			if (!this.searchTimer.IsRunning || this.searchTimer.ElapsedMilliseconds > this.millisecondsBetweenSearches)
-			{
-				this.searchTimer.Reset();
-			}
-			else
+			if (!searchTimer.IsRunning)
+			{
+				searchTimer.Start();
+			}
+
+			long searchTime = searchTimer.ElapsedMilliseconds;
+			long timeSinceLast = searchTime - this.lastSearch;
+
+			if (timeSinceLast < Math.Max(millisecondsBetweenSearches, UnityEngine.Time.smoothDeltaTime))
 			{
 				return;
 			}
+
+			this.lastSearch = searchTime;
 
 			// Skip vessels that have already been checked for a nearest relay this pass.
 			if (RelayDatabase.Instance.CheckedVesselsTable.ContainsKey(this.vessel.id))
@@ -182,15 +190,14 @@
 				return;
 			}
 
-			if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-			{
-				Tools.PostDebugMessage(string.Format(
-					"{0}: finding nearest relay for {1}",
-					this.GetType().Name,
-					this.ToString()
-				));
-			}
-
+			Tools.DebugLogger log;
+			#if DEBUG
+			log = Tools.DebugLogger.New(this);
+			#endif
+
+			log.AppendFormat("{0}: Target search started at {1} ms ({2} ms since last search).",
+				this.ToString(), searchTime, timeSinceLast);
+			
 			// Set this vessel as checked, so that we don't check it again.
 			RelayDatabase.Instance.CheckedVesselsTable[vessel.id] = true;
 
@@ -246,58 +253,43 @@
 				{
 					this.firstOccludingBody = fob;
 
-					if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-					{
-						Tools.PostDebugMessage("{6}: Vessel {0} discarded because we do not have line of sight." +
-							"\npotentialSqrDistance: {1}, bestOccludedSqrDistance: {2}, maxTransmitSqrDistance: {3}" +
-							"\npotentialSqrDistance < bestOccludedSqrDistance: {4}" +
-							"\npotentialSqrDistance < (this.maxTransmitDistance * this.maxTransmitDistance): {5}",
-							potentialVessel.vesselName,
-							potentialSqrDistance, bestOccludedSqrDistance, this.maxTransmitDistance * this.maxTransmitDistance,
-							potentialSqrDistance < bestOccludedSqrDistance,
-							potentialSqrDistance < (this.maxTransmitDistance * this.maxTransmitDistance),
-							this.ToString()
-						);
-					}
+					log.AppendFormat("\n\t{0}: Vessel {1} not in line of sight.",
+						this.ToString(), potentialVessel.vesselName);
 
 					if (
 						(potentialSqrDistance < bestOccludedSqrDistance) &&
 						(potentialSqrDistance < maxTransmitSqrDistance)
 					)
 					{
-						if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-						{
-							Tools.PostDebugMessage("{0}: Checking {1} relays on {2}.",
-								this.ToString(),
-								potentialVessel.GetAntennaRelays().Count(),
-								potentialVessel
+						
+						log.AppendFormat("\n\t\t{0}: Checking {1} relays on occluded vessel {2}.",
+							this.ToString(),
+							potentialVessel.GetAntennaRelays().Count(),
+							potentialVessel
+						);
+
+						foreach (IAntennaRelay occludedRelay in potentialVessel.GetAntennaRelays())
+						{
+							
+							log.AppendFormat(
+								"\n\t\t{0}: Checking candidate for bestOccludedRelay: {1}" +
+								"\n\t\tCanTransmit: {2}",
+								this.ToString(), occludedRelay, occludedRelay.CanTransmit()
 							);
-						}
-
-						foreach (IAntennaRelay occludedRelay in potentialVessel.GetAntennaRelays())
-						{
-							if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-							{
-								Tools.PostDebugMessage(this.ToString() +  " Checking candidate for bestOccludedRelay: {0}" +
-									"\n\tCanTransmit: {1}", occludedRelay, occludedRelay.CanTransmit());
-							}
-
+							
 							if (occludedRelay.CanTransmit())
 							{
 								this.bestOccludedRelay = occludedRelay;
 								bodyOccludingBestOccludedRelay = fob;
 								bestOccludedSqrDistance = potentialSqrDistance;
 
-								if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-								{
-									Tools.PostDebugMessage(this.ToString() + " Found new bestOccludedRelay: {0}" +
-										"\nfirstOccludingBody: {1}" +
-										"\nbestOccludedSqrDistance: {2}",
-										occludedRelay,
-										fob,
-										potentialSqrDistance
-									);
-								}
+								log.AppendFormat("\n\t{0}: Found new bestOccludedRelay: {1}" +
+									" (blocked by {2}; distance: {3} m)",
+									this.ToString(),
+									occludedRelay.ToString(),
+									fob,
+									potentialSqrDistance
+								);
 								break;
 							}
 						}
@@ -311,31 +303,29 @@
 				 * */
 				if (potentialSqrDistance > nearestRelaySqrDistance)
 				{
-					if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
-					{
-						Tools.PostDebugMessage("{0}: Vessel {1} discarded because it is out of range, or farther than another relay.",
-							this.ToString(),
-							potentialVessel.vesselName
-						);
-					}
+					
+					log.AppendFormat("\n\t{0}: Vessel {1} discarded because it is farther than another the nearest relay.",
+						this.ToString(),
+						potentialVessel.vesselName
+					);
 					continue;
 				}
 
-				nearestRelaySqrDistance = potentialSqrDistance;
-
 				foreach (IAntennaRelay potentialRelay in potentialVessel.GetAntennaRelays())
 				{
 					if (potentialRelay.CanTransmit() && potentialRelay.targetRelay != this)
 					{
+						// @TODO: Moved this here from outside the loop; why was it there?
+						nearestRelaySqrDistance = potentialSqrDistance;
 						this.nearestRelay = potentialRelay;
 
 						if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.id == this.vessel.id)
 						{
-							Tools.PostDebugMessage(string.Format("{0}: found new best relay {1} ({2})",
+							log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m)",
 								this.ToString(),
 								this.nearestRelay.ToString(),
-								this.nearestRelay.vessel.id
-							));
+								Math.Sqrt(nearestRelaySqrDistance)
+							);
 						}
 						break;
 					}
@@ -347,9 +337,7 @@
 			double kerbinSqrDistance = this.vessel.DistanceTo(Kerbin) - Kerbin.Radius;
 			kerbinSqrDistance *= kerbinSqrDistance;
 
-			Tools.DebugLogger log = Tools.DebugLogger.New(this);
-
-			log.AppendFormat("{0} ({1}): Search done, figuring status.", this.ToString(), this.GetType().Name);
+			log.AppendFormat("\n{0} ({1}): Search done, figuring status.", this.ToString(), this.GetType().Name);
 
 			// If we don't have LOS to Kerbin, focus on relays
 			if (!this.vessel.hasLineOfSightTo(Kerbin, out bodyOccludingKerbin, ARConfiguration.RadiusRatio))
@@ -360,7 +348,7 @@
 				// Therefore, this will only be true if a valid relay is in range.
 				if (nearestRelaySqrDistance <= maxTransmitSqrDistance)
 				{
-					log.AppendFormat("\n\tCan transmit to nearby relay {0} ({1} <= {2}).",
+					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
 							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
@@ -371,81 +359,118 @@
 				// If this isn't true, we can't transmit, but pick a second best of bestOccludedRelay and Kerbin anyway
 				else
 				{
-					log.AppendFormat("\n\tCan't transmit to nearby relay {0} ({1} > {2}).",
+					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
 							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
 					this.canTransmit = false;
 
-					// If the best occluded relay is closer than Kerbin, target it.
+					// If the best occluded relay is closer than Kerbin, check it against the nearest relay.
+					// Since bestOccludedSqrDistance is infinity if there are no occluded relays, this is safe
 					if (bestOccludedSqrDistance < kerbinSqrDistance)
 					{
-						log.AppendFormat("\n\t\tPicking occluded relay {0} as target ({1} < {2}).",
-							this.bestOccludedRelay == null ? "null" : this.bestOccludedRelay.ToString(),
-							bestOccludedSqrDistance, kerbinSqrDistance);
-
+						log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
+							bestOccludedRelay, kerbinSqrDistance);
+						
 						this.KerbinDirect = false;
-						this.targetRelay = this.bestOccludedRelay;
-						this.firstOccludingBody = bodyOccludingBestOccludedRelay;
-					}
-					// Otherwise, target Kerbin and report the first body blocking it.
+
+						// If the nearest relay is closer than the best occluded relay, pick it.
+						// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
+						if (nearestRelaySqrDistance < bestOccludedSqrDistance)
+						{
+							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
+								nearestRelaySqrDistance, bestOccludedSqrDistance);
+							
+							this.targetRelay = nearestRelay;
+							this.firstOccludingBody = null;
+						}
+						// Otherwise, target the best occluded relay.
+						else
+						{
+							log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
+								nearestRelaySqrDistance, bestOccludedSqrDistance);
+							
+							this.targetRelay = bestOccludedRelay;
+							this.firstOccludingBody = bodyOccludingBestOccludedRelay;
+						}
+					}
+					// Otherwise, check Kerbin against the nearest relay.
+					// Since we have LOS, blank the first occluding body.
 					else
 					{
-						log.AppendFormat("\n\t\tPicking Kerbin as target ({0} >= {1}).",
-							bestOccludedSqrDistance, kerbinSqrDistance);
+						log.AppendFormat("\n\t\t\tKerbin is closer than the best occluded relay ({0} >= {1})",
+							bestOccludedRelay, kerbinSqrDistance);
+						
+						this.firstOccludingBody = null;
+
+						// If the nearest relay is closer than Kerbin, pick it.
+						// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
+						if (nearestRelaySqrDistance < kerbinSqrDistance)
+						{
+							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
+								nearestRelaySqrDistance, kerbinSqrDistance);
+							
+							this.KerbinDirect = false;
+							this.targetRelay = nearestRelay;
+						}
+						// Otherwise, pick Kerbin.
+						else
+						{
+							log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
+								nearestRelaySqrDistance, kerbinSqrDistance);
+							
+							this.KerbinDirect = true;
+							this.targetRelay = null;
+						}
+					}
+				}
+			}
+			// If we do have LOS to Kerbin, try to prefer the closest of nearestRelay and Kerbin
+			else
+			{
+				log.AppendFormat("\n\tKerbin is in LOS.");
+
+				// If the nearest relay is closer than Kerbin and in range, transmit to it.
+				if (nearestRelaySqrDistance <= maxTransmitSqrDistance)
+				{
+					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
+						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
+							nearestRelaySqrDistance, maxTransmitSqrDistance);
+
+					this.canTransmit = true;
+
+					// If the nearestRelay is closer than Kerbin, use it.
+					if (nearestRelaySqrDistance < kerbinSqrDistance)
+					{
+						log.AppendFormat("\n\t\t\tPicking relay {0} over Kerbin ({1} < {2}).",
+							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
+							nearestRelaySqrDistance, kerbinSqrDistance);
+
+						this.KerbinDirect = false;
+						this.targetRelay = this.nearestRelay;
+					}
+					// Otherwise, Kerbin is closer, so use it.
+					else
+					{
+						log.AppendFormat("\n\t\t\tBut picking Kerbin over nearby relay {0} ({1} >= {2}).",
+							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
+								nearestRelaySqrDistance, kerbinSqrDistance);
 
 						this.KerbinDirect = true;
 						this.targetRelay = null;
-						this.firstOccludingBody = bodyOccludingKerbin;
-					}
-				}
-			}
-			// If we do have LOS to Kerbin, try to prefer the closest of nearestRelay and Kerbin
-			else
-			{
-				log.AppendFormat("\n\tKerbin is in LOS.");
-
-				// If the nearest relay is closer than Kerbin and in range, transmit to it.
-				if (nearestRelaySqrDistance <= maxTransmitSqrDistance)
-				{
-					log.AppendFormat("\n\tCan transmit to nearby relay {0} ({1} <= {2}).",
+					}
+				}
+				// If the nearest relay is out of range, we still need to check on Kerbin.
+				else
+				{
+					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
 							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
-					this.canTransmit = true;
-
-					// If the nearestRelay is closer than Kerbin, use it.
-					if (nearestRelaySqrDistance < kerbinSqrDistance)
-					{
-						log.AppendFormat("\n\tPicking relay {0} over Kerbin ({1} < {2}).",
-							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrDistance, kerbinSqrDistance);
-
-						this.KerbinDirect = false;
-						this.targetRelay = this.nearestRelay;
-					}
-					// Otherwise, Kerbin is closer, so use it.
-					else
-					{
-						log.AppendFormat("\n\tBut picking Kerbin over nearby relay {0} ({1} >= {2}).",
-							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-								nearestRelaySqrDistance, kerbinSqrDistance);
-
-						this.KerbinDirect = true;
-						this.targetRelay = null;
-					}
-				}
-				// If the nearest relay is out of range, we still need to check on Kerbin.
-				else
-				{
-					log.AppendFormat("\n\tCan't transmit to nearby relay {0} ({1} > {2}).",
-						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrDistance, maxTransmitSqrDistance);
-
 					// If Kerbin is in range, use it.
 					if (kerbinSqrDistance <= maxTransmitSqrDistance)
 					{
-						log.AppendFormat("\n\tCan transmit to Kerbin ({0} <= {1}).",
+						log.AppendFormat("\n\t\t\tCan transmit to Kerbin ({0} <= {1}).",
 							kerbinSqrDistance, maxTransmitSqrDistance);
 
 						this.canTransmit = true;
@@ -456,41 +481,79 @@
 					// Kerbin and bestOccludedRelay
 					else
 					{
-						log.AppendFormat("\n\tCan't transmit to Kerbin ({0} > {1}).",
+						log.AppendFormat("\n\t\t\tCan't transmit to Kerbin ({0} > {1}).",
 							kerbinSqrDistance, maxTransmitSqrDistance);
 
 						this.canTransmit = false;
 
-						// If the best occluded relay is closer than Kerbin, use it.
-						// Since bestOccludedSqrDistance is infinity if there are no occluded relays,
-						// this is safe
+						// If the best occluded relay is closer than Kerbin, check it against the nearest relay.
+						// Since bestOccludedSqrDistance is infinity if there are no occluded relays, this is safe
 						if (bestOccludedSqrDistance < kerbinSqrDistance)
 						{
-							log.AppendFormat("\n\t\tPicking occluded relay {0} as target ({1} < {2}).",
-								this.bestOccludedRelay == null ? "null" : this.bestOccludedRelay.ToString(),
-									bestOccludedSqrDistance, kerbinSqrDistance);
-
+							log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
+								bestOccludedRelay, kerbinSqrDistance);
+							
 							this.KerbinDirect = false;
-							this.targetRelay = bestOccludedRelay;
-							this.firstOccludingBody = bodyOccludingBestOccludedRelay;
-						}
-						// Otherwise, target Kerbin.  Since we have LOS, blank the first occluding body.
+
+							// If the nearest relay is closer than the best occluded relay, pick it.
+							// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
+							if (nearestRelaySqrDistance < bestOccludedSqrDistance)
+							{
+								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
+									nearestRelaySqrDistance, bestOccludedSqrDistance);
+								
+								this.targetRelay = nearestRelay;
+								this.firstOccludingBody = null;
+							}
+							// Otherwise, target the best occluded relay.
+							else
+							{
+								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
+									nearestRelaySqrDistance, bestOccludedSqrDistance);
+								
+								this.targetRelay = bestOccludedRelay;
+								this.firstOccludingBody = bodyOccludingBestOccludedRelay;
+							}
+						}
+						// Otherwise, check Kerbin against the nearest relay.
+						// Since we have LOS, blank the first occluding body.
 						else
 						{
-							log.AppendFormat("\n\t\tPicking Kerbin as target ({0} >= {1}).",
-								bestOccludedSqrDistance, kerbinSqrDistance);
-
-							this.KerbinDirect = true;
-							this.targetRelay = null;
+							log.AppendFormat("\n\t\t\tKerbin is closer than the best occluded relay ({0} >= {1})",
+								bestOccludedRelay, kerbinSqrDistance);
+							
 							this.firstOccludingBody = null;
-						}
-					}
-				}
-			}
+
+							// If the nearest relay is closer than Kerbin, pick it.
+							// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
+							if (nearestRelaySqrDistance < kerbinSqrDistance)
+							{
+								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
+									nearestRelaySqrDistance, kerbinSqrDistance);
+								
+								this.KerbinDirect = false;
+								this.targetRelay = nearestRelay;
+							}
+							// Otherwise, pick Kerbin.
+							else
+							{
+								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
+									nearestRelaySqrDistance, kerbinSqrDistance);
+								
+								this.KerbinDirect = true;
+								this.targetRelay = null;
+							}
+						}
+					}
+				}
+			}
+
+			log.AppendFormat("{0}: Target search completed at {1} ms ({2} ms elapsed).",
+				this.ToString(), searchTimer.ElapsedMilliseconds, searchTimer.ElapsedMilliseconds - searchTime);;
 
 			log.AppendFormat("\n{0}: Status determination complete.", this.ToString());
 
-			log.Print();
+			log.Print(false);
 
 			// Now that we're done with our recursive CanTransmit checks, flag this relay as not checked so it can be
 			// used next time.
@@ -518,9 +581,6 @@
 		public AntennaRelay(IAntennaRelay module)
 		{
 			this.moduleRef = module;
-
-			this.searchTimer = new System.Diagnostics.Stopwatch();
-			this.millisecondsBetweenSearches = 125L;
 		}
 	}
 }

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -33,23 +33,36 @@
 
 namespace AntennaRange
 {
-	/*
-	 * Wrapper class for ProtoPartModuleSnapshot extending AntennaRelay and implementing IAntennaRelay.
-	 * This is used for finding relays in unloaded Vessels.
-	 * */
+	/// <summary>
+	/// Wrapper class for ProtoPartModuleSnapshot extending AntennaRelay and implementing IAntennaRelay.
+	/// This is used for finding relays in unloaded Vessels.
+	/// </summary>
 	public class ProtoAntennaRelay : AntennaRelay, IAntennaRelay
 	{
 		// Stores the prototype part so we can make sure we haven't exploded or so.
-		protected ProtoPartSnapshot protoPart;
+		private ProtoPartSnapshot protoPart;
 
+		/// <summary>
+		/// Gets the parent Vessel.
+		/// </summary>
 		public override Vessel vessel
 		{
 			get
 			{
-				return this.protoPart.pVesselRef.vesselRef;
+				if (this.protoPart != null && this.protoPart.pVesselRef != null)
+				{
+					return this.protoPart.pVesselRef.vesselRef;
+				}
+				else
+				{
+					return null;
+				}
 			}
 		}
 
+		/// <summary>
+		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
+		/// </summary>
 		public override double nominalTransmitDistance
 		{
 			get
@@ -59,9 +72,8 @@
 		}
 
 		/// <summary>
-		/// The maximum distance at which this transmitter can operate.
+		/// The maximum distance at which this relay can operate.
 		/// </summary>
-		/// <value>The max transmit distance.</value>
 		public override double maxTransmitDistance
 		{
 			get
@@ -87,6 +99,10 @@
 			}
 		}
 
+		/// <summary>
+		/// Determines whether this instance can transmit.
+		/// <c>true</c> if this instance can transmit; otherwise, <c>false</c>.
+		/// </summary>
 		public override bool CanTransmit()
 		{
 			PartStates partState = (PartStates)this.protoPart.state;
@@ -104,31 +120,33 @@
 			return base.CanTransmit();
 		}
 
+		/// <summary>
+		/// Returns a <see cref="System.String"/> that represents the current <see cref="AntennaRange.ProtoAntennaRelay"/>.
+		/// </summary>
+		/// <returns>A <see cref="System.String"/> that represents the current <see cref="AntennaRange.ProtoAntennaRelay"/>.</returns>
 		public override string ToString()
 		{
-			return string.Format(
-				"{0} on {1}",
-				this.Title,
-				this.protoPart.pVesselRef.vesselName
-			);
+			System.Text.StringBuilder sb = new System.Text.StringBuilder();
+
+			sb.Append(this.Title);
+
+			if (this.protoPart != null && this.protoPart.pVesselRef != null)
+			{
+				sb.AppendFormat(" on {0}", this.protoPart.pVesselRef.vesselName);
+			}
+
+			return sb.ToString();
 		}
 
 		/// <summary>
-		/// Initializes a new instance of the <see cref="AntennaRange.ProtoAntennaRelay"/> class.
+		/// Initializes a new instance of the <see cref="AntennaRange.AntennaRelay"/> class.
 		/// </summary>
-		/// <param name="ms">The ProtoPartModuleSnapshot to wrap</param>
-		/// <param name="vessel">The parent Vessel</param>
+		/// <param name="prefabRelay">The module reference underlying this AntennaRelay,
+		/// as an <see cref="AntennaRange.IAntennaRelay"/></param>
+		/// <param name="pps">The prototype partreference on which the module resides.</param>
 		public ProtoAntennaRelay(IAntennaRelay prefabRelay, ProtoPartSnapshot pps) : base(prefabRelay)
 		{
 			this.protoPart = pps;
-		}
-
-		~ProtoAntennaRelay()
-		{
-			Tools.PostDebugMessage(string.Format(
-				"{0}: destroyed",
-				this.ToString()
-			));
 		}
 	}
 }

--- a/RelayDatabase.cs
+++ b/RelayDatabase.cs
@@ -25,6 +25,8 @@
 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma warning disable 1591
 
 using KSP;
 using System;

--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -33,9 +33,9 @@
 
 namespace AntennaRange
 {
-	/*
-	 * A class of utility extensions for Vessels and Relays to help find a relay path back to Kerbin.
-	 * */
+	/// <summary>
+	/// A class of utility extensions for Vessels and Relays to help find a relay path back to Kerbin.
+	/// </summary>
 	public static class RelayExtensions
 	{
 		/// <summary>
@@ -68,16 +68,31 @@
 			return relayOne.DistanceTo(relayTwo.vessel);
 		}
 
+		/// <summary>
+		/// Returns the square of the distance between this IAntennaRelay and a Vessel
+		/// </summary>
+		/// <param name="relay">This <see cref="IAntennaRelay"/></param>
+		/// <param name="vessel">A <see cref="Vessel"/></param>
 		public static double sqrDistanceTo(this AntennaRelay relay, Vessel vessel)
 		{
 			return relay.vessel.sqrDistanceTo(vessel);
 		}
 
+		/// <summary>
+		/// Returns the square of the distance between this IAntennaRelay and a CelestialBody
+		/// </summary>
+		/// <param name="relay">This <see cref="IAntennaRelay"/></param>
+		/// <param name="body">A <see cref="CelestialBody"/></param>
 		public static double sqrDistanceTo(this AntennaRelay relay, CelestialBody body)
 		{
 			return relay.vessel.sqrDistanceTo(body);
 		}
 
+		/// <summary>
+		/// Returns the square of the distance between this IAntennaRelay and another IAntennaRelay
+		/// </summary>
+		/// <param name="relayOne">This <see cref="IAntennaRelay"/></param>
+		/// <param name="relayTwo">Another <see cref="IAntennaRelay"/></param>
 		public static double sqrDistanceTo(this AntennaRelay relayOne, IAntennaRelay relayTwo)
 		{
 			return relayOne.vessel.sqrDistanceTo(relayTwo.vessel);
@@ -110,6 +125,10 @@
 			return false;
 		}
 
+		/// <summary>
+		/// Gets the <see cref="AntennaRange.ConnectionStatus"/> for this <see cref="Vessel"/>
+		/// </summary>
+		/// <param name="vessel">This <see cref="Vessel"/></param>
 		public static ConnectionStatus GetConnectionStatus(this Vessel vessel)
 		{
 			bool canTransmit = false;
@@ -136,6 +155,10 @@
 			}
 		}
 
+		/// <summary>
+		/// Gets the best relay on this Vessel.  The best relay may not be able to transmit.
+		/// </summary>
+		/// <param name="vessel">This <see cref="Vessel"/></param>
 		public static IAntennaRelay GetBestRelay(this Vessel vessel)
 		{
 			IAntennaRelay bestRelay = null;
@@ -157,6 +180,10 @@
 		}
 	}
 
+	#pragma warning disable 1591
+	/// <summary>
+	/// An Enum describing the connection status of a vessel or relay.
+	/// </summary>
 	public enum ConnectionStatus
 	{
 		None,