public void RenderMarkers(DisposableIterator apsis_iterator,
                                      MapObject.ObjectType type,
                                      NodeSource source,
                                      Vessel vessel,
                                      CelestialBody celestial)
            {
                // We render at most 64 markers of one type and one provenance (e.g., at
                // most 64 perilunes for the prediction of the active vessel).  This is
                // more than is readable, and keeps the size of the map node pool under
                // control.
                for (int i = 0; i < 64 && !apsis_iterator.IteratorAtEnd();
                     ++i, apsis_iterator.IteratorIncrement())
                {
                    QP apsis = apsis_iterator.IteratorGetDiscreteTrajectoryQP();
                    MapNodeProperties node_properties = new MapNodeProperties {
                        visible        = true,
                        object_type    = type,
                        vessel         = vessel,
                        celestial      = celestial,
                        world_position = (Vector3d)apsis.q,
                        velocity       = (Vector3d)apsis.p,
                        source         = source,
                        time           = apsis_iterator.IteratorGetDiscreteTrajectoryTime()
                    };

                    if (pool_index_ == nodes_.Count)
                    {
                        nodes_.Add(MakePoolNode());
                    }
                    else if (properties_[nodes_[pool_index_]].object_type != type ||
                             properties_[nodes_[pool_index_]].source != source)
                    {
                        // KSP attaches labels to its map nodes, but never detaches them.
                        // If the node changes type, we end up with an arbitrary combination of
                        // labels Ap, Pe, AN, DN.
                        // If the node changes source, the colour of the icon label is not
                        // updated to match the icon (making it unreadable in some cases).
                        // Recreating the node entirely takes a long time (approximately
                        // 𝑁 * 70 μs, where 𝑁 is the total number of map nodes in existence),
                        // instead we manually get rid of the labels.
                        foreach (var component in
                                 nodes_[pool_index_].transform.GetComponentsInChildren <
                                     TMPro.TextMeshProUGUI>())
                        {
                            if (component.name == "iconLabel(Clone)")
                            {
                                UnityEngine.Object.Destroy(component.gameObject);
                            }
                        }
                        // Ensure that KSP thinks the type changed, and reattaches icon
                        // labels next time around, otherwise we might end up with no labels.
                        // Null nodes do not have a label, so inducing a type change through
                        // Null does not result in spurious labels.
                        properties_[nodes_[pool_index_]].object_type =
                            MapObject.ObjectType.Null;
                        nodes_[pool_index_].NodeUpdate();
                    }
                    properties_[nodes_[pool_index_++]] = node_properties;
                }
            }
Exemple #2
0
            public void RenderMarkers(DisposableIterator apsis_iterator,
                                      MapObject.ObjectType type,
                                      NodeSource source,
                                      Vessel vessel,
                                      CelestialBody celestial)
            {
                for (; !apsis_iterator.IteratorAtEnd();
                     apsis_iterator.IteratorIncrement())
                {
                    QP apsis = apsis_iterator.IteratorGetDiscreteTrajectoryQP();
                    MapNodeProperties node_properties;
                    node_properties.object_type    = type;
                    node_properties.vessel         = vessel;
                    node_properties.celestial      = celestial;
                    node_properties.world_position = (Vector3d)apsis.q;
                    node_properties.velocity       = (Vector3d)apsis.p;
                    node_properties.source         = source;
                    node_properties.time           = apsis_iterator.IteratorGetDiscreteTrajectoryTime();

                    if (pool_index_ == nodes_.Count)
                    {
                        nodes_.Add(MakePoolNode());
                    }
                    else if (properties_[nodes_[pool_index_]].object_type != type)
                    {
                        // Do not reuse a node for different types, as this results in
                        // overlapping labels on KSP 1.3, e.g. a closest approach marker that
                        // also says "Ap" and "DN".
                        nodes_[pool_index_].Terminate();
                        properties_.Remove(nodes_[pool_index_]);
                        nodes_[pool_index_] = MakePoolNode();
                    }
                    properties_[nodes_[pool_index_++]] = node_properties;
                }
            }
