Hopefully the last bulk update for relays. Also includes a bunch of commenting.
[AntennaRange.git] / AntennaRelay.cs
blob:a/AntennaRelay.cs -> blob:b/AntennaRelay.cs
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
namespace AntennaRange namespace AntennaRange
{ {
public class AntennaRelay : IAntennaRelay public class AntennaRelay : IAntennaRelay
{ {
  // We don't have a Bard, so we'll hide Kerbin here.
protected CelestialBody Kerbin; protected CelestialBody Kerbin;
   
  /// <summary>
  /// Gets the parent Vessel.
  /// </summary>
  /// <value>The parent Vessel.</value>
public Vessel vessel public Vessel vessel
{ {
get; get;
protected set; protected set;
} }
   
// Returns the current distance to the center of Kerbin, which is totally where the Kerbals keep their radioes. /// <summary>
  /// Gets the transmit distance.
  /// </summary>
  /// <value>The transmit distance.</value>
public double transmitDistance public double transmitDistance
{ {
get get
{ {
IAntennaRelay nearestRelay = this.FindNearestRelay(); IAntennaRelay nearestRelay = this.FindNearestRelay();
   
  // If there is no available relay nearby...
if (nearestRelay == null) if (nearestRelay == null)
{ {
  // .. return the distance to Kerbin
return this.DistanceTo(this.Kerbin); return this.DistanceTo(this.Kerbin);
} }
else else
{ {
  /// ...otherwise, return the distance to the nearest available relay.
return this.DistanceTo(nearestRelay); return this.DistanceTo(nearestRelay);
} }
} }
} }
   
  /// <summary>
  /// The maximum distance at which this relay can operate.
  /// </summary>
  /// <value>The max transmit distance.</value>
public virtual float maxTransmitDistance public virtual float maxTransmitDistance
{ {
get; get;
set; set;
} }
   
/// <summary> /// <summary>
/// Gets a value indicating whether this <see cref="AntennaRange.ProtoDataTransmitter"/> has been checked during /// Gets a value indicating whether this <see cref="AntennaRange.ProtoDataTransmitter"/> has been checked during
/// the current relay attempt. /// the current relay attempt.
/// </summary> /// </summary>
/// <value><c>true</c> if relay checked; otherwise, <c>false</c>.</value> /// <value><c>true</c> if relay checked; otherwise, <c>false</c>.</value>
public virtual bool relayChecked public virtual bool relayChecked
{ {
get; get;
protected set; protected set;
} }
   
  /// <summary>
  /// 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 bool CanTransmit()
{ {
if (this.transmitDistance > this.maxTransmitDistance) if (this.transmitDistance > this.maxTransmitDistance)
{ {
return false; return false;
} }
else else
{ {
return true; return true;
} }
} }
   
/// <summary> /// <summary>
/// Finds the nearest relay. /// Finds the nearest relay.
/// </summary> /// </summary>
/// <returns>The nearest relay.</returns> /// <returns>The nearest relay or null, if no relays in range.</returns>
public IAntennaRelay FindNearestRelay() public IAntennaRelay FindNearestRelay()
{ {
  // Set this relay as checked, so that we don't check it again.
this.relayChecked = true; this.relayChecked = true;
   
  // Get a list of vessels within transmission range.
List<Vessel> nearbyVessels = FlightGlobals.Vessels List<Vessel> nearbyVessels = FlightGlobals.Vessels
.Where(v => (v.GetWorldPos3D() - vessel.GetWorldPos3D()).magnitude < this.maxTransmitDistance) .Where(v => (v.GetWorldPos3D() - vessel.GetWorldPos3D()).magnitude < this.maxTransmitDistance)
.ToList(); .ToList();
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Vessels in range: {1}", "{0}: Vessels in range: {1}",
this.GetType().Name, this.GetType().Name,
nearbyVessels.Count nearbyVessels.Count
)); ));
   
  // Remove this vessel.
nearbyVessels.RemoveAll(v => v.id == vessel.id); nearbyVessels.RemoveAll(v => v.id == vessel.id);
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Vessels in range excluding self: {1}", "{0}: Vessels in range excluding self: {1}",
this.GetType().Name, this.GetType().Name,
nearbyVessels.Count nearbyVessels.Count
)); ));
   
  // Get a flattened list of all IAntennaRelay modules and protomodules in transmission range.
