ARFlightController: Added pretty-lines toggle functionality to the map mode buttons.
ARFlightController: Added pretty-lines toggle functionality to the map mode buttons.

// AntennaRange © 2014 toadicus // AntennaRange © 2014 toadicus
// //
// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a // This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ // copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
   
using KSP; using KSP;
using System; using System;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace AntennaRange namespace AntennaRange
{ {
/// <summary> /// <summary>
/// A <see cref="UnityEngine.MonoBehaviour"/> responsible for managing configuration items for AntennaRange. /// A <see cref="UnityEngine.MonoBehaviour"/> responsible for managing configuration items for AntennaRange.
/// </summary> /// </summary>
[KSPAddon(KSPAddon.Startup.SpaceCentre, false)] [KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
public class ARConfiguration : MonoBehaviour public class ARConfiguration : MonoBehaviour
{ {
  private const string WINDOW_POS_KEY = "configWindowPos";
  private const string REQUIRE_LOS_KEY = "requireLineOfSight";
  private const string GRACE_RATIO_KEY = "graceRatio";
  private const string REQUIRE_PROBE_CONNECTION_KEY = "requireConnectionForControl";
  private const string FIXED_POWER_KEY = "fixedPowerCost";
  private const string PRETTY_LINES_KEY = "drawPrettyLines";
  private const string UPDATE_DELAY_KEY = "updateDelay";
   
/// <summary> /// <summary>
/// Indicates whether connections require line of sight. /// Indicates whether connections require line of sight.
/// </summary> /// </summary>
public static bool RequireLineOfSight public static bool RequireLineOfSight
{ {
get; get;
private set; private set;
} }
   
/// <summary> /// <summary>
/// A "fudge factor" ratio that pretends planets and moons are slightly smaller than reality to make /// A "fudge factor" ratio that pretends planets and moons are slightly smaller than reality to make
/// building communication constellations easier. /// building communication constellations easier.
/// </summary> /// </summary>
public static double RadiusRatio public static double RadiusRatio
{ {
get; get;
private set; private set;
} }
   
/// <summary> /// <summary>
/// Indicates whether unmanned vessels require a connection for control. /// Indicates whether unmanned vessels require a connection for control.
/// </summary> /// </summary>
public static bool RequireConnectionForControl public static bool RequireConnectionForControl
{ {
get; get;
private set; private set;
} }
   
/// <summary> /// <summary>
/// If true, relays will fix their power cost when above nominal range, decreasing data rate instead. /// If true, relays will fix their power cost when above nominal range, decreasing data rate instead.
/// </summary> /// </summary>
public static bool FixedPowerCost public static bool FixedPowerCost
{ {
get; get;
private set; private set;
} }
   
/// <summary> /// <summary>
/// Indicates whether this AntennaRange will draw pretty lines in map view. /// Indicates whether this AntennaRange will draw pretty lines in map view.
/// </summary> /// </summary>
public static bool PrettyLines public static bool PrettyLines
{ {
get; get;
  set;
  }
   
  public static long UpdateDelay
  {
  get;
private set; private set;
} }
   
#pragma warning disable 1591 #pragma warning disable 1591
   
private bool showConfigWindow; private bool showConfigWindow;
private Rect configWindowPos; private Rect configWindowPos;
   
  private string updateDelayStr;
  private long updateDelay;
   
private IButton toolbarButton; private IButton toolbarButton;
private ApplicationLauncherButton appLauncherButton; private ApplicationLauncherButton appLauncherButton;
   
private System.Version runningVersion; private System.Version runningVersion;
   
private KSP.IO.PluginConfiguration _config; private KSP.IO.PluginConfiguration _config;
private KSP.IO.PluginConfiguration config private KSP.IO.PluginConfiguration config
{ {
get get
{ {
if (this._config == null) if (this._config == null)
{ {
this._config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>(); this._config = KSP.IO.PluginConfiguration.CreateForType<AntennaRelay>();
} }
   
return this._config; return this._config;
} }
} }
   
public void Awake() public void Awake()
{ {
Tools.PostDebugMessage(this, "Waking up."); Tools.PostDebugMessage(this, "Waking up.");
   
this.runningVersion = this.GetType().Assembly.GetName().Version; this.runningVersion = this.GetType().Assembly.GetName().Version;
   
this.showConfigWindow = false; this.showConfigWindow = false;
this.configWindowPos = new Rect(Screen.width / 4, Screen.height / 2, 180, 15); this.configWindowPos = new Rect(Screen.width / 4, Screen.height / 2, 180, 15);
   
   
this.configWindowPos = this.LoadConfigValue("configWindowPos", this.configWindowPos); this.configWindowPos = this.LoadConfigValue(WINDOW_POS_KEY, this.configWindowPos);
   
ARConfiguration.RequireLineOfSight = this.LoadConfigValue("requireLineOfSight", false); ARConfiguration.RequireLineOfSight = this.LoadConfigValue(REQUIRE_LOS_KEY, false);
   
ARConfiguration.RadiusRatio = (1 - this.LoadConfigValue("graceRatio", .05d)); ARConfiguration.RadiusRatio = (1 - this.LoadConfigValue(GRACE_RATIO_KEY, .05d));
ARConfiguration.RadiusRatio *= ARConfiguration.RadiusRatio; ARConfiguration.RadiusRatio *= ARConfiguration.RadiusRatio;
   
ARConfiguration.RequireConnectionForControl = ARConfiguration.RequireConnectionForControl =
this.LoadConfigValue("requireConnectionForControl", false); this.LoadConfigValue(REQUIRE_PROBE_CONNECTION_KEY, false);
   
ARConfiguration.FixedPowerCost = this.LoadConfigValue("fixedPowerCost", false); ARConfiguration.FixedPowerCost = this.LoadConfigValue(FIXED_POWER_KEY, false);
   
ARConfiguration.PrettyLines = this.LoadConfigValue("drawPrettyLines", true); ARConfiguration.PrettyLines = this.LoadConfigValue(PRETTY_LINES_KEY, true);
   
  ARConfiguration.UpdateDelay = this.LoadConfigValue(UPDATE_DELAY_KEY, 16L);
   
  this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
   
GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
   
Debug.Log(string.Format("{0} v{1} - ARConfiguration loaded!", this.GetType().Name, this.runningVersion)); Debug.Log(string.Format("{0} v{1} - ARConfiguration loaded!", this.GetType().Name, this.runningVersion));
   
Tools.PostDebugMessage(this, "Awake."); Tools.PostDebugMessage(this, "Awake.");
} }
   
public void OnGUI() public void OnGUI()
{ {
// Only runs once, if the Toolbar is available. // Only runs once, if the Toolbar is available.
if (ToolbarManager.ToolbarAvailable) if (ToolbarManager.ToolbarAvailable)
{ {
if (this.toolbarButton == null) if (this.toolbarButton == null)
{ {
Tools.PostDebugMessage(this, "Toolbar available; initializing toolbar button."); Tools.PostDebugMessage(this, "Toolbar available; initializing toolbar button.");
   
this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConfiguration"); this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConfiguration");
this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.SPACECENTER); this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.SPACECENTER);
this.toolbarButton.Text = "AR"; this.toolbarButton.Text = "AR";
this.toolbarButton.TexturePath = "AntennaRange/Textures/toolbarIcon"; this.toolbarButton.TexturePath = "AntennaRange/Textures/toolbarIcon";
this.toolbarButton.TextColor = (Color)XKCDColors.Amethyst; this.toolbarButton.TextColor = (Color)XKCDColors.Amethyst;
this.toolbarButton.OnClick += delegate(ClickEvent e) this.toolbarButton.OnClick += delegate(ClickEvent e)
{ {
this.toggleConfigWindow(); this.toggleConfigWindow();
}; };
} }
} }
else if (this.appLauncherButton == null && ApplicationLauncher.Ready) else if (this.appLauncherButton == null && ApplicationLauncher.Ready)
{ {
Tools.PostDebugMessage(this, "Toolbar available; initializing AppLauncher button."); Tools.PostDebugMessage(this, "Toolbar available; initializing AppLauncher button.");
   
this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication( this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication(
this.toggleConfigWindow, this.toggleConfigWindow,
this.toggleConfigWindow, this.toggleConfigWindow,
ApplicationLauncher.AppScenes.SPACECENTER, ApplicationLauncher.AppScenes.SPACECENTER,
GameDatabase.Instance.GetTexture( GameDatabase.Instance.GetTexture(
"AntennaRange/Textures/appLauncherIcon", "AntennaRange/Textures/appLauncherIcon",
false false
) )
); );
} }
   
if (this.showConfigWindow) if (this.showConfigWindow)
{ {
Rect configPos = GUILayout.Window(354163056, Rect configPos = GUILayout.Window(354163056,
this.configWindowPos, this.configWindowPos,
this.ConfigWindow, this.ConfigWindow,
string.Format("AntennaRange {0}.{1}", this.runningVersion.Major, this.runningVersion.Minor), string.Format("AntennaRange {0}.{1}", this.runningVersion.Major, this.runningVersion.Minor),
GUILayout.ExpandHeight(true), GUILayout.ExpandHeight(true),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
   
configPos = Tools.ClampRectToScreen(configPos, 20); configPos = Tools.ClampRectToScreen(configPos, 20);
   
if (configPos != this.configWindowPos) if (configPos != this.configWindowPos)
{ {
this.configWindowPos = configPos; this.configWindowPos = configPos;
this.SaveConfigValue("configWindowPos", this.configWindowPos); this.SaveConfigValue(WINDOW_POS_KEY, this.configWindowPos);
} }
} }
} }
   
public void ConfigWindow(int _) public void ConfigWindow(int _)
{ {
GUILayout.BeginVertical(GUILayout.ExpandHeight(true)); GUILayout.BeginVertical(GUILayout.ExpandHeight(true));
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
bool requireLineOfSight = GUITools.Toggle(ARConfiguration.RequireLineOfSight, "Require Line of Sight"); bool requireLineOfSight = GUITools.Toggle(ARConfiguration.RequireLineOfSight, "Require Line of Sight");
if (requireLineOfSight != ARConfiguration.RequireLineOfSight) if (requireLineOfSight != ARConfiguration.RequireLineOfSight)
{ {
ARConfiguration.RequireLineOfSight = requireLineOfSight; ARConfiguration.RequireLineOfSight = requireLineOfSight;
this.SaveConfigValue("requireLineOfSight", requireLineOfSight); this.SaveConfigValue(REQUIRE_LOS_KEY, requireLineOfSight);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
bool requireConnectionForControl = bool requireConnectionForControl =
GUITools.Toggle( GUITools.Toggle(
ARConfiguration.RequireConnectionForControl, ARConfiguration.RequireConnectionForControl,
"Require Connection for Probe Control" "Require Connection for Probe Control"
); );
if (requireConnectionForControl != ARConfiguration.RequireConnectionForControl) if (requireConnectionForControl != ARConfiguration.RequireConnectionForControl)
{ {
ARConfiguration.RequireConnectionForControl = requireConnectionForControl; ARConfiguration.RequireConnectionForControl = requireConnectionForControl;
this.SaveConfigValue("requireConnectionForControl", requireConnectionForControl); this.SaveConfigValue(REQUIRE_PROBE_CONNECTION_KEY, requireConnectionForControl);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
   
bool fixedPowerCost = GUITools.Toggle(ARConfiguration.FixedPowerCost, "Use Fixed Power Cost"); bool fixedPowerCost = GUITools.Toggle(ARConfiguration.FixedPowerCost, "Use Fixed Power Cost");
if (fixedPowerCost != ARConfiguration.FixedPowerCost) if (fixedPowerCost != ARConfiguration.FixedPowerCost)
{ {
ARConfiguration.FixedPowerCost = fixedPowerCost; ARConfiguration.FixedPowerCost = fixedPowerCost;
this.SaveConfigValue("fixedPowerCost", fixedPowerCost); this.SaveConfigValue(FIXED_POWER_KEY, fixedPowerCost);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
   
bool prettyLines = GUITools.Toggle(ARConfiguration.PrettyLines, "Draw Pretty Lines"); bool prettyLines = GUITools.Toggle(ARConfiguration.PrettyLines, "Draw Pretty Lines");
if (prettyLines != ARConfiguration.PrettyLines) if (prettyLines != ARConfiguration.PrettyLines)
{ {
ARConfiguration.PrettyLines = prettyLines; ARConfiguration.PrettyLines = prettyLines;
this.SaveConfigValue("drawPrettyLines", prettyLines); this.SaveConfigValue(PRETTY_LINES_KEY, prettyLines);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
  GUILayout.BeginHorizontal();
   
  GUILayout.Label("Update Delay", GUILayout.ExpandWidth(false));
   
  this.updateDelayStr = GUILayout.TextField(this.updateDelayStr, 4, GUILayout.Width(40f));
   
  GUILayout.Label("ms", GUILayout.ExpandWidth(false));
   
  GUILayout.EndHorizontal();
   
  if (this.updateDelayStr.Length > 1 && long.TryParse(this.updateDelayStr, out this.updateDelay))
  {
  ARConfiguration.UpdateDelay = Math.Min(Math.Max(this.updateDelay, 16), 2500);
  this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
  }
   
if (requireLineOfSight) if (requireLineOfSight)
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
   
double graceRatio = 1d - Math.Sqrt(ARConfiguration.RadiusRatio); double graceRatio = 1d - Math.Sqrt(ARConfiguration.RadiusRatio);
double newRatio; double newRatio;
   
GUILayout.Label(string.Format("Line of Sight 'Fudge Factor': {0:P0}", graceRatio)); GUILayout.Label(string.Format("Line of Sight 'Fudge Factor': {0:P0}", graceRatio));
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
   
newRatio = GUILayout.HorizontalSlider((float)graceRatio, 0f, 1f, GUILayout.ExpandWidth(true)); newRatio = GUILayout.HorizontalSlider((float)graceRatio, 0f, 1f, GUILayout.ExpandWidth(true));
newRatio = Math.Round(newRatio, 2); newRatio = Math.Round(newRatio, 2);
   
if (newRatio != graceRatio) if (newRatio != graceRatio)
{ {
ARConfiguration.RadiusRatio = (1d - newRatio) * (1d - newRatio); ARConfiguration.RadiusRatio = (1d - newRatio) * (1d - newRatio);
this.SaveConfigValue("graceRatio", newRatio); this.SaveConfigValue(GRACE_RATIO_KEY, newRatio);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUI.DragWindow(); GUI.DragWindow();
} }
   
public void OnDestroy() public void OnDestroy()
{ {
GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
   
if (this.toolbarButton != null) if (this.toolbarButton != null)
{ {
this.toolbarButton.Destroy(); this.toolbarButton.Destroy();
} }
   
if (this.appLauncherButton != null) if (this.appLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton);
} }
} }
   
protected void onSceneChangeRequested(GameScenes scene) protected void onSceneChangeRequested(GameScenes scene)
{ {
if (scene != GameScenes.SPACECENTER) if (scene != GameScenes.SPACECENTER)
{ {
print("ARConfiguration: Requesting Destruction."); print("ARConfiguration: Requesting Destruction.");
MonoBehaviour.Destroy(this); MonoBehaviour.Destroy(this);
} }
} }
   
private void toggleConfigWindow() private void toggleConfigWindow()
{ {
this.showConfigWindow = !this.showConfigWindow; this.showConfigWindow = !this.showConfigWindow;
  this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
} }
   
private T LoadConfigValue<T>(string key, T defaultValue) private T LoadConfigValue<T>(string key, T defaultValue)
{ {
this.config.load(); this.config.load();
   
return config.GetValue(key, defaultValue); return config.GetValue(key, defaultValue);
} }
   
private void SaveConfigValue<T>(string key, T value) private void SaveConfigValue<T>(string key, T value)
{ {
this.config.load(); this.config.load();
   
this.config.SetValue(key, value); this.config.SetValue(key, value);
   
this.config.save(); this.config.save();
} }
} }
} }
   
// AntennaRange // AntennaRange
// //
// ARFlightController.cs // ARFlightController.cs
// //
// Copyright © 2014-2015, toadicus // Copyright © 2014-2015, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 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 // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 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. // 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, // 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 // 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, // 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 // 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, // 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 // 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. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
#pragma warning disable 1591 #pragma warning disable 1591
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace AntennaRange namespace AntennaRange
{ {
[KSPAddon(KSPAddon.Startup.Flight, false)] [KSPAddon(KSPAddon.Startup.Flight, false)]
public class ARFlightController : MonoBehaviour public class ARFlightController : MonoBehaviour
{ {
#region Fields #region Fields
private Dictionary<ConnectionStatus, string> toolbarTextures; private Dictionary<ConnectionStatus, string> toolbarTextures;
private Dictionary<ConnectionStatus, Texture> appLauncherTextures; private Dictionary<ConnectionStatus, Texture> appLauncherTextures;
   
private ARMapRenderer mapRenderer; private ARMapRenderer mapRenderer;
   
private IButton toolbarButton; private IButton toolbarButton;
   
private ApplicationLauncherButton appLauncherButton; private ApplicationLauncherButton appLauncherButton;
private Tools.DebugLogger log; private Tools.DebugLogger log;
   
private System.Diagnostics.Stopwatch updateTimer; private System.Diagnostics.Stopwatch updateTimer;
#endregion #endregion
   
#region Properties #region Properties
public ConnectionStatus currentConnectionStatus public ConnectionStatus currentConnectionStatus
{ {
get; get;
private set; private set;
} }
   
private string currentConnectionTexture private string currentConnectionTexture
{ {
get get
{ {
return this.toolbarTextures[this.currentConnectionStatus]; return this.toolbarTextures[this.currentConnectionStatus];
} }
} }
   
private Texture currentAppLauncherTexture private Texture currentAppLauncherTexture
{ {
get get
{ {
return this.appLauncherTextures[this.currentConnectionStatus]; return this.appLauncherTextures[this.currentConnectionStatus];
} }
} }
   
public ControlTypes currentControlLock public ControlTypes currentControlLock
{ {
get get
{ {
if (this.lockID == string.Empty) if (this.lockID == string.Empty)
{ {
return ControlTypes.None; return ControlTypes.None;
} }
   
return InputLockManager.GetControlLock(this.lockID); return InputLockManager.GetControlLock(this.lockID);
} }
} }
   
public string lockID public string lockID
{ {
get; get;
private set; private set;
} }
   
public ControlTypes lockSet public ControlTypes lockSet
{ {
get get
{ {
return ControlTypes.ALL_SHIP_CONTROLS; return ControlTypes.ALL_SHIP_CONTROLS;
} }
} }
   
public Vessel vessel public Vessel vessel
{ {
get get
{ {
if (FlightGlobals.ready && FlightGlobals.ActiveVessel != null) if (FlightGlobals.ready && FlightGlobals.ActiveVessel != null)
{ {
return FlightGlobals.ActiveVessel; return FlightGlobals.ActiveVessel;
} }
   
return null; return null;
} }
} }
#endregion #endregion
   
#region MonoBehaviour LifeCycle #region MonoBehaviour LifeCycle
private void Awake() private void Awake()
{ {
this.lockID = "ARConnectionRequired"; this.lockID = "ARConnectionRequired";
   
this.log = Tools.DebugLogger.New(this); this.log = Tools.DebugLogger.New(this);
   
this.updateTimer = new System.Diagnostics.Stopwatch(); this.updateTimer = new System.Diagnostics.Stopwatch();
   
this.toolbarTextures = new Dictionary<ConnectionStatus, string>(); this.toolbarTextures = new Dictionary<ConnectionStatus, string>();
   
this.toolbarTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection"; this.toolbarTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection";
this.toolbarTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal"; this.toolbarTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal";
this.toolbarTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon"; this.toolbarTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon";
   
this.appLauncherTextures = new Dictionary<ConnectionStatus, Texture>(); this.appLauncherTextures = new Dictionary<ConnectionStatus, Texture>();
   
this.appLauncherTextures[ConnectionStatus.None] = this.appLauncherTextures[ConnectionStatus.None] =
GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconNoConnection", false); GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconNoConnection", false);
this.appLauncherTextures[ConnectionStatus.Suboptimal] = this.appLauncherTextures[ConnectionStatus.Suboptimal] =
GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconSubOptimal", false); GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconSubOptimal", false);
this.appLauncherTextures[ConnectionStatus.Optimal] = this.appLauncherTextures[ConnectionStatus.Optimal] =
GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIcon", false); GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIcon", false);
   
if (ToolbarManager.ToolbarAvailable) if (ToolbarManager.ToolbarAvailable)
{ {
this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus"); this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus");
   
this.toolbarButton.TexturePath = this.toolbarTextures[ConnectionStatus.None]; this.toolbarButton.TexturePath = this.toolbarTextures[ConnectionStatus.None];
this.toolbarButton.Text = "AntennaRange"; this.toolbarButton.Text = "AntennaRange";
this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT); this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT);
this.toolbarButton.Enabled = false; this.toolbarButton.OnClick += (e) => (this.buttonToggle());
} }
   
GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
GameEvents.onVesselChange.Add(this.onVesselChange); GameEvents.onVesselChange.Add(this.onVesselChange);
} }
   
private void Start() private void Start()
{ {
this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>(); this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>();
} }
   
private void FixedUpdate() private void FixedUpdate()
{ {
if (this.appLauncherButton == null && !ToolbarManager.ToolbarAvailable && ApplicationLauncher.Ready)  
{  
this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication(  
ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW,  
this.appLauncherTextures[ConnectionStatus.None]  
);  
}  
   
this.log.Clear(); this.log.Clear();
   
VesselCommand availableCommand; VesselCommand availableCommand;
   
if (ARConfiguration.RequireConnectionForControl) if (ARConfiguration.RequireConnectionForControl)
{ {
availableCommand = this.vessel.CurrentCommand(); availableCommand = this.vessel.CurrentCommand();
} }
else else
{ {
availableCommand = VesselCommand.Crew; availableCommand = VesselCommand.Crew;
} }
   
log.AppendFormat("availableCommand: {0}\n\t" + log.AppendFormat("availableCommand: {0}\n\t" +
"(availableCommand & VesselCommand.Crew) == VesselCommand.Crew: {1}\n\t" + "(availableCommand & VesselCommand.Crew) == VesselCommand.Crew: {1}\n\t" +
"(availableCommand & VesselCommand.Probe) == VesselCommand.Probe: {2}\n\t" + "(availableCommand & VesselCommand.Probe) == VesselCommand.Probe: {2}\n\t" +
"vessel.HasConnectedRelay(): {3}", "vessel.HasConnectedRelay(): {3}",
(int)availableCommand, (int)availableCommand,
(availableCommand & VesselCommand.Crew) == VesselCommand.Crew, (availableCommand & VesselCommand.Crew) == VesselCommand.Crew,
(availableCommand & VesselCommand.Probe) == VesselCommand.Probe, (availableCommand & VesselCommand.Probe) == VesselCommand.Probe,
vessel.HasConnectedRelay() vessel.HasConnectedRelay()
); );
   
// If we are requiring a connection for control, the vessel does not have any adequately staffed pods, // 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... // and the vessel does not have any connected relays...
if ( if (
HighLogic.LoadedSceneIsFlight && HighLogic.LoadedSceneIsFlight &&
ARConfiguration.RequireConnectionForControl && ARConfiguration.RequireConnectionForControl &&
this.vessel != null && this.vessel != null &&
this.vessel.vesselType != VesselType.EVA && this.vessel.vesselType != VesselType.EVA &&
!( !(
(availableCommand & VesselCommand.Crew) == VesselCommand.Crew || (availableCommand & VesselCommand.Crew) == VesselCommand.Crew ||
(availableCommand & VesselCommand.Probe) == VesselCommand.Probe && vessel.HasConnectedRelay() (availableCommand & VesselCommand.Probe) == VesselCommand.Probe && vessel.HasConnectedRelay()
)) ))
{ {
// ...and if the controls are not currently locked... // ...and if the controls are not currently locked...
if (currentControlLock == ControlTypes.None) if (currentControlLock == ControlTypes.None)
{ {
// ...lock the controls. // ...lock the controls.
InputLockManager.SetControlLock(this.lockSet, this.lockID); InputLockManager.SetControlLock(this.lockSet, this.lockID);
} }
} }
// ...otherwise, if the controls are locked... // ...otherwise, if the controls are locked...
else if (currentControlLock != ControlTypes.None) else if (currentControlLock != ControlTypes.None)
{ {
// ...unlock the controls. // ...unlock the controls.
InputLockManager.RemoveControlLock(this.lockID); InputLockManager.RemoveControlLock(this.lockID);
} }
   
log.Print(); log.Print();
} }
   
private void Update() private void Update()
{ {
if (!this.updateTimer.IsRunning || this.updateTimer.ElapsedMilliseconds > 16L) if (this.toolbarButton != null)
  {
  this.toolbarButton.Enabled = MapView.MapIsEnabled;
  }
   
  if (this.appLauncherButton == null && !ToolbarManager.ToolbarAvailable && ApplicationLauncher.Ready)
  {
  this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication(
  this.buttonToggle, this.buttonToggle,
  ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW,
  this.appLauncherTextures[ConnectionStatus.None]
  );
  }
   
  if (!this.updateTimer.IsRunning || this.updateTimer.ElapsedMilliseconds > ARConfiguration.UpdateDelay)
{ {
this.updateTimer.Restart(); this.updateTimer.Restart();
} }
else else
{ {
return; return;
} }
   
this.log.Clear(); this.log.Clear();
   
if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null) if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null)
{ {
Vessel vessel; Vessel vessel;
IAntennaRelay relay; IAntennaRelay relay;
IList<IAntennaRelay> activeVesselRelays; IList<IAntennaRelay> activeVesselRelays;
   
for (int vIdx = 0; vIdx < FlightGlobals.Vessels.Count; vIdx++) for (int vIdx = 0; vIdx < FlightGlobals.Vessels.Count; vIdx++)
{ {
vessel = FlightGlobals.Vessels[vIdx]; vessel = FlightGlobals.Vessels[vIdx];
   
if (vessel == null || vessel == FlightGlobals.ActiveVessel) if (vessel == null || vessel == FlightGlobals.ActiveVessel)
{ {
continue; continue;
} }
   
log.AppendFormat("Fetching best relay for vessel {0}", vessel); log.AppendFormat("Fetching best relay for vessel {0}", vessel);
   
relay = vessel.GetBestRelay(); relay = vessel.GetBestRelay();
   
if (relay != null) if (relay != null)
{ {
log.AppendFormat("Finding nearest relay for best relay {0}", relay); log.AppendFormat("Finding nearest relay for best relay {0}", relay);
   
relay.FindNearestRelay(); relay.FindNearestRelay();
} }
} }
   
activeVesselRelays = RelayDatabase.Instance[FlightGlobals.ActiveVessel]; activeVesselRelays = RelayDatabase.Instance[FlightGlobals.ActiveVessel];
for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++) for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++)
{ {
relay = activeVesselRelays[rIdx]; relay = activeVesselRelays[rIdx];
   
relay.FindNearestRelay(); relay.FindNearestRelay();
} }
   
if (this.toolbarButton != null || this.appLauncherButton != null) if (this.toolbarButton != null || this.appLauncherButton != null)
{ {
log.Append("Checking vessel relay status.\n"); log.Append("Checking vessel relay status.\n");
   
this.currentConnectionStatus = FlightGlobals.ActiveVessel.GetConnectionStatus(); this.currentConnectionStatus = FlightGlobals.ActiveVessel.GetConnectionStatus();
   
log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}", log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
this.currentConnectionStatus, this.currentConnectionTexture); this.currentConnectionStatus, this.currentConnectionTexture);
   
if (this.toolbarButton != null) if (this.toolbarButton != null)
{ {
this.toolbarButton.TexturePath = this.currentConnectionTexture; this.toolbarButton.TexturePath = this.currentConnectionTexture;
   
if (this.currentConnectionStatus == ConnectionStatus.None) if (this.currentConnectionStatus == ConnectionStatus.None)
{ {
if (!this.toolbarButton.Important) this.toolbarButton.Important = true; if (!this.toolbarButton.Important) this.toolbarButton.Important = true;
} }
else else
{ {
if (this.toolbarButton.Important) this.toolbarButton.Important = false; if (this.toolbarButton.Important) this.toolbarButton.Important = false;
} }
} }
if (this.appLauncherButton != null) if (this.appLauncherButton != null)
{ {
this.appLauncherButton.SetTexture(this.currentAppLauncherTexture); this.appLauncherButton.SetTexture(this.currentAppLauncherTexture);
} }
} }
} }
   
log.Print(); log.Print();
} }
   
