Moved all of the vessel parsing code into the new RelayDatabase, which
Moved all of the vessel parsing code into the new RelayDatabase, which
watches some events to dirty the cache when states change. Also modules
will no longer offer to transmit if their part is dead or deactivated.

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -98,7 +98,7 @@
 		/// Determines whether this instance can transmit.
 		/// </summary>
 		/// <returns><c>true</c> if this instance can transmit; otherwise, <c>false</c>.</returns>
-		public bool CanTransmit()
+		public virtual bool CanTransmit()
 		{
 			if (this.transmitDistance > this.maxTransmitDistance)
 			{
@@ -207,14 +207,6 @@
 			return _nearestRelay;
 		}
 
-		public override string ToString()
-		{
-			return string.Format(
-				"Antenna relay on vessel {0}.",
-				vessel
-			);
-		}
-
 		/// <summary>
 		/// Initializes a new instance of the <see cref="AntennaRange.ProtoDataTransmitter"/> class.
 		/// </summary>

--- a/Extensions.cs
+++ b/Extensions.cs
@@ -82,87 +82,10 @@
 		/// <param name="vessel">This <see cref="Vessel"/></param>
 		public static IEnumerable<IAntennaRelay> GetAntennaRelays (this Vessel vessel)
 		{
-			Tools.PostDebugMessage(string.Format(
-				"{0}: Getting antenna relays from vessel {1}.",
-				"IAntennaRelay",
-				vessel.name
-			));
-
-			List<IAntennaRelay> Transmitters;
-
-			// If the vessel is loaded, we can fetch modules implementing IAntennaRelay directly.
-			if (vessel.loaded) {
-				Tools.PostDebugMessage(string.Format(
-					"{0}: vessel {1} is loaded.",
-					"IAntennaRelay",
-					vessel.name
-					));
-
-				// Gets a list of PartModules implementing IAntennaRelay
-				Transmitters = vessel.Parts
-					.SelectMany (p => p.Modules.OfType<IAntennaRelay> ())
-					.ToList();
-			}
-			// If the vessel is not loaded, we need to build ProtoAntennaRelays when we find relay ProtoPartSnapshots.
-			else
-			{
-				Tools.PostDebugMessage(string.Format(
-					"{0}: vessel {1} is not loaded.",
-					"IAntennaRelay",
-					vessel.name
-					));
-
-				Transmitters = new List<IAntennaRelay>();
-
-				// Loop through the ProtoPartModuleSnapshots in this Vessel
-				foreach (ProtoPartSnapshot pps in vessel.protoVessel.protoPartSnapshots)
-				{
-					IAntennaRelay relayModule;
-					ProtoAntennaRelay protoRelay;
-					int partHash;
-
-					relayModule = null;
-					protoRelay = null;
-					partHash = pps.GetHashCode();
-
-					if (prebuiltProtoRelays.ContainsKey(partHash))
-					{
-						protoRelay = prebuiltProtoRelays[partHash];
-					}
-					else
-					{
-						foreach (PartModule module in PartLoader.getPartInfoByName(pps.partName).partPrefab.Modules)
-						{
-							if (module is IAntennaRelay)
-							{
-								relayModule = module as IAntennaRelay;
-
-								protoRelay = new ProtoAntennaRelay(relayModule, vessel);
-								prebuiltProtoRelays[partHash] = protoRelay;
-								break;
-							}
-						}
-					}
-
-					if (protoRelay != null)
-					{
-						Transmitters.Add(protoRelay);
-					}
-				}
-			}
-
-			Tools.PostDebugMessage(string.Format(
-				"{0}: vessel {1} has {2} transmitters.",
-				"IAntennaRelay",
-				vessel.name,
-				Transmitters.Count
-				));
-
-			// Return the list of IAntennaRelays
-			return Transmitters;
+			return RelayDatabase.Instance[vessel].Values.ToList();
 		}
 
-		private static Dictionary<int, ProtoAntennaRelay> prebuiltProtoRelays = new Dictionary<int, ProtoAntennaRelay>();
+
 	}
 }
 

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -311,6 +311,18 @@
 		// Override ModuleDataTransmitter.CanTransmit to return false when transmission is not possible.
 		public new bool CanTransmit()
 		{
+			PartStates partState = this.part.State;
+			if (partState == PartStates.DEAD || partState == PartStates.DEACTIVATED)
+			{
+				Tools.PostDebugMessage(string.Format(
+					"{0}: {1} on {2} cannot transmit: {3}",
+					this.GetType().Name,
+					this.part.partInfo.title,
+					this.vessel.name,
+					Enum.GetName(typeof(PartStates), partState)
+				));
+				return false;
+			}
 			return this.relay.CanTransmit();
 		}
 
