// specifics support public Specifics Specs() { Specifics specs = new Specifics(); if (redundancy.Length > 0) { specs.Add("Redundancy", redundancy); } specs.Add("Repair", new CrewSpecs(repair).Info()); specs.Add(string.Empty); specs.Add("<color=#00ffff>Standard quality</color>"); specs.Add("MTBF", Lib.HumanReadableDuration(mtbf)); specs.Add(string.Empty); specs.Add("<color=#00ffff>High quality</color>"); specs.Add("MTBF", Lib.HumanReadableDuration(mtbf * Settings.QualityScale)); if (extra_cost > double.Epsilon) { specs.Add("Extra cost", Lib.HumanReadableCost(extra_cost * part.partInfo.cost)); } if (extra_mass > double.Epsilon) { specs.Add("Extra mass", Lib.HumanReadableMass(extra_mass * part.partInfo.partPrefab.mass)); } return(specs); }
// specifics support public Specifics Specs() { if (exp == null) { exp = ResearchAndDevelopment.GetExperiment(experiment_id); } var specs = new Specifics(); specs.Add(Lib.BuildString("<b>", ResearchAndDevelopment.GetExperiment(experiment_id).experimentTitle, "</b>")); if (!string.IsNullOrEmpty(experiment_desc)) { specs.Add(Lib.BuildString("<i>", experiment_desc, "</i>")); } specs.Add(string.Empty); double expSize = exp.scienceCap * exp.dataScale; if (sample_mass < float.Epsilon) { specs.Add("Data", Lib.HumanReadableDataSize(expSize)); specs.Add("Data rate", Lib.HumanReadableDataRate(data_rate)); specs.Add("Duration", Lib.HumanReadableDuration(expSize / data_rate)); } else { specs.Add("Sample size", Lib.HumanReadableSampleSize(expSize)); specs.Add("Sample mass", Lib.HumanReadableMass(sample_mass)); specs.Add("Duration", Lib.HumanReadableDuration(expSize / data_rate)); } specs.Add("EC required", Lib.HumanReadableRate(ec_rate)); if (crew_operate.Length > 0) { specs.Add("Opration", new CrewSpecs(crew_operate).Info()); } if (crew_reset.Length > 0) { specs.Add("Reset", new CrewSpecs(crew_reset).Info()); } if (crew_prepare.Length > 0) { specs.Add("Preparation", new CrewSpecs(crew_prepare).Info()); } if (!string.IsNullOrEmpty(requires)) { specs.Add(string.Empty); specs.Add("<color=#00ffff>Requirements:</color>", string.Empty); var tokens = Lib.Tokenize(requires, ','); foreach (string s in tokens) { specs.Add(Lib.BuildString("• <b>", Science.RequirementText(s), "</b>")); } } return(specs); }
private void UpdateCapacity() { if (drive == null) { return; } double mass = 0; foreach (var sample in drive.samples.Values) { mass += sample.mass; } totalSampleMass = mass; if (effectiveDataCapacity < 0 || effectiveSampleCapacity < 0 || IsPrivate()) { Fields["Capacity"].guiActive = false; Fields["Capacity"].guiActiveEditor = false; return; } double availableDataCapacity = effectiveDataCapacity; int availableSlots = effectiveSampleCapacity; if (Lib.IsFlight()) { availableDataCapacity = drive.FileCapacityAvailable(); availableSlots = Lib.SampleSizeToSlots(drive.SampleCapacityAvailable()); } Capacity = string.Empty; if (availableDataCapacity > double.Epsilon) { Capacity = Lib.HumanReadableDataSize(availableDataCapacity); } if (availableSlots > 0) { if (Capacity.Length > 0) { Capacity += " "; } Capacity += Lib.HumanReadableSampleSize(availableSlots); } if (Lib.IsFlight() && totalSampleMass > double.Epsilon) { Capacity += " " + Lib.HumanReadableMass(totalSampleMass); } }
// specifics support public Specifics Specs() { Specifics specs = new Specifics(); specs.Add(Local.Habitat_info1, Lib.HumanReadableVolume(volume > 0.0 ? volume : Lib.PartBoundsVolume(part)) + (volume > 0.0 ? "" : " (bounds)")); //"Volume" specs.Add(Local.Habitat_info2, Lib.HumanReadableSurface(surface > 0.0 ? surface : Lib.PartBoundsSurface(part)) + (surface > 0.0 ? "" : " (bounds)")); //"Surface" specs.Add(Local.Habitat_info3, max_pressure >= Settings.PressureThreshold ? Local.Habitat_yes : Local.Habitat_no); //"Pressurized""yes""no" if (inflate.Length > 0) { specs.Add(Local.Habitat_info4, Local.Habitat_yes); //"Inflatable""yes" } if (PhysicsGlobals.KerbalCrewMass > 0) { specs.Add(Local.Habitat_info5, Lib.HumanReadableMass(PhysicsGlobals.KerbalCrewMass));//"Added mass per crew" } return(specs); }
// specifics support public Specifics Specs() { Specifics specs = new Specifics(); specs.Add("Volume", Lib.HumanReadableVolume(volume > double.Epsilon ? volume : Lib.PartVolume(part))); specs.Add("Surface", Lib.HumanReadableSurface(surface > double.Epsilon ? surface : Lib.PartSurface(part))); if (inflate.Length > 0) { specs.Add("Inflatable", "yes"); } if (PhysicsGlobals.KerbalCrewMass > 0) { specs.Add("Added mass per crew", Lib.HumanReadableMass(PhysicsGlobals.KerbalCrewMass)); } return(specs); }
static void Render_sample(Panel p, uint partId, Sample sample, Drive drive, bool short_strings) { // render experiment name string exp_label = Lib.BuildString ( "<b>", Lib.Ellipsis(sample.subjectData.ExperimentTitle, Styles.ScaleStringLength(short_strings ? 24 : 38)), "</b> <size=", Styles.ScaleInteger(10).ToString(), ">", Lib.Ellipsis(sample.subjectData.SituationTitle, Styles.ScaleStringLength((short_strings ? 32 : 62) - Lib.Ellipsis(sample.subjectData.ExperimentTitle, Styles.ScaleStringLength(short_strings ? 24 : 38)).Length)), "</size>" ); string exp_tooltip = Lib.BuildString ( sample.subjectData.ExperimentTitle, "\n", Lib.Color(sample.subjectData.SituationTitle, Lib.Kolor.LightGrey) ); double exp_value = sample.size * sample.subjectData.SciencePerMB; if (exp_value >= 0.1) { exp_tooltip = Lib.BuildString(exp_tooltip, "\n<b>", Lib.HumanReadableScience(exp_value, false), "</b>"); } if (sample.mass > Double.Epsilon) { exp_tooltip = Lib.BuildString(exp_tooltip, "\n<b>", Lib.HumanReadableMass(sample.mass), "</b>"); } if (!string.IsNullOrEmpty(sample.resultText)) { exp_tooltip = Lib.BuildString(exp_tooltip, "\n", Lib.WordWrapAtLength(sample.resultText, 50)); } p.AddContent(exp_label, Lib.HumanReadableSampleSize(sample.size), exp_tooltip, (Action)null, () => Highlighter.Set(partId, Color.cyan)); p.AddRightIcon(sample.analyze ? Textures.lab_cyan : Textures.lab_black, Local.FILEMANAGER_analysis, () => { sample.analyze = !sample.analyze; }); //"Flag the file for analysis in a <b>laboratory</b>" p.AddRightIcon(Textures.toggle_red, Local.FILEMANAGER_Dumpsample, () => //"Dump the sample" { Lib.Popup(Local.FILEMANAGER_Warning_title, //"Warning!" Local.FILEMANAGER_DumpConfirm.Format(sample.subjectData.FullTitle), //"Do you really want to dump <<1>>?", new DialogGUIButton(Local.FILEMANAGER_DumpConfirm_button1, () => drive.Delete_sample(sample.subjectData)), //"Dump it" new DialogGUIButton(Local.FILEMANAGER_DumpConfirm_button2, () => { })); //"Keep it" } ); }
static void Render_sample(Panel p, uint partId, string filename, Sample sample, Drive drive, bool short_strings) { // get experiment info ExperimentInfo exp = Science.Experiment(filename); // render experiment name string exp_label = Lib.BuildString ( "<b>", Lib.Ellipsis(exp.name, Styles.ScaleStringLength(short_strings ? 24 : 38)), "</b> <size=", Styles.ScaleInteger(10).ToString(), ">", Lib.Ellipsis(ExperimentInfo.Situation(filename), Styles.ScaleStringLength((short_strings ? 32 : 62) - Lib.Ellipsis(exp.name, Styles.ScaleStringLength(short_strings ? 24 : 38)).Length)), "</size>" ); string exp_tooltip = Lib.BuildString ( exp.name, "\n", "<color=#aaaaaa>", ExperimentInfo.Situation(filename), "</color>" ); double exp_value = Science.Value(filename, sample.size); if (exp_value >= 0.1) { exp_tooltip = Lib.BuildString(exp_tooltip, "\n<b>", Lib.HumanReadableScience(exp_value), "</b>"); } if (sample.mass > Double.Epsilon) { exp_tooltip = Lib.BuildString(exp_tooltip, "\n<b>", Lib.HumanReadableMass(sample.mass), "</b>"); } p.AddContent(exp_label, Lib.HumanReadableSampleSize(sample.size), exp_tooltip, (Action)null, () => Highlighter.Set(partId, Color.cyan)); p.AddIcon(sample.analyze ? Icons.lab_cyan : Icons.lab_black, "Flag the file for analysis in a <b>laboratory</b>", () => { sample.analyze = !sample.analyze; }); p.AddIcon(Icons.toggle_red, "Dump the sample", () => { Lib.Popup("Warning!", Lib.BuildString("Do you really want to dump ", exp.FullName(filename), "?"), new DialogGUIButton("Dump it", () => drive.samples.Remove(filename)), new DialogGUIButton("Keep it", () => { })); } ); }
private void UpdateCapacity() { totalSampleMass = 0; foreach (var sample in drive.samples.Values) { totalSampleMass += sample.mass; } double availableDataCapacity = dataCapacity; int availableSlots = sampleCapacity; if (Lib.IsFlight()) { availableDataCapacity = drive.FileCapacityAvailable(); availableSlots = Lib.SampleSizeToSlots(drive.SampleCapacityAvailable()); } Capacity = string.Empty; if (availableDataCapacity > double.Epsilon) { Capacity = Lib.HumanReadableDataSize(availableDataCapacity); } if (availableSlots > 0) { if (Capacity.Length > 0) { Capacity += " "; } Capacity += Lib.HumanReadableSampleSize(availableSlots); } if (Lib.IsFlight() && totalSampleMass > double.Epsilon) { Capacity += " " + Lib.HumanReadableMass(totalSampleMass); } }
/// <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 void generate_details(Configure cfg) { // If a setup component is defined after the Configure module in the ConfigNode, // then it is not present in the part during Configure::OnLoad (at precompilation time) // so, find_module() will fail in that situation, resulting in no component details // being added to the Configure window. Therefore we are forced to generate the details // at first use every time the module is loaded, instead of generating them only once. // already generated if (details != null) { return; } // generate module details details = new List <Detail>(); foreach (ConfigureModule cm in modules) { // find module, skip if it doesn't exist PartModule m = cfg.find_module(cm); if (m == null) { continue; } // get title IModuleInfo module_info = m as IModuleInfo; string title = module_info != null?module_info.GetModuleTitle() : cm.type; if (title.Length == 0) { continue; } // get specs, skip if not implemented by module ISpecifics specifics = m as ISpecifics; if (specifics == null) { continue; } Specifics specs = specifics.Specs(); if (specs.entries.Count == 0) { continue; } // add title to details details.Add(new Detail(Lib.BuildString("<b><color=#00ffff>", title, "</color></b>"))); // add specs to details foreach (Specifics.Entry e in specs.entries) { details.Add(new Detail(e.label, e.value)); } } // get visible resources subset List <ConfigureResource> visible_resources = resources.FindAll(k => Lib.GetDefinition(k.name).isVisible); // generate resource details if (visible_resources.Count > 0) { // add resources title details.Add(new Detail("<b><color=#00ffff>Resources</color></b>")); // for each visible resource foreach (ConfigureResource cr in visible_resources) { // add capacity info details.Add(new Detail(cr.name, Lib.Parse.ToDouble(cr.maxAmount).ToString("F2"))); } } // generate extra details if (mass > double.Epsilon || cost > double.Epsilon) { details.Add(new Detail("<b><color=#00ffff>Extra</color></b>")); if (mass > double.Epsilon) { details.Add(new Detail("mass", Lib.HumanReadableMass(mass))); } if (cost > double.Epsilon) { details.Add(new Detail("cost", Lib.HumanReadableCost(cost))); } } }
/// <summary> /// parts that have experiments can't get their module info (what is shown in the VAB tooltip) correctly setup /// because the ExperimentInfo database isn't available at loading time, so we recompile their info manually. /// </summary> public void CompileModuleInfos() { if (PartLoader.LoadedPartsList == null) { Lib.Log("Dazed and confused: PartLoader.LoadedPartsList == null"); return; } foreach (AvailablePart ap in PartLoader.LoadedPartsList) { if (ap == null || ap.partPrefab == null) { Lib.Log("AvailablePart is null or without prefab: " + ap); continue; } foreach (PartModule module in ap.partPrefab.Modules) { if (module is Experiment expModule) { // don't show configurable experiments if (!expModule.isConfigurable && expModule.experiment_id == ExperimentId) { expModule.ExpInfo = this; // get module info for the ExperimentInfo, once if (string.IsNullOrEmpty(ModuleInfo)) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\n"; ModuleInfo += expModule.GetInfo(); } } } if (!string.IsNullOrEmpty(ModuleInfo)) { continue; } if (module is ModuleScienceExperiment stockExpModule) { if (stockExpModule.experimentID == ExperimentId) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\n" + Local.Experimentinfo_Datasize + ": "; //Data size ModuleInfo += Lib.HumanReadableDataSize(DataSize); if (stockExpModule.xmitDataScalar < Science.maxXmitDataScalarForSample) { ModuleInfo += "\n" + Local.Experimentinfo_generatesample; //Will generate a sample. ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " "; //Sample size: ModuleInfo += Lib.HumanReadableSampleSize(DataSize); } ModuleInfo += "\n\n"; ModuleInfo += Lib.Color(Local.Experimentinfo_Situations, Lib.Kolor.Cyan, true); //"Situations:\n" foreach (string s in AvailableSituations()) { ModuleInfo += Lib.BuildString("• <b>", s, "</b>\n"); } ModuleInfo += "\n"; ModuleInfo += stockExpModule.GetInfo(); } } else if (module is ModuleGroundExperiment groundExpModule) { if (groundExpModule.experimentId == ExperimentId) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\n" + Local.Experimentinfo_Datasize + ": "; //Data size ModuleInfo += Lib.HumanReadableDataSize(DataSize); ModuleInfo += "\n\n"; ModuleInfo += groundExpModule.GetInfo(); } } } // special cases if (ExperimentId == "asteroidSample" || ExperimentId.StartsWith("cometSample_", StringComparison.Ordinal)) { ModuleInfo = Local.Experimentinfo_Asteroid; //"Asteroid samples can be taken by kerbals on EVA" ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " "; //Sample size: ModuleInfo += Lib.HumanReadableSampleSize(DataSize); ModuleInfo += "\n" + Local.Experimentinfo_Samplemass + " "; //Sample mass: ModuleInfo += Lib.HumanReadableMass(DataSize * Settings.AsteroidSampleMassPerMB); } else if (IsROC) { string rocType = ExperimentId.Substring(ExperimentId.IndexOf('_') + 1); ROCDefinition rocDef = ROCManager.Instance.rocDefinitions.Find(p => p.type == rocType); if (rocDef != null) { ModuleInfo = Lib.Color(rocDef.displayName, Lib.Kolor.Cyan, true); ModuleInfo += "\n- " + Local.Experimentinfo_scannerarm; //Analyse with a scanner arm ModuleInfo += "\n " + Local.Experimentinfo_Datasize + ": "; //Data size ModuleInfo += Lib.HumanReadableDataSize(DataSize); if (rocDef.smallRoc) { ModuleInfo += "\n- " + Local.Experimentinfo_smallRoc; //Collectable on EVA as a sample" ModuleInfo += "\n" + Local.Experimentinfo_Samplesize + " "; //Sample size: ModuleInfo += Lib.HumanReadableSampleSize(DataSize); } else { ModuleInfo += "\n- " + Local.Experimentinfo_smallRoc2; //Can't be collected on EVA } foreach (RocCBDefinition body in rocDef.myCelestialBodies) { ModuleInfo += Lib.Color("\n\n" + Local.Experimentinfo_smallRoc3.Format(body.name), Lib.Kolor.Cyan, true); //"Found on <<1>>'s :" foreach (string biome in body.biomes) { ModuleInfo += "\n- "; ModuleInfo += biome; } } } } } }
/// <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); } } } }
/// <summary> /// parts that have experiments can't get their module info (what is shown in the VAB tooltip) correctly setup /// because the ExperimentInfo database isn't available at loading time, so we recompile their info manually. /// </summary> public void SetupPrefabs() { if (PartLoader.LoadedPartsList == null) { Lib.Log("Dazed and confused: PartLoader.LoadedPartsList == null"); return; } foreach (AvailablePart ap in PartLoader.LoadedPartsList) { if (ap == null || ap.partPrefab == null) { Lib.Log("AvailablePart is null or without prefab: " + ap); continue; } bool partHasExperimentModule = false; foreach (PartModule module in ap.partPrefab.Modules) { if (module is Experiment expModule) { if (expModule.experiment_id == ExperimentId) { expModule.ExpInfo = this; // works inside the ExperimentInfo ctor, but make sure it's called at the end of it. partHasExperimentModule = true; // get module info for the ExperimentInfo, once if (string.IsNullOrEmpty(ModuleInfo)) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\n"; ModuleInfo += expModule.GetInfo(); } } } if (!string.IsNullOrEmpty(ModuleInfo)) { continue; } if (module is ModuleScienceExperiment stockExpModule) { if (stockExpModule.experimentID == ExperimentId) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\nData size: "; ModuleInfo += Lib.HumanReadableDataSize(DataSize); if (stockExpModule.xmitDataScalar < Science.maxXmitDataScalarForSample) { ModuleInfo += "\nWill generate a sample."; ModuleInfo += "\nSample size: "; ModuleInfo += Lib.HumanReadableSampleSize(DataSize); } ModuleInfo += "\n\n"; ModuleInfo += Lib.Color("Situations:\n", Lib.Kolor.Cyan, true); foreach (string s in AvailableSituations()) { ModuleInfo += Lib.BuildString("• <b>", s, "</b>\n"); } ModuleInfo += "\n"; ModuleInfo += stockExpModule.GetInfo(); } } #if !KSP15_16 else if (module is ModuleGroundExperiment groundExpModule) { if (groundExpModule.experimentId == ExperimentId) { ModuleInfo = Lib.Color(Title, Lib.Kolor.Cyan, true); ModuleInfo += "\nData size: "; ModuleInfo += Lib.HumanReadableDataSize(DataSize); ModuleInfo += "\n\n"; ModuleInfo += groundExpModule.GetInfo(); } } #endif } // special cases if (ExperimentId == "asteroidSample") { ModuleInfo = "Asteroid samples can be taken by kerbals on EVA"; ModuleInfo += "\nSample size: "; ModuleInfo += Lib.HumanReadableSampleSize(DataSize); ModuleInfo += "\nSample mass: "; ModuleInfo += Lib.HumanReadableMass(DataSize * Settings.AsteroidSampleMassPerMB); } #if !KSP15_16 else if (IsROC) { string rocType = ExperimentId.Substring(ExperimentId.IndexOf('_') + 1); ROCDefinition rocDef = ROCManager.Instance.rocDefinitions.Find(p => p.type == rocType); if (rocDef != null) { ModuleInfo = Lib.Color(rocDef.displayName, Lib.Kolor.Cyan, true); ModuleInfo += "\n- Analyse with a scanner arm"; ModuleInfo += "\n Data size: "; ModuleInfo += Lib.HumanReadableDataSize(DataSize); if (rocDef.smallRoc) { ModuleInfo += "\n- Collectable on EVA as a sample"; ModuleInfo += "\nSample size: "; ModuleInfo += Lib.HumanReadableSampleSize(DataSize); } else { ModuleInfo += "\n- Can't be collected on EVA"; } foreach (RocCBDefinition body in rocDef.myCelestialBodies) { ModuleInfo += Lib.Color("\n\nFound on " + body.name + "'s :", Lib.Kolor.Cyan, true); foreach (string biome in body.biomes) { ModuleInfo += "\n- "; ModuleInfo += biome; } } } } #endif if (partHasExperimentModule && !ap.name.StartsWith("kerbalEVA")) { ap.moduleInfos.Clear(); ap.resourceInfos.Clear(); try { Lib.ReflectionCall(PartLoader.Instance, "CompilePartInfo", new Type[] { typeof(AvailablePart), typeof(Part) }, new object[] { ap, ap.partPrefab }); } catch (Exception ex) { Lib.Log("Could not patch the moduleInfo for part " + ap.name + " - " + ex.Message + "\n" + ex.StackTrace); } } } }
/// <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 void Update() { // in flight if (Lib.IsFlight()) { Vessel v = FlightGlobals.ActiveVessel; if (v == null || EVA.IsDead(v)) { return; } // get info from cache Vessel_info vi = Cache.VesselInfo(vessel); // do nothing if vessel is invalid if (!vi.is_valid) { return; } var sampleSize = (exp.scienceCap * exp.dataScale); var recordedPercent = Lib.HumanReadablePerc(dataSampled / sampleSize); var eta = data_rate < double.Epsilon || dataSampled >= sampleSize ? " done" : " T-" + Lib.HumanReadableDuration((sampleSize - dataSampled) / data_rate); // update ui Events["Toggle"].guiName = Lib.StatusToggle(exp.experimentTitle, !recording ? "stopped" : Lib.Color(issue.Length > 0 ? "#ffff00":"", Lib.HumanReadablePerc(dataSampled / sampleSize) + "...")); Events["Toggle"].active = (prepare_cs == null || didPrepare); Events["Prepare"].guiName = Lib.BuildString("Prepare <b>", exp.experimentTitle, "</b>"); Events["Prepare"].active = !didPrepare && prepare_cs != null && string.IsNullOrEmpty(last_subject_id); Events["Reset"].guiName = Lib.BuildString("Reset <b>", exp.experimentTitle, "</b>"); // we need a reset either if we have recorded data or did a setup bool resetActive = sample_mass < float.Epsilon && (reset_cs != null || prepare_cs != null) && !string.IsNullOrEmpty(last_subject_id); Events["Reset"].active = resetActive; Fields["ExperimentStatus"].guiName = exp.experimentTitle; Fields["ExperimentStatus"].guiActive = true; if (issue.Length > 0) { ExperimentStatus = Lib.BuildString("<color=#ffff00>", issue, "</color>"); } else if (dataSampled > 0) { string a = string.Empty; string b = string.Empty; if (sample_mass < float.Epsilon) { a = Lib.HumanReadableDataSize(dataSampled); b = Lib.HumanReadableDataSize(sampleSize); } else { a = Lib.SampleSizeToSlots(dataSampled).ToString(); b = Lib.HumanReadableSampleSize(sampleSize); if (remainingSampleMass > double.Epsilon) { b += " " + Lib.HumanReadableMass(remainingSampleMass) + " left"; } } ExperimentStatus = Lib.BuildString(a, "/", b, eta); } else { var size = sample_mass < double.Epsilon ? Lib.HumanReadableDataSize(sampleSize) : Lib.HumanReadableSampleSize(sampleSize); ExperimentStatus = Lib.BuildString("ready ", size, " in ", Lib.HumanReadableDuration(sampleSize / data_rate)); } } // in the editor else if (Lib.IsEditor()) { // update ui Events["Toggle"].guiName = Lib.StatusToggle(exp.experimentTitle, recording ? "recording" : "stopped"); Events["Reset"].active = false; Events["Prepare"].active = false; } }
// specifics support public Specifics Specs() { var specs = new Specifics(); var exp = Science.Experiment(experiment_id); if (exp == null) { specs.Add(Localizer.Format("#KERBALISM_ExperimentInfo_Unknown")); return(specs); } specs.Add(Lib.BuildString("<b>", exp.name, "</b>")); if (!string.IsNullOrEmpty(experiment_desc)) { specs.Add(Lib.BuildString("<i>", experiment_desc, "</i>")); } specs.Add(string.Empty); double expSize = exp.max_amount; if (sample_mass < float.Epsilon) { specs.Add("Data", Lib.HumanReadableDataSize(expSize)); specs.Add("Data rate", Lib.HumanReadableDataRate(data_rate)); specs.Add("Duration", Lib.HumanReadableDuration(expSize / data_rate)); } else { specs.Add("Sample size", Lib.HumanReadableSampleSize(expSize)); specs.Add("Sample mass", Lib.HumanReadableMass(sample_mass)); if (!sample_collecting && Math.Abs(sample_reservoir - sample_mass) > double.Epsilon && sample_mass > double.Epsilon) { specs.Add("Experiments", "" + Math.Round(sample_reservoir / sample_mass, 0)); } specs.Add("Duration", Lib.HumanReadableDuration(expSize / data_rate)); } List <string> situations = exp.Situations(); if (situations.Count > 0) { specs.Add(string.Empty); specs.Add("<color=#00ffff>Situations:</color>", string.Empty); foreach (string s in situations) { specs.Add(Lib.BuildString("• <b>", s, "</b>")); } } specs.Add(string.Empty); specs.Add("<color=#00ffff>Needs:</color>"); specs.Add("EC", Lib.HumanReadableRate(ec_rate)); foreach (var p in KerbalismProcess.ParseResources(resources)) { specs.Add(p.Key, Lib.HumanReadableRate(p.Value)); } if (crew_prepare.Length > 0) { var cs = new CrewSpecs(crew_prepare); specs.Add("Preparation", cs ? cs.Info() : "none"); } if (crew_operate.Length > 0) { var cs = new CrewSpecs(crew_operate); specs.Add("Operation", cs ? cs.Info() : "unmanned"); } if (crew_reset.Length > 0) { var cs = new CrewSpecs(crew_reset); specs.Add("Reset", cs ? cs.Info() : "none"); } if (!string.IsNullOrEmpty(requires)) { specs.Add(string.Empty); specs.Add("<color=#00ffff>Requires:</color>", string.Empty); var tokens = Lib.Tokenize(requires, ','); foreach (string s in tokens) { specs.Add(Lib.BuildString("• <b>", Science.RequirementText(s), "</b>")); } } return(specs); }
// specifics support public Specifics Specs() { Specifics specs = new Specifics(); if (redundancy.Length > 0) { specs.Add("Redundancy", redundancy); } specs.Add("Repair", new CrewSpecs(repair).Info()); specs.Add(string.Empty); specs.Add("<color=#00ffff>Standard quality</color>"); if (mtbf > 0) { specs.Add("MTBF", Lib.HumanReadableDuration(EffectiveMTBF(false, mtbf))); } if (turnon_failure_probability > 0) { specs.Add("Ignition failures", Lib.HumanReadablePerc(turnon_failure_probability, "F1")); } if (rated_operation_duration > 0) { specs.Add("Rated burn duration", Lib.HumanReadableDuration(EffectiveDuration(false, rated_operation_duration))); } if (rated_ignitions > 0) { specs.Add("Rated ignitions", EffectiveIgnitions(false, rated_ignitions).ToString()); } if (mtbf > 0 && rated_radiation > 0) { specs.Add("Radiation rating", Lib.HumanReadableRadiation(rated_radiation / 3600.0)); } specs.Add(string.Empty); specs.Add("<color=#00ffff>High quality</color>"); if (extra_cost > double.Epsilon) { specs.Add("Extra cost", Lib.HumanReadableCost(extra_cost * part.partInfo.cost)); } if (extra_mass > double.Epsilon) { specs.Add("Extra mass", Lib.HumanReadableMass(extra_mass * part.partInfo.partPrefab.mass)); } if (mtbf > 0) { specs.Add("MTBF", Lib.HumanReadableDuration(EffectiveMTBF(true, mtbf))); } if (turnon_failure_probability > 0) { specs.Add("Ignition failures", Lib.HumanReadablePerc(turnon_failure_probability / Settings.QualityScale, "F1")); } if (rated_operation_duration > 0) { specs.Add("Rated burn duration", Lib.HumanReadableDuration(EffectiveDuration(true, rated_operation_duration))); } if (rated_ignitions > 0) { specs.Add("Rated ignitions", EffectiveIgnitions(true, rated_ignitions).ToString()); } if (mtbf > 0 && rated_radiation > 0) { specs.Add("Radiation rating", Lib.HumanReadableRadiation(Settings.QualityScale * rated_radiation / 3600.0)); } return(specs); }