Exemple #1
0
        // The list of throttles is ordered under the assumption that you iterate
        // over the vessel as follows:
        //      foreach part in vessel.parts:
        //          foreach rcsModule in part.Modules.OfType<ModuleRCS>:
        //              ...
        // Note that rotation balancing is not supported at the moment.
        public void GetThrottles(Vessel vessel, VesselState state, Vector3 direction,
                                 out double[] throttles, out List <RCSSolver.Thruster> thrustersOut)
        {
            thrustersOut = callerThrusters;

            Vector3 rotation = Vector3.zero;

            var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal;

            // Update vessel info if needed.
            CheckVessel(vessel, state);

            Vector3      dir = direction.normalized;
            RCSSolverKey key = new RCSSolverKey(ref dir, rotation);

            if (thrusters.Count == 0)
            {
                throttles = double0;
            }
            else if (direction == Vector3.zero)
            {
                throttles = originalThrottles;
            }
            else if (results.TryGetValue(key, out throttles))
            {
                cacheHits++;
            }
            else
            {
                // This task hasn't been calculated. We'll handle that here.
                // Meanwhile, TryGetValue() will have set 'throttles' to null, but
                // we'll make it a 0-element array instead to avoid null checks.
                cacheMisses++;
                throttles = double0;

                if (pending.Contains(key))
                {
                    // We've submitted this key before, so we need to check the
                    // results queue.
                    while (resultsQueue.Count > 0)
                    {
                        SolverResult sr = (SolverResult)resultsQueue.Dequeue();
                        results[sr.key] = sr.throttles;
                        pending.Remove(sr.key);
                        if (sr.key == key)
                        {
                            throttles = sr.throttles;
                        }
                    }
                }
                else
                {
                    // This task was neither calculated nor pending, so we've never
                    // submitted it. Do so!
                    pending.Add(key);
                    tasks.Enqueue(new SolverTask(key, dir, rotation));
                    workEvent.Set();
                }
            }

            // Return a copy of the array to make sure ours isn't modified.
            throttles = (double[])throttles.Clone();
        }
        // Open and close intakes so that they provide the required flow but no
        // more.
        void OptimizeIntakes(VesselState.ResourceInfo info, double requiredFlow)
        {
            // The highly imperfect algorithm here is:
            // - group intakes by symmetry
            // - sort the groups by their size
            // - open a group at a time until we have enough airflow
            // - close the remaining groups

            // TODO: improve the algorithm:
            // 1. Take cost-benefit into account.  We want to open ram intakes
            //    before any others, and we probably never want to open
            //    nacelles.  We need more info to know how much thrust we lose
            //    for losing airflow, versus how much drag we gain for opening
            //    an intake.
            // 2. Take the center of drag into account.  We don't need to open
            //    symmetry groups all at once; we just need the center of drag
            //    to be in a good place.  Symmetry in the SPH also doesn't
            //    guarantee anything; we could be opening all pairs that are
            //    above the plane through the center of mass and none below,
            //    which makes control harder.
            // Even just point (1) means we want to solve knapsack.

            // Group intakes by symmetry, and collect the information by intake.
            var groups = new List<List<ModuleResourceIntake>>();
            var groupIds = new Dictionary<ModuleResourceIntake, int>();
            var data = new Dictionary<ModuleResourceIntake, VesselState.ResourceInfo.IntakeData>();
            foreach (var intakeData in info.intakes)
            {
                ModuleResourceIntake intake = intakeData.intake;
                data[intake] = intakeData;
                if (groupIds.ContainsKey(intake)) { continue; }

                // Create a group for this symmetry
                int grpId = groups.Count;
                var intakes = new List<ModuleResourceIntake>();
                groups.Add(intakes);

                // In DFS order, get all the symmetric parts.
                // We can't rely on symmetryCounterparts; see bug #52 by tavert:
                // https://github.com/MuMech/MechJeb2/issues/52
                var stack = new Stack<Part>();
                stack.Push(intake.part);
                while(stack.Count > 0) {
                    var part = stack.Pop();
                    var partIntake = part.Modules.OfType<ModuleResourceIntake>().FirstOrDefault();
                    if (partIntake == null || groupIds.ContainsKey(partIntake)) {
                        continue;
                    }

                    groupIds[partIntake] = grpId;
                    intakes.Add(partIntake);

                    foreach (var sympart in part.symmetryCounterparts) {
                        stack.Push(sympart);
                    }
                }
            }

            // For each group in sorted order, if we need more air, open any
            // closed intakes.  If we have enough air, close any open intakes.
            // OrderBy is stable, so we'll always be opening the same intakes.
            double airFlowSoFar = 0;
            KSPActionParam param = new KSPActionParam(KSPActionGroup.None,
                    KSPActionType.Activate);
            foreach (var grp in groups.OrderBy(grp => grp.Count))
            {
                if (airFlowSoFar < requiredFlow)
                {
                    foreach (var intake in grp)
                    {
                        double airFlowThisIntake = data[intake].predictedMassFlow;
                        if (!intake.intakeEnabled)
                        {
                            intake.ToggleAction(param);
                        }
                        airFlowSoFar += airFlowThisIntake;
                    }
                }
                else
                {
                    foreach (var intake in grp)
                    {
                        if (intake.intakeEnabled)
                        {
                            intake.ToggleAction(param);
                        }
                    }
                }
            }
        }
