コード例 #1
0
        /// <summary>
        /// Find the node before a given node
        /// </summary>
        /// <param name="vessel">The currently active vessel</param>
        /// <param name="cur">Node from which to start searching</param>
        /// <returns>
        /// Another node if any
        /// </returns>
        public PlanningNodeModel PrevNode(Vessel vessel, PlanningNodeModel cur)
        {
            var nodes  = NodesFor(vessel, true);
            var curIdx = nodes.IndexOf(cur);

            return(curIdx >= 0 ? nodes[(curIdx + nodes.Count - 1) % nodes.Count] : cur);
        }
コード例 #2
0
 private void openDialog(PlanningNodeModel toEdit)
 {
     if (editDialog == null)
     {
         editDialog              = new PlanningNodeEditDialog(toEdit, CanEdit);
         editDialog.CloseDialog += () => launcher.SetFalse(true);
         editDialog.NewNode     += () => {
             var nd = new PlanningNodeModel(
                 renderer.vessel?.mainBody ?? FlightGlobals.GetHomeBody(),
                 renderer.vessel);
             PlanningNodesManager.Instance.nodes.Add(nd);
             editNode(nd);
         };
         editDialog.DeleteNode += () => {
             PlanningNodesManager.Instance.nodes.Remove(editDialog.editingNode);
             OnNodeDeleted();
         };
         editDialog.PrevNode    += () => editNode(PlanningNodesManager.Instance.PrevNode(renderer.vessel, editDialog.editingNode));
         editDialog.NextNode    += () => editNode(PlanningNodesManager.Instance.NextNode(renderer.vessel, editDialog.editingNode));
         editDialog.BodyChanged += OnBodyChanged;
         editDialog.WarpTo      += WarpTo;
         editDialog.Show(launcher.GetAnchor());
     }
     else
     {
         // Already open, just switch to this node
         editDialog.editingNode = toEdit;
     }
 }
コード例 #3
0
 private void FixedUpdate()
 {
     if (solver != null && solver.targetBody != FlightGlobals.ActiveVessel?.targetObject as CelestialBody)
     {
         solver.targetBody = FlightGlobals.ActiveVessel?.targetObject as CelestialBody;
         editingNode.color = PlanningNodeModel.GetBodyColor(solver.targetBody);
         targeter.SetTarget(solver.targetBody?.orbitDriver);
         solver.UpdateFlightPlan();
     }
 }
コード例 #4
0
 private void WarpTo(PlanningNodeModel node)
 {
     if (TimeWarp.CurrentRate > 1)
     {
         TimeWarp.fetch.CancelAutoWarp();
         TimeWarp.SetRate(0, false);
     }
     else
     {
         TimeWarp.fetch.WarpTo(node.burnTime - WarpBuffer(node.origin, (float?)renderer.vessel?.orbit.ApA ?? 100000f));
     }
 }
コード例 #5
0
 private void Update()
 {
     if (node != null && solver != null && !solver.maneuverNodes.Contains(node))
     {
         // User deleted the node! Remove it from everything.
         PlanningNodesManager.Instance.nodes.Remove(editingNode);
         editingNode = null;
         node        = null;
         // Tell listeners to return to non-editing state
         DeleteMe?.Invoke();
     }
 }
コード例 #6
0
        /// <summary>
        /// Return the nodes for the given vessel
        /// </summary>
        /// <param name="vessel">The vessel for which to return nodes</param>
        /// <param name="includeGlobal">True to include non-vessel-specific nodes, false to omit</param>
        /// <returns>
        /// List of nodes
        /// </returns>
        public List <PlanningNodeModel> NodesFor(Vessel vessel, bool includeGlobal)
        {
            var matched = new List <PlanningNodeModel>();

            for (int i = 0; i < nodes.Count; ++i)
            {
                PlanningNodeModel nd = nodes[i];
                if (nd.vessel == vessel || (nd.vessel == null && includeGlobal))
                {
                    matched.Add(nd);
                }
            }
            return(matched);
        }
コード例 #7
0
        private void editNode(PlanningNodeModel toEdit)
        {
            if (editor != null)
            {
                StartCoroutine(editor.SwitchTo(toEdit));
            }
            if (editor == null)
            {
                editor             = gameObject.AddComponent <PlanningNodeEditor>();
                editor.canEdit     = CanEdit;
                editor.DeleteMe   += OnNodeDeleted;
                editor.CloseMe    += OnClose;
                editor.editingNode = toEdit;
            }

            openDialog(toEdit);
        }