private void OnDestroy() private void OnDestroy()
{ {
InputLockManager.RemoveControlLock(this.lockID); InputLockManager.RemoveControlLock(this.lockID);
   
if (this.mapRenderer != null) if (this.mapRenderer != null)
{ {
GameObject.Destroy(this.mapRenderer); GameObject.Destroy(this.mapRenderer);
} }
   
if (this.toolbarButton != null) if (this.toolbarButton != null)
{ {
this.toolbarButton.Destroy(); this.toolbarButton.Destroy();
} }
   
if (this.appLauncherButton != null) if (this.appLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton);
this.appLauncherButton = null; this.appLauncherButton = null;
} }
   
GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
GameEvents.onVesselChange.Remove(this.onVesselChange); GameEvents.onVesselChange.Remove(this.onVesselChange);
   
print("ARFlightController: Destroyed."); print("ARFlightController: Destroyed.");
} }
#endregion #endregion
   
  private void buttonToggle()
  {
  if (MapView.MapIsEnabled)
  {
  ARConfiguration.PrettyLines = !ARConfiguration.PrettyLines;
  }
  }
   
#region Event Handlers #region Event Handlers
private void onSceneChangeRequested(GameScenes scene) private void onSceneChangeRequested(GameScenes scene)
{ {
print("ARFlightController: Requesting Destruction."); print("ARFlightController: Requesting Destruction.");
MonoBehaviour.Destroy(this); MonoBehaviour.Destroy(this);
} }
   
private void onVesselChange(Vessel vessel) private void onVesselChange(Vessel vessel)
{ {
InputLockManager.RemoveControlLock(this.lockID); InputLockManager.RemoveControlLock(this.lockID);
} }
#endregion #endregion
} }
} }