Exemple #3
0
        private void CheckVessel(Vessel vessel, VesselState state)
        {
            bool changed = false;

            var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal;

            if (vessel.parts.Count != lastPartCount)
            {
                lastPartCount = vessel.parts.Count;
                changed       = true;
            }

            // Make sure all thrusters are still enabled, because if they're not,
            // our calculations will be wrong.
            for (int i = 0; i < thrusters.Count; i++)
            {
                if (!thrusters[i].partModule.isEnabled)
                {
                    changed = true;
                    break;
                }
            }

            // Likewise, make sure any previously-disabled RCS modules are still
            // disabled.
            for (int i = 0; i < lastDisabled.Count; i++)
            {
                var pm = lastDisabled[i];
                if (pm.isEnabled)
                {
                    changed = true;
                    break;
                }
            }

            // See if the CoM has moved too much.
            Rigidbody rootPartBody = vessel.rootPart.rigidbody;

            if (rootPartBody != null)
            {
                // But how much is "too much"? Well, it probably has something to do
                // with the ship's moment of inertia (MoI). Let's say the distance
                // 'd' that the CoM is allowed to shift without a reset is:
                //
                //      d = moi * x + c
                //
                // where 'moi' is the magnitude of the ship's moment of inertia and
                // 'x' and 'c' are tuning parameters to be determined.
                //
                // Using a few actual KSP ships, I burned RCS fuel (or moved fuel
                // from one tank to another) to see how far the CoM could shift
                // before the the rotation error on translation became annoying.
                // I came up with roughly:
                //
                //      d         moi
                //      0.005    2.34
                //      0.04    11.90
                //      0.07    19.96
                //
                // I then halved each 'd' value, because we'd like to address this
                // problem -before- it becomes annoying. Least-squares linear
                // regression on the (moi, d/2) pairs gives the following (with
                // adjusted R^2 = 0.999966):
                //
                //      moi = 542.268 d + 1.00654
                //      d = (moi - 1) / 542
                //
                // So the numbers below have some basis in reality. =)

                // Assume MoI magnitude is always >=2.34, since that's all I tested.
                comErrorThreshold = (Math.Max(state.MoI.magnitude, 2.34) - 1) / 542;

                Vector3 comState   = state.CoM;
                Vector3 rootPos    = state.rootPartPos;
                Vector3 com        = WorldToVessel(vessel, comState - rootPos);
                double  thisComErr = (lastCoM - com).magnitude;
                maxComError     = Math.Max(maxComError, thisComErr);
                _comError.value = thisComErr;
                if (_comError > comErrorThreshold)
                {
                    lastCoM = com;
                    changed = true;
                }
            }

            if (!changed)
            {
                return;
            }

            // Something about the vessel has changed. We need to reset everything.

            lastDisabled.Clear();

            // ModuleRCS has no originalThrusterPower attribute, so we have
            // to explicitly reset it.
            ResetThrusterForces();

            // Rebuild the list of thrusters.
            var ts = new List <RCSSolver.Thruster>();

            for (int index = 0; index < vessel.parts.Count; index++)
            {
                Part p = vessel.parts[index];
                foreach (ModuleRCS pm in p.Modules.OfType <ModuleRCS>())
                {
                    if (!pm.isEnabled)
                    {
                        // Keep track of this module so we'll know if it's enabled.
                        lastDisabled.Add(pm);
                    }
                    else if (p.Rigidbody != null && !pm.isJustForShow)
                    {
                        Vector3 pos = VesselRelativePos(state.CoM, vessel, p);

                        // Create a single RCSSolver.Thruster for this part. This
                        // requires some assumptions about how the game's RCS code will
                        // drive the individual thrusters (which we can't control).

                        Vector3[]  thrustDirs   = new Vector3[pm.thrusterTransforms.Count];
                        Quaternion rotationQuat = Quaternion.Inverse(vessel.GetTransform().rotation);
                        for (int i = 0; i < pm.thrusterTransforms.Count; i++)
                        {
                            thrustDirs[i] = (rotationQuat * -pm.thrusterTransforms[i].up).normalized;
                        }

                        ts.Add(new RCSSolver.Thruster(pos, thrustDirs, p, pm));
                    }
                }
            }
            callerThrusters.Clear();
            originalThrottles = new double[ts.Count];
            zeroThrottles     = new double[ts.Count];
            for (int i = 0; i < ts.Count; i++)
            {
                originalThrottles[i] = ts[i].originalForce;
                zeroThrottles[i]     = 0;
                callerThrusters.Add(ts[i]);
            }

            thrusters = ts;
            ClearResults();
        }
