/// <summary> Creates a <see cref="ConnectionInfo"/> object for the specified vessel from it's antenna modules</summary> private ConnectionInfo(Vessel v, bool powered, bool storm) { // return no connection if there is no ec left if (!powered) { return; } AntennaInfo ai = GetAntennaInfo(v, powered, storm); ec = ai.ec; rate = ai.rate * PreferencesScience.Instance.transmitFactor; linked = ai.linked; strength = ai.strength; target_name = ai.target_name; control_path = ai.control_path; switch (ai.status) { case 0: status = LinkStatus.direct_link; break; case 1: status = LinkStatus.indirect_link; break; case 2: status = LinkStatus.no_link; break; case 3: status = LinkStatus.plasma; break; case 4: status = LinkStatus.storm; break; default: status = LinkStatus.no_link; break; } }
private static AntennaInfo GetAntennaInfo(Vessel v, bool powered, bool storm) { AntennaInfo ai = new AntennaInfo(); ai.powered = powered; ai.storm = storm; ai.transmitting = !string.IsNullOrEmpty(Science.Transmitting(v, true)); API.Comm.Init(ai, v); if (ai.strength > -1) { return(ai); } // if CommNet is enabled if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { return(new AntennaInfoCommNet(v, powered, storm, ai.transmitting)); } // default: the simple stupid always connected signal system AntennaInfoCommNet antennaInfo = new AntennaInfoCommNet(v, powered, storm, ai.transmitting); antennaInfo.ec *= 0.16; antennaInfo.linked = true; antennaInfo.status = (int)LinkStatus.direct_link; antennaInfo.strength = 1; // 100 % antennaInfo.target_name = "DSN: KSC"; return(antennaInfo); }
public static void RTCommInfoHandler(AntennaInfo antennaInfo, Vessel v) { var ai = new AntennaInfoRT(v, antennaInfo.powered, antennaInfo.storm); antennaInfo.linked = ai.linked; antennaInfo.ec = ai.ec; antennaInfo.control_path = ai.control_path; antennaInfo.rate = ai.rate; antennaInfo.status = ai.status; antennaInfo.strength = ai.strength; antennaInfo.target_name = ai.target_name; }
//This initializes an antennaInfo object. Connection info handlers must //set antennaInfo.strength to a value >= 0, otherwise the antennaInfo will //be passed to the next handler. public void Init(AntennaInfo antennaInfo, Vessel pv) { //Loop through the list of listening methods and Invoke them. foreach (MethodInfo handler in handlers) { try { handler.Invoke(null, new object[] { antennaInfo, pv }); if (antennaInfo.strength > -1) { return; } } catch (Exception e) { Lib.Log("CommInfo handler threw exception " + e.Message + "\n" + e.ToString()); } } }
override public AntennaInfo AntennaInfo() { AntennaInfo result = base.AntennaInfo(); result.ec = 0; result.rate = 0; result.powered = cluster.IsPowered; if (result.powered) { result.rate = Settings.DataRateSurfaceExperiment; } Init(); return(result); }
/// <summary> Creates a <see cref="ConnectionInfo"/> object for the specified vessel from it's antenna modules</summary> private ConnectionInfo(Vessel v, bool powered, bool storm) { // return no connection if there is no ec left if (!powered) { return; } // wait until network is initialized (2 seconds after load) if (!Communications.NetworkInitialized) { return; } AntennaInfo ai = GetAntennaInfo(v, powered, storm); ec = SanityCheck(ai.ec, "ec", v); ec_idle = SanityCheck(ai.ec_idle, "ec_idle", v); rate = SanityCheck(ai.rate, "rate", v) * PreferencesScience.Instance.transmitFactor; linked = ai.linked; strength = SanityCheck(ai.strength, "strength", v); target_name = ai.target_name; control_path = ai.control_path; switch (ai.status) { case 0: status = LinkStatus.direct_link; break; case 1: status = LinkStatus.indirect_link; break; case 2: status = LinkStatus.no_link; break; case 3: status = LinkStatus.plasma; break; case 4: status = LinkStatus.storm; break; default: status = LinkStatus.no_link; break; } }
private static AntennaInfo GetAntennaInfo(Vessel v, bool powered, bool storm) { AntennaInfo ai = new AntennaInfo(); ai.powered = powered; ai.storm = storm; ai.transmitting = v.KerbalismData().filesTransmitted.Count > 0; API.Comm.Init(ai, v); if (ai.strength > -1) { return(ai); } var cluster = Serenity.GetScienceCluster(v); if (cluster != null) { return(new AntennaInfoSerenity(v, cluster, storm, ai.transmitting).AntennaInfo()); } // if CommNet is enabled if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { return(new AntennaInfoCommNet(v, powered, storm, ai.transmitting).AntennaInfo()); } // default: the simple stupid always connected signal system AntennaInfo antennaInfo = new AntennaInfoCommNet(v, powered, storm, ai.transmitting).AntennaInfo(); antennaInfo.ec *= 0.16; antennaInfo.linked = true; antennaInfo.status = (int)LinkStatus.direct_link; antennaInfo.strength = 1; // 100 % antennaInfo.target_name = "DSN: KSC"; return(antennaInfo); }
public double indirect_rate(double d, AntennaInfo relay_antenna) { double r = 0.0; for (int i = 0; i < type.Count; ++i) { if (type[i] == AntennaType.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] == AntennaType.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 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 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)); }