Merged Sarbian's 1.0 fixes to vessel simulator
Merged Sarbian's 1.0 fixes to vessel simulator

--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,4 +1,21 @@
-1.0.14.0,
+1.0.15.2, 13-02-2015
+    Padishar's Fixes:
+        Fixed: Calculation of per-stage resource mass.
+
+1.0.15.1, 13-02-2015
+    Rebuild
+    
+1.0.15.0, 08-02-2015
+    Padishar's Fixes:
+        Added: Support KIDS ISP thrust correction.
+        Fixed: Log spam for stage priority mode.
+        Fixed: Locked tanks preventing simulation from staging.
+        Fixed: No flow and all vessel modes to respect flow states.
+
+1.0.14.1, 28-12-2014
+    Fixed: Missing texture on the ER-7500 model.
+    
+1.0.14.0, 28-12-2014
     Added: Career mode that limits the Flight Engineer by:
         - Requiring an Engineer Kerbal of any level, or placement of an Engineer Chip or ER-7500 part.
         - Tracking station level 3 enables Flight Engineer everywhere.
@@ -13,6 +30,7 @@
     Changed: Editor Overlay Tabs start position moved over as to not overlap the parts menu.
     Fixed: Bug where STAGE_PRIORITY_FLOW resources would not be corrently disabled/enabled.
     Fixed: Issue with the formatting large Mass and Cost values.
+    Fixed: Error when loading the Engineer7500 part model.
 
 1.0.13.1, 16-12-2014
     Fixed: Issue with manoeuvre node readouts and low tier tracking station.

--- a/KerbalEngineer/CelestialBodies.cs
+++ b/KerbalEngineer/CelestialBodies.cs
@@ -124,8 +124,9 @@
                     this.CelestialBody = body;
                     this.Name = body.bodyName;
                     this.Gravity = 9.81 * body.GeeASL;
-                    this.Atmosphere = body.atmosphere ? 101.325 * body.atmosphereMultiplier : 0;
-                    this.Parent = parent;
+                    //this.Atmosphere = body.atmosphere ? body.GetPressure(0) : 0;
+                    this.Atmosphere = body.atmosphere ? body.atmospherePressureSeaLevel : 0;   // Check that one because I did not. S
+                    this.Parent = parent; 
 
                     // Set orbiting bodies information.
                     this.Children = new List<BodyInfo>();

--- a/KerbalEngineer/Editor/BuildAdvanced.cs
+++ b/KerbalEngineer/Editor/BuildAdvanced.cs
@@ -41,7 +41,7 @@
         private GUIStyle areaSettingStyle;
         private GUIStyle areaStyle;
         private float atmosphericPercentage = 1.0f;
-        private float atmosphericVelocity;
+        private float atmosphericMach;
         private GUIStyle bodiesButtonActiveStyle;
         private GUIStyle bodiesButtonStyle;
         private DropDown bodiesList;
@@ -133,6 +133,7 @@
                 this.bodiesList.DrawCallback = this.DrawBodiesList;
                 this.Load();
 
+                SimManager.UpdateModSettings();
                 SimManager.OnReady -= this.GetStageInfo;
                 SimManager.OnReady += this.GetStageInfo;
             }
@@ -262,7 +263,7 @@
                     SimManager.Atmosphere = 0;
                 }
 
-                SimManager.Velocity = this.atmosphericVelocity;
+                SimManager.Mach = this.atmosphericMach;
 
                 SimManager.RequestSimulation();
                 SimManager.TryStartSimulation();
@@ -304,9 +305,9 @@
             GUILayout.Space(5.0f);
 
             GUILayout.BeginVertical();
-            GUILayout.Label("Velocity: " + this.atmosphericVelocity.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Mach: " + this.atmosphericMach.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
             GUI.skin = HighLogic.Skin;
-            this.atmosphericVelocity = GUILayout.HorizontalSlider(this.atmosphericVelocity, 0, 2500f);
+            this.atmosphericMach = GUILayout.HorizontalSlider(this.atmosphericMach, 0, 25f); // the game limits mach to 50 but I did not see curve with more than 25
             GUI.skin = null;
             GUILayout.EndVertical();
             GUILayout.EndHorizontal();

--- a/KerbalEngineer/Editor/BuildOverlayVessel.cs
+++ b/KerbalEngineer/Editor/BuildOverlayVessel.cs
@@ -58,7 +58,7 @@
         #endregion
 
         #region Properties
-       
+
         public static bool Visible
         {
             get { return visible; }

--- a/KerbalEngineer/EngineerGlobals.cs
+++ b/KerbalEngineer/EngineerGlobals.cs
@@ -33,7 +33,7 @@
         /// <summary>
         ///     Current version of the Kerbal Engineer assembly.
         /// </summary>
-        public const string AssemblyVersion = "1.0.13.1";
+        public const string AssemblyVersion = "1.0.16.0";
 
         #endregion
 

--- a/KerbalEngineer/Extensions/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -83,11 +83,27 @@
         }
 
         /// <summary>
+        ///     Gets the cost of the part modules
+        ///     Same as stock but without mem allocation
+        /// </summary>
+        public static double GetModuleCostsNoAlloc(this Part part, float defaultCost)
+        {
+            float cost = 0f;
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is IPartCostModifier)
+                    cost += (pm as IPartCostModifier).GetModuleCost(defaultCost);
+            }
+            return cost;
+        }
+
+        /// <summary>
         ///     Gets the cost of the part including resources.
         /// </summary>
         public static double GetCostWet(this Part part)
         {
-            return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCosts(0.0f);
+            return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCostsNoAlloc(0.0f); // part.GetModuleCosts allocate 44B per call. 
         }
 
         /// <summary>
@@ -124,7 +140,13 @@
         /// </summary>
         public static T GetModule<T>(this Part part) where T : PartModule
         {
-            return part.Modules.OfType<T>().FirstOrDefault();
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is T)
+                    return (T)pm;
+            }
+            return null;
         }
 
         /// <summary>
@@ -264,7 +286,13 @@
         /// </summary>
         public static double GetResourceCostInverted(this Part part)
         {
-            return part.Resources.list.Sum(r => (r.maxAmount - r.amount) * r.info.unitCost);
+            double sum = 0;
+            for (int i = 0; i < part.Resources.list.Count; i++)
+            {
+                PartResource r = part.Resources.list[i];
+                sum += (r.maxAmount - r.amount) * r.info.unitCost;
+            }
+            return sum;
         }
 
         /// <summary>
@@ -309,7 +337,12 @@
         /// </summary>
         public static bool HasModule<T>(this Part part) where T : PartModule
         {
-            return part.Modules.OfType<T>().Any();
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                if (part.Modules[i] is T)
+                    return true;
+            }
+            return false;
         }
 
         /// <summary>
@@ -317,7 +350,13 @@
         /// </summary>
         public static bool HasModule<T>(this Part part, Func<T, bool> predicate) where T : PartModule
         {
-            return part.Modules.OfType<T>().Any(predicate);
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is T && predicate(pm as T))
+                    return true;
+            }
+            return false;
         }
 
         /// <summary>
@@ -421,8 +460,9 @@
         /// </summary>
         public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)
         {
-            foreach (var vesselPart in partsList)
-            {
+            for (int i = 0; i < partsList.Count; i++)
+            {
+                var vesselPart = partsList[i];
                 if (!vesselPart.HasModule(module.ClassID))
                 {
                     continue;
@@ -464,7 +504,7 @@
         /// </summary>
         public static bool IsSolidRocket(this Part part)
         {
-            return part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked;
+            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked) || (part.HasModule<ModuleEnginesFX>() && part.GetModuleEnginesFx().throttleLocked);
         }
 
         #endregion

--- a/KerbalEngineer/Flight/FlightEngineerCore.cs
+++ b/KerbalEngineer/Flight/FlightEngineerCore.cs
@@ -33,6 +33,7 @@
     using Sections;
     using Settings;
     using UnityEngine;
+    using VesselSimulator;
 
     #endregion
 
@@ -268,6 +269,9 @@
                 this.SectionWindows = new List<SectionWindow>();
                 this.SectionEditors = new List<SectionEditor>();
                 this.UpdatableModules = new List<IUpdatable>();
+
+                SimManager.UpdateModSettings();
+
                 Logger.Log("FlightEngineerCore->Awake");
             }
             catch (Exception ex)

--- a/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
@@ -126,7 +126,7 @@
                     var drag = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass() * p.maximum_drag);
                     var grav = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude;
                     var atmo = FlightGlobals.ActiveVessel.atmDensity;
-                    var coef = FlightGlobals.DragMultiplier;
+                    var coef = FlightGlobals.ActiveVessel.parts.Sum(p => p.DragCubes.DragCoeff);
 
                     TerminalVelocity = Math.Sqrt((2 * mass * grav) / (atmo * drag * coef));
                 }

--- a/KerbalEngineer/Flight/Readouts/Vessel/AttitudeProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/AttitudeProcessor.cs
@@ -123,7 +123,8 @@
             // This code was derived from MechJeb2's implementation for getting the vessel's surface relative rotation.
             this.centreOfMass = FlightGlobals.ActiveVessel.findWorldCenterOfMass();
             this.up = (this.centreOfMass - FlightGlobals.ActiveVessel.mainBody.position).normalized;
-            this.north = Vector3.Exclude(this.up, (FlightGlobals.ActiveVessel.mainBody.position + FlightGlobals.ActiveVessel.mainBody.transform.up * (float)FlightGlobals.ActiveVessel.mainBody.Radius) - this.centreOfMass).normalized;
+            this.north = Vector3.ProjectOnPlane((FlightGlobals.ActiveVessel.mainBody.position + FlightGlobals.ActiveVessel.mainBody.transform.up * (float)FlightGlobals.ActiveVessel.mainBody.Radius) - this.centreOfMass, this.up).normalized;
+
             return Quaternion.Inverse(Quaternion.Euler(90.0f, 0.0f, 0.0f) * Quaternion.Inverse(FlightGlobals.ActiveVessel.transform.rotation) * Quaternion.LookRotation(this.north, this.up));
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
@@ -119,7 +119,7 @@
                 SimManager.Gravity = FlightGlobals.ActiveVessel.mainBody.gravParameter /
                                      Math.Pow(FlightGlobals.ActiveVessel.mainBody.Radius +
                                               FlightGlobals.ActiveVessel.mainBody.GetAltitude(FlightGlobals.ActiveVessel.CoM), 2);
-                SimManager.Velocity = FlightGlobals.ActiveVessel.srfSpeed;
+                SimManager.Mach = FlightGlobals.ActiveVessel.mach;
             }
         }
 

--- a/KerbalEngineer/Helpers/Averager.cs
+++ b/KerbalEngineer/Helpers/Averager.cs
@@ -45,6 +45,12 @@
         private Vector3d sum = Vector3d.zero;
         private double totalweight = 0;
 