コード例 #8
0
 private void FixedUpdate()
 {
     if (solver != null && solver.targetBody != FlightGlobals.ActiveVessel?.targetObject as CelestialBody)
     {
         solver.targetBody = FlightGlobals.ActiveVessel?.targetObject as CelestialBody;
         editingNode.color = PlanningNodeModel.GetBodyColor(solver.targetBody);
         if (canEdit)
         {
             targeter.SetTarget(solver.targetBody?.orbitDriver);
         }
         else
         {
             // targeter will call this for us if needed
             solver.UpdateFlightPlan();
         }
     }
 }
コード例 #9
0
        /// <summary>
        /// Start editing a different node
        /// </summary>
        /// <param name="newNode">The node to edit</param>
        /// <returns>
        /// This is a coroutine because we want to give the stock objects one
        /// frame to update themselves before we create a new maneuver node
        /// </returns>
        public IEnumerator SwitchTo(PlanningNodeModel newNode)
        {
            DestroyNode();

            editingNode = newNode;

            driver.orbit.SetOrbit(
                editingNode.origin.orbit.inclination,
                editingNode.origin.orbit.eccentricity,
                editingNode.origin.orbit.semiMajorAxis,
                editingNode.origin.orbit.LAN,
                editingNode.origin.orbit.argumentOfPeriapsis,
                editingNode.origin.orbit.meanAnomalyAtEpoch,
                editingNode.origin.orbit.epoch,
                editingNode.origin.orbit.referenceBody
                );

            yield return(new WaitForEndOfFrame());

            node = solver.AddManeuverNode(editingNode.burnTime);
            // Don't need to update plan for zero dV (new) node
            if (editingNode.deltaV != node.DeltaV)
            {
                node.DeltaV = editingNode.deltaV;
                solver.UpdateFlightPlan();
            }
            if (canEdit)
            {
                node.AttachGizmo(MapView.ManeuverNodePrefab, conicRenderer);
                node.attachedGizmo.OnGizmoUpdated += OnGizmoUpdated;
            }

            // Hide the first orbit because it's already drawn with the original planet
            // and if drawn again it will be gold and distracting because PatchedConicRenderer
            // assumes that any orbit with a vessel that isn't the active vessel is the target
            var pr = conicRenderer.patchRenders[0];

            pr.lineWidth = 0;
            pr.MakeVector();

            ZoomTo();
        }
コード例 #10
0
        /// <summary>
        /// Find the planning node for the given vessel and body
        /// that is the closest to the needed excess V
        /// </summary>
        /// <param name="vessel">The vessel we're piloting</param>
        /// <param name="body">The body we're escaping</param>
        /// <returns>
        /// Which node is the closest, if any
        /// </returns>
        public PlanningNodeModel ClosestExcessV(Vessel vessel, CelestialBody body)
        {
            var nodes = NodesFor(vessel, true);
            PlanningNodeModel best     = null;
            double?           bestDiff = null;

            for (int i = 0; i < nodes.Count; ++i)
            {
                var nd = nodes[i];
                if (nd.origin == body)
                {
                    var escPat  = nd.escapePatch(vessel);
                    var excessV = escPat.getOrbitalVelocityAtUT(escPat.EndUT).xzy;
                    var diff    = (nd.BurnExcessV() - excessV).sqrMagnitude;
                    if (!bestDiff.HasValue || diff < bestDiff.Value)
                    {
                        best     = nd;
                        bestDiff = diff;
                    }
                }
            }
            return(best);
        }
