Now maintaining a hash table for ProtoAntennaRelays and using prefab modules to do the maths and stuff, in lieu of messing with persistence and stuff. Also made the error message prettier. proto_to_prefab
Now maintaining a hash table for ProtoAntennaRelays and using prefab modules to do the maths and stuff, in lieu of messing with persistence and stuff. Also made the error message prettier.

I should commit more often.

--- a/AntennaRange.cfg
+++ b/AntennaRange.cfg
@@ -48,8 +48,3 @@
 	}
 }
 
-@PART[*]:HAS[MODULE[ModuleLimitedDataTransmitter]]:Final
-{
-	isAntenna = True
-}
-

--- a/Extensions.cs
+++ b/Extensions.cs
@@ -103,7 +103,7 @@
 					.SelectMany (p => p.Modules.OfType<IAntennaRelay> ())
 					.ToList();
 			}
-			// If the vessel is not loaded, we need to find ProtoPartModuleSnapshots with a true IsAntenna field.
+			// If the vessel is not loaded, we need to build ProtoAntennaRelays when we find relay ProtoPartSnapshots.
 			else
 			{
 				Tools.PostDebugMessage(string.Format(
@@ -117,12 +117,37 @@
 				// Loop through the ProtoPartModuleSnapshots in this Vessel
 				foreach (ProtoPartSnapshot pps in vessel.protoVessel.protoPartSnapshots)
 				{
-					Transmitters.AddRange(
-						PartLoader.getPartInfoByName(pps.partName)
-						.partPrefab
-						.Modules
-						.OfType<IAntennaRelay>()
-					);
+					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);
+					}
 				}
 			}
 
@@ -136,6 +161,8 @@
 			// Return the list of IAntennaRelays
 			return Transmitters;
 		}
+
+		private static Dictionary<int, ProtoAntennaRelay> prebuiltProtoRelays = new Dictionary<int, ProtoAntennaRelay>();
 	}
 }
 

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -18,6 +18,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 using KSP;
 using UnityEngine;
 
@@ -56,14 +57,23 @@
 		// Sometimes we will need to communicate errors; this is how we do it.
 		protected ScreenMessage ErrorMsg;
 
-		// Let's make the error text pretty!
-		protected UnityEngine.GUIStyle ErrorStyle;
-
 		// The distance from Kerbin at which the antenna will perform exactly as prescribed by packetResourceCost
 		// and packetSize.
 		[KSPField(isPersistant = false)]
 		public float nominalRange;
 
+		[KSPField(isPersistant = false, guiActive = true, guiName = "Transmission Distance")]
+		public string UItransmitDistance;
+
+		[KSPField(isPersistant = false, guiActive = true, guiName = "Maximum Distance")]
+		public string UImaxTransmitDistance;
+
+		[KSPField(isPersistant = false, guiActive = true, guiName = "Packet Size")]
+		public string UIpacketSize;
+
+		[KSPField(isPersistant = false, guiActive = true, guiName = "Packet Cost")]
+		public string UIpacketCost;
+
 		// The multiplier on packetResourceCost that defines the maximum power output of the antenna.  When the power
 		// cost exceeds packetResourceCost * maxPowerFactor, transmission will fail.
 		[KSPField(isPersistant = false)]
@@ -72,6 +82,8 @@
 		// The multipler on packetSize that defines the maximum data bandwidth of the antenna.
 		[KSPField(isPersistant = false)]
 		public float maxDataFactor;