@@ -351,7 +363,9 @@
 			{
 				StringBuilder message = new StringBuilder();
 
-				message.Append("[" + base.part.partInfo.title + "] ");
+				message.Append("[");
+				message.Append(base.part.partInfo.title);
+				message.Append("] ");
 
 				message.Append("Beginning transmission ");
 
@@ -361,7 +375,8 @@
 				}
 				else
 				{
-					message.Append("via relay " + this.relay.nearestRelay);
+					message.Append("via ");
+					message.Append(this.relay.nearestRelay);
 				}
 
 				ScreenMessages.PostScreenMessage(message.ToString(), 4f, ScreenMessageStyle.UPPER_LEFT);
@@ -398,6 +413,15 @@
 			{
 				this.actionUIUpdate = false;
 			}
+		}
+
+		public override string ToString()
+		{
+			return string.Format(
+				"{0} on {1}.",
+				this.part.partInfo.title,
+				vessel.name
+			);
 		}
 
 		// When debugging, it's nice to have a button that just tells you everything.

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -29,6 +29,9 @@
 		// Stores the relay prefab
 		protected IAntennaRelay relayPrefab;
 
+		// Stores the prototype part so we can make sure we haven't exploded or so.
+		protected ProtoPartSnapshot protoPart;
+
 		/// <summary>
 		/// The maximum distance at which this transmitter can operate.
 		/// </summary>
@@ -52,15 +55,50 @@
 			protected set;
 		}
 
+		public string Title
+		{
+			get
+			{
+				return this.protoPart.partInfo.title;
+			}
+		}
+
+		public override bool CanTransmit()
+		{
+			PartStates partState = (PartStates)this.protoPart.state;
+			if (partState == PartStates.DEAD || partState == PartStates.DEACTIVATED)
+			{
+				Tools.PostDebugMessage(string.Format(
+					"{0}: {1} on {2} cannot transmit: {3}",
+					this.GetType().Name,
+					this.Title,
+					this.vessel.name,
+					Enum.GetName(typeof(PartStates), partState)
+				));
+				return false;
+			}
+			return base.CanTransmit();
+		}
+
+		public override string ToString()
+		{
+			return string.Format(
+				"{0} on {1}.",
+				this.Title,
+				vessel.name
+			);
+		}
+
 		/// <summary>
 		/// Initializes a new instance of the <see cref="AntennaRange.ProtoAntennaRelay"/> class.
 		/// </summary>
 		/// <param name="ms">The ProtoPartModuleSnapshot to wrap</param>
 		/// <param name="vessel">The parent Vessel</param>
-		public ProtoAntennaRelay(IAntennaRelay prefabRelay, Vessel vessel) : base(vessel)
+		public ProtoAntennaRelay(IAntennaRelay prefabRelay, ProtoPartSnapshot pps) : base(pps.pVesselRef.vesselRef)
 		{
 			this.relayPrefab = prefabRelay;
-			this.vessel = vessel;
+			this.protoPart = pps;
+			this.vessel = pps.pVesselRef.vesselRef;
 		}
 	}
 }

