Changes to Module, Core, and throughout to support module filtering by game mode. Also tweaks to CareerStatus.formatDelta.
[VOID.git] / VOIDCore_Generic.cs
blob:a/VOIDCore_Generic.cs -> blob:b/VOIDCore_Generic.cs
--- a/VOIDCore_Generic.cs
+++ b/VOIDCore_Generic.cs
@@ -26,6 +26,8 @@
 // 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 KerbalEngineer.Editor;
+using KerbalEngineer.Helpers;
 using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
@@ -37,7 +39,7 @@
 
 namespace VOID
 {
-	public abstract class VOIDCore_Generic<T> : VOID_SingletonModule<T>, IVOID_Module, IDisposable
+	public abstract class VOIDCore_Generic<T> : VOID_SingletonCore<T>, IVOID_Module, IDisposable
 		where T : VOID_Module, new()
 	{
 		/*
@@ -47,21 +49,10 @@
 		protected string VoidVersion;
 
 		[AVOID_SaveValue("configValue")]
-		protected VOID_SaveValue<int> _configVersion = VOIDCore.CONFIG_VERSION;
-
-		protected List<IVOID_Module> _modules = new List<IVOID_Module>();
-		protected bool _modulesLoaded = false;
-
-		[AVOID_SaveValue("mainWindowPos")]
-		protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f);
-		[AVOID_SaveValue("mainGuiMinimized")]
-		protected VOID_SaveValue<bool> mainGuiMinimized = false;
-
-		[AVOID_SaveValue("configWindowPos")]
-		protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f);
-		[AVOID_SaveValue("configWindowMinimized")]
-
-		protected VOID_SaveValue<bool> configWindowMinimized = true;
+		protected VOID_SaveValue<int> configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
+
+		protected List<IVOID_Module> modules = new List<IVOID_Module>();
+		protected bool modulesLoaded = false;
 
 		protected Texture2D VOIDIconTexture;
 		protected string VOIDIconOnActivePath;
@@ -69,45 +60,51 @@
 		protected string VOIDIconOffActivePath;
 		protected string VOIDIconOffInactivePath;
 
+		[AVOID_SaveValue("useToolbarManager")]
+		protected VOID_SaveValue<bool> useToolbarManager;
+
 		protected GUIStyle iconStyle;
 
 		protected int windowBaseID = -96518722;
-		protected int _windowID = 0;
+		protected int windowID = 0;
 
 		protected bool GUIStylesLoaded = false;
 
-		protected CelestialBody _homeBody;
+		protected CelestialBody homeBody;
 
 		[AVOID_SaveValue("togglePower")]
-		public VOID_SaveValue<bool> togglePower = true;
+		public VOID_SaveValue<bool> togglePower = (VOID_SaveValue<bool>)true;
 
 		public override bool powerAvailable { get; protected set; }
 
 		[AVOID_SaveValue("consumeResource")]
-		protected VOID_SaveValue<bool> consumeResource = false;
+		protected VOID_SaveValue<bool> consumeResource = (VOID_SaveValue<bool>)false;
 
 		[AVOID_SaveValue("resourceName")]
-		protected VOID_SaveValue<string> resourceName = "ElectricCharge";
+		protected VOID_SaveValue<string> resourceName = (VOID_SaveValue<string>)"ElectricCharge";
 
 		[AVOID_SaveValue("resourceRate")]
-		protected VOID_SaveValue<float> resourceRate = 0.2f;
+		protected VOID_SaveValue<float> resourceRate = (VOID_SaveValue<float>)0.2f;
 
 		[AVOID_SaveValue("updatePeriod")]
-		protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f;
+		protected VOID_SaveValue<double> updatePeriod = (VOID_SaveValue<double>)(1001f / 15000f);
 		protected string stringFrequency;
 
 		[AVOID_SaveValue("vesselSimActive")]
 		protected VOID_SaveValue<bool> vesselSimActive;
 
-		// Vessel Type Housekeeping
-		protected List<VesselType> _allVesselTypes = new List<VesselType>();
+		[AVOID_SaveValue("timeScaleFlags")]
+		protected VOID_SaveValue<UInt32> timeScaleFlags;
+
+		// Load-up housekeeping
 		protected bool vesselTypesLoaded = false;
+		protected bool simManagerLoaded = false;
 
 		protected string defaultSkin = "KSP window 2";
 
 		[AVOID_SaveValue("defaultSkin")]
-		protected VOID_SaveValue<string> _skinName;
-		protected int _skinIdx;
+		protected VOID_SaveValue<string> skinName;
+		protected int skinIdx;
 
 		protected Dictionary<string, GUISkin> validSkins;
 		protected string[] skinNames;
@@ -118,6 +115,8 @@
 				"SSUITextAreaDefault",
 				"ExperimentsDialogSkin",
 				"ExpRecoveryDialogSkin",
+				"KSP window 1",
+				"KSP window 3",
 				"KSP window 5",
 				"KSP window 6",
 				"PartTooltipSkin",
@@ -127,32 +126,78 @@
 
 		public override bool configDirty { get; set; }
 
-		internal IButton ToolbarButton;
-
-		internal ApplicationLauncherButton AppLauncherButton;
+		protected IButton ToolbarButton;
+		protected ApplicationLauncherButton AppLauncherButton;
+		protected IconState iconState;
 
 		/*
 		 * Properties
 		 * */
-		public override int configVersion
+		public override bool Active
 		{
 			get
 			{
-				return this._configVersion;
-			}
-		}
-
-		public bool factoryReset
+				return base.Active;
+			}
+			set
+			{
+				if (value != base.Active)
+				{
+					this.SetIconTexture(this.powerState | this.activeState);
+				}
+
+				base.Active = value;
+			}
+		}
+		public override IList<CelestialBody> AllBodies
+		{
+			get
+			{
+				return FlightGlobals.Bodies.AsReadOnly();
+			}
+		}
+
+		public override VesselType[] AllVesselTypes
 		{
 			get;
 			protected set;
 		}
 
