Major reworking of the HUD underpinnings to be more modular and require less code duplication. Also made the Editor HUD movable, but for now it's stuck along the left edge.
Major reworking of the HUD underpinnings to be more modular and require less code duplication. Also made the Editor HUD movable, but for now it's stuck along the left edge.

--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -39,7 +39,7 @@
 // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("0.15.*")]
+[assembly: AssemblyVersion("0.16.*")]
 // The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
 //[assembly: AssemblyDelaySign(false)]

--- a/VOID.csproj
+++ b/VOID.csproj
@@ -100,6 +100,7 @@
     <Compile Include="VOID_StageInfo.cs" />
     <Compile Include="VOID_Styles.cs" />
     <Compile Include="VOID_Data.cs" />
+    <Compile Include="VOID_HUDModule.cs" />
   </ItemGroup>
   <ProjectExtensions>
     <MonoDevelop>

--- a/VOIDEditorMaster.cs
+++ b/VOIDEditorMaster.cs
@@ -40,7 +40,7 @@
 //
 ///////////////////////////////////////////////////////////////////////////////
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using ToadicusTools;
@@ -105,6 +105,26 @@
 
 			this.Core.OnGUI();
 		}
+
+		public void OnDestroy()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnDestroy();
+		}
+
+		public void OnApplicationQuit()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnApplicationQuit();
+		}
 	}
 }
 

--- a/VOIDFlightMaster.cs
+++ b/VOIDFlightMaster.cs
@@ -42,7 +42,7 @@
 
 using System;
 using UnityEngine;
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using ToadicusTools;
 
 namespace VOID
@@ -104,6 +104,26 @@
 
 			this.Core.OnGUI();
 		}
+
+		public void OnDestroy()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnDestroy();
+		}
+
+		public void OnApplicationQuit()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnApplicationQuit();
+		}
     }
 }
 

--- a/VOID_CBInfoBrowser.cs
+++ b/VOID_CBInfoBrowser.cs
@@ -286,13 +286,13 @@
 		    else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
@@ -301,10 +301,10 @@
 		    else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));

--- a/VOID_Core.cs
+++ b/VOID_Core.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -178,6 +178,12 @@
 		internal IButton ToolbarButton;
 
 		internal ApplicationLauncherButton AppLauncherButton;
+
+		/*
+		 * Events
+		 * */
+		public delegate void VOIDEventHandler(object sender);
+		public event VOIDEventHandler onApplicationQuit;
 
 		/*
 		 * Properties
@@ -625,6 +631,11 @@
 			}
 		}
 
+		public void OnApplicationQuit()
+		{
+			this.onApplicationQuit(this);
+		}
+
 		public void ResetGUI()
 		{
 			this.StopGUI();
@@ -798,7 +809,7 @@
 					SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius);
 				}
 
-				SimManager.minSimTime = (long)(this.updatePeriod * 1000);
+				SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d));
 
 				SimManager.TryStartSimulation();
 			}
@@ -985,7 +996,7 @@
 			this.ToolbarButton.Text = this.VoidName;
 			this.SetIconTexture(this.powerState | this.activeState);
 
-			this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH);
+			this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT);
 
 			this.ToolbarButton.OnClick += 
 				(e) =>

--- a/VOID_Data.cs
+++ b/VOID_Data.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -242,7 +242,7 @@
 						return double.NaN;
 					}
 
-					return core.LastStage.totalMass - core.LastStage.totalBaseMass;
+					return core.LastStage.resourceMass;
 				},
 				"tons"
 			);
@@ -257,7 +257,7 @@
 						return double.NaN;
 					}
 
-					return core.LastStage.mass - core.LastStage.baseMass;
+					return core.LastStage.resourceMass;
 				},
 				"tons"
 			);
@@ -844,7 +844,7 @@
 						format = string.Intern("T + {0}");
 					}
 
-					return string.Format(format, VOID_Tools.ConvertInterval(interval));
+					return string.Format(format, VOID_Tools.FormatInterval(interval));
 				}
 			);
 
@@ -886,7 +886,7 @@
 						format = string.Intern("T + {0}");
 					}
 
-					return string.Format(format, VOID_Tools.ConvertInterval(interval));
+					return string.Format(format, VOID_Tools.FormatInterval(interval));
 				}
 			);
 
@@ -1040,13 +1040,13 @@
 		public static readonly VOID_StrValue timeToApo =
 			new VOID_StrValue(
 				"Time to Apoapsis",
-				new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToAp))
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.timeToAp))
 			);
 
 		public static readonly VOID_StrValue timeToPeri =
 			new VOID_StrValue(
 				"Time to Periapsis",
-				new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToPe))
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.timeToPe))
 			);
 
 		public static readonly VOID_DoubleValue orbitInclination =
@@ -1072,7 +1072,7 @@
 		public static readonly VOID_StrValue orbitPeriod =
 			new VOID_StrValue(
 				"Period",
-				new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.period))
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.period))
 			);
 
 		public static readonly VOID_DoubleValue semiMajorAxis =

--- a/VOID_DataLogger.cs
+++ b/VOID_DataLogger.cs
@@ -41,29 +41,34 @@
 		/*
 		 * Fields
 		 * */
-		protected bool stopwatch1_running;
+		#region Fields
 
 		protected bool _loggingActive;