Exemple #4
0
        override public void activateAction()
        {
            base.activateAction();
            warping = true;
            Orbit       orbit       = this.scriptModule.orbit;
            VesselState vesselState = this.scriptModule.vesselState;
            Vessel      vessel      = FlightGlobals.ActiveVessel;

            switch (warpTarget)
            {
            case WarpTarget.Periapsis:
                targetUT = orbit.NextPeriapsisTime(vesselState.time);
                break;

            case WarpTarget.Apoapsis:
                if (orbit.eccentricity < 1)
                {
                    targetUT = orbit.NextApoapsisTime(vesselState.time);
                }
                break;

            case WarpTarget.SoI:
                if (orbit.patchEndTransition != Orbit.PatchTransitionType.FINAL)
                {
                    targetUT = orbit.EndUT;
                }
                break;

            case WarpTarget.Node:
                if (vessel.patchedConicsUnlocked() && vessel.patchedConicSolver.maneuverNodes.Any())
                {
                    targetUT = vessel.patchedConicSolver.maneuverNodes[0].UT;
                }
                break;

            case WarpTarget.Time:
                targetUT = vesselState.time + timeOffset;
                break;

            case WarpTarget.PhaseAngleT:
                if (core.target.NormalTargetExists)
                {
                    Orbit reference;
                    if (core.target.TargetOrbit.referenceBody == orbit.referenceBody)
                    {
                        reference = orbit;                                 // we orbit arround the same body
                    }
                    else
                    {
                        reference = orbit.referenceBody.orbit;
                    }
                    // From Kerbal Alarm Clock
                    double angleChangePerSec = (360 / core.target.TargetOrbit.period) - (360 / reference.period);
                    double currentAngle      = reference.PhaseAngle(core.target.TargetOrbit, vesselState.time);
                    double angleDigff        = currentAngle - phaseAngle;
                    if (angleDigff > 0 && angleChangePerSec > 0)
                    {
                        angleDigff -= 360;
                    }
                    if (angleDigff < 0 && angleChangePerSec < 0)
                    {
                        angleDigff += 360;
                    }
                    double TimeToTarget = Math.Floor(Math.Abs(angleDigff / angleChangePerSec));
                    targetUT = vesselState.time + TimeToTarget;
                }
                break;

            case WarpTarget.AtmosphericEntry:
                try
                {
                    targetUT = OrbitExtensions.NextTimeOfRadius(vessel.orbit, vesselState.time, vesselState.mainBody.Radius + vesselState.mainBody.RealMaxAtmosphereAltitude());
                }
                catch
                {
                    warping = false;
                }
                break;

            case WarpTarget.SuicideBurn:
                try
                {
                    targetUT = OrbitExtensions.SuicideBurnCountdown(orbit, vesselState, vessel) + vesselState.time;
                }
                catch
                {
                    warping = false;
                }
                break;

            default:
                targetUT = vesselState.time;
                break;
            }
        }
        public static double SuicideBurnCountdown(Orbit orbit, VesselState vesselState, Vessel vessel)
        {
            if (vesselState.mainBody == null) return 0;
            if (orbit.PeA > 0) return Double.PositiveInfinity;

            double angleFromHorizontal = 90 - Vector3d.Angle(-vessel.srf_velocity, vesselState.up);
            angleFromHorizontal = MuUtils.Clamp(angleFromHorizontal, 0, 90);
            double sine = Math.Sin(angleFromHorizontal * Math.PI / 180);
            double g = vesselState.localg;
            double T = vesselState.limitedMaxThrustAccel;

            double effectiveDecel = 0.5 * (-2 * g * sine + Math.Sqrt((2 * g * sine) * (2 * g * sine) + 4 * (T * T - g * g)));
            double decelTime = vesselState.speedSurface / effectiveDecel;

            Vector3d estimatedLandingSite = vesselState.CoM + 0.5 * decelTime * vessel.srf_velocity;
            double terrainRadius = vesselState.mainBody.Radius + vesselState.mainBody.TerrainAltitude(estimatedLandingSite);
            double impactTime = 0;
            try
            {
                impactTime = orbit.NextTimeOfRadius(vesselState.time, terrainRadius);
            }
            catch (ArgumentException)
            {
                return 0;
            }
            return impactTime - decelTime / 2 - vesselState.time;
        }
