public Option <DeltaVStageInfoAdapter> StageDeltaV(long stage)
            {
                DeltaVStageInfo stageInfo = vessel.VesselDeltaV.GetStage((int)stage);

                return(stageInfo != null
                    ? new Option <DeltaVStageInfoAdapter>(new DeltaVStageInfoAdapter(this, stageInfo))
                    : new Option <DeltaVStageInfoAdapter>());
            }
Exemplo n.º 2
0
 /// <summary>
 /// Construct a one-stage deltaV calculator
 /// </summary>
 /// <param name="shared"></param>
 /// <param name="dv"></param>
 public DeltaVCalc(SharedObjects shared, DeltaVStageInfo dv)
 {
     this.shared = shared;
     // It is possible for the KSP API to give us a DeltaVStageInfo of null for
     // stages that currently don't have any dV (if they are just a stage with
     // a decoupler alone, for example).  If this value is null, then we should
     // behave as if the dV values are all zero:
     stageDV = dv;
     RegisterInitializer(InitializeSuffixes);
 }
Exemplo n.º 3
0
        public void ManeuverProvider()
        {
            if (FlightGlobals.ActiveVessel == null)
            {
                return;
            }

            myManeuver.timeToNextManeuver   = 0.0f;
            myManeuver.deltaVNextManeuver   = 0.0f;
            myManeuver.durationNextManeuver = 0.0f;
            myManeuver.deltaVTotal          = 0.0f;
            myManeuver.headingNextManeuver  = 0.0f;
            myManeuver.pitchNextManeuver    = 0.0f;

            if (FlightGlobals.ActiveVessel.patchedConicSolver != null)
            {
                if (FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes != null)
                {
                    System.Collections.Generic.List <ManeuverNode> maneuvers = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes;

                    if (maneuvers.Count > 0)
                    {
                        myManeuver.timeToNextManeuver = (float)(maneuvers[0].UT - Planetarium.GetUniversalTime());
                        myManeuver.deltaVNextManeuver = (float)maneuvers[0].DeltaV.magnitude;

                        WorldVecToNavHeading(FlightGlobals.ActiveVessel, maneuvers[0].GetBurnVector(maneuvers[0].patch), out myManeuver.headingNextManeuver, out myManeuver.pitchNextManeuver);

                        DeltaVStageInfo currentStageInfo = getCurrentStageDeltaV();
                        if (currentStageInfo != null)
                        {
                            //For now, use a simple crossmultiplication to compute the estimated burn time based on the current stage only
                            myManeuver.durationNextManeuver = (float)(maneuvers[0].DeltaV.magnitude * currentStageInfo.stageBurnTime) / currentStageInfo.deltaVActual;
                        }

                        foreach (ManeuverNode maneuver in maneuvers)
                        {
                            myManeuver.deltaVTotal += (float)maneuver.DeltaV.magnitude;
                        }
                    }
                }
            }
            if (maneuverChannel != null)
            {
                maneuverChannel.Fire(OutboundPackets.ManeuverData, myManeuver);
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Calculate the burn time for a given vessel and delta V amount
 /// </summary>
 /// <param name="dvCalc">Stock delta V object from a vessel</param>
 /// <returns>
 /// null if not ready yet;
 /// PositiveInfinity if not enough fuel to do the burn;
 /// NaN if we can't burn at all;
 /// otherwise number of seconds required for the burn
 /// </returns>
 public double?Duration(VesselDeltaV dvCalc)
 {
     if (dvCalc != null && totalDeltaV > 0)
     {
         if (!dvCalc.IsReady)
         {
             return(null);
         }
         else if (totalDeltaV > dvCalc.TotalDeltaVActual)
         {
             return(double.PositiveInfinity);
         }
         else
         {
             double remaining = totalDeltaV;
             double t         = 0;
             for (int i = 0; i < dvCalc.OperatingStageInfo.Count; ++i)
             {
                 DeltaVStageInfo stg    = dvCalc.OperatingStageInfo[i];
                 double          exhVel = stg.ispActual * PhysicsGlobals.GravitationalAcceleration;
                 if (remaining >= stg.deltaVActual)
                 {
                     // We need to expend this whole stage, so just add its complete time
                     remaining -= stg.deltaVActual;
                     t         += stg.stageBurnTime;
                 }
                 else
                 {
                     // We only need part of this stage, so appeal to Tsiolkovsky
                     t += exhVel
                          * stg.startMass
                          * (1.0 - Math.Exp(-remaining / exhVel))
                          / stg.thrustActual;
                     break;
                 }
             }
             return(t);
         }
     }
     else
     {
         // No such burn
         return(double.NaN);
     }
 }
Exemplo n.º 5
0
        public void BurnTimeProvider()
        {
            DeltaVStageInfo currentStageInfo = getCurrentStageDeltaV();

            if (currentStageInfo != null)
            {
                myBurnTimeStruct.stageBurnTime = (float)currentStageInfo.stageBurnTime;
                myBurnTimeStruct.totalBurnTime = (float)FlightGlobals.ActiveVessel.VesselDeltaV.TotalBurnTime;
            }
            else
            {
                myBurnTimeStruct.stageBurnTime = 0;
                myBurnTimeStruct.totalBurnTime = 0;
            }

            if (burnTimeChannel != null)
            {
                burnTimeChannel.Fire(OutboundPackets.BurnTime, myBurnTimeStruct);
            }
        }
Exemplo n.º 6
0
        public void DeltaVProvider()
        {
            DeltaVStageInfo currentStageInfo = getCurrentStageDeltaV();

            if (currentStageInfo != null)
            {
                myDeltaVStruct.stageDeltaV = (float)currentStageInfo.deltaVActual;
                myDeltaVStruct.totalDeltaV = (float)FlightGlobals.ActiveVessel.VesselDeltaV.TotalDeltaVActual;
            }
            else
            {
                myDeltaVStruct.stageDeltaV = 0;
                myDeltaVStruct.totalDeltaV = 0;
            }

            if (deltaVChannel != null)
            {
                deltaVChannel.Fire(OutboundPackets.DeltaV, myDeltaVStruct);
            }
        }
Exemplo n.º 7
0
        public void DeltaVEnvProvider()
        {
            DeltaVStageInfo currentStageInfo = getCurrentStageDeltaV();

            if (currentStageInfo != null)
            {
                myDeltaVEnvStruct.stageDeltaVASL = (float)currentStageInfo.deltaVatASL;
                myDeltaVEnvStruct.stageDeltaVVac = (float)currentStageInfo.deltaVinVac;
                myDeltaVEnvStruct.totalDeltaVASL = (float)FlightGlobals.ActiveVessel.VesselDeltaV.TotalDeltaVASL;
                myDeltaVEnvStruct.totalDeltaVVac = (float)FlightGlobals.ActiveVessel.VesselDeltaV.TotalDeltaVVac;
            }
            else
            {
                myDeltaVEnvStruct.stageDeltaVASL = 0;
                myDeltaVEnvStruct.stageDeltaVVac = 0;
                myDeltaVEnvStruct.totalDeltaVASL = 0;
                myDeltaVEnvStruct.totalDeltaVVac = 0;
            }

            if (deltaVEnvChannel != null)
            {
                deltaVEnvChannel.Fire(OutboundPackets.DeltaVEnv, myDeltaVEnvStruct);
            }
        }
Exemplo n.º 8
0
        //Return the DeltaVStageInfo of the first stage to consider for deltaV and burn time computation
        //Can return null when no deltaV is available (for instance in EVA).
        private DeltaVStageInfo getCurrentStageDeltaV()
        {
            if (FlightGlobals.ActiveVessel.VesselDeltaV == null)
            {
                return(null); //This happen in EVA for instance.
            }
            DeltaVStageInfo currentStageInfo = null;

            try
            {
                if (FlightGlobals.ActiveVessel.currentStage == FlightGlobals.ActiveVessel.VesselDeltaV.OperatingStageInfo.Count)
                {
                    // Rocket has not taken off, use first stage with deltaV (to avoid stage of only stabilizer)
                    for (int i = FlightGlobals.ActiveVessel.VesselDeltaV.OperatingStageInfo.Count - 1; i >= 0; i--)
                    {
                        currentStageInfo = FlightGlobals.ActiveVessel.VesselDeltaV.GetStage(i);
                        if (currentStageInfo.deltaVActual > 0)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    currentStageInfo = FlightGlobals.ActiveVessel.VesselDeltaV.GetStage(FlightGlobals.ActiveVessel.currentStage);
                }
            }
            catch (NullReferenceException)
            {
                // This happens when reverting a flight.
                // FlightGlobals.ActiveVessel.VesselDeltaV.OperatingStageInfo is not null but using it produce a
                // NullReferenceException in KSP code. This is probably due to the fact that the rocket is not fully initialized.
            }

            return(currentStageInfo);
        }
 internal DeltaVStageInfoAdapter(VesselAdapter vesselAdapter, DeltaVStageInfo deltaVStageInfo)
 {
     this.vesselAdapter   = vesselAdapter;
     this.deltaVStageInfo = deltaVStageInfo;
 }
Exemplo n.º 10
0
        private void UpdateStockDeltaV()
        {
            Profiler.BeginSample("UpdateStockDV");
            if (!_settings.DisableStockDeltaV)
            {
                return;
            }

            _updateDeltaV = false;

            if (HighLogic.LoadedSceneIsFlight)
            {
                if (FlightGlobals.ActiveVessel == null)
                {
                    return;
                }
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                if (EditorLogic.fetch == null || EditorLogic.fetch.ship == null)
                {
                    return;
                }
            }

            if (_vesselDeltaV == null)
            {
                return;
            }

            if (stages == null)
            {
                return;
            }

            if (_vesselDeltaV.enabled)
            {
                _vesselDeltaV.enabled = false;
            }

            List <DeltaVStageInfo> stageInfo = _vesselDeltaV.stageInfo;

            stageInfo.Clear();

            for (int i = stages.Length - 1; i >= 0; i--)
            {
                if (HighLogic.LoadedSceneIsFlight)
                {
                    stageInfo.Add(new DeltaVStageInfo((ShipConstruct)null, stages[i].number, _vesselDeltaV));
                }
                else if (HighLogic.LoadedSceneIsEditor)
                {
                    stageInfo.Add(new DeltaVStageInfo((Vessel)null, stages[i].number, _vesselDeltaV));
                }
            }

            if (_vesselDeltaVTotalDVActual != null && _vesselDeltaVTotalDVASL != null && _vesselDeltaVTotalDVVac != null)
            {
                _vesselDeltaVTotalDVActual.SetValue(_vesselDeltaV, _lastStage.totalDeltaV);
                _vesselDeltaVTotalDVASL.SetValue(_vesselDeltaV, _lastStage.totalDeltaV);
                _vesselDeltaVTotalDVVac.SetValue(_vesselDeltaV, _lastStage.totalDeltaV);
            }

            _vesselDeltaV.lowestStageWithDeltaV = int.MaxValue;

            for (int i = _vesselDeltaV.stageInfo.Count - 1; i >= 0; i--)
            {
                DeltaVStageInfo info = _vesselDeltaV.stageInfo[i];

                Stage stage = GetStage(info.stage);

                if (stage == null)
                {
                    continue;
                }

                info.deltaVActual = (float)stage.deltaV;
                info.deltaVatASL  = info.deltaVActual;
                info.deltaVinVac  = info.deltaVActual;

                double gee = HighLogic.LoadedSceneIsEditor ? _currentBody.GeeASL : FlightGlobals.currentMainBody.GeeASL;

                info.TWRActual = (float)(stage.actualThrust / (stage.startMass * gee * GRAVITY));
                info.TWRASL    = (float)(stage.thrust / (stage.startMass * gee * GRAVITY));
                info.TWRVac    = info.TWRASL;

                info.stageMass = (float)stage.mass;
                info.startMass = (float)stage.startMass;
                info.endMass   = (float)stage.endMass;
                info.fuelMass  = (float)stage.resourceMass;

                info.thrustActual = (float)stage.actualSimpleThrust;
                info.thrustASL    = (float)stage.simpleThrust;
                info.thrustVac    = info.thrustASL;

                info.vectoredThrustActual = (float)stage.actualThrust;
                info.vectoredThrustASL    = (float)stage.thrust;
                info.vectoredThrustVac    = info.vectoredThrustASL;

                info.ispActual = (float)stage.isp;
                info.ispASL    = (float)stage.isp;
                info.ispVac    = info.ispASL;

                info.totalExhaustVelocityActual = (float)stage.totalActualExhaustVelocity;
                info.totalExhaustVelocityASL    = (float)stage.totalExhaustVelocity;
                info.totalExhaustVelocityVAC    = info.totalExhaustVelocityASL;

                info.vectoredExhaustVelocityActual = stage.totalVectoredActualExhaustVelocity;
                info.vectoredExhaustVelocityASL    = stage.totalVectoredExhaustVelocity;
                info.vectoredExhaustVelocityVAC    = info.vectoredExhaustVelocityASL;

                info.stageBurnTime = (float)stage.time;

                if (stage.deltaV > 0)
                {
                    if (stage.number < _vesselDeltaV.lowestStageWithDeltaV)
                    {
                        _vesselDeltaV.lowestStageWithDeltaV = stage.number;
                    }
                }
            }
            Profiler.EndSample();
        }
Exemplo n.º 11
0
        /// <summary>
        /// Fires when the simulator is updated
        /// Populates the KSPFields for PP tanks so their PartModules can do the scaling
        /// </summary>
        private void OnSimUpdate(VesselDeltaV dvCalc)
        {
            if (dvCalc == null)
            {
                return;
            }
            if (Paused)
            {
                pausedDeltaV = dvCalc;
                return;
            }
            string nodesErr = "";

            getNodeStructureError(ref nodesErr);
            double totalMassChange = 0;

            for (int st = dvCalc.OperatingStageInfo.Count - 1; st >= 0; --st)
            {
                DeltaVStageInfo stage = dvCalc.OperatingStageInfo[st];

                List <SmartTankPart> drained = new List <SmartTankPart>(drainedTanks(dvCalc, stage.stage));
                int numTanks = drained.Count;

                if (stage != null && numTanks > 0)
                {
                    if (stage.thrustVac <= 0)
                    {
                        // No thrust on this stage, so fuel doesn't make sense either.
                        // Note that IdealTotalMass effectively is optional for the parts
                        // to obey; if AutoScale is false, they can ignore it.
                        for (int t = 0; t < numTanks; ++t)
                        {
                            // Reset all the tanks to minimum size with no thrust
                            drained[t].nodesError     = nodesErr;
                            drained[t].IdealTotalMass = 0;
                            if (drained[0].AutoScale)
                            {
                                totalMassChange -= partTotalMass(drained[t].part);
                            }
                        }
                    }
                    else
                    {
                        // This stage has thrust that we can balance against the fuel.

                        // Add up the current procedural tank mass
                        double currentProcTankMass = 0;
                        for (int t = 0; t < numTanks; ++t)
                        {
                            currentProcTankMass += partTotalMass(drained[t].part);
                        }

                        // Determine the mass that the procedural parts can't change
                        double nonProcMass = stage.startMass - currentProcTankMass + totalMassChange;

                        if (nonProcMass < 0)
                        {
                            // Sanity check, this is negative a lot
                            continue;
                        }

                        // Get the thrust this stage is configured to use
                        double thrust = drained[0].Atmospheric
                                                        ? stage.thrustASL
                                                        : stage.thrustVac;

                        // Calculate the mass to distribute among this stage's procedural tanks
                        // This includes their wet AND dry mass!
                        double targetProcTankMass = optimalTankMass(
                            thrust,
                            drained[0].bodyGravAccel,
                            drained[0].targetTWR,
                            nonProcMass
                            );

                        // Assume we'll have our way if auto scaling,
                        // otherwise use the existing mass
                        if (drained[0].AutoScale)
                        {
                            double massChange = targetProcTankMass > 0
                                                                ? targetProcTankMass - currentProcTankMass
                                                                : 0;
                            totalMassChange += massChange;
                        }

                        // Distribute the mass evenly
                        double massPerTank = targetProcTankMass / numTanks;
                        for (int t = 0; t < numTanks; ++t)
                        {
                            drained[t].nodesError     = nodesErr;
                            drained[t].IdealTotalMass = massPerTank;
                        }
                    }
                }
            }
        }