-		protected bool first_write;
-
-		protected double stopwatch1;
-
-		protected string csv_log_interval_str;
-
-		protected float csv_log_interval;
-
-		protected double csvCollectTimer;
-
-		protected System.Text.UTF8Encoding utf8Encoding;
+		protected bool firstWrite;
+
+		[AVOID_SaveValue("logInterval")]
+		protected VOID_SaveValue<float> logInterval;
+		protected string logIntervalStr;
+
+		protected float csvCollectTimer;
+
+		protected List<byte> csvBytes;
+
+		protected string _fileName;
 		protected FileStream _outputFile;
 
 		protected uint outstandingWrites;
 
-		protected List<string> csvList = new List<string>();
+		protected System.Text.UTF8Encoding _utf8Encoding;
+
+		#endregion
 
 		/*
 		 * Properties
 		 * */
+
+		#region Properties
+
 		// TODO: Add configurable or incremental file names.
 		protected bool loggingActive
 		{
@@ -77,40 +82,36 @@
 				{
 					if (value)
 					{
-
+						this.csvCollectTimer = 0f;
 					}
 					else
 					{
-						if (this._outputFile != null)
-						{
-							Tools.DebugLogger logger = Tools.DebugLogger.New(this);
-
-							logger.Append("CSV logging disabled, ");
-
-							logger.Append("disposing file.");
-							logger.Print();
-							this.outputFile.Dispose();
-							this._outputFile = null;
-						}
+						this.CloseFileIfOpen();
 					}
 
 					this._loggingActive = value;
 				}
 			}
 		}
+
 		protected string fileName
 		{
 			get
 			{
-				return KSP.IO.IOUtils.GetFilePathFor(
-					typeof(VOID_Core),
-					string.Format(
-						"{0}_{1}",
-						this.vessel.vesselName,
-						"data.csv"
-					),
-					null
-				);
+				if (this._fileName == null || this._fileName == string.Empty)
+				{
+					this._fileName = KSP.IO.IOUtils.GetFilePathFor(
+						typeof(VOID_Core),
+						string.Format(
+							"{0}_{1}",
+							this.vessel.vesselName,
+							"data.csv"
+						),
+						null
+					);
+				}
+
+				return this._fileName;
 			}
 		}
 
@@ -126,154 +127,85 @@
 					if (File.Exists(this.fileName))
 					{
 						logger.Append("append");
-						this._outputFile = new FileStream(this.fileName, FileMode.Append, FileAccess.Write, FileShare.Write, 512, true);
+						this._outputFile = new FileStream(
+							this.fileName,
+							FileMode.Append,
+							FileAccess.Write,
+							FileShare.Read,
+							512,
+							true
+						);
 					}
 					else
 					{
 						logger.Append("create");
-						this._outputFile = new FileStream(this.fileName, FileMode.Create, FileAccess.Write, FileShare.Write, 512, true);
-
-						byte[] bom = utf8Encoding.GetPreamble();
+						this._outputFile = new FileStream(
+							this.fileName,
+							FileMode.Create,
+							FileAccess.Write,
+							FileShare.Read,
+							512,
+							true
+						);
+
+						byte[] byteOrderMark = utf8Encoding.GetPreamble();
 
 						logger.Append(" and writing preamble");
-						outputFile.Write(bom, 0, bom.Length);
+						this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);
 					}
 
 					logger.Append('.');
+
+					logger.AppendFormat("  File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");
+
 					logger.Print();
 				}
 
 				return this._outputFile;
 			}
 		}
+
+		public UTF8Encoding utf8Encoding
+		{
+			get
+			{
+				if (this._utf8Encoding == null)
+				{
+					this._utf8Encoding = new UTF8Encoding(true);
+				}
+
+				return this._utf8Encoding;
+			}
+		}
+
+		#endregion
 
 		/*
 		 * Methods
 		 * */
