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); |
} |
} |
} |
} |
} |
} |
} |
} |
|
|
|
|