Exemple #6
0
    // The list of throttles is ordered under the assumption that you iterate
    // over the vessel as follows:
    //      foreach part in vessel.parts:
    //          foreach rcsModule in part.Modules.OfType<ModuleRCS>:
    //              ...
    // Note that rotation balancing is not supported at the moment.
    public void GetThrottles(Vessel vessel, VesselState state, Vector3 direction,
        out double[] throttles, out List<RCSSolver.Thruster> thrustersOut)
    {
        thrustersOut = callerThrusters;

        Vector3 rotation = Vector3.zero;

        var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal;

        // Update vessel info if needed.
        CheckVessel(vessel, state);

        Vector3 dir = direction.normalized;
        RCSSolverKey key = new RCSSolverKey(ref dir, rotation);

        if (thrusters.Count == 0)
        {
            throttles = double0;
        }
        else if (direction == Vector3.zero)
        {
            throttles = originalThrottles;
        }
        else if (results.TryGetValue(key, out throttles))
        {
            cacheHits++;
        }
        else
        {
            // This task hasn't been calculated. We'll handle that here.
            // Meanwhile, TryGetValue() will have set 'throttles' to null, but
            // we'll make it a 0-element array instead to avoid null checks.
            cacheMisses++;
            throttles = double0;

            if (pending.Contains(key))
            {
                // We've submitted this key before, so we need to check the
                // results queue.
                while (resultsQueue.Count > 0)
                {
                    SolverResult sr = (SolverResult)resultsQueue.Dequeue();
                    results[sr.key] = sr.throttles;
                    pending.Remove(sr.key);
                    if (sr.key == key)
                    {
                        throttles = sr.throttles;
                    }
                }
            }
            else
            {
                // This task was neither calculated nor pending, so we've never
                // submitted it. Do so!
                pending.Add(key);
                tasks.Enqueue(new SolverTask(key, dir, rotation));
                workEvent.Set();
            }
        }

        // Return a copy of the array to make sure ours isn't modified.
        throttles = (double[])throttles.Clone();
    }