-		public VOID_DataLogger()
-		{
-			this._Name = "CSV Data Logger";
-
-			this.stopwatch1_running = false;
-
-			this.loggingActive = false;
-			this.first_write = true;
-
-			this.stopwatch1 = 0;
-			this.csv_log_interval_str = "0.5";
-
-			this.csvCollectTimer = 0;
-			this.outstandingWrites = 0;
-
-			this.WindowPos.x = Screen.width - 520;
-			this.WindowPos.y = 85;
-		}
-
-		public override void ModuleWindow(int _)
-		{
-			GUIStyle txt_white = new GUIStyle(GUI.skin.label);
-			txt_white.normal.textColor = txt_white.focused.textColor = Color.white;
-			txt_white.alignment = TextAnchor.UpperRight;
-			GUIStyle txt_green = new GUIStyle(GUI.skin.label);
-			txt_green.normal.textColor = txt_green.focused.textColor = Color.green;
-			txt_green.alignment = TextAnchor.UpperRight;
-			GUIStyle txt_yellow = new GUIStyle(GUI.skin.label);
-			txt_yellow.normal.textColor = txt_yellow.focused.textColor = Color.yellow;
-			txt_yellow.alignment = TextAnchor.UpperRight;
-
-			GUILayout.BeginVertical();
-
-			GUILayout.Label("System time: " + DateTime.Now.ToString("HH:mm:ss"));
-			GUILayout.Label(VOID_Tools.ConvertInterval(stopwatch1));
-
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			if (GUILayout.Button("Start"))
-			{
-				if (stopwatch1_running == false) stopwatch1_running = true;
-			}
-			if (GUILayout.Button("Stop"))
-			{
-				if (stopwatch1_running == true) stopwatch1_running = false;
-			}
-			if (GUILayout.Button("Reset"))
-			{
-				if (stopwatch1_running == true) stopwatch1_running = false;
-				stopwatch1 = 0;
-			}
-			GUILayout.EndHorizontal();
-
-			GUIStyle label_style = txt_white;
-			string log_label = "Inactive";
-			if (loggingActive && vessel.situation.ToString() == "PRELAUNCH")
-			{
-				log_label = "Awaiting launch";
-				label_style = txt_yellow;
-			}
-			if (loggingActive && vessel.situation.ToString() != "PRELAUNCH")
-			{
-				log_label = "Active";
-				label_style = txt_green;
-			}
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			this.loggingActive = GUILayout.Toggle(loggingActive, "Data logging: ", GUILayout.ExpandWidth(false));
-
-			GUILayout.Label(log_label, label_style, GUILayout.ExpandWidth(true));
-			GUILayout.EndHorizontal();
-
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
-			csv_log_interval_str = GUILayout.TextField(csv_log_interval_str, GUILayout.ExpandWidth(true));
-			GUILayout.Label("s", GUILayout.ExpandWidth(false));
-			GUILayout.EndHorizontal();
-
-			float new_log_interval;
-			if (float.TryParse(csv_log_interval_str, out new_log_interval))
-			{
-				csv_log_interval = new_log_interval;
-			}
-
-			GUILayout.EndVertical();
-			GUI.DragWindow();
-		}
-
+		#region Monobehaviour Lifecycle
 		public void Update()
 		{
+			if (this.csvBytes != null && this.csvBytes.Count > 0)
+			{
+				// csvList is not empty, write it
+				this.AsyncWriteData();
+			}
+
 			// CSV Logging
 			// from ISA MapSat
 			if (loggingActive)
 			{
 				//data logging is on
 				//increment timers
-				csvCollectTimer += Time.deltaTime;
-
-				if (csvCollectTimer >= csv_log_interval && vessel.situation != Vessel.Situations.PRELAUNCH)
+				this.csvCollectTimer += Time.deltaTime;
+
+				if (this.csvCollectTimer >= this.logInterval)
 				{
 					//data logging is on, vessel is not prelaunch, and interval has passed
 					//write a line to the list
-					line_to_csvList();  //write to the csv
+					this.CollectLogData();
 				}
-
-				if (csvList.Count > 0)
-				{
-					// csvList is not empty and interval between writings to file has elapsed
-					//write it
-
-					// Tools.PostDebugMessage("")
-
-					this.AsyncWriteData();
-				}
-			}
-			else
-			{
-				//data logging is off
-				//reset any timers and clear anything from csvList
-				csvCollectTimer = 0f;
-				if (csvList.Count > 0) csvList.Clear();
-			}
-
-			if (stopwatch1_running)
-			{
-				stopwatch1 += Time.deltaTime;
 			}
 		}
 
@@ -285,79 +217,93 @@
 
 			logger.Append("Destroying...");
 
-			if (this.csvList.Count > 0)
-			{
-				logger.Append(" Writing final data...");
-				this.AsyncWriteData();
-			}
-
-			while (this.outstandingWrites > 0)
-			{
-				System.Threading.Thread.Sleep(10);
-			}
-
-			if (this._outputFile != null)
-			{
-				logger.Append(" Closing File...");
-				this.outputFile.Close();
-			}
+			this.CloseFileIfOpen();
 
 			logger.Append(" Done.");