+        public void Reset()
+        {
+            sum = Vector3d.zero;
+            totalweight = 0;
+        }
+
         public void Add(Vector3d v, double weight) {
             sum += v * weight;
             totalweight += weight;

--- a/KerbalEngineer/Helpers/ForceAccumulator.cs
+++ b/KerbalEngineer/Helpers/ForceAccumulator.cs
@@ -19,19 +19,39 @@
 
 using System;
 using System.Collections.Generic;
+using KerbalEngineer.VesselSimulator;
 
 namespace KerbalEngineer
 {
     // a (force, application point) tuple
     public class AppliedForce
     {
+        private static readonly Pool<AppliedForce> pool = new Pool<AppliedForce>(Create, Reset);
+
         public Vector3d vector;
         public Vector3d applicationPoint;
 
-        public AppliedForce(Vector3d vector, Vector3d applicationPoint) {
-            this.vector = vector;
-            this.applicationPoint = applicationPoint;
+        static private AppliedForce Create()
+        {
+            return new AppliedForce();
         }
+
+        static private void Reset(AppliedForce appliedForce) { }
+
+        static public AppliedForce New(Vector3d vector, Vector3d applicationPoint)
+        {
+            AppliedForce force = pool.Borrow();
+            force.vector = vector;
+            force.applicationPoint = applicationPoint;
+            return force;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+
     }
 
 	// This class was mostly adapted from FARCenterQuery, part of FAR, by ferram4, GPLv3
@@ -47,7 +67,7 @@
 	// some amount of residual torque. The line with the least amount of residual torque is chosen.
 	public class ForceAccumulator
 	{
-		// Total force.
+	    // Total force.
 		private Vector3d totalForce = Vector3d.zero;
 		// Torque needed to compensate if force were applied at origin.
 		private Vector3d totalZeroOriginTorque = Vector3d.zero;
@@ -99,5 +119,12 @@
         {
             return GetMinTorqueForceApplicationPoint(avgApplicationPoint.Get());
         }
+
+        public void Reset()
+        {
+            totalForce = Vector3d.zero;
+            totalZeroOriginTorque = Vector3d.zero;
+            avgApplicationPoint.Reset();
+        }
 	}
 }

--- /dev/null
+++ b/KerbalEngineer/Helpers/Pool.cs
@@ -1,1 +1,54 @@
+using System.Collections.Generic;
 
+namespace KerbalEngineer
+{
+    /// <summary>
+    ///     Pool of object
+    /// </summary>
+    public class Pool<T> {
+        
+        private readonly Stack<T> values = new Stack<T>();
+
+        private readonly CreateDelegate<T> create;
+        private readonly ResetDelegate<T> reset;
+
+        public delegate R CreateDelegate<out R>();
+        public delegate void ResetDelegate<in T1>(T1 a);
+        
+        /// <summary>
+        ///     Creates an empty pool with the specified object creation and reset delegates.
+        /// </summary>
+        public Pool(CreateDelegate<T> create, ResetDelegate<T> reset) {
+            this.create = create;
+            this.reset = reset;
+        }
+
+        /// <summary>
+        ///     Borrows an object from the pool.
+        /// </summary>
+        public T Borrow() {
+            lock (values) {
+                return values.Count > 0 ? values.Pop() : create();
+            }
+        }
+        
+        /// <summary>
+        ///     Release an object, reset it and returns it to the pool.
+        /// </summary>
+        public void Release(T value) {
+            reset(value);
+            lock (values) {
+                values.Push(value);
+            }
+        }
+        
+        /// <summary>
+        ///     Current size of the pool.
+        /// </summary>
+        public int Count()
+        {
+            return values.Count;
+        }
+
+    }
+}

--- a/KerbalEngineer/Helpers/Units.cs
+++ b/KerbalEngineer/Helpers/Units.cs
@@ -65,9 +65,9 @@
 
         public static string Cost(double value1, double value2, int decimals = 1)
         {
-            if (value1 >= 1e6 || value2 >= 1e6)
+            if (value1 >= 1000000.0 || value2 >= 1000000.0)
             {
-                return (value1 / 1000.0).ToString("N" + decimals) + " / " + (value2 / 1000.0f).ToString("N" + decimals) + "K";
+                return (value1 / 1000.0).ToString("N" + decimals) + " / " + (value2 / 1000.0).ToString("N" + decimals) + "K";
             }
             return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals);
         }
@@ -135,9 +135,8 @@
                 return value.ToString("N" + decimals + 2) + "t";
             }
 
-                value *= 1000.0;
-                return value.ToString("N" + decimals) + "kg";
-
+            value *= 1000.0;
+            return value.ToString("N" + decimals) + "kg";
         }
 
         public static string ToMass(double value1, double value2, int decimals = 0)
@@ -146,11 +145,10 @@
             {
                 return value1.ToString("N" + decimals + 2) + " / " + value2.ToString("N" + decimals + 2) + "t";
             }
-   
-                value1 *= 1000.0;
-                value2 *= 1000.0;
-                return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "kg";
-  
+
+            value1 *= 1000.0;
+            value2 *= 1000.0;
+            return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "kg";
         }
 
         public static string ToPercent(double value, int decimals = 2)

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -124,6 +124,11 @@
     <Compile Include="Helpers\TimeFormatter.cs" />
     <Compile Include="KeyBinder.cs" />
     <Compile Include="Control\ControlCentre.cs" />
+    <Compile Include="Smooth\Delegates\Delegates.cs" />
+    <Compile Include="Smooth\Dispose\Disposable.cs" />
+    <Compile Include="Smooth\Dispose\DisposalQueue.cs" />
+    <Compile Include="Smooth\Dispose\SmoothDisposer.cs" />
+    <Compile Include="Smooth\Pools\Pool.cs" />
     <Compile Include="UIControls\DropDown.cs" />
     <Compile Include="Logger.cs" />
     <Compile Include="EngineerGlobals.cs" />
@@ -207,8 +212,7 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
     </Reference>
     <Reference Include="System">
       <HintPath>..\Game\KSP_Data\Managed\System.dll</HintPath>
@@ -219,10 +223,10 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll</HintPath>
     </Reference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="PostBuildMacros">
     <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">

--- /dev/null
+++ b/KerbalEngineer/Smooth/Delegates/Delegates.cs
@@ -1,1 +1,25 @@
+using System;
 
+namespace Smooth.Delegates {
+	public delegate void DelegateAction();
+	public delegate void DelegateAction<in T1>(T1 _1);
+	public delegate void DelegateAction<in T1, in T2>(T1 _1, T2 _2);
+	public delegate void DelegateAction<in T1, in T2, in T3>(T1 _1, T2 _2, T3 _3);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4>(T1 _1, T2 _2, T3 _3, T4 _4);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4, in T5>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4, in T5, in T6>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8);
+	public delegate void DelegateAction<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8, T9 _9);
+
+	public delegate R DelegateFunc<out R>();
+	public delegate R DelegateFunc<in T1, out R>(T1 _1);
+	public delegate R DelegateFunc<in T1, in T2, out R>(T1 _1, T2 _2);
+	public delegate R DelegateFunc<in T1, in T2, in T3, out R>(T1 _1, T2 _2, T3 _3);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, out R>(T1 _1, T2 _2, T3 _3, T4 _4);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, in T5, out R>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, in T5, in T6, out R>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out R>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out R>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8);
+	public delegate R DelegateFunc<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out R>(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8, T9 _9);
+}

--- /dev/null
+++ b/KerbalEngineer/Smooth/Dispose/Disposable.cs
@@ -1,1 +1,106 @@
+using System;
+using Smooth.Delegates;
+using Smooth.Pools;
 
+namespace Smooth.Dispose {
+
+#if UNITY_IOS || UNITY_PS3 || UNITY_XBOX360 || UNITY_WII
+
+	/// <summary>
+	/// Wrapper around a value that uses the IDisposable interface to dispose of the value.
+	/// 
+	/// On iOS, this is a struct to avoid compute_class_bitmap errors.
+	/// 
+	/// On other platforms, it is a pooled object to avoid boxing when disposed by a using block with the Unity compiler.
+	/// </summary>
+	public struct Disposable<T> : IDisposable {
+		/// <summary>
+		/// Borrows a wrapper for the specified value and disposal delegate.
+		/// </summary>
+		public static Disposable<T> Borrow(T value, DelegateAction<T> dispose) {
+			return new Disposable<T>(value, dispose);
+		}
+		
+		private readonly DelegateAction<T> dispose;
+
+		/// <summary>
+		/// The wrapped value.
+		/// </summary>
+		public readonly T value;
+
+		public Disposable(T value, DelegateAction<T> dispose) {
+			this.value = value;
+			this.dispose = dispose;
+		}
+		
+		/// <summary>
+		/// Relinquishes ownership of the wrapper and disposes the wrapped value.
+		/// </summary>
+		public void Dispose() {
+			dispose(value);
+		}
+		
+		/// <summary>
+		/// Relinquishes ownership of the wrapper and adds it to the disposal queue.
+		/// </summary>
+		public void DisposeInBackground() {
+			DisposalQueue.Enqueue(this);
+		}
+	}
+
+#else
+
+	/// <summary>
+	/// Wrapper around a value that uses the IDisposable interface to dispose of the value.
+	/// 
+	/// On IOS, this is a value type to avoid compute_class_bitmap errors.
+	/// 
+	/// On other platforms, it is a pooled object to avoid boxing when disposed by a using block with the Unity compiler.
+	/// </summary>
+	public class Disposable<T> : IDisposable {
+		private static readonly Pool<Disposable<T>> pool = new Pool<Disposable<T>>(
+			() => new Disposable<T>(),
+			wrapper => {
+				wrapper.dispose(wrapper.value);
+				wrapper.dispose = t => {};
+				wrapper.value = default(T);
+			}
+		);
+
+		/// <summary>
+		/// Borrows a wrapper for the specified value and disposal delegate.
+		/// </summary>
+		public static Disposable<T> Borrow(T value, DelegateAction<T> dispose) {
+			var wrapper = pool.Borrow();
+			wrapper.value = value;
+			wrapper.dispose = dispose;
+			return wrapper;
+		}
+
+		private DelegateAction<T> dispose;
+
+		/// <summary>
+		/// The wrapped value.
+		/// </summary>
+		public T value { get; private set; }
+		
+		private Disposable() {}
+
+		/// <summary>
+		/// Relinquishes ownership of the wrapper, disposes the wrapped value, and returns the wrapper to the pool.
+		/// </summary>
+		public void Dispose() {
+			pool.Release(this);
+		}
+
+		/// <summary>
+		/// Relinquishes ownership of the wrapper and adds it to the disposal queue.
+		/// </summary>
+		public void DisposeInBackground() {
+			DisposalQueue.Enqueue(this);
+		}
+	}
+
+#endif
+
+}

--- /dev/null
+++ b/KerbalEngineer/Smooth/Dispose/DisposalQueue.cs
@@ -1,1 +1,67 @@
+using UnityEngine;
+using System;
+using System.Collections.Generic;
+using System.Threading;
 
+namespace Smooth.Dispose {
+
+	/// <summary>
+	/// Queues pooled resources for cleanup by a background thread.
+	/// 
+	/// By default, the disposal thread is woken up at the end of LateUpdate, when there is likely to be free CPU time available while GPU operations are in progress.
+	/// 
+	/// Various pools may be locked and unlocked while resources are released, potentially causing contention if pooled resources are borrowed during the disposal process.
+	/// 
+	/// Advanced users who are using pools from the main thread during the rendering phase may want to customize the point in the Unity event loop when the queue lock is pulsed, potentially pulsing from a Camera event.
+	/// </summary>
+	public static class DisposalQueue {
+		private static readonly object queueLock = new object();
+		private static Queue<IDisposable> enqueue = new Queue<IDisposable>();
+		private static Queue<IDisposable> dispose = new Queue<IDisposable>();
+
+		/// <summary>
+		/// Adds the specified item to the disposal queue.
+		/// </summary>
+		public static void Enqueue(IDisposable item) {
+			lock (queueLock) {
+				enqueue.Enqueue(item);
+			}
+		}
+
+		/// <summary>
+		/// Pulses the queue lock, potentially waking up the disposal thread.
+		/// </summary>
+		public static void Pulse() {
+			lock (queueLock) {
+				Monitor.Pulse(queueLock);
+			}
+		}
+
+		private static void Dispose() {
+			while (true) {
+				lock (queueLock) {
+					while (enqueue.Count == 0) {
+						Monitor.Wait(queueLock);
+					}
+					var t = enqueue;
+					enqueue = dispose;
+					dispose = t;
+				}
+				while (dispose.Count > 0) {
+					try {
+						dispose.Dequeue().Dispose();
+					} catch (ThreadAbortException) {
+					} catch (Exception e) {
+						Debug.LogError(e);
+					}
+				}
+			}
+		}
+
+		static DisposalQueue() {
+			new Thread(new ThreadStart(Dispose)).Start();
+			new GameObject(typeof(SmoothDisposer).Name).AddComponent<SmoothDisposer>();
+		}
+	}
+}
+

