Пример #1
0
        public static link_data Link(Vessel v, Vector3d position, antenna_data antenna, bool blackout, HashSet <Guid> avoid_inf_recursion)
        {
            // assume linked if signal mechanic is disabled
            if (!Kerbalism.features.signal)
            {
                return(new link_data(true, link_status.direct_link, double.MaxValue));
            }

            // if it has no antenna
            if (antenna.range <= double.Epsilon)
            {
                return(new link_data(false, link_status.no_antenna, 0.0));
            }

            // if there is a storm and the vessel is inside a magnetosphere
            if (blackout)
            {
                return(new link_data(false, link_status.no_link, 0.0));
            }

            // store raytracing data
            Vector3d dir;
            double   dist;
            bool     visible;

            // raytrace home body
            visible = Sim.RaytraceBody(v, position, FlightGlobals.GetHomeBody(), out dir, out dist);
            dist    = visible && antenna.range > dist ? dist : double.MaxValue;

            // if directly linked
            if (antenna.range > dist)
            {
                return(new link_data(true, link_status.direct_link, dist));
            }

            // for each other vessel
            foreach (Vessel w in FlightGlobals.Vessels)
            {
                // do not test with itself
                if (v == w)
                {
                    continue;
                }

                // skip vessels already in this chain
                if (avoid_inf_recursion.Contains(w.id))
                {
                    continue;
                }

                // get vessel from the cache
                // note: safe because we are avoiding infinite recursion
                vessel_info wi = Cache.VesselInfo(w);

                // skip invalid vessels
                if (!wi.is_valid)
                {
                    continue;
                }

                // skip non-relays and non-linked relays
                if (wi.antenna.relay_range <= double.Epsilon || !wi.link.linked)
                {
                    continue;
                }

                // raytrace the other vessel
                visible = Sim.RaytraceVessel(v, w, position, wi.position, out dir, out dist);
                dist    = visible && antenna.range > dist ? dist : double.MaxValue;

                // if indirectly linked
                // note: relays with no EC have zero relay_range
                // note: avoid relay loops
                if (antenna.range > dist && wi.antenna.relay_range > dist && !wi.link.path.Contains(v))
                {
                    // create indirect link data
                    link_data link = new link_data(wi.link);

                    // update the link data and return it
                    link.status   = link_status.indirect_link;
                    link.distance = dist; //< store distance of last link
                    link.path.Add(w);
                    return(link);
                }
            }

            // no link
            return(new link_data(false, link_status.no_link, 0.0));
        }
Пример #2
0
        // build the visibility caches
        void BuildVisibility()
        {
            // get home body
            CelestialBody home = FlightGlobals.GetHomeBody();

            // build direct visibility cache
            direct_visibility_cache.Clear();
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // get antenna data
                antenna_data ad = antennas[v.id];

                // raytrace home body
                Vector3d dir;
                double   dist    = 0.0;
                bool     visible = Sim.RaytraceBody(v, home, out dir, out dist);
                dist = Math.Abs(dist); //< avoid problem below water level

                // store in visibility cache
                // note: we store distance & visibility flag at the same time
                direct_visibility_cache.Add(v.id, visible && dist < ad.range ? dist : 0.0);
            }


            // build indirect visibility cache
            indirect_visibility_cache.Clear();
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // get antenna data
                antenna_data v_ad = antennas[v.id];

                // for each vessel
                foreach (Vessel w in FlightGlobals.Vessels)
                {
                    // skip invalid vessels
                    if (!Lib.IsVessel(w))
                    {
                        continue;
                    }

                    // do not test with itself
                    if (v == w)
                    {
                        continue;
                    }

                    // do not compute visibility when both vessels have a direct link
                    // rationale: optimization, the indirect visibility it never used in this case
                    if (direct_visibility_cache[v.id] > double.Epsilon && direct_visibility_cache[w.id] > double.Epsilon)
                    {
                        continue;
                    }

                    // generate merged guid
                    Guid id = Lib.CombineGuid(v.id, w.id);

                    // avoid raycasting the same pair twice
                    if (indirect_visibility_cache.ContainsKey(id))
                    {
                        continue;
                    }

                    // get antenna data
                    antenna_data w_ad = antennas[w.id];

                    // raytrace the vessel
                    Vector3d dir;
                    double   dist    = 0.0;
                    bool     visible = Sim.RaytraceVessel(v, w, out dir, out dist);

                    // store visibility in cache
                    // note: we store distance & visibility flag at the same time
                    // note: relay visibility is asymmetric, done at link build time
                    indirect_visibility_cache.Add(id, visible && dist < Math.Min(v_ad.range, w_ad.range) ? dist : 0.0);
                }
            }
        }
