public static New ( Part p, int id, double atmosphere, LogMsg log ) : |
||
p | Part | |
id | int | |
atmosphere | double | |
log | LogMsg | |
return |
public static PartSim New(Part p, int id, double atmosphere, LogMsg log)
{
PartSim partSim = pool.Borrow();
partSim.part = p;
partSim.centerOfMass = p.transform.TransformPoint(p.CoMOffset);
partSim.partId = id;
partSim.name = p.partInfo.name;
if (log != null) log.AppendLine("Create PartSim for ", partSim.name);
partSim.parent = null;
partSim.parentAttach = p.attachMode;
partSim.fuelCrossFeed = p.fuelCrossFeed;
partSim.noCrossFeedNodeKey = p.NoCrossFeedNodeKey;
partSim.decoupledInStage = partSim.DecoupledInStage(p);
partSim.isFuelLine = p.HasModule<CModuleFuelLine>();
partSim.isSepratron = partSim.IsSepratron();
partSim.inverseStage = p.inverseStage;
if (log != null) log.AppendLine("inverseStage = ", partSim.inverseStage);
partSim.resPriorityOffset = p.resourcePriorityOffset;
partSim.resPriorityUseParentInverseStage = p.resourcePriorityUseParentInverseStage;
partSim.resRequestRemainingThreshold = p.resourceRequestRemainingThreshold;
partSim.baseCost = p.GetCostDry();
if (log != null) log.AppendLine("Parent part = ", (p.parent == null ? "null" : p.parent.partInfo.name))
.AppendLine("physicalSignificance = ", p.physicalSignificance)
.AppendLine("PhysicsSignificance = ", p.PhysicsSignificance);
// Work out if the part should have no physical significance
// The root part is never "no physics"
partSim.isNoPhysics = p.physicalSignificance == Part.PhysicalSignificance.NONE ||
p.PhysicsSignificance == 1;
if (p.HasModule<LaunchClamp>())
{
partSim.realMass = 0d;
if (log != null) log.AppendLine("Ignoring mass of launch clamp");
}
else
{
partSim.realMass = p.mass;
if (log != null) log.AppendLine("Using part.mass of ", p.mass);
}
partSim.postStageMassAdjust = 0f;
if (log != null) log.AppendLine("Calculating postStageMassAdjust, prefabMass = ", p.prefabMass);
int count = p.Modules.Count;
for (int i = 0; i < count; i++)
{
if (log != null) log.AppendLine("Module: ", p.Modules[i].moduleName);
IPartMassModifier partMassModifier = p.Modules[i] as IPartMassModifier;
if (partMassModifier != null)
{
if (log != null) log.AppendLine("ChangeWhen = ", partMassModifier.GetModuleMassChangeWhen());
if (partMassModifier.GetModuleMassChangeWhen() == ModifierChangeWhen.STAGED)
{
float preStage = partMassModifier.GetModuleMass(p.prefabMass, ModifierStagingSituation.UNSTAGED);
float postStage = partMassModifier.GetModuleMass(p.prefabMass, ModifierStagingSituation.STAGED);
if (log != null) log.AppendLine("preStage = ", preStage, " postStage = ", postStage);
partSim.postStageMassAdjust += (postStage - preStage);
}
}
}
if (log != null) log.AppendLine("postStageMassAdjust = ", partSim.postStageMassAdjust);
for (int i = 0; i < p.Resources.Count; i++)
{
PartResource resource = p.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 (log != null) log.AppendLine(resource.resourceName, " = ", resource.amount);
partSim.resources.Add(resource.info.id, resource.amount);
partSim.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
}
else
{
if (log != null) log.AppendLine(resource.resourceName, " is NaN. Skipping.");
}
}
partSim.hasVessel = (p.vessel != null);
partSim.isLanded = partSim.hasVessel && p.vessel.Landed;
if (partSim.hasVessel)
{
partSim.vesselName = p.vessel.vesselName;
partSim.vesselType = p.vesselType;
}
partSim.initialVesselName = p.initialVesselName;
partSim.hasMultiModeEngine = p.HasModule<MultiModeEngine>();
partSim.hasModuleEngines = p.HasModule<ModuleEngines>();
partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEngines;
if (log != null) log.AppendLine("Created ", partSim.name, ". Decoupled in stage ", partSim.decoupledInStage);
return partSim;
}
// This function prepares the simulation by creating all the necessary data structures it will // need during the simulation. All required data is copied from the core game data structures // so that the simulation itself can be run in a background thread without having issues with // the core game changing the data while the simulation is running. public bool PrepareSimulation(LogMsg _log, List <Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false) { log = _log; if (log != null) { log.AppendLine("PrepareSimulation started"); } _timer.Reset(); _timer.Start(); // Store the parameters in members for ease of access in other functions partList = parts; gravity = theGravity; atmosphere = theAtmosphere; mach = theMach; lastStage = StageManager.LastStage; maxMach = 1.0f; if (log != null) { log.AppendLine("lastStage = ", lastStage); } // Clear the lists for our simulation parts allParts.Clear(); allFuelLines.Clear(); drainingParts.Clear(); allEngines.Clear(); activeEngines.Clear(); drainingResources.Clear(); // A dictionary for fast lookup of Part->PartSim during the preparation phase partSimLookup.Clear(); if (partList.Count > 0 && partList[0].vessel != null) { vesselName = partList[0].vessel.vesselName; vesselType = partList[0].vessel.vesselType; } // First we create a PartSim for each Part (giving each a unique id) int partId = 1; for (int i = 0; i < partList.Count; ++i) { Part part = partList[i]; // If the part is already in the lookup dictionary then log it and skip to the next part if (partSimLookup.ContainsKey(part)) { if (log != null) { log.AppendLine("Part ", part.name, " appears in vessel list more than once"); } continue; } // Create the PartSim PartSim partSim = PartSim.New(part, partId, atmosphere, log); // Add it to the Part lookup dictionary and the necessary lists partSimLookup.Add(part, partSim); allParts.Add(partSim); if (partSim.isFuelLine) { allFuelLines.Add(partSim); } if (partSim.isEngine) { partSim.CreateEngineSims(allEngines, atmosphere, mach, vectoredThrust, fullThrust, log); } if (partSim.isRCS) { partSim.CreateRCSSims(allRCS, atmosphere, mach, vectoredThrust, fullThrust, log); } partId++; } for (int i = 0; i < allEngines.Count; ++i) { maxMach = Mathf.Max(maxMach, allEngines[i].maxMach); } UpdateActiveEngines(); // 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 for (int i = 0; i < allParts.Count; i++) { PartSim partSim = allParts[i]; partSim.SetupParent(partSimLookup, log); } // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets if (HighLogic.LoadedSceneIsEditor) { for (int i = 0; i < allFuelLines.Count; ++i) { PartSim partSim = allFuelLines[i]; CModuleFuelLine fuelLine = partSim.part.GetModule <CModuleFuelLine>(); if (fuelLine.target != null) { PartSim targetSim; if (partSimLookup.TryGetValue(fuelLine.target, out targetSim)) { if (log != null) { log.AppendLine("Fuel line target is ", targetSim.name, ":", targetSim.partId); } targetSim.fuelTargets.Add(partSim.parent); } else { if (log != null) { log.AppendLine("No PartSim for fuel line target (", partSim.part.partInfo.name, ")"); } } } else { if (log != null) { log.AppendLine("Fuel line target is null"); } } } } if (log != null) { log.AppendLine("SetupAttachNodes and count stages"); } for (int i = 0; i < allParts.Count; ++i) { PartSim partSim = allParts[i]; partSim.SetupAttachNodes(partSimLookup, log); if (partSim.decoupledInStage >= lastStage) { lastStage = partSim.decoupledInStage + 1; } } // And finally release the Part references from all the PartSims if (log != null) { log.AppendLine("ReleaseParts"); } for (int i = 0; i < allParts.Count; ++i) { allParts[i].ReleasePart(); } // And dereference the core's part list partList = null; _timer.Stop(); if (log != null) { log.AppendLine("PrepareSimulation: ", _timer.ElapsedMilliseconds, "ms"); log.Flush(); } Dump(); log = null; return(true); }