Example #1
0
  // update every frame
  // note: we don't do it every simulation step because:
  // - performance
  // - during scene changes the vessel list change asynchronously, but is synched every frame, apparently
  public void Update()
  {
    // get existing antennas
    BuildAntennas();

    // build visibility cache
    BuildVisibility();

    // build the links cache
    BuildLinks();

    // if there is an active vessel, and is valid
    Vessel v = FlightGlobals.ActiveVessel;
    if (v != null && Lib.IsVessel(v))
    {
      // get link state
      link_data ld = links[v.id];

      // for each antenna
      foreach(Antenna m in v.FindPartModulesImplementing<Antenna>())
      {
        // remove incomplete data toggle
        m.Events["TransmitIncompleteToggle"].active = false;

        // enable/disable science transmission
        m.can_transmit = ld.linked;

        // store transmission distance in the antenna
        m.transmission_distance = ld.distance;
      }
    }
  }
Example #2
0
        public void update(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s)
        {
            // do nothing if signal mechanic is disabled
            if (!Kerbalism.features.signal)
            {
                return;
            }

            // get link data
            link_data link = vi.link;

            // consume relay ec
            // note: this is the only way to do it with new signal and resource systems
            if (vi.antenna.relay_range > 0.0)
            {
                foreach (Vessel w in FlightGlobals.Vessels)
                {
                    vessel_info wi = Cache.VesselInfo(w);
                    if (wi.is_valid)
                    {
                        if (wi.link.path.Contains(v))
                        {
                            resources.Consume(v, "ElectricCharge", vi.antenna.relay_cost * elapsed_s);
                            break;
                        }
                    }
                }
            }

            // maintain and send messages
            // - do nothing if db isn't ready
            // - do not send messages for vessels without an antenna
            if (link.status != link_status.no_antenna)
            {
                if (vd.msg_signal < 1 && !link.linked)
                {
                    vd.msg_signal = 1;
                    if (vd.cfg_signal == 1 && !vi.blackout) //< do not send message during storms
                    {
                        Message.Post(Severity.warning, Lib.BuildString("Signal lost with <b>", v.vesselName, "</b>"),
                                     vi.crew_count == 0 && Settings.RemoteControlLink ? "Remote control disabled" : "Data transmission disabled");
                    }
                }
                else if (vd.msg_signal > 0 && link.linked)
                {
                    vd.msg_signal = 0;
                    if (vd.cfg_signal == 1 && !Storm.JustEnded(v, elapsed_s)) //< do not send messages after a storm
                    {
                        var path = link.path;
                        Message.Post(Severity.relax, Lib.BuildString("<b>", v.vesselName, "</b> signal is back"),
                                     path.Count == 0 ? "We got a direct link with the space center" : Lib.BuildString("Relayed by <b>", path[path.Count - 1].vesselName, "</b>"));
                    }
                }
            }
        }
Example #3
0
 public link_data(link_data other)
 {
     this.linked   = other.linked;
     this.status   = other.status;
     this.distance = other.distance;
     this.path     = new List <Vessel>();
     foreach (Vessel v in other.path)
     {
         this.path.Add(v);
     }
 }
Example #4
0
        public void BuildLinks()
        {
            // clear links container
            links.Clear();

            // clear active relays container
            active_relays.Clear();

            // iterate over all vessels
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // generate and store link status
                link_data ld = ComputeLink(v, new HashSet <Guid>());
                links.Add(v.id, ld);

                // maintain and send messages
                // - do nothing if db isn't ready
                // - do not send messages for vessels without an antenna
                if (DB.Ready() && ld.status != link_status.no_antenna)
                {
                    vessel_data vd = DB.VesselData(v.id);
                    if (vd.msg_signal < 1 && !ld.linked)
                    {
                        vd.msg_signal = 1;
                        if (DB.Ready())
                        {
                            DB.NotificationData().first_signal_loss = 1; //< record first signal loss
                        }
                        if (vd.cfg_signal == 1 && !Blackout(v))          //< do not send message during storms
                        {
                            bool is_probe = (v.loaded ? v.GetCrewCount() == 0 : v.protoVessel.GetVesselCrew().Count == 0);
                            Message.Post(Severity.warning, "Signal lost with <b>" + v.vesselName + "</b>", is_probe ? "Remote control disabled" : "Data transmission disabled");
                        }
                    }
                    else if (vd.msg_signal > 0 && ld.linked)
                    {
                        vd.msg_signal = 0;
                        if (vd.cfg_signal == 1 && !Storm.JustEnded(v.mainBody, TimeWarp.deltaTime)) //< do not send messages after a storm
                        {
                            Message.Post(Severity.relax, "<b>" + v.vesselName + "</b> signal is back",
                                         ld.path.Count == 0 ? "We got a direct link with the space center" : "Relayed by <b>" + ld.path[ld.path.Count - 1] + "</b>");
                        }
                    }
                }
            }
        }
