ARFlightController: Fixed Update to run even if the icons are broken, and fixed the AppLauncher icon to exist in MapView.
ARFlightController: Fixed Update to run even if the icons are broken, and fixed the AppLauncher icon to exist in MapView.

--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -165,7 +165,7 @@
 			if (this.appLauncherButton == null && !ToolbarManager.ToolbarAvailable && ApplicationLauncher.Ready)
 			{
 				this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication(
-					ApplicationLauncher.AppScenes.FLIGHT,
+					ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW,
 					this.appLauncherTextures[ConnectionStatus.None]
 				);
 			}
@@ -235,35 +235,63 @@
 
 			this.log.Clear();
 
-			if (
-				(this.toolbarButton != null || this.appLauncherButton != null) &&
-				HighLogic.LoadedSceneIsFlight &&
-				FlightGlobals.ActiveVessel != null
-			)
-			{
-				log.Append("Checking vessel relay status.\n");
-
-				this.currentConnectionStatus = FlightGlobals.ActiveVessel.GetConnectionStatus();
-
-				log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
-					this.currentConnectionStatus, this.currentConnectionTexture);
-
-				if (this.toolbarButton != null)
-				{
-					this.toolbarButton.TexturePath = this.currentConnectionTexture;
-
-					if (this.currentConnectionStatus == ConnectionStatus.None)
+			if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null)
+			{
+				Vessel vessel;
+				IAntennaRelay relay;
+				IList<IAntennaRelay> activeVesselRelays;
+
+				for (int vIdx = 0; vIdx < FlightGlobals.Vessels.Count; vIdx++)
+				{
+					vessel = FlightGlobals.Vessels[vIdx];
+
+					if (vessel == FlightGlobals.ActiveVessel)
 					{
-						this.toolbarButton.Important = true;
+						continue;
 					}
-					else
+
+					relay = vessel.GetBestRelay();
+
+					if (relay != null)
 					{
-						this.toolbarButton.Important = false;
+						relay.FindNearestRelay();
 					}
 				}
-				if (this.appLauncherButton != null)
-				{
-					this.appLauncherButton.SetTexture(this.currentAppLauncherTexture);
+
+				activeVesselRelays = RelayDatabase.Instance[FlightGlobals.ActiveVessel];
+				for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++)
+				{
+					relay = activeVesselRelays[rIdx];
+
+					relay.FindNearestRelay();
+				}
+
+				if (this.toolbarButton != null || this.appLauncherButton != null)
+				{
+					log.Append("Checking vessel relay status.\n");
+
+					this.currentConnectionStatus = FlightGlobals.ActiveVessel.GetConnectionStatus();
+
+					log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
+						this.currentConnectionStatus, this.currentConnectionTexture);
+
+					if (this.toolbarButton != null)
+					{
+						this.toolbarButton.TexturePath = this.currentConnectionTexture;
+
+						if (this.currentConnectionStatus == ConnectionStatus.None)
+						{
+							if (!this.toolbarButton.Important) this.toolbarButton.Important = true;
+						}
+						else
+						{
+							if (this.toolbarButton.Important) this.toolbarButton.Important = false;
+						}
+					}
+					if (this.appLauncherButton != null)
+					{
+						this.appLauncherButton.SetTexture(this.currentAppLauncherTexture);
+					}
 				}
 			}
 

--- a/ARMapRenderer.cs
+++ b/ARMapRenderer.cs
@@ -26,8 +26,6 @@
 // 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.
 
-#define DEBUG
-
 #pragma warning disable 1591
 
 using KSP;
@@ -43,8 +41,15 @@
 		#region Fields
 		private Dictionary<Guid, LineRenderer> vesselLineRenderers;
 
+		// Debug Stuff
+		#pragma warning disable 649
+		private System.Diagnostics.Stopwatch timer;
+		private Tools.DebugLogger log;
+		private long relayStart;
+		private long start;
+		#pragma warning restore 649
+
 		#pragma warning disable 414
-		private bool dumpBool;
 		private Color thisColor;
 		#pragma warning restore 414
 		#endregion
@@ -91,12 +96,12 @@
 			{
 				this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>();
 			}
