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)); } }
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); }