IAntennaRelays: Added nominalTransmitDistance.
--- a/ARConfiguration.cs
+++ b/ARConfiguration.cs
@@ -8,8 +8,6 @@
using ToadicusTools;
using UnityEngine;
-[assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)]
-
namespace AntennaRange
{
[KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
@@ -19,6 +17,22 @@
private Rect configWindowPos;
private IButton toolbarButton;
+
+ private System.Version runningVersion;
+
+ private KSP.IO.PluginConfiguration _config;
+ private KSP.IO.PluginConfiguration config
+ {
+ get
+ {
+ if (this._config == null)
+ {
+ this._config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>();
+ }
+
+ return this._config;
+ }
+ }
public void Awake()
{
@@ -32,8 +46,11 @@
public void OnGUI()
{
+ // Only runs once, if the Toolbar is available.
if (this.toolbarButton == null && ToolbarManager.ToolbarAvailable)
{
+ this.runningVersion = this.GetType().Assembly.GetName().Version;
+
Tools.PostDebugMessage(this, "Toolbar available; initializing button.");
this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConfiguration");
@@ -46,14 +63,13 @@
this.showConfigWindow = !this.showConfigWindow;
};
- var config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>();
+ this.configWindowPos = this.LoadConfigValue("configWindowPos", this.configWindowPos);
+ AntennaRelay.requireLineOfSight = this.LoadConfigValue("requireLineOfSight", false);
+ ARFlightController.requireConnectionForControl =
+ this.LoadConfigValue("requireConnectionForControl", false);
+ ModuleLimitedDataTransmitter.fixedPowerCost = this.LoadConfigValue("fixedPowerCost", false);
- config.load();
-
- this.configWindowPos = config.GetValue<Rect>("configWindowPos", this.configWindowPos);
- AntennaRelay.requireLineOfSight = config.GetValue<bool>("requireLineOfSight", false);
-
- config.save();
+ Debug.Log(string.Format("{0} v{1} - ARonfiguration loaded!", this.GetType().Name, this.runningVersion));
}
if (this.showConfigWindow)
@@ -61,7 +77,7 @@
Rect configPos = GUILayout.Window(354163056,
this.configWindowPos,
this.ConfigWindow,
- "AntennaRange Configuration",
+ string.Format("AntennaRange {0}.{1}", this.runningVersion.Major, this.runningVersion.Minor),
GUILayout.ExpandHeight(true),
GUILayout.ExpandWidth(true)
);
@@ -81,11 +97,38 @@
GUILayout.BeginVertical(GUILayout.ExpandHeight(true));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
bool requireLineOfSight = GUILayout.Toggle(AntennaRelay.requireLineOfSight, "Require Line of Sight");
if (requireLineOfSight != AntennaRelay.requireLineOfSight)
{
AntennaRelay.requireLineOfSight = requireLineOfSight;
this.SaveConfigValue("requireLineOfSight", requireLineOfSight);
+ }
+
+ GUILayout.EndHorizontal();
+
+ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
+ bool requireConnectionForControl =
+ GUILayout.Toggle(
+ ARFlightController.requireConnectionForControl,
+ "Require Connection for Probe Control"
+ );
+ if (requireConnectionForControl != ARFlightController.requireConnectionForControl)
+ {
+ ARFlightController.requireConnectionForControl = requireConnectionForControl;
+ this.SaveConfigValue("requireConnectionForControl", requireConnectionForControl);
+ }
+
+ GUILayout.EndHorizontal();
+
+ GUILayout.BeginHorizontal();
+
+ bool fixedPowerCost = GUILayout.Toggle(ModuleLimitedDataTransmitter.fixedPowerCost, "Use fixed power cost");
+ if (fixedPowerCost != ModuleLimitedDataTransmitter.fixedPowerCost)
+ {
+ ModuleLimitedDataTransmitter.fixedPowerCost = fixedPowerCost;
+ this.SaveConfigValue("fixedPowerCost", fixedPowerCost);
}
GUILayout.EndHorizontal();
@@ -105,22 +148,18 @@
private T LoadConfigValue<T>(string key, T defaultValue)
{
- var config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>();
-
- config.load();
+ this.config.load();
return config.GetValue(key, defaultValue);
}
private void SaveConfigValue<T>(string key, T value)
{
- var config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>();
+ this.config.load();
- config.load();
+ this.config.SetValue(key, value);
- config.SetValue(key, value);
-
- config.save();
+ this.config.save();
}
}
}
--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -25,14 +25,253 @@
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using KSP;
using System;
+using System.Collections.Generic;
+using ToadicusTools;
+using UnityEngine;
namespace AntennaRange
{
- public class ARFlightController
+ [KSPAddon(KSPAddon.Startup.Flight, false)]
+ public class ARFlightController : MonoBehaviour
{
- public ARFlightController()
- {
+ #region Static Members
+ public static bool requireConnectionForControl;
+ #endregion
+
+ #region Fields
+ protected Dictionary<ConnectionStatus, string> connectionTextures;
+
+ protected ARMapRenderer mapRenderer;
+
+ protected IButton toolbarButton;
+ #endregion
+
+ #region Properties
+ public ConnectionStatus currentConnectionStatus
+ {
+ get;
+ protected set;
+ }
+
+ protected string currentConnectionTexture
+ {
+ get
+ {
+ return this.connectionTextures[this.currentConnectionStatus];
+ }
+ }
+
+ public ControlTypes currentControlLock
+ {
+ get
+ {
+ if (this.lockID == string.Empty)
+ {
+ return ControlTypes.None;
+ }
+
+ return InputLockManager.GetControlLock(this.lockID);
+ }
+ }
+
+ public string lockID
+ {
+ get;
+ protected set;
+ }
+
+ public ControlTypes lockSet
+ {
+ get
+ {
+ return ControlTypes.ALL_SHIP_CONTROLS;
+ }
+ }
+
+ public Vessel vessel
+ {
+ get
+ {
+ if (FlightGlobals.ready && FlightGlobals.ActiveVessel != null)
+ {
+ return FlightGlobals.ActiveVessel;
+ }
+
+ return null;
+ }
+ }
+ #endregion
+
+ #region MonoBehaviour LifeCycle
+ protected void Awake()
+ {
+ this.lockID = "ARConnectionRequired";
+
+ if (ToolbarManager.ToolbarAvailable)
+ {
+ this.connectionTextures = new Dictionary<ConnectionStatus, string>();
+
+ this.connectionTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection";
+ this.connectionTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal";
+ this.connectionTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon";
+
+ this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus");
+
+ this.toolbarButton.TexturePath = this.connectionTextures[ConnectionStatus.None];
+ this.toolbarButton.Text = "AntennaRange";
+ this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT);
+ this.toolbarButton.Enabled = false;
+ }
+
+ GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
+ GameEvents.onVesselChange.Add(this.onVesselChange);
+ }
+
+ protected void Start()
+ {
+ this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>();
+ }
+
+ protected void FixedUpdate()
+ {
+ Tools.DebugLogger log = Tools.DebugLogger.New(this);
+
+ // If we are requiring a connection for control, the vessel does not have any adequately staffed pods,
+ // and the vessel does not have any connected relays...
+ if (
+ HighLogic.LoadedSceneIsFlight &&
+ requireConnectionForControl &&
+ this.vessel != null &&
+ this.vessel.vesselType != VesselType.EVA &&
+ !this.vessel.hasCrewCommand() &&
+ !this.vessel.HasConnectedRelay())
+ {
+ // ...and if the controls are not currently locked...
+ if (currentControlLock == ControlTypes.None)
+ {
+ // ...lock the controls.
+ InputLockManager.SetControlLock(this.lockSet, this.lockID);
+ }
+ }
+ // ...otherwise, if the controls are locked...
+ else if (currentControlLock != ControlTypes.None)
+ {
+ // ...unlock the controls.
+ InputLockManager.RemoveControlLock(this.lockID);
+ }
+
+ if (HighLogic.LoadedSceneIsFlight && this.toolbarButton != null && FlightGlobals.ActiveVessel != null)
+ {
+ log.Append("Checking vessel relay status.\n");
+
+ List<ModuleLimitedDataTransmitter> relays =
+ FlightGlobals.ActiveVessel.getModulesOfType<ModuleLimitedDataTransmitter>();
+
+ log.AppendFormat("\t...found {0} relays\n", relays.Count);
+
+ bool vesselCanTransmit = false;
+ bool vesselHasOptimalRelay = false;
+
+ foreach (ModuleLimitedDataTransmitter relay in relays)
+ {
+ log.AppendFormat("\tvesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n",
+ vesselCanTransmit, vesselHasOptimalRelay);
+
+ log.AppendFormat("\tChecking relay {0}\n" +
+ "\t\tCanTransmit: {1}, transmitDistance: {2}, nominalRange: {3}\n",
+ relay,
+ relay.CanTransmit(),
+ relay.transmitDistance,
+ relay.nominalRange
+ );
+
+ bool relayCanTransmit = relay.CanTransmit();
+
+ if (!vesselCanTransmit && relayCanTransmit)
+ {
+ vesselCanTransmit = true;
+ }
+
+ if (!vesselHasOptimalRelay &&
+ relayCanTransmit &&
+ relay.transmitDistance <= (double)relay.nominalRange)
+ {
+ vesselHasOptimalRelay = true;
+ }
+
+ if (vesselCanTransmit && vesselHasOptimalRelay)
+ {
+ break;
+ }
+ }
+
+ log.AppendFormat("Done checking. vesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n",
+ vesselCanTransmit, vesselHasOptimalRelay);
+
+ if (vesselHasOptimalRelay)
+ {
+ this.currentConnectionStatus = ConnectionStatus.Optimal;
+ }
+ else if (vesselCanTransmit)
+ {
+ this.currentConnectionStatus = ConnectionStatus.Suboptimal;
+ }
+ else
+ {
+ this.currentConnectionStatus = ConnectionStatus.None;
+ }
+
+ log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
+ this.currentConnectionStatus, this.currentConnectionTexture);
+
+ this.toolbarButton.TexturePath = this.currentConnectionTexture;
+ }
+
+ log.Print();
+ }
+
+ protected void Destroy()
+ {
+ InputLockManager.RemoveControlLock(this.lockID);
+
+ if (this.toolbarButton != null)
+ {
+ this.toolbarButton.Destroy();
+ }
+
+ if (this.mapRenderer != null)
+ {
+ GameObject.Destroy(this.mapRenderer);
+ }
+
+ GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
+ GameEvents.onVesselChange.Remove(this.onVesselChange);
+ }
+ #endregion
+
+ #region Event Handlers
+ protected void onSceneChangeRequested(GameScenes scene)
+ {
+ if (scene != GameScenes.FLIGHT)
+ {
+ MonoBehaviour.DestroyImmediate(this, true);
+ }
+ }
+
+ protected void onVesselChange(Vessel vessel)
+ {
+ InputLockManager.RemoveControlLock(this.lockID);
+ }
+ #endregion
+
+ public enum ConnectionStatus
+ {
+ None,
+ Suboptimal,
+ Optimal
}
}
}
--- /dev/null
+++ b/ARMapRenderer.cs
@@ -1,1 +1,257 @@
-
+// AntennaRange
+//
+// ARMapRenderer.cs
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be used
+// to endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using KSP;
+using System;
+using System.Collections.Generic;
+using ToadicusTools;
+using UnityEngine;
+
+namespace AntennaRange
+{
+ public class ARMapRenderer : MonoBehaviour
+ {
+ #region Fields
+ private Dictionary<Guid, LineRenderer> vesselLineRenderers;
+ private Dictionary<Guid, bool> vesselFrameCache;
+ #endregion
+
+ #region Properties
+ public LineRenderer this[Guid idx]
+ {
+ get
+ {
+ if (this.vesselLineRenderers == null)
+ {
+ this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>();
+ }
+
+ if (!this.vesselLineRenderers.ContainsKey(idx))
+ {
+ GameObject obj = new GameObject();
+ obj.layer = 31;
+
+ LineRenderer lr = obj.AddComponent<LineRenderer>();
+
+ lr.SetColors(Color.green, Color.green);
+ lr.material = new Material(Shader.Find("Particles/Additive"));
+ lr.SetVertexCount(2);
+
+ this.vesselLineRenderers[idx] = lr;
+ }
+
+ return this.vesselLineRenderers[idx];
+ }
+ }
+ #endregion
+
+ #region MonoBehaviour Lifecycle
+ private void Awake()
+ {
+ this.vesselFrameCache = new Dictionary<Guid, bool>();
+ }
+
+ private void OnPreCull()
+ {
+ if (!HighLogic.LoadedSceneIsFlight || !MapView.MapIsEnabled)
+ {
+ return;
+ }
+
+ Tools.DebugLogger log = Tools.DebugLogger.New(this);
+
+ try
+ {
+ log.AppendFormat("OnPreCull.\n");
+
+ double sma;
+
+ switch (MapView.MapCamera.target.type)
+ {
+ case MapObject.MapObjectType.CELESTIALBODY:
+ sma = MapView.MapCamera.target.celestialBody.orbit.semiMajorAxis;
+ break;
+ case MapObject.MapObjectType.VESSEL:
+ sma = MapView.MapCamera.target.vessel.orbit.semiMajorAxis;
+ break;
+ default:
+ sma = ScaledSpace.ScaleFactor;
+ break;
+ }
+
+ log.AppendFormat("\tMapView: Draw3DLines: {0}\n" +
+ "\tMapView.MapCamera.camera.fieldOfView: {1}\n" +
+ "\tMapView.MapCamera.Distance: {2}\n" +
+ "\tDistanceVSSMAFactor: {3}\n",
+ MapView.Draw3DLines,
+ MapView.MapCamera.camera.fieldOfView,
+ MapView.MapCamera.Distance,
+ (float)((double)MapView.MapCamera.Distance / Math.Abs(sma) * ScaledSpace.InverseScaleFactor)
+ );
+
+ this.vesselFrameCache.Clear();
+
+ log.AppendLine("vesselFrameCache cleared.");
+
+ if (FlightGlobals.ready && FlightGlobals.Vessels != null)
+ {
+ log.AppendLine("FlightGlobals ready and Vessels list not null.");
+
+ foreach (Vessel vessel in FlightGlobals.Vessels)
+ {
+ if (vessel == null)
+ {
+ log.AppendFormat("Skipping vessel {0} altogether because it is null.\n");
+ continue;
+ }
+
+ log.AppendFormat("Checking vessel {0}.\n", vessel.vesselName);
+
+ switch (vessel.vesselType)
+ {
+ case VesselType.Debris:
+ case VesselType.EVA:
+ case VesselType.Unknown:
+ case VesselType.SpaceObject:
+ log.AppendFormat("\tDiscarded because vessel is of invalid type {0}\n",
+ vessel.vesselType);
+ continue;
+ }
+
+ if (vessel.HasConnectedRelay())
+ {
+ log.AppendLine("\tHas a connection, checking for the best relay to use for the line.");
+
+ IAntennaRelay vesselRelay = null;
+ float bestScore = float.PositiveInfinity;
+ float relayScore = float.NaN;
+
+ foreach (IAntennaRelay relay in RelayDatabase.Instance[vessel].Values)
+ {
+ relayScore = (float)relay.transmitDistance / relay.maxTransmitDistance;
+
+ if (relayScore < bestScore)
+ {
+ bestScore = relayScore;
+ vesselRelay = relay as IAntennaRelay;
+ }
+ }
+
+ if (vesselRelay != null)
+ {
+ log.AppendFormat("\t...picked relay {0} with a score of {1}",
+ vesselRelay, relayScore
+ );
+
+ this.SetRelayVertices(vesselRelay);
+ }
+ }
+ else if (this.vesselLineRenderers.ContainsKey(vessel.id))
+ {
+ log.AppendLine("\tDisabling line because vessel has no connection.");
+ this[vessel.id].enabled = false;
+ }
+ }
+ }
+ }
+ finally
+ {
+ log.Print();
+ }
+ }
+
+ private void Destroy()
+ {
+ this.vesselLineRenderers.Clear();
+ this.vesselLineRenderers = null;
+ }
+ #endregion
+
+ private void SetRelayVertices(IAntennaRelay relay)
+ {
+ do
+ {
+ if (this.vesselFrameCache.ContainsKey(relay.vessel.id))
+ {
+ break;
+ }
+
+ LineRenderer renderer = this[relay.vessel.id];
+
+ if (relay.CanTransmit())
+ {
+ Vector3d start;
+ Vector3d end;
+
+ renderer.enabled = true;
+
+ start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
+
+ if (relay.nearestRelay == null)
+ {
+ end = ScaledSpace.LocalToScaledSpace(AntennaRelay.Kerbin.position);
+ }
+ else
+ {
+ end = ScaledSpace.LocalToScaledSpace(relay.nearestRelay.vessel.GetWorldPos3D());
+ }
+
+ float lineWidth;
+
+ if (MapView.Draw3DLines)
+ {
+ lineWidth = 0.002f * MapView.MapCamera.Distance;
+ }
+ else
+ {
+ lineWidth = 1f;
+
+ start = MapView.MapCamera.camera.WorldToScreenPoint(start);
+ end = MapView.MapCamera.camera.WorldToScreenPoint(end);
+
+ float d = Screen.height / 2f + 0.01f;
+ start.z = start.z >= 0.15f ? d : -d;
+ end.z = end.z >= 0.15f ? d : -d;
+ }
+
+ renderer.SetWidth(lineWidth, lineWidth);
+
+ renderer.SetPosition(0, start);
+ renderer.SetPosition(1, end);
+
+ this.vesselFrameCache[relay.vessel.id] = true;
+
+ relay = relay.nearestRelay;
+ }
+ }
+ while (relay != null);
+ }
+ }
+}
+
+
--- a/AntennaRange.csproj
+++ b/AntennaRange.csproj
@@ -12,6 +12,7 @@
<ReleaseVersion>1.1</ReleaseVersion>
<SynchReleaseVersion>false</SynchReleaseVersion>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <UseMSBuildEngine>False</UseMSBuildEngine>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -79,6 +80,7 @@
<Compile Include="RelayExtensions.cs" />
<Compile Include="ARConfiguration.cs" />
<Compile Include="ARFlightController.cs" />
+ <Compile Include="ARMapRenderer.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -87,20 +89,23 @@
</None>
</ItemGroup>
<ItemGroup>
+ <Reference Include="Assembly-CSharp">
+ <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="System">
+ <HintPath>..\_KSPAssemblies\System.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="UnityEngine">
+ <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
<ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj">
<Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project>
<Name>ToadicusTools</Name>
</ProjectReference>
</ItemGroup>
- <ItemGroup>
- <Reference Include="Assembly-CSharp">
- <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
- </Reference>
- <Reference Include="System">
- <HintPath>..\_KSPAssemblies\System.dll</HintPath>
- </Reference>
- <Reference Include="UnityEngine">
- <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
- </Reference>
- </ItemGroup>
</Project>
--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -38,7 +38,9 @@
public static bool requireLineOfSight;
// We don't have a Bard, so we'll hide Kerbin here.
- protected CelestialBody Kerbin;
+ public static CelestialBody Kerbin;
+
+ protected CelestialBody _firstOccludingBody;
protected IAntennaRelay _nearestRelayCache;
protected IAntennaRelay moduleRef;
@@ -82,6 +84,18 @@
}
/// <summary>
+ /// Gets the first occluding body.
+ /// </summary>
+ /// <value>The first occluding body.</value>
+ public CelestialBody firstOccludingBody
+ {
+ get
+ {
+ return this._firstOccludingBody;
+ }
+ }
+
+ /// <summary>
/// Gets the transmit distance.
/// </summary>
/// <value>The transmit distance.</value>
@@ -95,7 +109,7 @@
if (this.nearestRelay == null)
{
// .. return the distance to Kerbin
- return this.DistanceTo(this.Kerbin);
+ return this.DistanceTo(Kerbin);
}
else
{
@@ -105,6 +119,12 @@
}
}
+ public virtual double nominalTransmitDistance
+ {
+ get;
+ set;
+ }
+
/// <summary>
/// The maximum distance at which this relay can operate.
/// </summary>
@@ -134,7 +154,11 @@
{
if (
this.transmitDistance > this.maxTransmitDistance ||
- (requireLineOfSight && this.nearestRelay == null && !this.vessel.hasLineOfSightTo(this.Kerbin))
+ (
+ requireLineOfSight &&
+ this.nearestRelay == null &&
+ !this.vessel.hasLineOfSightTo(Kerbin, out this._firstOccludingBody)
+ )
)
{
return false;
@@ -170,6 +194,8 @@
this,
this.vessel.id
));
+
+ this._firstOccludingBody = null;
// Set this vessel as checked, so that we don't check it again.
RelayDatabase.Instance.CheckedVesselsTable[vessel.id] = true;
@@ -211,7 +237,7 @@
}
// Skip vessels to which we do not have line of sight.
- if (requireLineOfSight && !this.vessel.hasLineOfSightTo(potentialVessel))
+ if (requireLineOfSight && !this.vessel.hasLineOfSightTo(potentialVessel, out this._firstOccludingBody))
{
Tools.PostDebugMessage(
this,
@@ -278,11 +304,14 @@
this.moduleRef = module;
this.searchTimer = new System.Diagnostics.Stopwatch();
- this.millisecondsBetweenSearches = 5000;
+ this.millisecondsBetweenSearches = 1250;
// 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");
+ if (AntennaRelay.Kerbin == null)
+ {
+ AntennaRelay.Kerbin = FlightGlobals.Bodies.FirstOrDefault(b => b.name == "Kerbin");
+ }
}
static AntennaRelay()
--- a/IAntennaRelay.cs
+++ b/IAntennaRelay.cs
@@ -42,11 +42,15 @@
/// <value>The parent Vessel.</value>
Vessel vessel { get; }
+ IAntennaRelay nearestRelay { get; }
+
/// <summary>
/// Gets the distance to the nearest relay or Kerbin, whichever is closer.
/// </summary>
/// <value>The distance to the nearest relay or Kerbin, whichever is closer.</value>
double transmitDistance { get; }
+
+ double nominalTransmitDistance { get; }
/// <summary>
/// The maximum distance at which this relay can operate.
--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -54,6 +54,10 @@
* */
public class ModuleLimitedDataTransmitter : ModuleDataTransmitter, IScienceDataTransmitter, IAntennaRelay
{
+ // If true, use a fixed power cost at the configured value and degrade data rates instead of increasing power
+ // requirements.
+ public static bool fixedPowerCost;
+
// Stores the packetResourceCost as defined in the .cfg file.
protected float _basepacketResourceCost;
@@ -73,6 +77,9 @@
// and packetSize.
[KSPField(isPersistant = false)]
public float nominalRange;
+
+ [KSPField(isPersistant = false, guiActive = true, guiName = "Relay")]
+ public string UIrelayStatus;
[KSPField(isPersistant = false, guiActive = true, guiName = "Transmission Distance")]
public string UItransmitDistance;
@@ -119,12 +126,33 @@
}
}
+ public IAntennaRelay nearestRelay
+ {
+ get
+ {
+ if (this.relay == null)
+ {
+ return null;
+ }
+
+ return this.relay.nearestRelay;
+ }
+ }
+
// Returns the distance to the nearest relay or Kerbin, whichever is closer.
public double transmitDistance
{
get
{
return this.relay.transmitDistance;
+ }
+ }
+
+ public double nominalTransmitDistance
+ {
+ get
+ {
+ return this.nominalRange;
}
}
@@ -229,6 +257,7 @@
{
this.relay = new AntennaRelay(this);
this.relay.maxTransmitDistance = this.maxTransmitDistance;
+ this.relay.nominalTransmitDistance = this.nominalRange;
this.UImaxTransmitDistance = Tools.MuMech_ToSI(this.maxTransmitDistance) + "m";
@@ -291,7 +320,7 @@
// transmission fails (see CanTransmit).
protected void PreTransmit_SetPacketResourceCost()
{
- if (this.transmitDistance <= this.nominalRange)
+ if (fixedPowerCost || this.transmitDistance <= this.nominalRange)
{
base.packetResourceCost = this._basepacketResourceCost;
}
@@ -300,13 +329,15 @@
base.packetResourceCost = this._basepacketResourceCost
* (float)Math.Pow (this.transmitDistance / this.nominalRange, 2);
}
+
+ base.packetResourceCost *= this.packetThrottle / 100f;
}
// Before transmission, set packetSize. Per above, packet size increases with the inverse square of
// distance. packetSize maxes out at _basepacketSize * maxDataFactor.
protected void PreTransmit_SetPacketSize()
{
- if (this.transmitDistance >= this.nominalRange)
+ if (!fixedPowerCost && this.transmitDistance >= this.nominalRange)
{
base.packetSize = this._basepacketSize;
}
@@ -332,6 +363,11 @@
// Override ModuleDataTransmitter.CanTransmit to return false when transmission is not possible.
public new bool CanTransmit()
{
+ if (this.relay == null)
+ {
+ return false;
+ }
+
PartStates partState = this.part.State;
if (partState == PartStates.DEAD || partState == PartStates.DEACTIVATED)
{
@@ -437,9 +473,27 @@
{
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";
+ if (this.CanTransmit())
+ {
+ this.UIrelayStatus = string.Intern("Connected");
+ this.UItransmitDistance = Tools.MuMech_ToSI(this.transmitDistance) + "m";
+ this.UIpacketSize = Tools.MuMech_ToSI(this.DataRate) + "MiT";
+ this.UIpacketCost = Tools.MuMech_ToSI(this.DataResourceCost) + "E";
+ }
+ else
+ {
+ if (this.relay.firstOccludingBody == null)
+ {
+ this.UIrelayStatus = string.Intern("Out of range");
+ }
+ else
+ {
+ this.UIrelayStatus = string.Format("Blocked by {0}", this.relay.firstOccludingBody.bodyName);
+ }
+ this.UImaxTransmitDistance = "N/A";
+ this.UIpacketSize = "N/A";
+ this.UIpacketCost = "N/A";
+ }
}
}
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -29,6 +29,8 @@
using System.Reflection;
using System.Runtime.CompilerServices;
+[assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)]
+
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("AntennaRange")]
@@ -37,10 +39,9 @@
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("1.1.*")]
+[assembly: AssemblyVersion("1.2.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]
-
--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -47,6 +47,14 @@
get
{
return this.protoPart.pVesselRef.vesselRef;
+ }
+ }
+
+ public override double nominalTransmitDistance
+ {
+ get
+ {
+ return this.moduleRef.nominalTransmitDistance;
}
}
--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -76,6 +76,24 @@
{
return RelayDatabase.Instance[vessel].Values.ToList();
}
+
+ /// <summary>
+ /// Determines if the specified vessel has a connected relay.
+ /// </summary>
+ /// <returns><c>true</c> if the specified vessel has a connected relay; otherwise, <c>false</c>.</returns>
+ /// <param name="vessel"></param>
+ public static bool HasConnectedRelay(this Vessel vessel)
+ {
+ foreach (IAntennaRelay relay in RelayDatabase.Instance[vessel].Values)
+ {
+ if (relay.CanTransmit())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
}
Binary files /dev/null and b/toolbarIcon.xcf differ