Added "Atmo" button to compact build engineer
Added "Atmo" button to compact build engineer
Removed title addition and doesn't show sliders

--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,3 +1,6 @@
+1.0.16.6, 02-05-15
+    Fixed: Separately staged fairing mass jettisons are now calculated in the editor.
+
 1.0.16.5, 02-05-2015
     Fixed: Delta-V not being correctly calculated.
     Changed: Editor locking now uses the InputLockManager.

--- a/KerbalEngineer/Editor/BuildAdvanced.cs
+++ b/KerbalEngineer/Editor/BuildAdvanced.cs
@@ -215,7 +215,7 @@
                 }
 
                 // Change the window title based on whether in compact mode or not.
-                title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion + (showAtmosphericDetails ? " (ATMOS.)" : String.Empty);
+                title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion;
 
                 // Reset the window size when the staging or something else has changed.
                 stagesLength = stages.Length;
@@ -354,7 +354,7 @@
                 GUILayout.Space(5.0f);
 
                 GUILayout.BeginVertical();
-                GUILayout.Label("Mach: " + atmosphericMach.ToString("F1"), settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
+                GUILayout.Label("Mach: " + atmosphericMach.ToString("F2"), settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
                 GUI.skin = HighLogic.Skin;
                 atmosphericMach = GUILayout.HorizontalSlider(Mathf.Clamp(atmosphericMach, 0.0f, maxMach), 0.0f, maxMach);
                 GUI.skin = null;
@@ -823,6 +823,14 @@
                     bodiesListPosition = new Rect(position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f);
                     bodiesList.enabled = GUI.Toggle(bodiesListPosition, bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), buttonStyle);
                     bodiesList.SetPosition(bodiesListPosition.Translate(position));
+                }
+                else
+                {
+                    if (GUI.Toggle(new Rect(position.width - 133.0f * GuiDisplaySize.Offset, 5.0f, 60.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMO", buttonStyle) != showAtmosphericDetails)
+                    {
+                        hasChanged = true;
+                        showAtmosphericDetails = !showAtmosphericDetails;
+                    }
                 }
 
                 // Draw the main informational display box.
@@ -841,7 +849,7 @@
                     DrawBurnTime();
                     GUILayout.EndHorizontal();
 
-                    if (showAtmosphericDetails)
+                    if (showAtmosphericDetails && !compactMode)
                     {
                         GUILayout.BeginVertical(areaSettingStyle);
                         DrawAtmosphericDetails();

--- a/KerbalEngineer/Editor/PartInfoItem.cs
+++ b/KerbalEngineer/Editor/PartInfoItem.cs
@@ -19,38 +19,69 @@
 
 namespace KerbalEngineer.Editor
 {
+    using System.Collections.Generic;
     using VesselSimulator;
 
-    public class PartInfoItem : Pool<PartInfoItem>
+    public class PartInfoItem
     {
+        private static readonly Pool<PartInfoItem> pool = new Pool<PartInfoItem>(Create, Reset);
+
         public string Name { get; set; }
 
         public string Value { get; set; }
 
+        private static PartInfoItem Create()
+        {
+            return new PartInfoItem();
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static void Release(List<PartInfoItem> objList)
+        {
+            for (int i = 0; i < objList.Count; ++i)
+            {
+                objList[i].Release();
+            }
+        }
+
+        private static void Reset(PartInfoItem obj)
+        {
+            obj.Name = string.Empty;
+            obj.Value = string.Empty;
+        }
+
         public static PartInfoItem Create(string name)
         {
-            return GetPoolObject().Initialise(name);
+            return New(name);
         }
 
         public static PartInfoItem Create(string name, string value)
         {
-            return GetPoolObject().Initialise(name, value);
+            return New(name, value);
         }
 
-        public PartInfoItem Initialise(string name)
+        public static PartInfoItem New(string name)
         {
-            Name = name;
-            Value = string.Empty;
+            PartInfoItem obj = pool.Borrow();
+            
+            obj.Name = name;
+            obj.Value = string.Empty;
 
-            return this;
+            return obj;
         }
 
-        public PartInfoItem Initialise(string name, string value)
+        public static PartInfoItem New(string name, string value)
         {
-            Name = name;
-            Value = value;
+            PartInfoItem obj = pool.Borrow();
 
-            return this;
+            obj.Name = name;
+            obj.Value = value;
+
+            return obj;
         }
     }
 }

--- 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.16.5";
+        public const string AssemblyVersion = "1.0.16.6";
 
         #endregion
 

--- a/KerbalEngineer/Extensions/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -25,9 +25,9 @@
 
     public static class PartExtensions
     {
-        private static Part cachePart;
-        private static PartModule cachePartModule;
-        private static PartResource cachePartResource;
+        //private static Part cachePart;
+        //private static PartModule cachePartModule;
+        //private static PartResource cachePartResource;
 
         /// <summary>
         ///     Gets whether the part contains a specific resource.
@@ -57,7 +57,7 @@
         /// </summary>
         public static bool EngineHasFuel(this Part part)
         {
-            cachePartModule = GetModule<ModuleEngines>(part);
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
             if (cachePartModule != null)
             {
                 return (cachePartModule as ModuleEngines).getFlameoutState;
@@ -89,11 +89,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>
@@ -109,7 +125,7 @@
         /// </summary>
         public static double GetMaxThrust(this Part part)
         {
-            cachePartModule = GetModule<ModuleEngines>(part);
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
             if (cachePartModule != null)
             {
                 return (cachePartModule as ModuleEngines).maxThrust;
@@ -129,14 +145,11 @@
         /// </summary>
         public static T GetModule<T>(this Part part) where T : PartModule
         {
-            PartModule partModule;
-            for (int i = 0; i < part.Modules.Count; ++i)
-            {
-                partModule = part.Modules[i];
-                if (partModule is T)
-                {
-                    return partModule as T;
-                }
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is T)
+                    return (T)pm;
             }
             return null;
         }
@@ -252,7 +265,7 @@
 
         public static ProtoModuleDecoupler GetProtoModuleDecoupler(this Part part)
         {
-            cachePartModule = GetModule<ModuleDecouple>(part);
+            PartModule cachePartModule = GetModule<ModuleDecouple>(part);
             if (cachePartModule == null)
             {
                 cachePartModule = GetModule<ModuleAnchoredDecoupler>(part);
@@ -270,7 +283,7 @@
         /// </summary>
         public static ProtoModuleEngine GetProtoModuleEngine(this Part part)
         {
-            cachePartModule = GetModule<ModuleEngines>(part);
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
             if (cachePartModule != null)
             {
                 return new ProtoModuleEngine(cachePartModule);
@@ -293,7 +306,7 @@
             double cost = 0.0;
             for (int i = 0; i < part.Resources.list.Count; ++i)
             {
-                cachePartResource = part.Resources.list[i];
+                PartResource cachePartResource = part.Resources.list[i];
                 cost = cost + (cachePartResource.amount * cachePartResource.info.unitCost);
             }
             return cost;
@@ -303,36 +316,36 @@
         ///     Gets the cost of the part's contained resources, inverted.
         /// </summary>
         public static double GetResourceCostInverted(this Part part)
+        {
+            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>
+        ///     Gets the cost of the part's maximum contained resources.
+        /// </summary>
+        public static double GetResourceCostMax(this Part part)
         {
             double cost = 0.0;
             for (int i = 0; i < part.Resources.list.Count; ++i)
             {
-                cachePartResource = part.Resources.list[i];
-                cost = cost + ((cachePartResource.maxAmount - cachePartResource.amount) * cachePartResource.info.unitCost);
+                PartResource cachePartResource = part.Resources.list[i];
+                cost = cost + (cachePartResource.maxAmount * cachePartResource.info.unitCost);
             }
             return cost;
         }
 
         /// <summary>
-        ///     Gets the cost of the part's maximum contained resources.
-        /// </summary>
-        public static double GetResourceCostMax(this Part part)
-        {
-            double cost = 0.0;
-            for (int i = 0; i < part.Resources.list.Count; ++i)
-            {
-                cachePartResource = part.Resources.list[i];
-                cost = cost + (cachePartResource.maxAmount * cachePartResource.info.unitCost);
-            }
-            return cost;
-        }
-
-        /// <summary>
         ///     Gets the current specific impulse for the engine.
         /// </summary>
         public static double GetSpecificImpulse(this Part part, float atmosphere)
         {
-            cachePartModule = GetModule<ModuleEngines>(part);
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
             if (cachePartModule != null)
             {
                 return (cachePartModule as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
@@ -360,12 +373,10 @@
         /// </summary>
         public static bool HasModule<T>(this Part part) where T : PartModule
         {
-            for (int i = 0; i < part.Modules.Count; ++i)
+            for (int i = 0; i < part.Modules.Count; i++)
             {
                 if (part.Modules[i] is T)
-                {
                     return true;
-                }
             }
             return false;
         }
@@ -375,13 +386,11 @@
         /// </summary>
         public static bool HasModule<T>(this Part part, Func<T, bool> predicate) where T : PartModule
         {
-            for (int i = 0; i < part.Modules.Count; ++i)
-            {
-                cachePartModule = part.Modules[i] as T;
-                if (cachePartModule != null && predicate(cachePartModule as T))
-                {
+            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;
         }
@@ -407,7 +416,7 @@
         /// </summary>
         public static bool HasOneShotAnimation(this Part part)
         {
-            cachePartModule = GetModule<ModuleAnimateGeneric>(part);
+            PartModule cachePartModule = GetModule<ModuleAnimateGeneric>(part);
             return cachePartModule != null && (cachePartModule as ModuleAnimateGeneric).isOneShot;
         }
 
@@ -488,15 +497,14 @@
         /// </summary>
         public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)
         {
-            for (int i = 0; i < partsList.Count; ++i)
-            {
-                cachePart = partsList[i];
-
-                if (HasModule(cachePart, module.ClassID) == false)
+            for (int i = 0; i < partsList.Count; i++)
+            {
+                var vesselPart = partsList[i];
+                if (!vesselPart.HasModule(module.ClassID))
                 {
                     continue;
                 }
-                if (cachePart == part)
+                if (vesselPart == part)
                 {
                     return true;
                 }
@@ -532,7 +540,7 @@
         /// </summary>
         public static bool IsSolidRocket(this Part part)
         {
-            return (HasModule<ModuleEngines>(part) && GetModuleEngines(part).throttleLocked) || (HasModule<ModuleEnginesFX>(part) && GetModuleEnginesFx(part).throttleLocked);
+            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked) || (part.HasModule<ModuleEnginesFX>() && part.GetModuleEnginesFx().throttleLocked);
         }
 
         public class ProtoModuleDecoupler

--- a/KerbalEngineer/Flight/Readouts/Vessel/PartCount.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/PartCount.cs
@@ -46,7 +46,7 @@
         {
             if (SimulationProcessor.ShowDetails)
             {
-                this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount), section.IsHud);
+                this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount, 0), section.IsHud);
             }
         }
 

--- 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;

--- a/KerbalEngineer/Helpers/Pool.cs
+++ b/KerbalEngineer/Helpers/Pool.cs
@@ -1,61 +1,53 @@
-namespace KerbalEngineer.VesselSimulator
+using System.Collections.Generic;
+
+namespace KerbalEngineer
 {
-    using System.Collections.Generic;
+    /// <summary>
+    ///     Pool of object
+    /// </summary>
+    public class Pool<T> {
+        
+        private readonly Stack<T> values = new Stack<T>();
 
-    public class Pool<T> where T : new()
-    {
-        private static List<T> available = new List<T>();
-        private static List<T> inUse = new List<T>();
+        private readonly CreateDelegate<T> create;
+        private readonly ResetDelegate<T> reset;
 
-        public static int PoolCount
-        {
-            get
-            {
-                return available.Count + inUse.Count;
+        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();
             }
         }
-
-        public static T GetPoolObject()
-        {
-            T obj;
-            if (available.Count > 0)
-            {
-                obj = available[0];
-                available.RemoveAt(0);
-            }
-            else
-            {
-                obj = new T();
-            }
-
-            inUse.Add(obj);
-            return obj;
-        }
-
-        public static void Release(T obj)
-        {
-            if (inUse.Contains(obj))
-            {
-                inUse.Remove(obj);
-                available.Add(obj);
+        
+        /// <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);
             }
         }
-
-        public static void Release(List<T> objList)
+        
+        /// <summary>
+        ///     Current size of the pool.
+        /// </summary>
+        public int Count()
         {
-            for (int i = 0; i < objList.Count; ++i)
-            {
-                Release(objList[i]);
-            }
-        }
-
-        public static void ReleaseAll()
-        {
-            for (int i = 0; i < inUse.Count; ++i)
-            {
-                available.Add(inUse[i]);
-            }
-            inUse.Clear();
+            return values.Count;
         }
     }
 }

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -208,7 +208,7 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
+      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
       <Private>False</Private>
     </Reference>
     <Reference Include="System">
@@ -220,10 +220,11 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
+      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll</HintPath>
       <Private>False</Private>
     </Reference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="PostBuildMacros">
     <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">

--- a/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
+++ b/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
@@ -26,11 +26,38 @@
     using System;
     using System.Text;
 
-    internal class AttachNodeSim : Pool<AttachNodeSim>
+    internal class AttachNodeSim
     {
+
+        private static readonly Pool<AttachNodeSim> pool = new Pool<AttachNodeSim>(Create, Reset);
+
         public PartSim attachedPartSim;
         public String id;
         public AttachNode.NodeType nodeType;
+
+        private static AttachNodeSim Create()
+        {
+            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)
         {
@@ -49,14 +76,5 @@
             buffer.Append(":");
             buffer.Append(id);
         }
-
-        public AttachNodeSim Initialise(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
-        {
-            attachedPartSim = partSim;
-            nodeType = newNodeType;
-            id = newId;
-
-            return this;
-        }
     }
 }

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -26,80 +26,111 @@
     using Helpers;
     using UnityEngine;
 
-    public class EngineSim : Pool<EngineSim>
+    public class EngineSim
     {
-        public double actualThrust = 0.0;
-        public List<AppliedForce> appliedForces = new List<AppliedForce>();
+        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 = new List<AppliedForce>();
         public float maxMach;
 
         public double thrust = 0;
 
         // Add thrust vector to account for directional losses
         public Vector3 thrustVec;
-        private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
-
-        public EngineSim Initialise(PartSim theEngine,
-            double atmosphere,
-            float machNumber,
-            float maxFuelFlow,
-            float minFuelFlow,
-            float thrustPercentage,
-            Vector3 vecThrust,
-            FloatCurve atmosphereCurve,
-            bool atmChangeFlow,
-            FloatCurve atmCurve,
-            FloatCurve velCurve,
-            float currentThrottle,
-            bool throttleLocked,
-            List<Propellant> propellants,
-            bool active,
-            float resultingThrust,
-            List<Transform> thrustTransforms)
-        {
+
+        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;
+            engineSim.maxMach = 0f;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static EngineSim New(PartSim theEngine,
+                         double atmosphere,
+                         float machNumber,
+                         float maxFuelFlow,
+                         float minFuelFlow,
+                         float thrustPercentage,
+                         Vector3 vecThrust,
+                         FloatCurve atmosphereCurve,
+                         bool atmChangeFlow,
+                         FloatCurve atmCurve,
+                         FloatCurve velCurve,
+                         float currentThrottle,
+                         float IspG,
+                         bool throttleLocked,
+                         List<Propellant> propellants,
+                         bool active,
+                         float resultingThrust,
+                         List<Transform> thrustTransforms)
+        {
+            EngineSim engineSim = pool.Borrow();
+
             StringBuilder buffer = null;
 
-            isp = 0.0;
-            maxMach = 0.0f;
-            actualThrust = 0.0;
-            partSim = theEngine;
-            isActive = active;
-            thrustVec = vecThrust;
-            resourceConsumptions.Reset();
-            appliedForces.Clear();
+            engineSim.isp = 0.0;
+            engineSim.maxMach = 0.0f;
+            engineSim.actualThrust = 0.0;
+            engineSim.partSim = theEngine;
+            engineSim.isActive = active;
+            engineSim.thrustVec = vecThrust;
+            engineSim.resourceConsumptions.Reset();
+            engineSim.appliedForces.Clear();
 
             double flowRate = 0.0;
-            if (partSim.hasVessel)
-            {
-                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, partSim.part.atmDensity, velCurve, machNumber, ref maxMach);
-                isp = atmosphereCurve.Evaluate((float)atmosphere);
-                thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, isp);
-                actualThrust = isActive ? resultingThrust : 0.0;
+            if (engineSim.partSim.hasVessel)
+            {
+                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach);
+                engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
+                engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
+                engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0;
 
                 if (throttleLocked)
                 {
-                    flowRate = GetFlowRate(thrust, isp);
+                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                 }
                 else
                 {
-                    if (currentThrottle > 0.0f && partSim.isLanded == false)
+                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                     {
-                        flowRate = GetFlowRate(actualThrust, isp);
+                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                     }
                     else
                     {
-                        flowRate = GetFlowRate(thrust, isp);
+                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                     }
                 }
             }
             else
             {
-                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, CelestialBodies.SelectedBody.GetDensity(BuildAdvanced.Altitude), velCurve, machNumber, ref maxMach);
-                isp = atmosphereCurve.Evaluate((float)atmosphere);
-                thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, isp);
-                flowRate = GetFlowRate(thrust, isp);
+                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, CelestialBodies.SelectedBody.GetDensity(BuildAdvanced.Altitude), velCurve, machNumber, ref engineSim.maxMach);
+                engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
+                engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
+                flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
             }
 
             if (SimManager.logOutput)
@@ -108,6 +139,10 @@
                 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;
             for (int i = 0; i < propellants.Count; ++i)
             {
@@ -132,9 +167,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);
-                }
-                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)
@@ -142,17 +182,18 @@
                 MonoBehaviour.print(buffer);
             }
 
-            appliedForces.Clear();
-            double thrustPerThrustTransform = thrust / thrustTransforms.Count;
-            for (int i = 0; i < thrustTransforms.Count; ++i)
+            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));
-            }
-
-            return this;
+
+                AppliedForce appliedForce = AppliedForce.New(direction * thrustPerThrustTransform, position);
+                engineSim.appliedForces.Add(appliedForce);
+            }
+
+            return engineSim;
         }
 
         public ResourceContainer ResourceConsumptions
@@ -217,53 +258,67 @@
             buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", thrust, actualThrust, isp);
         }
 
+        // 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>>();
-
-            for (int i = 0; i < resourceConsumptions.Types.Count; ++i)
-            {
-                int type = resourceConsumptions.Types[i];
-
-                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 (partSim.resources[type] > SimManager.RESOURCE_MIN && partSim.resourceFlowStates[type] != 0)
                         {
-                            sourcePartSet = new HashSet<PartSim>();
+                            //sourcePartSet = new HashSet<PartSim>();
                             //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
                             sourcePartSet.Add(partSim);
                         }
                         break;
 
                     case ResourceFlowMode.ALL_VESSEL:
-                        for (int j = 0; j < allParts.Count; ++j)
-                        {
-                            PartSim aPartSim = allParts[j];
+                        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:
-                        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
-                        int maxStage = -1;
+
+                        foreach (HashSet<PartSim> stagePartSet in stagePartSets.Values)
+                        {
+                            stagePartSet.Clear();
+                        }
+                        var maxStage = -1;
 
                         //Logger.Log(type);
-                        for (int j = 0; j < allParts.Count; ++j)
-                        {
-                            PartSim aPartSim = allParts[j];
+                        for (int i = 0; i < allParts.Count; i++)
+                        {
+                            var aPartSim = allParts[i];
                             if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0)
                             {
                                 continue;
@@ -294,14 +349,14 @@
                         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 " + partSim.name + ":" + partSim.partId);
                         }
-                        sourcePartSet = partSim.GetSourceSet(type, allParts, visited, log, "");
+                        partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, "");
                         if (SimManager.logOutput)
                         {
                             MonoBehaviour.print(log.buf);
@@ -313,7 +368,8 @@
                         break;
                 }
 
-                if (sourcePartSet != null && sourcePartSet.Count > 0)
+
+                if (sourcePartSet.Count > 0)
                 {
                     sourcePartSets[type] = sourcePartSet;
                     if (SimManager.logOutput)
@@ -328,13 +384,13 @@
                     }
                 }
             }
-
+            
             // If we don't have sources for all the needed resources then return false without setting up any drains
-            for (int i = 0; i < resourceConsumptions.Types.Count; ++i)
-            {
-                int type = resourceConsumptions.Types[i];
-
-                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)
                     {
@@ -345,12 +401,10 @@
                     return false;
                 }
             }
-
             // Now we set the drains on the members of the sets and update the draining parts set
-            for (int i = 0; i < resourceConsumptions.Types.Count; ++i)
-            {
-                int type = resourceConsumptions.Types[i];
-
+            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 = resourceConsumptions[type] / sourcePartSet.Count;
@@ -358,14 +412,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
@@ -17,9 +17,6 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-#endregion
 
 namespace KerbalEngineer.VesselSimulator
 {
@@ -31,8 +28,12 @@
     using Extensions;
     using UnityEngine;
 
-    public class PartSim : Pool<PartSim>
+    public class PartSim
     {
+        private static readonly Pool<PartSim> pool = new Pool<PartSim>(Create, Reset);
+
+        private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
+
         public double baseMass;
         public Vector3d centerOfMass;
         public double cost;
@@ -53,7 +54,10 @@
         public bool isLanded;
         public bool isNoPhysics;
         public bool isSepratron;
+        public bool isFairing;
         public bool localCorrectThrust;
+        public float moduleMass;
+        public int stageIndex;
         public String name;
         public String noCrossFeedNodeKey;
         public PartSim parent;
@@ -66,7 +70,121 @@
         public double startMass = 0d;
         public String vesselName;
         public VesselType vesselType;
-        private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
+        
+
+        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 " + 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);
+
+            partSim.cost = partSim.part.GetCostWet();
+
+            // Work out if the part should have no physical significance
+            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((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))
+                {
+                    if (SimManager.logOutput)
+                    {
+                        MonoBehaviour.print(resource.resourceName + " = " + resource.amount);
+                    }
+
+                    partSim.resources.Add(resource.info.id, resource.amount);
+                    partSim.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
+                }
+                else
+                {
+                    MonoBehaviour.print(resource.resourceName + " is NaN. Skipping.");
+                }
+            }
+
+            partSim.startMass = partSim.GetMass(-1);
+
+            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 " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
+            }
+            return partSim;
+        }
 
         public ResourceContainer ResourceDrains
         {
@@ -89,10 +207,10 @@
             bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(part);
             if (log != null)
             {
-                log.buf.AppendLine("CreateEngineSims for " + name);
-
-                foreach (PartModule partMod in part.Modules)
-                {
+                log.buf.AppendLine("CreateEngineSims for " + this.name);
+                for (int i = 0; i < this.part.Modules.Count; i++)
+                {
+                    PartModule partMod = this.part.Modules[i];
                     log.buf.AppendLine("Module: " + partMod.moduleName);
                 }
 
@@ -106,11 +224,9 @@
                 string mode = part.GetModule<MultiModeEngine>().mode;
 
                 List<ModuleEnginesFX> engines = part.GetModules<ModuleEnginesFX>();
-
                 for (int i = 0; i < engines.Count; ++i)
                 {
                     ModuleEnginesFX engine = engines[i];
-
                     if (engine.engineID == mode)
                     {
                         if (log != null)
@@ -118,9 +234,10 @@
                             log.buf.AppendLine("Module: " + engine.moduleName);
                         }
 
-                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = EngineSim.GetPoolObject().Initialise(this,
+                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
+
+                        EngineSim engineSim = EngineSim.New(
+                            this,
                             atmosphere,
                             (float)mach,
                             engine.maxFuelFlow,
@@ -132,6 +249,7 @@
                             engine.useAtmCurve ? engine.atmCurve : null,
                             engine.useVelCurve ? engine.velCurve : null,
                             engine.currentThrottle,
+                            engine.g,
                             engine.throttleLocked || fullThrust,
                             engine.propellants,
                             engine.isOperational,
@@ -154,9 +272,10 @@
                             log.buf.AppendLine("Module: " + engine.moduleName);
                         }
 
-                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = EngineSim.GetPoolObject().Initialise(this,
+                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
+
+                        EngineSim engineSim = EngineSim.New(
+                            this,
                             atmosphere,
                             (float)mach,
                             engine.maxFuelFlow,
@@ -168,6 +287,7 @@
                             engine.useAtmCurve ? engine.atmCurve : null,
                             engine.useVelCurve ? engine.velCurve : null,
                             engine.currentThrottle,
+                            engine.g,
                             engine.throttleLocked || fullThrust,
                             engine.propellants,
                             engine.isOperational,
@@ -287,7 +407,7 @@
             return true;
         }
 
-        public double GetMass()
+        public double GetMass(int currentStage)
         {
             double mass = baseMass;
 
@@ -296,10 +416,23 @@
                 mass += resources.GetResourceMass(resources.Types[i]);
             }
 
+            if (hasVessel == false && isFairing && inverseStage < currentStage)
+            {
+                mass = mass + moduleMass;
+            }
+
             return mass;
         }
-
-        public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent)
+                
+        public void ReleasePart()
+        {
+            this.part = null;
+        }
+
+        // All functions below this point must not rely on the part member (it may be null)
+        //
+
+        public void GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, HashSet<PartSim> allSources, LogMsg log, String indent)
         {
             if (log != null)
             {
@@ -307,10 +440,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)
@@ -318,7 +448,7 @@
                     log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
                 }
 
-                return allSources;
+                return;
             }
 
             //if (log != null)
@@ -329,10 +459,12 @@
             // Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
             // 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");
-            for (int i = 0; i < fuelTargets.Count; ++i)
-            {
-                PartSim partSim = fuelTargets[i];
-
+
+            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)
@@ -343,24 +475,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 (" + name + ":" + 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
 
@@ -371,16 +499,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 (fuelCrossFeed)
             {
+                lastCount = allSources.Count;
                 //MonoBehaviour.print("foreach attach node");
-                for (int i = 0; i < attachNodes.Count; ++i)
-                {
-                    AttachNodeSim attachSim = attachNodes[i];
-
+                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 (!(noCrossFeedNodeKey != null && noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(noCrossFeedNodeKey)))
+                            if (
+                                !(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 &&
+                                  attachSim.id.Contains(this.noCrossFeedNodeKey)))
                             {
                                 if (visited.Contains(attachSim.attachedPartSim))
                                 {
@@ -392,26 +522,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 (" + name + ":" + partId + ")");
-                    }
-
-                    return allSources;
+                        log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
+                    }
+
+                    return;
                 }
             }
 
@@ -431,7 +556,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 
@@ -447,15 +572,16 @@
                     }
                     else
                     {
-                        allSources = 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 (" + name + ":" + partId + ")");
+                                log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
                             }
 
-                            return allSources;
+                            return;
                         }
                     }
                 }
@@ -465,7 +591,7 @@
             //if (log != null)
             //    log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
 
-            return allSources;
+            return;
         }
 
         public double GetStartMass()
@@ -473,112 +599,12 @@
             return startMass;
         }
 
-        public PartSim Initialise(Part thePart, int id, double atmosphere, LogMsg log)
-        {
-            Reset(this);
-
-            part = thePart;
-            centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
-            partId = id;
-            name = part.partInfo.name;
-
-            if (log != null)
-            {
-                log.buf.AppendLine("Create PartSim for " + name);
-            }
-
-            parent = null;
-            parentAttach = part.attachMode;
-            fuelCrossFeed = part.fuelCrossFeed;
-            noCrossFeedNodeKey = part.NoCrossFeedNodeKey;
-            decoupledInStage = DecoupledInStage(part);
-            isFuelLine = part.HasModule<CModuleFuelLine>();
-            isFuelTank = part is FuelTank;
-            isSepratron = IsSepratron();
-            inverseStage = part.inverseStage;
-            //MonoBehaviour.print("inverseStage = " + inverseStage);
-
-            cost = part.GetCostWet();
-
-            // Work out if the part should have no physical significance
-            isNoPhysics = part.HasModule<LaunchClamp>();
-
-            if (isNoPhysics == false)
-            {
-                if (part.vessel != null)
-                {
-                    baseMass = part.mass;
-                }
-                else
-                {
-                    baseMass = part.mass + part.GetModuleMass(part.mass);
-                }
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print((isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + part.mass);
-            }
-
-            for (int i = 0; i < part.Resources.Count; ++i)
-            {
-                PartResource resource = 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))
-                {
-                    if (SimManager.logOutput)
-                    {
-                        MonoBehaviour.print(resource.resourceName + " = " + resource.amount);
-                    }
-
-                    resources.Add(resource.info.id, resource.amount);
-                    resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
-                }
-                else
-                {
-                    MonoBehaviour.print(resource.resourceName + " is NaN. Skipping.");
-                }
-            }
-
-            startMass = GetMass();
-
-            hasVessel = (part.vessel != null);
-            isLanded = hasVessel && part.vessel.Landed;
-            if (hasVessel)
-            {
-                vesselName = part.vessel.vesselName;
-                vesselType = part.vesselType;
-            }
-            initialVesselName = part.initialVesselName;
-
-            hasMultiModeEngine = part.HasModule<MultiModeEngine>();
-            hasModuleEnginesFX = part.HasModule<ModuleEnginesFX>();
-            hasModuleEngines = part.HasModule<ModuleEngines>();
-
-            isEngine = hasMultiModeEngine || hasModuleEnginesFX || hasModuleEngines;
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Created " + name + ". Decoupled in stage " + decoupledInStage);
-            }
-
-            return this;
-        }
-
-        public void ReleasePart()
-        {
-            part = null;
-        }
-
         public void RemoveAttachedParts(HashSet<PartSim> partSims)
         {
             // Loop through the attached parts
-            for (int i = 0; i < attachNodes.Count; ++i)
-            {
-                AttachNodeSim attachSim = attachNodes[i];
-
+            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))
                 {
@@ -615,7 +641,7 @@
                             log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
                         }
 
