ARConfiguration: Added support for update delay, and made the setter for PrettyLines public.
ARConfiguration: Added support for update delay, and made the setter for PrettyLines public.

--- a/ARConfiguration.cs
+++ b/ARConfiguration.cs
@@ -16,6 +16,14 @@
 	[KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
 	public class ARConfiguration : MonoBehaviour
 	{
+		private const string WINDOW_POS_KEY = "configWindowPos";
+		private const string REQUIRE_LOS_KEY = "requireLineOfSight";
+		private const string GRACE_RATIO_KEY = "graceRatio";
+		private const string REQUIRE_PROBE_CONNECTION_KEY = "requireConnectionForControl";
+		private const string FIXED_POWER_KEY = "fixedPowerCost";
+		private const string PRETTY_LINES_KEY = "drawPrettyLines";
+		private const string UPDATE_DELAY_KEY = "updateDelay";
+
 		/// <summary>
 		/// Indicates whether connections require line of sight.
 		/// </summary>
@@ -59,6 +67,12 @@
 		public static bool PrettyLines
 		{
 			get;
+			set;
+		}
+
+		public static long UpdateDelay
+		{
+			get;
 			private set;
 		}
 
@@ -66,6 +80,9 @@
 
 		private bool showConfigWindow;
 		private Rect configWindowPos;
+
+		private string updateDelayStr;
+		private long updateDelay;
 
 		private IButton toolbarButton;
 		private ApplicationLauncherButton appLauncherButton;
@@ -96,19 +113,23 @@
 			this.configWindowPos = new Rect(Screen.width / 4, Screen.height / 2, 180, 15);
 
 
-			this.configWindowPos = this.LoadConfigValue("configWindowPos", this.configWindowPos);
-
-			ARConfiguration.RequireLineOfSight = this.LoadConfigValue("requireLineOfSight", false);
-
-			ARConfiguration.RadiusRatio = (1 - this.LoadConfigValue("graceRatio", .05d));
+			this.configWindowPos = this.LoadConfigValue(WINDOW_POS_KEY, this.configWindowPos);
+
+			ARConfiguration.RequireLineOfSight = this.LoadConfigValue(REQUIRE_LOS_KEY, false);
+
+			ARConfiguration.RadiusRatio = (1 - this.LoadConfigValue(GRACE_RATIO_KEY, .05d));
 			ARConfiguration.RadiusRatio *= ARConfiguration.RadiusRatio;
 
 			ARConfiguration.RequireConnectionForControl =
-				this.LoadConfigValue("requireConnectionForControl", false);
-
-			ARConfiguration.FixedPowerCost = this.LoadConfigValue("fixedPowerCost", false);
-
-			ARConfiguration.PrettyLines = this.LoadConfigValue("drawPrettyLines", true);
+				this.LoadConfigValue(REQUIRE_PROBE_CONNECTION_KEY, false);
+
+			ARConfiguration.FixedPowerCost = this.LoadConfigValue(FIXED_POWER_KEY, false);
+
+			ARConfiguration.PrettyLines = this.LoadConfigValue(PRETTY_LINES_KEY, true);
+
+			ARConfiguration.UpdateDelay = this.LoadConfigValue(UPDATE_DELAY_KEY, 16L);
+
+			this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
 
 			GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
 
@@ -167,7 +188,7 @@
 				if (configPos != this.configWindowPos)
 				{
 					this.configWindowPos = configPos;
-					this.SaveConfigValue("configWindowPos", this.configWindowPos);
+					this.SaveConfigValue(WINDOW_POS_KEY, this.configWindowPos);
 				}
 			}
 		}
@@ -182,7 +203,7 @@
 			if (requireLineOfSight != ARConfiguration.RequireLineOfSight)
 			{
 				ARConfiguration.RequireLineOfSight = requireLineOfSight;
-				this.SaveConfigValue("requireLineOfSight", requireLineOfSight);
+				this.SaveConfigValue(REQUIRE_LOS_KEY, requireLineOfSight);
 			}
 
 			GUILayout.EndHorizontal();
@@ -197,7 +218,7 @@
 			if (requireConnectionForControl != ARConfiguration.RequireConnectionForControl)
 			{
 				ARConfiguration.RequireConnectionForControl = requireConnectionForControl;
-				this.SaveConfigValue("requireConnectionForControl", requireConnectionForControl);
+				this.SaveConfigValue(REQUIRE_PROBE_CONNECTION_KEY, requireConnectionForControl);
 			}
 
 			GUILayout.EndHorizontal();
@@ -208,7 +229,7 @@
 			if (fixedPowerCost != ARConfiguration.FixedPowerCost)
 			{
 				ARConfiguration.FixedPowerCost = fixedPowerCost;
-				this.SaveConfigValue("fixedPowerCost", fixedPowerCost);
+				this.SaveConfigValue(FIXED_POWER_KEY, fixedPowerCost);
 			}
 
 			GUILayout.EndHorizontal();
