void UpdateVesselInMasterStatusDisplay(Vessel vessel) { if (!masterStatus.ContainsKey(vessel.id)) { return; } var allPartsStatus = masterStatus[vessel.id].allPartsStatus; for (var i = 0; i < allPartsStatus.Count; i++) { var status = allPartsStatus[i]; ITestFlightCore core = status.flightCore; // Update the part status status.partStatus = core.GetPartStatus(); status.failures = core.GetActiveFailures(); status.flightData = core.GetFlightData(); double failureRate = core.GetBaseFailureRate(); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } status.momentaryFailureRate = failureRate; status.mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); status.runningTime = TestFlightUtil.FormatTime(core.GetBurnTime(), TestFlightUtil.TIMEFORMAT.SHORT_IDENTIFIER, false); allPartsStatus[i] = status; } }
// Get the FlightData or FlightTime for the part public static float GetFlightData(Part part, string alias) { ITestFlightCore core = TestFlightInterface.GetCore(part, alias); if (core == null) { return(0); } return(core.GetFlightData()); }
public override List <string> GetTestFlightInfo() { List <string> infoStrings = new List <string>(); if (core == null) { Log("Core is null"); return(infoStrings); } if (baseIgnitionChance == null) { Log("Curve is null"); return(infoStrings); } float flightData = core.GetFlightData(); if (flightData < 0f) { flightData = 0f; } infoStrings.Add("<b>Ignition Reliability</b>"); infoStrings.Add(String.Format("<b>Current Ignition Chance</b>: {0:P}", baseIgnitionChance.Evaluate(flightData))); infoStrings.Add(String.Format("<b>Maximum Ignition Chance</b>: {0:P}", baseIgnitionChance.Evaluate(baseIgnitionChance.maxTime))); if (additionalFailureChance > 0f) { infoStrings.Add(String.Format("<b>Cascade Failure Chance</b>: {0:P}", additionalFailureChance)); } if (pressureCurve != null & pressureCurve.Curve.keys.Length > 1) { float maxTime = pressureCurve.maxTime; infoStrings.Add("<b>This engine suffers a penalty to ignition based on dynamic pressure</b>"); infoStrings.Add($"<b>0 kPa Pressure Modifier:</b> {pressureCurve.Evaluate(0)}"); infoStrings.Add($"<b>{maxTime/1000} kPa Pressure Modifier</b>: {pressureCurve.Evaluate(maxTime):N}"); } if (pressureCurve != null & pressureCurve.Curve.keys.Length > 1) { float maxTime = pressureCurve.maxTime; infoStrings.Add("<b>This engine suffers a penalty to ignition based on dynamic pressure</b>"); infoStrings.Add($"<B>0 Pa Pressure Modifier: {pressureCurve.Evaluate(0)}"); infoStrings.Add($"<b>{maxTime} Pa Pressure Modifier</b>: {pressureCurve.Evaluate(maxTime):N}"); } return(infoStrings); }
internal override void Update() { if (!isReady) { return; } if (!tfScenario.SettingsEnabled) { return; } if (masterStatus == null) { masterStatus = new Dictionary <Guid, MasterStatusItem>(); } currentUTC = Planetarium.GetUniversalTime(); // ensure out vessel list is up to date Profiler.BeginSample("CacheVessels"); CacheVessels(); Profiler.EndSample(); if (currentUTC >= lastMasterStatusUpdate + tfScenario.userSettings.masterStatusUpdateFrequency) { lastMasterStatusUpdate = currentUTC; Profiler.BeginSample("VerifyMasterStatus"); VerifyMasterStatus(); Profiler.EndSample(); } // process vessels Profiler.BeginSample("ProcessVessels"); knownVesselsEnumerator = knownVessels.GetEnumerator(); while (knownVesselsEnumerator.MoveNext()) { KeyValuePair <Guid, double> entry = knownVesselsEnumerator.Current; Vessel vessel = null; Profiler.BeginSample("FindVessel"); for (int i = 0; i < FlightGlobals.Vessels.Count; i++) { if (FlightGlobals.Vessels[i].id == entry.Key) { vessel = FlightGlobals.Vessels[i]; } } Profiler.EndSample(); if (vessel == null) { continue; } if (vessel.loaded) { Profiler.BeginSample("ProcessParts"); List <Part> parts = vessel.Parts; for (int j = 0; j < parts.Count; j++) { // Each KSP part can be composed of N virtual parts Profiler.BeginSample("Reset Core List"); cores.Clear(); Profiler.EndSample(); Profiler.BeginSample("Get Cores"); for (int k = 0; k < parts[j].Modules.Count; k++) { ITestFlightCore core = parts[j].Modules[k] as ITestFlightCore; if (core != null && core.TestFlightEnabled) { cores.Add(core.Alias); } } Profiler.EndSample(); //cores = TestFlightInterface.GetActiveCores(vessel.parts[j]); if (cores == null || cores.Count <= 0) { continue; } Profiler.BeginSample("ProcessCores"); for (int k = 0; k < cores.Count; k++) { ITestFlightCore core = TestFlightUtil.GetCore(vessel.parts[j], cores[k]); if (core == null) { continue; } // Poll for flight data and part status if (!(currentUTC >= lastDataPoll + tfScenario.userSettings.masterStatusUpdateFrequency)) { continue; } // Update or Add part status in Master Status if (masterStatus.ContainsKey(vessel.id)) { Profiler.BeginSample("MasterStatus Existing Vessel"); // Vessel is already in the Master Status, so check if part is in there as well int existingPartIndex = -1; Profiler.BeginSample("Find Part"); for (int msIndex = 0; msIndex < masterStatus[vessel.id].allPartsStatus.Count; msIndex++) { if (masterStatus[vessel.id].allPartsStatus[msIndex].partID != vessel.parts[j].flightID) { continue; } existingPartIndex = msIndex; break; } Profiler.EndSample(); if (existingPartIndex > -1) { Profiler.BeginSample("Existing Part"); //PartStatus partStatus = masterStatus[vessel.id].allPartsStatus[existingPartIndex]; PartStatus partStatus = new PartStatus(); partStatus.lastSeen = currentUTC; partStatus.flightCore = core; partStatus.partName = core.Title; partStatus.partID = vessel.parts[j].flightID; Profiler.BeginSample("Part - GetPartStatus"); partStatus.partStatus = core.GetPartStatus(); Profiler.EndSample(); // get any failures Profiler.BeginSample("Part - GetActiveFailures"); partStatus.failures = core.GetActiveFailures(); Profiler.EndSample(); Profiler.BeginSample("Part - GetFlightData"); partStatus.flightData = core.GetFlightData(); Profiler.EndSample(); Profiler.BeginSample("Part - GetBaseFailureRate"); double failureRate = core.GetBaseFailureRate(); Profiler.EndSample(); Profiler.BeginSample("Part - GetWorstMomentaryFailureRate"); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } Profiler.EndSample(); partStatus.momentaryFailureRate = failureRate; partStatus.acknowledged = false; Profiler.BeginSample("Part - FailureRateToMTBFString"); core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, false, 999, out partStatus.mtbfString); //partStatus.mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); Profiler.EndSample(); masterStatus[vessel.id].allPartsStatus[existingPartIndex] = partStatus; Profiler.EndSample(); } else { Profiler.BeginSample("New Part"); PartStatus partStatus = new PartStatus(); partStatus.lastSeen = currentUTC; partStatus.flightCore = core; partStatus.partName = core.Title; partStatus.partID = vessel.parts[j].flightID; partStatus.partStatus = core.GetPartStatus(); // get any failures partStatus.failures = core.GetActiveFailures(); partStatus.flightData = core.GetFlightData(); double failureRate = core.GetBaseFailureRate(); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } partStatus.momentaryFailureRate = failureRate; partStatus.acknowledged = false; core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, false, 999, out partStatus.mtbfString); masterStatus[vessel.id].allPartsStatus.Add(partStatus); Profiler.EndSample(); } Profiler.EndSample(); } else { Profiler.BeginSample("MasterStatus New Vessel"); // Vessel is not in the Master Status so create a new entry for it and add this part PartStatus partStatus = new PartStatus(); partStatus.lastSeen = currentUTC; partStatus.flightCore = core; partStatus.partName = core.Title; partStatus.partID = vessel.parts[j].flightID; partStatus.partStatus = core.GetPartStatus(); // get any failures partStatus.failures = core.GetActiveFailures(); partStatus.flightData = core.GetFlightData(); double failureRate = core.GetBaseFailureRate(); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } partStatus.momentaryFailureRate = failureRate; partStatus.acknowledged = false; partStatus.mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); MasterStatusItem masterStatusItem = new MasterStatusItem(); masterStatusItem.vesselID = vessel.id; masterStatusItem.vesselName = vessel.GetName(); masterStatusItem.allPartsStatus = new List <PartStatus>(); masterStatusItem.allPartsStatus.Add(partStatus); masterStatus.Add(vessel.id, masterStatusItem); Profiler.EndSample(); } } Profiler.EndSample(); } } Profiler.EndSample(); if (currentUTC >= lastDataPoll + tfScenario.userSettings.minTimeBetweenDataPoll) { lastDataPoll = currentUTC; } if (currentUTC >= lastFailurePoll + tfScenario.userSettings.minTimeBetweenFailurePoll) { lastFailurePoll = currentUTC; } } Profiler.EndSample(); }
internal override void Update() { if (!isReady) { return; } if (masterStatus == null) { masterStatus = new Dictionary <Guid, MasterStatusItem>(); } currentUTC = Planetarium.GetUniversalTime(); // ensure out vessel list is up to date CacheVessels(); if (currentUTC >= lastMasterStatusUpdate + tfScenario.userSettings.masterStatusUpdateFrequency) { lastMasterStatusUpdate = currentUTC; VerifyMasterStatus(); } // process vessels foreach (var entry in knownVessels) { Vessel vessel = FlightGlobals.Vessels.Find(v => v.id == entry.Key); if (vessel.loaded) { foreach (Part part in vessel.parts) { ITestFlightCore core = TestFlightUtil.GetCore(part); if (core != null) { // Poll for flight data and part status if (currentUTC >= lastDataPoll + tfScenario.userSettings.masterStatusUpdateFrequency) { TestFlightData currentFlightData = new TestFlightData(); currentFlightData.scope = core.GetScope(); currentFlightData.flightData = core.GetFlightData(); currentFlightData.flightTime = core.GetFlightTime(); PartStatus partStatus = new PartStatus(); partStatus.flightCore = core; partStatus.partName = TestFlightUtil.GetPartTitle(part); partStatus.partID = part.flightID; partStatus.flightData = currentFlightData.flightData; partStatus.flightTime = currentFlightData.flightTime; partStatus.partStatus = core.GetPartStatus(); partStatus.timeToRepair = core.GetRepairTime(); double failureRate = core.GetBaseFailureRate(); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } partStatus.momentaryFailureRate = failureRate; partStatus.repairRequirements = core.GetRequirementsTooltip(); partStatus.acknowledged = core.IsFailureAcknowledged(); partStatus.activeFailure = core.GetFailureModule(); partStatus.mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); // Update or Add part status in Master Status if (masterStatus.ContainsKey(vessel.id)) { // Vessel is already in the Master Status, so check if part is in there as well int numItems = masterStatus[vessel.id].allPartsStatus.Count(p => p.partID == part.flightID); int existingPartIndex; if (numItems == 1) { existingPartIndex = masterStatus[vessel.id].allPartsStatus.FindIndex(p => p.partID == part.flightID); masterStatus[vessel.id].allPartsStatus[existingPartIndex] = partStatus; } else if (numItems == 0) { masterStatus[vessel.id].allPartsStatus.Add(partStatus); } else { existingPartIndex = masterStatus[vessel.id].allPartsStatus.FindIndex(p => p.partID == part.flightID); masterStatus[vessel.id].allPartsStatus[existingPartIndex] = partStatus; Log("[ERROR] TestFlightManager: Found " + numItems + " matching parts in Master Status Display!"); } } else { // Vessel is not in the Master Status so create a new entry for it and add this part MasterStatusItem masterStatusItem = new MasterStatusItem(); masterStatusItem.vesselID = vessel.id; masterStatusItem.vesselName = vessel.GetName(); masterStatusItem.allPartsStatus = new List <PartStatus>(); masterStatusItem.allPartsStatus.Add(partStatus); masterStatus.Add(vessel.id, masterStatusItem); } PartFlightData data = tfScenario.GetFlightDataForPartName(TestFlightUtil.GetFullPartName(part)); if (data != null) { data.AddFlightData(part.name, currentFlightData); } else { data = new PartFlightData(); data.AddFlightData(TestFlightUtil.GetFullPartName(part), currentFlightData); tfScenario.SetFlightDataForPartName(TestFlightUtil.GetFullPartName(part), data); } } } } } if (currentUTC >= lastDataPoll + tfScenario.userSettings.minTimeBetweenDataPoll) { lastDataPoll = currentUTC; } if (currentUTC >= lastFailurePoll + tfScenario.userSettings.minTimeBetweenFailurePoll) { lastFailurePoll = currentUTC; } } }
internal override void Update() { if (!isReady) { return; } if (masterStatus == null) { masterStatus = new Dictionary <Guid, MasterStatusItem>(); } currentUTC = Planetarium.GetUniversalTime(); // ensure out vessel list is up to date CacheVessels(); if (currentUTC >= lastMasterStatusUpdate + tfScenario.userSettings.masterStatusUpdateFrequency) { lastMasterStatusUpdate = currentUTC; VerifyMasterStatus(); } // process vessels foreach (var entry in knownVessels) { Vessel vessel = FlightGlobals.Vessels.Find(v => v.id == entry.Key); if (vessel.loaded) { foreach (Part part in vessel.parts) { // Each KSP part can be composed of N virtual parts List <string> cores = TestFlightInterface.GetActiveCores(part); if (cores == null || cores.Count <= 0) { continue; } foreach (string activeCore in cores) { ITestFlightCore core = TestFlightUtil.GetCore(part, activeCore); if (core != null) { // Poll for flight data and part status if (currentUTC >= lastDataPoll + tfScenario.userSettings.masterStatusUpdateFrequency) { // Old data structure deprecated v1.3 PartStatus partStatus = new PartStatus(); partStatus.lastSeen = currentUTC; partStatus.flightCore = core; partStatus.partName = core.Title; partStatus.partID = part.flightID; partStatus.partStatus = core.GetPartStatus(); // get any failures partStatus.failures = core.GetActiveFailures(); partStatus.flightData = core.GetFlightData(); double failureRate = core.GetBaseFailureRate(); MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate(); if (momentaryFailureRate.valid && momentaryFailureRate.failureRate > failureRate) { failureRate = momentaryFailureRate.failureRate; } partStatus.momentaryFailureRate = failureRate; partStatus.acknowledged = false; partStatus.mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); // Update or Add part status in Master Status if (masterStatus.ContainsKey(vessel.id)) { // Vessel is already in the Master Status, so check if part is in there as well int numItems = masterStatus[vessel.id].allPartsStatus.Count(p => p.partID == part.flightID); int existingPartIndex; if (numItems == 1) { existingPartIndex = masterStatus[vessel.id].allPartsStatus.FindIndex(p => p.partID == part.flightID); masterStatus[vessel.id].allPartsStatus[existingPartIndex] = partStatus; } else if (numItems == 0) { masterStatus[vessel.id].allPartsStatus.Add(partStatus); } else { existingPartIndex = masterStatus[vessel.id].allPartsStatus.FindIndex(p => p.partID == part.flightID); masterStatus[vessel.id].allPartsStatus[existingPartIndex] = partStatus; Log("[ERROR] TestFlightManager: Found " + numItems + " matching parts in Master Status Display!"); } } else { // Vessel is not in the Master Status so create a new entry for it and add this part MasterStatusItem masterStatusItem = new MasterStatusItem(); masterStatusItem.vesselID = vessel.id; masterStatusItem.vesselName = vessel.GetName(); masterStatusItem.allPartsStatus = new List <PartStatus>(); masterStatusItem.allPartsStatus.Add(partStatus); masterStatus.Add(vessel.id, masterStatusItem); } } } } } } if (currentUTC >= lastDataPoll + tfScenario.userSettings.minTimeBetweenDataPoll) { lastDataPoll = currentUTC; } if (currentUTC >= lastFailurePoll + tfScenario.userSettings.minTimeBetweenFailurePoll) { lastFailurePoll = currentUTC; } } }
internal override void DrawWindow(int id) { if (!tfScenario.SettingsEnabled) { return; } if (!isReady) { return; } if (SelectedPart == null) { return; } ITestFlightCore core = null; GUILayout.BeginVertical(); GUILayout.Label(String.Format("Selected Part: {0}", selectedAlias), Styles.styleEditorTitle); core = TestFlightUtil.GetCore(SelectedPart, selectedAlias); if (core != null) { float flightData = core.GetFlightData(); if (flightData < 0f) { flightData = 0f; } core.InitializeFlightData(flightData); GUILayout.BeginHorizontal(); double failureRate = core.GetBaseFailureRate(); Log(String.Format("Failure rate is {0:f2}", failureRate)); String mtbfString = core.FailureRateToMTBFString(failureRate, TestFlightUtil.MTBFUnits.SECONDS, 999); GUILayout.Label(String.Format("{0,-7:F2}<b>du</b>", flightData), GUILayout.Width(75)); GUILayout.Label(String.Format("{0,-5:F2} MTBF", mtbfString), GUILayout.Width(125)); GUILayout.EndHorizontal(); Log("Checking for RnD Status"); string partName = selectedAlias; float maxRnDData = core.GetMaximumRnDData(); if (flightData >= maxRnDData) { Log("Part has reached Max RnD"); GUILayout.Label("Part flight data meets or exceeds maximum lab R&D amount", Styles.styleEditorText); } else { Log("Part is RnD Eligible"); if (!tfRnDScenario.IsPartBeingResearched(partName)) { Log("Part is not being researched. Show research buttons"); int frequency = (int)tfRnDScenario.updateFrequency; Log(String.Format("Update Frequency is {0}", frequency)); TimeSpan span = new TimeSpan(0, 0, frequency); string cycleString; if (span.TotalDays > 1d) { cycleString = String.Format("{0:F2} days", span.TotalDays); } else { cycleString = String.Format("{0:F2} day", span.TotalDays); } GUILayout.Label("Hire Research Team", Styles.styleEditorTitle); GUILayout.Label("Research teams deduct funds and add flight data to your part", Styles.styleEditorText); GUILayout.Label("A research cycle lasts <b>" + cycleString + "</b>", Styles.styleEditorText); GUILayout.Label("At the end of each cycle, funds will be deducted and data added", Styles.styleEditorText); GUILayout.Label("The costs and research rate varies by team", Styles.styleEditorText); List <TestFlightRNDTeamSettings> teams = tfRnDScenario.GetAvailableTeams(); if (teams != null) { int numTeams = teams.Count; for (int i = 0; i < numTeams; i++) { GUILayout.BeginHorizontal(); if (GUILayout.Button(String.Format("Hire Team"), GUILayout.Width(100))) { tfRnDScenario.AddResearchTeam(SelectedPart, selectedAlias, i); } Log(String.Format("cycle is {0}", cycleString)); float points = teams[i].points; float cost = teams[i].costFactor * points; points = points * core.GetRnDRate(); cost = cost * core.GetRnDCost(); GUILayout.Label(String.Format("<b>{0,7:F2}</b> data, <b>{1,7:F2}</b> funds", points, cost), Styles.styleEditorTextAligned); GUILayout.EndHorizontal(); } } } else { Log("Part is already being researched. Show button to stop"); if (GUILayout.Button("Stop Research", GUILayout.Width(200))) { tfRnDScenario.RemoveResearch(partName); } } } } if (DrawToggle(ref tfScenario.userSettings.editorWindowLocked, "Lock Window", Styles.styleToggle)) { if (tfScenario.userSettings.editorWindowLocked) { CalculateWindowBounds(); tfScenario.userSettings.editorWindowPosition = WindowRect; DragEnabled = false; } else { DragEnabled = true; } tfScenario.userSettings.Save(); } GUILayout.EndVertical(); }