Пример #1
0
        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;
        }
Пример #2
0
 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.baseCost = 0d;
     partSim.baseMass = 0d;
     partSim.baseMassForCoM = 0d;
     partSim.startMass = 0d;
 }
Пример #3
0
 public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
 {
     if (part.parent != null)
     {
         parent = null;
         if (partSimLookup.TryGetValue(part.parent, out parent))
         {
             if (log != null) log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
             if (part.attachMode == AttachModes.SRF_ATTACH && part.attachRules.srfAttach && part.fuelCrossFeed && part.parent.fuelCrossFeed)
             {
                 if (log != null) log.buf.AppendLine("Added " + name + " to " + parent.name + " surface mounted fuel targets.");
                 parent.surfaceMountFuelTargets.Add(this);
             }
         }
         else
         {
             if (log != null) log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
         }
     }
 }
Пример #4
0
        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,
                        LogMsg log)
        {
            EngineSim engineSim = pool.Borrow();

            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.resourceFlowModes.Reset();
            engineSim.appliedForces.Clear();

            double flowRate = 0.0;
            if (engineSim.partSim.hasVessel)
            {
                if (log != null) log.buf.AppendLine("hasVessel is true");

                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 (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                }

                if (throttleLocked)
                {
                    if (log != null) log.buf.AppendLine("throttleLocked is true, using thrust for flowRate");
                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                }
                else
                {
                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                    {
                        if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                    }
                    else
                    {
                        if (log != null) log.buf.AppendLine("throttled down or landed, using thrust for flowRate");
                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                    }
                }
            }
            else
            {
                if (log != null) log.buf.AppendLine("hasVessel is false");
                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);
                engineSim.actualThrust = 0d;
                if (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                }

                if (log != null) log.buf.AppendLine("no vessel, using thrust for flowRate");
                flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
            }

            if (log != null) log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate);

            float flowMass = 0f;
            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];
                if (!propellant.ignoreForIsp)
                    flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
            }

            if (log != null) log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];

                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                {
                    continue;
                }

                double consumptionRate = propellant.ratio * flowRate / flowMass;
                if (log != null) log.buf.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);
                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());
            }

            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;

                AppliedForce appliedForce = AppliedForce.New(direction * thrustPerThrustTransform, position);
                engineSim.appliedForces.Add(appliedForce);
            }

            return engineSim;
        }
Пример #5
0
 public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
 {
     if (part.parent != null)
     {
         parent = null;
         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 + ")");
         }
     }
 }
Пример #6
0
        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,
                        LogMsg log)
        {
            EngineSim engineSim = pool.Borrow();

            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 (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(engineSim.thrust, engineSim.isp);
                }
                else
                {
                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                    {
                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                    }
                    else
                    {
                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                    }
                }
            }
            else
            {
                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, SimManager.Body.GetDensity(FlightGlobals.getStaticPressure(0, SimManager.Body), FlightGlobals.getExternalTemperature(0, SimManager.Body)), 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 (log != null) log.buf.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)
            {
                Propellant propellant = propellants[i];
                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
            }

            if (log != null) log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];

                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                {
                    continue;
                }

                double consumptionRate = propellant.ratio * flowRate / flowMass;
                if (log != null) log.buf.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);
            }

            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;

                AppliedForce appliedForce = AppliedForce.New(direction * thrustPerThrustTransform, position);
                engineSim.appliedForces.Add(appliedForce);
            }

            return engineSim;
        }