+
+		protected bool actionUIUpdate;
 
 		/*
 		 * Properties
@@ -182,15 +194,7 @@
 		// Build ALL the objects.
 		public ModuleLimitedDataTransmitter () : base()
 		{
-			// Make the error posting prettier.
-			this.ErrorStyle = new UnityEngine.GUIStyle();
-			this.ErrorStyle.normal.textColor = (UnityEngine.Color)XKCDColors.OrangeRed;
-			this.ErrorStyle.active.textColor = (UnityEngine.Color)XKCDColors.OrangeRed;
-			this.ErrorStyle.hover.textColor = (UnityEngine.Color)XKCDColors.OrangeRed;
-			this.ErrorStyle.fontStyle = UnityEngine.FontStyle.Normal;
-			this.ErrorStyle.padding.top = 32;
-
-			this.ErrorMsg = new ScreenMessage("", 4f, false, ScreenMessageStyle.UPPER_LEFT, this.ErrorStyle);
+			this.ErrorMsg = new ScreenMessage("", 4f, false, ScreenMessageStyle.UPPER_LEFT);
 		}
 
 		// At least once, when the module starts with a state on the launch pad or later, go find Kerbin.
@@ -202,6 +206,11 @@
 			{
 				this.relay = new AntennaRelay(vessel);
 				this.relay.maxTransmitDistance = this.maxTransmitDistance;
+
+				this.UImaxTransmitDistance = Tools.MuMech_ToSI(this.maxTransmitDistance) + "m";
+
+				GameEvents.onPartActionUICreate.Add(this.onPartActionUICreate);
+				GameEvents.onPartActionUIDismiss.Add(this.onPartActionUIDismiss);
 			}
 		}
 
@@ -244,9 +253,18 @@
 				Tools.MuMech_ToSI((double)this.transmitDistance, 2)
 				);
 
-			this.ErrorMsg.message = ErrorText;
-
-			ScreenMessages.PostScreenMessage(this.ErrorMsg, true);
+			this.ErrorMsg.message = string.Format(
+				"<color='#{0}{1}{2}{3}'><b>{4}</b></color>",
+				((int)(XKCDColors.OrangeRed.r * 255f)).ToString("x2"),
+				((int)(XKCDColors.OrangeRed.g * 255f)).ToString("x2"),
+				((int)(XKCDColors.OrangeRed.b * 255f)).ToString("x2"),
+				((int)(XKCDColors.OrangeRed.a * 255f)).ToString("x2"),
+				ErrorText
+			);
+
+			Tools.PostDebugMessage(this.GetType().Name + ": " + this.ErrorMsg.message);
+
+			ScreenMessages.PostScreenMessage(this.ErrorMsg, false);
 		}
 
 		// Before transmission, set packetResourceCost.  Per above, packet cost increases with the square of
@@ -331,26 +349,54 @@
 
 			if (this.CanTransmit())
 			{
-				string message;
-
-				message = "Beginning transmission ";
+				StringBuilder message = new StringBuilder();
+
+				message.Append("[" + base.part.partInfo.title + "] ");
+
+				message.Append("Beginning transmission ");
 
 				if (this.relay.nearestRelay == null)
 				{
-					message += "directly to Kerbin.";
+					message.Append("directly to Kerbin.");
 				}
 				else
 				{
-					message += "via relay " + this.relay.nearestRelay;
-				}
-
-				ScreenMessages.PostScreenMessage(message, 4f, ScreenMessageStyle.UPPER_LEFT);
+					message.Append("via relay " + this.relay.nearestRelay);
+				}
+
+				ScreenMessages.PostScreenMessage(message.ToString(), 4f, ScreenMessageStyle.UPPER_LEFT);
 
 				base.StartTransmission();
 			}
 			else
 			{
 				this.PostCannotTransmitError ();
+			}
+		}
+
+		public void Update()
+		{
+			if (this.actionUIUpdate)
+			{
+				this.UItransmitDistance = Tools.MuMech_ToSI(this.transmitDistance) + "m";
+				this.UIpacketSize = this.CanTransmit() ? Tools.MuMech_ToSI(this.DataRate) + "MiT" : "N/A";
+				this.UIpacketCost = this.CanTransmit() ? Tools.MuMech_ToSI(this.DataResourceCost) + "E" : "N/A";
+			}
+		}
+
+		public void onPartActionUICreate(Part eventPart)
+		{
+			if (eventPart == base.part)
+			{
+				this.actionUIUpdate = true;
+			}
+		}
+
+		public void onPartActionUIDismiss(Part eventPart)
+		{
+			if (eventPart == base.part)
+			{
+				this.actionUIUpdate = false;
 			}
 		}
 

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -26,11 +26,8 @@
 	 * */
 	public class ProtoAntennaRelay : AntennaRelay, IAntennaRelay
 	{
-		// Stores the proto module.
-		protected ProtoPartModuleSnapshot protoModule;
-
-		// Stores the proto part, which seems silly because all we need is the name.
-		protected Part partPrefab;
+		// Stores the relay prefab
+		protected IAntennaRelay relayPrefab;
 
 		/// <summary>
 		/// The maximum distance at which this transmitter can operate.
@@ -40,7 +37,7 @@
 		{
 			get
 			{
-				return this.partPrefab.Modules.OfType<ModuleLimitedDataTransmitter>().First().maxTransmitDistance;
+				return relayPrefab.maxTransmitDistance;
 			}
 		}
 
@@ -51,23 +48,8 @@
 		/// <value><c>true</c> if relay checked; otherwise, <c>false</c>.</value>
 		public override bool relayChecked
 		{
-			get
-			{
-				bool result;
-				Boolean.TryParse(this.protoModule.moduleValues.GetValue("relayChecked"), out result);
-				return result;
-			}
-			protected set
-			{
-				if (this.protoModule.moduleValues.HasValue("relayChecked"))
-				{
-					this.protoModule.moduleValues.SetValue("relayChecked", value.ToString ());
-				}
-				else
-				{
-					this.protoModule.moduleValues.AddValue("relayChecked", value);
-				}
-			}
+			get;
+			protected set;
 		}
 
 		/// <summary>
@@ -75,10 +57,10 @@
 		/// </summary>
 		/// <param name="ms">The ProtoPartModuleSnapshot to wrap</param>
 		/// <param name="vessel">The parent Vessel</param>
-		public ProtoAntennaRelay(ProtoPartModuleSnapshot ppms, ProtoPartSnapshot pps, Vessel vessel) : base(vessel)
+		public ProtoAntennaRelay(IAntennaRelay prefabRelay, Vessel vessel) : base(vessel)
 		{
-			this.protoModule = ppms;
-			this.partPrefab = PartLoader.getPartInfoByName(pps.partName).partPrefab;
+			this.relayPrefab = prefabRelay;
+			this.vessel = vessel;
 		}
 	}
 }