ARFlightController: New MonoBehaviour to require connectivity for probe control.
[AntennaRange.git] / ARFlightController.cs
blob:a/ARFlightController.cs -> blob:b/ARFlightController.cs
--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -26,8 +26,11 @@
 // 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.
 
+#pragma warning disable 1591
+
 using KSP;
 using System;
+using System.Collections.Generic;
 using ToadicusTools;
 using UnityEngine;
 
@@ -36,11 +39,43 @@
 	[KSPAddon(KSPAddon.Startup.Flight, false)]
 	public class ARFlightController : MonoBehaviour
 	{
-		#region Static Members
-		public static bool requireConnectionForControl;
+		#region Fields
+		private Dictionary<ConnectionStatus, string> connectionTextures;
+		private Dictionary<ConnectionStatus, Texture> appLauncherTextures;
+
+		private ARMapRenderer mapRenderer;
+
+		private IButton toolbarButton;
+
+		private ApplicationLauncherButton appLauncherButton;
+		private Tools.DebugLogger log;
+
+		private System.Diagnostics.Stopwatch updateTimer;
 		#endregion
 
 		#region Properties
+		public ConnectionStatus currentConnectionStatus
+		{
+			get;
+			private set;
+		}
+
+		private string currentConnectionTexture
+		{
+			get
+			{
+				return this.connectionTextures[this.currentConnectionStatus];
+			}
+		}
+
+		private Texture currentAppLauncherTexture
+		{
+			get
+			{
+				return this.appLauncherTextures[this.currentConnectionStatus];
+			}
+		}
+
 		public ControlTypes currentControlLock
 		{
 			get
@@ -57,14 +92,14 @@
 		public string lockID
 		{
 			get;
-			protected set;
+			private set;
 		}
 
 		public ControlTypes lockSet
 		{
 			get
 			{
-				return ControlTypes.GROUPS_ALL | ControlTypes.STAGING | ControlTypes.SAS | ControlTypes.RCS;
+				return ControlTypes.ALL_SHIP_CONTROLS;
 			}
 		}
 
@@ -83,43 +118,229 @@
 		#endregion
 
 		#region MonoBehaviour LifeCycle
-		protected void Awake()
+		private void Awake()
 		{
 			this.lockID = "ARConnectionRequired";
-		}
-
-		protected void FixedUpdate()
-		{
+
+			this.log = Tools.DebugLogger.New(this);
+
+			this.updateTimer = new System.Diagnostics.Stopwatch();
+
+			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.appLauncherTextures = new Dictionary<ConnectionStatus, Texture>();
+
+			this.appLauncherTextures[ConnectionStatus.None] =
+				GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconNoConnection", false);
+			this.appLauncherTextures[ConnectionStatus.Suboptimal] =
+				GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIconSubOptimal", false);
+			this.appLauncherTextures[ConnectionStatus.Optimal] =
+				GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIcon", false);
+
+			if (ToolbarManager.ToolbarAvailable)
+			{
+				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);
+		}
+
+		private void Start()
+		{
+			this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>();
+		}
+
+		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();
+
+			VesselCommand availableCommand;
+
+			if (ARConfiguration.RequireConnectionForControl)
+			{
+				availableCommand = this.vessel.CurrentCommand();
+			}
+			else
+			{
+				availableCommand = VesselCommand.Crew;
+			}
+
+			log.AppendFormat("availableCommand: {0}\n\t" +
+				"(availableCommand & VesselCommand.Crew) == VesselCommand.Crew: {1}\n\t" +
+				"(availableCommand & VesselCommand.Probe) == VesselCommand.Probe: {2}\n\t" +
+				"vessel.HasConnectedRelay(): {3}",
+				(int)availableCommand,
+				(availableCommand & VesselCommand.Crew) == VesselCommand.Crew,
+				(availableCommand & VesselCommand.Probe) == VesselCommand.Probe,
+				vessel.HasConnectedRelay()
+			);
+
+			// 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 (
-				requireConnectionForControl &&
+				HighLogic.LoadedSceneIsFlight &&
+				ARConfiguration.RequireConnectionForControl &&
 				this.vessel != null &&
-				!this.vessel.hasCrewCommand() &&
-				this.vessel.IsControllable
-			)
-			{
-				if (this.vessel.HasConnectedRelay())
-				{
-					if (currentControlLock != ControlTypes.None)
+				this.vessel.vesselType != VesselType.EVA &&
+				!(
+				    (availableCommand & VesselCommand.Crew) == VesselCommand.Crew ||
+				    (availableCommand & VesselCommand.Probe) == VesselCommand.Probe && 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);
+			}
+
+			log.Print();
+		}
+
+		private void Update()
+		{
+			if (!this.updateTimer.IsRunning || this.updateTimer.ElapsedMilliseconds > 83L)
+			{
+				this.updateTimer.Restart();
+			}
+			else
+			{
+				return;
+			}
+
+			this.log.Clear();
+
+			if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel != null)
+			{
+				Vessel vessel;
+				IAntennaRelay relay;
+				IList<IAntennaRelay> activeVesselRelays;
+
+				for (int vIdx = 0; vIdx < FlightGlobals.Vessels.Count; vIdx++)
+				{
+					vessel = FlightGlobals.Vessels[vIdx];
+
+					if (vessel == null || vessel == FlightGlobals.ActiveVessel)
 					{
-						InputLockManager.RemoveControlLock(this.lockID);
+						continue;
 					}
-				}
-				else
-				{
-					if (currentControlLock == ControlTypes.None)
+
+					log.AppendFormat("Fetching best relay for vessel {0}", vessel);
+
+					relay = vessel.GetBestRelay();
+
+					if (relay != null)
 					{
-						InputLockManager.SetControlLock(this.lockSet, this.lockID);
+						log.AppendFormat("Finding nearest relay for best relay {0}", relay);
+
+						relay.FindNearestRelay();
 					}
 				}
-			}
-		}
-
-		protected void Destroy()
-		{
-
+
+				activeVesselRelays = RelayDatabase.Instance[FlightGlobals.ActiveVessel];
+				for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++)
+				{
+					relay = activeVesselRelays[rIdx];
+
+					relay.FindNearestRelay();
+				}
+
+				if (this.toolbarButton != null || this.appLauncherButton != null)
+				{
+					log.Append("Checking vessel relay status.\n");
+
+					this.currentConnectionStatus = FlightGlobals.ActiveVessel.GetConnectionStatus();
+
+					log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
+						this.currentConnectionStatus, this.currentConnectionTexture);
+
+					if (this.toolbarButton != null)
+					{
+						this.toolbarButton.TexturePath = this.currentConnectionTexture;
+
+						if (this.currentConnectionStatus == ConnectionStatus.None)
+						{
+							if (!this.toolbarButton.Important) this.toolbarButton.Important = true;
+						}
+						else
+						{
+							if (this.toolbarButton.Important) this.toolbarButton.Important = false;
+						}
+					}
+					if (this.appLauncherButton != null)
+					{
+						this.appLauncherButton.SetTexture(this.currentAppLauncherTexture);
+					}
+				}
+			}
+
+			log.Print();
+		}
+
+		private void OnDestroy()
+		{
+			InputLockManager.RemoveControlLock(this.lockID);
+
+			if (this.mapRenderer != null)
+			{
+				GameObject.Destroy(this.mapRenderer);
+			}
+
+			if (this.toolbarButton != null)
+			{
+				this.toolbarButton.Destroy();
+			}
+
+			if (this.appLauncherButton != null)
+			{
+				ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton);
+				this.appLauncherButton = null;
+			}
+
+			GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
+			GameEvents.onVesselChange.Remove(this.onVesselChange);
+
+			print("ARFlightController: Destroyed.");
+		}
+		#endregion
+
+		#region Event Handlers
+		private void onSceneChangeRequested(GameScenes scene)
+		{
+			print("ARFlightController: Requesting Destruction.");
+			MonoBehaviour.Destroy(this);
+		}
+
+		private void onVesselChange(Vessel vessel)
+		{
+			InputLockManager.RemoveControlLock(this.lockID);
 		}
 		#endregion
 	}
 }
 
-