-		public override List<IVOID_Module> Modules
+		public override int ConfigVersion
 		{
 			get
 			{
-				return this._modules;
+				return this.configVersion;
+			}
+		}
+
+		public bool FactoryReset
+		{
+			get;
+			protected set;
+		}
+
+		public override CelestialBody HomeBody
+		{
+			get
+			{
+				if (this.homeBody == null)
+				{
+					if (Planetarium.fetch != null)
+					{
+						this.homeBody = Planetarium.fetch.Home;
+					}
+				}
+
+				return this.homeBody;
+			}
+		}
+
+		public override IList<IVOID_Module> Modules
+		{
+			get
+			{
+				return this.modules.AsReadOnly();
 			}
 		}
 
@@ -164,7 +209,7 @@
 				{
 					try
 					{
-						return this.validSkins[this._skinName];
+						return this.validSkins[this.skinName];
 					}
 					catch
 					{
@@ -175,68 +220,35 @@
 			}
 		}
 
-		public override int windowID
-		{
-			get
-			{
-				if (this._windowID == 0)
-				{
-					this._windowID = this.windowBaseID;
-				}
-				return this._windowID++;
-			}
-		}
-
-		public override List<CelestialBody> allBodies
-		{
-			get
-			{
-				return FlightGlobals.Bodies;
-			}
-		}
-
-		public override List<CelestialBody> sortedBodyList
+		public override List<CelestialBody> SortedBodyList
 		{
 			get;
 			protected set;
 		}
 
-		public override CelestialBody HomeBody
+		public override double UpdatePeriod
 		{
 			get
 			{
-				if (this._homeBody == null)
-				{
-					if (Planetarium.fetch != null)
-					{
-						this._homeBody = Planetarium.fetch.Home;
-					}
-				}
-
-				return this._homeBody;
-			}
-		}
-
-		public override List<VesselType> allVesselTypes
-		{
-			get
-			{
-				return this._allVesselTypes;
-			}
-		}
-
-		public override float updateTimer
+				return this.updatePeriod;
+			}
+		}
+
+		public override float UpdateTimer
 		{
 			get;
 			protected set;
 		}
 
-
-		public override double updatePeriod
+		public override int WindowID
 		{
 			get
 			{
-				return this._updatePeriod;
+				if (this.windowID == 0)
+				{
+					this.windowID = this.windowBaseID;
+				}
+				return this.windowID++;
 			}
 		}
 
@@ -252,6 +264,34 @@
 			protected set;
 		}
 
+		public override VOID_TimeScale TimeScale
+		{
+			get
+			{
+				return (VOID_TimeScale)this.timeScaleFlags.value;
+			}
+			protected set
+			{
+				this.timeScaleFlags.value = (UInt32)value;
+			}
+		}
+
+		protected IconState activeState
+		{
+			get
+			{
+				if (this.Active)
+				{
+					return IconState.Inactive;
+				}
+				else
+				{
+					return IconState.Active;
+				}
+
+			}
+		}
+
 		protected IconState powerState
 		{
 			get
@@ -265,55 +305,6 @@
 					return IconState.PowerOff;
 				}
 