-		}
-
-		#if DEBUG
-		private System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
-		#endif
-		private Tools.DebugLogger log = Tools.DebugLogger.New(typeof(ARMapRenderer));
+
+			#if DEBUG
+			this.timer = new System.Diagnostics.Stopwatch();
+			this.log = Tools.DebugLogger.New(this);
+			#endif
+		}
 
 		private void OnPreCull()
 		{
@@ -109,7 +114,6 @@
 
 			#if DEBUG
 			timer.Restart();
-			long start;
 			#endif
 
 			try
@@ -134,9 +138,7 @@
 					{
 						Vessel vessel = FlightGlobals.Vessels[i];
 
-						#if DEBUG
 						log.AppendFormat("\nStarting check for vessel {0} at {1}ms", vessel, timer.ElapsedMilliseconds);
-						#endif
 
 						if (vessel == null)
 						{
@@ -163,10 +165,13 @@
 
 						IAntennaRelay vesselRelay = vessel.GetBestRelay();
 
-						#if DEBUG
-						log.AppendFormat("\n\tGot best relay {0} for vessel {1} in {2} ms",
-							vesselRelay, vessel, timer.ElapsedMilliseconds - start);
-						#endif
+						if (vesselRelay == null)
+						{
+							continue;
+						}
+
+						log.AppendFormat("\n\tGot best relay {0} ({3}) for vessel {1} in {2} ms",
+							vesselRelay, vessel, timer.ElapsedMilliseconds - start, vesselRelay.GetType().Name);
 
 						if (vesselRelay != null)
 						{
@@ -176,10 +181,8 @@
 
 							this.SetRelayVertices(vesselRelay);
 
-							#if DEBUG
 							log.AppendFormat("\n\tSet relay vertices for {0} in {1}ms",
 								vessel, timer.ElapsedMilliseconds - start);
-							#endif
 						}
 					}
 				}
@@ -208,12 +211,15 @@
 		#endregion
 
 		#region Utility
-		#if DEBUG
-		private long relayStart;
-		#endif
 		private void SetRelayVertices(IAntennaRelay relay)
 		{
 			log.AppendFormat("\n\t\tDrawing line for relay chain starting at {0}.", relay);
+
+			if (relay.vessel == null)
+			{
+				log.Append("\n\t\tvessel is null, bailing out");
+				return;
+			}
 
 			LineRenderer renderer = this[relay.vessel.id];
 			Vector3d start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
@@ -240,7 +246,9 @@
 
 			int idx = 0;
 
+			#if DEBUG
 			relayStart = timer.ElapsedMilliseconds;
+			#endif
 
 			Vector3d nextPoint;
 

--- a/AntennaRange.csproj
+++ b/AntennaRange.csproj
@@ -80,7 +80,6 @@
     <Compile Include="ARConfiguration.cs" />
     <Compile Include="ARFlightController.cs" />
     <Compile Include="ARMapRenderer.cs" />
-    <Compile Include="VesselCache.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -111,8 +111,6 @@
 		{
 			get
 			{
-				//this.FindNearestRelay();
-
 				if (this.KerbinDirect || this.targetRelay == null)
 				{
 					return this.DistanceTo(Kerbin);
@@ -159,7 +157,6 @@
 		/// <returns><c>true</c> if this instance can transmit; otherwise, <c>false</c>.</returns>
 		public virtual bool CanTransmit()
 		{
-			//this.FindNearestRelay();
 			return this.canTransmit;
 		}
 
@@ -167,7 +164,7 @@
 		/// Finds the nearest relay.
 		/// </summary>
 		/// <returns>The nearest relay or null, if no relays in range.</returns>
-		private void FindNearestRelay()
+		public void FindNearestRelay()
 		{
 			if (!FlightGlobals.ready)
 			{
@@ -632,7 +629,9 @@
 			#if DEBUG
 			} catch (Exception ex) {
 				log.AppendFormat("\nCaught {0}: {1}\n{2}", ex.GetType().FullName, ex.ToString(), ex.StackTrace);
+			#if QUIT_ON_EXCEPTION
 				UnityEngine.Application.Quit();
+			#endif
 			} finally {
 			#endif
 			log.Print(false);
@@ -666,6 +665,8 @@
 		{
 			this.moduleRef = module;
 			this.isChecked = false;
+
+			Tools.PostLogMessage("{0}: constructed {1}", this.GetType().Name, this.ToString());
 		}
 	}
 }

--- a/IAntennaRelay.cs
+++ b/IAntennaRelay.cs
@@ -83,6 +83,8 @@
 		/// </summary>
 		bool CanTransmit();
 
+		void FindNearestRelay();
+
 		/// <summary>
 		/// Returns a <see cref="System.String"/> that represents the current <see cref="AntennaRange.IAntennaRelay"/>.
 		/// </summary>

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -436,6 +436,14 @@
 			return this.relay.CanTransmit();
 		}
 
+		public void FindNearestRelay()
+		{
+			if (this.relay != null)
+			{
+				this.relay.FindNearestRelay();
+			}
+		}
+
 		/// <summary>
 		/// Override ModuleDataTransmitter.TransmitData to check against CanTransmit and fail out when CanTransmit
 		/// returns false.
@@ -444,6 +452,8 @@
 		/// <param name="callback">Callback function</param>
 		public new void TransmitData(List<ScienceData> dataQueue, Callback callback)
 		{
+			this.FindNearestRelay();
+
 			this.PreTransmit_SetPacketSize();
 			this.PreTransmit_SetPacketResourceCost();
 
@@ -558,6 +568,8 @@
 		/// </summary>
 		public new void StartTransmission()
 		{
+			this.FindNearestRelay();
+
 			PreTransmit_SetPacketSize ();
 			PreTransmit_SetPacketResourceCost ();
 

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -54,6 +54,12 @@
 				}
 				else
 				{
+					Tools.PostLogMessage("{0}: Could not fetch vessel!  {1}{2}{3}",
+						this.ToString(),
+						this.protoPart == null ? "\n\tprotoPart=Null" : string.Empty,
+						this.protoPart != null && this.protoPart.pVesselRef == null ? "\n\tthis.protoPart.pVesselRef=Null" : string.Empty,
+						this.protoPart != null && this.protoPart.pVesselRef != null && this.protoPart.pVesselRef.vesselRef == null ? "\n\tthis.protoPart.pVesselRef.vesselRef=Null" : string.Empty
+					);
 					return null;
 				}
 			}
@@ -146,6 +152,8 @@
 		public ProtoAntennaRelay(IAntennaRelay prefabRelay, ProtoPartSnapshot pps) : base(prefabRelay)
 		{
 			this.protoPart = pps;
+
+			Tools.PostLogMessage("{0}: constructed {1}", this.GetType().Name, this.ToString());
 		}
 	}
 }

--- a/RelayDatabase.cs
+++ b/RelayDatabase.cs
@@ -43,7 +43,7 @@
 		 * Static members
 		 * */
 		// Singleton storage
-		protected static RelayDatabase _instance;
+		private static RelayDatabase _instance;
 		// Gets the singleton
 		public static RelayDatabase Instance
 		{
@@ -66,18 +66,17 @@
 		 * Fields
 		 * */
 		// Vessel.id-keyed hash table of Part.GetHashCode()-keyed tables of relay objects.
-		protected Dictionary<Guid, List<IAntennaRelay>> relayDatabase;
+		private Dictionary<Guid, List<IAntennaRelay>> relayDatabase;
+		private Dictionary<Guid, IAntennaRelay> bestRelayTable;
 
 		// Vessel.id-keyed hash table of part counts, used for caching
-		protected Dictionary<Guid, int> vesselPartCountTable;
-
-		protected Dictionary<Guid, BestVesselRelayCache> bestRelayTable;
+		private Dictionary<Guid, int> vesselPartCountTable;
 
 		// Vessel.id-keyed hash table of booleans to track what vessels have been checked so far this time.
 		public Dictionary<Guid, bool> CheckedVesselsTable;
 
-		protected int cacheHits;
-		protected int cacheMisses;
+		private int cacheHits;
+		private int cacheMisses;
 
 		/*
 		 * Properties
@@ -115,9 +114,43 @@
 		/* 
 		 * Methods
 		 * */
+		// Remove a vessel from the cache, if it exists.
+		public void DirtyVessel(Vessel vessel)
+		{
+			this.relayDatabase.Remove(vessel.id);
+			this.vesselPartCountTable.Remove(vessel.id);
+			this.relayDatabase.Remove(vessel.id);
+		}
+
+		// Returns true if both the relayDatabase and the vesselPartCountDB contain the vessel id.
+		public bool ContainsKey(Guid key)
+		{
+			return this.relayDatabase.ContainsKey(key);
+		}
+
+		// Returns true if both the relayDatabase and the vesselPartCountDB contain the vessel.
+		public bool ContainsKey(Vessel vessel)
+		{
+			return this.ContainsKey(vessel.id);
+		}
+
+		public IAntennaRelay GetBestVesselRelay(Vessel vessel)
+		{
+			IAntennaRelay relay;
+			if (this.bestRelayTable.TryGetValue(vessel.id, out relay))
+			{
+				return relay;
+			}
+			else
+			{
+				var dump = this[vessel];
+				return null;
+			}
+		}
+
 		// Adds a vessel to the database
 		// The return for this function isn't used yet, but seems useful for potential future API-uses
-		public bool AddVessel(Vessel vessel)
+		private bool AddVessel(Vessel vessel)
 		{
 			// If this vessel is already here...
 			if (this.ContainsKey(vessel))
@@ -148,7 +181,7 @@
 		}
 
 		// Update the vessel's entry in the table
-		public void UpdateVessel(Vessel vessel)
+		private void UpdateVessel(Vessel vessel)
 		{
 			// Squak if the database doesn't have the vessel
 			if (!this.ContainsKey(vessel))
@@ -169,54 +202,6 @@
 			this.vesselPartCountTable[vessel.id] = vessel.Parts.Count;
 		}
 
-		// Remove a vessel from the cache, if it exists.
-		public void DirtyVessel(Vessel vessel)
-		{
-			if (this.relayDatabase.ContainsKey(vessel.id))
-			{
-				this.relayDatabase.Remove(vessel.id);
-			}
-			if (this.vesselPartCountTable.ContainsKey(vessel.id))
-			{
-				this.vesselPartCountTable.Remove(vessel.id);
-			}
-		}
-
-		public void SetBestVesselRelay(Vessel vessel, BestVesselRelayCache relay)
-		{
-			this.bestRelayTable[vessel.id] = relay;
-		}
-
-		public bool TryGetBestVesselRelay(Vessel vessel, out BestVesselRelayCache relay)
-		{
-			return this.bestRelayTable.TryGetValue(vessel.id, out relay);
-		}
-
-		public BestVesselRelayCache GetBestVesselRelay(Vessel vessel)
-		{
-			BestVesselRelayCache relayCache;
-			if (this.TryGetBestVesselRelay(vessel, out relayCache))
-			{
-				return relayCache;
-			}
-
-			throw new ArgumentOutOfRangeException(
-				string.Format("RelayDatabase: Vessel {0} not in best vessel relay table.", vessel)
-			);
-		}
-
-		// Returns true if both the relayDatabase and the vesselPartCountDB contain the vessel id.
-		public bool ContainsKey(Guid key)
-		{
-			return this.relayDatabase.ContainsKey(key);
-		}
-
-		// Returns true if both the relayDatabase and the vesselPartCountDB contain the vessel.
-		public bool ContainsKey(Vessel vessel)
-		{
-			return this.ContainsKey(vessel.id);
-		}
-
 		// Runs when a vessel is modified (or when we switch to one, to catch docking events)
 		public void onVesselEvent(Vessel vessel)
 		{
@@ -241,7 +226,7 @@
 		}
 
 		// Runs when the player requests a scene change, such as when changing vessels or leaving flight.
-		public void onSceneChange(GameScenes scene)
+		private void onSceneChange(GameScenes scene)
 		{
 			// If the active vessel is a real thing...
 			if (FlightGlobals.ActiveVessel != null)
@@ -252,7 +237,7 @@
 		}
 
 		// Runs when parts are undocked
-		public void onPartEvent(Part part)
+		private void onPartEvent(Part part)
 		{
 			if (part != null && part.vessel != null)
 			{
@@ -261,14 +246,14 @@
 		}
 
 		// Runs when parts are coupled, as in docking
-		public void onFromPartToPartEvent(GameEvents.FromToAction<Part, Part> data)
+		private void onFromPartToPartEvent(GameEvents.FromToAction<Part, Part> data)
 		{
 			this.onPartEvent(data.from);
 			this.onPartEvent(data.to);
 		}
 
 		// Produce a Part-hashed table of relays for the given vessel
-		protected void getVesselRelays(Vessel vessel, ref List<IAntennaRelay> relays)
+		private void getVesselRelays(Vessel vessel, ref List<IAntennaRelay> relays)
 		{
 			// We're going to completely regen this table, so dump the current contents.
 			relays.Clear();
@@ -278,6 +263,10 @@
 				"IAntennaRelay",
 				vessel.vesselName
 			));
+
+			double bestRelayRange = double.NegativeInfinity;
+			IAntennaRelay bestRelay = null;
+			IAntennaRelay relay;
 
 			// If the vessel is loaded, we can fetch modules implementing IAntennaRelay directly.
 			if (vessel.loaded) {
@@ -302,8 +291,16 @@
 						// ...if the module is a relay...
 						if (module is IAntennaRelay)
 						{
+							relay = (module as IAntennaRelay);
+
+							if (relay.maxTransmitDistance > bestRelayRange)
+							{
+								bestRelayRange = relay.maxTransmitDistance;
+								bestRelay = relay;
+							}
+
 							// ...add the module to the table
-							relays.Add(module as IAntennaRelay);
+							relays.Add(relay);
 							// ...neglect relay objects after the first in each part.
 							break;
 						}
@@ -362,14 +359,24 @@
 								module
 							));
 
+							relay = new ProtoAntennaRelay(module as IAntennaRelay, pps);
+
+							if (relay.maxTransmitDistance > bestRelayRange)
+							{
+								bestRelayRange = relay.maxTransmitDistance;
+								bestRelay = relay;
+							}
+
 							// ...build a new ProtoAntennaRelay and add it to the table
-							relays.Add(new ProtoAntennaRelay(module as IAntennaRelay, pps));
+							relays.Add(relay);
 							// ...neglect relay objects after the first in each part.
 							break;
 						}
 					}
 				}
 			}
