Merge branch 'master' into PrettyLinesDev2
Merge branch 'master' into PrettyLinesDev2

Conflicts:
ARFlightController.cs

// AntennaRange // AntennaRange
// //
// ARFlightController.cs // ARFlightController.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, 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.
   
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 Static Members #region Static Members
public static bool requireConnectionForControl; public static bool requireConnectionForControl;
#endregion #endregion
   
#region Fields #region Fields
protected Dictionary<ConnectionStatus, string> connectionTextures; protected Dictionary<ConnectionStatus, string> connectionTextures;
   
protected ARMapRenderer mapRenderer; protected ARMapRenderer mapRenderer;
   
protected IButton toolbarButton; protected IButton toolbarButton;
#endregion #endregion
   
#region Properties #region Properties
public ConnectionStatus currentConnectionStatus public ConnectionStatus currentConnectionStatus
{ {
get; get;
protected set; protected set;
} }
   
protected string currentConnectionTexture protected string currentConnectionTexture
{ {
get get
{ {
return this.connectionTextures[this.currentConnectionStatus]; return this.connectionTextures[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;
protected set; protected 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
protected void Awake() protected void Awake()
{ {
this.lockID = "ARConnectionRequired"; this.lockID = "ARConnectionRequired";
   
if (ToolbarManager.ToolbarAvailable) if (ToolbarManager.ToolbarAvailable)
{ {
this.connectionTextures = new Dictionary<ConnectionStatus, string>(); this.connectionTextures = new Dictionary<ConnectionStatus, string>();
   
this.connectionTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection"; this.connectionTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection";
this.connectionTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal"; this.connectionTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal";
this.connectionTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon"; this.connectionTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon";
   
this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus"); this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus");
   
this.toolbarButton.TexturePath = this.connectionTextures[ConnectionStatus.None]; this.toolbarButton.TexturePath = this.connectionTextures[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.Enabled = false;
} }
   
GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
GameEvents.onVesselChange.Add(this.onVesselChange); GameEvents.onVesselChange.Add(this.onVesselChange);
} }
   
protected void Start() protected void Start()
{ {
this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>(); this.mapRenderer = MapView.MapCamera.gameObject.AddComponent<ARMapRenderer>();
} }
   
protected void FixedUpdate() protected void FixedUpdate()
{ {
Tools.DebugLogger log = Tools.DebugLogger.New(this); Tools.DebugLogger log = Tools.DebugLogger.New(this);
   
// 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 &&
requireConnectionForControl && requireConnectionForControl &&
this.vessel != null && this.vessel != null &&
this.vessel.vesselType != VesselType.EVA && this.vessel.vesselType != VesselType.EVA &&
!this.vessel.hasCrewCommand() && !this.vessel.hasCrewCommand() &&
!this.vessel.HasConnectedRelay()) !this.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);
} }
   
if (HighLogic.LoadedSceneIsFlight && this.toolbarButton != null && FlightGlobals.ActiveVessel != null) if (HighLogic.LoadedSceneIsFlight && this.toolbarButton != null && FlightGlobals.ActiveVessel != null)
{ {
log.Append("Checking vessel relay status.\n"); log.Append("Checking vessel relay status.\n");
   
List<ModuleLimitedDataTransmitter> relays = List<ModuleLimitedDataTransmitter> relays =
FlightGlobals.ActiveVessel.getModulesOfType<ModuleLimitedDataTransmitter>(); FlightGlobals.ActiveVessel.getModulesOfType<ModuleLimitedDataTransmitter>();
   
log.AppendFormat("\t...found {0} relays\n", relays.Count); log.AppendFormat("\t...found {0} relays\n", relays.Count);
   
bool vesselCanTransmit = false; bool vesselCanTransmit = false;
bool vesselHasOptimalRelay = false; bool vesselHasOptimalRelay = false;
   
foreach (ModuleLimitedDataTransmitter relay in relays) foreach (ModuleLimitedDataTransmitter relay in relays)
{ {
log.AppendFormat("\tvesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n", log.AppendFormat("\tvesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n",
vesselCanTransmit, vesselHasOptimalRelay); vesselCanTransmit, vesselHasOptimalRelay);
   
log.AppendFormat("\tChecking relay {0}\n" + log.AppendFormat("\tChecking relay {0}\n" +
"\t\tCanTransmit: {1}, transmitDistance: {2}, nominalRange: {3}\n", "\t\tCanTransmit: {1}, transmitDistance: {2}, nominalRange: {3}\n",
relay, relay,
relay.CanTransmit(), relay.CanTransmit(),
relay.transmitDistance, relay.transmitDistance,
relay.nominalRange relay.nominalRange
); );
   
bool relayCanTransmit = relay.CanTransmit(); bool relayCanTransmit = relay.CanTransmit();
   
if (!vesselCanTransmit && relayCanTransmit) if (!vesselCanTransmit && relayCanTransmit)
{ {
vesselCanTransmit = true; vesselCanTransmit = true;
} }
   
if (!vesselHasOptimalRelay && if (!vesselHasOptimalRelay &&
relayCanTransmit && relayCanTransmit &&
relay.transmitDistance <= (double)relay.nominalRange) relay.transmitDistance <= (double)relay.nominalRange)
{ {
vesselHasOptimalRelay = true; vesselHasOptimalRelay = true;
} }
   
if (vesselCanTransmit && vesselHasOptimalRelay) if (vesselCanTransmit && vesselHasOptimalRelay)
{ {
break; break;
} }
} }
   
log.AppendFormat("Done checking. vesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n", log.AppendFormat("Done checking. vesselCanTransmit: {0}, vesselHasOptimalRelay: {1}\n",
vesselCanTransmit, vesselHasOptimalRelay); vesselCanTransmit, vesselHasOptimalRelay);
   
if (vesselHasOptimalRelay) if (vesselHasOptimalRelay)
{ {
this.currentConnectionStatus = ConnectionStatus.Optimal; this.currentConnectionStatus = ConnectionStatus.Optimal;
} }
else if (vesselCanTransmit) else if (vesselCanTransmit)
{ {
this.currentConnectionStatus = ConnectionStatus.Suboptimal; this.currentConnectionStatus = ConnectionStatus.Suboptimal;
} }
else else
{ {
this.currentConnectionStatus = ConnectionStatus.None; this.currentConnectionStatus = ConnectionStatus.None;
} }
   
log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}", log.AppendFormat("currentConnectionStatus: {0}, setting texture to {1}",
this.currentConnectionStatus, this.currentConnectionTexture); this.currentConnectionStatus, this.currentConnectionTexture);
   
this.toolbarButton.TexturePath = this.currentConnectionTexture; this.toolbarButton.TexturePath = this.currentConnectionTexture;
} }
   