file:b/RelayDatabase.cs (new)
--- /dev/null
+++ b/RelayDatabase.cs
@@ -1,1 +1,236 @@
-
+// AntennaRange © 2014 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 KSP;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace AntennaRange
+{
+	public class RelayDatabase
+	{
+		/*
+		 * Static members
+		 * */
+		protected static RelayDatabase _instance;
+
+		public static RelayDatabase Instance
+		{
+			get
+			{	
+				if (_instance == null)
+				{
+					_instance = new RelayDatabase();
+				}
+
+				return _instance;
+			}
+		}
+
+		/*
+		 * Instance members
+		 * */
+
+		/*
+		 * Fields
+		 * */
+		protected Dictionary<Guid, Dictionary<int, IAntennaRelay>> relayDatabase;
+
+		protected Dictionary<Guid, int> vesselPartCountDB;
+
+		/*
+		 * Properties
+		 * */
+		public Dictionary<int, IAntennaRelay> this [Vessel vessel]
+		{
+			get
+			{
+				if (!this.ContainsKey(vessel.id))
+				{
+					this.AddVessel(vessel);
+				}
+				if (this.vesselPartCountDB[vessel.id] != vessel.Parts.Count)
+				{
+					this.UpdateVessel(vessel);
+				}
+
+				return relayDatabase[vessel.id];
+			}
+		}
+
+		/* 
+		 * Methods
+		 * */
+		public bool AddVessel(Vessel vessel)
+		{
+			if (relayDatabase.ContainsKey(vessel.id))
+			{
+				Debug.LogWarning(string.Format(
+					"{0}: Cannot add vessel '{1}' (id: {2}): Already in database.",
+					this.GetType().Name,
+					vessel.name,
+					vessel.id
+				));
+
+				return false;
+			}
+			else
+			{
+				this.UpdateVessel(vessel);
+
+				return true;
+			}
+		}
+
+		public void UpdateVessel(Vessel vessel)
+		{
+			if (!relayDatabase.ContainsKey(vessel.id))
+			{
+				Tools.PostDebugMessage(string.Format(
+					"{0}: Update called vessel '{1}' (id: {2}) not in database: vessel will be added.",
+					this.GetType().Name,
+					vessel.name,
+					vessel.id
+				));
+			}
+			else
+			{
+				// Remove stuff?
+			}
+
+			this.relayDatabase[vessel.id] = this.getVesselRelays(vessel);
+			this.vesselPartCountDB[vessel.id] = vessel.Parts.Count;
+		}
+
+		public bool ContainsKey(Guid key)
+		{
+			return (this.relayDatabase.ContainsKey(key) & this.vesselPartCountDB.ContainsKey(key));
+		}
+
+		public bool ContainsKey(Vessel vessel)
+		{
+			return this.ContainsKey(vessel.id);
+		}
+
+		public void onVesselWasModified(Vessel vessel)
+		{
+			if (this.ContainsKey(vessel))
+			{
+				if (this.vesselPartCountDB[vessel.id] != vessel.Parts.Count)
+				{
+					Tools.PostDebugMessage(string.Format(
+						"{0}: vessel '{1}' (id: {2}) was modified.",
+						this.GetType().Name,
+						vessel.name,
+						vessel.id
+					));
+
+					this.vesselPartCountDB[vessel.id] = -1;
+				}
+			}
+		}
+
+		protected Dictionary<int, IAntennaRelay> getVesselRelays(Vessel vessel)
+		{
+			Dictionary<int, IAntennaRelay> relays;
+
+			if (this.ContainsKey(vessel))
+			{
+				relays = this.relayDatabase[vessel.id];
+				relays.Clear();
+			}
+			else
+			{
+				relays = new Dictionary<int, IAntennaRelay>();
+			}
+
+			Tools.PostDebugMessage(string.Format(
+				"{0}: Getting antenna relays from vessel {1}.",
+				"IAntennaRelay",
+				vessel.name
+			));
+
+			// If the vessel is loaded, we can fetch modules implementing IAntennaRelay directly.
+			if (vessel.loaded) {
+				Tools.PostDebugMessage(string.Format(
+					"{0}: vessel {1} is loaded, searching for modules in loaded parts.",
+					"IAntennaRelay",
+					vessel.name
+				));
+
+				// Gets a list of PartModules implementing IAntennaRelay
+				foreach (Part part in vessel.Parts)
+				{
+					foreach (PartModule module in part.Modules)
+					{
+						if (module is IAntennaRelay)
+						{
+							relays.Add(part.GetHashCode(), module as IAntennaRelay);
+							break;
+						}
+					}
+				}
+			}
+			// If the vessel is not loaded, we need to build ProtoAntennaRelays when we find relay ProtoPartSnapshots.
+			else
+			{
+				Tools.PostDebugMessage(string.Format(
+					"{0}: vessel {1} is not loaded, searching for modules in prototype parts.",
+					"IAntennaRelay",
+					vessel.name
+				));
+
+				// Loop through the ProtoPartModuleSnapshots in this Vessel
+				foreach (ProtoPartSnapshot pps in vessel.protoVessel.protoPartSnapshots)
+				{
+					ProtoAntennaRelay protoRelay;
+					Part partPrefab = PartLoader.getPartInfoByName(pps.partName).partPrefab;
+
+					foreach (PartModule module in partPrefab.Modules)
+					{
+						if (module is IAntennaRelay)
+						{
+							protoRelay =
+								new ProtoAntennaRelay(module as IAntennaRelay, pps);
+							relays.Add(pps.GetHashCode(), protoRelay);
+							break;
+						}
+					}
+				}
+			}
+
+			Tools.PostDebugMessage(string.Format(
+				"{0}: vessel '{1}' has {2} transmitters.",
+				"IAntennaRelay",
+				vessel.name,
+				relays.Count
+			));
+
+			// Return the list of IAntennaRelays
+			return relays;
+		}
+
+		protected RelayDatabase()
+		{
+			relayDatabase =	new Dictionary<Guid, Dictionary<int, IAntennaRelay>>();
+			vesselPartCountDB = new Dictionary<Guid, int>();
+
+			GameEvents.onVesselWasModified.Add(this.onVesselWasModified);
+			GameEvents.onVesselChange.Add(this.onVesselWasModified);
+		}
+
+		~RelayDatabase()
+		{
+			GameEvents.onVesselWasModified.Remove(this.onVesselWasModified);
+			GameEvents.onVesselChange.Remove(this.onVesselWasModified);
+
+			Tools.PostDebugMessage(this.GetType().Name + " destroyed.");
+		}
+	}
+}
+
+