-			logger.Print();
-		}
-
-		~VOID_DataLogger()
-		{
-			this.OnDestroy();
-		}
-
-		protected void AsyncWriteCallback(IAsyncResult result)
-		{
-			Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
-
-			this.outputFile.EndWrite(result);
-			this.outstandingWrites--;
-		}
-
-		private void AsyncWriteData()
-		{
-			if (this.utf8Encoding == null)
-			{
-				this.utf8Encoding = new System.Text.UTF8Encoding(true, true);
-			}
-
-			List<byte> bytes = new List<byte>();
-
-			foreach (string line in this.csvList)
-			{
-				byte[] lineBytes = utf8Encoding.GetBytes(line);
-				bytes.AddRange(lineBytes);
-			}
-
-			WriteState state = new WriteState();
-
-			state.bytes = bytes.ToArray();
-			state.stream = this.outputFile;
-
-			this.outstandingWrites++;
-			var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
-
-			this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
-
-			this.csvList.Clear();
-		}
-
-		private void line_to_csvList()
-		{
+			logger.Print(false);
+		}
+
+		#endregion
+
+		#region VOID_Module Overrides
+
+		public override void LoadConfig()
+		{
+			base.LoadConfig();
+
+			this.logIntervalStr = this.logInterval.value.ToString("#.0##");
+		}
+
+		public override void ModuleWindow(int _)
+		{
+			GUILayout.BeginVertical();
+
+			GUILayout.Label(
+				string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")),
+				GUILayout.ExpandWidth(true)
+			);
+			GUILayout.Label(
+				string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())),
+				GUILayout.ExpandWidth(true)
+			);
+
+			GUIStyle activeLabelStyle = VOID_Styles.labelRed;
+			string activeLabelText = "Inactive";
+			if (loggingActive)
+			{
+				activeLabelText = "Active";
+				activeLabelStyle = VOID_Styles.labelGreen;
+			}
+
+			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
+			this.loggingActive = GUILayout.Toggle(loggingActive, "Data logging: ", GUILayout.ExpandWidth(false));
+			GUILayout.Label(activeLabelText, activeLabelStyle, GUILayout.ExpandWidth(true));
+
+			GUILayout.EndHorizontal();
+
+			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
+			GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
+
+			logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true));
+			GUILayout.Label("s", GUILayout.ExpandWidth(false));
+
+			GUILayout.EndHorizontal();
+
+			float newLogInterval;
+			if (float.TryParse(logIntervalStr, out newLogInterval))
+			{
+				logInterval.value = newLogInterval;
+				this.logIntervalStr = this.logInterval.value.ToString("#.0##");
+			}
+
+			GUILayout.EndVertical();
+
+			GUI.DragWindow();
+		}
+
+		#endregion
+
+		#region Data Collection
+
+		private void CollectLogData()
+		{
+			if (this.csvBytes == null)
+			{
+				this.csvBytes = new List<byte>();
+			}
+
 			//called if logging is on and interval has passed
 			//writes one line to the csvList
 
 			StringBuilder line = new StringBuilder();
 
-			if (first_write)
-			{
-				first_write = false;
+			if (firstWrite)
+			{
+				firstWrite = false;
 				line.Append(
+					"\"Kerbin Universal Time (s)\"," +
 					"\"Mission Elapsed Time (s)\t\"," +
 					"\"Altitude ASL (m)\"," +
 					"\"Altitude above terrain (m)\"," +
@@ -376,10 +322,13 @@
 				);
 			}
 
+			// Universal time
+			line.Append(Planetarium.GetUniversalTime().ToString("F2"));
+			line.Append(',');
+
 			//Mission time
 			line.Append(vessel.missionTime.ToString("F3"));
 			line.Append(',');
-
 
 			//Altitude ASL
 			line.Append(VOID_Data.orbitAltitude.Value.ToString("F3"));
@@ -430,7 +379,7 @@
 			line.Append(',');
 
 			//atm density
-			line.Append(Tools.MuMech_ToSI(VOID_Data.atmDensity.Value * 1000d, 3));
+			line.Append(VOID_Data.atmDensity.Value.ToString("G3"));
 			line.Append(',');
 
 			// Downrange Distance
@@ -438,16 +387,108 @@
 
 			line.Append('\n');
 
-			csvList.Add(line.ToString());
-
-			csvCollectTimer = 0f;
-		}
+			csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
+
+			this.csvCollectTimer = 0f;
+		}
+
+		#endregion
+
+		#region File IO Methods
+
+		protected void AsyncWriteCallback(IAsyncResult result)
+		{
+			Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
+
+			this.outputFile.EndWrite(result);
+			this.outstandingWrites--;
+		}
+
+		private void AsyncWriteData()
+		{
+			WriteState state = new WriteState();
+
+			state.bytes = this.csvBytes.ToArray();
+			state.stream = this.outputFile;
+
+			this.outstandingWrites++;
+			var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
+
+			this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
+
+			this.csvBytes.Clear();
+		}
+
+		private void CloseFileIfOpen()
+		{
+			Tools.DebugLogger logger = Tools.DebugLogger.New(this);
+
+			logger.AppendFormat("Cleaning up file {0}...", this.fileName);
+
+			if (this.csvBytes != null && this.csvBytes.Count > 0)
+			{
+				logger.Append(" Writing remaining data...");
+				this.AsyncWriteData();
+			}
+
+			logger.Append(" Waiting for writes to finish.");
+			while (this.outstandingWrites > 0)
+			{
+				logger.Append('.');
+				System.Threading.Thread.Sleep(10);
+			}
+
+			if (this._outputFile != null)
+			{
+				this._outputFile.Close();
+				this._outputFile = null;
+				logger.Append(" File closed.");
+			}
+
+			logger.Print(false);
+		}
+
+		#endregion
+
+		#region Constructors & Destructors
+
+		public VOID_DataLogger()
+		{
+			this._Name = "CSV Data Logger";
+
+			this.loggingActive = false;
+			this.firstWrite = true;
+
+			this.logInterval = 0.5f;
+			this.csvCollectTimer = 0f;
+
+			this.outstandingWrites = 0;
+
+			this.WindowPos.x = Screen.width - 520f;
+			this.WindowPos.y = 85f;
+
+			this.core.onApplicationQuit += delegate(object sender)
+			{
+				this.CloseFileIfOpen();
+			};
+		}
+
+		~VOID_DataLogger()
+		{
+			this.OnDestroy();
+		}
+
+		#endregion
+
+		#region Subclasses
 
 		private class WriteState
 		{
 			public byte[] bytes;
 			public FileStream stream;
 		}
+
+		#endregion
 	}
 }
 