Пример #3
0
        public static ConnectionInfo connection(Vessel v, Vector3d position, AntennaInfo antenna, bool blackout, HashSet <Guid> avoid_inf_recursion)
        {
            // if signal mechanic is disabled, use RemoteTech/CommNet/S4
            if (!Features.Signal)
            {
                return(OtherComms(v));
            }

            // if it has no antenna
            if (antenna.no_antenna)
            {
                return(new ConnectionInfo(LinkStatus.no_antenna));
            }

            // if there is a storm and the vessel is inside a magnetosphere
            if (blackout)
            {
                return(new ConnectionInfo(LinkStatus.blackout));
            }

            // store raytracing data
            Vector3d dir;
            double   dist;
            bool     visible;

            // store other data
            double rate;
            List <ConnectionInfo> connections = new List <ConnectionInfo>();

            // raytrace home body
            visible = Sim.RaytraceBody(v, position, FlightGlobals.GetHomeBody(), out dir, out dist);

            // get rate
            rate = antenna.direct_rate(dist);

            // if directly linked
            if (visible && rate > Settings.ControlRate)
            {
                ConnectionInfo conn = new ConnectionInfo(LinkStatus.direct_link, rate, antenna.direct_cost);
                connections.Add(conn);
            }

            // for each other vessel
            foreach (Vessel w in FlightGlobals.Vessels)
            {
                // do not test with itself
                if (v == w)
                {
                    continue;
                }

                // skip vessels already in this chain
                if (avoid_inf_recursion.Contains(w.id))
                {
                    continue;
                }

                // get vessel from the cache
                // - when:
                //   . cache is empty (eg: new savegame loaded)
                // - we avoid single-tick wrong paths arising from this situation:
                //   . vessel A is directly linked
                //   . vessel B is indirectly linked through A
                //   . cache is cleared (after loading a savegame)
                //   . cache of A is computed
                //   . in turn, cache of B is computed ignoring A (and stored)
                //   . until cache of B is re-computed, B will result incorrectly not linked
                // - in this way:
                //   . cache of A is computed
                //   . in turn, cache of B is computed ignoring A (but not stored)
                //   . cache of B is then computed correctly
                //   . do not degenerate into O(N^3) by using non-optimal path
                vessel_info wi;
                if (!Cache.HasVesselInfo(w, out wi))
                {
                    if (connections.Count > 0)
                    {
                        continue;
                    }
                    else
                    {
                        wi = new vessel_info(w, Lib.VesselID(w), 0);
                    }
                }

                // skip invalid vessels
                if (!wi.is_valid)
                {
                    continue;
                }

                // skip non-relays and non-linked relays
                if (!wi.antenna.is_relay || !wi.connection.linked)
                {
                    continue;
                }

                // raytrace the other vessel
                visible = Sim.RaytraceVessel(v, w, position, Lib.VesselPosition(w), out dir, out dist);

                // get rate
                rate = antenna.indirect_rate(dist, wi.antenna);

                // if indirectly linked
                // - relays with no EC have zero relay_range
                // - avoid relay loops
                if (visible && rate > Settings.ControlRate && !wi.connection.path.Contains(v))
                {
                    // create indirect link data
                    ConnectionInfo conn = new ConnectionInfo(wi.connection);

                    // update the link data and return it
                    conn.status = LinkStatus.indirect_link;
                    conn.rate   = Math.Min(conn.rate, rate);
                    conn.cost   = antenna.indirect_cost;
                    conn.path.Add(w);
                    connections.Add(conn);
                }
            }

            // if at least a connection has been found
            if (connections.Count > 0)
            {
                // select the best connection
                double best_rate  = 0.0;
                int    best_index = 0;
                for (int i = 0; i < connections.Count; ++i)
                {
                    if (connections[i].rate > best_rate)
                    {
                        best_rate  = connections[i].rate;
                        best_index = i;
                    }
                }

                // and return it
                return(connections[best_index]);
            }

            // no link
            return(new ConnectionInfo(LinkStatus.no_link));
        }