/// <summary> /// Load and creates a command after saving a command. Returns null if no object /// has been loaded. /// </summary> /// <param name="n">Node with the command infos</param> /// <param name="fc">Current flightcomputer</param> public static ICommand LoadCommand(ConfigNode n, FlightComputer fc) { ICommand command = null; // switch the different commands switch (n.name) { case "AttitudeCommand": { command = new AttitudeCommand(); break; } case "ActionGroupCommand": { command = new ActionGroupCommand(); break; } case "BurnCommand": { command = new BurnCommand(); break; } case "ManeuverCommand": { command = new ManeuverCommand(); break; } case "CancelCommand": { command = new CancelCommand(); break; } case "TargetCommand": { command = new TargetCommand(); break; } case "EventCommand": { command = new EventCommand(); break; } case "DriveCommand": { command = new DriveCommand(); break; } case "ExternalAPICommand": { command = new ExternalAPICommand(); break; } case "PartActionCommand": { command = new PartActionCommand(); break; } } if (command != null) { ConfigNode.LoadObjectFromConfig(command, n); // additional loadings var result = command.Load(n, fc); RTLog.Verbose("Loading command {0}({1})={2}", RTLogLevel.LVL1, n.name, command.CmdGuid, result); // delete command if we can't load the command correctlys if (result == false) command = null; } return command; }
/// <summary> /// Executes this command and invokes the <see cref="ReflectionExecuteMethod"/> /// on the <see cref="ReflectionType"/>. When this command is aborted the /// fallback commnd is "KillRot". /// </summary> /// <param name="computer">Current flightcomputer</param> /// <param name="ctrlState">Current FlightCtrlState</param> /// <returns>true: delete afterwards.</returns> public override bool Execute(FlightComputer computer, FlightCtrlState ctrlState) { bool finished = true; if (this.ReflectionExecuteMethod != "") { // invoke the Execution-method finished = (bool)this.callReflectionMember(this.ReflectionExecuteMethod); if (this.AbortCommand) { if (RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.Off(), true, true, true); finished = true; } if (!RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); finished = true; } } } return(finished); }
/// <summary> /// /// </summary> /// <param name="computer">FlightComputer instance of the computer of the vessel.</param> private void AbortManeuver(FlightComputer computer) { RTUtil.ScreenMessage("[Flight Computer]: Maneuver removed"); if (computer.Vessel.patchedConicSolver != null) { Node.RemoveSelf(); } // enqueue kill rot computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); }
/// <summary> /// Load and creates a command after saving a command. Returns null if no object /// has been loaded. /// </summary> /// <param name="n">Node with the command infos</param> /// <param name="fc">Current flightcomputer</param> public static ICommand LoadCommand(ConfigNode n, FlightComputer fc) { ICommand command = null; // switch the different commands switch (n.name) { case "AttitudeCommand": { command = new AttitudeCommand(); break; } case "ActionGroupCommand": { command = new ActionGroupCommand(); break; } case "BurnCommand": { command = new BurnCommand(); break; } case "ManeuverCommand": { command = new ManeuverCommand(); break; } case "CancelCommand": { command = new CancelCommand(); break; } case "TargetCommand": { command = new TargetCommand(); break; } case "EventCommand": { command = new EventCommand(); break; } case "DriveCommand": { command = new DriveCommand(); break; } case "ExternalAPICommand": { command = new ExternalAPICommand(); break; } case "PartActionCommand": { command = new PartActionCommand(); break; } case "StockAutopilotCommand": { command = new StockAutopilotCommand(); break; } case "HibernationCommand": { command = new HibernationCommand(); break; } case "AxisGroupCommand": { command = new AxisGroupCommand(); break; } case "PIDCommand": { command = new PIDCommand(); break; } case "FlightControlCommand": { command = new FlightControlCommand(); break; } } if (command != null) { ConfigNode.LoadObjectFromConfig(command, n); // additional loadings var result = command.Load(n, fc); RTLog.Verbose("Loading command {0}({1})={2}", RTLogLevel.LVL1, n.name, command.CmdGuid, result); // delete command if we can't load the command correctlys if (result == false) { command = null; } } return(command); }
/// <summary> /// This method will be triggerd right after the command was enqueued to /// the flight computer list. /// </summary> /// <param name="computer">Current flightcomputer</param> public override void CommandEnqueued(FlightComputer computer) { var timetoexec = (TimeStamp + ExtraDelay) - RTSettings.Instance.FCLeadTime; if (timetoexec - RTUtil.GameTime >= 0 && RTSettings.Instance.AutoInsertKaCAlerts) { var kaCAddonLabel = computer.Vessel.vesselName + " Maneuver"; if (RTCore.Instance != null && RTCore.Instance.KacAddon != null) { KaCItemId = RTCore.Instance.KacAddon.CreateAlarm(RemoteTech_KACWrapper.KACWrapper.KACAPI.AlarmTypeEnum.Maneuver, kaCAddonLabel, timetoexec, computer.Vessel.id); } } // also add a maneuver node command to the queue computer.Enqueue(AttitudeCommand.ManeuverNode(timetoexec), true, true, true); }
/// <summary> /// This method will be triggerd right after the command was enqueued to /// the flight computer list. /// </summary> /// <param name="computer">Current flightcomputer</param> public override void CommandEnqueued(FlightComputer computer) { string KaCAddonLabel = String.Empty; double timetoexec = (this.TimeStamp + this.ExtraDelay) - 180; if (timetoexec - RTUtil.GameTime >= 0 && RTSettings.Instance.AutoInsertKaCAlerts == true) { KaCAddonLabel = computer.Vessel.vesselName + " Maneuver"; if (RTCore.Instance != null && RTCore.Instance.kacAddon != null) { this.KaCItemId = RTCore.Instance.kacAddon.CreateAlarm(AddOns.KerbalAlarmClockAddon.AlarmTypeEnum.Maneuver, KaCAddonLabel, timetoexec); } } // also add a maneuver node command to the queue computer.Enqueue(AttitudeCommand.ManeuverNode(timetoexec), true, true, true); }
/// <summary> /// /// </summary> /// <param name="computer">FlightComputer instance of the computer of the vessel.</param> private void AbortManeuver(FlightComputer computer) { RTUtil.ScreenMessage("[Flight Computer]: Maneuver removed"); if (computer.Vessel.patchedConicSolver != null) { Node.RemoveSelf(); } // Flight Computer mode after execution based on settings if (RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.Off(), true, true, true); } if (!RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); } }
/// <summary> /// Executes this command and invokes the <see cref="ReflectionExecuteMethod"/> /// on the <see cref="ReflectionType"/>. When this command is aborted the /// fallback commnd is "KillRot". /// </summary> /// <param name="computer">Current flightcomputer</param> /// <param name="ctrlState">Current FlightCtrlState</param> /// <returns>true: delete afterwards.</returns> public override bool Execute(FlightComputer computer, FlightCtrlState ctrlState) { bool finished = true; if (this.ReflectionExecuteMethod != "") { // invoke the Execution-method finished = (bool)this.callReflectionMember(this.ReflectionExecuteMethod); if (this.AbortCommand) { // enqueue killRot after aborting this command computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); finished = true; } } return(finished); }
/// <summary> /// Executes the maneuver burn for the configured maneuver node. /// </summary> /// <param name="computer">FlightComputer instance of the computer of the vessel the ManeuverCommand is for.</param> /// <param name="ctrlState">FlightCtrlState instance of the current state of the vessel.</param> /// <returns>true if the command has finished its work, false otherwise.</returns> public override bool Execute(FlightComputer computer, FlightCtrlState ctrlState) { // Halt the command if we reached our target or were command to abort by the previous tick if (this.RemainingDelta <= 0.01 || this.abortOnNextExecute) { computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); return(true); } // Orientate vessel to maneuver prograde var forward = Node.GetBurnVector(computer.Vessel.orbit).normalized; var up = (computer.SignalProcessor.Body.position - computer.SignalProcessor.Position).normalized; var orientation = Quaternion.LookRotation(forward, up); FlightCore.HoldOrientation(ctrlState, computer, orientation); // This represents the theoretical acceleration but is off by a few m/s^2, probably because some parts are partially physicsless double thrustToMass = (FlightCore.GetTotalThrust(computer.Vessel) / computer.Vessel.GetTotalMass()); // We need to know if the engine was activated or not to show the proper info text in the command if (thrustToMass == 0.0) { this.EngineActivated = false; return(false); } this.EngineActivated = true; // Before any throttling, those two values may differ from after the throttling took place this.RemainingDelta = this.getRemainingDeltaV(computer); this.RemainingTime = this.RemainingDelta / thrustToMass; // In case we would overpower with 100% thrust, calculate how much we actually need and set it. if (computer.Vessel.acceleration.magnitude > this.RemainingDelta) { // Formula which leads to this: a = ( vE – vS ) / dT this.throttle = this.RemainingDelta / computer.Vessel.acceleration.magnitude; } ctrlState.mainThrottle = (float)this.throttle; // TODO: THIS CAN PROBABLY BE REMOVED? RemainingDelta = this.getRemainingDeltaV(computer); // After throttling, the remaining time differs from beforehand (dividing delta by throttled thrustToMass) this.RemainingTime = this.RemainingDelta / (ctrlState.mainThrottle * thrustToMass); // We need to abort if the remaining delta was already low enough so it only takes exactly one more tick! double ticksRemaining = this.RemainingTime / TimeWarp.deltaTime; if (ticksRemaining <= 1) { this.throttle *= ticksRemaining; ctrlState.mainThrottle = (float)this.throttle; this.abortOnNextExecute = true; return(false); } // we only compare up to the fiftieth part due to some burn-up delay when just firing up the engines if (this.lowestDeltaV > 0 && // Do ignore the first tick (this.RemainingDelta - 0.02) > this.lowestDeltaV) { // Aborting because deltaV was rising again! computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); return(true); } // Lowest delta always has to be stored to be able to compare it in the next tick if (this.lowestDeltaV == 0 || // Always do it on the first tick this.RemainingDelta < this.lowestDeltaV) { this.lowestDeltaV = this.RemainingDelta; } return(false); }