// calculate a cache entry for the vessel static vessel_info Compute(Vessel v) { vessel_info info = new vessel_info(); info.position = Lib.VesselPosition(v); info.sunlight = Sim.RaytraceBody(v, Sim.Sun(), out info.sun_dir, out info.sun_dist); info.temperature = Sim.Temperature(v, info.sunlight); info.cosmic_radiation = Radiation.CosmicRadiation(v); info.belt_radiation = Radiation.BeltRadiation(v); info.storm_radiation = Radiation.StormRadiation(v, info.sunlight); info.env_radiation = info.cosmic_radiation + info.belt_radiation + info.storm_radiation; info.breathable = Sim.Breathable(v); foreach(var p in Kerbalism.rules) { Rule r = p.Value; if (r.resource_name.Length > 0) { var vmon = new vmon_cache(); vmon.depletion = r.EstimateLifetime(v); double amount = Lib.GetResourceAmount(v, r.resource_name); double capacity = Lib.GetResourceCapacity(v, r.resource_name); vmon.level = capacity > double.Epsilon ? amount / capacity : 1.0; //< level is 1 with no capacity info.vmon.Add(p.Value.name, vmon); } } return info; }
// get vessel info from the cache, or compute a new one and add it to the cache public static vessel_info VesselInfo(Vessel v) { // get the info from the cache, if it exist vessel_info info; if (instance.vessels.TryGetValue(v.id, out info)) return info; // compute vessel info info = new vessel_info(); info.position = Lib.VesselPosition(v); info.sunlight = Sim.RaytraceBody(v, Sim.Sun(), out info.sun_dir, out info.sun_dist); info.temperature = Sim.Temperature(v, info.sunlight); info.cosmic_radiation = Radiation.CosmicRadiation(v); info.belt_radiation = Radiation.BeltRadiation(v); info.storm_radiation = Radiation.StormRadiation(v, info.sunlight); info.radiation = (info.cosmic_radiation + info.belt_radiation + info.storm_radiation) * (1.0 - Radiation.Shielding(v)); // store vessel info in the cache instance.vessels.Add(v.id, info); // return the vessel info return info; }
public Vessel_info(Vessel v, UInt64 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 there is enough EC for a powered state powered = ResourceCache.Info(v, "ElectricCharge").amount > double.Epsilon; // 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; // 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); zerog = !landed && (!v.mainBody.atmosphere || v.mainBody.atmosphereDepth < v.altitude); if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f) { highspeedWarp(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); // communications info connection = new ConnectionInfo(v, powered, blackout); transmitting = Science.Transmitting(v, connection.linked && connection.rate > double.Epsilon); // habitat data volume = Habitat.Tot_volume(v); surface = Habitat.Tot_surface(v); pressure = Habitat.Pressure(v); evas = (uint)(Math.Max(0, ResourceCache.Info(v, "Nitrogen").amount - 330) / PreferencesLifeSupport.Instance.evaAtmoLoss); poisoning = Habitat.Poisoning(v); humidity = Habitat.Humidity(v); shielding = Habitat.Shielding(v); living_space = Habitat.Living_space(v); volume_per_crew = Habitat.Volume_per_crew(v); comforts = new Comforts(v, landed, crew_count > 1, connection.linked && connection.rate > double.Epsilon); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }
// 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 // 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 antenna = new AntennaInfo(v); avoid_inf_recursion.Add(v.id); connection = Signal.connection(v, position, antenna, 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.tot_volume(v); surface = Habitat.tot_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, connection.linked); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }
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)); }
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)); }
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); }