-			}
-		}
-
-		protected IconState activeState
-		{
-			get
-			{
-				if (this.mainGuiMinimized)
-				{
-					return IconState.Inactive;
-				}
-				else
-				{
-					return IconState.Active;
-				}
-
-			}
-		}
-
-		protected bool UseToolbarManager
-		{
-			get
-			{
-				return useToolbarManager & ToolbarManager.ToolbarAvailable;
-			}
-			set
-			{
-				if (useToolbarManager == value)
-				{
-					return;
-				}
-
-				if (value == false && this.ToolbarButton != null)
-				{
-					this.ToolbarButton.Destroy();
-					this.ToolbarButton = null;
-				}
-				if (value == true)
-				{
-					if (this.AppLauncherButton != null)
-					{
-						ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
-						this.AppLauncherButton = null;
-					}
-
-					this.InitializeToolbarButton();
-				}
-
-				useToolbarManager = value;
 			}
 		}
 
@@ -328,17 +319,19 @@
 		/*
 		 * Events
 		 * */
+		// public 
 		public override event VOIDEventHandler onApplicationQuit;
 		public override event VOIDEventHandler onSkinChanged;
+		public override event VOIDEventHandler onUpdate;
 
 		/*
 		 * Methods
 		 * */
 		public override void DrawGUI()
 		{
-			this._windowID = this.windowBaseID;
-
-			if (!this._modulesLoaded)
+			this.windowID = this.windowBaseID;
+
+			if (!this.modulesLoaded)
 			{
 				this.LoadModulesOfType<IVOID_Module>();
 			}
@@ -358,86 +351,22 @@
 					this,
 					"ToolbarAvailable: {0}, UseToobarManager: {1}",
 					ToolbarManager.ToolbarAvailable,
-					this.UseToolbarManager);
-			}
-
-			if (!this.UseToolbarManager)
-			{
-				if (this.AppLauncherButton == null)
-				{
-					Tools.PostDebugMessage(this,
-						"UseToolbarManager = false (ToolbarAvailable = {0}) and " +
-						"AppLauncherButton is null, making AppLauncher button.",
-						ToolbarManager.ToolbarAvailable
-					);
-					this.InitializeAppLauncherButton();
-				}
-			}
-			else if (this.ToolbarButton == null)
-			{
-				Tools.PostDebugMessage(this,
-					"UseToolbarManager = true (ToolbarAvailable = {0}) and " +
-					"ToolbarButton is null, making Toolbar button.",
-					ToolbarManager.ToolbarAvailable
-				);
-				this.InitializeToolbarButton();
-			}
-
-			if (!this.mainGuiMinimized)
-			{
-
-				Rect _mainWindowPos = this.mainWindowPos;
-
-				_mainWindowPos = GUILayout.Window(
-					this.windowID,
-					_mainWindowPos,
-					VOID_Tools.GetWindowHandler(this.VOIDMainWindow),
-					string.Join(" ", new string[] { this.VoidName, this.VoidVersion }),
-					GUILayout.Width(250),
-					GUILayout.Height(50)
-				);
-
-				if (HighLogic.LoadedSceneIsEditor)
-				{
-					_mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);
-				}
-				else
-				{
-					_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
-				}
-
-				if (_mainWindowPos != this.mainWindowPos)
-				{
-					this.mainWindowPos = _mainWindowPos;
-				}
-			}
-
-			if (!this.configWindowMinimized && !this.mainGuiMinimized)
-			{
-				Rect _configWindowPos = this.configWindowPos;
-
-				_configWindowPos = GUILayout.Window(
-					this.windowID,
-					_configWindowPos,
-					VOID_Tools.GetWindowHandler(this.VOIDConfigWindow),
-					string.Join(" ", new string[] { this.VoidName, "Configuration" }),
-					GUILayout.Width(250),
-					GUILayout.Height(50)
-				);
-
-				if (HighLogic.LoadedSceneIsEditor)
-				{
-					_configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);
-				}
-				else
-				{
-					_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
-				}
-
-				if (_configWindowPos != this.configWindowPos)
-				{
-					this.configWindowPos = _configWindowPos;
-				}
+					this.useToolbarManager);
+			}
+
+			if (
+				this.iconState != (this.powerState | this.activeState) ||
+				(this.VOIDIconTexture == null && this.AppLauncherButton != null)
+			)
+			{
+				this.iconState = this.powerState | this.activeState;
+
+				this.SetIconTexture(this.iconState);
+			}
+
+			if (this.Active)
+			{
+				base.DrawGUI();
 			}
 		}
 