Example #5
0
  public void Update()
  {
    // do nothing if tech tree is not ready
    if (!Lib.TechReady()) return;

    // get range
    double range = Signal.Range(scope, Signal.ECC());

    // update rmb ui status
    RangeStatus = Lib.HumanReadableRange(range);
    RelayStatus = relay ? "Active" : "Disabled";

    // when in flight
    if (HighLogic.LoadedSceneIsFlight)
    {
      // remove incomplete data toggle
      Events["TransmitIncompleteToggle"].active = false;

      // get vessel info from the cache
      vessel_info info = Cache.VesselInfo(vessel);

      // proper antenna mechanics for valid vessels
      if (info.is_valid)
      {
        // shortcut
        link_data link = info.link;

        // enable/disable science transmission
        can_transmit = link.linked;

        // determine currect packet cost
        // note: we set it to max float if out of range, to indirectly specify antenna score
        if (link.distance <= range)
        {
          this.packetResourceCost = (float)(min_transmission_cost + (max_transmission_cost - min_transmission_cost) * link.distance / range);
          CostStatus = Lib.BuildString(this.packetResourceCost.ToString("F2"), " EC/Mbit");
        }
        else
        {
          this.packetResourceCost = float.MaxValue;
          CostStatus = "";
        }
      }
      // sane defaults for invalid vessels
      else
      {
        can_transmit = false;
        this.packetResourceCost = float.MaxValue;
        CostStatus = "";
      }
    }
  }
Example #6
0
  GUIContent indicator_signal(Vessel v)
  {
    GUIContent state = new GUIContent();
    link_data ld = Signal.Link(v);
    switch(ld.status)
    {
      case link_status.direct_link:
        state.image = icon_signal_direct;
        state.tooltip = "Direct link";
        break;

      case link_status.indirect_link:
        state.image = icon_signal_relay;
        if (ld.path.Count == 1)
        {
          state.tooltip = "Signal relayed by <b>" + ld.path[ld.path.Count - 1] + "</b>";
        }
        else
        {
          state.tooltip = "Signal relayed by:";
          for(int i=ld.path.Count-1; i>0; --i) state.tooltip += "\n<b>" + ld.path[i] + "</b>";
        }
        break;

      case link_status.no_link:
        state.image = icon_signal_none;
        state.tooltip = !Signal.Blackout(v) ? "No signal" : "Blackout";
        break;

      case link_status.no_antenna:
        state.image = icon_signal_none;
        state.tooltip = "No antenna";
        break;
    }
    return state;
  }
Example #7
0
  GUIContent indicator_signal(Vessel v, vessel_info vi)
  {
    GUIContent state = new GUIContent();
    link_data ld = vi.link;
    switch(ld.status)
    {
      case link_status.direct_link:
        state.image = icon_signal_direct;
        state.tooltip = "Direct link";
        break;

      case link_status.indirect_link:
        state.image = icon_signal_relay;
        if (ld.path.Count == 1)
        {
          state.tooltip = Lib.BuildString("Signal relayed by <b>", ld.path[ld.path.Count - 1].vesselName, "</b>");
        }
        else
        {
          state.tooltip = "Signal relayed by:";
          for(int i=ld.path.Count-1; i>0; --i) state.tooltip += Lib.BuildString("\n<b>", ld.path[i].vesselName, "</b>");
        }
        break;

      case link_status.no_link:
        state.image = icon_signal_none;
        state.tooltip = !vi.blackout ? "No signal" : "Blackout";
        break;

      case link_status.no_antenna:
        state.image = icon_signal_none;
        state.tooltip = "No antenna";
        break;
    }
    return state;
  }