--- /dev/null
+++ b/KerbalEngineer/Smooth/Dispose/SmoothDisposer.cs
@@ -1,1 +1,21 @@
+using UnityEngine;
+using System;
+using Smooth.Dispose;
 
+public class SmoothDisposer : MonoBehaviour {
+	private static SmoothDisposer instance;
+
+	private void Awake() {
+		if (instance) {
+			Debug.LogWarning("Only one " + GetType().Name + " should exist at a time, instantiated by the " + typeof(DisposalQueue).Name + " class.");
+			Destroy(this);
+		} else {
+			instance = this;
+			DontDestroyOnLoad(this);
+		}
+	}
+	
+	private void LateUpdate() {
+		DisposalQueue.Pulse();
+	}
+}

--- /dev/null
+++ b/KerbalEngineer/Smooth/Pools/Pool.cs
@@ -1,1 +1,60 @@
+using System;
+using System.Collections.Generic;
+using Smooth.Delegates;
+using Smooth.Dispose;
 
+namespace Smooth.Pools {
+	/// <summary>
+	/// Pool that lends values of type T.
+	/// </summary>
+	public class Pool<T> {
+		private readonly Stack<T> values = new Stack<T>();
+
+		private readonly DelegateFunc<T> create;
+		private readonly DelegateAction<T> reset;
+		private readonly DelegateAction<T> release;
+
+		private Pool() {}
+		
+		/// <summary>
+		/// Creates a new pool with the specified value creation and reset delegates.
+		/// </summary>
+		public Pool(DelegateFunc<T> create, DelegateAction<T> reset) {
+			this.create = create;
+			this.reset = reset;
+			this.release = Release;
+		}
+
+		/// <summary>
+		/// Borrows a value from the pool.
+		/// </summary>
+		public T Borrow() {
+			lock (values) {
+				return values.Count > 0 ? values.Pop() : create();
+			}
+		}
+		
+		/// <summary>
+		/// Relinquishes ownership of the specified value and returns it to the pool.
+		/// </summary>
+		public void Release(T value) {
+			reset(value);
+			lock (values) {
+				values.Push(value);
+			}
+		}
+
+		/// <summary>
+		/// Borrows a wrapped value from the pool.
+		/// </summary>
+		public Disposable<T> BorrowDisposable() {
+			return Disposable<T>.Borrow(Borrow(), release);
+		}
+
+        public int Count()
+	    {
+	        return values.Count;
+	    }
+
+	}
+}

--- a/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
+++ b/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
@@ -28,15 +28,35 @@
 {
     internal class AttachNodeSim
     {
+
+        private static readonly Pool<AttachNodeSim> pool = new Pool<AttachNodeSim>(Create, Reset);
+
         public PartSim attachedPartSim;
         public String id;
         public AttachNode.NodeType nodeType;
 
-        public AttachNodeSim(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
+        private static AttachNodeSim Create()
         {
-            this.attachedPartSim = partSim;
-            this.nodeType = newNodeType;
-            this.id = newId;
+            return new AttachNodeSim();
+        }
+
+        public static AttachNodeSim New(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
+        {
+            AttachNodeSim nodeSim = pool.Borrow();
+
+            nodeSim.attachedPartSim = partSim;
+            nodeSim.nodeType = newNodeType;
+            nodeSim.id = newId;
+
+            return nodeSim;
+        }
+
+        static private void Reset(AttachNodeSim attachNodeSim) { }
+
+
+        public void Release()
+        {
+            pool.Release(this);
         }
 
         public void DumpToBuffer(StringBuilder buffer)

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -23,7 +23,6 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
-
 using UnityEngine;
 
 #endregion
@@ -32,36 +31,67 @@
 {
     public class EngineSim
     {
+        private static readonly Pool<EngineSim> pool = new Pool<EngineSim>(Create, Reset);
+
         private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
 
         public double actualThrust = 0;
         public bool isActive = false;
         public double isp = 0;
         public PartSim partSim;
-        public List<AppliedForce> appliedForces;
+        public List<AppliedForce> appliedForces = new List<AppliedForce>();
 
         public double thrust = 0;
 
         // Add thrust vector to account for directional losses
         public Vector3 thrustVec;
 
-        public EngineSim(PartSim theEngine,
+        private static EngineSim Create()
+        {
+            return new EngineSim();
+        }
+
+        private static void Reset(EngineSim engineSim)
+        {
+            engineSim.resourceConsumptions.Reset();
+            engineSim.actualThrust = 0;
+            engineSim.isActive = false;
+            engineSim.isp = 0;
+            for (int i = 0; i < engineSim.appliedForces.Count; i++)
+            {
+                engineSim.appliedForces[i].Release();
+            }
+            engineSim.appliedForces.Clear();
+            engineSim.thrust = 0;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static EngineSim New(PartSim theEngine,
                          double atmosphere,
-                         double velocity,
-                         float maxThrust,
-                         float minThrust,
+                         double machNumber,
+                         float maxFuelFlow,
+                         float minFuelFlow,
                          float thrustPercentage,
-                         float requestedThrust,
                          Vector3 vecThrust,
-                         float realIsp,
                          FloatCurve atmosphereCurve,
-                         FloatCurve velocityCurve,
+                         bool atmChangeFlow,
+                         FloatCurve atmCurve,
+                         FloatCurve velCurve,
+                         float currentThrottle,
+                         float IspG,
                          bool throttleLocked,
                          List<Propellant> propellants,
                          bool active,
                          bool correctThrust,
                          List<Transform> thrustTransforms)
         {
+            EngineSim engineSim = pool.Borrow();
+
+
             StringBuilder buffer = null;
             //MonoBehaviour.print("Create EngineSim for " + theEngine.name);
             //MonoBehaviour.print("maxThrust = " + maxThrust);
@@ -70,80 +100,91 @@
             //MonoBehaviour.print("requestedThrust = " + requestedThrust);
             //MonoBehaviour.print("velocity = " + velocity);
 
-            this.partSim = theEngine;
-
-            this.isActive = active;
-            this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
+            engineSim.partSim = theEngine;
+
+            engineSim.isActive = active;
+            //this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
             //MonoBehaviour.print("thrust = " + thrust);
 
-            this.thrustVec = vecThrust;
+            engineSim.thrustVec = vecThrust;
 
             double flowRate = 0d;
-            if (this.partSim.hasVessel)
+            if (engineSim.partSim.hasVessel)
             {
                 //MonoBehaviour.print("hasVessel is true");
-                this.actualThrust = isActive ? requestedThrust : 0.0;
-                if (velocityCurve != null)
-                {
-                    this.actualThrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);
-                }
-
-                this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm);
-                if (this.isp == 0d)
-                {
-                    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
-                }
-
-                if (correctThrust && realIsp == 0)
-                {
-                    float ispsl = atmosphereCurve.Evaluate(0);
-                    if (ispsl != 0)
-                    {
-                        this.thrust = this.thrust * this.isp / ispsl;
+
+                //this.actualThrust = this.isActive ? resultingThrust : 0.0;
+
+                engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
+
+                //if (this.isp == 0d)
+                //{
+                //    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
+                //}
+
+
+                // correctThrust is less usefull now that the stock engines do it. Keep or remove.
+
+                //if (correctThrust && realIsp == 0)
+                //{
+                //    float ispsl = atmosphereCurve.Evaluate(0);
+                //    if (ispsl != 0)
+                //    {
+                //        this.thrust = this.thrust * this.isp / ispsl;
+                //    }
+                //    else
+                //    {
+                //        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
+                //    }
+                //    //MonoBehaviour.print("corrected thrust = " + thrust);
+                //}
+
+                //if (velocityCurve != null)
+                //{
+                //    this.thrust *= velocityCurve.Evaluate((float)velocity);
+                //    //MonoBehaviour.print("thrust at velocity = " + thrust);
+                //}
+                
+                float multiplier = 1;
+                if (atmChangeFlow)
+                {
+                    multiplier = (float)(theEngine.part.atmDensity / 1.225);
+                    if (atmCurve != null)
+                    {
+                        multiplier = atmCurve.Evaluate(multiplier);
+                    }
+                    //MonoBehaviour.print("corrected thrust = " + thrust);
+                }
+                if (velCurve != null)
+                {
+                    multiplier *= velCurve.Evaluate((float)machNumber);
+                }
+
+                if (throttleLocked)
+                {
+                    //MonoBehaviour.print("throttleLocked is true");
+                    //flowRate = this.thrust / (this.isp * 9.82);
+                    flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
+                }
+                else
+                {
+                    if (theEngine.isLanded)
+                    {
+                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
+                        flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, FlightInputHandler.state.mainThrottle * (thrustPercentage / 100f)) * multiplier;
                     }
                     else
                     {
-                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
-                    }
-                    //MonoBehaviour.print("corrected thrust = " + thrust);
-                }
-
-                if (velocityCurve != null)
-                {
-                    this.thrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("thrust at velocity = " + thrust);
-                }
-
-                if (throttleLocked)
-                {
-                    //MonoBehaviour.print("throttleLocked is true");
-                    flowRate = this.thrust / (this.isp * 9.82);
-                }
-                else
-                {
-                    if (this.partSim.isLanded)
-                    {
-                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
-                        flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.82);
-                    }
-                    else
-                    {
-                        if (requestedThrust > 0)
-                        {
-                            if (velocityCurve != null)
-                            {
-                                requestedThrust *= velocityCurve.Evaluate((float)velocity);
-                                //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);
-                            }
-
+                        if (currentThrottle > 0)
+                        {
                             //MonoBehaviour.print("requestedThrust > 0");
-                            flowRate = requestedThrust / (this.isp * 9.82);
+                            //flowRate = requestedThrust / (this.isp * 9.82) * multiplier;
+                            flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, currentThrottle * (thrustPercentage / 100f)) * multiplier;
                         }
                         else
                         {
                             //MonoBehaviour.print("requestedThrust <= 0");
-                            flowRate = this.thrust / (this.isp * 9.82);
+                            flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
                         }
                     }
                 }
@@ -151,32 +192,42 @@
             else
             {
                 //MonoBehaviour.print("hasVessel is false");
-                this.isp = atmosphereCurve.Evaluate((float)atmosphere);
-                if (this.isp == 0d)
+                engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
+                if (engineSim.isp == 0d)
                 {
                     MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");
                 }
-                if (correctThrust)
-                {
-                    float ispsl = atmosphereCurve.Evaluate(0);
-                    if (ispsl != 0)
-                    {
-                        this.thrust = this.thrust * this.isp / ispsl;
-                    }
-                    else
-                    {
-                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
-                    }
-                    //MonoBehaviour.print("corrected thrust = " + thrust);
-                }
-
-                if (velocityCurve != null)
-                {
-                    this.thrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("thrust at velocity = " + thrust);
-                }
-
-                flowRate = this.thrust / (this.isp * 9.82);
+                //if (correctThrust)
+                //{
+                //    float ispsl = atmosphereCurve.Evaluate(0);
+                //    if (ispsl != 0)
+                //    {
+                //        this.thrust = this.thrust * this.isp / ispsl;
+                //    }
+                //    else
+                //    {
+                //        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
+                //    }
+                //    //MonoBehaviour.print("corrected thrust = " + thrust);
+                //}
+
+                float multiplier = 1;
+                if (atmChangeFlow)
+                {
+                    //multiplier = (float)(this.partSim.part.atmDensity / 1.225);
+                    multiplier = (float)atmosphere;    // technically wrong but the same for my Editor need
+                    if (atmCurve != null)
+                    {
+                        multiplier = atmCurve.Evaluate(multiplier);
+                    }
+                }
+
+                if (velCurve != null)
+                {
+                    multiplier *= velCurve.Evaluate((float)machNumber);
+                }
+
+                flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
             }
 
             if (SimManager.logOutput)
@@ -185,9 +236,14 @@
                 buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
             }
 
+            engineSim.thrust = flowRate * (engineSim.isp * IspG);
+            // I did not look into the diff between those 2 so I made them equal...
+            engineSim.actualThrust = engineSim.thrust;
+
             float flowMass = 0f;
-            foreach (Propellant propellant in propellants)
-            {
+            for (int i = 0; i < propellants.Count; i++)
+            {
+                Propellant propellant = propellants[i];
                 flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
             }
 
@@ -196,8 +252,9 @@
                 buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
             }
 
-            foreach (Propellant propellant in propellants)
-            {
+            for (int i = 0; i < propellants.Count; i++)
+            {
+                Propellant propellant = propellants[i];
                 if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                 {
                     continue;
@@ -206,9 +263,14 @@
                 double consumptionRate = propellant.ratio * flowRate / flowMass;
                 if (SimManager.logOutput)
                 {
-                    buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);
-                }
-                this.resourceConsumptions.Add(propellant.id, consumptionRate);
+                    buffer.AppendFormat(
+                        "Add consumption({0}, {1}:{2:d}) = {3:g6}\n",
+                        ResourceContainer.GetResourceName(propellant.id),
+                        theEngine.name,
+                        theEngine.partId,
+                        consumptionRate);
+                }
+                engineSim.resourceConsumptions.Add(propellant.id, consumptionRate);
             }
 
             if (SimManager.logOutput)
@@ -216,13 +278,17 @@
                 MonoBehaviour.print(buffer);
             }
 
-            appliedForces = new List<AppliedForce>();
-            double thrustPerThrustTransform = thrust / thrustTransforms.Count;
-            foreach (Transform thrustTransform in thrustTransforms) {
+            double thrustPerThrustTransform = engineSim.thrust / thrustTransforms.Count;
+            for (int i = 0; i < thrustTransforms.Count; i++)
+            {
+                Transform thrustTransform = thrustTransforms[i];
                 Vector3d direction = thrustTransform.forward.normalized;
                 Vector3d position = thrustTransform.position;
-                appliedForces.Add(new AppliedForce(direction * thrustPerThrustTransform, position));
-            }
+
+                AppliedForce appliedForce = AppliedForce.New(direction * thrustPerThrustTransform, position);
+                engineSim.appliedForces.Add(appliedForce);
+            }
+            return engineSim;
         }
 
         public ResourceContainer ResourceConsumptions
@@ -230,50 +296,70 @@
             get { return this.resourceConsumptions; }
         }
 
+        // A dictionary to hold a set of parts for each resource
+        Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+        HashSet<PartSim> visited = new HashSet<PartSim>();
+
         public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)
         {
             LogMsg log = null;
-
-            // A dictionary to hold a set of parts for each resource
-            Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
-
-            foreach (int type in this.resourceConsumptions.Types)
-            {
-                HashSet<PartSim> sourcePartSet = null;
+            
+            foreach (HashSet<PartSim> sourcePartSet in sourcePartSets.Values)
+            {
+                sourcePartSet.Clear();
+            }
+
+            for (int index = 0; index < this.resourceConsumptions.Types.Count; index++)
+            {
+                int type = this.resourceConsumptions.Types[index];
+
+                HashSet<PartSim> sourcePartSet;
+                if (!sourcePartSets.TryGetValue(type, out sourcePartSet))
+                {
+                    sourcePartSet = new HashSet<PartSim>();
+                    sourcePartSets.Add(type, sourcePartSet);
+                }
                 switch (ResourceContainer.GetResourceFlowMode(type))
                 {
                     case ResourceFlowMode.NO_FLOW:
-                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN)
-                        {
-                            sourcePartSet = new HashSet<PartSim>();
+                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN && this.partSim.resourceFlowStates[type] != 0)
+                        {
+                            //sourcePartSet = new HashSet<PartSim>();
                             //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
                             sourcePartSet.Add(this.partSim);
                         }
                         break;
 
                     case ResourceFlowMode.ALL_VESSEL:
-                        foreach (PartSim aPartSim in allParts)
-                        {
-                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
+                        for (int i = 0; i < allParts.Count; i++)
+                        {
+                            PartSim aPartSim = allParts[i];
+                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN && aPartSim.resourceFlowStates[type] != 0)
                             {
-                                if (sourcePartSet == null)
-                                {
-                                    sourcePartSet = new HashSet<PartSim>();
-                                }
-
                                 sourcePartSet.Add(aPartSim);
                             }
                         }
                         break;
 
                     case ResourceFlowMode.STAGE_PRIORITY_FLOW:
-                        var stagePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+                        foreach (HashSet<PartSim> stagePartSet in stagePartSets.Values)
+                        {
+                            stagePartSet.Clear();
+                        }
                         var maxStage = -1;
 
-                        Logger.Log(type);
-                        foreach (var aPartSim in allParts)
-                        {
-                            if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0) continue;
+                        //Logger.Log(type);
+                        for (int i = 0; i < allParts.Count; i++)
+                        {
+                            var aPartSim = allParts[i];
+                            if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0)
+                            {
+                                continue;
+                            }
 
                             var stage = aPartSim.DecouplerCount();
                             if (stage > maxStage)
@@ -300,14 +386,16 @@
                         break;
 
                     case ResourceFlowMode.STACK_PRIORITY_SEARCH:
-                        HashSet<PartSim> visited = new HashSet<PartSim>();
+                        visited.Clear();
 
                         if (SimManager.logOutput)
                         {
                             log = new LogMsg();
-                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId);
-                        }
-                        sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, log, "");
+                            log.buf.AppendLine(
+                                "Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" +
+                                this.partSim.partId);
+                        }
+                        this.partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, "");
                         if (SimManager.logOutput)
                         {
                             MonoBehaviour.print(log.buf);
@@ -315,11 +403,14 @@
                         break;
 
                     default:
-                        MonoBehaviour.print("SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");
+                        MonoBehaviour.print(
+                            "SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " +
+                            ResourceContainer.GetResourceName(type) + ")");
                         break;
                 }
 
-                if (sourcePartSet != null && sourcePartSet.Count > 0)
+
+                if (sourcePartSet.Count > 0)
                 {
                     sourcePartSets[type] = sourcePartSet;
                     if (SimManager.logOutput)
@@ -334,11 +425,13 @@
                     }
                 }
             }