@@ -448,7 +377,7 @@
 			if (
 				this.vesselSimActive &&
 				(
-					this.vessel != null ||
+					this.Vessel != null ||
 					(
 						HighLogic.LoadedSceneIsEditor &&
 						EditorLogic.RootPart != null &&
@@ -461,38 +390,20 @@
 				this.UpdateSimManager();
 			}
 
-			if (!this.guiRunning)
+			if (!this.GUIRunning)
 			{
 				this.StartGUI();
 			}
 
-			foreach (IVOID_Module module in this.Modules)
-			{
-				Tools.PostDebugMessage(
-					this,
-					"\n\tmodule.Name={0}" +
-					"\n\tmodule.guiRunning={1}" +
-					"\n\tmodule.toggleActive={2}" +
-					"\n\tmodule.inValidScene={3}" +
-					"\n\tthis.togglePower={4}" +
-					"\n\tthis.factoryReset={5}" +
-					"\n\tHighLogic.LoadedSceneIsEditor={6}" +
-					"\n\t(EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0)={7}" +
-					"\n\t(EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)={8}",
-					module.Name,
-					module.guiRunning,
-					module.toggleActive,
-					module.inValidScene,
-					this.togglePower,
-					this.factoryReset,
-					HighLogic.LoadedSceneIsEditor,
-					(EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0),
-					(EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)
-				);
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
 				if (
-					!module.guiRunning &&
-					module.toggleActive &&
-					module.inValidScene &&
+					!module.GUIRunning &&
+					module.Active &&
+					module.InValidScene &&
 					(
 						!HighLogic.LoadedSceneIsEditor ||
 						(EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0)
@@ -502,12 +413,12 @@
 					module.StartGUI();
 				}
 				if (
-					module.guiRunning &&
+					module.GUIRunning &&
 					(
-						!module.toggleActive ||
+						!module.Active ||
 					    !this.togglePower ||
-						!module.inValidScene ||
-					    this.factoryReset ||
+						!module.InValidScene ||
+					    this.FactoryReset ||
 						(
 							HighLogic.LoadedSceneIsEditor &&
 							(EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)
@@ -524,8 +435,58 @@
 				}
 			}
 
-			this.CheckAndSave();
-			this.updateTimer += Time.deltaTime;
+			if (this.useToolbarManager)
+			{
+				if (this.AppLauncherButton != null)
+				{
+					ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
+					this.AppLauncherButton = null;
+				}
+
+				if (this.ToolbarButton == null)
+				{
+					this.InitializeToolbarButton();
+				}
+			}
+			else
+			{
+				if (this.ToolbarButton != null)
+				{
+					this.ToolbarButton.Destroy();
+					this.ToolbarButton = null;
+				}
+
+				if (this.AppLauncherButton == null)
+				{
+					this.InitializeAppLauncherButton();
+				}
+
+			}
+
+			this.saveTimer += Time.deltaTime;
+
+			if (this.saveTimer > 2f)
+			{
+				if (this.configDirty)
+				{
+
+					Tools.PostDebugMessage(string.Format(
+							"{0}: Time to save, checking if configDirty: {1}",
+							this.GetType().Name,
+							this.configDirty
+						));
+
+					this.SaveConfig();
+					this.saveTimer = 0;
+				}
+			}
+
+			this.UpdateTimer += Time.deltaTime;
+
+			if (this.onUpdate != null)
+			{
+				this.onUpdate(this);
+			}
 		}
 
 		public virtual void FixedUpdate()
@@ -533,10 +494,10 @@
 			bool newPowerState = this.powerAvailable;
 
 			if (this.togglePower && this.consumeResource &&
-			    this.vessel.vesselType != VesselType.EVA &&
+			    this.Vessel.vesselType != VesselType.EVA &&
 			    TimeWarp.deltaTime != 0)
 			{
-				float powerReceived = this.vessel.rootPart.RequestResource(
+				float powerReceived = this.Vessel.rootPart.RequestResource(
 					this.resourceName,
 					this.resourceRate * TimeWarp.fixedDeltaTime
 				);
@@ -553,12 +514,14 @@
 				if (this.powerAvailable != newPowerState)
 				{
 					this.powerAvailable = newPowerState;
-					this.SetIconTexture(this.powerState | this.activeState);
-				}
-			}
-
-			foreach (IVOID_Module module in this.Modules)
-			{
+				}
+			}
+
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
 				if (module is IVOID_BehaviorModule)
 				{
 					((IVOID_BehaviorModule)module).FixedUpdate();
@@ -568,8 +531,11 @@
 
 		public void OnDestroy()
 		{
-			foreach (IVOID_Module module in this.Modules)
-			{
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
 				if (module is IVOID_BehaviorModule)
 				{
 					((IVOID_BehaviorModule)module).OnDestroy();
@@ -589,12 +555,23 @@
 			this.OnDestroy();
 		}
 
+		public override void StartGUI()
+		{
+			if (!this.GUIRunning)
+			{
+				RenderingManager.AddToPostDrawQueue(3, this.DrawGUI);
+			}
+		}
+
 		public void ResetGUI()
 		{
 			this.StopGUI();
 
-			foreach (IVOID_Module module in this.Modules)
-			{
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
 				module.StopGUI();
 				module.StartGUI();
 			}
@@ -602,7 +579,7 @@
 			this.StartGUI();
 		}
 
-		public void VOIDMainWindow(int _)
+		public override void ModuleWindow(int id)
 		{
 			GUILayout.BeginVertical();
 
@@ -616,15 +593,22 @@
 					if (GUILayout.Button("Power " + str))
 					{
 						togglePower.value = !togglePower;
-						this.SetIconTexture(this.powerState | this.activeState);
 					}
 				}
 
 				if (togglePower || !HighLogic.LoadedSceneIsFlight)
 				{
-					foreach (IVOID_Module module in this.Modules)
+					IVOID_Module module;
+					for (int idx = 0; idx < this.modules.Count; idx++)
 					{
-						module.toggleActive = GUILayout.Toggle(module.toggleActive, module.Name);
+						module = this.modules[idx];
+
+						if (module is VOID_ConfigWindow)
+						{
+							continue;
+						}
+
+						module.Active = GUITools.Toggle(module.Active, module.Name);
 					}
 				}
 			}
@@ -633,30 +617,75 @@
 				GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
 			}
 
-			this.configWindowMinimized.value = !GUILayout.Toggle(!this.configWindowMinimized, "Configuration");
+			VOID_ConfigWindow.Instance.Active = GUITools.Toggle(
+				VOID_ConfigWindow.Instance.Active,
+				"Configuration"
+			);
 
 			GUILayout.EndVertical();
-			GUI.DragWindow();
-		}
-
-		public void VOIDConfigWindow(int _)
-		{
-			GUILayout.BeginVertical();
-
-			this.DrawConfigurables();
-
-			GUILayout.EndVertical();
-			GUI.DragWindow();
+
+			base.ModuleWindow(id);
 		}
 
 		public override void DrawConfigurables()
 		{
 			GUIContent _content;
 
-			this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available");
-
-			this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value,
+			this.useToolbarManager.value = GUITools.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available");
+
+			this.vesselSimActive.value = GUITools.Toggle(this.vesselSimActive.value,
 				"Enable Engineering Calculations");
+
+			bool useEarthTime = (this.TimeScale & VOID_TimeScale.KERBIN_TIME) == 0u;
+			bool useSiderealTime = (this.TimeScale & VOID_TimeScale.SOLAR_DAY) == 0u;
+			bool useRoundedScale = (this.TimeScale & VOID_TimeScale.ROUNDED_SCALE) != 0u;
+
+			useEarthTime = GUITools.Toggle(useEarthTime, "Use Earth Time (changes KSP option)");
+
+			GameSettings.KERBIN_TIME = !useEarthTime;
+
+			useSiderealTime = GUITools.Toggle(
+				useSiderealTime,
+				string.Format(
+					"Time Scale: {0}",
+					useSiderealTime ? "Sidereal" : "Solar"
+				)
+			);
+
+			useRoundedScale = GUITools.Toggle(
+				useRoundedScale,
+				string.Format(
+					"Time Scale: {0}",
+					useRoundedScale ? "Rounded" : "True"
+				)
+			);
+
+			if (useEarthTime)
+			{
+				this.TimeScale &= ~VOID_TimeScale.KERBIN_TIME;
+			}
+			else
+			{
+				this.TimeScale |= VOID_TimeScale.KERBIN_TIME;
+			}
+
+			if (useSiderealTime)
+			{
+				this.TimeScale &= ~VOID_TimeScale.SOLAR_DAY;
+			}
+			else
+			{
+				this.TimeScale |= VOID_TimeScale.SOLAR_DAY;
+			}
+
+			if (useRoundedScale)
+			{
+				this.TimeScale |= VOID_TimeScale.ROUNDED_SCALE;
+			}
+			else
+			{
+				this.TimeScale &= ~VOID_TimeScale.ROUNDED_SCALE;
+			}
 
 			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
@@ -668,11 +697,11 @@
 			_content.tooltip = "Select previous skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this._skinIdx--;
+				this.skinIdx--;
 				Tools.PostDebugMessage(string.Format(
-					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
+					"{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
 					this.GetType().Name,
-					this._skinName,
+					this.skinName,
 					this.validSkins.Count
 				));
 			}
@@ -685,24 +714,24 @@
 			_content.tooltip = "Select next skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this._skinIdx++;
+				this.skinIdx++;
 				Tools.PostDebugMessage(string.Format(
-					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
+					"{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
 					this.GetType().Name,
-					this._skinName,
+					this.skinName,
 					this.validSkins.Count
 				));
 			}
 
-			this._skinIdx %= this.skinNames.Length;
-			if (this._skinIdx < 0)
-			{
-				this._skinIdx += this.skinNames.Length;
-			}
-
-			if (this._skinName != skinNames[this._skinIdx])
-			{
-				this._skinName.value = skinNames[this._skinIdx];
+			this.skinIdx %= this.skinNames.Length;
+			if (this.skinIdx < 0)
+			{
+				this.skinIdx += this.skinNames.Length;
+			}
+
+			if (this.skinName != skinNames[this.skinIdx])
+			{
+				this.skinName.value = skinNames[this.skinIdx];
 				this.GUIStylesLoaded = false;
 			}
 
@@ -712,59 +741,63 @@
 			GUILayout.Label("Update Rate (Hz):");
 			if (this.stringFrequency == null)
 			{
-				this.stringFrequency = (1f / this.updatePeriod).ToString();
+				this.stringFrequency = (1f / this.UpdatePeriod).ToString();
 			}
 			this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true));
 
 			if (GUILayout.Button("Apply"))
 			{
-				double updateFreq = 1f / this.updatePeriod;
+				double updateFreq = 1f / this.UpdatePeriod;
 				double.TryParse(stringFrequency, out updateFreq);
-				this._updatePeriod = 1 / updateFreq;
+				this.updatePeriod.value = 1 / updateFreq;
 			}
 			GUILayout.EndHorizontal();
 
-			foreach (IVOID_Module mod in this.Modules)
-			{
-				mod.DrawConfigurables();
-			}
-
-			this.factoryReset = GUILayout.Toggle(this.factoryReset, "Factory Reset");
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
+				module.DrawConfigurables();
+			}
+
+			this.FactoryReset = GUITools.Toggle(this.FactoryReset, "Factory Reset");
 		}
 
 		protected void UpdateSimManager()
 		{
-			if (SimManager.ResultsReady())
-			{
-				Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
-
-				this.Stages = SimManager.Stages;
-
-				if (this.Stages != null)
-				{
-					this.LastStage = this.Stages.Last();
-				}
-
-				if (HighLogic.LoadedSceneIsEditor)
-				{
-					SimManager.Gravity = VOID_Data.KerbinGee;
-				}
-				else
-				{
-					double radius = this.vessel.Radius();
-					SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius);
-				}
-
-				SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d));
-
-				SimManager.TryStartSimulation();
-			}
+			if (HighLogic.LoadedSceneIsFlight)
+			{
+				double radius = this.Vessel.Radius();
+				SimManager.Gravity = this.Vessel.mainBody.gravParameter / (radius * radius);
+				SimManager.Atmosphere = this.Vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres;
+				SimManager.Mach = this.Vessel.mach;
+				BuildAdvanced.Altitude = this.Vessel.altitude;
+				CelestialBodies.SelectedBody = this.Vessel.mainBody;
+			}
+
 			#if DEBUG