@@ -219,10 +240,26 @@
 			if (prettyLines != ARConfiguration.PrettyLines)
 			{
 				ARConfiguration.PrettyLines = prettyLines;
-				this.SaveConfigValue("drawPrettyLines", prettyLines);
-			}
-
-			GUILayout.EndHorizontal();
+				this.SaveConfigValue(PRETTY_LINES_KEY, prettyLines);
+			}
+
+			GUILayout.EndHorizontal();
+
+			GUILayout.BeginHorizontal();
+
+			GUILayout.Label("Update Delay", GUILayout.ExpandWidth(false));
+
+			this.updateDelayStr = GUILayout.TextField(this.updateDelayStr, 4, GUILayout.Width(40f));
+
+			GUILayout.Label("ms", GUILayout.ExpandWidth(false));
+
+			GUILayout.EndHorizontal();
+
+			if (this.updateDelayStr.Length > 1 && long.TryParse(this.updateDelayStr, out this.updateDelay))
+			{
+				ARConfiguration.UpdateDelay = Math.Min(Math.Max(this.updateDelay, 16), 2500);
+				this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
+			}
 
 			if (requireLineOfSight)
 			{
@@ -243,7 +280,7 @@
 				if (newRatio != graceRatio)
 				{
 					ARConfiguration.RadiusRatio = (1d - newRatio) * (1d - newRatio);
-					this.SaveConfigValue("graceRatio", newRatio);
+					this.SaveConfigValue(GRACE_RATIO_KEY, newRatio);
 				}
 
 				GUILayout.EndHorizontal();
@@ -281,6 +318,7 @@
 		private void toggleConfigWindow()
 		{
 			this.showConfigWindow = !this.showConfigWindow;
+			this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
 		}
 
 		private T LoadConfigValue<T>(string key, T defaultValue)

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -331,8 +331,11 @@
 					needle = potentialBestRelay;
 					bool isCircular = false;
 
+					int iterCount = 0;
 					while (needle != null)
 					{
+						iterCount++;
+
 						if (needle.KerbinDirect)
 						{
 							break;
@@ -345,6 +348,29 @@
 
 						if (needle.targetRelay.vessel == this.vessel || needle == this.moduleRef)
 						{
+							isCircular = true;
+							break;
+						}
+
+						// Avoid infinite loops when we're not catching things right.
+						if (iterCount > FlightGlobals.Vessels.Count)
+						{
+							Tools.PostErrorMessage(
+								"[{0}] iterCount exceeded while checking for circular network; assuming it is circular" +
+								"\n\tneedle={1}" +
+								"\n\tthis.moduleRef={2}",
+								this,
+								needle == null ? "null" : string.Format(
+									"{0}, needle.KerbinDirect={1}, needle.targetRelay={2}",
+									needle, needle.KerbinDirect, needle.targetRelay == null ? "null" : string.Format(
+										"{0}\n\tneedle.targetRelay.vessel={1}",
+										needle.targetRelay,
+										needle.targetRelay.vessel == null ?
+											"null" : needle.targetRelay.vessel.vesselName
+									)
+								),
+								this.moduleRef == null ? "null" : this.moduleRef.ToString()
+							);
 							isCircular = true;
 							break;
 						}
@@ -389,7 +415,10 @@
 			);
 
 			// If we don't have LOS to Kerbin, focus on relays
-			if (!this.vessel.hasLineOfSightTo(Kerbin, out bodyOccludingKerbin, ARConfiguration.RadiusRatio))
+			if (
+				ARConfiguration.RequireLineOfSight &&
+				!this.vessel.hasLineOfSightTo(Kerbin, out bodyOccludingKerbin, ARConfiguration.RadiusRatio)
+			)
 			{
 				log.AppendFormat("\n\tKerbin LOS is blocked by {0}.", bodyOccludingKerbin.bodyName);
 

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -149,6 +149,14 @@
 				{
 					return this.part.vessel;
 				}
+				else if (
+					this.part.protoPartSnapshot != null &&
+					this.part.protoPartSnapshot.pVesselRef != null &&
+					this.part.protoPartSnapshot.pVesselRef.vesselRef != null
+				)
+				{
+					return this.part.protoPartSnapshot.pVesselRef.vesselRef;
+				}
 				else
 				{
 					this.LogError("Vessel and/or part reference are null, returning null vessel.");

--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -39,7 +39,7 @@
 // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("1.8.*")]
+[assembly: AssemblyVersion("1.9.*")]
 // The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
 //[assembly: AssemblyDelaySign(false)]