/// <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(); } } #if !KSP15_16 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(); } } #endif } // 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); } #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- " + 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; } } } } #endif } }
/// <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; } 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 Update() { if (Lib.IsFlight()) { Drive drive = DB.Vessel(vessel).drive; // if no location was ever specified, set it here if (drive.location == 0) { drive.location = part.flightID; } // if this is the location the data is stored if (drive.location == part.flightID) { // get data size double size = drive.size(); // show DATA UI button, with size info Events["ToggleUI"].guiName = Lib.StatusToggle("Data", size > double.Epsilon ? Lib.HumanReadableDataSize(size) : "empty"); Events["ToggleUI"].active = true; // show TakeData eva action button, if there is something to take Events["TakeData"].active = size > double.Epsilon; // show StoreData eva action button, if active vessel is an eva kerbal and there is something to store from it Vessel v = FlightGlobals.ActiveVessel; Events["StoreData"].active = v != null && v.isEVA && !EVA.IsDead(v) && DB.Vessel(v).drive.size() > double.Epsilon; // hide TransferLocation button Events["TransferData"].active = false; } // if this is not the location the data is stored else { // hide DATA UI button Events["ToggleUI"].active = false; // hide EVA actions Events["TakeData"].active = false; Events["StoreData"].active = false; // show TransferData button Events["TransferData"].active = true; } } }
// 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); }
// return size of data stored in Mb (including samples) public string Size() { return(Lib.BuildString(Lib.HumanReadableDataSize(FilesSize()), " ", Lib.HumanReadableSampleSize(SamplesSize()))); }
public override void OnStart(StartState state) { // don't break tutorial scenarios if (Lib.DisableScenario(this)) { return; } if (Lib.IsEditor()) { if (effectiveDataCapacity == -1.0) { effectiveDataCapacity = dataCapacity; } if (dataCapacity > 0.0 && maxDataCapacityFactor > 0) { Fields["dataCapacityUI"].guiActiveEditor = true; var o = (UI_ChooseOption)Fields["dataCapacityUI"].uiControlEditor; dataCapacities = GetDataCapacitySizes(); int currentCapacityIndex = dataCapacities.FindIndex(p => p.Value == effectiveDataCapacity); if (currentCapacityIndex >= 0) { dataCapacityUI = dataCapacities[currentCapacityIndex].Key; } else { effectiveDataCapacity = dataCapacities[0].Value; dataCapacityUI = dataCapacities[0].Key; } string[] dataOptions = new string[dataCapacities.Count]; for (int i = 0; i < dataCapacities.Count; i++) { dataOptions[i] = Lib.HumanReadableDataSize(dataCapacities[i].Value); } o.options = dataOptions; } if (effectiveSampleCapacity == -1) { effectiveSampleCapacity = sampleCapacity; } if (sampleCapacity > 0 && maxSampleCapacityFactor > 0) { Fields["sampleCapacityUI"].guiActiveEditor = true; var o = (UI_ChooseOption)Fields["sampleCapacityUI"].uiControlEditor; sampleCapacities = GetSampleCapacitySizes(); int currentCapacityIndex = sampleCapacities.FindIndex(p => p.Value == effectiveSampleCapacity); if (currentCapacityIndex >= 0) { sampleCapacityUI = sampleCapacities[currentCapacityIndex].Key; } else { effectiveSampleCapacity = sampleCapacities[0].Value; sampleCapacityUI = sampleCapacities[0].Key; } string[] sampleOptions = new string[sampleCapacities.Count]; for (int i = 0; i < sampleCapacities.Count; i++) { sampleOptions[i] = Lib.HumanReadableSampleSize(sampleCapacities[i].Value); } o.options = sampleOptions; } } if (Lib.IsFlight() && hdId == 0) { hdId = part.flightID; } if (drive == null) { if (!Lib.IsFlight()) { drive = new Drive(title, effectiveDataCapacity, effectiveSampleCapacity, !string.IsNullOrEmpty(experiment_id)); } else { PartData pd = vessel.KerbalismData().GetPartData(part.flightID); if (pd.Drive == null) { drive = new Drive(part.partInfo.title, effectiveDataCapacity, effectiveSampleCapacity, !string.IsNullOrEmpty(experiment_id)); pd.Drive = drive; } else { drive = pd.Drive; } } } UpdateCapacity(); }