Exemple #7
0
    private void CheckVessel(Vessel vessel, VesselState state)
    {
        bool changed = false;

        var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal;

        if (vessel.parts.Count != lastPartCount)
        {
            lastPartCount = vessel.parts.Count;
            changed = true;
        }

        // Make sure all thrusters are still enabled, because if they're not,
        // our calculations will be wrong.
        for (int i = 0; i < thrusters.Count; i++)
        {
            if (!thrusters[i].partModule.isEnabled)
            {
                changed = true;
                break;
            }
        }

        // Likewise, make sure any previously-disabled RCS modules are still
        // disabled.
        foreach (var pm in lastDisabled)
        {
            if (pm.isEnabled)
            {
                changed = true;
                break;
            }
        }

        // See if the CoM has moved too much.
        Rigidbody rootPartBody = vessel.rootPart.rigidbody;
        if (rootPartBody != null)
        {
            // But how much is "too much"? Well, it probably has something to do
            // with the ship's moment of inertia (MoI). Let's say the distance
            // 'd' that the CoM is allowed to shift without a reset is:
            //
            //      d = moi * x + c
            //
            // where 'moi' is the magnitude of the ship's moment of inertia and
            // 'x' and 'c' are tuning parameters to be determined.
            //
            // Using a few actual KSP ships, I burned RCS fuel (or moved fuel
            // from one tank to another) to see how far the CoM could shift
            // before the the rotation error on translation became annoying.
            // I came up with roughly:
            //
            //      d         moi
            //      0.005    2.34
            //      0.04    11.90
            //      0.07    19.96
            //
            // I then halved each 'd' value, because we'd like to address this
            // problem -before- it becomes annoying. Least-squares linear
            // regression on the (moi, d/2) pairs gives the following (with
            // adjusted R^2 = 0.999966):
            //
            //      moi = 542.268 d + 1.00654
            //      d = (moi - 1) / 542
            //
            // So the numbers below have some basis in reality. =)

            // Assume MoI magnitude is always >=2.34, since that's all I tested.
            comErrorThreshold = (Math.Max(state.MoI.magnitude, 2.34) - 1) / 542;

            Vector3 comState = state.CoM;
            Vector3 rootPos = state.rootPartPos;
            Vector3 com = WorldToVessel(vessel, comState - rootPos);
            double thisComErr = (lastCoM - com).magnitude;
            maxComError = Math.Max(maxComError, thisComErr);
            _comError.value = thisComErr;
            if (_comError > comErrorThreshold)
            {
                lastCoM = com;
                changed = true;
            }
        }

        if (!changed) return;

        // Something about the vessel has changed. We need to reset everything.

        lastDisabled.Clear();

        // ModuleRCS has no originalThrusterPower attribute, so we have
        // to explicitly reset it.
        ResetThrusterForces();

        // Rebuild the list of thrusters.
        var ts = new List<RCSSolver.Thruster>();
        foreach (Part p in vessel.parts)
        {
            foreach (ModuleRCS pm in p.Modules.OfType<ModuleRCS>())
            {
                if (!pm.isEnabled)
                {
                    // Keep track of this module so we'll know if it's enabled.
                    lastDisabled.Add(pm);
                }
                else if (p.Rigidbody != null && !pm.isJustForShow)
                {
                    Vector3 pos = VesselRelativePos(state.CoM, vessel, p);

                    // Create a single RCSSolver.Thruster for this part. This
                    // requires some assumptions about how the game's RCS code will
                    // drive the individual thrusters (which we can't control).

                    Vector3[] thrustDirs = new Vector3[pm.thrusterTransforms.Count];
                    Quaternion rotationQuat = Quaternion.Inverse(vessel.GetTransform().rotation);
                    for (int i = 0; i < pm.thrusterTransforms.Count; i++)
                    {
                        thrustDirs[i] = (rotationQuat * -pm.thrusterTransforms[i].up).normalized;
                    }

                    ts.Add(new RCSSolver.Thruster(pos, thrustDirs, p, pm));
                }
            }
        }
        callerThrusters.Clear();
        originalThrottles = new double[ts.Count];
        zeroThrottles = new double[ts.Count];
        for (int i = 0; i < ts.Count; i++)
        {
            originalThrottles[i] = ts[i].originalForce;
            zeroThrottles[i] = 0;
            callerThrusters.Add(ts[i]);
        }

        thrusters = ts;
        ClearResults();
    }