-
+            
             // If we don't have sources for all the needed resources then return false without setting up any drains
-            foreach (int type in this.resourceConsumptions.Types)
-            {
-                if (!sourcePartSets.ContainsKey(type))
+            for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
+            {
+                int type = this.resourceConsumptions.Types[i];
+                HashSet<PartSim> sourcePartSet; 
+                if (!sourcePartSets.TryGetValue(type, out sourcePartSet) || sourcePartSet.Count() == 0)
                 {
                     if (SimManager.logOutput)
                     {
@@ -349,10 +442,10 @@
                     return false;
                 }
             }
-
             // Now we set the drains on the members of the sets and update the draining parts set
-            foreach (int type in this.resourceConsumptions.Types)
-            {
+            for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
+            {
+                int type = this.resourceConsumptions.Types[i];
                 HashSet<PartSim> sourcePartSet = sourcePartSets[type];
                 // Loop through the members of the set 
                 double amount = this.resourceConsumptions[type] / sourcePartSet.Count;
@@ -360,14 +453,15 @@
                 {
                     if (SimManager.logOutput)
                     {
-                        MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);
+                        MonoBehaviour.print(
+                            "Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" +
+                            partSim.partId);
                     }
 
                     partSim.resourceDrains.Add(type, amount);
                     drainingParts.Add(partSim);
                 }
             }
-
             return true;
         }
 

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -25,7 +25,6 @@
 using System.Text;
 
 using KerbalEngineer.Extensions;
-
 using UnityEngine;
 
 #endregion
@@ -36,7 +35,10 @@
 
     public class PartSim
     {
+        private static readonly Pool<PartSim> pool = new Pool<PartSim>(Create, Reset);
+
         private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
+
         public Vector3d centerOfMass;
         public double baseMass = 0d;
         public double cost;
@@ -70,49 +72,80 @@
         public double startMass = 0d;
         public String vesselName;
         public VesselType vesselType;
-
-        public PartSim(Part thePart, int id, double atmosphere, LogMsg log)
-        {
-            this.part = thePart;
-            this.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
-            this.partId = id;
-            this.name = this.part.partInfo.name;
+        
+
+        private static PartSim Create()
+        {
+            return new PartSim();
+        }
+
+        private static void Reset(PartSim partSim)
+        {
+            for (int i = 0; i < partSim.attachNodes.Count; i++)
+            {
+                partSim.attachNodes[i].Release();
+            }
+            partSim.attachNodes.Clear();
+            partSim.fuelTargets.Clear();
+            partSim.resourceDrains.Reset();
+            partSim.resourceFlowStates.Reset();
+            partSim.resources.Reset();
+            partSim.baseMass = 0d;
+            partSim.startMass = 0d;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static PartSim New(Part thePart, int id, double atmosphere, LogMsg log)
+        {
+            PartSim partSim = pool.Borrow();
+
+
+            partSim.part = thePart;
+            partSim.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
+            partSim.partId = id;
+            partSim.name = partSim.part.partInfo.name;
 
             if (log != null)
             {
-                log.buf.AppendLine("Create PartSim for " + this.name);
-            }
-
-            this.parent = null;
-            this.parentAttach = part.attachMode;
-            this.fuelCrossFeed = this.part.fuelCrossFeed;
-            this.noCrossFeedNodeKey = this.part.NoCrossFeedNodeKey;
-            this.decoupledInStage = this.DecoupledInStage(this.part);
-            this.isFuelLine = this.part.HasModule<CModuleFuelLine>();
-            this.isFuelTank = this.part is FuelTank;
-            this.isSepratron = this.IsSepratron();
-            this.inverseStage = this.part.inverseStage;
+                log.buf.AppendLine("Create PartSim for " + partSim.name);
+            }
+
+            partSim.parent = null;
+            partSim.parentAttach = partSim.part.attachMode;
+            partSim.fuelCrossFeed = partSim.part.fuelCrossFeed;
+            partSim.noCrossFeedNodeKey = partSim.part.NoCrossFeedNodeKey;
+            partSim.decoupledInStage = partSim.DecoupledInStage(partSim.part);
+            partSim.isFuelLine = partSim.part.HasModule<CModuleFuelLine>();
+            partSim.isFuelTank = partSim.part is FuelTank;
+            partSim.isSepratron = partSim.IsSepratron();
+            partSim.inverseStage = partSim.part.inverseStage;
             //MonoBehaviour.print("inverseStage = " + inverseStage);
 
-            this.cost = this.part.GetCostWet();
+            partSim.cost = partSim.part.GetCostWet();
 
             // Work out if the part should have no physical significance
-            this.isNoPhysics = this.part.HasModule<LaunchClamp>() ||
-                               this.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
-                               this.part.PhysicsSignificance == 1;
-
-            if (!this.isNoPhysics)
-            {
-                this.baseMass = this.part.mass;
+            partSim.isNoPhysics = partSim.part.HasModule<LaunchClamp>() ||
+                               partSim.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
+                               partSim.part.PhysicsSignificance == 1;
+
+            if (!partSim.isNoPhysics)
+            {
+                partSim.baseMass = partSim.part.mass;
             }
 
             if (SimManager.logOutput)
             {
-                MonoBehaviour.print((this.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + this.part.mass);
-            }
-
-            foreach (PartResource resource in this.part.Resources)
-            {
+                MonoBehaviour.print((partSim.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + partSim.part.mass);
+            }
+
+            for (int i = 0; i < partSim.part.Resources.Count; i++)
+            {
+                PartResource resource = partSim.part.Resources[i];
+
                 // Make sure it isn't NaN as this messes up the part mass and hence most of the values
                 // This can happen if a resource capacity is 0 and tweakable
                 if (!Double.IsNaN(resource.amount))
@@ -122,8 +155,8 @@
                         MonoBehaviour.print(resource.resourceName + " = " + resource.amount);
                     }
 
-                    this.resources.Add(resource.info.id, resource.amount);
-                    this.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
+                    partSim.resources.Add(resource.info.id, resource.amount);
+                    partSim.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
                 }
                 else
                 {
@@ -131,27 +164,28 @@
                 }
             }
 
-            this.startMass = this.GetMass();
-
-            this.hasVessel = (this.part.vessel != null);
-            this.isLanded = this.hasVessel && this.part.vessel.Landed;
-            if (this.hasVessel)
-            {
-                this.vesselName = this.part.vessel.vesselName;
-                this.vesselType = this.part.vesselType;
-            }
-            this.initialVesselName = this.part.initialVesselName;
-
-            this.hasMultiModeEngine = this.part.HasModule<MultiModeEngine>();
-            this.hasModuleEnginesFX = this.part.HasModule<ModuleEnginesFX>();
-            this.hasModuleEngines = this.part.HasModule<ModuleEngines>();
-
-            this.isEngine = this.hasMultiModeEngine || this.hasModuleEnginesFX || this.hasModuleEngines;
+            partSim.startMass = partSim.GetMass();
+
+            partSim.hasVessel = (partSim.part.vessel != null);
+            partSim.isLanded = partSim.hasVessel && partSim.part.vessel.Landed;
+            if (partSim.hasVessel)
+            {
+                partSim.vesselName = partSim.part.vessel.vesselName;
+                partSim.vesselType = partSim.part.vesselType;
+            }
+            partSim.initialVesselName = partSim.part.initialVesselName;
+
+            partSim.hasMultiModeEngine = partSim.part.HasModule<MultiModeEngine>();
+            partSim.hasModuleEnginesFX = partSim.part.HasModule<ModuleEnginesFX>();
+            partSim.hasModuleEngines = partSim.part.HasModule<ModuleEngines>();
+
+            partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEnginesFX || partSim.hasModuleEngines;
 
             if (SimManager.logOutput)
             {
-                MonoBehaviour.print("Created " + this.name + ". Decoupled in stage " + this.decoupledInStage);
-            }
+                MonoBehaviour.print("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
+            }
+            return partSim;
         }
 
         public ResourceContainer Resources
@@ -164,15 +198,15 @@
             get { return this.resourceDrains; }
         }
 
-        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log)
+        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
         {
             bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part);
             if (log != null)
             {
                 log.buf.AppendLine("CreateEngineSims for " + this.name);
-
-                foreach (PartModule partMod in this.part.Modules)
-                {
+                for (int i = 0; i < this.part.Modules.Count; i++)
+                {
+                    PartModule partMod = this.part.Modules[i];
                     log.buf.AppendLine("Module: " + partMod.moduleName);
                 }
 
@@ -185,8 +219,10 @@
                 // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                 string mode = this.part.GetModule<MultiModeEngine>().mode;
 
-                foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
-                {
+                List<ModuleEnginesFX> enginesFx = this.part.GetModules<ModuleEnginesFX>();
+                for (int i = 0; i < enginesFx.Count; i++)
+                {
+                    ModuleEnginesFX engine = enginesFx[i];
                     if (engine.engineID == mode)
                     {
                         if (log != null)
@@ -196,32 +232,37 @@
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
-                        EngineSim engineSim = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            engine.propellants,
-                                                            engine.isOperational,
-                                                            correctThrust,
-                                                            engine.thrustTransforms);
+                        EngineSim engineSim = EngineSim.New(
+                            this,
+                            atmosphere,
+                            mach,
+                            engine.maxFuelFlow,
+                            engine.minFuelFlow,
+                            engine.thrustPercentage,
+                            thrustvec,
+                            engine.atmosphereCurve,
+                            engine.atmChangeFlow,
+                            engine.useAtmCurve ? engine.atmCurve : null,
+                            engine.useVelCurve ? engine.velCurve : null,
+                            engine.currentThrottle,
+                            engine.g,
+                            engine.throttleLocked || fullThrust,
+                            engine.propellants,
+                            engine.isOperational,
+                            correctThrust,
+                            engine.thrustTransforms);
                         allEngines.Add(engineSim);
                     }
                 }
             }
             else
             {
-                if (this.hasModuleEnginesFX)
-                {
-                    foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
-                    {
+                if (this.hasModuleEngines)
+                {
+                    List<ModuleEngines> engines = this.part.GetModules<ModuleEngines>();  // only place that still allocate some memory
+                    for (int i = 0; i < engines.Count; i++)
+                    {
+                        ModuleEngines engine = engines[i];
                         if (log != null)
                         {
                             log.buf.AppendLine("Module: " + engine.moduleName);
@@ -229,56 +270,28 @@
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
-                        EngineSim engineSim = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            engine.propellants,
-                                                            engine.isOperational,
-                                                            correctThrust,
-                                                            engine.thrustTransforms);
+                        EngineSim engineSim = EngineSim.New(
+                            this,
+                            atmosphere,
+                            mach,
+                            engine.maxFuelFlow,
+                            engine.minFuelFlow,
+                            engine.thrustPercentage,
+                            thrustvec,
+                            engine.atmosphereCurve,
+                            engine.atmChangeFlow,
+                            engine.useAtmCurve ? engine.atmCurve : null,
+                            engine.useVelCurve ? engine.velCurve : null,
+                            engine.currentThrottle,
+                            engine.g,
+                            engine.throttleLocked || fullThrust,
+                            engine.propellants,
+                            engine.isOperational,
+                            correctThrust,
+                            engine.thrustTransforms);
                         allEngines.Add(engineSim);
                     }
                 }
-
-                if (this.hasModuleEngines)
-                {
-                    foreach (ModuleEngines engine in this.part.GetModules<ModuleEngines>())
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
-
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            engine.propellants,
-                                                            engine.isOperational,
-                                                            correctThrust,
-                                                            engine.thrustTransforms);
-                        allEngines.Add(engineSim);
-                    }
-                }
             }
 
             if (log != null)
@@ -295,11 +308,17 @@
             }
 
             Vector3 thrustvec = Vector3.zero;
-            foreach (Transform trans in thrustTransforms)
-            {
+            for (int i = 0; i < thrustTransforms.Count; i++)
+            {
+                Transform trans = thrustTransforms[i];
                 if (log != null)
                 {
-                    log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
+                    log.buf.AppendFormat(
+                        "Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n",
+                        trans.forward.x,
+                        trans.forward.y,
+                        trans.forward.z,
+                        trans.forward.magnitude);
                 }
 
                 thrustvec -= trans.forward;
@@ -350,11 +369,14 @@
             }
 
             this.attachNodes.Clear();
-            foreach (AttachNode attachNode in this.part.attachNodes)
-            {
+            for (int i = 0; i < this.part.attachNodes.Count; i++)
+            {
+                AttachNode attachNode = this.part.attachNodes[i];
                 if (log != null)
                 {
-                    log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
+                    log.buf.AppendLine(
+                        "AttachNode " + attachNode.id + " = " +
+                        (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
                 }
 
                 if (attachNode.attachedPart != null && attachNode.id != "Strut")
@@ -367,7 +389,8 @@
                             log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
                         }
 
-                        this.attachNodes.Add(new AttachNodeSim(attachedSim, attachNode.id, attachNode.nodeType));
+                        AttachNodeSim attachnode = AttachNodeSim.New(attachedSim, attachNode.id, attachNode.nodeType);
+                        this.attachNodes.Add(attachnode);
                     }
                     else
                     {
@@ -379,8 +402,9 @@
                 }
             }
 
-            foreach (Part p in this.part.fuelLookupTargets)
-            {
+            for (int i = 0; i < this.part.fuelLookupTargets.Count; i++)
+            {
+                Part p = this.part.fuelLookupTargets[i];
                 if (p != null)
                 {
                     PartSim targetSim;
@@ -446,18 +470,13 @@
                 return true;
             }
 
-            var modList = this.part.Modules.OfType<ModuleEngines>();
-            if (modList.Count() == 0)
+            if (!this.part.IsEngine())
             {
                 return false;
             }
 
-            if (modList.First().throttleLocked)
-            {
-                return true;
-            }
-
-            return false;
+
+            return this.part.IsSolidRocket();
         }
 
         public void ReleasePart()
@@ -468,7 +487,7 @@
         // All functions below this point must not rely on the part member (it may be null)
         //
 
-        public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent)
+        public void GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, HashSet<PartSim> allSources, LogMsg log, String indent)
         {
             if (log != null)
             {
@@ -476,10 +495,7 @@
                 indent += "  ";
             }
 
-            HashSet<PartSim> allSources = new HashSet<PartSim>();
-            HashSet<PartSim> partSources = null;
-
-            // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns empty list.
+            // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns as is.
             if (visited.Contains(this))
             {
                 if (log != null)
@@ -487,7 +503,7 @@
                     log.buf.AppendLine(indent + "Returning empty set, already visited (" + this.name + ":" + this.partId + ")");
                 }
 
-                return allSources;
+                return;
             }
 
             //if (log != null)
@@ -499,8 +515,11 @@
             // Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
             //MonoBehaviour.print("foreach fuel line");
 
-            foreach (PartSim partSim in this.fuelTargets)
-            {
+            int lastCount = allSources.Count;
+
+            for (int i = 0; i < this.fuelTargets.Count; i++)
+            {
+                PartSim partSim = this.fuelTargets[i];
                 if (visited.Contains(partSim))
                 {
                     //if (log != null)
@@ -511,24 +530,20 @@
                     //if (log != null)
                     //    log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
 
-                    partSources = partSim.GetSourceSet(type, allParts, visited, log, indent);
-                    if (partSources.Count > 0)
-                    {
-                        allSources.UnionWith(partSources);
-                        partSources.Clear();
-                    }
-                }
-            }
-
-            if (allSources.Count > 0)
+                    partSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                }
+            }
+
+            if (allSources.Count > lastCount)
             {
                 if (log != null)
                 {
-                    log.buf.AppendLine(indent + "Returning " + allSources.Count + " fuel target sources (" + this.name + ":" + this.partId + ")");
-                }
-
-                return allSources;
-            }
+                    log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")");
+                }
+
+                return;
+            }
+
 
             // Rule 3: This rule has been removed and merged with rules 4 and 7 to fix issue with fuel tanks with disabled crossfeed
 