--- a/VOID_EditorCore.cs
+++ b/VOID_EditorCore.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -115,7 +115,7 @@
 
 			foreach (IVOID_EditorModule module in this.Modules)
 			{
-				if (EditorLogic.startPod == null)
+				if (EditorLogic.RootPart == null)
 				{
 					module.StopGUI();
 					continue;
@@ -130,7 +130,7 @@
 				}
 			}
 
-			if (EditorLogic.startPod == null || !HighLogic.LoadedSceneIsEditor)
+			if (EditorLogic.RootPart == null || !HighLogic.LoadedSceneIsEditor)
 			{
 				this.StopGUI();
 				return;

--- a/VOID_EditorHUD.cs
+++ b/VOID_EditorHUD.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -37,41 +37,20 @@
 
 namespace VOID
 {
-	public class VOID_EditorHUD : VOID_Module, IVOID_EditorModule
+	public class VOID_EditorHUD : VOID_HUDModule, IVOID_EditorModule
 	{
 		/*
 		 * Fields
 		 * */
-		[AVOID_SaveValue("colorIndex")]
-		protected VOID_SaveValue<int> _colorIndex = 0;
-
-		protected List<Color> textColors = new List<Color>();
-
-		protected GUIStyle labelStyle;
-
+		[AVOID_SaveValue("ehudWindowPos")]
+		protected VOID_SaveValue<Rect> ehudWindowPos;
+
+		protected HUDWindow ehudWindow;
 		protected EditorVesselOverlays _vesselOverlays;
 
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
-		{
-			get
-			{
-				return this._colorIndex;
-			}
-			set
-			{
-				if (this._colorIndex >= this.textColors.Count - 1)
-				{
-					this._colorIndex = 0;
-					return;
-				}
-
-				this._colorIndex = value;
-			}
-		}
-
 		protected EditorVesselOverlays vesselOverlays
 		{
 			get
@@ -122,57 +101,26 @@
 
 			this.toggleActive = true;
 
-			this.textColors.Add(Color.green);
-			this.textColors.Add(Color.black);
-			this.textColors.Add(Color.white);
-			this.textColors.Add(Color.red);
-			this.textColors.Add(Color.blue);
-			this.textColors.Add(Color.yellow);
-			this.textColors.Add(Color.gray);
-			this.textColors.Add(Color.cyan);
-			this.textColors.Add(Color.magenta);
-
-			this.labelStyle = new GUIStyle ();
-			// this.labelStyle.alignment = TextAnchor.UpperRight;
-			this.labelStyle.normal.textColor = this.textColors [this.ColorIndex];
+			this.ehudWindow = new HUDWindow(
+				this.ehudWindowFunc,
+				new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f)
+			);
+			this.Windows.Add(this.ehudWindow);
+			this.ehudWindowPos = this.ehudWindow.WindowPos;
 
 			Tools.PostDebugMessage (this.GetType().Name + ": Constructed.");
 		}
 
-		public override void DrawGUI()
-		{
-			SimManager.RequestSimulation();
+		public void ehudWindowFunc(int id)
+		{
+			StringBuilder hudString = new StringBuilder();
 
 			if (this.core.LastStage == null)
 			{
 				return;
 			}
 
-			float hudLeft;
-			StringBuilder hudString;
-
-			if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Parts)
-			{
-				hudLeft = EditorPanels.Instance.partsPanelWidth + 10;
-			}
-			else if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions)
-			{
-				hudLeft = EditorPanels.Instance.actionsPanelWidth + 10;
-			}
-			else
-			{
-				return;
-			}
-
-			GUI.skin = this.core.Skin;
-
-			Rect hudPos = new Rect (hudLeft, 48, 300, 32);
-
-			hudString = new StringBuilder();
-
 			// GUI.skin = AssetBase.GetGUISkin("KSP window 2");
-
-			labelStyle.normal.textColor = textColors [ColorIndex];
 
 			hudString.Append("Total Mass: ");
 			hudString.Append(this.core.LastStage.totalMass.ToString("F3"));
@@ -212,18 +160,60 @@
 					).ToString("F3"));
 			}
 
-			GUI.Label (
-				hudPos,
-				hudString.ToString(),
-				labelStyle);
-		}
-
-		public override void DrawConfigurables()
-		{
-			if (GUILayout.Button ("Change HUD color", GUILayout.ExpandWidth (false)))
-			{
-				++this.ColorIndex;
-			}
+			GUILayout.Label(hudString.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
+
+			if (!this.positionsLocked)
+			{
+				GUI.DragWindow();
+			}
+
+			GUI.BringWindowToBack(id);
+		}
+
+		public override void DrawGUI()
+		{
+			float hudLeft;
+
+			if (EditorLogic.fetch.editorScreen == EditorScreen.Parts)
+			{
+				hudLeft = EditorPanels.Instance.partsPanelWidth + 10f;
+				hudLeft += EditorPartList.Instance.transformTopLeft.position.x -
+					EditorPartList.Instance.transformTopLeft.parent.parent.position.x -
+					72f;
+			}
+			else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions)
+			{
+				hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f;
+			}
+			else
+			{
+				return;
+			}
+
+			bool snapToEdge = Mathf.Abs(this.ehudWindowPos.value.xMin - hudLeft) < 15f;
+
+			Tools.PostDebugMessage(this,
+				"EditorPartList topLeft.parent.parent.position: {0}\n" +
+				"EditorPartList topLeft.parent.position: {1}\n" +
+				"EditorPartList topLeft.position: {2}\n" +
+				"snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})",
+				EditorPartList.Instance.transformTopLeft.parent.parent.position,
+				EditorPartList.Instance.transformTopLeft.parent.position,
+				EditorPartList.Instance.transformTopLeft.position,
+				snapToEdge, this.ehudWindowPos.value.xMin, hudLeft
+			);
+
+			base.DrawGUI();
+
+			Rect hudPos = this.ehudWindow.WindowPos;
+
+			hudPos.xMin = hudLeft;
+			hudPos.width = this.ehudWindow.defaultWindowPos.width;
+
+			this.ehudWindowPos.value = hudPos;
+
+			this.ehudWindow.WindowPos = this.ehudWindowPos;
+
 		}
 	}
 }