-                        attachNodes.Add(AttachNodeSim.GetPoolObject().Initialise(attachedSim, attachNode.id, attachNode.nodeType));
+                        attachNodes.Add(AttachNodeSim.New(attachedSim, attachNode.id, attachNode.nodeType));
                     }
                     else
                     {
@@ -697,43 +723,6 @@
             return time;
         }
 
-        private static void Reset(PartSim partSim)
-        {
-            partSim.attachNodes.Clear();
-            partSim.fuelTargets.Clear();
-            partSim.resourceDrains.Reset();
-            partSim.resourceFlowStates.Reset();
-            partSim.resources.Reset();
-            partSim.baseMass = 0.0;
-            partSim.startMass = 0.0;
-            partSim.centerOfMass = Vector3d.zero;
-            partSim.cost = 0.0;
-            partSim.decoupledInStage = 0;
-            partSim.fuelCrossFeed = false;
-            partSim.hasModuleEngines = false;
-            partSim.hasModuleEnginesFX = false;
-            partSim.hasMultiModeEngine = false;
-            partSim.hasVessel = false;
-            partSim.initialVesselName = null;
-            partSim.inverseStage = 0;
-            partSim.isDecoupler = false;
-            partSim.isEngine = false;
-            partSim.isFuelLine = false;
-            partSim.isFuelTank = false;
-            partSim.isLanded = false;
-            partSim.isNoPhysics = false;
-            partSim.isSepratron = false;
-            partSim.localCorrectThrust = false;
-            partSim.name = null;
-            partSim.noCrossFeedNodeKey = null;
-            partSim.parent = null;
-            partSim.parentAttach = AttachModes.SRF_ATTACH;
-            partSim.part = null;
-            partSim.partId = 0;
-            partSim.vesselName = null;
-            partSim.vesselType = VesselType.Base;
-        }
-
         private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
         {
             if (thrustTransforms == null)
@@ -799,6 +788,11 @@
                    thePart.HasModule<ModuleAnchoredDecoupler>();
         }
 