Exemple #3
0
            public void RenderMarkers(DisposableIterator apsis_iterator,
                                      MapObject.ObjectType type,
                                      NodeSource source,
                                      ReferenceFrameSelector reference_frame)
            {
                MapObject associated_map_object;

                UnityEngine.Color colour;
                switch (type)
                {
                case MapObject.ObjectType.Apoapsis:
                case MapObject.ObjectType.Periapsis:
                    CelestialBody fixed_body = reference_frame.selected_celestial;
                    associated_map_object = fixed_body.MapObject;
                    colour = fixed_body.orbit == null
              ? XKCDColors.SunshineYellow
              : fixed_body.orbitDriver.Renderer.nodeColor;
                    break;

                case MapObject.ObjectType.ApproachIntersect:
                    associated_map_object = reference_frame.target_override.mapObject;
                    colour = XKCDColors.Chartreuse;
                    break;

                case MapObject.ObjectType.AscendingNode:
                case MapObject.ObjectType.DescendingNode:
                    if (!reference_frame.target_override &&
                        (reference_frame.frame_type ==
                         ReferenceFrameSelector.FrameType.BODY_CENTRED_NON_ROTATING ||
                         reference_frame.frame_type ==
                         ReferenceFrameSelector.FrameType.BODY_SURFACE))
                    {
                        // In one-body frames, the apsides are shown with the colour of the
                        // body.
                        // The nodes are with respect to the equator, rather than with respect
                        // to an orbit. We show the nodes in a different (but arbitrary)
                        // colour so that they can be distinguished easily.
                        associated_map_object = reference_frame.selected_celestial.MapObject;
                        colour = XKCDColors.Chartreuse;
                    }
                    else
                    {
                        // In two-body frames, if apsides are shown, they are shown with the
                        // colour of the secondary (or in XKCD chartreuse if the secondary is
                        // a vessel).
                        // The nodes are with respect to the orbit of the secondary around the
                        // primary. We show the nodes with the colour of the primary.
                        CelestialBody primary = reference_frame.target_override
              ? reference_frame.selected_celestial
              : reference_frame.selected_celestial.referenceBody;
                        associated_map_object = primary.MapObject;
                        colour = primary.orbit == null
              ? XKCDColors.SunshineYellow
              : primary.orbitDriver.Renderer.nodeColor;
                    }
                    break;

                default:
                    throw Log.Fatal($"Unexpected type {type}");
                }
                colour.a = 1;

                for (int i = 0; i < MaxRenderedNodes && !apsis_iterator.IteratorAtEnd();
                     ++i, apsis_iterator.IteratorIncrement())
                {
                    QP apsis = apsis_iterator.IteratorGetDiscreteTrajectoryQP();
                    MapNodeProperties node_properties = new MapNodeProperties {
                        visible               = true,
                        object_type           = type,
                        colour                = colour,
                        reference_frame       = reference_frame,
                        world_position        = (Vector3d)apsis.q,
                        velocity              = (Vector3d)apsis.p,
                        source                = source,
                        time                  = apsis_iterator.IteratorGetDiscreteTrajectoryTime(),
                        associated_map_object = associated_map_object,
                    };
                    if (type == MapObject.ObjectType.Periapsis &&
                        reference_frame.selected_celestial.GetAltitude(
                            node_properties.world_position) < 0)
                    {
                        node_properties.object_type = MapObject.ObjectType.PatchTransition;
                        node_properties.colour      = XKCDColors.Orange;
                    }

                    if (pool_index_ == nodes_.Count)
                    {
                        nodes_.Add(MakePoolNode());
                    }
                    else if (properties_[nodes_[pool_index_]].object_type !=
                             node_properties.object_type ||
                             properties_[nodes_[pool_index_]].colour !=
                             node_properties.colour)
                    {
                        // KSP attaches labels to its map nodes, but never detaches them.
                        // If the node changes type, we end up with an arbitrary combination of
                        // labels Ap, Pe, AN, DN.
                        // Similarly, if the node changes colour, the colour of the icon label
                        // is not updated to match the icon (making it unreadable in some
                        // cases).  Recreating the node entirely takes a long time
                        // (approximately 𝑁 * 70 μs, where 𝑁 is the total number of map nodes
                        // in existence), instead we manually get rid of the labels.
                        foreach (var component in
                                 nodes_[pool_index_].transform.GetComponentsInChildren <
                                     TMPro.TextMeshProUGUI>())
                        {
                            if (component.name == "iconLabel(Clone)")
                            {
                                UnityEngine.Object.Destroy(component.gameObject);
                            }
                        }
                        // Ensure that KSP thinks the type changed, and reattaches icon
                        // labels next time around, otherwise we might end up with no labels.
                        // Null nodes do not have a label, so inducing a type change through
                        // Null does not result in spurious labels.  Note that the type is
                        // updated only if the node is visible.
                        properties_[nodes_[pool_index_]].visible     = true;
                        properties_[nodes_[pool_index_]].object_type =
                            MapObject.ObjectType.Null;
                        nodes_[pool_index_].NodeUpdate();
                    }
                    properties_[nodes_[pool_index_++]] = node_properties;
                }
            }
       private static extern void SetVesselStateOffset(
 IntPtr plugin,
 [MarshalAs(UnmanagedType.LPStr)] String vessel_guid,
 QP from_parent);
       private static extern void InsertCelestial(
 IntPtr plugin,
 int celestial_index,
 double gravitational_parameter,
 int parent_index,
 QP from_parent);