--- a/VOID_HUD.cs
+++ b/VOID_HUD.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -36,47 +36,22 @@
 
 namespace VOID
 {
-	public class VOID_HUD : VOID_Module, IVOID_Module
+	public class VOID_HUD : VOID_HUDModule, IVOID_Module
 	{
 		/*
 		 * Fields
 		 * */
-		[AVOID_SaveValue("colorIndex")]
-		protected VOID_SaveValue<int> _colorIndex;
-
-		protected List<Color> textColors;
-
-		protected Rect leftHUDdefaultPos;
-		protected Rect rightHUDdefaultPos;
-
 		[AVOID_SaveValue("leftHUDPos")]
 		protected VOID_SaveValue<Rect> leftHUDPos;
 		[AVOID_SaveValue("rightHUDPos")]
 		protected VOID_SaveValue<Rect> rightHUDPos;
 
-		[AVOID_SaveValue("positionsLocked")]
-		protected VOID_SaveValue<bool> positionsLocked;
+		protected HUDWindow leftWindow;
+		protected HUDWindow rightWindow;
 
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
-		{
-			get
-			{
-				return this._colorIndex;
-			}
-			set
-			{
-				if (this._colorIndex >= this.textColors.Count - 1)
-				{
-					this._colorIndex = 0;
-					return;
-				}
-
-				this._colorIndex = value;
-			}
-		}
 
 		/* 
 		 * Methods
@@ -87,29 +62,25 @@
 
 			this.toggleActive = true;
 
-			this._colorIndex = 0;
+			this.leftWindow = new HUDWindow(this.leftHUDWindow, new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f));
+			this.Windows.Add(this.leftWindow);
 
-			this.textColors = new List<Color>();
+			this.leftHUDPos = this.leftWindow.WindowPos;
 
-			this.textColors.Add(Color.green);
-			this.textColors.Add(Color.black);
-			this.textColors.Add(Color.white);
-			this.textColors.Add(Color.red);
-			this.textColors.Add(Color.blue);
-			this.textColors.Add(Color.yellow);
-			this.textColors.Add(Color.gray);
-			this.textColors.Add(Color.cyan);
-			this.textColors.Add(Color.magenta);
+			this.rightWindow = new HUDWindow(this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f));
+			this.Windows.Add(this.rightWindow);
 
-			this.leftHUDdefaultPos = new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f);
-			this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-
-			this.rightHUDdefaultPos = new Rect(Screen.width * .625f, 0f, 300f, 90f);
-			this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
-
-			this.positionsLocked = true;
+			this.rightHUDPos = this.rightWindow.WindowPos;
 
 			Tools.PostDebugMessage ("VOID_HUD: Constructed.");
+		}
+
+		public override void DrawGUI()
+		{
+			base.DrawGUI();
+
+			this.leftHUDPos.value = this.leftWindow.WindowPos;
+			this.rightHUDPos.value = this.rightWindow.WindowPos;
 		}
 
 		protected void leftHUDWindow(int id)
@@ -219,52 +190,6 @@
 
 			GUI.BringWindowToBack(id);
 		}
-
-		public override void DrawGUI()
-		{
-			VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex];
-
-			GUI.skin = this.core.Skin;
-
-			if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate))
-			{
-				SimManager.RequestSimulation();
-			}
-
-			this.leftHUDPos.value = GUI.Window(
-				this.core.windowID,
-				this.leftHUDPos,
-				VOID_Tools.GetWindowHandler(this.leftHUDWindow),
-				GUIContent.none,
-				GUIStyle.none
-			);
-
-			this.rightHUDPos.value = GUI.Window(
-				this.core.windowID,
-				this.rightHUDPos,
-				VOID_Tools.GetWindowHandler(this.rightHUDWindow),
-				GUIContent.none,
-				GUIStyle.none
-			);
-		}
-
-		public override void DrawConfigurables()
-		{
-			if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
-			{
-				++this.ColorIndex;
-			}
-
-			if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
-			{
-				this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-				this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
-			}
-
-			this.positionsLocked = GUILayout.Toggle(this.positionsLocked,
-				string.Intern("Lock HUD Positions"),
-				GUILayout.ExpandWidth(false));
-		}
 	}
 }
 

--- a/VOID_HUDAdvanced.cs
+++ b/VOID_HUDAdvanced.cs
@@ -26,7 +26,7 @@
 // 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 Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -37,37 +37,38 @@
 
 namespace VOID
 {
-	public class VOID_HUDAdvanced : VOID_Module, IVOID_Module
+	public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module
 	{
 		/*
 		 * Fields
 		 * */
 		protected VOID_HUD primaryHUD;
 
-		protected Rect leftHUDdefaultPos;
-		protected Rect rightHUDdefaultPos;
+		protected HUDWindow leftHUD;
+		protected HUDWindow rightHUD;
 
 		[AVOID_SaveValue("leftHUDPos")]
 		protected VOID_SaveValue<Rect> leftHUDPos;
 		[AVOID_SaveValue("rightHUDPos")]
 		protected VOID_SaveValue<Rect> rightHUDPos;
 
-		[AVOID_SaveValue("positionsLocked")]
-		protected VOID_SaveValue<bool> positionsLocked;
-
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
+		public override int ColorIndex
 		{
 			get
 			{
-				if (this.primaryHUD == null)
-				{
-					return 0;
-				}
-
-				return this.primaryHUD.ColorIndex;
+				if (this.primaryHUD != null)
+				{
+					return this.primaryHUD.ColorIndex;
+				}
+
+				return base.ColorIndex;
+			}
+			set
+			{
+				base.ColorIndex = value;
 			}
 		}
 
@@ -80,19 +81,23 @@
 
 			this.toggleActive = true;
 
-			this.leftHUDdefaultPos = new Rect(
+			this.leftHUD = new HUDWindow(this.leftHUDWindow, new Rect(
 				Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f,
 				Screen.height - 200f,
-				300f, 90f
+				300f, 90f)
 			);
-			this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-
-			this.rightHUDdefaultPos = new Rect(
+			this.Windows.Add(this.leftHUD);
+
+			this.leftHUDPos = this.leftHUD.WindowPos;
+
+			this.rightHUD = new HUDWindow(this.rightHUDWindow, new Rect(
 				Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f,
 				Screen.height - 200f,
-				300f, 90f
+				300f, 90f)
 			);
-			this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
+			this.Windows.Add(this.rightHUD);
+
+			this.rightHUDPos = this.rightHUD.WindowPos;
 
 			this.positionsLocked = true;
 
@@ -182,8 +187,8 @@
 				}
 
 				rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n",
-					VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnRemaining.Value),
-					VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnDuration.Value)
+					VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnRemaining.Value),
+					VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnDuration.Value)
 				);
 
 				if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty)