@@ -539,14 +554,18 @@
             //  The order in which mount points of a part are scanned appears to be fixed and defined by the part specification file. [Experiment]
             if (this.fuelCrossFeed)
             {
+                lastCount = allSources.Count;
                 //MonoBehaviour.print("foreach attach node");
-                foreach (AttachNodeSim attachSim in this.attachNodes)
-                {
+                for (int i = 0; i < this.attachNodes.Count; i++)
+                {
+                    AttachNodeSim attachSim = this.attachNodes[i];
                     if (attachSim.attachedPartSim != null)
                     {
                         if (attachSim.nodeType == AttachNode.NodeType.Stack)
                         {
-                            if (!(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(this.noCrossFeedNodeKey)))
+                            if (
+                                !(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 &&
+                                  attachSim.id.Contains(this.noCrossFeedNodeKey)))
                             {
                                 if (visited.Contains(attachSim.attachedPartSim))
                                 {
@@ -558,26 +577,21 @@
                                     //if (log != null)
                                     //    log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
 
-                                    partSources = attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, log, indent);
-                                    if (partSources.Count > 0)
-                                    {
-                                        allSources.UnionWith(partSources);
-                                        partSources.Clear();
-                                    }
+                                    attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
                                 }
                             }
                         }
                     }
                 }
 
-                if (allSources.Count > 0)
+                if (allSources.Count > lastCount)
                 {
                     if (log != null)
                     {
-                        log.buf.AppendLine(indent + "Returning " + allSources.Count + " attached sources (" + this.name + ":" + this.partId + ")");
-                    }
-
-                    return allSources;
+                        log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
+                    }
+
+                    return;
                 }
             }
 