Exemple #6
0
        public override TJCRDIR Dir(string file)
        {
            QuickStream BT = null;

            try {
                BT = QuickStream.ReadFile(file);
                var    ret = new TJCRDIR();
                string s;
                do
                {
                    if (BT.EOF)
                    {
                        throw new Exception("JQL heading not found!");
                    }
                    s = RL(BT);
                } while (s == "" || qstr.Prefixed(s, "#"));
                if (s != "JQL")
                {
                    throw new Exception("JQL not properly headed!");
                }
                var optional = true;
                var author   = "";
                var notes    = "";
                while (!BT.EOF)
                {
                    s = RL(BT);
                    var c = new QP(s);
                    if (s != "" && (!qstr.Prefixed(s, "#")))
                    {
                        switch (c.commando)
                        {
                        case "REQUIRED":
                        case "REQ":
                            optional = false;
                            break;

                        case "OPTIONAL":
                        case "OPT":
                            optional = true;
                            break;

                        case "PATCH": {
                            var to = c.parameter.IndexOf('>');
                            if (to < 0)
                            {
                                var p = JCR6.Dir(c.parameter);
                                if (p == null)
                                {
                                    if (optional)
                                    {
                                        break;
                                    }
                                    throw new Exception($"Patch error {JCR6.JERROR}");
                                }
                                ret.Patch(p);
                            }
                            else
                            {
                                var rw = c.parameter.Substring(0, to).Trim().Replace("\\", "/");
                                var tg = c.parameter.Substring(to + 1).Trim().Replace("\\", "/");
                                var p  = JCR6.Dir(rw);
                                if (p == null)
                                {
                                    if (optional)
                                    {
                                        break;
                                    }
                                    throw new Exception($"Patch error {JCR6.JERROR}");
                                }
                                ret.Patch(p, tg);
                            }
                            break;
                        }

                        case "AUTHOR":
                        case "AUT":
                            author = c.parameter;
                            break;

                        case "NOTES":
                        case "NTS":
                            notes = c.parameter;
                            break;

                        case "RAW": {
                            var p  = c.parameter.IndexOf('>');
                            var rw = c.parameter.Replace("\\", "/");
                            var tg = rw;
                            if (p >= 0)
                            {
                                rw = c.parameter.Substring(0, p).Trim().Replace("\\", "/");
                                tg = c.parameter.Substring(p + 1).Trim().Replace("\\", "/");
                            }
                            if (tg.Length > 1 && tg[1] == ':')
                            {
                                tg = tg.Substring(2);
                            }
                            while (tg[1] == '/')
                            {
                                tg = tg.Substring(1);
                            }
                            if (rw == "")
                            {
                                throw new Exception("RAW no original");
                            }
                            if (tg == "")
                            {
                                throw new Exception("RAW no target");
                            }
                            if (!File.Exists(rw))
                            {
                                if (optional)
                                {
                                    break;
                                }
                                throw new Exception($"Required raw file \"{rw}\" doesn't exist!");
                            }
                            var e = new TJCREntry();
                            e.Entry                   = tg;
                            e.MainFile                = rw;
                            e.Storage                 = "Store";
                            e.Offset                  = 0;
                            e.Size                    = (int)new FileInfo(rw).Length;
                            e.CompressedSize          = e.Size;
                            e.Notes                   = notes;
                            e.Author                  = author;
                            ret.Entries[tg.ToUpper()] = e;
                            break;
                        }

                        case "TEXT":
                        case "TXT": {
                            var tg = c.parameter.Trim().Replace("\\", "/");
                            if (tg.Length > 1 && tg[1] == ':')
                            {
                                tg = tg.Substring(2);
                            }
                            while (tg[1] == '/')
                            {
                                tg = tg.Substring(1);
                            }
                            if (tg == "")
                            {
                                throw new Exception("TEXT no target");
                            }
                            var e   = new TJCREntry();
                            var buf = new byte[5];
                            e.Entry    = tg;
                            e.MainFile = file;
                            e.Storage  = "Store";
                            e.Offset   = (int)BT.Position;
                            e.Notes    = notes;
                            e.Author   = author;
                            do
                            {
                                if (BT.EOF)
                                {
                                    throw new Exception("Unexpected end of file (TXT Block not ended)");
                                }
                                for (int i = 0; i < 4; i++)
                                {
                                    buf[i] = buf[i + 1];
                                }
                                buf[4] = BT.ReadByte();
                                //Console.WriteLine(Encoding.UTF8.GetString(buf, 0, buf.Length));
                            } while (Encoding.UTF8.GetString(buf, 0, buf.Length) != "@END@");
                            RL(BT);
                            e.Size                    = (int)(BT.Position - 7) - e.Offset;
                            e.CompressedSize          = e.Size;
                            ret.Entries[tg.ToUpper()] = e;
                            break;
                        }

                        case "COMMENT":
                        case "CMT": {
                            if (c.parameter == "")
                            {
                                throw new Exception("Comment without a name");
                            }
                            var cmt = new StringBuilder("");
                            var l   = "";
                            do
                            {
                                if (BT.EOF)
                                {
                                    throw new Exception("Unexpected end of file (COMMENT block not ended)");
                                }
                                l = RL(BT, false);
                                if (l.Trim() != "@END@")
                                {
                                    cmt.Append($"{l}\n");
                                }
                            } while (l.Trim() != "@END@");
                            ret.Comments[c.parameter] = cmt.ToString();
                            break;
                        }

                        case "IMPORT":
                            ret.PatchFile(c.parameter);
                            break;

                        case "END":
                            return(ret);

                        default: throw new Exception($"Unknown instruction! {c.commando}");
                        }
                    }
                }
                return(ret);
            } catch (Exception e) {
                JCR6.JERROR = $"JQL error: {e.Message}";
#if DEBUG
                Console.WriteLine(e.StackTrace);
#endif
                return(null);
            } finally {
                if (BT != null)
                {
                    BT.Close();
                }
            }
        }
