Fixed some issues with the vessel simulation.
Fixed some issues with the vessel simulation.

--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,4 +1,4 @@
-1.0.12.0
+1.0.12.0, 01-12-2014
 	Added: Setting in Build Engineer to enable/disable vectored thrust calculations.
 	Added: Thrust torque field in Build Engineer (courtesy of mic_e).
 	Added: New readouts to the vessel category:
@@ -16,6 +16,8 @@
 		- Vectored Thrust Toggle
 
 	Fixed: The category selection within the section editors to not always reset back to 'Orbital'.
+	Fixed: Issue where the vessel simulation can sometimes permanently freeze.
+	Fixed: Issue where the vessel simulation would not show updates when the delay was set lower than the frame rate.
 
 1.0.11.3, 11-11-2014
     Changed: Gravity measurements for Isp to 9.82.

--- a/KerbalEngineer/Editor/BuildAdvanced.cs
+++ b/KerbalEngineer/Editor/BuildAdvanced.cs
@@ -132,6 +132,9 @@
                 this.bodiesList = this.gameObject.AddComponent<DropDown>();
                 this.bodiesList.DrawCallback = this.DrawBodiesList;
                 this.Load();
+
+                SimManager.OnReady -= this.GetStageInfo;
+                SimManager.OnReady += this.GetStageInfo;
             }
             catch (Exception ex)
             {
@@ -165,6 +168,11 @@
             }
         }
 
+        private void GetStageInfo()
+        {
+            this.stages = SimManager.Stages;
+        }
+
         protected void OnGUI()
         {
             try
@@ -173,13 +181,6 @@
                 {
                     return;
                 }
-
-                if (SimManager.ResultsReady())
-                {
-                    this.stages = SimManager.Stages;
-                }
-
-                SimManager.RequestSimulation();
 
                 if (this.stages == null)
                 {
@@ -267,6 +268,8 @@
                 }
 
                 SimManager.Velocity = this.atmosphericVelocity;
+
+                SimManager.RequestSimulation();
                 SimManager.TryStartSimulation();
             }
             catch (Exception ex)
@@ -492,9 +495,9 @@
             }
             GUILayout.EndHorizontal();
 
-            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime + "ms", this.settingStyle);
+            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.Milliseconds + "ms", this.settingStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 2000.0f);
+            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 2000.0f));
             GUI.skin = null;
         }
 

--- a/KerbalEngineer/Editor/BuildOverlayVessel.cs
+++ b/KerbalEngineer/Editor/BuildOverlayVessel.cs
@@ -99,6 +99,19 @@
             }
         }
 