Example #8
0
        // called at every frame
        public void Update()
        {
            // FIXME: can't double-click on vessel to switch active one, if line is rendered

            // hide all lines
            foreach (var l in lines)
            {
                l.Value.Show(false);
            }

            // do nothing if db isn't ready
            if (!DB.Ready())
            {
                return;
            }

            // do nothing if signal is disabled
            if (!Kerbalism.features.signal)
            {
                return;
            }

            // do nothing if not in map view or tracking station
            if (!MapView.MapIsEnabled)
            {
                return;
            }

            // get homebody position
            Vector3d home = FlightGlobals.GetHomeBody().position;

            // iterate all vessels
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // skip resque missions
                if (Lib.IsResqueMission(v))
                {
                    continue;
                }

                // skip EVA kerbals
                if (v.isEVA)
                {
                    continue;
                }

                // get vessel data
                vessel_data vd = DB.VesselData(v.id);

                // do nothing if showlink is disabled
                if (vd.cfg_showlink == 0)
                {
                    continue;
                }

                // get link status
                link_data ld = Signal.Link(v);

                // if there is an antenna
                if (ld.status != link_status.no_antenna)
                {
                    // get line renderer from the cache
                    Line line = getLine(v.id);

                    // start of the line
                    Vector3d a = Lib.VesselPosition(v);

                    // determine end of line and color
                    Vector3d b;
                    Color    clr;
                    if (ld.status == link_status.direct_link)
                    {
                        b   = home;
                        clr = Color.green;
                    }
                    else if (ld.status == link_status.indirect_link)
                    {
                        Vessel relay = FlightGlobals.Vessels.Find(k => k.id == ld.path_id[ld.path.Count - 1]);
                        if (relay == null)
                        {
                            line.Show(false); continue;
                        }                                    //< skip if it doesn't exist anymore
                        b   = Lib.VesselPosition(relay);
                        clr = Color.yellow;
                    }
                    else // no link
                    {
                        b   = home;
                        clr = Color.red;
                    }

                    // setup the line and show it
                    line.UpdatePoints(a, b, clr);
                    line.Show(true);
                }
            }
        }
Example #9
0
        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));
        }
Example #10
0
        public static void render()
        {
            // get home body position
            Vector3 home = ScaledSpace.LocalToScaledSpace(FlightGlobals.GetHomeBody().position);

            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // get info from the cache
                vessel_info vi = Cache.VesselInfo(v);

                // skip invalid vessels
                if (!vi.is_valid)
                {
                    continue;
                }

                // get data from db
                vessel_data vd = DB.VesselData(v.id);

                // skip vessels with showlink disabled
                if (vd.cfg_showlink == 0)
                {
                    continue;
                }

                // get link data
                link_data link = vi.link;

                // skip vessels with no antenna
                if (link.status == link_status.no_antenna)
                {
                    continue;
                }

                // start of the line
                Vector3 a = ScaledSpace.LocalToScaledSpace(v.GetWorldPos3D());

                // determine end of line and color
                Vector3 b;
                Color   color;
                if (link.status == link_status.no_link)
                {
                    b     = home;
                    color = Color.red;
                }
                else if (link.status == link_status.direct_link)
                {
                    b     = home;
                    color = Color.green;
                }
                else //< indirect link
                {
                    // get link path
                    var path = link.path;

                    // use relay position
                    b     = ScaledSpace.LocalToScaledSpace(path[path.Count - 1].GetWorldPos3D());
                    color = Color.yellow;
                }

                // commit the line
                LineRenderer.commit(a, b, color);
            }
        }
Example #11
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));
        }