A whole bunch of changes to start making simple relays possible.
A whole bunch of changes to start making simple relays possible.

--- a/AntennaRange.cs
+++ b/AntennaRange.cs
@@ -21,6 +21,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using KSP;
+using UnityEngine;
 
 namespace AntennaRange
 {
@@ -40,7 +41,7 @@
 	/*
 	 * Fields
 	 * */
-	public class ModuleLimitedDataTransmitter : ModuleDataTransmitter, IScienceDataTransmitter
+	public class ModuleLimitedDataTransmitter : ModuleDataTransmitter, ILimitedScienceDataTransmitter
 	{
 		// Stores the packetResourceCost as defined in the .cfg file.
 		protected float _basepacketResourceCost;
@@ -73,6 +74,13 @@
 		// The multipler on packetSize that defines the maximum data bandwidth of the antenna.
 		[KSPField(isPersistant = false)]
 		public float maxDataFactor;
+
+		[KSPField(isPersistant = true)]
+		protected float ARmaxTransmitDistance;
+
+		// Call this an antenna, to make things easier on us.  This behavior is borrowed from RemoteTech by Cilph.
+		[KSPField(isPersistant = true)]
+		public bool IsAntenna = true;
 
 		/*
 		 * Properties
@@ -90,11 +98,12 @@
 		}
 
 		// Returns the maximum distance this module can transmit
-		public double maxTransmitDistance
+		[KSPField(isPersistant = true)]
+		public float maxTransmitDistance
 		{
 			get
 			{
-				return Math.Sqrt (this.maxPowerFactor) * this.nominalRange;
+				return this.ARmaxTransmitDistance;
 			}
 		}
 
@@ -206,6 +215,8 @@
 			this.Fields.Load(node);
 			base.Fields.Load(node);
 
+			this.ARmaxTransmitDistance = Mathf.Sqrt (this.maxPowerFactor) * this.nominalRange;
+
 			base.OnLoad (node);
 
 			this._basepacketSize = base.packetSize;
@@ -233,7 +244,7 @@
 		{
 			string ErrorText = string.Format (
 				"Unable to transmit: out of range!  Maximum range = {0}m; Current range = {1}m.",
-				Tools.MuMech_ToSI((double)this.maxTransmitDistance, 2),
+				Tools.MuMech_ToSI((double)this.ARmaxTransmitDistance, 2),
 				Tools.MuMech_ToSI((double)this.transmitDistance, 2)
 				);
 
@@ -279,14 +290,17 @@
 		{
 			string text = base.GetInfo();
 			text += "Nominal Range: " + Tools.MuMech_ToSI((double)this.nominalRange, 2) + "m\n";
-			text += "Maximum Range: " + Tools.MuMech_ToSI((double)this.maxTransmitDistance, 2) + "m\n";
+			text += "Maximum Range: " + Tools.MuMech_ToSI((double)this.ARmaxTransmitDistance, 2) + "m\n";
 			return text;
 		}
 
 		// Override ModuleDataTransmitter.CanTransmit to return false when transmission is not possible.
 		public new bool CanTransmit()
 		{
-			if (this.transmitDistance < this.maxTransmitDistance)
+			this.PreTransmit_SetPacketResourceCost();
+			this.PreTransmit_SetPacketSize();
+
+			if (this.transmitDistance < this.ARmaxTransmitDistance)
 			{
 				return true;
 			}
@@ -312,16 +326,8 @@
 					nearbyVessels.Count
 					));
 
-				List<Part> nearbyParts = nearbyVessels.SelectMany(v => v.Parts).ToList();
-
-				Tools.PostDebugMessage(string.Format(
-					"{0}: Parts in nearby vessels: {1}",
-					this.GetType().Name,
-					nearbyParts.Count
-					));
-
-				List<ModuleLimitedDataTransmitter> nearbyTransmitters = nearbyParts
-					.SelectMany(p => p.Modules.OfType<ModuleLimitedDataTransmitter>())
+				List<ILimitedScienceDataTransmitter> nearbyTransmitters = nearbyVessels
+					.SelectMany (v => v.GetTransmitters ())
 					.ToList();
 
 				Tools.PostDebugMessage(string.Format(
@@ -346,24 +352,9 @@
 					nearbyTransmitters.Count
 					));
 
-				List<ModuleLimitedDataTransmitter> nearbyRelays = this._relayVessels
-					.Where(v => (v.GetWorldPos3D() - vessel.GetWorldPos3D()).magnitude < this.transmitDistance)
-					.Where(v => v.id != vessel.id)
-					.SelectMany(v => v.Parts)
-					.SelectMany(p => p.Modules.OfType<ModuleLimitedDataTransmitter>())
-					.Where(m => !m.relayChecked)
-					.Where(m => m.CanTransmit())
-					.ToList();
-
-				Tools.PostDebugMessage(string.Format(
-					"{0}: Found {1} nearby relays.",
-					this.GetType().Name,
-					nearbyRelays.Count
-				));
-
 				this.relayChecked = false;
 
-				if (nearbyRelays.Count == 0)
+				if (nearbyTransmitters.Count == 0)
 				{
 					return false;
 				}
@@ -378,22 +369,20 @@
 		// returns false.
 		public new void TransmitData(List<ScienceData> dataQueue)
 		{
-			this.PreTransmit_SetPacketSize ();
-			this.PreTransmit_SetPacketResourceCost ();
+			if (this.CanTransmit())
+			{
+				base.TransmitData(dataQueue);
+			}
+			else
+			{
+				this.PostCannotTransmitError ();
+			}
 
 			Tools.PostDebugMessage (
 				"distance: " + this.transmitDistance
 				+ " packetSize: " + this.packetSize
 				+ " packetResourceCost: " + this.packetResourceCost
 			);
-			if (this.CanTransmit())
-			{
-				base.TransmitData(dataQueue);
-			}
-			else
-			{
-				this.PostCannotTransmitError ();
-			}
 		}
 
 		// Override ModuleDataTransmitter.StartTransmission to check against CanTransmit and fail out when CanTransmit
@@ -444,7 +433,7 @@
 				base.packetSize,
 				this._basepacketResourceCost,
 				base.packetResourceCost,
-				this.maxTransmitDistance,
+				this.ARmaxTransmitDistance,
 				this.transmitDistance,
 				this.nominalRange,
 				this.CanTransmit(),

file:b/Extensions.cs (new)
--- /dev/null
+++ b/Extensions.cs
@@ -1,1 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
+namespace AntennaRange
+{
+	public static class Extensions
+	{
+		public static IEnumerable<ILimitedScienceDataTransmitter> GetTransmitters (this Vessel vessel)
+		{
+			List<ILimitedScienceDataTransmitter> Transmitters;
+
+			if (vessel.loaded) {
+				Transmitters = vessel.Parts
+					.SelectMany (p => p.Modules.OfType<ILimitedScienceDataTransmitter> ())
+					.ToList();
+			} else {
+				Transmitters = new List<ILimitedScienceDataTransmitter>();
+
+				foreach (ProtoPartModuleSnapshot ms in vessel.protoVessel.protoPartSnapshots.SelectMany(ps => ps.modules))
+				{
+					if (ms.IsAntenna())
+					{
+						Transmitters.Add(new ProtoDataTransmitter(ms, vessel));
+					}
+				}
+			}
+
+			return Transmitters;
+		}
+
+		public static bool IsAntenna (this PartModule module)
+		{
+			return module.Fields.GetValue<bool> ("IsAntenna");
+		}
+
+		public static bool IsAntenna(this ProtoPartModuleSnapshot protomodule)
+		{
+			bool result;
+
+			return Boolean.TryParse (protomodule.moduleValues.GetValue ("IsAntenna") ?? "False", out result)
+				? result : false;
+		}
+	}
+}
+
+

--- /dev/null
+++ b/ILimitedScienceDataTransmitter.cs
@@ -1,1 +1,13 @@
+using System;
 
+namespace AntennaRange
+{
+	public interface ILimitedScienceDataTransmitter : IScienceDataTransmitter
+	{
+		float maxTransmitDistance { get; }
+
+		bool relayChecked { get; }
+	}
+}
+
+

--- /dev/null
+++ b/ProtoDataTransmitter.cs
@@ -1,1 +1,121 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
+namespace AntennaRange
+{
+	public class ProtoDataTransmitter : ILimitedScienceDataTransmitter
+	{
+		protected ProtoPartModuleSnapshot snapshot;
+		protected Vessel vessel;
+
+		// Returns the current distance to the center of Kerbin, which is totally where the Kerbals keep their radioes.
+		protected double transmitDistance
+		{
+			get
+			{
+				Vector3d KerbinPos = FlightGlobals.Bodies.FirstOrDefault(b => b.name == "Kerbin").position;
+				Vector3d ActivePos = this.vessel.GetWorldPos3D();
+
+				return (ActivePos - KerbinPos).magnitude;
+			}
+		}
+
+		/// <summary>
+		/// The maximum distance at which this transmitter can operate.
+		/// </summary>
+		/// <value>The max transmit distance.</value>
+		public float maxTransmitDistance
+		{
+			get
+			{
+				double result;
+				Double.TryParse(snapshot.moduleValues.GetValue ("ARmaxTransmitDistance") ?? "0", out result);
+				return (float)result;
+			}
+		}
+
+		/// <summary>
+		/// Gets the data rate in MiT per second.
+		/// </summary>
+		/// <value>The data rate.</value>
+		public float DataRate
+		{
+			get;
+			protected set;
+		}
+
+		/// <summary>
+		/// Gets the data resource cost in units of ElectricCharge.
+		/// </summary>
+		/// <value>The data resource cost.</value>
+		public double DataResourceCost
+		{
+			get;
+			protected set;
+		}
+
+		/// <summary>
+		/// Gets a value indicating whether this <see cref="AntennaRange.ProtoDataTransmitter"/> has been checked during
+		/// the current relay attempt.
+		/// </summary>
+		/// <value><c>true</c> if relay checked; otherwise, <c>false</c>.</value>
+		public bool relayChecked
+		{
+			get;
+			protected set;
+		}
+
+		/// <summary>
+		/// Determines whether this module can transmit.
+		/// </summary>
+		/// <returns><c>true</c> if this module can transmit; otherwise, <c>false</c>.</returns>
+		public bool CanTransmit()
+		{
+			Tools.PostDebugMessage (string.Format (
+				"{0}: transmitDistance: {1}, maxDistance: {2}",
+				this.GetType().Name,
+				this.transmitDistance,
+				this.maxTransmitDistance
+			));
+
+			if (this.transmitDistance < this.maxTransmitDistance)
+			{
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		/// <summary>
+		/// Determines whether this module is busy.
+		/// </summary>
+		/// <returns><c>true</c> if this module is busy; otherwise, <c>false</c>.</returns>
+		public bool IsBusy()
+		{
+			return false;
+		}
+
+		/// <summary>
+		/// Transmits the data in a queue.
+		/// </summary>
+		/// <param name="dataQueue">Data queue to be transmitted.</param>
+		public void TransmitData(List<ScienceData> dataQueue) {}
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="AntennaRange.ProtoDataTransmitter"/> class.
+		/// </summary>
+		/// <param name="ms"><see cref="ProtoPartModuleSnapshot"/></param>
+		public ProtoDataTransmitter(ProtoPartModuleSnapshot ms, Vessel v)
+		{
+			this.snapshot = ms;
+			this.vessel = v;
+
+			this.relayChecked = false;
+		}
+	}
+}
+
+