public link_data ComputeLink(Vessel v, HashSet <Guid> avoid_inf_recursion) { // if it has no antenna if (antennas[v.id].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(v)) { return(new link_data(false, link_status.no_link, 0.0)); } // check for direct link // note: we also get distance from the cache and store it in the link double direct_visible_dist = direct_visibility_cache[v.id]; bool direct_visible = direct_visible_dist > 0.0; if (direct_visible) { return(new link_data(true, link_status.direct_link, direct_visible_dist)); } // avoid infinite recursion avoid_inf_recursion.Add(v.id); // get antenna data antenna_data v_ad = antennas[v.id]; // check for indirect link foreach (Vessel w in FlightGlobals.Vessels) { // skip invalid vessels if (!Lib.IsVessel(w)) { continue; } // avoid infinite recursion if (avoid_inf_recursion.Contains(w.id)) { continue; } // avoid testing against itself if (v == w) { continue; } // get antenna data antenna_data w_ad = antennas[w.id]; // check for indirect link to home body // note: we also get distance from the cache // note: we check the relay range, that is asymmetric double indirect_visible_dist = indirect_visibility_cache[Lib.CombineGuid(v.id, w.id)]; bool indirect_visible = indirect_visible_dist > 0.0 && indirect_visible_dist < Math.Min(v_ad.range, w_ad.relay_range); if (indirect_visible) { // check link to home body, recursively link_data next_link = ComputeLink(w, avoid_inf_recursion); // if indirectly linked if (next_link.linked) { // flag the relay for ec consumption, but only once if (!active_relays.ContainsKey(w.id)) { active_relays.Add(w.id, w_ad.relay_cost); } // update the link data and return it next_link.status = link_status.indirect_link; next_link.distance = indirect_visible_dist; //< store distance of last link next_link.path.Add(w.vesselName); next_link.path_id.Add(w.id); return(next_link); } } } // no link return(new link_data(false, link_status.no_link, 0.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)); }
// 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); } } }
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 // 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 resque mission vessel is_resque = Lib.IsResqueMission(v); if (is_resque) return; // dead EVA are not valid vessels if (v.isEVA && EVA.KerbalData(v).eva_dead) 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 once position = Lib.VesselPosition(v); // 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; // if the orbit length vs simulation step is lower than an acceptable threshold, use discrete sun visibility if (v.mainBody.flightGlobalsIndex != 0) { double orbit_period = Sim.OrbitalPeriod(v); if (orbit_period / Kerbalism.elapsed_s < 16.0) sunlight = 1.0 - Sim.ShadowPeriod(v) / orbit_period; } // calculate environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); breathable = Sim.Breathable(v); landed = Lib.Landed(v); // calculate temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); // calculate radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out inside_pause, out inside_belt); // calculate malfunction stuff max_malfunction = Reliability.MaxMalfunction(v); avg_quality = Reliability.AverageQuality(v); // calculate signal info antenna = new antenna_data(v); avoid_inf_recursion.Add(v.id); link = Signal.Link(v, position, antenna, blackout, avoid_inf_recursion); avoid_inf_recursion.Remove(v.id); // partial data about modules, used by vessel info/monitor scrubbers = Scrubber.PartialData(v); recyclers = Recycler.PartialData(v); greenhouses = Greenhouse.PartialData(v); // woot relativity time_dilation = Sim.TimeDilation(v); }