List<IAntennaRelay> nearbyRelays = nearbyVessels.SelectMany(v => v.GetAntennaRelays()).ToList(); List<IAntennaRelay> nearbyRelays = nearbyVessels.SelectMany(v => v.GetAntennaRelays()).ToList();
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Found {1} nearby relays.", "{0}: Found {1} nearby relays.",
this.GetType().Name, this.GetType().Name,
nearbyRelays.Count nearbyRelays.Count
)); ));
   
  // Remove all relays already checked this time.
nearbyRelays.RemoveAll(r => r.relayChecked); nearbyRelays.RemoveAll(r => r.relayChecked);
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Found {1} nearby relays not already checked.", "{0}: Found {1} nearby relays not already checked.",
this.GetType().Name, this.GetType().Name,
nearbyRelays.Count nearbyRelays.Count
)); ));
   
  // Remove all relays that cannot transmit.
  // This call to r.CanTransmit() starts a depth-first recursive search for relays with a path back to Kerbin.
nearbyRelays.RemoveAll(r => !r.CanTransmit()); nearbyRelays.RemoveAll(r => !r.CanTransmit());
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Found {1} nearby relays not already checked that can transmit.", "{0}: Found {1} nearby relays not already checked that can transmit.",
this.GetType().Name, this.GetType().Name,
nearbyRelays.Count nearbyRelays.Count
)); ));
   
  // Sort the available relays by distance.
nearbyRelays.Sort(new RelayComparer(this.vessel)); nearbyRelays.Sort(new RelayComparer(this.vessel));
   
  // Get the nearest available relay, or null if there are no available relays nearby.
IAntennaRelay nearestRelay = nearbyRelays.FirstOrDefault(); IAntennaRelay nearestRelay = nearbyRelays.FirstOrDefault();
   
  // Now that we're done with our recursive CanTransmit checks, flag this relay as not checked so it can be
  // used next time.
this.relayChecked = false; this.relayChecked = false;
   
  // Return the nearest available relay, or null if there are no available relays nearby.
return nearestRelay; return nearestRelay;
} }
   
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AntennaRange.ProtoDataTransmitter"/> class. /// Initializes a new instance of the <see cref="AntennaRange.ProtoDataTransmitter"/> class.
/// </summary> /// </summary>
/// <param name="ms"><see cref="ProtoPartModuleSnapshot"/></param> /// <param name="ms"><see cref="ProtoPartModuleSnapshot"/></param>
public AntennaRelay(Vessel v) public AntennaRelay(Vessel v)
{ {
this.vessel = v; this.vessel = v;
   
  // HACK: This might not be safe in all circumstances, but since AntennaRelays are not built until Start,
  // we hope it is safe enough.
this.Kerbin = FlightGlobals.Bodies.FirstOrDefault(b => b.name == "Kerbin"); this.Kerbin = FlightGlobals.Bodies.FirstOrDefault(b => b.name == "Kerbin");
} }
   
  /*
  * Class implementing IComparer<IAntennaRelay> for use in sorting relays by distance.
  * */
internal class RelayComparer : IComparer<IAntennaRelay> internal class RelayComparer : IComparer<IAntennaRelay>
{ {
  /// <summary>
  /// The reference Vessel (usually the active vessel).
  /// </summary>
protected Vessel referenceVessel; protected Vessel referenceVessel;
   
  // We don't want no stinking public parameterless constructors.
private RelayComparer() {} private RelayComparer() {}
   
  /// <summary>
  /// Initializes a new instance of the <see cref="AntennaRange.AntennaRelay+RelayComparer"/> class for use
  /// in sorting relays by distance.
  /// </summary>
  /// <param name="reference">The reference Vessel</param>
public RelayComparer(Vessel reference) public RelayComparer(Vessel reference)
{ {
this.referenceVessel = reference; this.referenceVessel = reference;
} }
   
  /// <summary>
  /// Compare the <see cref="IAntennaRelay"/>s "one" and "two".
  /// </summary>
  /// <param name="one">The first IAntennaRelay in the comparison</param>
  /// <param name="two">The second IAntennaRelay in the comparison</param>
public int Compare(IAntennaRelay one, IAntennaRelay two) public int Compare(IAntennaRelay one, IAntennaRelay two)
{ {
double distanceOne; double distanceOne;
double distanceTwo; double distanceTwo;
   
distanceOne = one.vessel.DistanceTo(referenceVessel); distanceOne = one.vessel.DistanceTo(referenceVessel);
distanceTwo = two.vessel.DistanceTo(referenceVessel); distanceTwo = two.vessel.DistanceTo(referenceVessel);
   
return distanceOne.CompareTo(distanceTwo); return distanceOne.CompareTo(distanceTwo);
} }
} }
} }
} }