+
+			this.bestRelayTable[vessel.id] = bestRelay;
 
 			Tools.PostDebugMessage(string.Format(
 				"{0}: vessel '{1}' ({2}) has {3} transmitters.",
@@ -381,13 +388,13 @@
 		}
 
 		// Construct the singleton
-		protected RelayDatabase()
+		private RelayDatabase()
 		{
 			// Initialize the databases
 			this.relayDatabase = new Dictionary<Guid, List<IAntennaRelay>>();
+			this.bestRelayTable = new Dictionary<Guid, IAntennaRelay>();
 			this.vesselPartCountTable = new Dictionary<Guid, int>();
 			this.CheckedVesselsTable = new Dictionary<Guid, bool>();
-			this.bestRelayTable = new Dictionary<Guid, BestVesselRelayCache>();
 
 			this.cacheHits = 0;
 			this.cacheMisses = 0;
@@ -448,21 +455,6 @@
 		}
 		#endif
 	}
-
-	public class BestVesselRelayCache
-	{
-		public Vessel vessel;
-		public IAntennaRelay relay;
-		public long timeStamp;
-
-		public BestVesselRelayCache() {}
-		public BestVesselRelayCache(Vessel _vessel, IAntennaRelay _relay, long _timeStamp)
-		{
-			this.vessel = _vessel;
-			this.relay = _relay;
-			this.timeStamp = _timeStamp;
-		}
-	}
 }
 
 

