public static void TelemetryPanel(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) return; // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) return; // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>TELEMETRY</color>")); p.Width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.telemetry; // time-out simulation if (p.Timeout(vi)) return; // get vessel data VesselData vd = DB.Vessel(v); // get resources Vessel_resources resources = ResourceCache.Get(v); // get crew var crew = Lib.CrewList(v); // draw the content Render_crew(p, crew); Render_greenhouse(p, vi); Render_supplies(p, v, vi, resources); Render_habitat(p, v, vi); Render_environment(p, v, vi); // collapse eva kerbal sections into one if (v.isEVA) p.Collapse("EVA SUIT"); }
// to be called as window refresh function void window_body(Panel p) { // outside the editor if (!Lib.IsEditor()) { // if part doesn't exist anymore if (FlightGlobals.FindPartByID(part.flightID) == null) { return; } } // inside the editor else { // if the part doesn't exist anymore (eg: removed, user hit undo) if (GetInstanceID() == 0) { return; } } // for each selected setup for (int selected_i = 0; selected_i < selected.Count; ++selected_i) { // find index in unlocked setups for (int setup_i = 0; setup_i < unlocked.Count; ++setup_i) { if (unlocked[setup_i].name == selected[selected_i]) { // commit panel render_panel(p, unlocked[setup_i], selected_i, setup_i); } } } // set metadata p.title(Lib.BuildString("Configure <color=#cccccc>", Lib.Ellipsis(title, Styles.ScaleStringLength(40)), "</color>")); p.width(Styles.ScaleWidthFloat(300.0f)); }
/// <summary> /// If short_strings parameter is true then the strings used for display of the data will be shorter when inflight. /// </summary> public static void Fileman(this Panel p, Vessel v, bool short_strings = false) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " <color=#cccccc>FILE MANAGER</color>")); p.Width(Styles.ScaleWidthFloat(465.0f)); p.paneltype = Panel.PanelType.data; // time-out simulation if (!Lib.IsControlUnit(v) && p.Timeout(vi)) { return; } var drives = Drive.GetDriveParts(v); int filesCount = 0; double usedDataCapacity = 0; double totalDataCapacity = 0; int samplesCount = 0; int usedSlots = 0; int totalSlots = 0; double totalMass = 0; bool unlimitedData = false; bool unlimitedSamples = false; foreach (var idDrivePair in drives) { var drive = idDrivePair.Value; if (!drive.is_private) { usedDataCapacity += drive.FilesSize(); totalDataCapacity += drive.dataCapacity; unlimitedData |= drive.dataCapacity < 0; unlimitedSamples |= drive.sampleCapacity < 0; usedSlots += drive.SamplesSize(); totalSlots += drive.sampleCapacity; } filesCount += drive.files.Count; samplesCount += drive.samples.Count; foreach (var sample in drive.samples.Values) { totalMass += sample.mass; } } if (filesCount > 0 || totalDataCapacity > 0) { var title = "DATA " + Lib.HumanReadableDataSize(usedDataCapacity); if (!unlimitedData) { title += Lib.BuildString(" (", Lib.HumanReadablePerc((totalDataCapacity - usedDataCapacity) / totalDataCapacity), " available)"); } p.AddSection(title); foreach (var idDrivePair in drives) { uint partId = idDrivePair.Key; var drive = idDrivePair.Value; foreach (var pair in drive.files) { string filename = pair.Key; File file = pair.Value; Render_file(p, partId, filename, file, drive, short_strings && Lib.IsFlight(), v); } } if (filesCount == 0) { p.AddContent("<i>no files</i>", string.Empty); } } if (samplesCount > 0 || totalSlots > 0) { var title = "SAMPLES " + Lib.HumanReadableMass(totalMass) + " " + Lib.HumanReadableSampleSize(usedSlots); if (totalSlots > 0 && !unlimitedSamples) { title += ", " + Lib.HumanReadableSampleSize(totalSlots) + " available"; } p.AddSection(title); foreach (var idDrivePair in drives) { uint partId = idDrivePair.Key; var drive = idDrivePair.Value; foreach (var pair in drive.samples) { string samplename = pair.Key; Sample sample = pair.Value; Render_sample(p, partId, samplename, sample, drive, short_strings && Lib.IsFlight()); } } if (samplesCount == 0) { p.AddContent("<i>no samples</i>", string.Empty); } } }
public static void Devman(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>" + Localizer.Format("#KERBALISM_UI_devman") + "</color>")); p.Width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.scripts; // time-out simulation if (!Lib.IsControlUnit(v) && p.Timeout(vi)) { return; } // get devices Dictionary <uint, Device> devices = Computer.Boot(v); int deviceCount = 0; // direct control if (script_index == 0) { // draw section title and desc p.AddSection ( Localizer.Format("#KERBALISM_UI_devices"), Description(), () => p.Prev(ref script_index, (int)ScriptType.last), () => p.Next(ref script_index, (int)ScriptType.last), true ); // for each device foreach (var pair in devices) { // render device entry Device dev = pair.Value; if (!dev.IsVisible()) { continue; } p.AddContent(dev.Name(), dev.Info(), string.Empty, dev.Toggle, () => Highlighter.Set(dev.Part(), Color.cyan)); deviceCount++; } } // script editor else { // get script ScriptType script_type = (ScriptType)script_index; string script_name = script_type.ToString().Replace('_', ' ').ToUpper(); Script script = DB.Vessel(v).computer.Get(script_type); // draw section title and desc p.AddSection ( script_name, Description(), () => p.Prev(ref script_index, (int)ScriptType.last), () => p.Next(ref script_index, (int)ScriptType.last), true ); // for each device foreach (var pair in devices) { Device dev = pair.Value; if (!dev.IsVisible()) { continue; } // determine tribool state int state = !script.states.ContainsKey(pair.Key) ? -1 : !script.states[pair.Key] ? 0 : 1; // render device entry p.AddContent ( dev.Name(), state == -1 ? "<color=#999999>" + Localizer.Format("#KERBALISM_UI_dontcare") + " </color>" : state == 0 ? "<color=red>" + Localizer.Format("#KERBALISM_Generic_OFF") + "</color>" : "<color=cyan>" + Localizer.Format("#KERBALISM_Generic_ON") + "</color>", string.Empty, () => { switch (state) { case -1: script.Set(dev, true); break; case 0: script.Set(dev, null); break; case 1: script.Set(dev, false); break; } }, () => Highlighter.Set(dev.Part(), Color.cyan) ); deviceCount++; } } // no devices case if (deviceCount == 0) { p.AddContent("<i>no devices</i>"); } }
public static void config(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>VESSEL CONFIG</color>")); p.width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.config; // time-out simulation if (p.timeout(vi)) { return; } // get data from db VesselData vd = DB.Vessel(v); // toggle rendering string tooltip; if (Features.Reliability) { p.section("RENDERING"); } if (Features.Reliability) { tooltip = "Highlight failed components"; p.content("highlight malfunctions", string.Empty, tooltip); p.icon(vd.cfg_highlights ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_highlights)); } // toggle messages p.section("MESSAGES"); tooltip = "Receive a message when\nElectricCharge level is low"; p.content("battery", string.Empty, tooltip); p.icon(vd.cfg_ec ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_ec)); if (Features.Supplies) { tooltip = "Receive a message when\nsupply resources level is low"; p.content("supply", string.Empty, tooltip); p.icon(vd.cfg_supply ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_supply)); } if (RemoteTech.Enabled() || HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { tooltip = "Receive a message when signal is lost or obtained"; p.content("signal", string.Empty, tooltip); p.icon(vd.cfg_signal ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_signal)); } if (Features.Reliability) { tooltip = "Receive a message\nwhen a component fail"; p.content("reliability", string.Empty, tooltip); p.icon(vd.cfg_malfunction ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_malfunction)); } if (Features.SpaceWeather) { tooltip = "Receive a message\nduring CME events"; p.content("storm", string.Empty, tooltip); p.icon(vd.cfg_storm ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_storm)); } if (Features.Automation) { tooltip = "Receive a message when\nscripts are executed"; p.content("script", string.Empty, tooltip); p.icon(vd.cfg_script ? Icons.toggle_green : Icons.toggle_red, tooltip, () => p.toggle(ref vd.cfg_script)); } }
/// <summary> /// If short_strings parameter is true then the strings used for display of the data will be shorter when inflight. /// </summary> public static void Fileman(this Panel p, Vessel v, bool short_strings = false) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache VesselData vd = v.KerbalismData(); // if not a valid vessel, leave the panel empty if (!vd.IsSimulated) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " ", Lib.Color(Local.FILEMANAGER_title, Lib.Kolor.LightGrey))); //"FILE MANAGER" p.Width(Styles.ScaleWidthFloat(465.0f)); p.paneltype = Panel.PanelType.data; // time-out simulation if (!Lib.IsControlUnit(v) && p.Timeout(vd)) { return; } List <ObjectPair <uint, Drive> > drives = new List <ObjectPair <uint, Drive> >(); int filesCount = 0; double usedDataCapacity = 0; double totalDataCapacity = 0; int samplesCount = 0; int usedSlots = 0; int totalSlots = 0; double totalMass = 0; bool unlimitedData = false; bool unlimitedSamples = false; foreach (PartData partData in vd.PartDatas) { Drive drive = partData.Drive; if (drive == null) { continue; } drives.Add(new ObjectPair <uint, Drive>(partData.FlightId, drive)); if (!drive.is_private) { usedDataCapacity += drive.FilesSize(); totalDataCapacity += drive.dataCapacity; unlimitedData |= drive.dataCapacity < 0; unlimitedSamples |= drive.sampleCapacity < 0; usedSlots += drive.SamplesSize(); totalSlots += drive.sampleCapacity; } filesCount += drive.files.Count; samplesCount += drive.samples.Count; foreach (var sample in drive.samples.Values) { totalMass += sample.mass; } } if (filesCount > 0 || totalDataCapacity > 0) { var title = Local.FILEMANAGER_DataCapacity + " " + Lib.HumanReadableDataSize(usedDataCapacity); //"DATA " if (!unlimitedData) { title += Local.FILEMANAGER_DataAvailable.Format(Lib.HumanReadablePerc((totalDataCapacity - usedDataCapacity) / totalDataCapacity)); //Lib.BuildString(" (", Lib.HumanReadablePerc((totalDataCapacity - usedDataCapacity) / totalDataCapacity), " available)"); } p.AddSection(title); foreach (var drive in drives) { foreach (File file in drive.Value.files.Values) { Render_file(p, drive.Key, file, drive.Value, short_strings && Lib.IsFlight(), v); } } if (filesCount == 0) { p.AddContent("<i>" + Local.FILEMANAGER_nofiles + "</i>", string.Empty); //no files } } if (samplesCount > 0 || totalSlots > 0) { var title = Local.FILEMANAGER_SAMPLESMass.Format(Lib.HumanReadableMass(totalMass)) + " " + Lib.HumanReadableSampleSize(usedSlots); //"SAMPLES " + if (totalSlots > 0 && !unlimitedSamples) { title += ", " + Lib.HumanReadableSampleSize(totalSlots) + " " + Local.FILEMANAGER_SAMPLESAvailable; //available } p.AddSection(title); foreach (var drive in drives) { foreach (Sample sample in drive.Value.samples.Values) { Render_sample(p, drive.Key, sample, drive.Value, short_strings && Lib.IsFlight()); } } if (samplesCount == 0) { p.AddContent("<i>" + Local.FILEMANAGER_nosamples + "</i>", string.Empty); //no samples } } }
public static void Devman(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get data VesselData vd = v.KerbalismData(); // if not a valid vessel, leave the panel empty if (!vd.IsSimulated) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), Lib.Color("#KERBALISM_UI_devman", Lib.Kolor.LightGrey))); p.Width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.scripts; // time-out simulation if (!Lib.IsControlUnit(v) && p.Timeout(vd)) { return; } // get devices List <Device> devices = Computer.GetModuleDevices(v); int deviceCount = 0; // direct control if (script_index == 0) { // draw section title and desc p.AddSection ( Localizer.Format("#KERBALISM_UI_devices"), Description(), () => p.Prev(ref script_index, (int)ScriptType.last), () => p.Next(ref script_index, (int)ScriptType.last), false ); bool hasVesselDeviceSection = false; bool hasModuleDeviceSection = false; // for each device for (int i = devices.Count - 1; i >= 0; i--) { Device dev = devices[i]; dev.OnUpdate(); if (!dev.IsVisible) { continue; } // create vessel device section if necessary if (dev is VesselDevice) { if (!hasVesselDeviceSection) { p.AddSection("VESSEL DEVICES"); hasVesselDeviceSection = true; } } // create module device section if necessary else { if (!hasModuleDeviceSection) { p.AddSection("MODULE DEVICES"); hasModuleDeviceSection = true; } } if (dev.PartId != 0u) { p.AddContent(dev.DisplayName, dev.Status, dev.Tooltip, dev.Toggle, () => Highlighter.Set(dev.PartId, Color.cyan)); } else { p.AddContent(dev.DisplayName, dev.Status, dev.Tooltip, dev.Toggle); } if (dev.Icon != null) { p.SetLeftIcon(dev.Icon.texture, dev.Icon.tooltip, dev.Icon.onClick); } deviceCount++; } } // script editor else { // get script ScriptType script_type = (ScriptType)script_index; string script_name = script_type.ToString().Replace('_', ' ').ToUpper(); Script script = v.KerbalismData().computer.Get(script_type); // draw section title and desc p.AddSection ( script_name, Description(), () => p.Prev(ref script_index, (int)ScriptType.last), () => p.Next(ref script_index, (int)ScriptType.last) ); bool hasVesselDeviceSection = false; bool hasModuleDeviceSection = false; // for each device for (int i = devices.Count - 1; i >= 0; i--) { Device dev = devices[i]; dev.OnUpdate(); if (!dev.IsVisible) { continue; } // determine tribool state int state = !script.states.ContainsKey(dev.Id) ? -1 : !script.states[dev.Id] ? 0 : 1; // create vessel device section if necessary if (dev is VesselDevice) { if (!hasVesselDeviceSection) { p.AddSection("VESSEL DEVICES"); hasVesselDeviceSection = true; } } // create module device section if necessary else { if (!hasModuleDeviceSection) { p.AddSection("MODULE DEVICES"); hasModuleDeviceSection = true; } } // render device entry p.AddContent ( dev.DisplayName, state == -1 ? Lib.Color(Localizer.Format("#KERBALISM_UI_dontcare"), Lib.Kolor.DarkGrey) : Lib.Color(state == 0, Localizer.Format("#KERBALISM_Generic_OFF"), Lib.Kolor.Yellow, Localizer.Format("#KERBALISM_Generic_ON"), Lib.Kolor.Green), string.Empty, () => { switch (state) { case -1: script.Set(dev, true); break; case 0: script.Set(dev, null); break; case 1: script.Set(dev, false); break; } }, () => Highlighter.Set(dev.PartId, Color.cyan) ); deviceCount++; } } // no devices case if (deviceCount == 0) { p.AddContent("<i>no devices</i>"); } }
/// <summary> /// If short_strings parameter is true then the strings used for display of the data will be shorter when inflight. /// </summary> public static void Fileman(this Panel p, Vessel v, bool short_strings = false) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " <color=#cccccc>FILE MANAGER</color>")); p.Width(Styles.ScaleWidthFloat(465.0f)); p.paneltype = Panel.PanelType.data; // time-out simulation if (p.Timeout(vi)) { return; } foreach (var idDrivePair in DB.Vessel(v).drives) { var drive = idDrivePair.Value; if (drive.dataCapacity > double.Epsilon) { // draw data section p.AddSection(Lib.BuildString("DATA ", drive.name, " ", Lib.HumanReadableDataSize(drive.dataCapacity), " (", Lib.HumanReadablePerc(drive.FilesSize() / drive.dataCapacity), ")")); foreach (var pair in drive.files) { string filename = pair.Key; File file = pair.Value; Render_file(p, filename, file, drive, short_strings && Lib.IsFlight(), Cache.VesselInfo(v).connection.rate); } if (drive.files.Count == 0) { p.AddContent("<i>no files</i>", string.Empty); } } if (drive.sampleCapacity > 0) { double mass = 0; foreach (var sample in drive.samples.Values) { mass += sample.mass; } // draw samples section p.AddSection(Lib.BuildString("SAMPLES ", drive.name, " ", Lib.HumanReadableSampleSize(drive.sampleCapacity), " (", Lib.HumanReadablePerc(drive.SamplesSize() / drive.sampleCapacity), ") ", Lib.HumanReadableMass(mass))); foreach (var pair in drive.samples) { string filename = pair.Key; Sample sample = pair.Value; Render_sample(p, filename, sample, drive, short_strings && Lib.IsFlight()); } if (drive.samples.Count == 0) { p.AddContent("<i>no samples</i>", string.Empty); } } } }
public static void Config(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) return; // get vessel data VesselData vd = v.KerbalismData(); // if not a valid vessel, leave the panel empty if (!vd.IsSimulated) return; // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " ", Lib.Color(Local.VESSELCONFIG_title, Lib.Kolor.LightGrey)));//"VESSEL CONFIG" p.Width(Styles.ScaleWidthFloat(355.0f)); p.paneltype = Panel.PanelType.config; // toggle rendering string tooltip; if (Features.Reliability) { p.AddSection(Local.VESSELCONFIG_RENDERING);//"RENDERING" } if (Features.Reliability) { tooltip = Local.VESSELCONFIG_Highlightfailed_desc;//"Highlight failed components" p.AddContent(Local.VESSELCONFIG_Highlightfailed, string.Empty, tooltip);//"highlight malfunctions" p.AddRightIcon(vd.cfg_highlights ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_highlights)); } // toggle messages p.AddSection(Local.VESSELCONFIG_MESSAGES);//"MESSAGES" tooltip = Local.VESSELCONFIG_EClow;//"Receive a message when\nElectricCharge level is low" p.AddContent(Local.VESSELCONFIG_battery, string.Empty, tooltip);//"battery" p.AddRightIcon(vd.cfg_ec ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_ec)); if (Features.Supplies) { tooltip = Local.VESSELCONFIG_Supplylow;//"Receive a message when\nsupply resources level is low" p.AddContent(Local.VESSELCONFIG_supply, string.Empty, tooltip);//"supply" p.AddRightIcon(vd.cfg_supply ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_supply)); } if (API.Comm.handlers.Count > 0 || HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { tooltip = Local.VESSELCONFIG_Signallost;//"Receive a message when signal is lost or obtained" p.AddContent(Local.VESSELCONFIG_signal, string.Empty, tooltip);//"signal" p.AddRightIcon(vd.cfg_signal ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_signal)); } if (Features.Reliability) { tooltip = Local.VESSELCONFIG_Componentfail;//"Receive a message\nwhen a component fail" p.AddContent(Local.VESSELCONFIG_reliability, string.Empty, tooltip);//"reliability" p.AddRightIcon(vd.cfg_malfunction ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_malfunction)); } if (Features.SpaceWeather) { tooltip = Local.VESSELCONFIG_CMEevent;//"Receive a message\nduring CME events" p.AddContent(Local.VESSELCONFIG_storm, string.Empty, tooltip);//"storm" p.AddRightIcon(vd.cfg_storm ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_storm)); } if (Features.Automation) { tooltip = Local.VESSELCONFIG_ScriptExe;//"Receive a message when\nscripts are executed" p.AddContent(Local.VESSELCONFIG_script, string.Empty, tooltip);//"script" p.AddRightIcon(vd.cfg_script ? Textures.toggle_green : Textures.toggle_red, tooltip, () => p.Toggle(ref vd.cfg_script)); } }
/// <summary> /// Shows the Network status, ControlPath, Signal strength /// </summary> public static void ConnMan(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " <color=#cccccc>CONNECTION MANAGER</color>")); p.Width(Styles.ScaleWidthFloat(365.0f)); p.paneltype = Panel.PanelType.connection; // time-out simulation if (p.Timeout(vi)) { return; } // draw ControlPath section p.AddSection("CONTROL PATH"); if (vi.connection.linked) { if (RemoteTech.Enabled) { if (vi.connection.controlPath != null) { Guid i = v.id; foreach (Guid id in vi.connection.controlPath) { p.AddContent( Lib.Ellipsis(RemoteTech.GetSatelliteName(i) + " \\ " + RemoteTech.GetSatelliteName(id), 35), Lib.HumanReadablePerc(Math.Ceiling((1 - (RemoteTech.GetCommsDistance(i, id) / RemoteTech.GetCommsMaxDistance(i, id))) * 10000) / 10000, "F2"), "\nDistance: " + Lib.HumanReadableRange(RemoteTech.GetCommsDistance(i, id)) + "\nMax Distance: " + Lib.HumanReadableRange(RemoteTech.GetCommsMaxDistance(i, id))); i = id; } } } if (HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) { foreach (CommLink link in v.connection.ControlPath) { double antennaPower = link.end.isHome ? link.start.antennaTransmit.power + link.start.antennaRelay.power : link.start.antennaTransmit.power; double signalStrength = 1 - ((link.start.position - link.end.position).magnitude / Math.Sqrt(antennaPower * link.end.antennaRelay.power)); signalStrength = (3 - (2 * signalStrength)) * Math.Pow(signalStrength, 2); p.AddContent( Lib.Ellipsis(Localizer.Format(link.end.name).Replace("Kerbin", "DSN"), 35), Lib.HumanReadablePerc(Math.Ceiling(signalStrength * 10000) / 10000, "F2"), "\nDistance: " + Lib.HumanReadableRange((link.start.position - link.end.position).magnitude) + "\nMax Distance: " + Lib.HumanReadableRange(Math.Sqrt((link.start.antennaTransmit.power + link.start.antennaRelay.power) * link.end.antennaRelay.power)) ); } } } else { p.AddContent("<i>no connection</i>", string.Empty); } }