Moved no physics mass moving into SetupAttachNodes where all parent links have been setup so that the whole parent chain can be followed to move the mass to the correct part
Moved no physics mass moving into SetupAttachNodes where all parent links have been setup so that the whole parent chain can be followed to move the mass to the correct part

--- a/KerbalEngineer/Flight/Readouts/Orbital/Eccentricity.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/Eccentricity.cs
@@ -43,7 +43,7 @@
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F3"), section.IsHud);
+            this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F5"), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -108,9 +108,7 @@
             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;
@@ -126,18 +124,19 @@
             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.isNoPhysics = partSim.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
                                partSim.part.PhysicsSignificance == 1;
 
-            if (!partSim.isNoPhysics)
+            if (partSim.part.HasModule<LaunchClamp>())
+            {
+                if (log != null)
+                  log.buf.AppendLine("Ignoring mass of launch clamp");
+            }
+            else
             {
                 partSim.baseMass = partSim.part.mass;
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print((partSim.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + partSim.part.mass);
+                if (log != null)
+                    log.buf.AppendLine("Using part.mass of " + partSim.part.mass);
             }
 
             for (int i = 0; i < partSim.part.Resources.Count; i++)
@@ -148,17 +147,16 @@
                 // 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);
-                    }
+                    if (log != null)
+                        log.buf.AppendLine(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.");
+                    if (log != null)
+                        log.buf.AppendLine(resource.resourceName + " is NaN. Skipping.");
                 }
             }
 
@@ -179,10 +177,9 @@
 
             partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEnginesFX || partSim.hasModuleEngines;
 
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
-            }
+            if (log != null)
+                log.buf.AppendLine("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
+
             return partSim;
         }
 
@@ -360,8 +357,9 @@
 
             buffer.AppendFormat(", isSep = {0}", isSepratron);
 
-            foreach (int type in resources.Types)
-            {
+            for (int i = 0; i < resources.Types.Count; i++)
+            {
+                int type = resources.Types[i];
                 buffer.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), resources[type]);
             }
 
@@ -384,8 +382,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);
@@ -456,7 +455,7 @@
 
             // 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");
+            //MonoBehaviour.print("for each fuel line");
 
             int lastCount = allSources.Count;
 
@@ -499,7 +498,7 @@
             if (fuelCrossFeed)
             {
                 lastCount = allSources.Count;
-                //MonoBehaviour.print("foreach attach node");
+                //MonoBehaviour.print("for each attach node");
                 for (int i = 0; i < this.attachNodes.Count; i++)
                 {
                     AttachNodeSim attachSim = this.attachNodes[i];
@@ -609,6 +608,17 @@
                     attachSim.attachedPartSim = null;
                 }
             }
+
+            // Loop through the fuel targets (fuel line sources)
+            for (int i = 0; i < this.fuelTargets.Count; i++)
+            {
+                PartSim fuelTargetSim = this.fuelTargets[i];
+                // If the part is in the set then "remove" it by clearing the PartSim reference
+                if (fuelTargetSim != null && partSims.Contains(fuelTargetSim))
+                {
+                    this.fuelTargets[i] = null;
+                }
+            }
         }
 
         public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
@@ -676,6 +686,23 @@
                     }
                 }
             }
+
+            if (isNoPhysics)
+            {
+                if (log != null)
+                    log.buf.AppendLine("Moving NoPhysics part mass of " + this.baseMass + " to parent part");
+
+                // Go up the parent chain until we find a part that is physically significant or we reach the root
+                PartSim MassParent = parent;
+                while (MassParent.isNoPhysics && (MassParent.parent != null))
+                    MassParent = MassParent.parent;
+
+                // Apply this part's mass to the part we have found
+                MassParent.baseMass += this.baseMass;
+
+                // And zero out this part's mass
+                this.baseMass = 0;
+            }
         }
 
         public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
@@ -686,16 +713,12 @@
                 if (partSimLookup.TryGetValue(part.parent, out parent))
                 {
                     if (log != null)
-                    {
                         log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
-                    }
                 }
                 else
                 {
                     if (log != null)
-                    {
                         log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
-                    }
                 }
             }
         }