Exemple #8
0
        public void onPartFixedUpdate()
        {
            if (settingsChanged)
            {
                saveSettings();
            }

            if ((part == null))
            {
                print("F part == null");
                return;
            }
            if ((part.vessel == null))
            {
                print("F part.vessel == null");
                return;
            }

            if (((part.vessel.rootPart is Decoupler) || (part.vessel.rootPart is RadialDecoupler)) && part.vessel.rootPart.gameObject.layer != 2)
            {
                print("Disabling collision with decoupler...");
                EditorLogic.setPartLayer(part.vessel.rootPart.gameObject, 2);
            }

            if (part.vessel.orbit.objectType != Orbit.ObjectType.VESSEL)
            {
                part.vessel.orbit.objectType = Orbit.ObjectType.VESSEL;
            }

            if (!part.isConnected)
            {
                List<Part> tmp = new List<Part>(part.vessel.parts);
                foreach (Part p in tmp)
                {
                    if ((p is Decoupler) || (p is RadialDecoupler))
                    {
                        print("Disabling collision with decoupler...");
                        EditorLogic.setPartLayer(p.gameObject, 2);
                    }
                }

                tmp = new List<Part>(part.vessel.parts);
                foreach (Part p in tmp)
                {
                    p.isConnected = true;
                    if (p.State == PartStates.IDLE)
                    {
                        p.force_activate();
                    }
                }
            }

            if (!allJebs.ContainsKey(part.vessel))
            {
                allJebs[part.vessel] = new VesselStateKeeper();
                allJebs[part.vessel].controller = this;
            }

            if (!allJebs[part.vessel].jebs.Contains(this))
            {
                allJebs[part.vessel].jebs.Add(this);
            }

            if (allJebs[part.vessel].controller == this)
            {
                allJebs[part.vessel].state.Update(part.vessel);
                vesselState = allJebs[part.vessel].state;

                foreach (ComputerModule module in modules)
                {
                    module.vesselState = vesselState;
                    module.onPartFixedUpdate();
                }

                if (!liftedOff && (FlightGlobals.ActiveVessel == part.vessel) && (Staging.CurrentStage <= Staging.LastStage))
                {
                    foreach (ComputerModule module in modules)
                    {
                        module.onLiftOff();
                    }
                    liftedOff = true;
                }

                if (part.vessel != FlightGlobals.ActiveVessel)
                {
                    FlightCtrlState s = new FlightCtrlState();
                    drive(s);
                    part.vessel.FeedInputFeed(s);
                }
            }
        }