+        private bool IsFairing(Part thePart)
+        {
+            return thePart.HasModule<ModuleProceduralFairing>();
+        }
+
         private bool IsSepratron()
         {
             if (!part.ActivatesEvenIfDisconnected)

--- 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.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/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -42,17 +42,17 @@
         private List<EngineSim> allEngines = new List<EngineSim>();
         private List<PartSim> allFuelLines = new List<PartSim>();
         private List<PartSim> allParts = new List<PartSim>();
-        private Dictionary<Part, PartSim> partSimLookup = new Dictionary<Part, PartSim>();
         private double atmosphere;
         private int currentStage;
         private double currentisp;
+        private HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
         private bool doingCurrent;
-        private List<PartSim> dontStageParts = new List<PartSim>();
-        List<List<PartSim>> dontStagePartsLists = new List<List<PartSim>>();
-        private HashSet<PartSim> drainingParts = new HashSet<PartSim>();
-        private HashSet<int> drainingResources = new HashSet<int>();
-        private HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
+        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 = new List<Part>();
@@ -75,9 +75,21 @@
         public String vesselName;
         public VesselType vesselType;
         private WeightedVectorAverager vectorAverager = new WeightedVectorAverager();
+        private static ModuleProceduralFairing moduleProceduralFairing;
 
         public Simulation()
         {
+            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
+            partSimLookup = new Dictionary<Part, PartSim>();
+
             if (SimManager.logOutput)
             {
                 MonoBehaviour.print("Simulation created");
@@ -91,7 +103,7 @@
                 double mass = 0d;
 
                 for (int i = 0; i < allParts.Count; ++i) { 
-                    mass += allParts[i].GetMass();
+                    mass += allParts[i].GetMass(currentStage);
                 }
 
                 return mass;
@@ -107,7 +119,7 @@
                 for (int i = 0; i < allParts.Count; ++i)
                 {
                     PartSim partSim = allParts[i];
-                    vectorAverager.Add(partSim.centerOfMass, partSim.GetMass());
+                    vectorAverager.Add(partSim.centerOfMass, partSim.GetMass(currentStage));
                 }
 
                 return vectorAverager.Get();
@@ -135,6 +147,7 @@
             this.atmosphere = theAtmosphere;
             this.mach = theMach;
             this.lastStage = Staging.lastStage;
+            this.maxMach = 1.0f;
             //MonoBehaviour.print("lastStage = " + lastStage);
 
             // Clear the lists for our simulation parts
@@ -145,10 +158,6 @@
             activeEngines.Clear();
             drainingResources.Clear();
 
-            PartSim.ReleaseAll();
-            EngineSim.ReleaseAll();
-            AttachNodeSim.ReleaseAll();
-
             // A dictionary for fast lookup of Part->PartSim during the preparation phase
             partSimLookup.Clear();
 
@@ -157,7 +166,7 @@
                 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;
             for (int i = 0; i < partList.Count; ++i)
@@ -175,7 +184,7 @@
                 }
 
                 // Create the PartSim
-                PartSim partSim = PartSim.GetPoolObject().Initialise(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);
@@ -201,8 +210,9 @@
 
             // 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);
             }
 
@@ -280,7 +290,7 @@
 
             return true;
         }