+        protected void Awake()
+        {
+            try
+            {
+                SimManager.OnReady -= this.GetStageInfo;
+                SimManager.OnReady += this.GetStageInfo;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
+
         protected void Start()
         {
             try
@@ -160,6 +173,11 @@
             this.tabPosition.y = this.windowPosition.y - this.tabPosition.height;
         }
 
+        private void GetStageInfo()
+        {
+            this.lastStage = SimManager.LastStage;
+        }
+
         private void SetVesselInfo()
         {
             SimManager.Gravity = CelestialBodies.SelectedBody.Gravity;
@@ -175,11 +193,6 @@
 
             SimManager.RequestSimulation();
             SimManager.TryStartSimulation();
-
-            if (SimManager.ResultsReady())
-            {
-                this.lastStage = SimManager.LastStage;
-            }
 
             if (this.lastStage != null)
             {

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
@@ -28,6 +28,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Miscellaneous
 {
+    using System;
+
     public class SimulationDelay : ReadoutModule
     {
         #region Constructors
@@ -49,7 +51,7 @@
             GUILayout.BeginHorizontal();
             GUILayout.Label("Sim Delay", this.NameStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 1000.0f);
+            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 1000.0f));
             GUI.skin = null;
             GUILayout.EndHorizontal();
         }

--- a/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
@@ -19,14 +19,19 @@
 
 #region Using Directives
 
-using System;
 
-using KerbalEngineer.VesselSimulator;
 
 #endregion
 
 namespace KerbalEngineer.Flight.Readouts.Vessel
 {
+    #region Using Directives
+
+    using System;
+    using VesselSimulator;
+
+    #endregion
+
     public class SimulationProcessor : IUpdatable, IUpdateRequest
     {
         #region Instance
@@ -34,6 +39,15 @@
         #region Fields
 
         private static readonly SimulationProcessor instance = new SimulationProcessor();
+
+        #endregion
+
+        #region Constructors
+
+        static SimulationProcessor()
+        {
+            SimManager.OnReady += GetStageInfo;
+        }
 
         #endregion
 
@@ -72,7 +86,13 @@
 
         #endregion
 
-        #region Methods: public
+        #region Methods
+
+        private static void GetStageInfo()
+        {
+            Stages = SimManager.Stages;
+            LastStage = SimManager.LastStage;
+        }
 
         public static void RequestUpdate()
         {
@@ -89,9 +109,6 @@
                 return;
             }
 
-            Stages = SimManager.Stages;
-            LastStage = SimManager.LastStage;
-
             if (Stages != null && LastStage != null)
             {
                 ShowDetails = true;
@@ -104,9 +121,6 @@
                                               FlightGlobals.ActiveVessel.mainBody.GetAltitude(FlightGlobals.ActiveVessel.CoM), 2);
                 SimManager.Velocity = FlightGlobals.ActiveVessel.srfSpeed;
             }
-
-            // Cybutek: We should be allowing this to be set too but not sure where you want to put the control
-            //SimManager.vectoredThrust = vectoredThrust; 
         }
 
         #endregion

--- a/KerbalEngineer/VesselSimulator/SimManager.cs
+++ b/KerbalEngineer/VesselSimulator/SimManager.cs
@@ -17,84 +17,77 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.VesselSimulator
 {
+    #region Using Directives
+
+    using System;
+    using System.Diagnostics;
+    using System.Reflection;
+    using System.Threading;
+    using UnityEngine;
+
+    #endregion
+
     public class SimManager
     {
+        #region Constants
+
         public const double RESOURCE_MIN = 0.0001;
 
-        private static bool bRequested;
-        private static bool bRunning;
-        private static readonly Stopwatch timer = new Stopwatch();
-        private static long delayBetweenSims;
+        #endregion
+
+        #region Fields
 
         public static bool dumpTree = false;
         public static bool logOutput = false;
+        public static TimeSpan minSimTime = new TimeSpan(0, 0, 0, 0, 150);
         public static bool vectoredThrust = true;
-        public static long minSimTime = 150;
+        private static readonly object locker = new object();
+        private static readonly Stopwatch timer = new Stopwatch();
 
         // Support for RealFuels using reflection to check localCorrectThrust without dependency
-        private static bool hasCheckedForRealFuels;
-        private static bool hasInstalledRealFuels;
 
         private static FieldInfo RF_ModuleEngineConfigs_locaCorrectThrust;
         private static FieldInfo RF_ModuleHybridEngine_locaCorrectThrust;
         private static FieldInfo RF_ModuleHybridEngines_locaCorrectThrust;
+        private static bool bRequested;
+        private static bool bRunning;
+        private static TimeSpan delayBetweenSims;
+        private static bool hasCheckedForRealFuels;
+        private static bool hasInstalledRealFuels;
+
+        #endregion
+
+        #region Delegates
+
+        public delegate void ReadyEvent();
+
+        #endregion
+
+        #region Events
+
+        public static event ReadyEvent OnReady;
+
+        #endregion
+
+        #region Properties
+
+        public static double Atmosphere { get; set; }
+
+        public static double Gravity { get; set; }
+
+        public static Stage LastStage { get; private set; }
+
         public static Stage[] Stages { get; private set; }
-        public static Stage LastStage { get; private set; }
+
+        public static double Velocity { get; set; }
+
         public static String failMessage { get; private set; }
-        public static double Gravity { get; set; }
-        public static double Atmosphere { get; set; }
-        public static double Velocity { get; set; }
-
-        private static void GetRealFuelsTypes()
-        {
-            hasCheckedForRealFuels = true;
-
-            foreach (AssemblyLoader.LoadedAssembly assembly in AssemblyLoader.loadedAssemblies)
-            {
-                MonoBehaviour.print("Assembly:" + assembly.assembly);
-
-                if (assembly.assembly.ToString().Split(',')[0] == "RealFuels")
-                {
-                    MonoBehaviour.print("Found RealFuels mod");
-
-                    Type RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
-                    if (RF_ModuleEngineConfigs_Type != null)
-                    {
-                        RF_ModuleEngineConfigs_locaCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
-                    }
-
-                    Type RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
-                    if (RF_ModuleHybridEngine_Type != null)
-                    {
-                        RF_ModuleHybridEngine_locaCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
-                    }
-
-                    Type RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
-                    if (RF_ModuleHybridEngines_Type != null)
-                    {
-                        RF_ModuleHybridEngines_locaCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
-                    }
-
-                    hasInstalledRealFuels = true;
-                    break;
-                }
-            }
-        }
+
+        #endregion
+
+        #region Methods
 
         public static bool DoesEngineUseCorrectedThrust(Part theEngine)
         {
@@ -106,7 +99,7 @@
             // Look for any of the Real Fuels engine modules and call the relevant method to find out
             if (RF_ModuleEngineConfigs_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleEngineConfigs"))
             {
-                PartModule modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
+                var modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
                 if (modEngineConfigs != null)
                 {
                     // Check the localCorrectThrust
@@ -119,7 +112,7 @@
 
             if (RF_ModuleHybridEngine_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngine"))
             {
-                PartModule modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
+                var modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
                 if (modHybridEngine != null)
                 {
                     // Check the localCorrectThrust
@@ -132,7 +125,7 @@
 
             if (RF_ModuleHybridEngines_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngines"))
             {
-                PartModule modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
+                var modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
                 if (modHybridEngines != null)
                 {
                     // Check the localCorrectThrust
@@ -144,124 +137,6 @@
             }
 
             return false;
-        }
-
-        public static void RequestSimulation()
-        {
-            if (!hasCheckedForRealFuels)
-            {
-                GetRealFuelsTypes();
-            }
-
-            bRequested = true;
-            if (!timer.IsRunning)
-            {
-                timer.Start();
-            }
-        }
-
-        public static void TryStartSimulation()
-        {
-            if (bRequested && !bRunning && (HighLogic.LoadedSceneIsEditor || FlightGlobals.ActiveVessel != null) && timer.ElapsedMilliseconds > delayBetweenSims)
-            {
-                bRequested = false;
-                timer.Reset();
-                StartSimulation();
-            }
-        }
-
-        public static bool ResultsReady()
-        {
-            return !bRunning;
-        }
-
-        private static void ClearResults()
-        {
-            failMessage = "";
-            Stages = null;
-            LastStage = null;
-        }
-
-        private static void StartSimulation()
-        {
-            try
-            {
-                bRunning = true;
-                ClearResults();
-                timer.Start();
-
-                List<Part> parts = HighLogic.LoadedSceneIsEditor ? EditorLogic.SortedShipList : FlightGlobals.ActiveVessel.Parts;
-
-                // Create the Simulation object in this thread
-                Simulation sim = new Simulation();
-
-                // This call doesn't ever fail at the moment but we'll check and return a sensible error for display
-                if (sim.PrepareSimulation(parts, Gravity, Atmosphere, Velocity, dumpTree, vectoredThrust))
-                {
-                    ThreadPool.QueueUserWorkItem(RunSimulation, sim);
-                }
-                else
-                {
-                    failMessage = "PrepareSimulation failed";
-                    bRunning = false;
-                    logOutput = false;
-                }
-            }
-            catch (Exception e)
-            {
-                MonoBehaviour.print("Exception in StartSimulation: " + e);
-                failMessage = e.ToString();
-                bRunning = false;
-                logOutput = false;
-            }
-            dumpTree = false;
-        }
-
-        private static void RunSimulation(object simObject)
-        {
-            try
-            {
-                Stages = (simObject as Simulation).RunSimulation();
-                if (Stages != null)
-                {
-                    if (logOutput)
-                    {
-                        foreach (Stage stage in Stages)
-                        {
-                            stage.Dump();
-                        }
-                    }
-                    LastStage = Stages.Last();
-                }
-            }
-            catch (Exception e)
-            {
-                MonoBehaviour.print("Exception in RunSimulation: " + e);
-                Stages = null;
-                LastStage = null;
-                failMessage = e.ToString();
-            }
-
-            timer.Stop();
-#if TIMERS
-            MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
-#else
-            if (logOutput)
-            {
-                MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
-            }
-#endif
-            delayBetweenSims = minSimTime - timer.ElapsedMilliseconds;
-            if (delayBetweenSims < 0)
-            {
-                delayBetweenSims = 0;
-            }
-
-            timer.Reset();
-            timer.Start();
-
-            bRunning = false;
-            logOutput = false;
         }
 
         public static String GetVesselTypeString(VesselType vesselType)
@@ -293,5 +168,197 @@
             }
             return "Undefined";
         }
+
+        public static void RequestSimulation()
+        {
+            if (!hasCheckedForRealFuels)
+            {
+                GetRealFuelsTypes();
+            }
+
+            lock (locker)
+            {
+                bRequested = true;
+                if (!timer.IsRunning)
+                {
+                    timer.Start();
+                }
+            }
+        }
+
+        public static bool ResultsReady()
+        {
+            lock (locker)
+            {
+                return !bRunning;
+            }
+        }
+
+        public static void TryStartSimulation()
+        {
+            lock (locker)
+            {
+                if (!bRequested || bRunning || (timer.Elapsed < delayBetweenSims && timer.Elapsed >= TimeSpan.Zero) || (!HighLogic.LoadedSceneIsEditor && FlightGlobals.ActiveVessel == null))
+                {
+                    return;
+                }
+
+                bRequested = false;
+                timer.Reset();
+            }
+
+            StartSimulation();
+        }
+
+        private static void ClearResults()
+        {
+            failMessage = "";
+            Stages = null;
+            LastStage = null;
+        }
+
+        private static void GetRealFuelsTypes()
+        {
+            hasCheckedForRealFuels = true;
+
+            foreach (var assembly in AssemblyLoader.loadedAssemblies)
+            {
+                MonoBehaviour.print("Assembly:" + assembly.assembly);
+
+                if (assembly.assembly.ToString().Split(',')[0] == "RealFuels")
+                {
+                    MonoBehaviour.print("Found RealFuels mod");
+
+                    var RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
+                    if (RF_ModuleEngineConfigs_Type != null)
+                    {
+                        RF_ModuleEngineConfigs_locaCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
+                    if (RF_ModuleHybridEngine_Type != null)
+                    {
+                        RF_ModuleHybridEngine_locaCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
+                    if (RF_ModuleHybridEngines_Type != null)
+                    {
+                        RF_ModuleHybridEngines_locaCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
+                    }
+
+                    hasInstalledRealFuels = true;
+                    break;
+                }
+            }
+        }
+
+        private static void RunSimulation(object simObject)
+        {
+            try
+            {
+                Stages = (simObject as Simulation).RunSimulation();
+                if (Stages != null && Stages.Length > 0)
+                {
+                    if (logOutput)
+                    {
+                        foreach (var stage in Stages)
+                        {
+                            stage.Dump();
+                        }
+                    }
+                    LastStage = Stages[Stages.Length - 1];
+                }
+            }
+            catch (Exception e)
+            {
+                MonoBehaviour.print("Exception in RunSimulation: " + e);
+                Logger.Exception(e);
+                Stages = null;
+                LastStage = null;
+                failMessage = e.ToString();
+            }
+            lock (locker)
+            {
+                timer.Stop();
+#if TIMERS
+            MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
+#else
+                if (logOutput)
+                {
+                    MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
+                }
+#endif
+
+                delayBetweenSims = minSimTime - timer.Elapsed;
+                if (delayBetweenSims < TimeSpan.Zero)
+                {
+                    delayBetweenSims = TimeSpan.Zero;
+                }
+
+                timer.Reset();
+                timer.Start();
+
+                bRunning = false;
+                if (OnReady != null)
+                {
+                    OnReady();
+                }
+            }
+
+            logOutput = false;
+        }
+
+        private static void StartSimulation()
+        {
+            try
+            {
+                lock (locker)
+                {
+                    bRunning = true;
+                }
+
+                ClearResults();
+
+                lock (locker)
+                {
+                    timer.Start();
+                }
+
+                var parts = HighLogic.LoadedSceneIsEditor ? EditorLogic.SortedShipList : FlightGlobals.ActiveVessel.Parts;
+
+                // Create the Simulation object in this thread
+                var sim = new Simulation();
+
+                // This call doesn't ever fail at the moment but we'll check and return a sensible error for display
+                if (sim.PrepareSimulation(parts, Gravity, Atmosphere, Velocity, dumpTree, vectoredThrust))
+                {
+                    ThreadPool.QueueUserWorkItem(RunSimulation, sim);
+                }
+                else
+                {
+                    failMessage = "PrepareSimulation failed";
+                    lock (locker)
+                    {
+                        bRunning = false;
+                    }
+                    logOutput = false;
+                }
+            }
+            catch (Exception e)
+            {
+                MonoBehaviour.print("Exception in StartSimulation: " + e);
+                Logger.Exception(e);
+                failMessage = e.ToString();
+                lock (locker)
+                {
+                    bRunning = false;
+                }
+                logOutput = false;
+            }
+            dumpTree = false;
+        }
+
+        #endregion
     }
 }

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -512,6 +512,10 @@
                         MonoBehaviour.print("stageStartMass = " + this.stageStartMass);
                         MonoBehaviour.print("stepStartMass = " + this.stepStartMass);
                         MonoBehaviour.print("StepEndMass   = " + this.stepEndMass);
+                        Logger.Log("exceeded loop count");
+                        Logger.Log("stageStartMass = " + this.stageStartMass);
+                        Logger.Log("stepStartMass = " + this.stepStartMass);
+                        Logger.Log("StepEndMass   = " + this.stepEndMass);
                         break;
                     }
 

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