-			else
-			{
-				Tools.PostDebugMessage(this, "VesselSimulator results not ready.");
-			}
+			SimManager.logOutput = true;
 			#endif
+
+			SimManager.TryStartSimulation();
+
+			Tools.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²",
+				SimManager.Atmosphere,
+				SimManager.Gravity
+			);
+		}
+
+		protected void GetSimManagerResults()
+		{
+			Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
+
+			this.Stages = SimManager.Stages;
+
+			if (this.Stages != null)
+			{
+				this.LastStage = this.Stages.Last();
+			}
 		}
 
 		protected void LoadModulesOfType<U>()
@@ -772,10 +805,17 @@
 			Tools.DebugLogger sb = Tools.DebugLogger.New(this);
 			sb.AppendLine("Loading modules...");
 
-			foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies)
-			{
-				foreach (Type loadedType in assy.assembly.GetExportedTypes())
-				{
+			AssemblyLoader.LoadedAssembly assy;
+			for (int aIdx = 0; aIdx < AssemblyLoader.loadedAssemblies.Count; aIdx++)
+			{
+				assy = AssemblyLoader.loadedAssemblies[aIdx];
+
+				Type[] loadedTypes = assy.assembly.GetExportedTypes();
+				Type loadedType;
+				for (int tIdx = 0; tIdx < loadedTypes.Length; tIdx++)
+				{
+					loadedType = loadedTypes[tIdx];
+
 					if (
 						loadedType.IsInterface ||
 						loadedType.IsAbstract ||
@@ -788,46 +828,6 @@
 
 					sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name);
 
-					GameScenes[] validScenes = null;
-
-					foreach (var attr in loadedType.GetCustomAttributes(true))
-					{
-						if (attr is VOID_ScenesAttribute)
-						{
-							validScenes = ((VOID_ScenesAttribute)attr).ValidScenes;
-
-							sb.Append("VOID_ScenesAttribute found;");
-
-							break;
-						}
-					}
-
-					if (validScenes == null)
-					{
-						validScenes = new GameScenes[] { GameScenes.FLIGHT };
-
-
-						sb.Append("VOID_ScenesAttribute not found;");
-
-					}
-
-					sb.AppendFormat(
-						" validScenes set to {0}.",
-						string.Join(
-							", ",
-							validScenes.Select(s => Enum.GetName(typeof(GameScenes), s)).ToArray()
-						)
-					);
-
-					if (!validScenes.Contains(HighLogic.LoadedScene))
-					{
-						sb.AppendFormat("  {0} not found in validScenes, skipping.",
-							Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene));
-						continue;
-					}
-
-					sb.AppendFormat("Loading IVOID_Module type {0}...", loadedType.Name);
-
 					try
 					{
 						this.LoadModule(loadedType);
@@ -844,7 +844,7 @@
 				}
 			}
 
-			this._modulesLoaded = true;
+			this.modulesLoaded = true;
 
 			sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count);
 
@@ -853,7 +853,7 @@
 
 		protected void LoadModule(Type T)
 		{
-			var existingModules = this._modules.Where(mod => mod.GetType().Name == T.Name);
+			var existingModules = this.modules.Where(mod => mod.GetType().Name == T.Name);
 			if (existingModules.Any())
 			{
 				Tools.PostDebugMessage(string.Format(
@@ -866,7 +866,9 @@
 
 			var InstanceProperty = T.GetProperty(
 				"Instance",
-				System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
+				System.Reflection.BindingFlags.Static |
+				System.Reflection.BindingFlags.Public |
+				System.Reflection.BindingFlags.FlattenHierarchy
 			);
 
 			object modInstance = null;
@@ -886,14 +888,24 @@
 				module = Activator.CreateInstance(T) as IVOID_Module;
 			}
 
-			module.LoadConfig();
-			this._modules.Add(module);
-
-			Tools.PostDebugMessage(string.Format(
-				"{0}: loaded module {1}.",
-				this.GetType().Name,
-				T.Name
-			));
+			if (module.InValidGame && module.InValidScene)
+			{
+				module.LoadConfig();
+				this.modules.Add(module);
+
+				Tools.PostDebugMessage(string.Format(
+						"{0}: loaded module {1}.",
+						this.GetType().Name,
+						T.Name
+					));
+			}
+			else
+			{
+				if (module is IDisposable)
+				{
+					(module as IDisposable).Dispose();
+				}
+			}
 		}
 
 		protected void LoadSkins()
@@ -926,29 +938,29 @@
 
 			for (int i = 0; i < this.skinNames.Length; i++)
 			{
-				if (this.skinNames[i] == this._skinName)
-				{
-					this._skinIdx = i;
+				if (this.skinNames[i] == this.skinName)
+				{
+					this.skinIdx = i;
 				}
 				if (this.skinNames[i] == this.defaultSkin)
 				{
 					defaultIdx = i;
 				}
-				if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue)
+				if (this.skinIdx != int.MinValue && defaultIdx != int.MinValue)
 				{
 					break;
 				}
 			}
 
-			if (this._skinIdx == int.MinValue)
-			{
-				this._skinIdx = defaultIdx;
+			if (this.skinIdx == int.MinValue)
+			{
+				this.skinIdx = defaultIdx;
 			}
 
 			Tools.PostDebugMessage(string.Format(
 				"{0}: _skinIdx = {1}.",
 				this.GetType().Name,
-				this._skinName.ToString()
+				this.skinName.ToString()
 			));
 
 			this.skinsLoaded = true;
@@ -966,28 +978,35 @@
 			this.GUIStylesLoaded = true;
 		}
 
-		protected void LoadVesselTypes()
-		{
-			this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToList();
-			this.vesselTypesLoaded = true;
-		}
-
 		protected void LoadBeforeUpdate()
 		{
 			if (!this.vesselTypesLoaded)
 			{
-				this.LoadVesselTypes();
-			}
-
-			if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
-			{
-				this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
-				this.sortedBodyList.Sort(new CBListComparer());
-				this.sortedBodyList.Reverse();
-
-				Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
-			}
-
+				this.AllVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToArray();
+				this.vesselTypesLoaded = true;
+			}
+
+			if (this.SortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
+			{
+				this.SortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
+				this.SortedBodyList.Sort(new CBListComparer());
+				this.SortedBodyList.Reverse();
+
+				Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.SortedBodyList.Select(b => b.bodyName).ToArray())));
+			}
+
+			// SimManager initialization that we don't necessarily want to repeat every Update.
+			if (!this.simManagerLoaded && this.HomeBody != null)
+			{
+				SimManager.Gravity = VOID_Data.KerbinGee;
+				SimManager.Atmosphere = 0d;
+				SimManager.Mach = 1d;
+				CelestialBodies.SelectedBody = this.HomeBody;
+				BuildAdvanced.Altitude = 0d;
+				SimManager.OnReady += this.GetSimManagerResults;
+
+				this.simManagerLoaded = true;
+			}
 		}
 
 		protected void InitializeToolbarButton()