Exemple #9
0
        public void onPartStart()
        {
            vesselState = new VesselState();

            modules.Add(new MechJebModuleSmartASS(this));
            modules.Add(new MechJebModuleTranslatron(this));
            modules.Add(new MechJebModuleRendezvous(this));
            modules.Add(new MechJebModuleSurfaceInfo(this));
            modules.Add (new MechJebModuleOrbitInfo(this));
            //modules.Add(new MechJebModuleVesselInfo(this));
            modules.Add(new MechJebModuleLandingAutopilot(this));
            modules.Add(new MechJebModuleAscentAutopilot(this));
            modules.Add(new MechJebModuleOrbitOper(this));
            //modules.Add(new MechJebModuleOrbitPlane(this));

            //modules.Add(new MechJebModuleJoke(this));

            //modules.Add(new MechJebModuleAscension(this));

            foreach (ComputerModule module in modules)
            {
                module.onPartStart();
            }
        }
 public ComputerModule(MechJebCore core)
 {
     this.core   = core;
     part        = core.part;
     vesselState = core.vesselState;
 }
        override public void activateAction()
        {
            base.activateAction();
            Vessel        vessel      = this.scriptModule.vessel;
            VesselState   vesselState = this.scriptModule.vesselState;
            Orbit         orbit       = this.scriptModule.orbit;
            CelestialBody mainBody    = this.scriptModule.mainBody;

            const double leadTime            = 30;
            double       closestApproachTime = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time);

            if (actionType == 0)             //Align planes
            {
                double   UT;
                Vector3d dV;
                if (orbit.AscendingNodeExists(core.target.TargetOrbit))
                {
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT);
                }
                else
                {
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT);
                }
                vessel.RemoveAllManeuverNodes();
                vessel.PlaceManeuverNode(this.scriptModule.orbit, dV, UT);
            }
            else if (actionType == 1)             //Establish new orbit
            {
                double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius;

                vessel.RemoveAllManeuverNodes();
                if (orbit.ApR < phasingOrbitRadius)
                {
                    double   UT1 = vesselState.time + leadTime;
                    Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius);
                    vessel.PlaceManeuverNode(orbit, dV1, UT1);
                    Orbit    transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch;
                    double   UT2           = transferOrbit.NextApoapsisTime(UT1);
                    Vector3d dV2           = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2);
                    vessel.PlaceManeuverNode(transferOrbit, dV2, UT2);
                }
                else if (orbit.PeR > phasingOrbitRadius)
                {
                    double   UT1 = vesselState.time + leadTime;
                    Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius);
                    vessel.PlaceManeuverNode(orbit, dV1, UT1);
                    Orbit    transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch;
                    double   UT2           = transferOrbit.NextPeriapsisTime(UT1);
                    Vector3d dV2           = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2);
                    vessel.PlaceManeuverNode(transferOrbit, dV2, UT2);
                }
                else
                {
                    double   UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius);
                    Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT);
                    vessel.PlaceManeuverNode(orbit, dV, UT);
                }
            }
            else if (actionType == 2)             //Intercept with Hohmann transfer
            {
                double   UT;
                Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out UT);
                vessel.RemoveAllManeuverNodes();
                vessel.PlaceManeuverNode(orbit, dV, UT);
            }
            else if (actionType == 3)             //Match velocities at closest approach
            {
                double   UT = closestApproachTime;
                Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit);
                vessel.RemoveAllManeuverNodes();
                vessel.PlaceManeuverNode(orbit, dV, UT);
            }
            else if (actionType == 4)             //Get closer
            {
                double   UT          = vesselState.time;
                double   interceptUT = UT + 100;
                Vector3d dV          = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, interceptUT, 10);
                vessel.RemoveAllManeuverNodes();
                vessel.PlaceManeuverNode(orbit, dV, UT);
            }

            this.endAction();
        }
