// 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(List<Part> parts, double theGravity, double theAtmosphere = 0, double theVelocity = 0, bool dumpTree = false, bool vectoredThrust = false)
{
LogMsg log = null;
if (SimManager.logOutput)
{
log = new LogMsg();
log.buf.AppendLine("PrepareSimulation started");
dumpTree = true;
}
_timer.Start();
// Store the parameters in members for ease of access in other functions
partList = parts;
gravity = theGravity;
atmosphere = theAtmosphere;
velocity = theVelocity;
lastStage = Staging.lastStage;
//MonoBehaviour.print("lastStage = " + lastStage);
// Create the lists for our simulation parts
allParts = new List<PartSim>();
allFuelLines = new List<PartSim>();
drainingParts = new HashSet<PartSim>();
allEngines = new List<EngineSim>();
activeEngines = new List<EngineSim>();
drainingResources = new HashSet<int>();
// A dictionary for fast lookup of Part->PartSim during the preparation phase
Dictionary<Part, PartSim> partSimLookup = new Dictionary<Part, PartSim>();
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;
foreach (Part part in partList)
{
// 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.buf.AppendLine("Part " + part.name + " appears in vessel list more than once");
continue;
}
// Create the PartSim
PartSim partSim = new PartSim(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, velocity, vectoredThrust, log);
partId++;
}
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
foreach (PartSim partSim in allParts)
{
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)
{
foreach (PartSim partSim in allFuelLines)
{
if ((partSim.part as FuelLine).target != null)
{
PartSim targetSim;
if (partSimLookup.TryGetValue((partSim.part as FuelLine).target, out targetSim))
{
if (log != null)
log.buf.AppendLine("Fuel line target is " + targetSim.name + ":" + targetSim.partId);
targetSim.fuelTargets.Add(partSim.parent);
}
else
{
if (log != null)
log.buf.AppendLine("No PartSim for fuel line target (" + partSim.part.partInfo.name + ")");
}
}
else
{
if (log != null)
log.buf.AppendLine("Fuel line target is null");
}
}
}
//MonoBehaviour.print("SetupAttachNodes and count stages");
foreach (PartSim partSim in allParts)
{
partSim.SetupAttachNodes(partSimLookup, log);
if (partSim.decoupledInStage >= lastStage)
lastStage = partSim.decoupledInStage + 1;
}
// And finally release the Part references from all the PartSims
//MonoBehaviour.print("ReleaseParts");
foreach (PartSim partSim in allParts)
partSim.ReleasePart();
// And dereference the core's part list
partList = null;
_timer.Stop();
if (log != null)
{
log.buf.AppendLine("PrepareSimulation: " + _timer.ElapsedMilliseconds + "ms");
log.Flush();
}
if (dumpTree)
Dump();
return true;
}