// 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); } } } } }
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(); }
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; }
// 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(); }
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(); }
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); } } }
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(); }
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(); }
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); } } }