static ConnectionInfo OtherComms(Vessel v, KAntennaInfo antenna, HashSet <Guid> avoid_inf_recursion)
        {
            // hard-coded transmission rate and cost
            const double ext_rate = 0.064;
            const double ext_cost = 0.1;

            // if RemoteTech is present and enabled
            if (RemoteTech.Enabled())
            {
                return(RemoteTech.Connected(v.id)
        ? new ConnectionInfo(LinkStatus.direct_link, ext_rate, ext_cost)
        : new ConnectionInfo(LinkStatus.no_link));
            }
            // if CommNet is enabled
            else if (Features.KCommNet)
            {
                return(v.connection != null && v.connection.IsConnected
        ? new ConnectionInfo(LinkStatus.direct_link, ext_rate * v.connection.SignalStrength, ext_cost)
        : new ConnectionInfo(LinkStatus.no_link));
            }
            // the simple stupid signal system
            else
            {
                return(new ConnectionInfo(LinkStatus.direct_link, ext_rate, ext_cost));
            }
        }
Example #2
0
        public double Indirect_Rate(double d, KAntennaInfo relay_antenna)
        {
            double r = 0.0;

            for (int i = 0; i < type.Count; ++i)
            {
                if (type[i] == KAntennaType.low_gain)
                {
                    r += Antenna.Calculate_Rate(d, dist[i], rate[i]);
                }
            }

            double indirect_r = 0.0;

            for (int i = 0; i < relay_antenna.type.Count; ++i)
            {
                if (relay_antenna.type[i] == KAntennaType.low_gain && relay_antenna.relay[i])
                {
                    indirect_r += Antenna.Calculate_Rate(d, relay_antenna.dist[i], relay_antenna.rate[i]);
                }
            }

            return(Math.Min(r, indirect_r));
        }
        public static ConnectionInfo Connection(Vessel v, Vector3d position, KAntennaInfo antenna, bool blackout, HashSet <Guid> avoid_inf_recursion)
        {
            // if signal mechanic is disabled, use RemoteTech/CommNet/S4
            if (!Features.Signal)
            {
                return(OtherComms(v, antenna, avoid_inf_recursion));
            }

            // 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
            bool visible;

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

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

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

            // if directly linked
            if (visible && rate > 0.0)
            {
                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
                if (!Cache.HasVesselInfo(w, out Vessel_Info 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.kAntenna.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.kAntenna);

                // if indirectly linked
                // - relays with no EC have zero relay_range
                // - avoid relay loops
                if (visible && rate > 0.0 && !wi.connection.path.Contains(v))
                {
                    // create indirect link data
                    ConnectionInfo conn = new ConnectionInfo(wi.connection)
                    {
                        // update the link data and return it
                        status = LinkStatus.indirect_link,
                        cost   = antenna.indirect_cost
                    };

                    conn.rate = Math.Min(conn.rate, rate);
                    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));
        }
        // ctor
        public Vessel_Info(Vessel v, uint vessel_id, UInt64 inc)
        {
            // NOTE: anything used here can't in turn use cache, unless you know what you are doing

            // NOTE: you can't cache vessel position
            //  at any point in time all vessel/body positions are relative to a different frame of reference
            //  so comparing the current position of a vessel, with the cached one of another make no sense

            // associate with an unique incremental id
            this.inc = inc;

            // determine if this is a valid vessel
            is_vessel = Lib.IsVessel(v);

            if (!is_vessel)
            {
                return;
            }

            // determine if this is a rescue mission vessel
            is_rescue = Misc.IsRescueMission(v);
            if (is_rescue)
            {
                return;
            }

            // dead EVA are not valid vessels
            if (EVA.IsDead(v))
            {
                return;
            }

            // shortcut for common tests
            is_valid = true;

            // generate id once
            id = vessel_id;

            // calculate crew info for the vessel
            crew_count    = Lib.CrewCount(v);
            crew_capacity = Lib.CrewCapacity(v);

            // get vessel position
            Vector3d position = Lib.VesselPosition(v);

            // this should never happen again
            if (Vector3d.Distance(position, v.mainBody.position) < 1.0)
            {
                throw new Exception("Shit hit the fan for vessel " + v.vesselName);
            }

            // determine if in sunlight, calculate sun direction and distance
            sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

            // at the two highest timewarp speed, the number of sun visibility samples drop to the point that
            // the quantization error first became noticeable, and then exceed 100%
            // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight
            // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending
            if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f)
            {
                sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v);
            }

            // environment stuff
            atmo_factor        = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
            gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
            underwater         = Sim.Underwater(v);
            breathable         = Sim.Breathable(v, underwater);
            landed             = Lib.Landed(v);

            // temperature at vessel position
            temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);
            temp_diff   = Sim.TempDiff(temperature, v.mainBody, landed);

            // radiation
            radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar);

            // extended atmosphere
            thermosphere = Sim.InsideThermosphere(v);
            exosphere    = Sim.InsideExosphere(v);

            // malfunction stuff
            malfunction = Reliability.HasMalfunction(v);
            critical    = Reliability.HasCriticalFailure(v);

            // signal info
            if (Features.KCommNet)
            {
                antenna = Cache.AntennaInfo(v);
                avoid_inf_recursion.Add(v.id);
            }
            else
            {
                kAntenna = new KAntennaInfo(v);
                avoid_inf_recursion.Add(v.id);
            }
            // TODO: Need to create a Signal integrated with CommNet
            connection   = Signal.Connection(v, position, kAntenna, blackout, avoid_inf_recursion);
            transmitting = Science.Transmitting(v, connection.linked);
            relaying     = Signal.Relaying(v, avoid_inf_recursion);
            avoid_inf_recursion.Remove(v.id);

            // habitat data
            volume       = Habitat.Total_Volume(v);
            surface      = Habitat.Total_Surface(v);
            pressure     = Habitat.Pressure(v);
            poisoning    = Habitat.Poisoning(v);
            shielding    = Habitat.Shielding(v);
            living_space = Habitat.Living_Space(v);
            comforts     = new Comforts(v, landed, crew_count > 1, true); // TODO: replace 'true' for connection.linked

            // data about greenhouses
            greenhouses = Greenhouse.Greenhouses(v);

            // other stuff
            gravioli = Sim.Graviolis(v);
        }