log.Print(); log.Print();
} }
   
protected void Destroy() protected void OnDestroy()
{ {
InputLockManager.RemoveControlLock(this.lockID); InputLockManager.RemoveControlLock(this.lockID);
   
if (this.toolbarButton != null) if (this.toolbarButton != null)
{ {
this.toolbarButton.Destroy(); this.toolbarButton.Destroy();
} }
   
if (this.mapRenderer != null) if (this.mapRenderer != null)
{ {
GameObject.Destroy(this.mapRenderer); GameObject.Destroy(this.mapRenderer);
} }
   
GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested); GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
GameEvents.onVesselChange.Remove(this.onVesselChange); GameEvents.onVesselChange.Remove(this.onVesselChange);
   
  print("ARFlightController: Destroyed.");
} }
#endregion #endregion
   
#region Event Handlers #region Event Handlers
protected void onSceneChangeRequested(GameScenes scene) protected void onSceneChangeRequested(GameScenes scene)
{ {
if (scene != GameScenes.FLIGHT) if (scene != GameScenes.FLIGHT)
{ {
MonoBehaviour.DestroyImmediate(this, true); print("ARFlightController: Requesting Destruction.");
  MonoBehaviour.Destroy(this);
} }
} }
   
protected void onVesselChange(Vessel vessel) protected void onVesselChange(Vessel vessel)
{ {
InputLockManager.RemoveControlLock(this.lockID); InputLockManager.RemoveControlLock(this.lockID);
} }
#endregion #endregion
   
public enum ConnectionStatus public enum ConnectionStatus
{ {
None, None,
Suboptimal, Suboptimal,
Optimal Optimal
} }
} }
} }