@@ -229,32 +234,11 @@
 					}
 				}
 			}
-			else
-			{
-				if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate))
-				{
-					SimManager.RequestSimulation();
-				}
-
-				this.leftHUDPos.value = GUI.Window(
-					this.core.windowID,
-					this.leftHUDPos,
-					VOID_Tools.GetWindowHandler(this.leftHUDWindow),
-					GUIContent.none,
-					GUIStyle.none
-				);
-
-				if (VOID_Data.upcomingManeuverNodes > 0)
-				{
-					this.rightHUDPos.value = GUI.Window(
-						this.core.windowID,
-						this.rightHUDPos,
-						VOID_Tools.GetWindowHandler(this.rightHUDWindow),
-						GUIContent.none,
-						GUIStyle.none
-					);
-				}
-			}
+
+			base.DrawGUI();
+
+			this.leftHUDPos.value = this.leftHUD.WindowPos;
+			this.rightHUDPos.value = this.rightHUD.WindowPos;
 		}
 
 		public override void DrawConfigurables()

file:b/VOID_HUDModule.cs (new)
--- /dev/null
+++ b/VOID_HUDModule.cs
@@ -1,1 +1,167 @@
+// VOID
+//
+// VOID_HUDModule.cs
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be used
+//    to endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+using KerbalEngineer.VesselSimulator;
+using KSP;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ToadicusTools;
+using UnityEngine;
+
+namespace VOID
+{
+	public abstract class VOID_HUDModule : VOID_Module
+	{
+		[AVOID_SaveValue("colorIndex")]
+		protected VOID_SaveValue<int> _colorIndex;
+
+		protected List<Color> textColors;
+
+		[AVOID_SaveValue("positionsLocked")]
+		protected VOID_SaveValue<bool> positionsLocked;
+
+		public virtual int ColorIndex
+		{
+			get
+			{
+				return this._colorIndex;
+			}
+			set
+			{
+				if (this._colorIndex >= this.textColors.Count - 1)
+				{
+					this._colorIndex = 0;
+					return;
+				}
+
+				this._colorIndex = value;
+			}
+		}
+
+		public virtual List<HUDWindow> Windows
+		{
+			get;
+			protected set;
+		}
+
+		public VOID_HUDModule() : base()
+		{
+			this._colorIndex = 0;
+
+			this.textColors = new List<Color>();
+
+			this.textColors.Add(Color.green);
+			this.textColors.Add(Color.black);
+			this.textColors.Add(Color.white);
+			this.textColors.Add(Color.red);
+			this.textColors.Add(Color.blue);
+			this.textColors.Add(Color.yellow);
+			this.textColors.Add(Color.gray);
+			this.textColors.Add(Color.cyan);
+			this.textColors.Add(Color.magenta);
+
+			this.positionsLocked = true;
+
+			this.Windows = new List<HUDWindow>();
+		}
+
+		public override void DrawGUI()
+		{
+			VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex];
+
+			GUI.skin = this.core.Skin;
+
+			if (HighLogic.LoadedSceneIsEditor ||
+				(TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
+			)
+			{
+				SimManager.RequestSimulation();
+			}
+
+			foreach (HUDWindow window in this.Windows)
+			{
+				window.WindowPos = GUI.Window(
+					this.core.windowID,
+					window.WindowPos,
+					VOID_Tools.GetWindowHandler(window.WindowFunction),
+					GUIContent.none,
+					GUIStyle.none
+				);
+			}
+		}
+
+		public override void DrawConfigurables()
+		{
+			if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
+			{
+				++this.ColorIndex;
+			}
+
+			if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
+			{
+				foreach (HUDWindow window in this.Windows)
+				{
+					window.WindowPos = new Rect(window.defaultWindowPos);
+				}
+			}
+
+			this.positionsLocked = GUILayout.Toggle(this.positionsLocked,
+				string.Intern("Lock HUD Positions"),
+				GUILayout.ExpandWidth(false));
+		}
+	}
+
+	public class HUDWindow
+	{
+		public readonly Rect defaultWindowPos;
+
+		public Action<int> WindowFunction
+		{
+			get;
+			private set;
+		}
+
+		public Rect WindowPos
+		{
+			get;
+			set;
+		}
+
+		private HUDWindow() {}
+
+		public HUDWindow(Action<int> windowFunc, Rect defaultPos)
+		{
+			this.WindowFunction = windowFunc;
+			this.defaultWindowPos = defaultPos;
+			this.WindowPos = new Rect(this.defaultWindowPos);
+		}
+	}
+}
+
+