Пример #7
0
        // This function works out if it is time to stage
        private bool AllowedToStage()
        {
            StringBuilder buffer = null;

            if (SimManager.logOutput)
            {
                buffer = new StringBuilder(1024);
                buffer.AppendLine("AllowedToStage");
                buffer.AppendFormat("currentStage = {0:d}\n", this.currentStage);
            }

            if (this.activeEngines.Count > 0)
            {
                for (int i = 0; i < dontStageParts.Count; ++i)
                {
                    PartSim partSim = dontStageParts[i];

                    if (SimManager.logOutput)
                    {
                        partSim.DumpPartToBuffer(buffer, "Testing: ");
                    }
                    //buffer.AppendFormat("isSepratron = {0}\n", partSim.isSepratron ? "true" : "false");

                    if (!partSim.isSepratron && !partSim.EmptyOf(this.drainingResources))
                    {
                        if (SimManager.logOutput)
                        {
                            partSim.DumpPartToBuffer(buffer, "Decoupled part not empty => false: ");
                            MonoBehaviour.print(buffer);
                        }
                        return(false);
                    }

                    if (partSim.isEngine)
                    {
                        for (int j = 0; j < activeEngines.Count; ++j)
                        {
                            EngineSim engine = activeEngines[j];

                            if (engine.partSim == partSim)
                            {
                                if (SimManager.logOutput)
                                {
                                    partSim.DumpPartToBuffer(buffer, "Decoupled part is active engine => false: ");
                                    MonoBehaviour.print(buffer);
                                }
                                return(false);
                            }
                        }
                    }
                }
            }

            if (this.currentStage == 0 && this.doingCurrent)
            {
                if (SimManager.logOutput)
                {
                    buffer.AppendLine("Current stage == 0 && doingCurrent => false");
                    MonoBehaviour.print(buffer);
                }
                return(false);
            }

            if (SimManager.logOutput)
            {
                buffer.AppendLine("Returning true");
                MonoBehaviour.print(buffer);
            }
            return(true);
        }