@@ -1037,8 +1056,7 @@
 
 		protected void ToggleMainWindow()
 		{
-			this.mainGuiMinimized = !this.mainGuiMinimized;
-			this.SetIconTexture(this.powerState | this.activeState);
+			this.Active = !this.Active;
 		}
 
 		protected void SetIconTexture(IconState state)
@@ -1064,49 +1082,37 @@
 
 		protected void SetIconTexture(string texturePath)
 		{
+			if (texturePath == null)
+			{
+				return;
+			}
+
 			if (this.ToolbarButton != null)
 			{
 				this.ToolbarButton.TexturePath = texturePath;
 			}
 
-			this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
-
 			if (this.AppLauncherButton != null)
 			{
+				this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
+
 				this.AppLauncherButton.SetTexture(VOIDIconTexture);
 			}
 		}
 
-		protected virtual void CheckAndSave()
-		{
-			this.saveTimer += Time.deltaTime;
-
-			if (this.saveTimer > 2f)
-			{
-				if (!this.configDirty)
-				{
-					return;
-				}
-
-				Tools.PostDebugMessage(string.Format(
-					"{0}: Time to save, checking if configDirty: {1}",
-					this.GetType().Name,
-					this.configDirty
-				));
-
-				this.SaveConfig();
-				this.saveTimer = 0;
-			}
-		}
-
 		public override void LoadConfig()
 		{
 			base.LoadConfig();
 
-			foreach (IVOID_Module module in this.Modules)
-			{
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
 				module.LoadConfig();
 			}
+
+			this.TimeScale |= GameSettings.KERBIN_TIME ? VOID_TimeScale.KERBIN_TIME : 0u;
 		}
 
 		public override void SaveConfig()
