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,8 +17,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#region Using Directives
-#endregion
namespace KerbalEngineer.VesselSimulator
{
@@ -30,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;
@@ -68,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
{
@@ -91,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);
}
@@ -108,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)
@@ -120,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,
@@ -134,6 +249,7 @@
engine.useAtmCurve ? engine.atmCurve : null,
engine.useVelCurve ? engine.velCurve : null,
engine.currentThrottle,
+ engine.g,
engine.throttleLocked || fullThrust,
engine.propellants,
engine.isOperational,
@@ -156,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,
@@ -170,6 +287,7 @@
engine.useAtmCurve ? engine.atmCurve : null,
engine.useVelCurve ? engine.velCurve : null,
engine.currentThrottle,
+ engine.g,
engine.throttleLocked || fullThrust,
engine.propellants,
engine.isOperational,
@@ -305,8 +423,16 @@
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)
{
@@ -314,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)
@@ -325,7 +448,7 @@
log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
}
- return allSources;
+ return;
}
//if (log != null)
@@ -336,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)
@@ -350,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
@@ -378,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))
{
@@ -399,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;
}
}
@@ -438,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
@@ -454,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;
}
}
}
@@ -472,7 +591,7 @@
//if (log != null)
// log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
- return allSources;
+ return;
}
public double GetStartMass()
@@ -480,105 +599,12 @@
return startMass;
}
- public PartSim Initialise(Part thePart, int id, double atmosphere, LogMsg log)
- {
- Reset(this);
-
- part = thePart;
- hasVessel = (part.vessel != null);
- 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();
- isFairing = IsFairing(part);
- inverseStage = part.inverseStage;
- stageIndex = part.inStageIndex;
- //MonoBehaviour.print("inverseStage = " + inverseStage);
-
- // Work out if the part should have no physical significance
- isNoPhysics = part.HasModule<LaunchClamp>();
- if (isNoPhysics == false)
- {
- baseMass = part.mass;
- if (hasVessel == false)
- {
- moduleMass = part.GetModuleMass(part.mass);
- }
- }
-
- cost = part.GetCostWet();
-
- 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.");
- }
- }
-
- 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;
-
- startMass = GetMass(-1);
-
- 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,46 +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.isFairing = 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;
- partSim.moduleMass = 0.0f;
- partSim.stageIndex = 0;
- }
-
private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
{
if (thrustTransforms == null)
--- 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>();
@@ -79,6 +79,17 @@
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");
@@ -136,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
@@ -146,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();
@@ -158,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)
@@ -176,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);
@@ -202,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);
}
@@ -281,7 +290,7 @@
return true;
}
-
+
// This function runs the simulation and returns a newly created array of Stage objects
public Stage[] RunSimulation()
{
@@ -301,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
@@ -461,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, "");
}
}
@@ -473,6 +482,7 @@
log.Flush();
}
+
// Now we will loop until we are allowed to stage
int loopCounter = 0;
@@ -480,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;
@@ -498,7 +507,6 @@
{
MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")");
}
-
foreach (PartSim partSim in this.drainingParts)
{
partSim.DrainResources(resourceDrainTime);
@@ -530,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)
{
@@ -556,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
@@ -636,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)
@@ -668,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)
@@ -701,7 +730,6 @@
for (int i = 0; i < allEngines.Count; ++i)
{
EngineSim engine = allEngines[i];
-
if (engine.isActive)
{
this.activeEngines.Add(engine);
@@ -739,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;
@@ -799,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);
@@ -898,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();
}
}
}
@@ -917,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);
}
@@ -959,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":
{