Пример #8
0
        // This function runs the simulation and returns a newly created array of Stage objects
        public Stage[] RunSimulation()
        {
            if (SimManager.logOutput)
            {
                MonoBehaviour.print("RunSimulation started");
            }

            this._timer.Reset();
            this._timer.Start();

            LogMsg log = null;

            if (SimManager.logOutput)
            {
                log = new LogMsg();
            }

            // 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
            bool anyActive = false;

            for (int i = 0; i < allEngines.Count; ++i)
            {
                EngineSim engine = allEngines[i];

                if (log != null)
                {
                    log.buf.AppendLine("Testing engine mod of " + engine.partSim.name + ":" + engine.partSim.partId);
                }
                bool bActive = engine.isActive;
                bool bStage  = (engine.partSim.inverseStage >= this.currentStage);
                if (log != null)
                {
                    log.buf.AppendLine("bActive = " + bActive + "   bStage = " + bStage);
                }
                if (HighLogic.LoadedSceneIsFlight)
                {
                    if (bActive)
                    {
                        anyActive = true;
                    }
                    if (bActive != bStage)
                    {
                        // If the active state is different to the state due to staging
                        if (log != null)
                        {
                            log.buf.AppendLine("Need to do current active engines first");
                        }

                        this.doingCurrent = true;
                    }
                }
                else
                {
                    if (bStage)
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Marking as active");
                        }

                        engine.isActive = true;
                    }
                }
            }

            // If we need to do current because of difference in engine activation and there actually are active engines
            // then we do the extra stage otherwise activate the next stage and don't treat it as current
            if (this.doingCurrent && anyActive)
            {
                this.currentStage++;
            }
            else
            {
                this.ActivateStage();
                this.doingCurrent = false;
            }

            // Create a list of lists of PartSims that prevent decoupling
            BuildDontStageLists(log);

            if (log != null)
            {
                log.Flush();
            }

            // Create the array of stages that will be returned
            Stage[] stages = new Stage[this.currentStage + 1];

            int startStage = currentStage;

            // Loop through the stages
            while (this.currentStage >= 0)
            {
                if (log != null)
                {
                    log.buf.AppendLine("Simulating stage " + this.currentStage);
                    log.Flush();
                    this._timer.Reset();
                    this._timer.Start();
                }

                // Update active engines and resource drains
                this.UpdateResourceDrains();

                // Update the masses of the parts to correctly handle "no physics" parts
                this.stageStartMass = this.UpdatePartMasses();

                if (log != null)
                {
                    this.allParts[0].DumpPartToBuffer(log.buf, "", this.allParts);
                }

                // Create the Stage object for this stage
                Stage stage = new Stage();

                this.stageTime      = 0d;
                this.vecStageDeltaV = Vector3.zero;

                this.stageStartCom = this.ShipCom;

                this.stepStartMass = this.stageStartMass;
                this.stepEndMass   = 0;

                this.CalculateThrustAndISP();

                // Store various things in the Stage object
                stage.thrust = this.totalStageThrust;
                if (log != null)
                {
                    log.buf.AppendLine("stage.thrust = " + stage.thrust);
                }
                stage.thrustToWeight    = this.totalStageThrust / (this.stageStartMass * this.gravity);
                stage.maxThrustToWeight = stage.thrustToWeight;
                if (log != null)
                {
                    log.buf.AppendLine("StageMass = " + stageStartMass);
                }
                if (log != null)
                {
                    log.buf.AppendLine("Initial maxTWR = " + stage.maxThrustToWeight);
                }
                stage.actualThrust         = this.totalStageActualThrust;
                stage.actualThrustToWeight = this.totalStageActualThrust / (this.stageStartMass * this.gravity);

                // calculate torque and associates
                stage.maxThrustTorque = this.totalStageThrustForce.TorqueAt(this.stageStartCom).magnitude;

                // torque divided by thrust. imagine that all engines are at the end of a lever that tries to turn the ship.
                // this numerical value, in meters, would represent the length of that lever.
                double torqueLeverArmLength = (stage.thrust <= 0) ? 0 : stage.maxThrustTorque / stage.thrust;

                // how far away are the engines from the CoM, actually?
                double thrustDistance = (this.stageStartCom - this.totalStageThrustForce.GetAverageForceApplicationPoint()).magnitude;

                // the combination of the above two values gives an approximation of the offset angle.
                double sinThrustOffsetAngle = 0;
                if (thrustDistance > 1e-7)
                {
                    sinThrustOffsetAngle = torqueLeverArmLength / thrustDistance;
                    if (sinThrustOffsetAngle > 1)
                    {
                        sinThrustOffsetAngle = 1;
                    }
                }

                stage.thrustOffsetAngle = Math.Asin(sinThrustOffsetAngle) * 180 / Math.PI;

                // Calculate the total cost of the vessel at this point
                stage.totalCost = 0d;
                for (int i = 0; i < allParts.Count; ++i)
                {
                    if (this.currentStage > allParts[i].decoupledInStage)
                    {
                        stage.totalCost += allParts[i].GetCost(currentStage);
                    }
                }

                // The total mass is simply the mass at the start of the stage
                stage.totalMass = this.stageStartMass;

                // If we have done a previous stage
                if (currentStage < startStage)
                {
                    // Calculate what the previous stage's mass and cost were by subtraction
                    Stage prev = stages[currentStage + 1];
                    prev.cost = prev.totalCost - stage.totalCost;
                    prev.mass = prev.totalMass - stage.totalMass;
                }

                // The above code will never run for the last stage so set those directly
                if (currentStage == 0)
                {
                    stage.cost = stage.totalCost;
                    stage.mass = stage.totalMass;
                }

                this.dontStageParts = dontStagePartsLists[this.currentStage];

                if (log != null)
                {
                    log.buf.AppendLine("Stage setup took " + this._timer.ElapsedMilliseconds + "ms");

                    if (this.dontStageParts.Count > 0)
                    {
                        log.buf.AppendLine("Parts preventing staging:");
                        for (int i = 0; i < this.dontStageParts.Count; i++)
                        {
                            PartSim partSim = this.dontStageParts[i];
                            partSim.DumpPartToBuffer(log.buf, "");
                        }
                    }
                    else
                    {
                        log.buf.AppendLine("No parts preventing staging");
                    }

                    log.Flush();
                }


                // Now we will loop until we are allowed to stage
                int loopCounter = 0;
                while (!this.AllowedToStage())
                {
                    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;
                    foreach (PartSim partSim in this.drainingParts)
                    {
                        double time = partSim.TimeToDrainResource();
                        if (time < resourceDrainTime)
                        {
                            resourceDrainTime = time;
                            partMinDrain      = partSim;
                        }
                    }

                    if (log != null)
                    {
                        MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")");
                    }
                    foreach (PartSim partSim in this.drainingParts)
                    {
                        partSim.DrainResources(resourceDrainTime);
                    }

                    // Get the mass after draining
                    this.stepEndMass = this.ShipMass;
                    this.stageTime  += resourceDrainTime;

                    double stepEndTWR = this.totalStageThrust / (this.stepEndMass * this.gravity);
                    //MonoBehaviour.print("After drain mass = " + stepEndMass);
                    //MonoBehaviour.print("currentThrust = " + totalStageThrust);
                    //MonoBehaviour.print("currentTWR = " + stepEndTWR);
                    if (stepEndTWR > stage.maxThrustToWeight)
                    {
                        stage.maxThrustToWeight = stepEndTWR;
                    }

                    //MonoBehaviour.print("newMaxTWR = " + stage.maxThrustToWeight);

                    // If we have drained anything and the masses make sense then add this step's deltaV to the stage total
                    if (resourceDrainTime > 0d && this.stepStartMass > this.stepEndMass && this.stepStartMass > 0d && this.stepEndMass > 0d)
                    {
                        this.vecStageDeltaV += this.vecThrust * (float)((this.currentisp * Units.GRAVITY * Math.Log(this.stepStartMass / this.stepEndMass)) / this.simpleTotalThrust);
                    }

                    // Update the active engines and resource drains for the next step
                    this.UpdateResourceDrains();

                    // Recalculate the current thrust and isp for the next step
                    this.CalculateThrustAndISP();

                    // Check if we actually changed anything
                    if (this.stepStartMass == this.stepEndMass)
                    {
                        //MonoBehaviour.print("No change in mass");
                        break;
                    }

                    // Check to stop rampant looping
                    if (loopCounter == 1000)
                    {
                        MonoBehaviour.print("exceeded loop count");
                        MonoBehaviour.print("stageStartMass = " + this.stageStartMass);
                        MonoBehaviour.print("stepStartMass = " + this.stepStartMass);
                        MonoBehaviour.print("StepEndMass   = " + this.stepEndMass);
                        Logger.Log("exceeded loop count");
                        Logger.Log("stageStartMass = " + this.stageStartMass);
                        Logger.Log("stepStartMass = " + this.stepStartMass);
                        Logger.Log("StepEndMass   = " + this.stepEndMass);
                        break;
                    }

                    // The next step starts at the mass this one ended at
                    this.stepStartMass = this.stepEndMass;
                }


                // Store more values in the Stage object and stick it in the array

                // Store the magnitude of the deltaV vector
                stage.deltaV       = this.vecStageDeltaV.magnitude;
                stage.resourceMass = this.stageStartMass - this.stepEndMass;

                // Recalculate effective stage isp from the stage deltaV (flip the standard deltaV calculation around)
                // Note: If the mass doesn't change then this is a divide by zero
                if (this.stageStartMass != this.stepStartMass)
                {
                    stage.isp          = stage.deltaV / (Units.GRAVITY * Math.Log(this.stageStartMass / this.stepStartMass));
                    stage.resourceMass = this.stageStartMass - this.stepEndMass;
                }
                else
                {
                    stage.isp          = 0;
                    stage.resourceMass = 0;
                }

                // Zero stage time if more than a day (this should be moved into the window code)
                stage.time                = (this.stageTime < SECONDS_PER_DAY) ? this.stageTime : 0d;
                stage.number              = this.doingCurrent ? -1 : this.currentStage; // Set the stage number to -1 if doing current engines
                stage.totalPartCount      = this.allParts.Count;
                stage.maxMach             = maxMach;
                stages[this.currentStage] = stage;

                // Now activate the next stage
                this.currentStage--;
                this.doingCurrent = false;

                if (log != null)
                {
                    // Log how long the stage took
                    this._timer.Stop();
                    MonoBehaviour.print("Simulating stage took " + this._timer.ElapsedMilliseconds + "ms");
                    stage.Dump();
                    this._timer.Reset();
                    this._timer.Start();
                }

                // Activate the next stage
                this.ActivateStage();

                if (log != null)
                {
                    // Log how long it took to activate
                    this._timer.Stop();
                    MonoBehaviour.print("ActivateStage took " + this._timer.ElapsedMilliseconds + "ms");
                }
            }

            // Now we add up the various total fields in the stages
            for (int i = 0; i < stages.Length; i++)
            {
                // For each stage we total up the cost, mass, deltaV and time for this stage and all the stages above
                for (int j = i; j >= 0; j--)
                {
                    stages[i].totalDeltaV += stages[j].deltaV;
                    stages[i].totalTime   += stages[j].time;
                    stages[i].partCount    = i > 0 ? stages[i].totalPartCount - stages[i - 1].totalPartCount : stages[i].totalPartCount;
                }
                // We also total up the deltaV for stage and all stages below
                for (int j = i; j < stages.Length; j++)
                {
                    stages[i].inverseTotalDeltaV += stages[j].deltaV;
                }

                // Zero the total time if the value will be huge (24 hours?) to avoid the display going weird
                // (this should be moved into the window code)
                if (stages[i].totalTime > SECONDS_PER_DAY)
                {
                    stages[i].totalTime = 0d;
                }
            }

            if (log != null)
            {
                this._timer.Stop();
                MonoBehaviour.print("RunSimulation: " + this._timer.ElapsedMilliseconds + "ms");
            }
            FreePooledObject();

            return(stages);
        }