Exemple #7
0
            public void RenderMarkers(DisposableIterator apsis_iterator,
                                      Provenance provenance,
                                      ReferenceFrameSelector reference_frame)
            {
                if (!nodes_.ContainsKey(provenance))
                {
                    nodes_.Add(provenance, new SingleProvenancePool());
                }
                var       pool = nodes_[provenance];
                MapObject associated_map_object;

                UnityEngine.Color colour;
                switch (provenance.type)
                {
                case MapObject.ObjectType.Apoapsis:
                case MapObject.ObjectType.Periapsis:
                    CelestialBody fixed_body = reference_frame.Centre();
                    associated_map_object = fixed_body.MapObject;
                    colour = fixed_body.orbit == null
                     ? XKCDColors.SunshineYellow
                     : fixed_body.orbitDriver.Renderer.nodeColor;
                    break;

                case MapObject.ObjectType.ApproachIntersect:
                    associated_map_object = reference_frame.target.mapObject;
                    colour = XKCDColors.Chartreuse;
                    break;

                case MapObject.ObjectType.AscendingNode:
                case MapObject.ObjectType.DescendingNode:
                    if (reference_frame.Centre() == null)
                    {
                        // In two-body frames, if apsides are shown, they are shown with the
                        // colour of the secondary (or in XKCD chartreuse if the secondary is
                        // a vessel).
                        // The nodes are with respect to the orbit of the secondary around the
                        // primary. We show the nodes with the colour of the primary.
                        CelestialBody primary = reference_frame.OrientingBody();
                        associated_map_object = primary.MapObject;
                        colour = primary.orbit == null
                        ? XKCDColors.SunshineYellow
                        : primary.orbitDriver.Renderer.nodeColor;
                    }
                    else
                    {
                        // In one-body frames, the apsides are shown with the colour of the
                        // body.
                        // The nodes are with respect to the equator, rather than with respect
                        // to an orbit. We show the nodes in a different (but arbitrary)
                        // colour so that they can be distinguished easily.
                        associated_map_object = reference_frame.Centre().MapObject;
                        colour = XKCDColors.Chartreuse;
                    }
                    break;

                default:
                    throw Log.Fatal($"Unexpected type {provenance.type}");
                }
                colour.a = 1;

                for (int i = 0;
                     i < MaxNodesPerProvenance && !apsis_iterator.IteratorAtEnd();
                     ++i, apsis_iterator.IteratorIncrement())
                {
                    QP apsis = apsis_iterator.IteratorGetDiscreteTrajectoryQP();
                    MapNodeProperties node_properties = new MapNodeProperties {
                        visible               = true,
                        object_type           = provenance.type,
                        colour                = colour,
                        reference_frame       = reference_frame,
                        world_position        = (Vector3d)apsis.q,
                        velocity              = (Vector3d)apsis.p,
                        source                = provenance.source,
                        time                  = apsis_iterator.IteratorGetDiscreteTrajectoryTime(),
                        associated_map_object = associated_map_object,
                    };
                    if (provenance.type == MapObject.ObjectType.Periapsis &&
                        reference_frame.Centre().GetAltitude(
                            node_properties.world_position) < 0)
                    {
                        node_properties.object_type = MapObject.ObjectType.PatchTransition;
                        node_properties.colour      = XKCDColors.Orange;
                    }

                    if (pool.nodes_used == pool.nodes.Count)
                    {
                        pool.nodes.Add(MakePoolNode());
                    }
                    properties_[pool.nodes[pool.nodes_used++]] = node_properties;
                }
            }
Exemple #8
0
 private static extern void SetVesselStateOffset(
     IntPtr plugin,
     [MarshalAs(UnmanagedType.LPStr)] String vessel_guid,
     QP from_parent);
Exemple #9
0
 private static extern void InsertCelestial(
     IntPtr plugin,
     int celestial_index,
     double gravitational_parameter,
     int parent_index,
     QP from_parent);