--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -166,45 +166,7 @@
 		/// <param name="vessel">This <see cref="Vessel"/></param>
 		public static IAntennaRelay GetBestRelay(this Vessel vessel)
 		{
-			BestVesselRelayCache relayCache;
-
-			if (RelayDatabase.Instance.TryGetBestVesselRelay(vessel, out relayCache))
-			{
-				if (
-					AntennaRelay.searchTimer.ElapsedMilliseconds - relayCache.timeStamp <
-					AntennaRelay.millisecondsBetweenSearches
-				)
-				{
-					return relayCache.relay;
-				}
-			}
-			else
-			{
-				relayCache = new BestVesselRelayCache();
-				relayCache.vessel = vessel;
-				RelayDatabase.Instance.SetBestVesselRelay(vessel, relayCache);
-			}
-
-			double bestScore = double.PositiveInfinity;
-			double relayScore = double.NaN;
-
-			IList<IAntennaRelay> vesselRelays = RelayDatabase.Instance[vessel];
-			IAntennaRelay relay;
-			for (int rIdx = 0; rIdx < vesselRelays.Count; rIdx++)
-			{
-				relay = vesselRelays[rIdx];
-				relayScore = relay.transmitDistance / relay.maxTransmitDistance;
-
-				if (relayScore < bestScore)
-				{
-					bestScore = relayScore;
-					relayCache.relay = relay;
-				}
-			}
-
-			relayCache.timeStamp = AntennaRelay.searchTimer.ElapsedMilliseconds;
-
-			return relayCache.relay;
+			return RelayDatabase.Instance.GetBestVesselRelay(vessel);
 		}
 	}
 

file:a/VesselCache.cs (deleted)
--- a/VesselCache.cs
+++ /dev/null
@@ -1,16 +1,1 @@
-// AntennaRange © 2015 toadicus
-//
-// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
-// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
-using System;
 
-namespace AntennaRange
-{
-	public class Relay
-	{
-		public Vessel vessel;
-		public IAntennaRelay targetRelay;
-	}
-}
-
-