Пример #9
0
        // 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 theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false)
        {
            LogMsg log = null;

            if (SimManager.logOutput)
            {
                log = new LogMsg();
                log.buf.AppendLine("PrepareSimulation started");
                dumpTree = true;
            }
            this._timer.Reset();
            this._timer.Start();

            // Store the parameters in members for ease of access in other functions
            this.partList   = parts;
            this.gravity    = theGravity;
            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
            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 (this.partList.Count > 0 && this.partList[0].vessel != null)
            {
                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)
            {
                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.buf.AppendLine("Part " + part.name + " appears in vessel list more than once");
                    }
                    continue;
                }

                // Create the PartSim
                PartSim partSim = PartSim.New(part, partId, this.atmosphere, log);

                // Add it to the Part lookup dictionary and the necessary lists
                partSimLookup.Add(part, partSim);
                this.allParts.Add(partSim);
                if (partSim.isFuelLine)
                {
                    this.allFuelLines.Add(partSim);
                }
                if (partSim.isEngine)
                {
                    partSim.CreateEngineSims(this.allEngines, this.atmosphere, this.mach, vectoredThrust, fullThrust, log);
                }

                partId++;
            }

            for (int i = 0; i < allEngines.Count; ++i)
            {
                maxMach = Mathf.Max(maxMach, allEngines[i].maxMach);
            }

            this.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 < this.allParts.Count; i++)
            {
                PartSim partSim = this.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.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");
            for (int i = 0; i < allParts.Count; ++i)
            {
                PartSim partSim = allParts[i];

                partSim.SetupAttachNodes(partSimLookup, log);
                if (partSim.decoupledInStage >= this.lastStage)
                {
                    this.lastStage = partSim.decoupledInStage + 1;
                }
            }

            // And finally release the Part references from all the PartSims
            //MonoBehaviour.print("ReleaseParts");
            for (int i = 0; i < allParts.Count; ++i)
            {
                allParts[i].ReleasePart();
            }

            // And dereference the core's part list
            this.partList = null;

            this._timer.Stop();
            if (log != null)
            {
                log.buf.AppendLine("PrepareSimulation: " + this._timer.ElapsedMilliseconds + "ms");
                log.Flush();
            }

            if (dumpTree)
            {
                this.Dump();
            }

            return(true);
        }