public override OverlayTooltip TooltipContent(double latitude, double longitude, CelestialBody body) { var biome = ScanSatWrapper.Instance.GetBiome(longitude, latitude, body); var all = Enum.GetValues(typeof(ExperimentSituations)).Cast <ExperimentSituations>() .Select(situation => ResearchAndDevelopment.GetExperimentIDs().Select(ResearchAndDevelopment.GetExperiment) .Where(x => x.biomeMask != 0 && x.situationMask != 0) .Where(x => x.IsAvailableWhileFixed(situation, body)) .GroupBy(x => x.BiomeIsRelevantWhile(situation)) .SelectMany(x => x.Select(y => new { exp = y, subj = ResearchAndDevelopment.GetExperimentSubject(y, situation, body, x.Key ? biome.name : "") })) .Select(x => new { value = ResearchAndDevelopment.GetScienceValue(x.exp.dataScale * x.exp.baseValue, x.subj), exp = x }) .Aggregate(new { str = "", total = 0f }, (a, x) => new { str = a.str + " name: " + x.exp.exp.experimentTitle + " value: " + x.value, total = a.total + x.value }, result => "Situation " + Enum.GetName(typeof(ExperimentSituations), situation) + " total: " + result.total + result.str)) .Aggregate("", (str, x) => str + x + "\n"); var main = ResearchAndDevelopment.GetExperimentIDs().Select(ResearchAndDevelopment.GetExperiment) .Where(x => x.biomeMask != 0 && x.situationMask != 0) .Where(x => x.IsAvailableWhileFixed(_situation, body)) .GroupBy(x => x.BiomeIsRelevantWhile(_situation)) .SelectMany(x => x.Select(y => new { exp = y, subj = ResearchAndDevelopment.GetExperimentSubject(y, _situation, body, x.Key ? biome.name : "") })) .Select(x => new { value = ResearchAndDevelopment.GetScienceValue(x.exp.dataScale * x.exp.baseValue, x.subj), exp = x }) .Aggregate(new { str = "", total = 0f }, (a, x) => new { str = a.str + " name: " + x.exp.exp.experimentTitle + " value: " + x.value, total = a.total + x.value }, result => "Situation " + Enum.GetName(typeof(ExperimentSituations), _situation) + " total: " + result.total + result.str); return(new OverlayTooltip(biome.name, new GUIContent(main + "\n\n" + all), new Vector2(500, 500))); }
public static void RegisterMethods() { RegisterMethod(new Method <ScienceExperiment, string>("Name", e => e == null ? "" : e.experimentTitle)); RegisterGlobalFunction(new Function <List <ScienceExperiment> >("AllExperiments", () => ResearchAndDevelopment.Instance == null ? new List <ScienceExperiment>() : ResearchAndDevelopment.GetExperimentIDs().Select <string, ScienceExperiment>(ResearchAndDevelopment.GetExperiment).ToList(), false)); RegisterGlobalFunction(new Function <CelestialBody, List <ScienceExperiment> >("AvailableExperiments", (cb) => Util.Science.AvailableExperiments(cb).ToList(), false)); }
public int RebuildObserverList() { observers.Clear(); ScanInterface scanInterface = GetComponent <ScanInterface>(); if (scanInterface == null) { Log.Error("ExperimentManager.RebuildObserverList: No ScanInterface component found"); // this is bad; things won't break if the scan interface } // construct the experiment observer list ... foreach (var expid in ResearchAndDevelopment.GetExperimentIDs()) { if (expid != "evaReport" && expid != "surfaceSample") // special cases { if (FlightGlobals.ActiveVessel.FindPartModulesImplementing <ModuleScienceExperiment>().Any(mse => mse.experimentID == expid)) { observers.Add(new ExperimentObserver(vesselStorage, ProfileManager.ActiveProfile[expid], biomeFilter, scanInterface, expid)); } } } observers.Add(new SurfaceSampleObserver(vesselStorage, ProfileManager.ActiveProfile["surfaceSample"], biomeFilter, scanInterface)); try { if (ProfileManager.ActiveProfile["evaReport"].Enabled) { if (Settings.Instance.EvaReportOnTop) { observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); observers.Insert(0, new EvaReportObserver(vesselStorage, ProfileManager.ActiveProfile["evaReport"], biomeFilter, scanInterface)); } else { observers.Add(new EvaReportObserver(vesselStorage, ProfileManager.ActiveProfile["evaReport"], biomeFilter, scanInterface)); observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); } } else { observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); } } catch (NullReferenceException e) { Log.Error("ExperimentManager.RebuildObserverList: Active profile does not seem to have an \"evaReport\" entry; {0}", e); } watcher = UpdateObservers(); // to prevent any problems by rebuilding in the middle of enumeration OnObserversRebuilt(); return(observers.Count); }
protected bool ValidateExperiment(string experiment) { if (string.IsNullOrEmpty(experiment)) { return(true); } if (!ResearchAndDevelopment.GetExperimentIDs().Contains(experiment)) { throw new ArgumentException("Not a valid experiment!"); } return(true); }
private void Setup() { settings = new Dictionary <string, ExperimentSettings>(); try { List <string> experimentIDs = ResearchAndDevelopment.GetExperimentIDs(); foreach (string current in experimentIDs) { settings.Add(current, new ExperimentSettings()); } } catch (System.Exception ex) { Log.Debug("[ScienceAlert]:Profile '{1}' constructor exception: {0}", ex, string.IsNullOrEmpty(name) ? "(unnamed)" : name); } }
protected new void OnGUI() { if (!adjustedSkin) { Skin.window.stretchHeight = true; List <string> experimentTitles = new List <string>(); ResearchAndDevelopment.GetExperimentIDs().ForEach(id => experimentTitles.Add(ResearchAndDevelopment.GetExperiment(id).experimentTitle)); Skin.button.fixedWidth = Mathf.Max(64f, experimentTitles.Max(title => { float minWidth = 0f; float maxWidth = 0f; Skin.button.CalcMinMaxWidth(new GUIContent(title + " (123.4)"), out minWidth, out maxWidth); return(maxWidth); })); adjustedSkin = true; } base.OnGUI(); }
//Attempts to inject the stuff that should have been in sciencedefs to begin with private void rdInject() { ScienceExperiment temp = null; try { List <String> ids = ResearchAndDevelopment.GetExperimentIDs(); if (_debug) { Debug.Log("(CB) Injecting experimental results..."); } ScienceExperiment exp; foreach (String id in ids) { exp = ResearchAndDevelopment.GetExperiment(id); if (id.Equals("temperatureScan")) { temp = exp; } foreach (sciresult res in _resultList) { if (res.expid.Equals(id) && !exp.Results.ContainsKey(res.biome)) { exp.Results.Add(res.biome, res.res); } // else //if (_debug) Debug.Log(res.biome + " already exists for " + exp.experimentTitle); } if (_debug) { Debug.Log("(CB) " + exp.experimentTitle); } //foreach (String key in exp.Results.Keys) //Debug.Log(key + " | " + exp.Results[key]); } Debug.Log("(CB) R&D injection complete."); rdInjected = true; } catch { Debug.Log("(CB) Error attempting R&D injection."); } }
/// <summary> /// Some necessary setup shared between constructors /// </summary> private void Setup() { settings = new Dictionary <string, ProfileData.ExperimentSettings>(); try { var expids = ResearchAndDevelopment.GetExperimentIDs(); foreach (var id in expids) { settings.Add(id, new ProfileData.ExperimentSettings()); } } catch (Exception e) { // this is most likely to happen on GetExperimentIDs, which // will throw an exception if there are duplicate experiment // id entries Log.Error("Profile '{1}' constructor exception: {0}", e, string.IsNullOrEmpty(name) ? "(unnamed)" : name); } }
public void OnProfileChanged() { if (ScienceAlertProfileManager.ActiveProfile == null) { return; } thresholdValue = ScienceAlertProfileManager.ActiveProfile.ScienceThreshold.ToString("F2", formatter); List <string> experimentIDs = ResearchAndDevelopment.GetExperimentIDs(); IOrderedEnumerable <string> orderedEnumerable = from expid in experimentIDs orderby ResearchAndDevelopment.GetExperiment(expid).experimentTitle select expid; experimentIds.Clear(); using (IEnumerator <string> enumerator = orderedEnumerable.GetEnumerator()) { while (enumerator.MoveNext()) { string current = enumerator.Current; experimentIds.Add(current, (int)System.Convert.ChangeType(ScienceAlertProfileManager.ActiveProfile[current].Filter, ScienceAlertProfileManager.ActiveProfile[current].Filter.GetTypeCode())); } } }
public void GetSciData() { if (ResearchAndDevelopment.Instance == null) { return; } dataOutputList = new List <Experiment>(); List <ScienceSubject> newExperiments = new List <ScienceSubject>(); List <string> exIds = ResearchAndDevelopment.GetExperimentIDs(); List <ScienceSubject> subjectslist = ResearchAndDevelopment.GetSubjects(); //I am glad this code runs only once! Too expensive! foreach (string id in exIds) { foreach (ExperimentSituations experimentSituation in Enum.GetValues(typeof(ExperimentSituations))) { foreach (CelestialBody body in FlightGlobals.Bodies) { bool ocean = body.ocean; if (ExperimentSituations.SrfSplashed == experimentSituation && !ocean) { continue; } if ((ExperimentSituations.FlyingHigh == experimentSituation || ExperimentSituations.FlyingLow == experimentSituation) && !body.atmosphere) { continue; } ScienceExperiment experiment = ResearchAndDevelopment.GetExperiment(id); bool available = experiment.IsAvailableWhile(experimentSituation, body); if (available) { bool shouldHaveBiome = experiment.BiomeIsRelevantWhile(experimentSituation); if (shouldHaveBiome) { foreach (string biome in ResearchAndDevelopment.GetBiomeTags(body)) { if (KSPScienceSettings.getBoolSetting("ShowOnlyKnownBiomes")) { bool foundBiome = subjectslist.Any(subject => subject.id.Contains("@" + body.name) && subject.id.Contains(biome.Replace(" ", ""))); if (!foundBiome) { continue; } } ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, biome); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } if (body.BiomeMap == null || body.BiomeMap.Attributes.Length == 0) { ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, ""); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } } else { ScienceSubject ssj = new ScienceSubject(experiment, experimentSituation, body, ""); if (id == "asteroidSample") { ssj.scienceCap = experiment.scienceCap; } newExperiments.Add(ssj); } } } } } foreach (ScienceSubject scienceSubject in subjectslist) { newExperiments.RemoveAll(subject => subject.id == scienceSubject.id); string title = scienceSubject.id; double earned = Math.Round(scienceSubject.science, 1); double remain = Math.Round(scienceSubject.scienceCap - scienceSubject.science, 1); string body = LibraryUtils.FindExperimentBody(scienceSubject.id.Split('@')[1]); string type = scienceSubject.id.Split('@')[0]; Experiment experiment = new Experiment(title, earned, remain, body, type); dataOutputList.Add(experiment); } foreach (ScienceSubject newExperiment in newExperiments) { newExperiment.scientificValue = 1f; CelestialBody thisBody = FlightGlobals.Bodies.Find(celestialBody => newExperiment.id.Split('@')[1].StartsWith(celestialBody.name)); Experiment ex = new Experiment(newExperiment.id, 0, Math.Round(newExperiment.scienceCap, 1), thisBody.name, newExperiment.id.Split('@')[0]); dataOutputList.Add(ex); } dataOutputList.Sort(SortByName); if (KSPScienceSettings.getBoolSetting("ShowOnlyKnownExperiments")) { allExperimentTypes = GetKnownExperimentTypes(); } else { allExperimentTypes = GetAllExperimentTypes(); } }
public static void Init() { Lib.Log("ScienceDB init started"); int subjectCount = 0; double totalScience = 0.0; // get our extra defintions ConfigNode[] expDefNodes = GameDatabase.Instance.GetConfigNodes("EXPERIMENT_DEFINITION"); // create our subject database // Note : GetExperimentIDs will force the creation of all ScienceExperiment objects, // no matter if the RnD instance is null or not because the ScienceExperiment dictionary is static. foreach (string experimentId in ResearchAndDevelopment.GetExperimentIDs()) { if (experimentId == "recovery") { continue; } ConfigNode kerbalismExpNode = null; foreach (ConfigNode expDefNode in expDefNodes) { string id = string.Empty; if (expDefNode.TryGetValue("id", ref id) && id == experimentId) { kerbalismExpNode = expDefNode.GetNode("KERBALISM_EXPERIMENT"); // return null if not found break; } } ScienceExperiment stockDef = ResearchAndDevelopment.GetExperiment(experimentId); if (stockDef == null) { Lib.Log("ScienceExperiment is null for experiment Id=" + experimentId + ", skipping...", Lib.LogLevel.Warning); continue; } ExperimentInfo expInfo = new ExperimentInfo(stockDef, kerbalismExpNode); if (!experiments.ContainsKey(experimentId)) { experiments.Add(experimentId, expInfo); } if (!subjectByExpThenSituationId.ContainsKey(expInfo)) { subjectByExpThenSituationId.Add(expInfo, new Dictionary <int, SubjectData>()); } for (int bodyIndex = 0; bodyIndex < FlightGlobals.Bodies.Count; bodyIndex++) { CelestialBody body = FlightGlobals.Bodies[bodyIndex]; if (!expInfo.IgnoreBodyRestrictions && !expInfo.ExpBodyConditions.IsBodyAllowed(body)) { continue; } // ScienceSituationUtils.validSituations is all situations in the enum, apart from the "None" value foreach (ScienceSituation scienceSituation in ScienceSituationUtils.validSituations) { // test the ScienceExperiment situation mask if (!scienceSituation.IsAvailableForExperiment(expInfo)) { continue; } // don't add impossible body / situation combinations if (!expInfo.IgnoreBodyRestrictions && !scienceSituation.IsAvailableOnBody(body)) { continue; } // virtual biomes always have priority over normal biomes : if (scienceSituation.IsVirtualBiomesRelevantForExperiment(expInfo)) { foreach (VirtualBiome virtualBiome in expInfo.VirtualBiomes) { if (!virtualBiome.IsAvailableOnBody(body)) { continue; } SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation, (int)virtualBiome); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; totalScience += subjectData.ScienceMaxValue; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, (int)virtualBiome, subjectData); } } // if the biome mask says the situation is biome dependant : else if (scienceSituation.IsBodyBiomesRelevantForExperiment(expInfo) && body.BiomeMap != null && body.BiomeMap.Attributes.Length > 1) { for (int biomeIndex = 0; biomeIndex < body.BiomeMap.Attributes.Length; biomeIndex++) { SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation, biomeIndex); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; totalScience += subjectData.ScienceMaxValue; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, biomeIndex, subjectData); } } // else generate the global, biome agnostic situation else { SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; totalScience += subjectData.ScienceMaxValue; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, -1, subjectData); } } } } // cache that call IEnumerable <ExperimentInfo> experimentInfosCache = ExperimentInfos; // first parse all the IncludeExperiment configs foreach (ExperimentInfo experimentInfo in experimentInfosCache) { experimentInfo.ParseIncludedExperiments(); } // then check for infinite recursion from bad configs List <ExperimentInfo> chainedExperiments = new List <ExperimentInfo>(); foreach (ExperimentInfo experimentInfo in experimentInfosCache) { chainedExperiments.Clear(); ExperimentInfo.CheckIncludedExperimentsRecursion(experimentInfo, chainedExperiments); } // now we are sure all the include experiment chains are valid foreach (ExperimentInfo experimentInfo in experimentInfosCache) { // populate the included experiments chains at the subject level foreach (KeyValuePair <int, SubjectData> subjectInfo in subjectByExpThenSituationId[experimentInfo]) { foreach (ExperimentInfo includedInfo in experimentInfo.IncludedExperiments) { SubjectData subjectToInclude = GetSubjectData(includedInfo, subjectInfo.Key); if (subjectToInclude != null) { subjectInfo.Value.IncludedSubjects.Add(subjectToInclude); } } } // Get the experiment description that will be shown in the science archive by calling GetInfo() on the first found partmodule using it // TODO: this isn't ideal, if there are several modules with different values (ex : data rate, ec rate...), the archive info will use the first found one. // Ideally we should revamp the whole handling of that (because it's a mess from the partmodule side too) experimentInfo.CompileModuleInfos(); } Lib.Log($"ScienceDB init done : {subjectCount} subjects found, total science points : {totalScience.ToString("F1")}"); }
/****************************************************************************** * Implementation Details ******************************************************************************/ protected override Rect Setup() { // position blocker in front of ApplicationLauncher buttons. The window is going to be drawn on // top of them regardless; this will just prevent us from accidentally interacting with them backstop.SetZ(ApplicationLauncher.Instance.anchor.transform.position.z - 50f); // culture setting Log.Normal("Configuring NumberFormatInfo for current locale"); formatter = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone(); formatter.CurrencySymbol = string.Empty; formatter.CurrencyDecimalDigits = 2; formatter.NumberDecimalDigits = 2; formatter.PercentDecimalDigits = 2; audio = AudioPlayer.Audio; if (audio == null) { Log.Error("DraggableOptionsWindow: Failed to find AudioPlayer instance"); } var rawIds = ResearchAndDevelopment.GetExperimentIDs(); var sortedIds = rawIds.OrderBy(expid => ResearchAndDevelopment.GetExperiment(expid).experimentTitle); Log.Debug("OptionsWindow: sorted {0} experiment IDs", sortedIds.Count()); foreach (var id in sortedIds) { experimentIds.Add(id, (int)Convert.ChangeType(ProfileManager.ActiveProfile[id].Filter, ProfileManager.ActiveProfile[id].Filter.GetTypeCode())); Log.Debug("Settings: experimentId {0} has filter index {1}", id, experimentIds[id]); } /* * Unresearched = 0, * NotMaxed = 1, * LessThanFiftyPercent = 2, * LessThanNinetyPercent = 3 */ filterList.Add(new GUIContent("Unresearched")); filterList.Add(new GUIContent("Not maxed")); filterList.Add(new GUIContent("< 50% collected")); filterList.Add(new GUIContent("< 90% collected")); openButton = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnOpen.png", false); saveButton = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnSave.png", false); returnButton = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnReturn.png", false); deleteButton = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnDelete.png", false); renameButton = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnRename.png", false); var tex = ResourceUtil.GetEmbeddedTexture("ScienceAlert.Resources.btnExpand.png", false); if (tex == null) { Log.Error("Failed to retrieve expand button texture from stream"); } else { Log.Debug("Collapse button texture loaded successfully"); expandButton = tex; collapseButton = UnityEngine.Texture.Instantiate(expandButton) as Texture2D; ResourceUtil.FlipTexture(collapseButton, true, true); collapseButton.Compress(false); expandButton.Compress(false); } blackPixel.SetPixel(0, 0, Color.black); blackPixel.Apply(); blackPixel.filterMode = FilterMode.Bilinear; whiteLabel = (GUISkin)GUISkin.Instantiate(Settings.Skin); whiteLabel.label.onNormal.textColor = Color.white; whiteLabel.toggle.onNormal.textColor = Color.white; whiteLabel.label.onActive.textColor = Color.white; submenu = OpenPane.None; Title = "ScienceAlert Options"; // smaller label for less important text hints miniLabelLeft = new GUIStyle(Skin.label); miniLabelLeft.fontSize = 10; miniLabelLeft.normal.textColor = miniLabelLeft.onNormal.textColor = Color.white; miniLabelRight = new GUIStyle(miniLabelLeft); miniLabelRight.alignment = TextAnchor.MiddleRight; miniLabelCenter = new GUIStyle(miniLabelLeft); miniLabelCenter.alignment = TextAnchor.MiddleCenter; Settings.Instance.OnSave += OnAboutToSave; base.OnVisibilityChange += OnVisibilityChanged; GameEvents.onVesselChange.Add(OnVesselChanged); LoadFrom(Settings.Instance.additional.GetNode("OptionsWindow") ?? new ConfigNode()); return(new Rect(windowRect.x, windowRect.y, 324, Screen.height / 5 * 3)); }
/// <summary> /// Gets an enumeration of all available experiments /// </summary> /// <returns></returns> public static IEnumerable <ScienceExperiment> AvailableExperiments() { if (ResearchAndDevelopment.Instance == null) { return(Enumerable.Empty <ScienceExperiment>()); } IEnumerable <ScienceExperiment> experiments = ResearchAndDevelopment.GetExperimentIDs().Select <string, ScienceExperiment>(ResearchAndDevelopment.GetExperiment); // Build a mapping of experiment => parts if (experimentParts == null) { experimentParts = new Dictionary <string, List <AvailablePart> >(); // Check the stock experiment foreach (KeyValuePair <AvailablePart, string> pair in PartLoader.Instance.parts. Where(p => p.moduleInfos.Any(mod => experimentModules.Contains(mod.moduleName.Replace(" ", "")))). SelectMany(p => p.partConfig.GetNodes("MODULE"). Where(node => experimentModules.Contains(node.GetValue("name"))). Select(node => new KeyValuePair <AvailablePart, string>(p, node.GetValue("experimentID"))))) { if (!string.IsNullOrEmpty(pair.Value)) { if (!experimentParts.ContainsKey(pair.Value)) { experimentParts[pair.Value] = new List <AvailablePart>(); } experimentParts[pair.Value].Add(pair.Key); } } // Check for specific modules specified in configurator foreach (ExperimentRules rules in experiments.Select(exp => GetExperimentRules(exp.id)).Where(r => !string.IsNullOrEmpty(r.partModule))) { if (!experimentParts.ContainsKey(rules.id)) { experimentParts[rules.id] = new List <AvailablePart>(); } string module = rules.partModule; foreach (AvailablePart p in PartLoader.Instance.parts.Where(p => p.moduleInfos.Any(mod => mod.moduleName == module))) { experimentParts[rules.id].Add(p); } } // Add part-specific rules foreach (ExperimentRules rules in experiments.Select(exp => GetExperimentRules(exp.id)).Where(r => r.part != null)) { if (!experimentParts.ContainsKey(rules.id)) { experimentParts[rules.id] = new List <AvailablePart>(); } foreach (string pname in rules.part) { foreach (AvailablePart p in PartLoader.Instance.parts.Where(p => p.name == pname)) { LoggingUtil.LogVerbose(typeof(Science), "Adding entry for " + rules.id + " = " + p.name); experimentParts[rules.id].Add(p); } } } // List out the partless experiments foreach (ScienceExperiment exp in experiments.Where(exp => GetExperimentRules(exp.id).partless)) { partlessExperiments[exp.id] = true; } } // Filter out anything tied to a part that isn't unlocked experiments = experiments.Where(exp => partlessExperiments.ContainsKey(exp.id) || experimentParts.ContainsKey(exp.id) && experimentParts[exp.id].Any(ResearchAndDevelopment.PartTechAvailable)); return(experiments); }
public static void Init() { Lib.Log("ScienceDB init started"); int subjectCount = 0; // get our extra defintions ConfigNode[] expDefNodes = GameDatabase.Instance.GetConfigNodes("EXPERIMENT_DEFINITION"); // create our subject database // Note : GetExperimentIDs will force the creation of all ScienceExperiment objects, // no matter if the RnD instance is null or not because the ScienceExperiment dictionary is static. foreach (string experimentId in ResearchAndDevelopment.GetExperimentIDs()) { if (experimentId == "recovery") { continue; } ConfigNode kerbalismExpNode = null; foreach (ConfigNode expDefNode in expDefNodes) { string id = string.Empty; if (expDefNode.TryGetValue("id", ref id) && id == experimentId) { kerbalismExpNode = expDefNode.GetNode("KERBALISM_EXPERIMENT"); // return null if not found break; } } ScienceExperiment stockDef = ResearchAndDevelopment.GetExperiment(experimentId); if (stockDef == null) { Lib.Log("ScienceExperiment is null for experiment Id=" + experimentId + ", skipping...", Lib.LogLevel.Warning); continue; } ExperimentInfo expInfo = new ExperimentInfo(stockDef, kerbalismExpNode); if (!experiments.ContainsKey(experimentId)) { experiments.Add(experimentId, expInfo); } if (!subjectByExpThenSituationId.ContainsKey(expInfo)) { subjectByExpThenSituationId.Add(expInfo, new Dictionary <int, SubjectData>()); } for (int bodyIndex = 0; bodyIndex < FlightGlobals.Bodies.Count; bodyIndex++) { CelestialBody body = FlightGlobals.Bodies[bodyIndex]; if (!expInfo.IgnoreBodyRestrictions && !expInfo.ExpBodyConditions.IsBodyAllowed(body)) { continue; } // ScienceSituationUtils.validSituations is all situations in the enum, apart from the "None" value foreach (ScienceSituation scienceSituation in ScienceSituationUtils.validSituations) { // test the ScienceExperiment situation mask if (!scienceSituation.IsAvailableForExperiment(expInfo)) { continue; } // don't add impossible body / situation combinations if (!expInfo.IgnoreBodyRestrictions && !scienceSituation.IsAvailableOnBody(body)) { continue; } // virtual biomes always have priority over normal biomes : if (scienceSituation.IsVirtualBiomesRelevantForExperiment(expInfo)) { foreach (VirtualBiome virtualBiome in expInfo.VirtualBiomes) { if (!virtualBiome.IsAvailableOnBody(body)) { continue; } SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation, (int)virtualBiome); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, (int)virtualBiome, subjectData); bodiesSituationsBiomesSubjects.AddSubject(bodyIndex, scienceSituation, (int)virtualBiome, subjectData); } } // if the biome mask says the situation is biome dependant : else if (scienceSituation.IsBodyBiomesRelevantForExperiment(expInfo) && body.BiomeMap != null && body.BiomeMap.Attributes.Length > 1) { for (int biomeIndex = 0; biomeIndex < body.BiomeMap.Attributes.Length; biomeIndex++) { SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation, biomeIndex); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, biomeIndex, subjectData); bodiesSituationsBiomesSubjects.AddSubject(bodyIndex, scienceSituation, biomeIndex, subjectData); } } // else generate the global, biome agnostic situation else { SubjectData subjectData = null; if (expInfo.HasDBSubjects) { Situation situation = new Situation(bodyIndex, scienceSituation); subjectData = new SubjectData(expInfo, situation); subjectByExpThenSituationId[expInfo].Add(situation.Id, subjectData); knownStockSubjectsId.Add(subjectData.StockSubjectId); subjectCount++; } expBodiesSituationsBiomesSubject.AddSubject(expInfo, bodyIndex, scienceSituation, -1, subjectData); bodiesSituationsBiomesSubjects.AddSubject(bodyIndex, scienceSituation, -1, subjectData); } } } } Lib.Log("ScienceDB init done : " + subjectCount + " subjects found"); }
/// <summary> /// Recreates all ExperimentObservers. This is done so that we never have any ExperimentObservers /// that watch for experiments that the current Vessel doesn't have, except in special cases like /// EVA reports or surface samples. /// </summary> /// <returns>Number of observers created</returns> public int RebuildObserverList() { Log.Normal("Rebuilding observer list"); observers.Clear(); ScanInterface scanInterface = GetComponent <ScanInterface>(); if (scanInterface == null) { Log.Error("ExperimentManager.RebuildObserverList: No ScanInterface component found"); // this is bad; things won't break if the scan interface } // is the default but there should always be a ScanInterface-type // script attached to this GO // construct the experiment observer list ... foreach (var expid in ResearchAndDevelopment.GetExperimentIDs()) { if (expid != "evaReport" && expid != "surfaceSample") // special cases { if (ResearchAndDevelopment.GetExperiment(expid).situationMask == 0 && ResearchAndDevelopment.GetExperiment(expid).biomeMask == 0) { // we can't monitor this experiment, so no need to clutter the // ui with it Log.Verbose("Experiment '{0}' cannot be monitored due to zero'd situation and biome flag masks.", ResearchAndDevelopment.GetExperiment(expid).experimentTitle); } else if (FlightGlobals.ActiveVessel.FindPartModulesImplementing <ModuleScienceExperiment>().Any(mse => mse.experimentID == expid)) { // only add this observer if at least one applicable experiment is onboard observers.Add(new ExperimentObserver(vesselStorage, ProfileManager.ActiveProfile[expid], biomeFilter, scanInterface, expid)); } } } // surfaceSample is a special case: it's technically available on any // crewed vessel observers.Add(new SurfaceSampleObserver(vesselStorage, ProfileManager.ActiveProfile["surfaceSample"], biomeFilter, scanInterface)); // evaReport is a special case. It technically exists on any crewed // vessel. That vessel won't report it normally though, unless // the vessel is itself an eva'ing Kerbal. Since there are conditions // that would result in the experiment no longer being available // (kerbal dies, user goes out on eva and switches back to ship, and // so on) I think it's best we separate it out into its own // Observer type that will account for these changes and any others // that might not necessarily trigger a VesselModified event try { if (ProfileManager.ActiveProfile["evaReport"].Enabled) { if (Settings.Instance.EvaReportOnTop) { observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); observers.Insert(0, new EvaReportObserver(vesselStorage, ProfileManager.ActiveProfile["evaReport"], biomeFilter, scanInterface)); } else { observers.Add(new EvaReportObserver(vesselStorage, ProfileManager.ActiveProfile["evaReport"], biomeFilter, scanInterface)); observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); } } else { observers = observers.OrderBy(obs => obs.ExperimentTitle).ToList(); } } catch (NullReferenceException e) { // this is another one of those things that should never happen but if they did // it'd be in a quiet "why isn't this list sorted?" way Log.Error("ExperimentManager.RebuildObserverList: Active profile does not seem to have an \"evaReport\" entry; {0}", e); } watcher = UpdateObservers(); // to prevent any problems by rebuilding in the middle of enumeration OnObserversRebuilt(); return(observers.Count); }
private void SetExperiments(ExperimentSituations situations) { _experiments = ResearchAndDevelopment.GetExperimentIDs().Select(ResearchAndDevelopment.GetExperiment) .Where(x => x.biomeMask != 0 && x.situationMask != 0) .Where(x => x.IsAvailableWhileFixed(situations, _body)).ToList(); }