-
+        
         // This function runs the simulation and returns a newly created array of Stage objects
         public Stage[] RunSimulation()
         {
@@ -300,7 +310,6 @@
             // 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
@@ -372,7 +381,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)
@@ -445,6 +453,11 @@
                         stage.cost += partSim.cost;
                         stage.mass += partSim.GetStartMass();
                     }
+
+                    if (partSim.hasVessel == false && partSim.isFairing && partSim.inverseStage == currentStage)
+                    {
+                        stage.mass += partSim.moduleMass;
+                    }
                 }
 
                 this.dontStageParts = dontStagePartsLists[this.currentStage];
@@ -456,8 +469,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, "");
                         }
                     }
@@ -468,6 +482,7 @@
 
                     log.Flush();
                 }
+
 
                 // Now we will loop until we are allowed to stage
                 int loopCounter = 0;
@@ -475,7 +490,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;
@@ -493,7 +507,6 @@
                     {
                         MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")");
                     }
-
                     foreach (PartSim partSim in this.drainingParts)
                     {
                         partSim.DrainResources(resourceDrainTime);
@@ -525,7 +538,7 @@
 
                     // Recalculate the current thrust and isp for the next step
                     this.CalculateThrustAndISP();
-
+                    
                     // Check if we actually changed anything
                     if (this.stepStartMass == this.stepEndMass)
                     {
@@ -551,6 +564,7 @@
                     this.stepStartMass = this.stepEndMass;
                 }
 
+
                 // Store more values in the Stage object and stick it in the array
 
                 // Store the magnitude of the deltaV vector
@@ -631,8 +645,27 @@
                 this._timer.Stop();
                 MonoBehaviour.print("RunSimulation: " + this._timer.ElapsedMilliseconds + "ms");
             }