@@ -1120,11 +1126,14 @@
 
 			config.load();
 
-			this._SaveToConfig(config);
-
-			foreach (IVOID_Module module in this.Modules)
-			{
-				module._SaveToConfig(config);
+			this.Save(config);
+
+			IVOID_Module module;
+			for (int idx = 0; idx < this.modules.Count; idx++)
+			{
+				module = this.modules[idx];
+
+				module.Save(config);
 			}
 
 			config.save();
@@ -1134,18 +1143,18 @@
 
 		public VOIDCore_Generic()
 		{
-			this.Name = "VOID Core";
-
 			System.Version version = this.GetType().Assembly.GetName().Version;
 
 			this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision);
 
+			this.Name = string.Format("VOID {0}", this.VoidVersion.ToString());
+
 			this.powerAvailable = true;
 
-			this.toggleActive = true;
-
-			this._skinName = this.defaultSkin;
-			this._skinIdx = int.MinValue;
+			this.Active = true;
+
+			this.skinName = (VOID_SaveValue<string>)this.defaultSkin;
+			this.skinIdx = int.MinValue;
 
 			this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow";
 			this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow";
@@ -1153,24 +1162,24 @@
 			this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark";
 
 			this.saveTimer = 0f;
-			this.updateTimer = 0f;
-
-			this.vesselSimActive = true;
-
-			this.UseToolbarManager = ToolbarManager.ToolbarAvailable;
+			this.UpdateTimer = 0f;
+
+			this.vesselSimActive = (VOID_SaveValue<bool>)true;
+
+			this.useToolbarManager = (VOID_SaveValue<bool>)ToolbarManager.ToolbarAvailable;
 
 			this.LoadConfig();
 
-			this._configVersion = VOIDCore.CONFIG_VERSION;
-			
-			this.SetIconTexture(this.powerState | this.activeState);
-
-			this.factoryReset = false;
-		}
-
-		public virtual void Dispose()
+			this.configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
+
+			this.FactoryReset = false;
+		}
+
+		public override void Dispose()
 		{
 			this.StopGUI();
+
+			this.onSkinChanged(this);
 
 			if (this.AppLauncherButton != null)
 			{
@@ -1186,15 +1195,6 @@
 			_instance = null;
 			_initialized = false;
 		}
-
-		protected enum IconState
-		{
-			PowerOff = 1,
-			PowerOn = 2,
-			Inactive = 4,
-			Active = 8
-		}
 	}
 }
 
-