@@ -597,7 +611,7 @@
                     }
                 }
 
-                return allSources;
+                return;
             }
 
             // Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its 
@@ -613,15 +627,16 @@
                     }
                     else
                     {
-                        allSources = this.parent.GetSourceSet(type, allParts, visited, log, indent);
-                        if (allSources.Count > 0)
+                        lastCount = allSources.Count;
+                        this.parent.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                        if (allSources.Count > lastCount)
                         {
                             if (log != null)
                             {
-                                log.buf.AppendLine(indent + "Returning " + allSources.Count + " parent sources (" + this.name + ":" + this.partId + ")");
+                                log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
                             }
 
-                            return allSources;
+                            return;
                         }
                     }
                 }
@@ -631,14 +646,15 @@
             //if (log != null)
             //    log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
 
-            return allSources;
+            return;
         }
 
         public void RemoveAttachedParts(HashSet<PartSim> partSims)
         {
             // Loop through the attached parts
-            foreach (AttachNodeSim attachSim in this.attachNodes)
-            {
+            for (int i = 0; i < this.attachNodes.Count; i++)
+            {
+                AttachNodeSim attachSim = this.attachNodes[i];
                 // If the part is in the set then "remove" it by clearing the PartSim reference
                 if (partSims.Contains(attachSim.attachedPartSim))
                 {
@@ -650,8 +666,9 @@
         public void DrainResources(double time)
         {
             //MonoBehaviour.print("DrainResources(" + name + ":" + partId + ", " + time + ")");
-            foreach (int type in this.resourceDrains.Types)
-            {
+            for (int i = 0; i < this.resourceDrains.Types.Count; i++)
+            {
+                int type = this.resourceDrains.Types[i];
                 //MonoBehaviour.print("draining " + (time * resourceDrains[type]) + " " + ResourceContainer.GetResourceName(type));
                 this.resources.Add(type, -time * this.resourceDrains[type]);
                 //MonoBehaviour.print(ResourceContainer.GetResourceName(type) + " left = " + resources[type]);
@@ -663,8 +680,9 @@
             //MonoBehaviour.print("TimeToDrainResource(" + name + ":" + partId + ")");
             double time = double.MaxValue;
 
-            foreach (int type in this.resourceDrains.Types)
-            {
+            for (int i = 0; i < this.resourceDrains.Types.Count; i++)
+            {
+                int type = this.resourceDrains.Types[i];
                 if (this.resourceDrains[type] > 0)
                 {
                     time = Math.Min(time, this.resources[type] / this.resourceDrains[type]);
@@ -677,6 +695,19 @@
             return time;
         }
 
+        public bool EmptyOf(HashSet<int> types)
+        {
+            foreach (int type in types)
+            {
+                if (this.resources.HasType(type) && this.resourceFlowStates[type] != 0 && (double)this.resources[type] > SimManager.RESOURCE_MIN)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
         public int DecouplerCount()
         {
             int count = 0;
@@ -702,8 +733,9 @@
         {
             double mass = this.baseMass;
 
-            foreach (int type in this.resources.Types)
-            {
+            for (int i = 0; i < this.resources.Types.Count; i++)
+            {
+                int type = this.resources.Types[i];
                 mass += this.resources.GetResourceMass(type);
             }
 
@@ -737,8 +769,9 @@
 
             buffer.AppendFormat(", isSep = {0}", this.isSepratron);
 
-            foreach (int type in this.resources.Types)
-            {
+            for (int i = 0; i < this.resources.Types.Count; i++)
+            {
+                int type = this.resources.Types[i];
                 buffer.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), this.resources[type]);
             }
 
@@ -761,8 +794,9 @@
             if (allParts != null)
             {
                 String newPrefix = prefix + " ";
-                foreach (PartSim partSim in allParts)
-                {
+                for (int i = 0; i < allParts.Count; i++)
+                {
+                    PartSim partSim = allParts[i];
                     if (partSim.parent == this)
                     {
                         partSim.DumpPartToBuffer(buffer, newPrefix, allParts);

--- a/KerbalEngineer/VesselSimulator/ResourceContainer.cs
+++ b/KerbalEngineer/VesselSimulator/ResourceContainer.cs
@@ -19,6 +19,7 @@
 
 #region Using Directives
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
 
@@ -30,15 +31,17 @@
 {
     public class ResourceContainer
     {
-        private Hashtable resources = new Hashtable();
+        private Dictionary<int, double> resources = new Dictionary<int, double>();
+        private List<int> types = new List<int>();
 
         public double this[int type]
         {
             get
             {
-                if (this.resources.ContainsKey(type))
+                double value;
+                if (this.resources.TryGetValue(type, out value))
                 {
-                    return (double)this.resources[type];
+                    return value;
                 }
 
                 return 0d;
@@ -52,6 +55,7 @@
                 else
                 {
                     this.resources.Add(type, value);
+                    this.types.Add(type);
                 }
             }
         }
@@ -60,13 +64,6 @@
         {
             get
             {
-                List<int> types = new List<int>();
-
-                foreach (int key in this.resources.Keys)
-                {
-                    types.Add(key);
-                }
-
                 return types;
             }
         }
@@ -92,7 +89,7 @@
             {
                 foreach (int type in this.resources.Keys)
                 {
-                    if ((double)this.resources[type] > SimManager.RESOURCE_MIN)
+                    if (this.resources[type] > SimManager.RESOURCE_MIN)
                     {
                         return false;
                     }
@@ -111,7 +108,7 @@
         {
             foreach (int type in types)
             {
-                if (this.HasType(type) && (double)this.resources[type] > SimManager.RESOURCE_MIN)
+                if (this.HasType(type) && this.resources[type] > SimManager.RESOURCE_MIN)
                 {
                     return false;
                 }
@@ -124,17 +121,19 @@
         {
             if (this.resources.ContainsKey(type))
             {
-                this.resources[type] = (double)this.resources[type] + amount;
+                this.resources[type] = this.resources[type] + amount;
             }
             else
             {
                 this.resources.Add(type, amount);
+                this.types.Add(type);
             }
         }
 
         public void Reset()
         {
-            this.resources = new Hashtable();
+            this.resources.Clear();
+            this.types.Clear();
         }
 
         public void Debug()
@@ -148,7 +147,7 @@
         public double GetResourceMass(int type)
         {
             double density = GetResourceDensity(type);
-            return density == 0d ? 0d : (double)this.resources[type] * density;
+            return density == 0d ? 0d : this.resources[type] * density;
         }
 
         public static ResourceFlowMode GetResourceFlowMode(int type)
@@ -158,7 +157,7 @@
 
         public static ResourceTransferMode GetResourceTransferMode(int type)
         {
-            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;
+            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;;
         }
 
         public static float GetResourceDensity(int type)

--- a/KerbalEngineer/VesselSimulator/SimManager.cs
+++ b/KerbalEngineer/VesselSimulator/SimManager.cs
@@ -46,17 +46,20 @@
         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 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;
+
+        // Support for RealFuels using reflection to check localCorrectThrust without dependency
+
+        private static bool hasCheckedForMods;
         private static bool hasInstalledRealFuels;
-
+        private static FieldInfo RF_ModuleEngineConfigs_localCorrectThrust;
+        private static FieldInfo RF_ModuleHybridEngine_localCorrectThrust;
+        private static FieldInfo RF_ModuleHybridEngines_localCorrectThrust;
+        private static bool hasInstalledKIDS;
+        private static MethodInfo KIDS_Utils_GetIspMultiplier;
+        private static bool bKIDSThrustISP = false;
         #endregion
 
         #region Delegates
@@ -81,7 +84,7 @@
 
         public static Stage[] Stages { get; private set; }
 
-        public static double Velocity { get; set; }
+        public static double Mach { get; set; }
 
         public static String failMessage { get; private set; }
 
@@ -89,54 +92,112 @@
 
         #region Methods
 
+        private static void CheckForMods()
+        {
+            hasCheckedForMods = true;
+
+            foreach (var assembly in AssemblyLoader.loadedAssemblies)
+            {
+                MonoBehaviour.print("Assembly:" + assembly.assembly);
+
+                var name = assembly.assembly.ToString().Split(',')[0];
+
+                if (name == "RealFuels")
+                {
+                    MonoBehaviour.print("Found RealFuels mod");
+
+                    var RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
+                    if (RF_ModuleEngineConfigs_Type != null)
+                    {
+                        RF_ModuleEngineConfigs_localCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
+                    if (RF_ModuleHybridEngine_Type != null)
+                    {
+                        RF_ModuleHybridEngine_localCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
+                    if (RF_ModuleHybridEngines_Type != null)
+                    {
+                        RF_ModuleHybridEngines_localCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
+                    }
+
+                    hasInstalledRealFuels = true;
+                    break;
+                }
+                else if (name == "KerbalIspDifficultyScaler")
+                {
+                    var KIDS_Utils_Type = assembly.assembly.GetType("KerbalIspDifficultyScaler.KerbalIspDifficultyScalerUtils");
+                    if (KIDS_Utils_Type != null)
+                    {
+                        KIDS_Utils_GetIspMultiplier = KIDS_Utils_Type.GetMethod("GetIspMultiplier");
+                    }
+
+                    hasInstalledKIDS = true;
+                }
+            }
+        }
+
         public static bool DoesEngineUseCorrectedThrust(Part theEngine)
         {
-            if (!hasInstalledRealFuels /*|| HighLogic.LoadedSceneIsFlight*/)
-            {
-                return false;
-            }
-
-            // 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"))
-            {
-                var modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
-                if (modEngineConfigs != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleEngineConfigs_locaCorrectThrust.GetValue(modEngineConfigs))
-                    {
-                        return true;
-                    }
-                }
-            }
-
-            if (RF_ModuleHybridEngine_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngine"))
-            {
-                var modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
-                if (modHybridEngine != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleHybridEngine_locaCorrectThrust.GetValue(modHybridEngine))
-                    {
-                        return true;
-                    }
-                }
-            }
-
-            if (RF_ModuleHybridEngines_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngines"))
-            {
-                var modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
-                if (modHybridEngines != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleHybridEngines_locaCorrectThrust.GetValue(modHybridEngines))
-                    {
-                        return true;
-                    }
-                }
+            if (hasInstalledRealFuels)
+            {
+                // Look for any of the Real Fuels engine modules and call the relevant method to find out
+                if (RF_ModuleEngineConfigs_localCorrectThrust != null && theEngine.Modules.Contains("ModuleEngineConfigs"))
+                {
+                    var modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
+                    if (modEngineConfigs != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleEngineConfigs_localCorrectThrust.GetValue(modEngineConfigs);
+                    }
+                }
+
+                if (RF_ModuleHybridEngine_localCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngine"))
+                {
+                    var modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
+                    if (modHybridEngine != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleHybridEngine_localCorrectThrust.GetValue(modHybridEngine);
+                    }
+                }
+
+                if (RF_ModuleHybridEngines_localCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngines"))
+                {
+                    var modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
+                    if (modHybridEngines != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleHybridEngines_localCorrectThrust.GetValue(modHybridEngines);
+                    }
+                }
+            }
+
+            if (hasInstalledKIDS && HighLogic.LoadedSceneIsEditor)
+            {
+                return bKIDSThrustISP;
             }
 
             return false;
+        }
+
+        public static void UpdateModSettings()
+        {
+            if (!hasCheckedForMods)
+            {
+                CheckForMods();
+            }
+
+            if (hasInstalledKIDS)
+            {
+                // (out ispMultiplierVac, out ispMultiplierAtm, out extendToZeroIsp, out thrustCorrection, out ispCutoff, out thrustCutoff);
+                object[] parameters = new object[6];
+                KIDS_Utils_GetIspMultiplier.Invoke(null, parameters);
+                bKIDSThrustISP = (bool)parameters[3];
+            }
         }
 
         public static String GetVesselTypeString(VesselType vesselType)
@@ -171,9 +232,9 @@
 
         public static void RequestSimulation()
         {
-            if (!hasCheckedForRealFuels)
-            {
-                GetRealFuelsTypes();
+            if (!hasCheckedForMods)
+            {
+                CheckForMods();
             }
 
             lock (locker)
@@ -215,42 +276,6 @@
             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)
@@ -331,7 +356,7 @@
                 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))
+                if (sim.PrepareSimulation(parts, Gravity, Atmosphere, Mach, dumpTree, vectoredThrust))
                 {
                     ThreadPool.QueueUserWorkItem(RunSimulation, sim);
                 }

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -45,11 +45,14 @@
         private double atmosphere;
         private int currentStage;
         private double currentisp;
+        private HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
         private bool doingCurrent;
         private List<PartSim> dontStageParts;
+        private List<List<PartSim>> dontStagePartsLists = new List<List<PartSim>>();
         private HashSet<PartSim> drainingParts;
         private HashSet<int> drainingResources;
         private double gravity;
+        private Dictionary<Part, PartSim> partSimLookup;
 
         private int lastStage;
         private List<Part> partList;
@@ -67,92 +70,106 @@
         private Vector3 vecActualThrust;
         private Vector3 vecStageDeltaV;
         private Vector3 vecThrust;
-        private double velocity;
+        private double mach;
         public String vesselName;
         public VesselType vesselType;
 
         public Simulation()
         {
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Simulation created");
-            }
-        }
-
-        private double ShipMass
-        {
-            get
-            {
-                double mass = 0d;
-
-                foreach (PartSim partSim in this.allParts)
-                {
-                    mass += partSim.GetMass();
-                }
-
-                return mass;
-            }
-        }
-
-        private Vector3d ShipCom
-        {
-            get
-            {
-                WeightedVectorAverager averager = new WeightedVectorAverager();
-
-                foreach (PartSim partSim in this.allParts)
-                {
-                    averager.Add(partSim.centerOfMass, partSim.GetMass());
-                }
-
-                return averager.Get();
-            }
-        }
-
-        // This function prepares the simulation by creating all the necessary data structures it will 
-        // need during the simulation.  All required data is copied from the core game data structures 
-        // so that the simulation itself can be run in a background thread without having issues with 
-        // the core game changing the data while the simulation is running.
-        public bool PrepareSimulation(List<Part> parts, double theGravity, double theAtmosphere = 0, double theVelocity = 0, bool dumpTree = false, bool vectoredThrust = false)
-        {
-            LogMsg log = null;
-            if (SimManager.logOutput)
-            {
-                log = new LogMsg();
-                log.buf.AppendLine("PrepareSimulation started");
-                dumpTree = true;
-            }
-            this._timer.Start();
-
-            // Store the parameters in members for ease of access in other functions
-            this.partList = parts;
-            this.gravity = theGravity;
-            this.atmosphere = theAtmosphere;
-            this.velocity = theVelocity;
-            this.lastStage = Staging.lastStage;
-            //MonoBehaviour.print("lastStage = " + lastStage);
-
-            // Create the lists for our simulation parts
             this.allParts = new List<PartSim>();
             this.allFuelLines = new List<PartSim>();
             this.drainingParts = new HashSet<PartSim>();
             this.allEngines = new List<EngineSim>();
             this.activeEngines = new List<EngineSim>();
             this.drainingResources = new HashSet<int>();
+            this.totalStageThrustForce = new ForceAccumulator();
 
             // A dictionary for fast lookup of Part->PartSim during the preparation phase
-            Dictionary<Part, PartSim> partSimLookup = new Dictionary<Part, PartSim>();
+            partSimLookup = new Dictionary<Part, PartSim>();
+
+            if (SimManager.logOutput)
+            {
+                MonoBehaviour.print("Simulation created");
+            }
+        }
+
+        private double ShipMass
+        {
+            get
+            {
+                double mass = 0d;
+
+                for (int i = 0; i < this.allParts.Count; i++)
+                {
+                    PartSim partSim = this.allParts[i];
+                    mass += partSim.GetMass();
+                }
+
+                return mass;
+            }
+        }
+
+        private Vector3d ShipCom
+        {
+            get
+            {
+                WeightedVectorAverager averager = new WeightedVectorAverager();
+
+                for (int i = 0; i < this.allParts.Count; i++)
+                {
+                    PartSim partSim = this.allParts[i];
+                    averager.Add(partSim.centerOfMass, partSim.GetMass());
+                }
+
+                return averager.Get();
+            }
+        }
+
+        // This function prepares the simulation by creating all the necessary data structures it will 
+        // need during the simulation.  All required data is copied from the core game data structures 
+        // so that the simulation itself can be run in a background thread without having issues with 
+        // the core game changing the data while the simulation is running.
+        public bool PrepareSimulation(List<Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false)
+        {
+            LogMsg log = null;
+            if (SimManager.logOutput)
+            {
+                log = new LogMsg();
+                log.buf.AppendLine("PrepareSimulation started");
+                dumpTree = true;
+            }
+            this._timer.Start();
+
+            // Store the parameters in members for ease of access in other functions
+            this.partList = parts;
+            this.gravity = theGravity;
+            this.atmosphere = theAtmosphere;
+            this.mach = theMach;
+            this.lastStage = Staging.lastStage;
+            //MonoBehaviour.print("lastStage = " + lastStage);
+
+            // Clear the lists for our simulation parts
+            this.allParts.Clear();
+            this.allFuelLines.Clear();
+            this.drainingParts.Clear();
+            this.allEngines.Clear();
+            this.activeEngines.Clear();
+            this.drainingResources.Clear();
+
+            // A dictionary for fast lookup of Part->PartSim during the preparation phase
+            partSimLookup.Clear();
 
             if (this.partList.Count > 0 && this.partList[0].vessel != null)
             {
                 this.vesselName = this.partList[0].vessel.vesselName;
                 this.vesselType = this.partList[0].vessel.vesselType;
             }
-
+            //MonoBehaviour.print("PrepareSimulation pool size = " + PartSim.pool.Count());
             // First we create a PartSim for each Part (giving each a unique id)
             int partId = 1;
-            foreach (Part part in this.partList)
-            {
+            for (int i = 0; i < this.partList.Count; i++)
+            {
+                Part part = this.partList[i];
                 // If the part is already in the lookup dictionary then log it and skip to the next part
                 if (partSimLookup.ContainsKey(part))
                 {
@@ -164,7 +181,7 @@
                 }
 
                 // Create the PartSim
-                PartSim partSim = new PartSim(part, partId, this.atmosphere, log);
+                PartSim partSim = PartSim.New(part, partId, this.atmosphere, log);
 
                 // Add it to the Part lookup dictionary and the necessary lists
                 partSimLookup.Add(part, partSim);
@@ -175,7 +192,7 @@
                 }
                 if (partSim.isEngine)
                 {
-                    partSim.CreateEngineSims(this.allEngines, this.atmosphere, this.velocity, vectoredThrust, log);
+                    partSim.CreateEngineSims(this.allEngines, this.atmosphere, this.mach, vectoredThrust, fullThrust, log);
                 }
 
                 partId++;
@@ -185,16 +202,18 @@
 
             // Now that all the PartSims have been created we can do any set up that needs access to other parts
             // First we set up all the parent links
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 partSim.SetupParent(partSimLookup, log);
             }
 
             // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets
             if (HighLogic.LoadedSceneIsEditor)
             {
-                foreach (PartSim partSim in this.allFuelLines)
-                {
+                for (int i = 0; i < this.allFuelLines.Count; i++)
+                {
+                    PartSim partSim = this.allFuelLines[i];
                     CModuleFuelLine fuelLine = partSim.part.GetModule<CModuleFuelLine>();
                     if (fuelLine.target != null)
                     {
@@ -227,8 +246,9 @@
             }
 
             //MonoBehaviour.print("SetupAttachNodes and count stages");
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 partSim.SetupAttachNodes(partSimLookup, log);
                 if (partSim.decoupledInStage >= this.lastStage)
                 {
@@ -238,8 +258,9 @@
 
             // And finally release the Part references from all the PartSims
             //MonoBehaviour.print("ReleaseParts");
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 partSim.ReleasePart();
             }
 
@@ -260,7 +281,7 @@
 
             return true;
         }
-
+        
         // This function runs the simulation and returns a newly created array of Stage objects
         public Stage[] RunSimulation()
         {
@@ -280,13 +301,13 @@
             // Start with the last stage to simulate
             // (this is in a member variable so it can be accessed by AllowedToStage and ActivateStage)
             this.currentStage = this.lastStage;
-
             // Work out which engines would be active if just doing the staging and if this is different to the 
             // currently active engines then generate an extra stage
             // Loop through all the engines
             bool anyActive = false;
-            foreach (EngineSim engine in this.allEngines)
-            {
+            for (int i = 0; i < this.allEngines.Count; i++)
+            {
+                EngineSim engine = this.allEngines[i];
                 if (log != null)
                 {
                     log.buf.AppendLine("Testing engine mod of " + engine.partSim.name + ":" + engine.partSim.partId);
@@ -341,7 +362,7 @@
             }
 
             // Create a list of lists of PartSims that prevent decoupling
-            List<List<PartSim>> dontStagePartsLists = this.BuildDontStageLists(log);
+            this.BuildDontStageLists(log);
 
             if (log != null)
             {
@@ -350,7 +371,6 @@
 
             // Create the array of stages that will be returned
             Stage[] stages = new Stage[this.currentStage + 1];
-
 
             // Loop through the stages
             while (this.currentStage >= 0)
@@ -414,8 +434,9 @@
 
                 // Calculate the cost and mass of this stage and add all engines and tanks that are decoupled
                 // in the next stage to the dontStageParts list
-                foreach (PartSim partSim in this.allParts)
-                {
+                for (int i = 0; i < this.allParts.Count; i++)
+                {
+                    PartSim partSim = this.allParts[i];
                     if (partSim.decoupledInStage == this.currentStage - 1)
                     {
                         stage.cost += partSim.cost;
@@ -432,8 +453,9 @@
                     if (this.dontStageParts.Count > 0)
                     {
                         log.buf.AppendLine("Parts preventing staging:");
-                        foreach (PartSim partSim in this.dontStageParts)
-                        {
+                        for (int i = 0; i < this.dontStageParts.Count; i++)
+                        {
+                            PartSim partSim = this.dontStageParts[i];
                             partSim.DumpPartToBuffer(log.buf, "");
                         }
                     }
@@ -444,6 +466,7 @@
 
                     log.Flush();
                 }
+
 
                 // Now we will loop until we are allowed to stage
                 int loopCounter = 0;
@@ -451,7 +474,6 @@
                 {
                     loopCounter++;
                     //MonoBehaviour.print("loop = " + loopCounter);
-
                     // Calculate how long each draining tank will take to drain and run for the minimum time
                     double resourceDrainTime = double.MaxValue;
                     PartSim partMinDrain = null;
@@ -469,7 +491,6 @@
                     {
                         MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")");
                     }
-
                     foreach (PartSim partSim in this.drainingParts)
                     {
                         partSim.DrainResources(resourceDrainTime);
@@ -501,7 +522,7 @@
 
                     // Recalculate the current thrust and isp for the next step
                     this.CalculateThrustAndISP();
-
+                    
                     // Check if we actually changed anything
                     if (this.stepStartMass == this.stepEndMass)
                     {
@@ -527,11 +548,12 @@
                     this.stepStartMass = this.stepEndMass;
                 }
 
+
                 // Store more values in the Stage object and stick it in the array
 
                 // Store the magnitude of the deltaV vector
                 stage.deltaV = this.vecStageDeltaV.magnitude;
-                stage.resourceMass = this.stepStartMass - this.stepEndMass;
+                stage.resourceMass = this.stageStartMass - this.stepEndMass;
 
                 // Recalculate effective stage isp from the stage deltaV (flip the standard deltaV calculation around)
                 // Note: If the mass doesn't change then this is a divide by zero
@@ -606,29 +628,54 @@
                 this._timer.Stop();
                 MonoBehaviour.print("RunSimulation: " + this._timer.ElapsedMilliseconds + "ms");
             }
-
+            FreePooledObject();
+            
             return stages;
         }
 
-        private List<List<PartSim>> BuildDontStageLists(LogMsg log)
+        
+        // Make sure we free them all, even if they should all be free already at this point
+        public void FreePooledObject()
+        {
+            //MonoBehaviour.print("FreePooledObject pool size before = " + PartSim.pool.Count() + " for " + allParts.Count + " parts");
+            foreach (PartSim part in allParts)
+            {
+                part.Release();
+            }
+            //MonoBehaviour.print("FreePooledObject pool size after = " + PartSim.pool.Count());
+
+            //MonoBehaviour.print("FreePooledObject pool size before = " + EngineSim.pool.Count() + " for " + allEngines.Count + " engines");
+            foreach (EngineSim engine in allEngines)
+            {
+                engine.Release();
+            }
+            //MonoBehaviour.print("FreePooledObject pool size after = " + EngineSim.pool.Count());
+        }
+
+        private void BuildDontStageLists(LogMsg log)
         {
             if (log != null)
             {
                 log.buf.AppendLine("Creating list with capacity of " + (this.currentStage + 1));
             }
-            List<List<PartSim>> lists = new List<List<PartSim>>();
+            
             for (int i = 0; i <= this.currentStage; i++)
             {
-                lists.Add(new List<PartSim>());
-            }
-
-            foreach (PartSim partSim in this.allParts)
-            {
+                if (i < dontStagePartsLists.Count)
+                    dontStagePartsLists[i].Clear();
+                else
+                    dontStagePartsLists.Add(new List<PartSim>());
+            }
+
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 if (partSim.isEngine || !partSim.Resources.Empty)
                 {
                     if (log != null)
                     {
-                        log.buf.AppendLine(partSim.name + ":" + partSim.partId + " is engine or tank, decoupled = " + partSim.decoupledInStage);
+                        log.buf.AppendLine(
+                            partSim.name + ":" + partSim.partId + " is engine or tank, decoupled = " + partSim.decoupledInStage);
                     }
 
                     if (partSim.decoupledInStage < -1 || partSim.decoupledInStage > this.currentStage - 1)
@@ -640,28 +687,27 @@
                     }
                     else
                     {
-                        lists[partSim.decoupledInStage + 1].Add(partSim);
+                        dontStagePartsLists[partSim.decoupledInStage + 1].Add(partSim);
                     }
                 }
             }
 
             for (int i = 1; i <= this.lastStage; i++)
             {
-                if (lists[i].Count == 0)
-                {
-                    lists[i] = lists[i - 1];
-                }
-            }
-
-            return lists;
+                if (dontStagePartsLists[i].Count == 0)
+                {
+                    dontStagePartsLists[i] = dontStagePartsLists[i - 1];
+                }
+            }
         }
 
         // This function simply rebuilds the active engines by testing the isActive flag of all the engines
         private void UpdateActiveEngines()
         {
             this.activeEngines.Clear();
-            foreach (EngineSim engine in this.allEngines)
-            {
+            for (int i = 0; i < this.allEngines.Count; i++)
+            {
+                EngineSim engine = this.allEngines[i];
                 if (engine.isActive)
                 {
                     this.activeEngines.Add(engine);
@@ -679,12 +725,12 @@
             this.totalStageActualThrust = 0d;
             this.totalStageFlowRate = 0d;
             this.totalStageIspFlowRate = 0d;
-            this.totalStageThrustForce = new ForceAccumulator();
-
+            this.totalStageThrustForce.Reset();
             // Loop through all the active engines totalling the thrust, actual thrust and mass flow rates
             // The thrust is totalled as vectors
-            foreach (EngineSim engine in this.activeEngines)
-            {
+            for (int i = 0; i < this.activeEngines.Count; i++)
+            {
+                EngineSim engine = this.activeEngines[i];
                 this.simpleTotalThrust += engine.thrust;
                 this.vecThrust += ((float)engine.thrust * engine.thrustVec);
                 this.vecActualThrust += ((float)engine.actualThrust * engine.thrustVec);
@@ -692,13 +738,13 @@
                 this.totalStageFlowRate += engine.ResourceConsumptions.Mass;
                 this.totalStageIspFlowRate += engine.ResourceConsumptions.Mass * engine.isp;
 
-                foreach (AppliedForce f in engine.appliedForces) {
+                for (int j = 0; j < engine.appliedForces.Count; j++)
+                {
+                    AppliedForce f = engine.appliedForces[j];
                     this.totalStageThrustForce.AddForce(f);
                 }
             }
-
             //MonoBehaviour.print("vecThrust = " + vecThrust.ToString() + "   magnitude = " + vecThrust.magnitude);
-
             this.totalStageThrust = this.vecThrust.magnitude;
             this.totalStageActualThrust = this.vecActualThrust.magnitude;
 
@@ -733,14 +779,16 @@
             this.drainingParts.Clear();
 
             // Loop through all the active engine modules
-            foreach (EngineSim engine in this.activeEngines)
-            {
+            for (int i = 0; i < this.activeEngines.Count; i++)
+            {
+                EngineSim engine = this.activeEngines[i];
                 // Set the resource drains for this engine
                 if (engine.SetResourceDrains(this.allParts, this.allFuelLines, this.drainingParts))
                 {
                     // If it is active then add the consumed resource types to the set
-                    foreach (int type in engine.ResourceConsumptions.Types)
-                    {
+                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; j++)
+                    {
+                        int type = engine.ResourceConsumptions.Types[j];
                         this.drainingResources.Add(type);
                     }
                 }
@@ -754,8 +802,9 @@
                 StringBuilder buffer = new StringBuilder(1024);
                 buffer.AppendFormat("Active engines = {0:d}\n", this.activeEngines.Count);
                 int i = 0;
-                foreach (EngineSim engine in this.activeEngines)
-                {
+                for (int j = 0; j < this.activeEngines.Count; j++)
+                {
+                    EngineSim engine = this.activeEngines[j];
                     engine.DumpEngineToBuffer(buffer, "Engine " + (i++) + ":");
                 }
                 MonoBehaviour.print(buffer);
@@ -775,15 +824,16 @@
 
             if (this.activeEngines.Count > 0)
             {
-                foreach (PartSim partSim in this.dontStageParts)
-                {
+                for (int i = 0; i < this.dontStageParts.Count; i++)
+                {
+                    PartSim partSim = this.dontStageParts[i];
                     if (SimManager.logOutput)
                     {
                         partSim.DumpPartToBuffer(buffer, "Testing: ");
                     }
                     //buffer.AppendFormat("isSepratron = {0}\n", partSim.isSepratron ? "true" : "false");
 
-                    if (!partSim.isSepratron && !partSim.Resources.EmptyOf(this.drainingResources))
+                    if (!partSim.isSepratron && !partSim.EmptyOf(this.drainingResources))
                     {
                         if (SimManager.logOutput)
                         {
@@ -795,8 +845,9 @@
 
                     if (partSim.isEngine)
                     {
-                        foreach (EngineSim engine in this.activeEngines)
-                        {
+                        for (int j = 0; j < this.activeEngines.Count; j++)
+                        {
+                            EngineSim engine = this.activeEngines[j];
                             if (engine.partSim == partSim)
                             {
                                 if (SimManager.logOutput)
@@ -834,9 +885,10 @@
         private void ActivateStage()
         {
             // Build a set of all the parts that will be decoupled
-            HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
-            foreach (PartSim partSim in this.allParts)
-            {
+            decoupledParts.Clear();
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 if (partSim.decoupledInStage >= this.currentStage)
                 {
                     decoupledParts.Add(partSim);
@@ -847,14 +899,17 @@
             {
                 // Remove it from the all parts list
                 this.allParts.Remove(partSim);
+                partSim.Release();
                 if (partSim.isEngine)
                 {
                     // If it is an engine then loop through all the engine modules and remove all the ones from this engine part
                     for (int i = this.allEngines.Count - 1; i >= 0; i--)
                     {
-                        if (this.allEngines[i].partSim == partSim)
+                        EngineSim engine = this.allEngines[i];
+                        if (engine.partSim == partSim)
                         {
                             this.allEngines.RemoveAt(i);
+                            engine.Release();
                         }
                     }
                 }
@@ -866,15 +921,17 @@
             }
 
             // Loop through all the (remaining) parts
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 // Ask the part to remove all the parts that are decoupled
                 partSim.RemoveAttachedParts(decoupledParts);
             }
 
             // Now we loop through all the engines and activate those that are ignited in this stage
-            foreach (EngineSim engine in this.allEngines)
-            {
+            for (int i = 0; i < this.allEngines.Count; i++)
+            {
+                EngineSim engine = this.allEngines[i];
                 if (engine.partSim.inverseStage == this.currentStage)
                 {
                     engine.isActive = true;

--- a/KerbalEngineer/VesselSimulator/Stage.cs
+++ b/KerbalEngineer/VesselSimulator/Stage.cs
@@ -29,27 +29,28 @@
 {
     public class Stage
     {
-        public double actualThrust = 0f;
-        public double actualThrustToWeight = 0f;
-        public double cost = 0d;
-        public double deltaV = 0f;
-        public double inverseTotalDeltaV = 0f;
-        public double isp = 0f;
-        public double mass = 0f;
-        public double maxThrustToWeight = 0f;
+        public double actualThrust = 0.0;
+        public double actualThrustToWeight = 0.0;
+        public double cost = 0.0;
+        public double deltaV = 0.0;
+        public double inverseTotalDeltaV = 0.0;
+        public double isp = 0.0;
+        public double mass = 0.0;
+        public double rcsMass = 0.0;
+        public double maxThrustToWeight = 0.0;
         public int number = 0;
-        public double thrust = 0f;
-        public double thrustToWeight = 0f;
-        public double time = 0f;
-        public double totalCost = 0;
-        public double totalDeltaV = 0f;
-        public double totalMass = 0f;
-        public double totalTime = 0f;
+        public double thrust = 0.0;
+        public double thrustToWeight = 0.0;
+        public double time = 0.0;
+        public double totalCost = 0.0;
+        public double totalDeltaV = 0.0;
+        public double totalMass = 0.0;
+        public double totalTime = 0.0;
         public int totalPartCount = 0;
         public int partCount = 0;
         public double resourceMass = 0.0;
-        public double maxThrustTorque = 0f;
-        public double thrustOffsetAngle = 0f;
+        public double maxThrustTorque = 0.0;
+        public double thrustOffsetAngle = 0.0;
 
         public void Dump()
         {

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ
--- a/Output/KerbalEngineer/KerbalEngineer.version
+++ b/Output/KerbalEngineer/KerbalEngineer.version
@@ -5,8 +5,8 @@
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":13,
-		"BUILD":1
+		"PATCH":15,
+		"BUILD":2
 	},
 	"KSP_VERSION":
 	{

 Binary files /dev/null and b/Output/KerbalEngineer/Parts/Engineer7500/model000.mbm differ
--- a/Output/KerbalEngineer/Parts/Engineer7500/part.cfg
+++ b/Output/KerbalEngineer/Parts/Engineer7500/part.cfg
@@ -7,7 +7,6 @@
 	
 	// --- asset parameters ---
 	mesh = model.mu
-	texture = model000.mbm
 	rescaleFactor = 0.8
 
 	PhysicsSignificance = 1

 Binary files a/Output/KerbalEngineer/Parts/Engineer7500/textures/model000.mbm and /dev/null differ