-
+            FreePooledObject();
+            
             return stages;
+        }
+
+        // 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)
@@ -663,7 +696,8 @@
                 {
                     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)
@@ -696,7 +730,6 @@
             for (int i = 0; i < allEngines.Count; ++i)
             {
                 EngineSim engine = allEngines[i];
-
                 if (engine.isActive)
                 {
                     this.activeEngines.Add(engine);
@@ -734,9 +767,7 @@
                     this.totalStageThrustForce.AddForce(engine.appliedForces[j]);
                 }
             }
-
             //MonoBehaviour.print("vecThrust = " + vecThrust.ToString() + "   magnitude = " + vecThrust.magnitude);
-
             this.totalStageThrust = this.vecThrust.magnitude;
             this.totalStageActualThrust = this.vecActualThrust.magnitude;
 
@@ -794,8 +825,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);
@@ -893,14 +925,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();
                         }
                     }
                 }
@@ -912,7 +947,8 @@
             }
 
             // Loop through all the (remaining) parts
-            for (int i = 0; i < allParts.Count; ++i) { 
+            for (int i = 0; i < allParts.Count; ++i)
+            { 
                 // Ask the part to remove all the parts that are decoupled
                 allParts[i].RemoveAttachedParts(decoupledParts);
             }
@@ -954,3 +990,4 @@
         }
     }
 }
+

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