コード例 #11
0
        /// <summary>
        /// Initialize the dialog
        /// </summary>
        /// <param name="nodeToEdit">The node we'll be editing</param>
        /// <param name="canEdit">True if we can open the maneuver node editing tools, false otherwise</param>
        public PlanningNodeEditDialog(PlanningNodeModel nodeToEdit, bool canEdit)
            : base(-1, -1, pad, new RectOffset(4, 4, 4, 4), TextAnchor.UpperLeft)
        {
            editingNode = nodeToEdit;

            var toprow = new List <DialogGUIBase>()
            {
                TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                   "PlanningNode_DeleteButtonCaption",
                                                   () => DeleteNode?.Invoke(),
                                                   buttonWidth, buttonHeight,
                                                   false
                                                   )
                {
                    tooltipText = "PlanningNode_DeleteButtonTooltip"
                }),
                new DialogGUIFlexibleSpace(),
                TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                   "PlanningNode_CloseButtonCaption",
                                                   () => CloseDialog?.Invoke(),
                                                   buttonWidth, buttonHeight,
                                                   false
                                                   )
                {
                    tooltipText = "PlanningNode_CloseButtonTooltip"
                })
            };

            if (canEdit)
            {
                toprow.Insert(0, TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                                    "PlanningNode_NewButtonCaption",
                                                                    () => NewNode?.Invoke(),
                                                                    buttonWidth, buttonHeight,
                                                                    false
                                                                    )
                {
                    tooltipText = "PlanningNode_NewButtonTooltip"
                }));
            }
            AddChild(new DialogGUIHorizontalLayout(
                         -1, -1, 8, new RectOffset(0, 0, 0, 0), TextAnchor.MiddleLeft,
                         toprow.ToArray()
                         ));
            AddChild(new DialogGUIHorizontalLayout(
                         -1, -1, pad, new RectOffset(0, 0, 0, 0), TextAnchor.MiddleLeft,
                         new DialogGUILabel("PlanningNode_NameLabelCaption", buttonWidth / 2),
                         NotifyOnFocus(new DialogGUITextInput(
                                           editingNode.name,
                                           false,
                                           24,
                                           s => { return(editingNode.name = s); },
                                           () => { return(editingNode.name); },
                                           TMP_InputField.ContentType.Standard,
                                           buttonHeight
                                           ),
                                       // Don't trigger other parts of the game while they're typing a name in the text field
                                       v => InputLockManager.SetControlLock(MyLocks, "PlanningNodeEditDialogName"),
                                       v => InputLockManager.RemoveControlLock("PlanningNodeEditDialogName")
                                       ),
                         TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                            "PlanningNode_PrevNodeCaption",
                                                            () => PrevNode?.Invoke(),
                                                            smallBtnWidth, buttonHeight,
                                                            false
                                                            )
            {
                tooltipText = canEdit ? "PlanningNode_PrevNodeTooltip" : "PlanningNode_PrevNodeViewOnlyTooltip"
            }),
                         TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                            "PlanningNode_NextNodeCaption",
                                                            () => NextNode?.Invoke(),
                                                            smallBtnWidth, buttonHeight,
                                                            false
                                                            )
            {
                tooltipText = canEdit ? "PlanningNode_NextNodeTooltip" : "PlanningNode_NextNodeViewOnlyTooltip"
            })
                         ));
            AddChild(new DialogGUIHorizontalLayout(
                         -1, -1, pad, new RectOffset(0, 0, 0, 0), TextAnchor.MiddleLeft,
                         new DialogGUILabel("PlanningNode_HueLabelCaption", buttonWidth / 2),
                         new DialogGUISlider(
                             () => {
                if (editingNode != null)
                {
                    Color.RGBToHSV(editingNode.color, out float hue, out float _, out float _);
                    return(hue);
                }
                return(0f);
            },
                             0f, 1f, false, -1, buttonHeight,
                             v => {
                if (editingNode != null)
                {
                    editingNode.color = Color.HSVToRGB(v, 0.5f, 0.75f);
                }
            }
                             )
                         ));
            if (canEdit)
            {
                AddChild(new DialogGUIHorizontalLayout(
                             -1, -1, pad, new RectOffset(0, 0, 0, 0), TextAnchor.MiddleLeft,
                             new DialogGUILabel("PlanningNode_BodyLabelCaption", buttonWidth / 2),
                             new DialogGUILabel(
                                 () => editingNode.origin.bodyName,
                                 -1
                                 ),
                             TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                                "PlanningNode_PrevBodyCaption",
                                                                () => BodyChanged?.Invoke(prevBody(editingNode.origin)),
                                                                smallBtnWidth, buttonHeight,
                                                                false
                                                                )
                {
                    tooltipText = "PlanningNode_PrevBodyTooltip"
                }),
                             TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                                "PlanningNode_NextBodyCaption",
                                                                () => BodyChanged?.Invoke(nextBody(editingNode.origin)),
                                                                smallBtnWidth, buttonHeight,
                                                                false
                                                                )
                {
                    tooltipText = "PlanningNode_NextBodyTooltip"
                })
                             ));
                AddChild(TooltipExtensions.DeferTooltip(new DialogGUIToggle(
                                                            () => editingNode.vessel == null,
                                                            "PlanningNode_ShowForAllCheckboxCaption",
                                                            b => { editingNode.vessel = b ? null : FlightGlobals.ActiveVessel; }
                                                            )
                {
                    tooltipText = "PlanningNode_ShowForAllCheckboxTooltip"
                }));
            }
            AddChild(TooltipExtensions.DeferTooltip(new DialogGUIButton(
                                                        "PlanningNode_WarpToCaption",
                                                        () => WarpTo?.Invoke(editingNode),
                                                        buttonWidth, buttonHeight,
                                                        false
                                                        )
            {
                tooltipText = "PlanningNode_WarpToTooltip"
            }));

            // Don't try to plot a maneuver from the Sun
            for (int i = 0; i < FlightGlobals.Bodies.Count; ++i)
            {
                var b = FlightGlobals.Bodies[i];
                if (b.referenceBody != null && b.referenceBody != b)
                {
                    allowedBodies.Add(b);
                }
            }
        }
コード例 #12
0
 private void MarkerClicked(PlanningNodeModel whichNode)
 {
     EditNode?.Invoke(whichNode);
 }