diff --git a/MicroEngineerProject/MicroEngineer.csproj b/MicroEngineerProject/MicroEngineer.csproj index 8dc9ead..3a2aaab 100644 --- a/MicroEngineerProject/MicroEngineer.csproj +++ b/MicroEngineerProject/MicroEngineer.csproj @@ -1,28 +1,39 @@ - - netstandard2.0 - true - latest - true - OnBuildSuccess - - - - - - - - - - - external_dlls\UnityEngine.IMGUIModule.dll - - - external_dlls\UnityEngine.TextRenderingModule.dll - - - - - - + + netstandard2.0 + true + latest + true + OnBuildSuccess + + + + + + + + + + external_dlls\UitkForKsp2.dll + + + external_dlls\UitkForKsp2.Controls.dll + + + external_dlls\UnityEngine.IMGUIModule.dll + + + external_dlls\UnityEngine.InputLegacyModule.dll + + + external_dlls\UnityEngine.TextRenderingModule.dll + + + external_dlls\UnityEngine.UIElementsModule.dll + + + + + + \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs index 2ebc799..72d755e 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using BepInEx.Logging; +using Newtonsoft.Json; namespace MicroMod { @@ -15,6 +16,7 @@ public class BaseEntry public string Description; [JsonProperty] public MicroEntryCategory Category; + public EntryType EntryType; public bool IsDefault; [JsonProperty] public bool HideWhenNoData; @@ -38,10 +40,53 @@ public string Formatting set => _formatting = value; } - public virtual object EntryValue { get; set; } + private object entryValue; + public virtual object EntryValue + { + get => entryValue; + + set + { + if (value != entryValue) + { + entryValue = value; + + switch (EntryType) + { + case EntryType.BasicText: + OnEntryValueChanged?.Invoke(ValueDisplay, UnitDisplay); + break; + case EntryType.Time: + var time = Utility.ParseSecondsToTimeFormat((double?)value ?? 0); + OnEntryTimeValueChanged?.Invoke(time.Days, time.Hours, time.Minutes, time.Seconds); + break; + case EntryType.LatitudeLongitude: + var latLon = Utility.ParseDegreesToDMSFormat((double?)value ?? 0); + OnEntryLatLonChanged?.Invoke(latLon.Degrees, latLon.Minutes, latLon.Seconds, BaseUnit); + break; + case EntryType.StageInfo: + OnStageInfoChanged?.Invoke((List)entryValue); + break; + case EntryType.Separator: + break; + default: + break; + } + } + } + } + + public delegate void EntryValueChanged(string value, string unit); + public delegate void EntryTimeValueChanged(int days, int hours, int minutes, int seconds); + public delegate void EntryLatLonChanged(int degrees, int minutes, int seconds, string direction); + public delegate void StageInfoChanged(List stages); + public event EntryValueChanged OnEntryValueChanged; + public event EntryTimeValueChanged OnEntryTimeValueChanged; + public event EntryLatLonChanged OnEntryLatLonChanged; + public event StageInfoChanged OnStageInfoChanged; /// - /// Controls how the value should be displayed. Should be overriden in a inheritet class for a concrete implementation. + /// Controls how the value should be displayed. Can be overriden in a inheritet class for a more specialized implementation. /// public virtual string ValueDisplay { diff --git a/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs index 8721465..34730d7 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs @@ -1,5 +1,4 @@ - -namespace MicroMod +namespace MicroMod { public class BodyEntry : BaseEntry { } @@ -68,5 +67,5 @@ public override void RefreshData() } public override string ValueDisplay => base.ValueDisplay; - } + } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/FlightEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/FlightEntries.cs index da143df..0d76542 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/FlightEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/FlightEntries.cs @@ -1,5 +1,4 @@ - -namespace MicroMod +namespace MicroMod { public class FlightEntry : BaseEntry { } @@ -317,7 +316,7 @@ public override string ValueDisplay return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); } } - } + } public class DragCoefficient : FlightEntry { diff --git a/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs index 657a0e6..a8dd85c 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs @@ -6,7 +6,7 @@ namespace MicroMod { public class ManeuverEntry : BaseEntry { - internal int SelectedNodeIndex = 0; + public int SelectedNodeIndex = 0; } public class DeltaVRequired : ManeuverEntry @@ -123,6 +123,7 @@ public TimeToNode() { Name = "Time to node"; Description = "Time until vessel reaches the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = true; BaseUnit = "s"; @@ -134,17 +135,6 @@ public override void RefreshData() List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); EntryValue = nodes?.ElementAtOrDefault(base.SelectedNodeIndex)?.Time - GameManager.Instance.Game.UniverseModel.UniversalTime; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class BurnTime : ManeuverEntry @@ -153,6 +143,7 @@ public BurnTime() { Name = "Burn time"; Description = "Length of time needed to complete the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = true; BaseUnit = "s"; @@ -164,17 +155,6 @@ public override void RefreshData() List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); EntryValue = nodes?.ElementAtOrDefault(base.SelectedNodeIndex)?.BurnDuration; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class ProjectedAp : ManeuverEntry @@ -239,6 +219,7 @@ public Maneuver_TimeToAp() { Name = "Time to Ap."; Description = "Shows the Time to Apoapsis vessel will have after reaching the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = true; BaseUnit = "s"; @@ -252,17 +233,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .TimeToAp; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_TimeToPe : ManeuverEntry @@ -271,6 +241,7 @@ public Maneuver_TimeToPe() { Name = "Time to Pe."; Description = "Shows the Time to Periapsis vessel will have after reaching the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = true; BaseUnit = "s"; @@ -284,17 +255,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .TimeToPe; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_Inclination : ManeuverEntry @@ -351,6 +311,7 @@ public Maneuver_Period() { Name = "Period"; Description = "The period of the vessel's orbit after the burn."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = true; BaseUnit = "s"; @@ -364,17 +325,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .period; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_TrueAnomaly : ManeuverEntry @@ -642,11 +592,12 @@ public Maneuver_ObT() { Name = "Orbit time"; Description = "Shows orbit time in seconds from the Periapsis when vessel reaches the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = false; BaseUnit = "s"; NumberOfDecimalDigits = 0; - Formatting = "N"; + Formatting = null; } public override void RefreshData() @@ -656,17 +607,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .ObT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_OrbitPercent : ManeuverEntry @@ -699,11 +639,12 @@ public Maneuver_EndUT() { Name = "UT"; Description = "Universal Time when vessel reaches the maneuver node."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = false; BaseUnit = "s"; NumberOfDecimalDigits = 3; - Formatting = "N"; + Formatting = null; } public override void RefreshData() @@ -713,17 +654,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .EndUT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_UniversalTimeAtClosestApproach : ManeuverEntry @@ -732,6 +662,7 @@ public Maneuver_UniversalTimeAtClosestApproach() { Name = "UT close.app."; Description = "Universal Time at the point of closest approach."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = false; BaseUnit = null; @@ -745,17 +676,6 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .UniversalTimeAtClosestApproach; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Maneuver_UniversalTimeAtSoiEncounter : ManeuverEntry @@ -764,6 +684,7 @@ public Maneuver_UniversalTimeAtSoiEncounter() { Name = "UT SOI enc."; Description = "Universal Time at the point of transition to another Sphere Of Influence."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Maneuver; IsDefault = false; BaseUnit = null; @@ -777,16 +698,5 @@ public override void RefreshData() .ElementAtOrDefault(base.SelectedNodeIndex)? .UniversalTimeAtSoiEncounter; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/MiscEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/MiscEntries.cs index 7bc6ce5..8e5139c 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/MiscEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/MiscEntries.cs @@ -9,13 +9,14 @@ public class Separator : MiscEntry { public Separator() { - Name = "--------------"; + Name = "Separator"; Description = "It's a separator!"; + EntryType = EntryType.Separator; Category = MicroEntryCategory.Misc; IsDefault = false; - BaseUnit = "---"; + BaseUnit = null; Formatting = null; - EntryValue = "--------------"; + EntryValue = null; } } @@ -46,28 +47,18 @@ public EndUT() { Name = "UT"; Description = "Universal Time."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; NumberOfDecimalDigits = 0; - Formatting = "N"; + Formatting = null; } public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.EndUT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class StartUT : MiscEntry @@ -76,28 +67,18 @@ public StartUT() { Name = "Start UT"; Description = "Time passed since vessel was launched."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; NumberOfDecimalDigits = 0; - Formatting = "N"; + Formatting = null; } public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.StartUT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class LaunchTime : MiscEntry @@ -106,6 +87,7 @@ public LaunchTime() { Name = "Launch time"; Description = "Universal Time when vessel was launched."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; @@ -117,17 +99,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.launchTime; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class TimeSinceLaunch : MiscEntry @@ -136,6 +107,7 @@ public TimeSinceLaunch() { Name = "Time since launch"; Description = "Time since the vessel launched."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; @@ -147,17 +119,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.TimeSinceLaunch; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class AutopilotStatus_IsEnabled : MiscEntry @@ -246,6 +207,7 @@ public UniversalTimeAtClosestApproach() { Name = "UT close.app."; Description = "Universal Time at closest approach."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; @@ -257,17 +219,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.UniversalTimeAtClosestApproach; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class UniversalTimeAtSoiEncounter : MiscEntry @@ -276,6 +227,7 @@ public UniversalTimeAtSoiEncounter() { Name = "UT SOI enc."; Description = "Universal Time at the point of transfer to another sphere of influence."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Misc; IsDefault = false; BaseUnit = "s"; @@ -287,16 +239,5 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.UniversalTimeAtSoiEncounter; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/OabStageInfoEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/OabStageInfoEntries.cs index 7db5168..1846891 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/OabStageInfoEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/OabStageInfoEntries.cs @@ -1,7 +1,7 @@ -using KSP.Game; +using BepInEx.Logging; +using KSP.Game; using KSP.Sim.DeltaV; using KSP.Sim.impl; -using Newtonsoft.Json; namespace MicroMod { @@ -16,6 +16,7 @@ public TotalBurnTime_OAB() { Name = "Total burn time (OAB)"; Description = "Shows the total length of burn the vessel can mantain."; + EntryType = EntryType.Time; Category = MicroEntryCategory.OAB; IsDefault = true; BaseUnit = "s"; @@ -28,20 +29,6 @@ public override void RefreshData() { EntryValue = Utility.VesselDeltaVComponentOAB?.TotalBurnTime; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - if (UseDHMSFormatting) - return Utility.SecondsToTimeString((double)EntryValue); - else - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } } public class TotalDeltaVASL_OAB : OabStageInfoEntry @@ -121,9 +108,6 @@ public override void RefreshData() /// public class Torque : OabStageInfoEntry { - [JsonProperty] - internal bool IsActive = false; - public Torque() { Name = "Torque"; @@ -136,9 +120,6 @@ public Torque() public override void RefreshData() { - if (!this.IsActive) - return; - Vector3d com = GameManager.Instance?.Game?.OAB?.Current?.Stats?.MainAssembly?.CenterOfProperties?.CoM ?? Vector3d.zero; Vector3d cot = GameManager.Instance?.Game?.OAB?.Current?.Stats?.MainAssembly?.CenterOfProperties?.CoT ?? Vector3d.zero; @@ -168,7 +149,7 @@ public override string ValueDisplay { get { - if (EntryValue == null || !this.IsActive) + if (EntryValue == null) return "-"; if ((double)EntryValue >= 1.0) @@ -184,12 +165,15 @@ public override string ValueDisplay /// public class StageInfo_OAB : OabStageInfoEntry { - public List CelestialBodyForStage = new(); + public List CelestialBodyForStage = new(); + public delegate void StageInfoOABChanged(List stages); + public event StageInfoOABChanged OnStageInfoOABChanged; public StageInfo_OAB() { Name = "Stage Info (OAB)"; Description = "Holds a list of stage info parameters."; + EntryType = EntryType.StageInfoOAB; Category = MicroEntryCategory.OAB; IsDefault = true; BaseUnit = null; @@ -204,35 +188,62 @@ public override void RefreshData() if (Utility.VesselDeltaVComponentOAB?.StageInfo == null) return; - foreach (var stage in Utility.VesselDeltaVComponentOAB.StageInfo) + for (int i = 0; i < Utility.VesselDeltaVComponentOAB.StageInfo.Count; i++) { - ((List)EntryValue).Add(new DeltaVStageInfo_OAB + var retrieved = Utility.VesselDeltaVComponentOAB.StageInfo[i]; + var stage = new DeltaVStageInfo_OAB() + { + Index = i, + DeltaVActual = retrieved.DeltaVActual, + DeltaVASL = retrieved.DeltaVatASL, + DeltaVVac = retrieved.DeltaVinVac, + DryMass = retrieved.DryMass, + EndMass = retrieved.EndMass, + FuelMass = retrieved.FuelMass, + IspASL = retrieved.IspASL, + IspActual = retrieved.IspActual, + IspVac = retrieved.IspVac, + SeparationIndex = retrieved.SeparationIndex, + Stage = retrieved.Stage, + StageBurnTime = Utility.ParseSecondsToTimeFormat(retrieved.StageBurnTime), + StageMass = retrieved.StageMass, + StartMass = retrieved.StartMass, + TWRASL = retrieved.TWRASL, + TWRActual = retrieved.TWRActual, + TWRVac = retrieved.TWRVac, + ThrustASL = retrieved.ThrustASL, + ThrustActual = retrieved.ThrustActual, + ThrustVac = retrieved.ThrustVac, + TotalExhaustVelocityASL = retrieved.TotalExhaustVelocityASL, + TotalExhaustVelocityActual = retrieved.TotalExhaustVelocityActual, + TotalExhaustVelocityVAC = retrieved.TotalExhaustVelocityVAC, + DeltaVStageInfo = retrieved + }; + + if (i < CelestialBodyForStage.Count) { - DeltaVActual = stage.DeltaVActual, - DeltaVASL = stage.DeltaVatASL, - DeltaVVac = stage.DeltaVinVac, - DryMass = stage.DryMass, - EndMass = stage.EndMass, - FuelMass = stage.FuelMass, - IspASL = stage.IspASL, - IspActual = stage.IspActual, - IspVac = stage.IspVac, - SeparationIndex = stage.SeparationIndex, - Stage = stage.Stage, - StageBurnTime = stage.StageBurnTime, - StageMass = stage.StageMass, - StartMass = stage.StartMass, - TWRASL = stage.TWRASL, - TWRActual = stage.TWRActual, - TWRVac = stage.TWRVac, - ThrustASL = stage.ThrustASL, - ThrustActual = stage.ThrustActual, - ThrustVac = stage.ThrustVac, - TotalExhaustVelocityASL = stage.TotalExhaustVelocityASL, - TotalExhaustVelocityActual = stage.TotalExhaustVelocityActual, - TotalExhaustVelocityVAC = stage.TotalExhaustVelocityVAC, - DeltaVStageInfo = stage - }); + // CelestialBody already created for this stage. Attaching it to the stage. + stage.CelestialBody = CelestialBodyForStage[i]; + } + else + { + // This is a new stage. Need to create another CelestialBody. + var cel = MicroCelestialBodies.Instance.GetHomeBody(); + stage.CelestialBody = cel; + CelestialBodyForStage.Add(cel); + } + + // Apply TWR factor to the value and recalculate sea level TWR and DeltaV + stage.Recalculate_TWR(); + stage.Recalculate_SLT(); + stage.Recalculate_DeltaVSeaLevel(); + + // KSP2 has a strange way of displaying stage numbers, so we need a little hack + stage.Recalculate_StageNumber(Utility.VesselDeltaVComponentOAB.StageInfo.Count); + + ((List)EntryValue).Add(stage); + + OnStageInfoOABChanged?.Invoke(((List)EntryValue).Where(s => s.DeltaVVac > 0.0001 || s.DeltaVASL > 0.0001).ToList()); } } @@ -244,45 +255,49 @@ public override string ValueDisplay } } - /// - /// Adds a new string to the CelestialBodyForStage list that corresponds to the HomeWorld, i.e. Kerbin - /// - /// - internal void AddNewCelestialBody(MicroCelestialBodies celestialBodies) + public void UpdateCelestialBodyAtIndex(int index, string selectedBodyName) { - this.CelestialBodyForStage.Add(celestialBodies.Bodies.Find(b => b.IsHomeWorld).Name); + var body = MicroCelestialBodies.Instance.GetBodyByName(selectedBodyName); + CelestialBodyForStage[index] = body; + RefreshData(); } } /// /// Parameters for one stage /// - internal class DeltaVStageInfo_OAB + public class DeltaVStageInfo_OAB { - internal double DeltaVActual; - internal double DeltaVASL; - internal double DeltaVVac; - internal double DryMass; - internal double EndMass; - internal double FuelMass; - internal double IspASL; - internal double IspActual; - internal double IspVac; - internal int SeparationIndex; - internal int Stage; - internal double StageBurnTime; - internal double StageMass; - internal double StartMass; - internal float TWRASL; - internal float TWRActual; - internal float TWRVac; - internal float ThrustASL; - internal float ThrustActual; - internal float ThrustVac; - internal float TotalExhaustVelocityASL; - internal float TotalExhaustVelocityActual; - internal float TotalExhaustVelocityVAC; - internal DeltaVStageInfo DeltaVStageInfo; + /// + /// Index in DeltaVStageInfo_OAB is linked to the CelestialBodyForStage Index. + /// When stages are refreshed, DeltaVStageInfo_OAB grabs the CelestialBodyForStage at the same Index. + /// + public int Index; + public double DeltaVActual; + public double DeltaVASL; + public double DeltaVVac; + public double DryMass; + public double EndMass; + public double FuelMass; + public double IspASL; + public double IspActual; + public double IspVac; + public int SeparationIndex; + public int Stage; + public TimeParsed StageBurnTime; + public double StageMass; + public double StartMass; + public float TWRASL; + public float TWRActual; + public float TWRVac; + public float ThrustASL; + public float ThrustActual; + public float ThrustVac; + public float TotalExhaustVelocityASL; + public float TotalExhaustVelocityActual; + public float TotalExhaustVelocityVAC; + public CelestialBody CelestialBody; + public DeltaVStageInfo DeltaVStageInfo; private float GetThrustAtAltitude(double altitude, CelestialBodyComponent cel) => this.DeltaVStageInfo.EnginesActiveInStage?.Select(e => e.Engine.MaxThrustOutputAtm(atmPressure: cel.GetPressure(altitude) / 101.325))?.Sum() ?? 0; private double GetISPAtAltitude(double altitude, CelestialBodyComponent cel) @@ -295,7 +310,13 @@ private double GetISPAtAltitude(double altitude, CelestialBodyComponent cel) } private double GetDeltaVelAlt(double altitude, CelestialBodyComponent cel) => GetISPAtAltitude(altitude, cel) * 9.80665 * Math.Log(this.DeltaVStageInfo.StartMass / this.DeltaVStageInfo.EndMass); private double GetTWRAtAltitude(double altitude, CelestialBodyComponent cel) => this.DeltaVStageInfo.TWRVac * (GetThrustAtAltitude(altitude, cel) / this.DeltaVStageInfo.ThrustVac); - internal double GetTWRAtSeaLevel(CelestialBodyComponent cel) => this.GetTWRAtAltitude(0, cel); - internal double GetDeltaVelAtSeaLevel(CelestialBodyComponent cel) => GetDeltaVelAlt(0, cel); + private double GetTWRAtSeaLevel(CelestialBodyComponent cel) => this.GetTWRAtAltitude(0, cel); + private double GetDeltaVelAtSeaLevel(CelestialBodyComponent cel) => GetDeltaVelAlt(0, cel); + + // Public methods to be used to recalculate retrieved values + public void Recalculate_TWR() => this.TWRVac = this.TWRVac * (float)this.CelestialBody.TwrFactor; + public void Recalculate_SLT() => this.TWRASL = (float)(this.GetTWRAtSeaLevel(this.CelestialBody.CelestialBodyComponent) * this.CelestialBody.TwrFactor); + public void Recalculate_DeltaVSeaLevel() => this.DeltaVASL = this.GetDeltaVelAtSeaLevel(this.CelestialBody.CelestialBodyComponent); + public void Recalculate_StageNumber(int noOfStages) => this.Stage = noOfStages - this.Stage; } } diff --git a/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs index 37c1cbb..648201b 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs @@ -62,9 +62,10 @@ public TimeToApoapsis() { Name = "Time to Ap."; Description = "Shows the time until the vessel reaches apoapsis, the highest point of the orbit."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Orbital; IsDefault = true; - BaseUnit = "s"; + BaseUnit = null; Formatting = null; } @@ -72,17 +73,6 @@ public override void RefreshData() { EntryValue = (Utility.ActiveVessel.Situation == VesselSituations.Landed || Utility.ActiveVessel.Situation == VesselSituations.PreLaunch) ? 0f : Utility.ActiveVessel.Orbit.TimeToAp; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class TimeToPeriapsis : OrbitalEntry @@ -91,6 +81,7 @@ public TimeToPeriapsis() { Name = "Time to Pe."; Description = "Shows the time until the vessel reaches periapsis, the lowest point of the orbit."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Orbital; IsDefault = true; BaseUnit = "s"; @@ -101,17 +92,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.TimeToPe; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Inclination : OrbitalEntry @@ -162,6 +142,7 @@ public Period() { Name = "Period"; Description = "Shows the amount of time it will take to complete a full orbit."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Orbital; IsDefault = true; BaseUnit = "s"; @@ -172,17 +153,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.period; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class OrbitalSpeed : OrbitalEntry @@ -448,6 +418,7 @@ public ObT() { Name = "Orbit time"; Description = "Shows orbit time in seconds from the Periapsis."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Orbital; IsDefault = false; BaseUnit = "s"; @@ -459,17 +430,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.ObT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class OrbitPercent : OrbitalEntry @@ -534,16 +494,5 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.Orbit.UniversalTimeAtSoiEncounter - GameManager.Instance.Game.UniverseModel.UniversalTime; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return (double)EntryValue >= 0 ? Utility.SecondsToTimeString((double)EntryValue) : "-"; - } - } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/StageInfoEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/StageInfoEntries.cs index c3c3b45..f01a8d3 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/StageInfoEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/StageInfoEntries.cs @@ -1,4 +1,5 @@ - +using KSP.Sim.DeltaV; + namespace MicroMod { public class StageInfoEntry: BaseEntry @@ -9,7 +10,8 @@ public class StageInfo : StageInfoEntry public StageInfo() { Name = "Stage Info"; - Description = "Stage Info object, not implemented yet."; // TODO Stage Info display and description + Description = ""; + EntryType = EntryType.StageInfo; Category = MicroEntryCategory.Stage; IsDefault = true; BaseUnit = null; @@ -18,9 +20,37 @@ public StageInfo() public override void RefreshData() { - EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo; + EntryValue = ParseStages(Utility.ActiveVessel.VesselDeltaV?.StageInfo); } public override string ValueDisplay => base.ValueDisplay; + + public List ParseStages(List deltaVStages) + { + var stages = new List(); + + if (deltaVStages == null) + return stages; + + var nonEmptyStages = deltaVStages.FindAll(s => s.DeltaVinVac > 0.0001 || s.DeltaVatASL > 0.0001); + + for (int i = nonEmptyStages.Count - 1; i >= 0; i--) + { + var time = Utility.ParseSecondsToTimeFormat(nonEmptyStages[i].StageBurnTime); + var stage = new Stage + { + StageNumber = deltaVStages.Count - nonEmptyStages[i].Stage, + DeltaVActual = nonEmptyStages[i].DeltaVActual, + TwrActual = nonEmptyStages[i].TWRActual, + BurnDays = time.Days, + BurnHours = time.Hours, + BurnMinutes = time.Minutes, + BurnSeconds = time.Seconds + }; + stages.Add(stage); + } + + return stages; + } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs index 22169e1..89b8f95 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs @@ -25,7 +25,8 @@ public AltitudeAgl() public override void RefreshData() { - EntryValue = Utility.ActiveVessel.AltitudeFromTerrain; + // AltitudeFromScenery seems to be the correct value to use for altitude above ground underneath the vessel + EntryValue = Utility.ActiveVessel.AltitudeFromScenery; } public override string ValueDisplay => base.ValueDisplay; @@ -75,7 +76,9 @@ public AltitudeFromScenery() public override void RefreshData() { - EntryValue = Utility.ActiveVessel.AltitudeFromScenery; + // We'll use AltitudeFromTerrain for this entry for now. It indicates some height above the ground level + // This may be a bug where they've switched AltitudeFromTerrain and AltitudeFromScenery values + EntryValue = Utility.ActiveVessel.AltitudeFromTerrain; } public override string ValueDisplay => base.ValueDisplay; @@ -130,7 +133,7 @@ public override void RefreshData() public override string ValueDisplay => base.ValueDisplay; } - + public class Situation : SurfaceEntry { public Situation() @@ -195,6 +198,7 @@ public Latitude() { Name = "Latitude"; Description = "Shows the vessel's latitude position around the celestial body. Latitude is the angle from the equator towards the poles."; + EntryType = EntryType.LatitudeLongitude; Category = MicroEntryCategory.Surface; IsDefault = true; Formatting = null; @@ -205,17 +209,6 @@ public override void RefreshData() EntryValue = Utility.ActiveVessel.Latitude; BaseUnit = Utility.ActiveVessel.Latitude < 0 ? "S" : "N"; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return Utility.DegreesToDMS((double)EntryValue); - } - } } public class Longitude : SurfaceEntry @@ -224,6 +217,7 @@ public Longitude() { Name = "Longitude"; Description = "Shows the vessel's longitude position around the celestial body. Longitude is the angle from the body's prime meridian to the current meridian."; + EntryType = EntryType.LatitudeLongitude; Category = MicroEntryCategory.Surface; IsDefault = true; Formatting = null; @@ -234,17 +228,6 @@ public override void RefreshData() EntryValue = Utility.ActiveVessel.Longitude; BaseUnit = Utility.ActiveVessel.Longitude < 0 ? "W" : "E"; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return Utility.DegreesToDMS((double)EntryValue); - } - } } public class DynamicPressure_kPa : SurfaceEntry @@ -337,5 +320,5 @@ public override void RefreshData() } public override string ValueDisplay => base.ValueDisplay; - } + } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/TargetEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/TargetEntries.cs index a1f144a..58ffac0 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/TargetEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/TargetEntries.cs @@ -256,6 +256,7 @@ public Target_Period() { Name = "Period"; Description = "Shows the amount of time it will take the target to complete a full orbit."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Target; IsDefault = true; BaseUnit = "s"; @@ -266,17 +267,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.period; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Target_Obtvelocity : TargetEntry @@ -517,6 +507,7 @@ public Target_ObT() { Name = "Orbit time"; Description = "Shows orbit time in seconds from the Periapsis."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Target; IsDefault = false; BaseUnit = "s"; @@ -528,17 +519,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.ObT; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class Target_ReferenceBodyConstants_Radius : TargetEntry @@ -688,6 +668,7 @@ public TimeToCloseApproach1() { Name = "C.A.Time1"; Description = "Close approach time to target (1)."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Target; IsDefault = true; HideWhenNoData = true; @@ -701,17 +682,6 @@ public override void RefreshData() EntryValue = isValid != null && isValid == true ? EntryValue = Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect1Target.UniversalTime - Utility.UniversalTime : null; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class RelativeSpeedAtCloseApproach1 : TargetEntry @@ -776,6 +746,7 @@ public TimeToCloseApproach2() { Name = "C.A.Time2"; Description = "Close approach time to target (2)."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Target; IsDefault = false; HideWhenNoData = true; @@ -789,17 +760,6 @@ public override void RefreshData() EntryValue = isValid != null && isValid == true ? EntryValue = Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect2Target.UniversalTime - Utility.UniversalTime : null; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? Utility.SecondsToTimeString((double)EntryValue, true, false) : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class RelativeSpeedAtCloseApproach2 : TargetEntry diff --git a/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs index 09f08c8..9136ad1 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs @@ -1,5 +1,4 @@ - -namespace MicroMod +namespace MicroMod { public class VesselEntry : BaseEntry { } @@ -21,7 +20,7 @@ public override void RefreshData() EntryValue = Utility.ActiveVessel.DisplayName; } - public override string ValueDisplay => EntryValue?.ToString(); + public override string ValueDisplay => base.ValueDisplay; } public class Mass : VesselEntry @@ -131,6 +130,7 @@ public TotalBurnTime() { Name = "Total burn time"; Description = "Burn Time vessel can sustain with 100% thrust."; + EntryType = EntryType.Time; Category = MicroEntryCategory.Vessel; IsDefault = false; BaseUnit = "s"; @@ -142,17 +142,6 @@ public override void RefreshData() { EntryValue = Utility.ActiveVessel.VesselDeltaV?.TotalBurnTime; } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, Utility.SecondsToTimeString((double)EntryValue, true, false)); - } - } } public class StageThrustActual : VesselEntry diff --git a/MicroEngineerProject/MicroEngineer/Managers/Manager.cs b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs index d74d035..d1647a9 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/Manager.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs @@ -1,22 +1,23 @@ using BepInEx.Logging; using KSP.Game; using System.Reflection; +using UitkForKsp2.API; using UnityEngine; namespace MicroMod { - internal class Manager + public class Manager { private static Manager _instance; - internal List Windows; - internal List Entries; + public List Windows; + public List Entries; private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Manager"); public List TextFieldNames = new List(); - internal Manager() + public Manager() { Entries = InitializeEntries(); Windows = InitializeWindows(); @@ -56,7 +57,7 @@ public void Update() /// /// Builds the list of all Entries /// - internal List InitializeEntries() + public List InitializeEntries() { Entries = new List(); @@ -83,7 +84,7 @@ internal List InitializeEntries() /// /// Builds the default Windows and fills them with default Entries /// - internal List InitializeWindows() + public List InitializeWindows() { Windows = new List(); @@ -96,17 +97,16 @@ internal List InitializeWindows() IsFlightActive = false, IsMapActive = false, //EditorRect = null, - FlightRect = new Rect(Styles.MainGuiX, Styles.MainGuiY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(1350, 160, 0, 0) // About 3/4 of the screen }); - Windows.Add(new SettingsWIndow + Windows.Add(new SettingsWindow { - ActiveTheme = Styles.ActiveTheme, IsEditorActive = false, IsFlightActive = false, IsMapActive = false, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight) + FlightRect = new Rect(ReferenceResolution.Width/2, ReferenceResolution.Height/2, 0, 0) }); Windows.Add(new EntryWindow @@ -123,7 +123,7 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Vessel, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Vessel && entry.IsDefault).ToList() }); @@ -141,7 +141,7 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Orbital, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Orbital && entry.IsDefault).ToList() }); @@ -159,7 +159,7 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Surface, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Surface && entry.IsDefault).ToList() }); @@ -177,17 +177,17 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Flight, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Flight && entry.IsDefault).ToList() }); - Windows.Add(new EntryWindow + Windows.Add(new TargetWindow { Name = "Target", Abbreviation = "TGT", Description = "Flight entries", IsEditorActive = false, - IsFlightActive = true, + IsFlightActive = false, IsMapActive = false, IsEditorPoppedOut = false, IsFlightPoppedOut = false, @@ -195,7 +195,7 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Target, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Target && entry.IsDefault).ToList() }); @@ -205,7 +205,7 @@ internal List InitializeWindows() Abbreviation = "MAN", Description = "Maneuver entries", IsEditorActive = false, - IsFlightActive = true, + IsFlightActive = false, IsMapActive = false, IsEditorPoppedOut = false, IsFlightPoppedOut = false, @@ -213,7 +213,7 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Maneuver, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Maneuver && entry.IsDefault).ToList() }); @@ -223,7 +223,7 @@ internal List InitializeWindows() Abbreviation = "STG", Description = "Stage entries", IsEditorActive = false, - IsFlightActive = true, + IsFlightActive = false, IsMapActive = false, IsEditorPoppedOut = false, IsFlightPoppedOut = false, @@ -231,24 +231,16 @@ internal List InitializeWindows() IsLocked = false, MainWindow = MainWindow.Stage, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Stage && entry.IsDefault).ToList() }); - Windows.Add(new EntryWindow + Windows.Add(new StageInfoOabWindow { - Name = "Stage (OAB)", - Abbreviation = "SOAB", - Description = "Stage Info window for OAB", - IsEditorActive = false, + IsEditorActive = true, IsFlightActive = false, // Not used IsMapActive = false, // Not used - IsEditorPoppedOut = true, // Not used - IsFlightPoppedOut = false, // Not used - IsMapPoppedOut = false, // Not used - IsLocked = false, // Not used - MainWindow = MainWindow.StageInfoOAB, - EditorRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, 0, 0), + EditorRect = new Rect(645, 41, 0, 0), // Top-center of the screen Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.OAB && entry.IsDefault).ToList() }); @@ -265,7 +257,7 @@ internal List InitializeWindows() /// Creates a new custom window user can fill with any entry /// /// - internal int CreateCustomWindow(List editableWindows) + public int CreateCustomWindow(List editableWindows) { // Default window's name will be CustomX where X represents the first not used integer int nameID = 1; @@ -289,7 +281,7 @@ internal int CreateCustomWindow(List editableWindows) IsLocked = false, MainWindow = MainWindow.None, //EditorRect = null, - FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + FlightRect = new Rect(ReferenceResolution.Width / 2, ReferenceResolution.Height / 2, 0, 0), Entries = new List() }; @@ -299,34 +291,15 @@ internal int CreateCustomWindow(List editableWindows) return editableWindows.Count - 1; } - internal void ResetLayout() + /// + /// TODO implement layout reset + /// + public void ResetLayout() { Windows.Clear(); Entries.Clear(); Entries = InitializeEntries(); Windows = InitializeWindows(); } - - internal void LoadLayout() - { - Utility.LoadLayout(Windows); - } - - internal void SaveLayout() => Utility.SaveLayout(Windows); - - public void PupulateTextFieldNames(List entries) - { - TextFieldNames.Clear(); - TextFieldNames.Add(Utility.InputDisableWindowAbbreviation); - TextFieldNames.Add(Utility.InputDisableWindowName); - - foreach (var entry in entries) - { - entry.Id = Guid.NewGuid(); - TextFieldNames.Add(entry.Id.ToString()); - } - } - - public void AddTextFieldName(string name) => TextFieldNames.Add(name); } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs index 990f1e0..dc329e4 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs @@ -1,15 +1,16 @@ -using KSP.Game; +using BepInEx.Logging; +using KSP.Game; using KSP.Messages; -using KSP.UI.Binding; -using UnityEngine; +using MicroEngineer.UI; namespace MicroMod { - internal class MessageManager + public class MessageManager { + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.MessageManager"); private static MessageManager _instance; - internal MessageManager() + public MessageManager() { } public static MessageManager Instance @@ -31,7 +32,7 @@ public void SubscribeToMessages() Utility.RefreshGameManager(); // While in OAB we use the VesselDeltaVCalculationMessage event to refresh data as it's triggered a lot less frequently than Update() - Utility.MessageCenter.Subscribe(new Action(this.RefreshStagingDataOAB)); + Utility.MessageCenter.Subscribe(new Action(obj => this.RefreshStagingDataOAB((VesselDeltaVCalculationMessage)obj))); // We are loading layout state when entering Flight or OAB game state Utility.MessageCenter.Subscribe(new Action(this.GameStateEntered)); @@ -63,66 +64,66 @@ private void OnManeuverRemovedMessage(MessageCenterMessage message) private void OnPartManipulationCompletedMessage(MessageCenterMessage obj) { - EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); - - Torque torque = (Torque)Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Torque"); + var torque = ((StageInfoOabWindow)Manager.Instance.Windows.Find(w => w is StageInfoOabWindow)).Entries.Find(e => e is Torque); torque.RefreshData(); } private void GameStateEntered(MessageCenterMessage obj) { Utility.RefreshGameManager(); + _logger.LogDebug($"Entered GameStateEntered. GameState: {Utility.GameState.GameState}." + + $"MainGui.IsFlightActive: {Manager.Instance.Windows.OfType().FirstOrDefault().IsFlightActive}." + + $"StageOab.IsEditorActive: {Manager.Instance.Windows.OfType().FirstOrDefault().IsEditorActive}."); + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) { Utility.LoadLayout(Manager.Instance.Windows); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) { - UI.Instance.ShowGuiFlight = Manager.Instance.Windows.OfType().FirstOrDefault().IsFlightActive; - GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(UI.Instance.ShowGuiFlight); - } + FlightSceneController.Instance.ShowGui = Manager.Instance.Windows.OfType().FirstOrDefault().IsFlightActive; + } if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) { - UI.Instance.ShowGuiOAB = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive; - GameObject.Find("BTN - MicroEngineerOAB")?.GetComponent()?.SetValue(UI.Instance.ShowGuiOAB); - UI.Instance.CelestialBodies.GetBodies(); - UI.Instance.CelestialBodySelectionStageIndex = -1; - Styles.SetActiveTheme(Theme.Gray); // TODO implement other themes in OAB + OABSceneController.Instance.ShowGui = Manager.Instance.Windows.OfType().FirstOrDefault().IsEditorActive; } } } private void GameStateLeft(MessageCenterMessage obj) - { + { Utility.RefreshGameManager(); + var maingui = Manager.Instance.Windows.OfType().FirstOrDefault(); + var stageOab = Manager.Instance.Windows.OfType().FirstOrDefault(); + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) { - Utility.SaveLayout(Manager.Instance.Windows); + _logger.LogDebug($"Initiating Save from GameStateLeft."); + Utility.SaveLayout(); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) - UI.Instance.ShowGuiFlight = false; + FlightSceneController.Instance.ShowGui = false; if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) - UI.Instance.ShowGuiOAB = false; + OABSceneController.Instance.ShowGui = false; } } /// /// Refresh all staging data while in OAB /// - private void RefreshStagingDataOAB(MessageCenterMessage obj) + public void RefreshStagingDataOAB(VesselDeltaVCalculationMessage msg = null) { // Check if message originated from ships in flight. If yes, return. - VesselDeltaVCalculationMessage msg = (VesselDeltaVCalculationMessage)obj; - if (msg.DeltaVComponent.Ship == null || !msg.DeltaVComponent.Ship.IsLaunchAssembly()) return; + if (msg != null && (msg.DeltaVComponent.Ship == null || !msg.DeltaVComponent.Ship.IsLaunchAssembly())) return; Utility.RefreshGameManager(); if (Utility.GameState.GameState != GameState.VehicleAssemblyBuilder) return; Utility.RefreshStagesOAB(); - EntryWindow stageWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + StageInfoOabWindow stageWindow = Manager.Instance.Windows.OfType().FirstOrDefault(); if (Utility.VesselDeltaVComponentOAB?.StageInfo == null) { @@ -130,8 +131,7 @@ private void RefreshStagingDataOAB(MessageCenterMessage obj) return; } - foreach (var entry in stageWindow.Entries) - entry.RefreshData(); + stageWindow.RefreshData(); } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs b/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs index 72d3006..9ea3112 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs @@ -1,25 +1,52 @@ -using KSP.Game; +using BepInEx.Logging; +using KSP.Game; using KSP.Sim.impl; namespace MicroMod { - internal class MicroCelestialBodies + public class MicroCelestialBodies { + private static MicroCelestialBodies _instance; + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.MicroCelestialBodies"); + public List Bodies = new(); + public static MicroCelestialBodies Instance + { + get + { + if (_instance == null) + _instance = new MicroCelestialBodies(); + + return _instance; + } + } + + public MicroCelestialBodies() + { + _logger.LogDebug("Instantiating singleton."); + InitializeBodies(); + } + /// /// Refreshes the list of all CelestialBodies. Does nothing if list is already populated. /// /// True = refresh completed successfully or list is already populated - internal bool GetBodies() + public void InitializeBodies() { if (this.Bodies.Count > 0) - return true; + { + _logger.LogInfo("Skipping CelestialBodies build as they're already populated."); + return; + } List bodies = GameManager.Instance?.Game?.UniverseModel?.GetAllCelestialBodies(); if (bodies == null || bodies.Count == 0) - return false; + { + _logger.LogError("Error retrieving CelestialBodies from GameManager.Instance.Game.UniverseModel."); + return; + } foreach (var body in bodies) { @@ -37,7 +64,14 @@ internal bool GetBodies() // Reorder and format all celestial bodies so they form a tree-like structure TryReorderBodies(); - return true; + // Get TWR for each body + foreach (var body in Bodies) + { + body.TwrFactor = GetTwrFactor(body.Name); + } + + _logger.LogInfo("CelestialBodies successfully built."); + return; } private void TryReorderBodies() @@ -81,7 +115,6 @@ private List InstantiateCelestialBodies (CelestialBodyComponent c return instantiatedBodies; } - /// /// Instantiates a single CelestialBody and formats it according to level of indentation /// @@ -108,7 +141,7 @@ private CelestialBody InstantiateCelestialBody(CelestialBodyComponent cel, int l body.DisplayName = $"└ {body.DisplayName}"; for (int i = 0; i < level; i++) - body.DisplayName = $" {body.DisplayName}"; + body.DisplayName = $" {body.DisplayName}"; } return body; @@ -119,7 +152,7 @@ private CelestialBody InstantiateCelestialBody(CelestialBodyComponent cel, int l /// /// Name of the CelestialBody for which the TWR factor is calculated /// TWR factor that needs to be multiplied with HomeWorld's TWR to get TWR at the selected body - internal double GetTwrFactor(string bodyName) + public double GetTwrFactor(string bodyName) { if (Bodies.Count == 0) return 0; CelestialBody homeWorld = Bodies.Find(b => b.IsHomeWorld); @@ -128,15 +161,29 @@ internal double GetTwrFactor(string bodyName) return homeWorld.GravityASL / targetBody.GravityASL; } + + public CelestialBody GetHomeBody() + { + if (Bodies == null || Bodies.Count == 0) + return null; + + return Bodies.Find(b => b.IsHomeWorld); + } + + public CelestialBody GetBodyByName(string requestedBodyName) + { + return Bodies.Find(b => b.DisplayName.ToLowerInvariant() == requestedBodyName.ToLowerInvariant()); + } } - internal class CelestialBody + public class CelestialBody { - internal string Name; - internal string DisplayName; - internal double GravityASL; - internal bool HasAtmosphere; - internal bool IsHomeWorld; - internal CelestialBodyComponent CelestialBodyComponent; + public string Name; + public string DisplayName; + public double GravityASL; + public bool HasAtmosphere; + public bool IsHomeWorld; + public double TwrFactor; + public CelestialBodyComponent CelestialBodyComponent; } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/UI.cs b/MicroEngineerProject/MicroEngineer/Managers/UI.cs deleted file mode 100644 index f5dc88c..0000000 --- a/MicroEngineerProject/MicroEngineer/Managers/UI.cs +++ /dev/null @@ -1,829 +0,0 @@ -using BepInEx.Logging; -using KSP.Game; -using KSP.Sim.impl; -using KSP.UI.Binding; -using UnityEngine; - -namespace MicroMod -{ - internal class UI - { - private static UI _instance; - private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.UI"); - - internal bool ShowGuiFlight; - internal bool ShowGuiOAB; - private bool _showGuiSettingsFlight; - - // If game input is enabled or disabled (used for locking controls when user is editing a text field - private bool _gameInputState = true; - - #region Editing window - private bool _showEditWindow = false; - private int _selectedWindowId = 0; - private MicroEntryCategory _selectedCategory = MicroEntryCategory.Vessel; - private (bool condition, int index) _showTooltip = (false, 0); - #endregion - - // Index of the stage for which user wants to select a different CelestialBody for different TWR calculations. -1 -> no stage is selected - internal int CelestialBodySelectionStageIndex = -1; - private bool _showGuiSettingsOAB; - - Rect settingsFlightRect; - - /// - /// Holds data on all bodies for calculating TWR (currently) - /// - internal MicroCelestialBodies CelestialBodies = new(); - - internal UI() - { - } - - public static UI Instance - { - get - { - if (_instance == null) - _instance = new UI(); - - return _instance; - } - } - - internal void OnGUI() - { - GUI.skin = Styles.SpaceWarpUISkin; - - Utility.RefreshGameManager(); - if (Utility.GameState?.GameState == GameState.VehicleAssemblyBuilder) - OnGUI_OAB(); - else - OnGUI_Flight(); - } - - private void OnGUI_Flight() - { - _gameInputState = Utility.ToggleGameInputOnControlInFocus(_gameInputState, ShowGuiFlight); - - if (!ShowGuiFlight || Utility.ActiveVessel == null) return; - - MainGuiWindow mainGui = (MainGuiWindow)Manager.Instance.Windows.Find(w => w is MainGuiWindow); - - // Draw main GUI that contains docked windows - mainGui.FlightRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - mainGui.FlightRect, - FillMainGUI, - "// MICRO ENGINEER", - Styles.MainWindowStyle, - GUILayout.Height(0) - ); - mainGui.FlightRect.position = Utility.ClampToScreen(mainGui.FlightRect.position, mainGui.FlightRect.size); - - List entryWindows = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList(); - - // Draw all other popped out windows - foreach (var (window, index) in entryWindows - .Select((window, index) => (window, index)) - .Where(x => x.window.IsFlightActive && x.window.IsFlightPoppedOut) // must be active & popped out - .Where(x => x.window.MainWindow != MainWindow.Stage)) // Stage is special, it'll be drawn separately - { - // Skip drawing of Target window if there's no active target - if (window.MainWindow == MainWindow.Target && !Utility.TargetExists()) - continue; - - // Skip drawing of Maneuver window if there's no active maneuver - if (window.MainWindow == MainWindow.Maneuver && !Utility.ManeuverExists()) - continue; - - // If window is locked set alpha to 20% - if (window.IsLocked) - GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.2f); - window.FlightRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - window.FlightRect, - (id) => DrawPopoutWindow(window), - "", - Styles.PopoutWindowStyle, - GUILayout.Height(0), - GUILayout.Width(Styles.WindowWidth - )); - - // Set alpha back to 100% - if (window.IsLocked) - GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1); - - // Snap popped out windows - var settings = Manager.Instance.Windows.Find(w => w is SettingsWIndow) as SettingsWIndow; - if (settings.SnapWindows && window.IsBeingDragged) - HandleSnapping(window); - - window.FlightRect.position = Utility.ClampToScreen(window.FlightRect.position, window.FlightRect.size); - } - - // Draw popped out Stages - StageWindow stageWindow= entryWindows.OfType().FirstOrDefault(); - if (stageWindow.IsFlightActive && stageWindow.IsFlightPoppedOut) - stageWindow.DrawWindow(this); - - // Draw Edit Window - if (_showEditWindow) - { - Styles.EditWindowRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - Styles.EditWindowRect, - DrawEditWindow, - "", - Styles.EditWindowStyle, - GUILayout.Height(0) - ); - } - - // Draw Settings window in Flight - if (_showGuiSettingsFlight) - { - settingsFlightRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - settingsFlightRect, - DrawSettingsFlightWindow, - "", - Styles.SettingsFlightStyle, - GUILayout.Height(0) - ); - } - } - - private void DrawSettingsFlightWindow(int id) - { - GUILayout.BeginHorizontal(); - GUILayout.Label("// SETTINGS"); - GUILayout.FlexibleSpace(); - _showGuiSettingsFlight = !CloseButton(Styles.CloseBtnStyle); - GUILayout.EndHorizontal(); - - GUILayout.Space(10); - GUILayout.Label("Edit window entries"); - if (GUILayout.Button("EDIT WINDOWS", Styles.NormalBtnStyle)) - { - _showEditWindow = !_showEditWindow; - Manager.Instance.PupulateTextFieldNames(GetEditableWindows()[_selectedWindowId].Entries); - } - - GUILayout.Space(10); - GUILayout.Label("Layout control"); - if (GUILayout.Button("SAVE LAYOUT", Styles.NormalBtnStyle)) - { - Manager.Instance.SaveLayout(); - _showGuiSettingsFlight = false; - } - if (GUILayout.Button("LOAD LAYOUT", Styles.NormalBtnStyle)) - Manager.Instance.LoadLayout(); - if (GUILayout.Button("RESET LAYOUT", Styles.NormalBtnStyle)) - { - Manager.Instance.ResetLayout(); - _selectedWindowId = 0; - } - - GUILayout.Space(10); - GUILayout.Label("Theme"); - GUILayout.Space(-10); - - GUILayout.BeginHorizontal(); - var settingsWindow = Manager.Instance.Windows.Find(w => w.GetType() == typeof(SettingsWIndow)) as SettingsWIndow; - if (GUILayout.Toggle(Styles.ActiveTheme == Theme.munix, "munix", Styles.SectionToggleStyle)) - { - Styles.SetActiveTheme(Theme.munix); - settingsWindow.ActiveTheme = Theme.munix; - } - GUILayout.FlexibleSpace(); - if (GUILayout.Toggle(Styles.ActiveTheme == Theme.Gray, "Gray", Styles.SectionToggleStyle)) - { - Styles.SetActiveTheme(Theme.Gray); - settingsWindow.ActiveTheme = Theme.Gray; - } - GUILayout.FlexibleSpace(); - if (GUILayout.Toggle(Styles.ActiveTheme == Theme.Black, "Black", Styles.SectionToggleStyle)) - { - Styles.SetActiveTheme(Theme.Black); - settingsWindow.ActiveTheme = Theme.Black; - } - GUILayout.EndHorizontal(); - - GUILayout.Space(10); - GUILayout.Label("Other"); - GUILayout.Space(-10); - settingsWindow.SnapWindows = GUILayout.Toggle(settingsWindow.SnapWindows, "Window snapping", Styles.SectionToggleStyle); - - GUI.DragWindow(new Rect(0, 0, Screen.width, Screen.height)); - } - - private void OnGUI_OAB() - { - if (!ShowGuiOAB) return; - - EntryWindow stageInfoOAB = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); - if (stageInfoOAB.Entries.Find(e => e.Name == "Stage Info (OAB)").EntryValue == null) return; - - stageInfoOAB.EditorRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - stageInfoOAB.EditorRect, - DrawStageInfoOAB, - "", - Styles.StageOABWindowStyle, - GUILayout.Height(0) - ); - stageInfoOAB.EditorRect.position = Utility.ClampToScreen(stageInfoOAB.EditorRect.position, stageInfoOAB.EditorRect.size); - - // Draw window for selecting CelestialBody for a stage - // -1 -> no selection of CelestialBody is taking place - // any other int -> index represents the stage number for which the selection was clicked - if (CelestialBodySelectionStageIndex > -1) - { - Rect stageInfoOabRect = stageInfoOAB.EditorRect; - Rect celestialBodyRect = new Rect(stageInfoOabRect.x + stageInfoOabRect.width, stageInfoOabRect.y, 0, 0); - - celestialBodyRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - celestialBodyRect, - DrawCelestialBodySelection, - "", - Styles.CelestialSelectionStyle, - GUILayout.Height(0) - ); - } - - // Draw Settings window for the StageInfoOAB - if (_showGuiSettingsOAB) - { - Rect stageInfoOabRect = stageInfoOAB.EditorRect; - Rect settingsRect = new Rect(stageInfoOabRect.x + stageInfoOabRect.width, stageInfoOabRect.y, 0, 0); - - settingsRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - settingsRect, - DrawSettingsOabWindow, - "", - Styles.SettingsOabStyle, - GUILayout.Height(0) - ); - } - } - - #region Flight scene UI - /// - /// Draws the main GUI with all windows that are toggled and docked - /// - /// - private void FillMainGUI(int windowID) - { - List entryWindows = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList(); - - GUILayout.Space(-15); - GUILayout.BeginHorizontal(); - if (GUILayout.Button(Styles.Settings20Texture, Styles.SettingsMainGuiBtnStyle)) - { - Rect mainGuiRect = Manager.Instance.Windows.OfType().FirstOrDefault().FlightRect; - settingsFlightRect = new Rect(mainGuiRect.x - Styles.WindowWidthSettingsFlight, mainGuiRect.y, Styles.WindowWidthSettingsFlight, 0); - _showGuiSettingsFlight = !_showGuiSettingsFlight; - } - GUILayout.FlexibleSpace(); - if (CloseButton(Styles.CloseMainGuiBtnStyle)) - CloseWindow(); - GUILayout.EndHorizontal(); - - try - { - GUILayout.BeginHorizontal(); - - int toggleIndex = -1; - // Draw toggles for all windows except MainGui and StageInfoOAB - foreach (EntryWindow window in entryWindows.Where(x => x.MainWindow != MainWindow.MainGui && x.MainWindow != MainWindow.StageInfoOAB)) - { - // layout can fit 6 toggles, so if all 6 slots are filled then go to a new line. Index == 0 is the MainGUI which isn't rendered - if (++toggleIndex % 6 == 0 && toggleIndex > 0) - { - GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(); - } - window.IsFlightActive = GUILayout.Toggle(window.IsFlightActive, window.Abbreviation, Styles.SectionToggleStyle); - } - GUILayout.EndHorizontal(); - GUILayout.Space(-5); - - // Draw Stage window next - StageWindow stageWindow = entryWindows.OfType().FirstOrDefault(); - if (stageWindow.IsFlightActive && !stageWindow.IsFlightPoppedOut) - stageWindow.DrawWindow(this); - - // Draw all other windows - foreach (var (window, index) in entryWindows - .Select((window, index) => (window, index)) - .Where(x => x.window.IsFlightActive && !x.window.IsFlightPoppedOut) // must be active & docked - .Where(x => x.window.MainWindow != MainWindow.Stage)) // Stage is special, it'll be drawn separately - - { - // Skip drawing of Target window if there's no active target - if (window.MainWindow == MainWindow.Target && !Utility.TargetExists()) - continue; - - // Skip drawing of Maneuver window if there's no active maneuver - if (window.MainWindow == MainWindow.Maneuver && !Utility.ManeuverExists()) - continue; - - DrawSectionHeader(window.Name, ref window.IsFlightPoppedOut, window.IsLocked); - - window.DrawWindowHeader(); - - for (int i = 0; i < window.Entries.Count; i++) - { - if (window.Entries[i].HideWhenNoData && window.Entries[i].ValueDisplay == "-") - continue; - GUIStyle s = i == 0 ? Styles.EntryBackground_First : i < window.Entries.Count - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; - DrawEntry(s, window.Entries[i].Name, window.Entries[i].ValueDisplay, window.Entries[i].UnitDisplay); - } - - window.DrawWindowFooter(); - - DrawSectionEnd(window); - } - - GUI.DragWindow(new Rect(0, 0, Styles.WindowWidth, Styles.WindowHeight)); - } - catch (Exception ex) - { - _logger.LogError(ex); - } - } - - /// - /// Draws all windows that are toggled and popped out - /// - /// - private void DrawPopoutWindow(EntryWindow w) - { - GUILayout.Space(-5); - DrawSectionHeader(w.Name, ref w.IsFlightPoppedOut, w.IsLocked); - - w.DrawWindowHeader(); - - for (int i = 0; i < w.Entries.Count; i++) - { - if (w.Entries[i].HideWhenNoData && w.Entries[i].ValueDisplay == "-") - continue; - GUIStyle s = i == 0 ? Styles.EntryBackground_First : i < w.Entries.Count - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; - DrawEntry(s, w.Entries[i].Name, w.Entries[i].ValueDisplay, w.Entries[i].UnitDisplay); - } - - w.DrawWindowFooter(); - - DrawSectionEnd(w); - } - - private void DrawSectionHeader(string sectionName, ref bool isPopout, bool isLocked) - { - GUILayout.Space(10); - GUILayout.BeginHorizontal(); - - GUILayout.Label($"{sectionName}", Styles.WindowTitleLabelStyle); - GUILayout.FlexibleSpace(); - if(GUILayout.Button(Styles.Settings15Texture, Styles.SettingsBtnStyle)) - { - _selectedWindowId = Manager.Instance.Windows. - FindAll(w => w is EntryWindow).Cast().ToList(). - FindAll(w => w.IsEditable). - FindIndex(w => w.Name == sectionName); - _showEditWindow = true; - Manager.Instance.PupulateTextFieldNames(GetEditableWindows()[_selectedWindowId].Entries); - } - isPopout = isPopout && !isLocked ? !CloseButton(Styles.CloseBtnStyle) : !isPopout ? GUILayout.Button(Styles.PopoutTexture, Styles.PopoutBtnStyle) : isPopout; - GUILayout.EndHorizontal(); - - GUILayout.Space(Styles.NegativeSpacingAfterHeader); - } - - private void DrawEntry(GUIStyle backgroundTexture, string entryName, string value, string unit = "") - { - GUILayout.BeginHorizontal(backgroundTexture); - GUILayout.Label(entryName, Styles.NameLabelStyle); - GUILayout.FlexibleSpace(); - GUILayout.Label(value, Styles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label(unit, Styles.UnitLabelStyle); - GUILayout.EndHorizontal(); - GUILayout.Space(Styles.NegativeSpacingAfterEntry); - } - - private void DrawSectionEnd(EntryWindow window) - { - if (window.IsFlightPoppedOut) - { - if (!window.IsLocked) - GUI.DragWindow(new Rect(0, 0, Styles.WindowWidth, Styles.WindowHeight)); - - GUILayout.Space(Styles.SpacingBelowPopout); - } - else - { - GUILayout.Space(Styles.SpacingAfterSection); - } - } - - /// - /// Window for edditing window contents. Add/Remove/Reorder entries. - /// - /// - private void DrawEditWindow(int windowIndex) - { - List editableWindows = GetEditableWindows(); - List entriesByCategory = Manager.Instance.Entries.FindAll(e => e.Category == _selectedCategory); // All entries belong to a category, but they can still be placed in any window - - GUILayout.Space(-5); - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - _showEditWindow = !CloseButton(Styles.CloseBtnStyle); - GUILayout.EndHorizontal(); - GUILayout.Space(5); - - #region Selection of window to be edited - GUILayout.BeginHorizontal(); - GUILayout.Label("EDITING WINDOW", Styles.TitleLabelStyle); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<", Styles.OneCharacterHighBtnStyle)) - { - _selectedWindowId = _selectedWindowId > 0 ? _selectedWindowId - 1 : editableWindows.Count - 1; - Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); - } - GUI.SetNextControlName(Utility.InputDisableWindowAbbreviation); - editableWindows[_selectedWindowId].Abbreviation = GUILayout.TextField(editableWindows[_selectedWindowId].Abbreviation, Styles.WindowSelectionAbbrevitionTextFieldStyle); - editableWindows[_selectedWindowId].Abbreviation = Utility.ValidateAbbreviation(editableWindows[_selectedWindowId].Abbreviation); - GUI.SetNextControlName(Utility.InputDisableWindowName); - editableWindows[_selectedWindowId].Name = GUILayout.TextField(editableWindows[_selectedWindowId].Name, Styles.WindowSelectionTextFieldStyle); - if (GUILayout.Button(">", Styles.OneCharacterHighBtnStyle)) - { - _selectedWindowId = _selectedWindowId < editableWindows.Count - 1 ? _selectedWindowId + 1 : 0; - Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); - } - GUILayout.EndHorizontal(); - #endregion - - GUILayout.Space(-10); - GUILayout.BeginHorizontal(); - GUILayout.BeginVertical(); - GUILayout.Space(10); - editableWindows[_selectedWindowId].IsLocked = GUILayout.Toggle(editableWindows[_selectedWindowId].IsLocked, "Locked"); - GUILayout.EndVertical(); - GUILayout.FlexibleSpace(); - if (editableWindows[_selectedWindowId].IsDeletable) - { - if (GUILayout.Button("DEL WINDOW", Styles.NormalBtnStyle)) - { - Manager.Instance.Windows.Remove(editableWindows[_selectedWindowId]); - editableWindows.Remove(editableWindows[_selectedWindowId]); - _selectedWindowId--; - } - } - if (GUILayout.Button("NEW WINDOW", Styles.NormalBtnStyle)) - _selectedWindowId = Manager.Instance.CreateCustomWindow(editableWindows); - GUILayout.EndHorizontal(); - - GUILayout.Space(10); - Styles.DrawHorizontalLine(); - GUILayout.Space(10); - - #region Installed entries in the selected window - GUILayout.BeginHorizontal(); - GUILayout.Label("Installed", Styles.NormalLabelStyle); - GUILayout.EndHorizontal(); - - var entries = editableWindows[_selectedWindowId].Entries.ToList(); - for (int i = 0; i < entries.Count; i++) - { - GUIStyle backgroundStyle = i == 0 ? Styles.EntryBackground_First : i < entries.Count - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; - - GUILayout.BeginHorizontal(backgroundStyle); - - GUI.SetNextControlName(entries[i].Id.ToString()); - entries[i].Name = GUILayout.TextField(entries[i].Name, Styles.InstalledEntryFieldStyle); - GUILayout.FlexibleSpace(); - GUI.enabled = entries[i].NumberOfDecimalDigits < 5; - if (entries[i].Formatting != null && GUILayout.Button(Styles.IncreaseDecimalDigitsTexture, Styles.OneCharacterBtnStyle)) - { - entries[i].NumberOfDecimalDigits++; - } - GUI.enabled = entries[i].NumberOfDecimalDigits > 0; - if (entries[i].Formatting != null && GUILayout.Button(Styles.DecreaseDecimalDigitsTexture, Styles.OneCharacterBtnStyle)) - { - entries[i].NumberOfDecimalDigits--; - } - GUI.enabled = i > 0; - if (GUILayout.Button("↑", Styles.OneCharacterBtnStyle)) - { - editableWindows[_selectedWindowId].MoveEntryUp(i); - } - GUI.enabled = i < editableWindows[_selectedWindowId].Entries.Count - 1; - if (GUILayout.Button("↓", Styles.OneCharacterBtnStyle)) - { - editableWindows[_selectedWindowId].MoveEntryDown(i); - } - GUI.enabled = true; - if (GUILayout.Button("X", Styles.OneCharacterBtnStyle)) - editableWindows[_selectedWindowId].RemoveEntry(i); - GUILayout.EndHorizontal(); - GUILayout.Space(-4); - } - #endregion - - GUILayout.Space(20); - Styles.DrawHorizontalLine(); - GUILayout.Space(10); - - #region All entries that can be added to any IsEditable window - GUILayout.BeginHorizontal(); - GUILayout.Label("Add", Styles.NormalLabelStyle); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("Category", Styles.NormalLabelStyle); - GUILayout.FlexibleSpace(); - - if (GUILayout.Button("<", Styles.OneCharacterHighBtnStyle)) - { - _selectedCategory = (int)_selectedCategory > 0 ? - _selectedCategory - 1 : - Enum.GetValues(typeof(MicroEntryCategory)).Cast().Last(); - } - GUILayout.Label(_selectedCategory.ToString(), Styles.NormalCenteredLabelStyle); - if (GUILayout.Button(">", Styles.OneCharacterHighBtnStyle)) - { - _selectedCategory = (int)_selectedCategory < (int)Enum.GetValues(typeof(MicroEntryCategory)).Cast().Last() ? - _selectedCategory + 1 : - Enum.GetValues(typeof(MicroEntryCategory)).Cast().First(); - } - GUILayout.EndHorizontal(); - - for (int i = 0; i < entriesByCategory.Count; i++) - { - GUIStyle backgroundStyle = i == 0 ? Styles.EntryBackground_First : i < entriesByCategory.Count - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; - - GUILayout.BeginHorizontal(backgroundStyle); - GUILayout.Label(entriesByCategory[i].Name, Styles.NameLabelStyle); - if (GUILayout.Button("?", Styles.OneCharacterBtnStyle)) - { - if (!_showTooltip.condition) - _showTooltip = (true, i); - else - { - if (_showTooltip.index != i) - _showTooltip = (true, i); - else - _showTooltip = (false, i); - } - } - if (GUILayout.Button("+", Styles.OneCharacterBtnStyle)) - { - editableWindows[_selectedWindowId].AddEntry(Activator.CreateInstance(entriesByCategory[i].GetType()) as BaseEntry); - Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); - } - GUILayout.EndHorizontal(); - - if (_showTooltip.condition && _showTooltip.index == i) - { - GUILayout.BeginHorizontal(); - GUILayout.Label(entriesByCategory[i].Description, Styles.BlueLabelStyle); - GUILayout.EndHorizontal(); - } - GUILayout.Space(Styles.NegativeSpacingAfterEntry + 7); - } - GUILayout.Space(10); - #endregion - - GUI.DragWindow(new Rect(0, 0, Styles.WindowWidth, Styles.WindowHeight)); - } - - private List GetEditableWindows() - { - return Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().FindAll(w => w.IsEditable); // Editable windows are all except MainGUI, Settings, Stage and StageInfoOAB - } - - #endregion - - #region OAB scene UI - - private void DrawStageInfoOAB(int windowID) - { - EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); - List stageInfoOabEntries = stageInfoOabWindow.Entries; - - GUILayout.BeginHorizontal(); - GUILayout.Label($"Stage Info"); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(Styles.Settings15Texture, Styles.SettingsBtnStyle)) - _showGuiSettingsOAB = !_showGuiSettingsOAB; - - if (CloseButton(Styles.CloseBtnStyle)) - { - GameObject.Find("BTN-MicroEngineerOAB")?.GetComponent()?.SetValue(false); - stageInfoOabWindow.IsEditorActive = false; - ShowGuiOAB = false; - } - - GUILayout.EndHorizontal(); - - // Draw StageInfo header - Delta V fields - GUILayout.BeginHorizontal(); - GUILayout.Label("Total ∆v (ASL, vacuum)", Styles.NameLabelStyle); - GUILayout.FlexibleSpace(); - GUILayout.Label($"{stageInfoOabEntries.Find(e => e.Name == "Total ∆v Actual (OAB)").ValueDisplay}, {stageInfoOabEntries.Find(e => e.Name == "Total ∆v Vac (OAB)").ValueDisplay}", Styles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label("m/s", Styles.UnitLabelStyle); - GUILayout.EndHorizontal(); - - // Draw Torque - Torque torque = (Torque)stageInfoOabEntries.Find(e => e.Name == "Torque"); - if (torque.IsActive) - { - GUILayout.Space(Styles.NegativeSpacingAfterEntry); - GUILayout.BeginHorizontal(); - GUILayout.Label("Torque", Styles.NameLabelStyle); - GUILayout.FlexibleSpace(); - GUILayout.Label(torque.ValueDisplay, Styles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label(torque.UnitDisplay, Styles.UnitLabelStyle); - GUILayout.EndHorizontal(); - } - - // Draw Stage table header - GUILayout.BeginHorizontal(); - GUILayout.Label("Stage", Styles.NameLabelStyle, GUILayout.Width(40)); - GUILayout.FlexibleSpace(); - GUILayout.Label("TWR", Styles.TableHeaderLabelStyle, GUILayout.Width(65)); - GUILayout.Label("SLT", Styles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("", Styles.TableHeaderLabelStyle, GUILayout.Width(30)); - GUILayout.Label("ASL ∆v", Styles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("", Styles.TableHeaderLabelStyle, GUILayout.Width(30)); - GUILayout.Label("Vac ∆v", Styles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("Burn Time", Styles.TableHeaderLabelStyle, GUILayout.Width(110)); - GUILayout.Space(20); - GUILayout.Label("Body", Styles.TableHeaderCenteredLabelStyle, GUILayout.Width(80)); - GUILayout.EndHorizontal(); - GUILayout.Space(Styles.NegativeSpacingAfterEntry); - - StageInfo_OAB stageInfoOab = (StageInfo_OAB)stageInfoOabWindow.Entries - .Find(e => e.Name == "Stage Info (OAB)"); - - // Draw each stage that has delta v - var stages = ((List)stageInfoOab.EntryValue) - .FindAll(s => s.DeltaVVac > 0.0001 || s.DeltaVASL > 0.0001); - - int celestialIndex = -1; - for (int stageIndex = stages.Count - 1; stageIndex >= 0; stageIndex--) - { - // Check if this stage has a CelestialBody attached. If not, create a new CelestialBody and assign it to HomeWorld (i.e. Kerbin) - if (stageInfoOab.CelestialBodyForStage.Count == ++celestialIndex) - stageInfoOab.AddNewCelestialBody(CelestialBodies); - - GUILayout.BeginHorizontal(); - GUILayout.Label(String.Format("{0:00}", ((List)stageInfoOab.EntryValue).Count - stages[stageIndex].Stage), Styles.NameLabelStyle, GUILayout.Width(40)); - GUILayout.FlexibleSpace(); - - // We calculate what factor needs to be applied to TWR in order to compensate for different gravity of the selected celestial body - double twrFactor = CelestialBodies.GetTwrFactor(stageInfoOab.CelestialBodyForStage[celestialIndex]); - GUILayout.Label(String.Format("{0:N2}", stages[stageIndex].TWRVac * twrFactor), Styles.ValueLabelStyle, GUILayout.Width(65)); - - // Calculate Sea Level TWR and DeltaV - CelestialBodyComponent cel = CelestialBodies.Bodies.Find(b => b.Name == stageInfoOab.CelestialBodyForStage[celestialIndex]).CelestialBodyComponent; - GUILayout.Label(String.Format("{0:N2}", stages[stageIndex].GetTWRAtSeaLevel(cel) * twrFactor), Styles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label(String.Format("{0:N0}", stages[stageIndex].GetDeltaVelAtSeaLevel(cel)), Styles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label("m/s", Styles.UnitLabelStyleStageOAB, GUILayout.Width(30)); - - GUILayout.Label(String.Format("{0:N0}", stages[stageIndex].DeltaVVac), Styles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label("m/s", Styles.UnitLabelStyleStageOAB, GUILayout.Width(30)); - GUILayout.Label(Utility.SecondsToTimeString(stages[stageIndex].StageBurnTime, true, true), Styles.ValueLabelStyle, GUILayout.Width(110)); - GUILayout.Space(20); - GUILayout.BeginVertical(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(stageInfoOab.CelestialBodyForStage[celestialIndex], Styles.CelestialBodyBtnStyle)) - { - CelestialBodySelectionStageIndex = celestialIndex; - } - GUILayout.EndVertical(); - GUILayout.EndHorizontal(); - GUILayout.Space(Styles.NegativeSpacingAfterEntry); - } - - GUILayout.Space(Styles.SpacingBelowPopout); - - GUI.DragWindow(new Rect(0, 0, Screen.width, Screen.height)); - } - - /// - /// Opens a window for selecting a CelestialObject for the stage on the given index - /// - private void DrawCelestialBodySelection(int id) - { - GUILayout.BeginVertical(); - - foreach (var body in CelestialBodies.Bodies) - { - if (GUILayout.Button(body.DisplayName, Styles.CelestialSelectionBtnStyle)) - { - StageInfo_OAB stageInfoOab = (StageInfo_OAB)Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Stage Info (OAB)"); - stageInfoOab.CelestialBodyForStage[CelestialBodySelectionStageIndex] = body.Name; - - // Hide the selection window - CelestialBodySelectionStageIndex = -1; - } - } - - GUILayout.EndVertical(); - } - - /// - /// Opens a Settings window for OAB - /// - private void DrawSettingsOabWindow(int id) - { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - _showGuiSettingsOAB = !CloseButton(Styles.CloseBtnStyle); - GUILayout.EndHorizontal(); - - EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); - List stageInfoOabEntries = stageInfoOabWindow.Entries; - Torque torqueEntry = (Torque)stageInfoOabEntries.Find(e => e.Name == "Torque"); - - torqueEntry.IsActive = GUILayout.Toggle(torqueEntry.IsActive, "Display Torque (experimental)\nTurn on CoT & CoM for this", Styles.SectionToggleStyle); - GUILayout.Space(15); - } - - #endregion - - private void CloseWindow() - { - GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(false); - ShowGuiFlight = false; - } - - /// - /// Draws a close button (X) - /// - /// Where to position the close button - /// - internal bool CloseButton(GUIStyle style)//Rect rect) - { - //return GUI.Button(rect, Styles.CloseButtonTexture, Styles.CloseBtnStyle); - return GUILayout.Button(Styles.CloseButtonTexture, style); - } - - internal void HandleSnapping(EntryWindow draggedWindow) - { - List poppedOutWindows = Manager.Instance.Windows - .FindAll(w => typeof(EntryWindow).IsAssignableFrom(w.GetType())) - .Cast() - .Where(w => w.IsFlightActive && w.IsFlightPoppedOut) - .ToList(); - - var settings = Manager.Instance.Windows.Find(w => w is SettingsWIndow) as SettingsWIndow; - - foreach (var otherWindow in poppedOutWindows) - { - // Check if the current window is close to any edge of the other window - if (otherWindow != draggedWindow && Utility.AreRectsNear(draggedWindow.FlightRect, otherWindow.FlightRect)) - { - // Snap to the left edge - if (Mathf.Abs(draggedWindow.FlightRect.xMin - otherWindow.FlightRect.xMin) < settings.SnapDistance) - draggedWindow.FlightRect.x = otherWindow.FlightRect.xMin; - - // Snap to the right edge - if (Mathf.Abs(draggedWindow.FlightRect.xMax - otherWindow.FlightRect.xMin) < settings.SnapDistance) - draggedWindow.FlightRect.x = otherWindow.FlightRect.xMin - draggedWindow.FlightRect.width; - - // Snap to the left edge - if (Mathf.Abs(draggedWindow.FlightRect.xMin - otherWindow.FlightRect.xMax) < settings.SnapDistance) - draggedWindow.FlightRect.x = otherWindow.FlightRect.xMax; - - // Snap to the right edge - if (Mathf.Abs(draggedWindow.FlightRect.xMax - otherWindow.FlightRect.xMax) < settings.SnapDistance) - draggedWindow.FlightRect.x = otherWindow.FlightRect.xMax - draggedWindow.FlightRect.width; - - // Snap to the top edge - if (Mathf.Abs(draggedWindow.FlightRect.yMin - otherWindow.FlightRect.yMin) < settings.SnapDistance) - draggedWindow.FlightRect.y = otherWindow.FlightRect.yMin; - - // Snap to the bottom edge - if (Mathf.Abs(draggedWindow.FlightRect.yMax - otherWindow.FlightRect.yMin) < settings.SnapDistance) - draggedWindow.FlightRect.y = otherWindow.FlightRect.yMin - draggedWindow.FlightRect.height; - - // Snap to the top edge - if (Mathf.Abs(draggedWindow.FlightRect.yMin - otherWindow.FlightRect.yMax) < settings.SnapDistance) - draggedWindow.FlightRect.y = otherWindow.FlightRect.yMax; - - // Snap to the bottom edge - if (Mathf.Abs(draggedWindow.FlightRect.yMax - otherWindow.FlightRect.yMax) < settings.SnapDistance) - draggedWindow.FlightRect.y = otherWindow.FlightRect.yMax - draggedWindow.FlightRect.height; - } - } - } - } -} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs index 77846d2..08ba07e 100644 --- a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs +++ b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs @@ -4,15 +4,17 @@ using SpaceWarp.API.Assets; using SpaceWarp.API.Mods; using SpaceWarp.API.UI.Appbar; -using KSP.UI.Binding; +using MicroEngineer.UI; +using KSP.Game; +using BepInEx.Logging; namespace MicroMod { - //[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] - [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "1.1.1")] + [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "1.2.0")] [BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)] public class MicroEngineerMod : BaseSpaceWarpPlugin { + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineerMod"); public static MicroEngineerMod Instance { get; set; } public string GUID; @@ -21,10 +23,6 @@ public override void OnInitialized() Instance = this; GUID = Info.Metadata.GUID; - - //BackwardCompatibilityInitializations(); - - Styles.Initialize(); MessageManager.Instance.SubscribeToMessages(); @@ -35,9 +33,11 @@ public override void OnInitialized() AssetManager.GetAsset($"{GUID}/images/icon.png"), isOpen => { - UI.Instance.ShowGuiFlight = isOpen; - Manager.Instance.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = isOpen; - GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(isOpen); + if (isOpen) + Manager.Instance.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = isOpen; + FlightSceneController.Instance.ShowGui = isOpen; + _logger.LogDebug($"Initiating Save from Appbar.RegisterAppButton."); + Utility.SaveLayout(); }); Appbar.RegisterOABAppButton( @@ -46,32 +46,34 @@ public override void OnInitialized() AssetManager.GetAsset($"{GUID}/images/icon.png"), isOpen => { - UI.Instance.ShowGuiOAB = isOpen; - Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive = isOpen; - GameObject.Find("BTN-MicroEngineerOAB")?.GetComponent()?.SetValue(isOpen); + if (isOpen) + Manager.Instance.Windows.Find(w => w.GetType() == typeof(StageInfoOabWindow)).IsEditorActive = isOpen; + OABSceneController.Instance.ShowGui = isOpen; + _logger.LogDebug($"Initiating Save from Appbar.RegisterOABAppButton."); + Utility.SaveLayout(); }); } - private void BackwardCompatibilityInitializations() - { - // Preserve backward compatibility with SpaceWarp 1.1.x - if (Utility.IsModOlderThan("SpaceWarp", 1, 2, 0)) - { - Logger.LogInfo("Older Space Warp version detected. Setting mod GUID to \"micro_engineer\"."); - GUID = "micro_engineer"; - } - else - Logger.LogInfo("New Space Warp version detected. No backward compatibility needed."); - } - public void Update() { - Manager.Instance.Update(); - } + Manager.Instance.Update(); - private void OnGUI() - { - UI.Instance.OnGUI(); + // Keyboard shortcut for opening UI + if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKeyDown(KeyCode.E)) + { + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) + { + bool guiState = FlightSceneController.Instance.ShowGui; + FlightSceneController.Instance.ShowGui = !guiState; + Manager.Instance.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = !guiState; + } + else if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) + { + bool guiState = OABSceneController.Instance.ShowGui; + OABSceneController.Instance.ShowGui = !guiState; + Manager.Instance.Windows.Find(w => w.GetType() == typeof(StageInfoOabWindow)).IsEditorActive = !guiState; + } + } } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/UI/Controllers/EditWindowsController.cs b/MicroEngineerProject/MicroEngineer/UI/Controllers/EditWindowsController.cs new file mode 100644 index 0000000..bc98fc6 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/UI/Controllers/EditWindowsController.cs @@ -0,0 +1,389 @@ +using BepInEx.Logging; +using MicroMod; +using UnityEngine; +using UnityEngine.UIElements; + +namespace MicroEngineer.UI +{ + public class EditWindowsController : MonoBehaviour + { + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.EditWindowsController"); + + private EditWindowsItemControl _selectedAvailableEntry; + private EditWindowsItemControl _selectedInstalledEntry; + private List _editableWindows; + private List _installedControls = new(); + private float _timeOfLastClick; + + public int SelectedWindowId; + + public UIDocument EditWindows { get; set; } + public VisualElement Root { get; set; } + public Button CloseButton { get; set; } + public ScrollView AvailableScrollView { get; set; } + public ScrollView InstalledScrollView { get; set; } + public DropdownField CategoryDropdown { get; set; } + public TextField SelectedWindow { get; set; } + public Button PreviousWindow { get; set; } + public Button NextWindow { get; set; } + public Button NewWindow { get; set; } + public Button DeleteWindow { get; set; } + public Toggle LockWindow { get; set; } + public Button AddEntry { get; set; } + public Button RemoveEntry { get; set; } + public Button MoveUp { get; set; } + public Button MoveDown { get; set; } + + public EditWindowsController() + { } + + private void OnEnable() + { + StartCoroutine(StartInitialization()); + } + + private System.Collections.IEnumerator StartInitialization() + { + // wait for 1 frame until SelectedWindowId is set in FlightSceneController + yield return null; + + _logger.LogDebug("Entering OnEnable."); + EditWindows = GetComponent(); + Root = EditWindows.rootVisualElement; + + CloseButton = Root.Q