// 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 = PartExtensions.GetModule <CModuleFuelLine>(partSim.part);
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);
}