--- a/VOID_Module.cs
+++ b/VOID_Module.cs
@@ -253,7 +253,6 @@
 			switch (HighLogic.LoadedScene)
 			{
 				case GameScenes.EDITOR:
-				case GameScenes.SPH:
 					if (cursorInWindow)
 					{
 						InputLockManager.SetControlLock(

--- a/VOID_Rendezvous.cs
+++ b/VOID_Rendezvous.cs
@@ -205,7 +205,7 @@
 					{
 						GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 						GUILayout.Label("Period:");
-						GUILayout.Label(VOID_Tools.ConvertInterval(v.orbit.period), GUILayout.ExpandWidth(false));
+						GUILayout.Label(VOID_Tools.FormatInterval(v.orbit.period), GUILayout.ExpandWidth(false));
 						GUILayout.EndHorizontal();
 
 						GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));

--- a/VOID_StageInfo.cs
+++ b/VOID_StageInfo.cs
@@ -3,7 +3,7 @@
 // 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/
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -99,7 +99,7 @@
 				(TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
 			)
 			{
-				Engineer.VesselSimulator.SimManager.RequestSimulation();
+				KerbalEngineer.VesselSimulator.SimManager.RequestSimulation();
 			}
 
 			if (!this.stylesApplied)

--- a/VOID_TWR.cs
+++ b/VOID_TWR.cs
@@ -27,7 +27,7 @@
 				(TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
 			)
 			{
-				Engineer.VesselSimulator.SimManager.RequestSimulation();
+				KerbalEngineer.VesselSimulator.SimManager.RequestSimulation();
 			}
 
 			GUILayout.BeginVertical();

--- a/VOID_Tools.cs
+++ b/VOID_Tools.cs
@@ -95,13 +95,13 @@
 		#endregion
 
 		#region VESSEL_EXTENSIONS_SCIENCE
-		public static CBAttributeMap.MapAttribute GetBiome(this Vessel vessel)
-		{
-			CBAttributeMap.MapAttribute mapAttribute;
+		public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel)
+		{
+			CBAttributeMapSO.MapAttribute mapAttribute;
 
 			try
 			{
-				CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap;
+				CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap;
 
 				double lat = vessel.latitude * Math.PI / 180d;
 				double lon = vessel.longitude * Math.PI / 180d;
@@ -162,7 +162,7 @@
 			}
 			catch (NullReferenceException)
 			{
-				mapAttribute = new CBAttributeMap.MapAttribute();
+				mapAttribute = new CBAttributeMapSO.MapAttribute();
 				mapAttribute.name = "N/A";
 			}
 
@@ -335,7 +335,7 @@
 						func(id);
 					}
 					#if DEBUG
-					catch (ArgumentException ex)
+					catch (ArgumentException)
 					#else
 					catch (ArgumentException)
 					#endif
@@ -373,7 +373,7 @@
 		/// </summary>
 		/// <returns>Human readable interval</returns>
 		/// <param name="seconds"></param>
-		public static string ConvertInterval(double seconds)
+		public static string FormatInterval(double seconds)
 		{
 			return UnpackedTime.FromSeconds(seconds).FormatAsSpan();
 		}

--- a/VOID_VesselInfo.cs
+++ b/VOID_VesselInfo.cs
@@ -26,8 +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 Engineer.VesselSimulator;
-using Engineer.Extensions;
+using KerbalEngineer.VesselSimulator;
+using KerbalEngineer.Extensions;
 using KSP;
 using System;
 using System.Collections.Generic;