Exemple #12
0
 public ComputerModule(MechJebCore core)
 {
     this.core = core;
     part = core.part;
     vesselState = core.vesselState;
 }
Exemple #13
0
        public void onPartStart()
        {
            vesselState = new VesselState();

            Version v = Assembly.GetAssembly(typeof(MechJebCore)).GetName().Version;

            version = v.Major.ToString() + "." + v.Minor.ToString() + "." + v.Build.ToString();

            modules.Add(new MechJebModuleSmartASS(this));
            modules.Add(new MechJebModuleTranslatron(this));
            modules.Add(new MechJebModuleOrbitInfo(this));
            modules.Add(new MechJebModuleSurfaceInfo(this));
            modules.Add(new MechJebModuleVesselInfo(this));
            modules.Add(new MechJebModuleLandingAutopilot(this));
            modules.Add(new MechJebModuleAscentAutopilot(this));
            modules.Add(new MechJebModuleOrbitOper(this));
            modules.Add(new MechJebModuleRendezvous(this));
            modules.Add(new MechJebModuleILS(this));
            modules.Add(new MechJebModuleTablePhase(this));

            //modules.Add(new MechJebModuleOrbitPlane(this));

            //modules.Add(new MechJebModuleJoke(this));

            //modules.Add(new MechJebModuleAscension(this));

            autom8 = new MechJebModuleAutom8(this);
            modules.Add(autom8);

            foreach (ComputerModule module in modules)
            {
                module.onPartStart();
            }

            part.Events.Add(new BaseEvent("MechJebLua", MechJebLua));

            loadSettings();
        }
Exemple #14
0
        public void onPartFixedUpdate()
        {
            if (settingsChanged)
            {
                saveSettings();
            }
            if (settingsVersion != settings.version)
            {
                loadSettings();
            }

            if ((part == null))
            {
                print("F part == null");
                return;
            }
            if ((part.vessel == null))
            {
                print("F part.vessel == null");
                return;
            }

            if (part.vessel.orbit.objectType != Orbit.ObjectType.VESSEL)
            {
                part.vessel.orbit.objectType = Orbit.ObjectType.VESSEL;
            }

            if (!part.isConnected)
            {
                List<Part> tmp = new List<Part>(part.vessel.parts);
                foreach (Part p in tmp)
                {
                    p.isConnected = true;
                    if ((p.State == PartStates.DEACTIVATED) && !(p is Decoupler || p is RadialDecoupler || p is DecouplerGUI))
                    {
                        p.force_activate();
                    }
                }
            }

            if (!allJebs.ContainsKey(part.vessel))
            {
                allJebs[part.vessel] = new VesselStateKeeper();
                allJebs[part.vessel].controller = this;
            }

            if (!allJebs[part.vessel].jebs.Contains(this))
            {
                allJebs[part.vessel].jebs.Add(this);
            }

            if (allJebs[part.vessel].controller == this)
            {
                allJebs[part.vessel].state.Update(part.vessel);
                attitudeError = attitudeActive ? Math.Abs(Vector3d.Angle(attitudeGetReferenceRotation(attitudeReference) * attitudeTarget * Vector3d.forward, vesselState.forward)) : 0; ;
                vesselState = allJebs[part.vessel].state;

                foreach (ComputerModule module in modules)
                {
                    module.vesselState = vesselState;
                    module.onPartFixedUpdate();
                }

                if (!liftedOff && (FlightGlobals.ActiveVessel == part.vessel) && (Staging.CurrentStage <= Staging.lastStage))
                {
                    foreach (ComputerModule module in modules)
                    {
                        module.onLiftOff();
                    }
                    liftedOff = true;
                }

                if (part.vessel == FlightGlobals.ActiveVessel)
                {
                    MechJebModuleAutom8.instance = autom8;
                }
                else
                {
                    FlightCtrlState s = new FlightCtrlState();
                    drive(s);
                    part.vessel.FeedInputFeed(s);
                }
            }
        }