diff --git a/MicroEngineerProject/MicroEngineer.sln b/MicroEngineerProject/MicroEngineer.sln index 1333d5b..4d3a884 100644 --- a/MicroEngineerProject/MicroEngineer.sln +++ b/MicroEngineerProject/MicroEngineer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31605.320 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroEngineer", "MicroEngineer.csproj", "{2CD77478-E170-4D5C-91CA-0ABB24A30E5A}" EndProject @@ -11,8 +11,8 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Debug|Any CPU.Build.0 = Release|Any CPU {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2CD77478-E170-4D5C-91CA-0ABB24A30E5A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection diff --git a/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs new file mode 100644 index 0000000..9e1f3d8 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs @@ -0,0 +1,130 @@ +using Newtonsoft.Json; + +namespace MicroMod +{ + /// + /// Base class for all Entries (values that can be attached to windows) + /// + [JsonObject(MemberSerialization.OptIn)] + public class BaseEntry + { + [JsonProperty] + public string Name; + [JsonProperty] + public string Description; + [JsonProperty] + public MicroEntryCategory Category; + public bool IsDefault; + [JsonProperty] + public bool HideWhenNoData; + [JsonProperty] + public string MiliUnit; + [JsonProperty] + public string BaseUnit; + [JsonProperty] + public string KiloUnit; + [JsonProperty] + public string MegaUnit; + [JsonProperty] + public string GigaUnit; + [JsonProperty] + public byte NumberOfDecimalDigits; + [JsonProperty("Formatting")] + private string _formatting; + public string Formatting + { + get => String.IsNullOrEmpty(_formatting) ? null : $"{{0:{_formatting}{this.NumberOfDecimalDigits}}}"; + set => _formatting = value; + } + + public virtual object EntryValue { get; set; } + + /// + /// Controls how the value should be displayed. Should be overriden in a inheritet class for a concrete implementation. + /// + public virtual string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + if (String.IsNullOrEmpty(this.Formatting)) + return EntryValue.ToString(); + + if (!double.TryParse(EntryValue.ToString(), out double d)) + return EntryValue.ToString(); // This case shouldn't exist, but just to be sure + + if (Math.Abs(d) < 1) // mili + { + return !String.IsNullOrEmpty(this.MiliUnit) ? String.Format(Formatting, d * 1000) : + String.Format(Formatting, d); + } + else if (Math.Abs(d) < 1000000) // base + { + return String.Format(Formatting, d); + } + else if (Math.Abs(d) < 1000000000) // kilo + { + return !String.IsNullOrEmpty(this.KiloUnit) ? String.Format(Formatting, d / 1000) : + String.Format(Formatting, d); + + } + else if (Math.Abs(d) < 1000000000000) // mega + { + return !String.IsNullOrEmpty(this.MegaUnit) ? String.Format(Formatting, d / 1000000) : + !String.IsNullOrEmpty(this.KiloUnit) ? String.Format(Formatting, d / 1000) : + String.Format(Formatting, d); + + } + else // giga + { + return !String.IsNullOrEmpty(this.GigaUnit) ? String.Format(Formatting, d / 1000000000) : + !String.IsNullOrEmpty(this.MegaUnit) ? String.Format(Formatting, d / 1000000) : + !String.IsNullOrEmpty(this.KiloUnit) ? String.Format(Formatting, d / 1000) : + String.Format(Formatting, d); + } + } + } + + public virtual string UnitDisplay + { + get + { + if (EntryValue == null) + return ""; + + if (String.IsNullOrEmpty(this.Formatting)) + return this.BaseUnit ?? ""; + + if (!double.TryParse(EntryValue.ToString(), out double d)) + return this.BaseUnit ?? ""; // This case shouldn't exist, but just to be sure + + if (d > 0.001 && d < 1) // mili + { + return this.MiliUnit ?? this.BaseUnit ?? ""; + } + else if (Math.Abs(d) < 1000000) // base + { + return this.BaseUnit ?? ""; + } + else if (Math.Abs(d) < 1000000000) // kilo + { + return this.KiloUnit ?? this.BaseUnit ?? ""; + + } + else if (Math.Abs(d) < 1000000000000) // mega + { + return this.MegaUnit ?? this.KiloUnit ?? this.BaseUnit ?? ""; + + } + else // giga + { + return this.GigaUnit ?? this.MegaUnit ?? this.KiloUnit ?? this.BaseUnit ?? ""; + } + } + } + + public virtual void RefreshData() { } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs new file mode 100644 index 0000000..37fbab7 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/BodyEntries.cs @@ -0,0 +1,72 @@ + +namespace MicroMod +{ + public class BodyEntry : BaseEntry + { } + + public class Body : BodyEntry + { + public Body() + { + Name = "Body"; + Description = "Shows the body that vessel is currently at."; + Category = MicroEntryCategory.Body; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.mainBody.bodyName; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ReferenceBodyConstants_Radius : BodyEntry + { + public ReferenceBodyConstants_Radius() + { + Name = "Body radius"; + Description = "Body's radius."; + Category = MicroEntryCategory.Body; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.ReferenceBodyConstants.Radius; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ReferenceBodyConstants_StandardGravitationParameter : BodyEntry + { + public ReferenceBodyConstants_StandardGravitationParameter() + { + Name = "Std. grav. param."; + Description = "Product of the gravitational constant G and the mass M of the body."; + Category = MicroEntryCategory.Body; + IsDefault = false; + BaseUnit = "μ"; + NumberOfDecimalDigits = 4; + Formatting = "e"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.ReferenceBodyConstants.StandardGravitationParameter; + } + + 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 new file mode 100644 index 0000000..da143df --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/FlightEntries.cs @@ -0,0 +1,413 @@ + +namespace MicroMod +{ + public class FlightEntry : BaseEntry + { } + + public class Speed : FlightEntry + { + public Speed() + { + Name = "Speed"; + Description = "Shows the vessel's total velocity."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.SurfaceVelocity.magnitude; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class MachNumber : FlightEntry + { + public MachNumber() + { + Name = "Mach number"; + Description = "Shows the ratio of vessel's speed and local speed of sound."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.SimulationObject.Telemetry.MachNumber; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class GeeForce : FlightEntry + { + public GeeForce() + { + Name = "G-Force"; + Description = "Measurement of the type of force per unit mass – typically acceleration – that causes a perception of weight, with a g-force of 1 g equal to the conventional value of gravitational acceleration on Earth/Kerbin."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "g"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.geeForce; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class AngleOfAttack : FlightEntry + { + public AngleOfAttack() + { + Name = "AoA"; + Description = "Angle of Attack specifies the angle between the chord line of the wing and the vector representing the relative motion between the aircraft and the atmosphere."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = AeroForces.AngleOfAttack; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SideSlip : FlightEntry + { + public SideSlip() + { + Name = "Sideslip"; + Description = "A slip is an aerodynamic state where an aircraft is moving somewhat sideways as well as forward relative to the oncoming airflow or relative wind."; + Category = MicroEntryCategory.Flight; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = AeroForces.SideSlip; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Heading : FlightEntry + { + public Heading() + { + Name = "Heading"; + Description = "Heading of a vessel is the compass direction in which the craft's nose is pointed."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Heading; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Pitch_HorizonRelative : FlightEntry + { + public Pitch_HorizonRelative() + { + Name = "Pitch"; + Description = "Lateral axis passes through an aircraft from wingtip to wingtip. Rotation about this axis is called pitch (moving up-down)."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Pitch_HorizonRelative; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Roll_HorizonRelative : FlightEntry + { + public Roll_HorizonRelative() + { + Name = "Roll"; + Description = "Longitudinal axis passes through the aircraft from nose to tail. Rotation about this axis is called roll (rotating left-right)."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Roll_HorizonRelative; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Yaw_HorizonRelative : FlightEntry + { + public Yaw_HorizonRelative() + { + Name = "Yaw"; + Description = "Vertical axis passes through an aircraft from top to bottom. Rotation about this axis is called yaw (moving left-right)."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Yaw_HorizonRelative; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Zenith : FlightEntry + { + public Zenith() + { + Name = "Zenith"; + Description = "The zenith is an imaginary point directly above a particular location, on the celestial sphere. \"Above\" means in the vertical direction opposite to the gravity direction."; + Category = MicroEntryCategory.Flight; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Zenith; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalLift : FlightEntry + { + public TotalLift() + { + Name = "Total lift"; + Description = "Shows the total lift force produced by the vessel."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + MiliUnit = "mN"; + BaseUnit = "N"; + KiloUnit = "kN"; + MegaUnit = "MN"; + GigaUnit = "GN"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = AeroForces.TotalLift; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + double toReturn = (double)EntryValue * 1000; + return String.IsNullOrEmpty(base.Formatting) ? toReturn.ToString() : String.Format(base.Formatting, toReturn); + } + } + } + + public class TotalDrag : FlightEntry + { + public TotalDrag() + { + Name = "Total drag"; + Description = "Shows the total drag force exerted on the vessel."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + MiliUnit = "mN"; + BaseUnit = "N"; + KiloUnit = "kN"; + MegaUnit = "MN"; + GigaUnit = "GN"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = AeroForces.TotalDrag; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + double toReturn = (double)EntryValue * 1000; + return String.IsNullOrEmpty(base.Formatting) ? toReturn.ToString() : String.Format(base.Formatting, toReturn); + } + } + } + + public class LiftDivDrag : FlightEntry + { + public LiftDivDrag() + { + Name = "Lift / Drag"; + Description = "Shows the ratio of total lift and drag forces."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = AeroForces.TotalLift / AeroForces.TotalDrag; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + double toReturn = (double)EntryValue * 1000; + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); + } + } + } + + public class DragCoefficient : FlightEntry + { + public DragCoefficient() + { + Name = "Drag coefficient"; + Description = "Dimensionless quantity that is used to quantify the drag or resistance of an object in a fluid environment, such as air or water."; + Category = MicroEntryCategory.Flight; + IsDefault = false; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.DragCoefficient; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ExposedArea : FlightEntry + { + public ExposedArea() + { + Name = "Exposed area"; + Description = "The surface area that interacts with the working fluid or gas."; + Category = MicroEntryCategory.Flight; + IsDefault = false; + BaseUnit = null; // TODO + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.ExposedArea; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class AtmosphericDensity : FlightEntry + { + public AtmosphericDensity() + { + Name = "Atm. density"; + Description = "Shows the atmospheric density."; + Category = MicroEntryCategory.Flight; + IsDefault = true; + MiliUnit = "mg/L"; + BaseUnit = "g/L"; + KiloUnit = "kg/L"; + MegaUnit = "Mg/L"; + GigaUnit = "Gg/L"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.SimulationObject.Telemetry.AtmosphericDensity; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SoundSpeed : FlightEntry + { + public SoundSpeed() + { + Name = "Speed of sound"; + Description = "Distance travelled per unit of time by a sound wave as it propagates through the air."; + Category = MicroEntryCategory.Flight; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.SoundSpeed; + } + + public override string ValueDisplay => base.ValueDisplay; + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs new file mode 100644 index 0000000..657a0e6 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/ManeuverEntries.cs @@ -0,0 +1,792 @@ +using KSP.Game; +using KSP.Sim.impl; +using KSP.Sim.Maneuver; + +namespace MicroMod +{ + public class ManeuverEntry : BaseEntry + { + internal int SelectedNodeIndex = 0; + } + + public class DeltaVRequired : ManeuverEntry + { + public DeltaVRequired() + { + Name = "∆v required"; + Description = "Delta velocity needed to complete the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); + + EntryValue = (nodes == null || nodes.Count == 0) ? null : + (nodes.Count == 1) ? (Utility.ActiveVessel.Orbiter.ManeuverPlanSolver.GetVelocityAfterFirstManeuver(out double ut).vector - Utility.ActiveVessel.Orbit.GetOrbitalVelocityAtUTZup(ut)).magnitude : + (nodes.Count >= base.SelectedNodeIndex + 1) ? nodes[base.SelectedNodeIndex].BurnRequiredDV : + null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ManeuverPrograde : ManeuverEntry + { + public ManeuverPrograde() + { + Name = "∆v prograde"; + Description = "Prograde/Retrograde component of the total change in velocity."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); + EntryValue = nodes?.ElementAtOrDefault(base.SelectedNodeIndex)?.BurnVector.z; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ManeuverNormal : ManeuverEntry + { + public ManeuverNormal() + { + Name = "∆v normal"; + Description = "Normal component of the total change in velocity."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); + EntryValue = nodes?.ElementAtOrDefault(base.SelectedNodeIndex)?.BurnVector.y; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ManeuverRadial : ManeuverEntry + { + public ManeuverRadial() + { + Name = "∆v radial"; + Description = "Radial component of the total change in velocity."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + List nodes = Utility.ActiveVessel?.SimulationObject?.FindComponent()?.GetNodes(); + EntryValue = nodes?.ElementAtOrDefault(base.SelectedNodeIndex)?.BurnVector.x; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TimeToNode : ManeuverEntry + { + public TimeToNode() + { + Name = "Time to node"; + Description = "Time until vessel reaches the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public BurnTime() + { + Name = "Burn time"; + Description = "Length of time needed to complete the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public ProjectedAp() + { + Name = "Projected Ap."; + Description = "Projected Apoapsis vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .ApoapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ProjectedPe : ManeuverEntry + { + public ProjectedPe() + { + Name = "Projected Pe."; + Description = "Projected Periapsis vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .PeriapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_TimeToAp : ManeuverEntry + { + public Maneuver_TimeToAp() + { + Name = "Time to Ap."; + Description = "Shows the Time to Apoapsis vessel will have after reaching the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_TimeToPe() + { + Name = "Time to Pe."; + Description = "Shows the Time to Periapsis vessel will have after reaching the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_Inclination() + { + Name = "Inclination"; + Description = "The inclination of the vessel's orbit after the burn."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalElements.Inclination; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_Eccentricity : ManeuverEntry + { + public Maneuver_Eccentricity() + { + Name = "Eccentricity"; + Description = "The eccentricity of the vessel's orbit after the burn."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = null; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalElements.Eccentricity; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_Period : ManeuverEntry + { + public Maneuver_Period() + { + Name = "Period"; + Description = "The period of the vessel's orbit after the burn."; + Category = MicroEntryCategory.Maneuver; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_TrueAnomaly() + { + Name = "True anomaly"; + Description = "True Anomaly vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .TrueAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class Maneuver_MeanAnomaly : ManeuverEntry + { + public Maneuver_MeanAnomaly() + { + Name = "Mean anomaly"; + Description = "Mean Anomaly vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .MeanAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class Maneuver_EccentricAnomaly : ManeuverEntry + { + public Maneuver_EccentricAnomaly() + { + Name = "Eccentric anomaly"; + Description = "Eccentric Anomaly vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .EccentricAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class Maneuver_LongitudeOfAscendingNode : ManeuverEntry + { + public Maneuver_LongitudeOfAscendingNode() + { + Name = "LAN Ω"; + Description = "Longitude of Ascending Node vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalElements.LongitudeOfAscendingNode; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_ArgumentOfPeriapsis : ManeuverEntry + { + public Maneuver_ArgumentOfPeriapsis() + { + Name = "Argument of Pe."; + Description = "Argument of Periapsis vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalElements.ArgumentOfPeriapsis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_SemiLatusRectum : ManeuverEntry + { + public Maneuver_SemiLatusRectum() + { + Name = "Semi latus rect"; + Description = "Semi Latus Rectum vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .SemiLatusRectum; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_SemiMajorAxis : ManeuverEntry + { + public Maneuver_SemiMajorAxis() + { + Name = "Semi major axis"; + Description = "Semi Major Axis vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalElements.SemiMajorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_SemiMinorAxis : ManeuverEntry + { + public Maneuver_SemiMinorAxis() + { + Name = "Semi minor axis"; + Description = "Semi Minor Axis vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .SemiMinorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_OrbitalEnergy : ManeuverEntry + { + public Maneuver_OrbitalEnergy() + { + Name = "Orbital energy"; + Description = "Orbital Energy vessel will have after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + MiliUnit = "mJ"; + BaseUnit = "J"; + KiloUnit = "kJ"; + MegaUnit = "MJ"; + GigaUnit = "GJ"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .OrbitalEnergy; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_ObT : ManeuverEntry + { + public Maneuver_ObT() + { + Name = "Orbit time"; + Description = "Shows orbit time in seconds from the Periapsis when vessel reaches the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_OrbitPercent() + { + Name = "Orbit percent"; + Description = "Orbit percent vessel will have passed after completing the maneuver."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "%"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .ElementAtOrDefault(base.SelectedNodeIndex)? + .orbitPercent * 100; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Maneuver_EndUT : ManeuverEntry + { + public Maneuver_EndUT() + { + Name = "UT"; + Description = "Universal Time when vessel reaches the maneuver node."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_UniversalTimeAtClosestApproach() + { + Name = "UT close.app."; + Description = "Universal Time at the point of closest approach."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 + { + public Maneuver_UniversalTimeAtSoiEncounter() + { + Name = "UT SOI enc."; + Description = "Universal Time at the point of transition to another Sphere Of Influence."; + Category = MicroEntryCategory.Maneuver; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList? + .Where(p => p.ActivePatch == true) + .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 new file mode 100644 index 0000000..7bc6ce5 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/MiscEntries.cs @@ -0,0 +1,302 @@ +using KSP.Sim; + +namespace MicroMod +{ + public class MiscEntry : BaseEntry + { } + + public class Separator : MiscEntry + { + public Separator() + { + Name = "--------------"; + Description = "It's a separator!"; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "---"; + Formatting = null; + EntryValue = "--------------"; + } + } + + public class GravityForPos : MiscEntry + { + public GravityForPos() + { + Name = "Local gravity"; + Description = "Local gravity vessel is experiencing."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "ms2"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.gravityForPos.magnitude; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class EndUT : MiscEntry + { + public EndUT() + { + Name = "UT"; + Description = "Universal Time."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public StartUT() + { + Name = "Start UT"; + Description = "Time passed since vessel was launched."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public LaunchTime() + { + Name = "Launch time"; + Description = "Universal Time when vessel was launched."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public TimeSinceLaunch() + { + Name = "Time since launch"; + Description = "Time since the vessel launched."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public AutopilotStatus_IsEnabled() + { + Name = "Autopilot"; + Description = "Is autopilot enabled or disabled."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AutopilotStatus.IsEnabled; + } + + public override string ValueDisplay => EntryValue != null ? (bool)EntryValue ? "Enabled" : "Disabled" : "-"; + } + + public class AutopilotStatus_Mode : MiscEntry + { + public AutopilotStatus_Mode() + { + Name = "Autopilot mode"; + Description = "Mode vessel's autopilot is using: stability assist, prograde, retrograde, normal, etc."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AutopilotStatus.Mode; + } + + public override string ValueDisplay => EntryValue != null ? (AutopilotMode)EntryValue == AutopilotMode.StabilityAssist ? "Stability" : EntryValue.ToString() : null; + } + + public class AltimeterMode : MiscEntry + { + public AltimeterMode() + { + Name = "Altimeter mode"; + Description = "Mode vessel's altimeter is using: Sea Level or Ground Level."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.altimeterMode; + } + + public override string ValueDisplay => EntryValue != null ? (AltimeterDisplayMode)EntryValue == AltimeterDisplayMode.SeaLevel ? "Sea Level" : (AltimeterDisplayMode)EntryValue == AltimeterDisplayMode.GroundLevel ? "Ground Level" : "-" : "-"; + } + + public class SpeedMode : MiscEntry + { + public SpeedMode() + { + Name = "Speed mode"; + Description = "Mode vessel's velocity meter is using: Orbit, Surface or Target."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.speedMode; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class UniversalTimeAtClosestApproach : MiscEntry + { + public UniversalTimeAtClosestApproach() + { + Name = "UT close.app."; + Description = "Universal Time at closest approach."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public UniversalTimeAtSoiEncounter() + { + Name = "UT SOI enc."; + Description = "Universal Time at the point of transfer to another sphere of influence."; + Category = MicroEntryCategory.Misc; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 new file mode 100644 index 0000000..f0c342d --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/OabStageInfoEntries.cs @@ -0,0 +1,301 @@ +using KSP.Game; +using KSP.Sim.DeltaV; +using KSP.Sim.impl; +using Newtonsoft.Json; + +namespace MicroMod +{ + public class OabStageInfoEntry : BaseEntry + { } + + public class TotalBurnTime_OAB : OabStageInfoEntry + { + public bool UseDHMSFormatting; // TODO: implement + + public TotalBurnTime_OAB() + { + Name = "Total burn time (OAB)"; + Description = "Shows the total length of burn the vessel can mantain."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + BaseUnit = "s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + UseDHMSFormatting = true; + } + + 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 + { + public TotalDeltaVASL_OAB() + { + Name = "Total ∆v ASL (OAB)"; + Description = "Shows the vessel's total delta velocity At Sea Level."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + public override void RefreshData() + { + EntryValue = Utility.VesselDeltaVComponentOAB?.TotalDeltaVASL; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalDeltaVActual_OAB : OabStageInfoEntry + { + public TotalDeltaVActual_OAB() + { + Name = "Total ∆v actual (OAB)"; + Description = "Shows the vessel's actual total delta velocity (not used in OAB)."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + public override void RefreshData() + { + EntryValue = Utility.VesselDeltaVComponentOAB?.TotalDeltaVActual; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalDeltaVVac_OAB : OabStageInfoEntry + { + public TotalDeltaVVac_OAB() + { + Name = "Total ∆v Vac (OAB)"; + Description = "Shows the vessel's total delta velocity in Vacuum."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + public override void RefreshData() + { + EntryValue = Utility.VesselDeltaVComponentOAB?.TotalDeltaVVac; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + /// + /// Calculates torque from the Center of Thrust and Center of Mass + /// + public class Torque : OabStageInfoEntry + { + [JsonProperty] + internal bool IsActive = false; + + public Torque() + { + Name = "Torque"; + Description = "Thrust torque that is generated by not having Thrust Vector and Center of Mass aligned. Turn on the Center of Thrust and Center of Mass VAB indicators to get an accurate value."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + 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; + + if (com == Vector3d.zero || cot == Vector3d.zero) + return; + + List engines = GameManager.Instance?.Game?.OAB?.Current?.Stats?.MainAssembly?.VesselDeltaV?.EngineInfo; + if (engines == null || engines.Count == 0) + return; + + Vector3d force = new Vector3d(); + + foreach (var engine in engines) + { + force += engine.ThrustVectorVac; + } + + var leverArm = cot - com; + + Vector3d torque = Vector3d.Cross(force, (Vector3d)leverArm); + + this.EntryValue = torque.magnitude; + this.BaseUnit = (double)EntryValue >= 1.0 ? "kNm" : "Nm"; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null || !this.IsActive) + return "-"; + + if ((double)EntryValue >= 1.0) + return $"{String.Format("{0:F2}", EntryValue)}"; + + return Math.Abs((double)EntryValue) > double.Epsilon ? $"{String.Format("{0:F2}", (double)EntryValue * 1000.0)}" : $"{String.Format("{0:F0}", (double)EntryValue)}"; + } + } + } + + /// + /// Holds stage info parameters for each stage. Also keeps information about the celestial body user selected in the window. + /// + public class StageInfo_OAB : OabStageInfoEntry + { + public List CelestialBodyForStage = new(); + + public StageInfo_OAB() + { + Name = "Stage Info (OAB)"; + Description = "Holds a list of stage info parameters."; + Category = MicroEntryCategory.OAB; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue ??= new List(); + + ((List)EntryValue).Clear(); + + if (Utility.VesselDeltaVComponentOAB?.StageInfo == null) return; + + foreach (var stage in Utility.VesselDeltaVComponentOAB.StageInfo) + { + ((List)EntryValue).Add(new DeltaVStageInfo_OAB + { + 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 + }); + } + } + + public override string ValueDisplay + { + get + { + return "-"; + } + } + + /// + /// Adds a new string to the CelestialBodyForStage list that corresponds to the HomeWorld, i.e. Kerbin + /// + /// + internal void AddNewCelestialBody(MicroCelestialBodies celestialBodies) + { + this.CelestialBodyForStage.Add(celestialBodies.Bodies.Find(b => b.IsHomeWorld).Name); + } + } + + /// + /// Parameters for one stage + /// + internal 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; + + 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) + { + float sum = 0; + foreach (DeltaVEngineInfo engInfo in this.DeltaVStageInfo.EnginesActiveInStage) + sum += engInfo.Engine.MaxThrustOutputAtm(atmPressure: cel.GetPressure(altitude) / 101.325) / + engInfo.Engine.currentEngineModeData.atmosphereCurve.Evaluate((float)cel.GetPressure(altitude) / 101.325f); + return GetThrustAtAltitude(altitude, cel) / sum; + } + 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); + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs new file mode 100644 index 0000000..37c1cbb --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/OrbitalEntries.cs @@ -0,0 +1,549 @@ +using KSP.Game; +using KSP.Sim.impl; + +namespace MicroMod +{ + public class OrbitalEntry : BaseEntry + { } + + public class Apoapsis : OrbitalEntry + { + public Apoapsis() + { + Name = "Apoapsis"; + Description = "Vessel's apoapsis height relative to the sea level. Apoapsis is the highest point of an orbit."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.ApoapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Periapsis : OrbitalEntry + { + public Periapsis() + { + Name = "Periapsis"; + Description = "Vessel's periapsis height relative to the sea level. Periapsis is the lowest point of an orbit."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.PeriapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TimeToApoapsis : OrbitalEntry + { + public TimeToApoapsis() + { + Name = "Time to Ap."; + Description = "Shows the time until the vessel reaches apoapsis, the highest point of the orbit."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public TimeToPeriapsis() + { + Name = "Time to Pe."; + Description = "Shows the time until the vessel reaches periapsis, the lowest point of the orbit."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public Inclination() + { + Name = "Inclination"; + Description = "Shows the vessel's orbital inclination relative to the equator."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.inclination; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Eccentricity : OrbitalEntry + { + public Eccentricity() + { + Name = "Eccentricity"; + Description = "Shows the vessel's orbital eccentricity which is a measure of how much an elliptical orbit is 'squashed'."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + BaseUnit = null; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.eccentricity; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Period : OrbitalEntry + { + public Period() + { + Name = "Period"; + Description = "Shows the amount of time it will take to complete a full orbit."; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public OrbitalSpeed() + { + Name = "Orbital speed"; + Description = "Shows the vessel's orbital speed"; + Category = MicroEntryCategory.Orbital; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.OrbitalSpeed; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TrueAnomaly : OrbitalEntry + { + public TrueAnomaly() + { + Name = "True anomaly"; + Description = "Angle between the direction of periapsis and the current position of the object, as seen from the main focus of the ellipse."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.TrueAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, Utility.RadiansToDegrees((double)EntryValue)); + } + } + } + + public class MeanAnomaly : OrbitalEntry + { + public MeanAnomaly() + { + Name = "Mean anomaly"; + Description = "Parameter used to describe the position of an object in its orbit around the celestial body."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.MeanAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class EccentricAnomaly : OrbitalEntry + { + public EccentricAnomaly() + { + Name = "Eccentric anomaly"; + Description = "Angle at the center of the orbital ellipse from the semi major axis to the line that passes through the center of the ellipse and the point on the auxiliary circle that is the intersection of the line perpendicular to the semi major axis and passes through the point in the orbit where the vessel is."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.EccentricAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class LongitudeOfAscendingNode : OrbitalEntry + { + public LongitudeOfAscendingNode() + { + Name = "LAN Ω"; + Description = "Longitude of Ascending Node is an angle from a specified reference direction, called the origin of longitude, to the direction of the ascending node, as measured in a specified reference plane."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.OrbitalElements.LongitudeOfAscendingNode; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ArgumentOfPeriapsis : OrbitalEntry + { + public ArgumentOfPeriapsis() + { + Name = "Argument of Pe."; + Description = "Angle from the line of the ascending node on the equatorial plane to the point of periapsis passage."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.OrbitalElements.ArgumentOfPeriapsis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SemiLatusRectum : OrbitalEntry + { + public SemiLatusRectum() + { + Name = "Semi latus rect"; + Description = "Half the length of the chord through one focus, perpendicular to the major axis."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.SemiLatusRectum; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SemiMajorAxis : OrbitalEntry + { + public SemiMajorAxis() + { + Name = "Semi major axis"; + Description = "Shows the distance from the center of an orbit to the farthest edge."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.OrbitalElements.SemiMajorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SemiMinorAxis : OrbitalEntry + { + public SemiMinorAxis() + { + Name = "Semi minor axis"; + Description = "Shows the distance from the center of an orbit to the nearest edge."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.SemiMinorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class OrbitalEnergy : OrbitalEntry + { + public OrbitalEnergy() + { + Name = "Orbital energy"; + Description = "Constant sum of two orbiting bodies' mutual potential energy and their total kinetic energy divided by the reduced mass."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + MiliUnit = "mJ"; + BaseUnit = "J"; + KiloUnit = "kJ"; + MegaUnit = "MJ"; + GigaUnit = "GJ"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.OrbitalEnergy / 1000.0; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ObT : OrbitalEntry + { + public ObT() + { + Name = "Orbit time"; + Description = "Shows orbit time in seconds from the Periapsis."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + 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 + { + public OrbitPercent() + { + Name = "Orbit percent"; + Description = "Percent of the orbit completed."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "%"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.orbitPercent * 100; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class OrbitRadius : OrbitalEntry + { + public OrbitRadius() + { + Name = "Orbit radius"; + Description = "Length from the center of the ellipse to the object."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbit.radius; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class SoiTransition : OrbitalEntry + { + public SoiTransition() + { + Name = "SOI trans."; + Description = "Shows the amount of time it will take to transition to another Sphere Of Influence."; + Category = MicroEntryCategory.Orbital; + IsDefault = false; + BaseUnit = "s"; + Formatting = null; + } + + 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 new file mode 100644 index 0000000..c3c3b45 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/StageInfoEntries.cs @@ -0,0 +1,26 @@ + +namespace MicroMod +{ + public class StageInfoEntry: BaseEntry + { } + + public class StageInfo : StageInfoEntry + { + public StageInfo() + { + Name = "Stage Info"; + Description = "Stage Info object, not implemented yet."; // TODO Stage Info display and description + Category = MicroEntryCategory.Stage; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo; + } + + public override string ValueDisplay => base.ValueDisplay; + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs new file mode 100644 index 0000000..22169e1 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/SurfaceEntries.cs @@ -0,0 +1,341 @@ +using KSP.Sim.impl; +using static KSP.Rendering.Planets.PQSData; + +namespace MicroMod +{ + public class SurfaceEntry : BaseEntry + { } + + public class AltitudeAgl : SurfaceEntry + { + public AltitudeAgl() + { + Name = "Altitude (ground)"; + Description = "Shows the vessel's altitude above ground Level."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AltitudeFromTerrain; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class AltitudeAsl : SurfaceEntry + { + public AltitudeAsl() + { + Name = "Altitude (sea)"; + Description = "Shows the vessel's altitude above sea level."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AltitudeFromSeaLevel; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class AltitudeFromScenery : SurfaceEntry + { + public AltitudeFromScenery() + { + Name = "Altitude (scenery)"; + Description = "Shows the vessel's altitude above scenery."; + Category = MicroEntryCategory.Surface; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AltitudeFromScenery; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class VerticalVelocity : SurfaceEntry + { + public VerticalVelocity() + { + Name = "Vertical vel."; + Description = "Shows the vessel's vertical velocity (up/down)."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VerticalSrfSpeed; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class HorizontalVelocity : SurfaceEntry + { + public HorizontalVelocity() + { + Name = "Horizontal vel."; + Description = "Shows the vessel's horizontal velocity across a celestial body's surface."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.HorizontalSrfSpeed; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Situation : SurfaceEntry + { + public Situation() + { + Name = "Situation"; + Description = "Shows the vessel's current situation: Landed, Flying, Orbiting, etc."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Situation; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return Utility.SituationToString((VesselSituations)EntryValue); + } + } + } + + public class Biome : SurfaceEntry + { + public Biome() + { + Name = "Biome"; + Description = "Shows the biome currently below the vessel."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.SimulationObject.Telemetry.SurfaceBiome; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return Utility.BiomeToString((BiomeSurfaceData)EntryValue); + } + } + } + + public class Latitude : SurfaceEntry + { + 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."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + Formatting = null; + } + + 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 + { + 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."; + Category = MicroEntryCategory.Surface; + IsDefault = true; + Formatting = null; + } + + 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 + { + public DynamicPressure_kPa() + { + Name = "Dynamic pressure"; + Description = "Dynamic Pressure (q) is a defined property of a moving flow of gas. It describes how much pressure the airflow is having on the vessel."; + Category = MicroEntryCategory.Surface; + IsDefault = false; + MiliUnit = "Pa"; + BaseUnit = "kPa"; + KiloUnit = "MPa"; + MegaUnit = "GPa"; + GigaUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.DynamicPressure_kPa; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StaticPressure_kPa : SurfaceEntry + { + public StaticPressure_kPa() + { + Name = "Static pressure"; + Description = "Static pressure is a term used to define the amount of pressure exerted by a fluid that is not moving - ambient pressure."; + Category = MicroEntryCategory.Surface; + IsDefault = false; + MiliUnit = "Pa"; + BaseUnit = "kPa"; + KiloUnit = "MPa"; + MegaUnit = "GPa"; + GigaUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.StaticPressure_kPa; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class AtmosphericTemperature : SurfaceEntry + { + public AtmosphericTemperature() + { + Name = "Static ambient temp."; + Description = "Temperature measured outside the vessel. The sensor which detects SAT must be carefully sited to ensure that airflow over it does not affect the indicated temperature."; + Category = MicroEntryCategory.Surface; + IsDefault = false; + BaseUnit = "K"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.AtmosphericTemperature; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class ExternalTemperature : SurfaceEntry + { + public ExternalTemperature() + { + Name = "Total air temp."; + Description = "Measured by means of a sensor positioned in the airflow, kinetic heating will result, raising the temperature measured above the Static ambient temperature."; + Category = MicroEntryCategory.Surface; + IsDefault = false; + BaseUnit = "K"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.ExternalTemperature; + } + + 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 new file mode 100644 index 0000000..a1f144a --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/TargetEntries.cs @@ -0,0 +1,832 @@ +using KSP.Sim.impl; + +namespace MicroMod +{ + public class TargetEntry : BaseEntry + { } + + public class Target_Name : TargetEntry + { + public Target_Name() + { + Name = "Name"; + Description = "Target's name."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.DisplayName; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TargetApoapsis : TargetEntry + { + public TargetApoapsis() + { + Name = "Target Ap."; + Description = "Shows the target's apoapsis height relative to the sea level."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.ApoapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TargetPeriapsis : TargetEntry + { + public TargetPeriapsis() + { + Name = "Target Pe."; + Description = "Shows the target's periapsis height relative to the sea level."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.PeriapsisArl; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class DistanceToTarget : TargetEntry + { + public DistanceToTarget() + { + Name = "Distance to Tgt"; + Description = "Shows the current distance between the vessel and the target."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit != null ? (Utility.ActiveVessel.Orbit.Position - Utility.ActiveVessel.TargetObject.Orbit.Position).magnitude : null; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + // return value only if vessel and target are in the same SOI + return Utility.ActiveVessel.Orbit.referenceBody == Utility.ActiveVessel.TargetObject.Orbit.referenceBody ? + String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue) : "-"; + } + } + } + + public class RelativeSpeed : TargetEntry + { + public RelativeSpeed() + { + Name = "Rel. speed"; + Description = "Shows the relative velocity between the vessel and the target."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit != null ? (Utility.ActiveVessel.Orbit.relativeVelocity - Utility.ActiveVessel.TargetObject.Orbit.relativeVelocity).magnitude : null; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + // return value only if vessel and target are in the same SOI + if (Utility.ActiveVessel.Orbit.referenceBody != Utility.ActiveVessel.TargetObject.Orbit.referenceBody) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); + } + } + } + + public class RelativeInclination : TargetEntry + { + public RelativeInclination() + { + Name = "Rel. inclination"; + Description = "Shows the relative inclination between the vessel and the target."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.AscendingNodeTarget.Inclination; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + // return value only if vessel and target are in the same SOI + if (Utility.ActiveVessel.Orbit.referenceBody != Utility.ActiveVessel.TargetObject?.Orbit?.referenceBody) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); + } + } + } + + public class Target_AltitudeFromSeaLevel : TargetEntry + { + public Target_AltitudeFromSeaLevel() + { + Name = "Altitude (sea)"; + Description = "Shows the target's altitude above sea level."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.AltitudeFromSeaLevel; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_Inclination : TargetEntry + { + public Target_Inclination() + { + Name = "Inclination"; + Description = "Shows the target's orbital inclination relative to the equator."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.inclination; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_Eccentricity : TargetEntry + { + public Target_Eccentricity() + { + Name = "Eccentricity"; + Description = "Shows the target's orbital eccentricity which is a measure of how much an elliptical orbit is 'squashed'."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = null; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.eccentricity; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_Period : TargetEntry + { + public Target_Period() + { + Name = "Period"; + Description = "Shows the amount of time it will take the target to complete a full orbit."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = "s"; + Formatting = null; + } + + 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 + { + public Target_Obtvelocity() + { + Name = "Orbital speed"; + Description = "Shows the target's orbital speed."; + Category = MicroEntryCategory.Target; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.ObtVelocity.magnitude; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_TrueAnomaly : TargetEntry + { + public Target_TrueAnomaly() + { + Name = "True anomaly"; + Description = "Angle between the direction of periapsis and the current position of the object, as seen from the main focus of the ellipse."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.TrueAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, Utility.RadiansToDegrees((double)EntryValue)); + } + } + } + + public class Target_MeanAnomaly : TargetEntry + { + public Target_MeanAnomaly() + { + Name = "Mean anomaly"; + Description = "Parameter used to describe the position of the target in its orbit around the celestial body."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.MeanAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class Target_EccentricAnomaly : TargetEntry + { + public Target_EccentricAnomaly() + { + Name = "Eccentric anomaly"; + Description = "Angle at the center of the orbital ellipse from the semi major axis to the line that passes through the center of the ellipse and the point on the auxiliary circle that is the intersection of the line perpendicular to the semi major axis and passes through the point in the orbit where the target is."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.EccentricAnomaly; + } + + public override string ValueDisplay + { + get + { + if (EntryValue == null) + return "-"; + + return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, (double)EntryValue * PatchedConicsOrbit.Rad2Deg); + } + } + } + + public class Target_LongitudeOfAscendingNode : TargetEntry + { + public Target_LongitudeOfAscendingNode() + { + Name = "LAN Ω"; + Description = "Shows the target's Longitude Of Ascending Node."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.longitudeOfAscendingNode; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_ArgumentOfPeriapsis : TargetEntry + { + public Target_ArgumentOfPeriapsis() + { + Name = "Argument of Pe."; + Description = "Angle from the line of the ascending node on the equatorial plane to the point of periapsis passage."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.argumentOfPeriapsis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_SemiLatusRectum : TargetEntry + { + public Target_SemiLatusRectum() + { + Name = "Semi latus rect"; + Description = "Half the length of the chord through one focus, perpendicular to the major axis."; + Category = MicroEntryCategory.Target; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.SemiLatusRectum; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_SemiMajorAxis : TargetEntry + { + public Target_SemiMajorAxis() + { + Name = "Semi major axis"; + Description = "Shows the distance from the center of an orbit to the farthest edge."; + Category = MicroEntryCategory.Target; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.semiMajorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_SemiMinorAxis : TargetEntry + { + public Target_SemiMinorAxis() + { + Name = "Semi minor axis"; + Description = "Shows the distance from the center of an orbit to the nearest edge."; + Category = MicroEntryCategory.Target; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.SemiMinorAxis; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_ObT : TargetEntry + { + public Target_ObT() + { + Name = "Orbit time"; + Description = "Shows orbit time in seconds from the Periapsis."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 3; + Formatting = "N"; + } + + 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 + { + public Target_ReferenceBodyConstants_Radius() + { + Name = "Body radius"; + Description = "Radius of the body that target is orbiting."; + Category = MicroEntryCategory.Target; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.referenceBody?.radius; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_ReferenceBodyConstants_StandardGravitationParameter : TargetEntry + { + public Target_ReferenceBodyConstants_StandardGravitationParameter() + { + Name = "Std. grav. param."; + Description = "Product of the gravitational constant G and the mass M of the body target is orbiting."; + Category = MicroEntryCategory.Target; + IsDefault = false; + BaseUnit = "μ"; + NumberOfDecimalDigits = 4; + Formatting = "e"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.referenceBody?.gravParameter; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Target_OrbitRadius : TargetEntry + { + public Target_OrbitRadius() + { + Name = "Orbit radius"; + Description = "Length from the center of the ellipse to the object."; + Category = MicroEntryCategory.Target; + IsDefault = false; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TargetObject?.Orbit?.radius; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class PhaseAngle : TargetEntry + { + public PhaseAngle() + { + Name = "Phase angle"; + Description = "Angle between your vessel, the reference body and the target. How much \"ahead\" or \"behind\" in phase you are with the target."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.TargetExists() ? TransferInfo.GetPhaseAngle() : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TransferAngle : TargetEntry + { + public TransferAngle() + { + Name = "Transfer angle"; + Description = "Phase angle needed for an optimal Hohmann transfer orbit. Use a circular orbit for a more accurate value."; + Category = MicroEntryCategory.Target; + IsDefault = true; + BaseUnit = "°"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.TargetExists() ? TransferInfo.GetTransferAngle() : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class DistanceAtCloseApproach1 : TargetEntry + { + public DistanceAtCloseApproach1() + { + Name = "C.A.Dist.1"; + Description = "Close approach distance to target (1)."; + Category = MicroEntryCategory.Target; + IsDefault = true; + HideWhenNoData = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect1Target?.IsValid; + + EntryValue = isValid != null && isValid == true ? Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect1Target.RelativeDistance : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TimeToCloseApproach1 : TargetEntry + { + public TimeToCloseApproach1() + { + Name = "C.A.Time1"; + Description = "Close approach time to target (1)."; + Category = MicroEntryCategory.Target; + IsDefault = true; + HideWhenNoData = true; + BaseUnit = "s"; + Formatting = null; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect1Target?.IsValid; + + 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 + { + public RelativeSpeedAtCloseApproach1() + { + Name = "C.A.Speed1"; + Description = "Close approach relative speed to target (1)."; + Category = MicroEntryCategory.Target; + IsDefault = true; + HideWhenNoData = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect1Target?.IsValid; + + EntryValue = isValid != null && isValid == true ? EntryValue = Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect1Target.RelativeSpeed : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class DistanceAtCloseApproach2 : TargetEntry + { + public DistanceAtCloseApproach2() + { + Name = "C.A.Dist.2"; + Description = "Close approach distance to target (2)."; + Category = MicroEntryCategory.Target; + IsDefault = false; + HideWhenNoData = true; + MiliUnit = "mm"; + BaseUnit = "m"; + KiloUnit = "km"; + MegaUnit = "Mm"; + GigaUnit = "Gm"; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect2Target?.IsValid; + + EntryValue = isValid != null && isValid == true ? EntryValue = Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect2Target.RelativeDistance : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TimeToCloseApproach2 : TargetEntry + { + public TimeToCloseApproach2() + { + Name = "C.A.Time2"; + Description = "Close approach time to target (2)."; + Category = MicroEntryCategory.Target; + IsDefault = false; + HideWhenNoData = true; + BaseUnit = "s"; + Formatting = null; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect2Target?.IsValid; + + 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 + { + public RelativeSpeedAtCloseApproach2() + { + Name = "C.A.Speed2"; + Description = "Close approach relative speed to target (2)."; + Category = MicroEntryCategory.Target; + IsDefault = false; + HideWhenNoData = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + bool? isValid = Utility.ActiveVessel.Orbiter?.OrbitTargeter?.Intersect2Target?.IsValid; + + EntryValue = isValid != null && isValid == true ? EntryValue = Utility.ActiveVessel.Orbiter.OrbitTargeter.Intersect2Target.RelativeSpeed : null; + } + + public override string ValueDisplay => base.ValueDisplay; + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs b/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs new file mode 100644 index 0000000..09f08c8 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Entries/VesselEntries.cs @@ -0,0 +1,462 @@ + +namespace MicroMod +{ + public class VesselEntry : BaseEntry + { } + + public class VesselName : VesselEntry + { + public VesselName() + { + Name = "Name"; + Description = "Name of the current vessel."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.DisplayName; + } + + public override string ValueDisplay => EntryValue?.ToString(); + } + + public class Mass : VesselEntry + { + public Mass() + { + Name = "Mass"; + Description = "Total mass of the vessel."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + MiliUnit = "g"; + BaseUnit = "kg"; + KiloUnit = "T"; + MegaUnit = "kT"; + GigaUnit = "MT"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.totalMass * 1000; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalDeltaVActual : VesselEntry + { + public TotalDeltaVActual() + { + Name = "Total ∆v"; + Description = "Vessel's total delta velocity."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.TotalDeltaVActual; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalDeltaVASL : VesselEntry + { + public TotalDeltaVASL() + { + Name = "Total ∆v ASL"; + Description = "Total delta velocity of the vessel At Sea Level."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.TotalDeltaVASL; + } + + public override string ValueDisplay => base.ValueDisplay; + + } + + public class TotalDeltaVVac : VesselEntry + { + public TotalDeltaVVac() + { + Name = "Total ∆v Vac"; + Description = "Total delta velocity of the vessel in vacuum."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + MiliUnit = "mm/s"; + BaseUnit = "m/s"; + KiloUnit = "km/s"; + MegaUnit = "Mm/s"; + GigaUnit = "Gm/s"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.TotalDeltaVVac; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalBurnTime : VesselEntry + { + public TotalBurnTime() + { + Name = "Total burn time"; + Description = "Burn Time vessel can sustain with 100% thrust."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + 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 + { + public StageThrustActual() + { + Name = "Thrust"; + Description = "Vessel's actual thrust."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + MiliUnit = "N"; + BaseUnit = "kN"; + KiloUnit = "MN"; + MegaUnit = "GN"; + GigaUnit = null; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo.FirstOrDefault()?.ThrustActual; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageThrustASL : VesselEntry + { + public StageThrustASL() + { + Name = "Thrust (ASL)"; + Description = "Vessel's thrust At Sea Level."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + MiliUnit = "N"; + BaseUnit = "kN"; + KiloUnit = "MN"; + MegaUnit = "GN"; + GigaUnit = null; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.ThrustASL * 1000; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageThrustVac : VesselEntry + { + public StageThrustVac() + { + Name = "Thrust (vacuum)"; + Description = "Vessel's thrust in vacuum."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + MiliUnit = "N"; + BaseUnit = "kN"; + KiloUnit = "MN"; + MegaUnit = "GN"; + GigaUnit = null; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.ThrustVac * 1000; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageTWRActual : VesselEntry + { + public StageTWRActual() + { + Name = "TWR"; + Description = "Vessel's Thrust to Weight Ratio."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo.FirstOrDefault()?.TWRActual; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageTWRASL : VesselEntry + { + public StageTWRASL() + { + Name = "TWR (ASL)"; + Description = "Vessel's Thrust to Weight Ratio At Sea Level."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.TWRASL; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageTWRVac : VesselEntry + { + public StageTWRVac() + { + Name = "TWR (vacuum)"; + Description = "Vessel's Thrust to Weight Ratio in vacuum."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = null; + NumberOfDecimalDigits = 2; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.TWRVac; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageISPActual : VesselEntry + { + public StageISPActual() + { + Name = "ISP"; + Description = "Specific impulse (ISP) is a measure of how efficiently a reaction mass engine creates thrust."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.IspActual; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageISPAsl : VesselEntry + { + public StageISPAsl() + { + Name = "ISP (ASL)"; + Description = "Specific impulse At Sea Level."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.IspASL; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageISPVac : VesselEntry + { + public StageISPVac() + { + Name = "ISP (vacuum)"; + Description = "Specific impulse in vacuum."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "s"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.StageInfo?.FirstOrDefault()?.IspVac; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class FuelPercentage : VesselEntry + { + public FuelPercentage() + { + Name = "Vessel fuel"; + Description = "Vessel's fuel percentage left."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "%"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.FuelPercentage; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class StageFuelPercentage : VesselEntry + { + public StageFuelPercentage() + { + Name = "Stage fuel"; + Description = "Stage fuel percentage left."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "%"; + NumberOfDecimalDigits = 1; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.StageFuelPercentage; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class PartsCount : VesselEntry + { + public PartsCount() + { + Name = "Parts"; + Description = "Number of parts vessel is constructed of."; + Category = MicroEntryCategory.Vessel; + IsDefault = true; + BaseUnit = null; + Formatting = null; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.VesselDeltaV?.PartInfo?.Count; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class Throttle : VesselEntry + { + public Throttle() + { + Name = "Throttle"; + Description = "Vessel's current throttle in %."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = "%"; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.flightCtrlState.mainThrottle * 100; + } + + public override string ValueDisplay => base.ValueDisplay; + } + + public class TotalCommandCrewCapacity : VesselEntry + { + public TotalCommandCrewCapacity() + { + Name = "Command crew capacity"; + Description = "Crew capacity of all parts."; + Category = MicroEntryCategory.Vessel; + IsDefault = false; + BaseUnit = null; + NumberOfDecimalDigits = 0; + Formatting = "N"; + } + + public override void RefreshData() + { + EntryValue = Utility.ActiveVessel.TotalCommandCrewCapacity; + } + + public override string ValueDisplay => base.ValueDisplay; + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/Manager.cs b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs new file mode 100644 index 0000000..77bfd24 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs @@ -0,0 +1,311 @@ +using BepInEx.Logging; +using KSP.Game; +using System.Reflection; +using UnityEngine; + +namespace MicroMod +{ + internal class Manager + { + internal List Windows; + internal List Entries; + internal UI UI; + internal MessageManager MessageManager; + private MicroEngineerMod _plugin; + + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Manager"); + + internal Manager(MicroEngineerMod plugin) + { + _plugin = plugin; + Entries = InitializeEntries(); + Windows = InitializeWindows(); + + // Load window positions and states from disk, if file exists + Utility.LoadLayout(Windows); + } + + public void Update() + { + Utility.RefreshGameManager(); + + // Perform flight UI updates only if we're in Flight or Map view + if (Utility.GameState != null && (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView)) + { + Utility.RefreshActiveVesselAndCurrentManeuver(); + + if (Utility.ActiveVessel == null) + return; + + // Refresh all active windows' entries + foreach (EntryWindow window in Windows.Where(w => w.IsFlightActive && w is EntryWindow)) + window.RefreshData(); + } + } + + /// + /// Builds the list of all Entries + /// + internal List InitializeEntries() + { + Entries = new List(); + + Assembly assembly = Assembly.GetExecutingAssembly(); + Type[] types = assembly.GetTypes(); + + // Exclude base classes + Type[] excludedTypes = new[] { typeof(BaseEntry), typeof(BodyEntry), typeof(FlightEntry), + typeof(ManeuverEntry), typeof(MiscEntry), typeof(OabStageInfoEntry), typeof(OrbitalEntry), + typeof(StageInfoEntry), typeof(SurfaceEntry), typeof(TargetEntry), typeof(VesselEntry) }; + + Type[] entryTypes = types.Where(t => typeof(BaseEntry).IsAssignableFrom(t) && !excludedTypes.Contains(t)).ToArray(); + + foreach (Type entryType in entryTypes) + { + BaseEntry entry = Activator.CreateInstance(entryType) as BaseEntry; + if (entry != null) + Entries.Add(entry); + } + + return Entries; + } + + /// + /// Builds the default Windows and fills them with default Entries + /// + internal List InitializeWindows() + { + Windows = new List(); + + try + { + Windows.Add(new MainGuiWindow + { + LayoutVersion = Utility.CurrentLayoutVersion, + IsEditorActive = false, + IsFlightActive = false, + IsMapActive = false, + //EditorRect = null, + FlightRect = new Rect(Styles.MainGuiX, Styles.MainGuiY, Styles.WindowWidth, Styles.WindowHeight), + }); + + 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) + }); + + Windows.Add(new EntryWindow + { + Name = "Vessel", + Abbreviation = "VES", + Description = "Vessel entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Vessel, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Vessel && entry.IsDefault).ToList() + }); + + Windows.Add(new EntryWindow + { + Name = "Orbital", + Abbreviation = "ORB", + Description = "Orbital entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Orbital, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Orbital && entry.IsDefault).ToList() + }); + + Windows.Add(new EntryWindow + { + Name = "Surface", + Abbreviation = "SUR", + Description = "Surface entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Surface, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Surface && entry.IsDefault).ToList() + }); + + Windows.Add(new EntryWindow + { + Name = "Flight", + Abbreviation = "FLT", + Description = "Flight entries", + IsEditorActive = false, + IsFlightActive = false, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Flight, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Flight && entry.IsDefault).ToList() + }); + + Windows.Add(new EntryWindow + { + Name = "Target", + Abbreviation = "TGT", + Description = "Flight entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Target, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Target && entry.IsDefault).ToList() + }); + + Windows.Add(new ManeuverWindow + { + Name = "Maneuver", + Abbreviation = "MAN", + Description = "Maneuver entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Maneuver, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Maneuver && entry.IsDefault).ToList() + }); + + Windows.Add(new StageWindow + { + Name = "Stage", + Abbreviation = "STG", + Description = "Stage entries", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.Stage, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.Stage && entry.IsDefault).ToList() + }); + + Windows.Add(new EntryWindow + { + Name = "Stage (OAB)", + Abbreviation = "SOAB", + Description = "Stage Info window for OAB", + IsEditorActive = false, + 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), + Entries = Entries.Where(entry => entry.Category == MicroEntryCategory.OAB && entry.IsDefault).ToList() + }); + + return Windows; + } + catch (Exception ex) + { + _logger.LogError("Error creating a BaseWindow. Full exception: " + ex); + return null; + } + } + + /// + /// Creates a new custom window user can fill with any entry + /// + /// + internal int CreateCustomWindow(List editableWindows) + { + // Default window's name will be CustomX where X represents the first not used integer + int nameID = 1; + foreach (EntryWindow window in editableWindows) + { + if (window.Name == "Custom" + nameID) + nameID++; + } + + EntryWindow newWindow = new() + { + Name = "Custom" + nameID, + Abbreviation = nameID.ToString().Length == 1 ? "Cu" + nameID : nameID.ToString().Length == 2 ? "C" + nameID : nameID.ToString(), + Description = "", + IsEditorActive = false, + IsFlightActive = true, + IsMapActive = false, + IsEditorPoppedOut = false, + IsFlightPoppedOut = false, + IsMapPoppedOut = false, + IsLocked = false, + MainWindow = MainWindow.None, + //EditorRect = null, + FlightRect = new Rect(Styles.PoppedOutX, Styles.PoppedOutY, Styles.WindowWidth, Styles.WindowHeight), + Entries = new List() + }; + + Windows.Add(newWindow); + editableWindows.Add(newWindow); + + return editableWindows.Count - 1; + } + + internal void ResetLayout() + { + Windows.Clear(); + Entries.Clear(); + Entries = InitializeEntries(); + Windows = InitializeWindows(); + UI.Windows = Windows; + MessageManager.Windows = Windows; + } + + internal void LoadLayout() + { + Utility.LoadLayout(Windows); + UI.Windows = Windows; + MessageManager.Windows = Windows; + } + + internal void SaveLayout() => Utility.SaveLayout(Windows); + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs new file mode 100644 index 0000000..f9661c8 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs @@ -0,0 +1,139 @@ +using BepInEx.Logging; +using KSP.Game; +using KSP.Messages; + +namespace MicroMod +{ + internal class MessageManager + { + MicroEngineerMod _plugin; + private Manager _manager; + private UI _ui; + internal List Windows; + + private static readonly ManualLogSource _logger = Logger.CreateLogSource("MicroEngineer.MessageManager"); + + internal MessageManager(MicroEngineerMod plugin, Manager manager, UI ui) + { + _plugin = plugin; + _manager = manager; + _ui = ui; + Windows = _manager.Windows; + + SubscribeToMessages(); + } + + /// + /// Subscribe to KSP2 messages + /// + internal 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)); + + // We are loading layout state when entering Flight or OAB game state + Utility.MessageCenter.Subscribe(new Action(this.GameStateEntered)); + + // We are saving layout state when exiting from Flight or OAB game state + Utility.MessageCenter.Subscribe(new Action(this.GameStateLeft)); + + // Sets the selected node index to the newly created node + Utility.MessageCenter.Subscribe(new Action(this.OnManeuverCreatedMessage)); + + // Resets node index + Utility.MessageCenter.Subscribe(new Action(this.OnManeuverRemovedMessage)); + + // Torque update for StageInfoOAB + Utility.MessageCenter.Subscribe(new Action(this.OnPartManipulationCompletedMessage)); + } + + private void OnManeuverCreatedMessage(MessageCenterMessage message) + { + var maneuverWindow = Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; + maneuverWindow.OnManeuverCreatedMessage(message); + } + + private void OnManeuverRemovedMessage(MessageCenterMessage message) + { + var maneuverWindow = Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; + maneuverWindow.OnManeuverRemovedMessage(message); + } + + private void OnPartManipulationCompletedMessage(MessageCenterMessage obj) + { + EntryWindow stageInfoOabWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + + Torque torque = (Torque)Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Torque"); + torque.RefreshData(); + } + + private void GameStateEntered(MessageCenterMessage obj) + { + _logger.LogInfo("Message triggered: GameStateEnteredMessage"); + + Utility.RefreshGameManager(); + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) + { + Utility.LoadLayout(Windows); + _manager.Windows = Windows; + _ui.Windows = Windows; + + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) + _ui.ShowGuiFlight = Windows.OfType().FirstOrDefault().IsFlightActive; + + if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) + { + _ui.ShowGuiOAB = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive; + _ui.CelestialBodies.GetBodies(); + _ui.CelestialBodySelectionStageIndex = -1; + Styles.SetActiveTheme(Theme.Gray); // TODO implement other themes in OAB + } + } + } + + private void GameStateLeft(MessageCenterMessage obj) + { + _logger.LogInfo("Message triggered: GameStateLeftMessage"); + + Utility.RefreshGameManager(); + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) + { + Utility.SaveLayout(Windows); + + if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) + _ui.ShowGuiFlight = false; + + if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) + _ui.ShowGuiOAB = false; + } + } + + /// + /// Refresh all staging data while in OAB + /// + private void RefreshStagingDataOAB(MessageCenterMessage obj) + { + // 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; + + Utility.RefreshGameManager(); + if (Utility.GameState.GameState != GameState.VehicleAssemblyBuilder) return; + + Utility.RefreshStagesOAB(); + + EntryWindow stageWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + + if (Utility.VesselDeltaVComponentOAB?.StageInfo == null) + { + stageWindow.Entries.Find(e => e.Name == "Stage Info (OAB)").EntryValue = null; + return; + } + + foreach (var entry in stageWindow.Entries) + entry.RefreshData(); + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroCelestialBodies.cs b/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs similarity index 99% rename from MicroEngineerProject/MicroEngineer/MicroCelestialBodies.cs rename to MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs index afb5c24..72d3006 100644 --- a/MicroEngineerProject/MicroEngineer/MicroCelestialBodies.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/MicroCelestialBodies.cs @@ -139,4 +139,4 @@ internal class CelestialBody internal bool IsHomeWorld; internal CelestialBodyComponent CelestialBodyComponent; } -} +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/UI.cs b/MicroEngineerProject/MicroEngineer/Managers/UI.cs new file mode 100644 index 0000000..f15787e --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Managers/UI.cs @@ -0,0 +1,760 @@ +using BepInEx.Logging; +using KSP.Game; +using KSP.Sim.impl; +using KSP.UI.Binding; +using UnityEngine; + +namespace MicroMod +{ + internal class UI + { + private MicroEngineerMod _plugin; + private Manager _manager; + + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.UI"); + + internal List Windows; + + 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(MicroEngineerMod plugin, Manager manager) + { + _plugin = plugin; + _manager = manager; + Windows = manager.Windows; + } + + 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)Windows.Find(w => w is MainGuiWindow); // window => window.MainWindow == MainWindow.MainGui); + + // 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 = 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( + index, + window.FlightRect, + DrawPopoutWindow, + "", + 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); + + 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; + + GUILayout.Space(10); + GUILayout.Label("Layout control"); + if (GUILayout.Button("SAVE LAYOUT", Styles.NormalBtnStyle)) + { + _manager.SaveLayout(); + _showGuiSettingsFlight = false; + } + GUILayout.Space(5); + if (GUILayout.Button("LOAD LAYOUT", Styles.NormalBtnStyle)) + _manager.LoadLayout(); + if (GUILayout.Button("RESET LAYOUT", Styles.NormalBtnStyle)) + { + _manager.ResetLayout(); + _selectedWindowId = 0; + } + + GUILayout.Space(10); + GUILayout.Label("Theme"); + GUILayout.Space(-10); + + GUILayout.BeginHorizontal(); + var settingsWindow = 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(); + + GUI.DragWindow(new Rect(0, 0, Screen.width, Screen.height)); + } + + private void OnGUI_OAB() + { + if (!ShowGuiOAB) return; + + EntryWindow stageInfoOAB = 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 = Windows.FindAll(w => w is EntryWindow).Cast().ToList(); + + GUILayout.Space(-15); + GUILayout.BeginHorizontal(); + if (GUILayout.Button(Styles.Settings20Texture, Styles.SettingsMainGuiBtnStyle)) + { + Rect mainGuiRect = 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(int windowIndex) + { + List entryWindows = Windows.FindAll(w => w is EntryWindow).Cast().ToList(); + EntryWindow w = Windows.FindAll(w => w is EntryWindow).Cast().ToList()[windowIndex]; + + 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(); + + // If window is popped out and it's not locked => show the close button. If it's not popped out => show to popup arrow + //isPopout = isPopout && !isLocked ? !CloseButton(Styles.CloseBtnRect) : !isPopout ? GUILayout.Button("⇖", Styles.PopoutBtnStyle) : isPopout; + //isPopout = isPopout && !isLocked ? !CloseButton(Styles.CloseBtnRect) : !isPopout ? GUILayout.Button("⇖", Styles.PopoutBtnStyle) : isPopout; + + GUILayout.Label($"{sectionName}", Styles.WindowTitleLabelStyle); + GUILayout.FlexibleSpace(); + if(GUILayout.Button(Styles.Settings15Texture, Styles.SettingsBtnStyle)) + { + _selectedWindowId = Windows. + FindAll(w => w is EntryWindow).Cast().ToList(). + FindAll(w => w.IsEditable). + FindIndex(w => w.Name == sectionName); + _showEditWindow = true; + } + 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 = Windows.FindAll(w => w is EntryWindow).Cast().ToList().FindAll(w => w.IsEditable); // Editable windows are all except MainGUI, Settings, Stage and StageInfoOAB + List entriesByCategory = _manager.Entries.FindAll(e => e.Category == _selectedCategory); // All window stageInfoOabEntries 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; + } + 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; + } + 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)) + { + Windows.Remove(editableWindows[_selectedWindowId]); + editableWindows.Remove(editableWindows[_selectedWindowId]); + _selectedWindowId--; + } + } + if (GUILayout.Button("NEW WINDOW", Styles.NormalBtnStyle)) + _selectedWindowId = _manager.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); + + GUILayout.Label(entries[i].Name, Styles.NameLabelStyle); + 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(entriesByCategory[i]); + } + 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)); + } + + #endregion + + #region OAB scene UI + + private void DrawStageInfoOAB(int windowID) + { + EntryWindow stageInfoOabWindow = 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)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 = 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); + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs index 3831268..aacc6f7 100644 --- a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs +++ b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs @@ -1,65 +1,30 @@ using BepInEx; -using KSP.Game; using UnityEngine; using SpaceWarp; using SpaceWarp.API.Assets; using SpaceWarp.API.Mods; using SpaceWarp.API.UI.Appbar; using KSP.UI.Binding; -using KSP.Sim.DeltaV; -using KSP.Messages; -using KSP.Sim.impl; namespace MicroMod { - [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "0.8.0")] + [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "1.0.0")] [BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)] public class MicroEngineerMod : BaseSpaceWarpPlugin { - private bool _showGuiFlight; - private bool _showGuiOAB; - private bool _showGuiSettingsOAB; - - #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 - - /// - /// Holds all entries we can have in any window - /// - private List MicroEntries; - - /// - /// All windows that can be rendered - /// - private List MicroWindows; - - /// - /// Holds data on all bodies for calculating TWR (currently) - /// - private MicroCelestialBodies _celestialBodies = new(); - - // Index of the stage for which user wants to select a different CelestialBody for different TWR calculations. -1 -> no stage is selected - private int _celestialBodySelectionStageIndex = -1; - - // If game input is enabled or disabled (used for locking controls when user is editing a text field - private bool _gameInputState = true; - - private float _lastUpdate = 0; + private Manager _manager; + private MessageManager _messagesManager; + private UI _ui; public override void OnInitialized() { - MicroStyles.InitializeStyles(); - InitializeEntries(); - InitializeWindows(); - SubscribeToMessages(); - InitializeCelestialBodies(); - - // Load window positions and states from disk, if file exists - MicroUtility.LoadLayout(MicroWindows); + Styles.Initialize(this); + + _manager = new Manager(this); + _ui = new UI(this, _manager); + _messagesManager = new MessageManager(this, _manager, _ui); + _manager.UI = _ui; + _manager.MessageManager = _messagesManager; BackwardCompatibilityInitializations(); @@ -70,8 +35,8 @@ public override void OnInitialized() AssetManager.GetAsset($"{SpaceWarpMetadata.ModID}/images/icon.png"), isOpen => { - _showGuiFlight = isOpen; - MicroWindows.Find(w => w.MainWindow == MainWindow.MainGui).IsFlightActive = isOpen; + _ui.ShowGuiFlight = isOpen; + _manager.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = isOpen; GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(isOpen); }); @@ -81,1206 +46,32 @@ public override void OnInitialized() AssetManager.GetAsset($"{SpaceWarpMetadata.ModID}/images/icon.png"), isOpen => { - _showGuiOAB = isOpen; - MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive = isOpen; + _ui.ShowGuiOAB = isOpen; + _manager.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive = isOpen; GameObject.Find("BTN - MicroEngineerOAB")?.GetComponent()?.SetValue(isOpen); }); } private void BackwardCompatibilityInitializations() { - // Preserve backward compatibility with 0.6.0. If user previously saved the layout and then upgraded without deleting the original folder, then StageInfoOAB window will be wiped by LoadLayout(). So, we add it manually now. - if (MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB) == null) - InitializeStageInfoOABWindow(); - // Preserve backward compatibility with SpaceWarp 1.0.1 - if (MicroUtility.IsModOlderThan("SpaceWarp", 1, 1, 0)) + if (Utility.IsModOlderThan("SpaceWarp", 1, 1, 0)) { - Logger.LogInfo("Space Warp older version detected. Loading old MicroStyles."); - MicroStyles.SetStylesForOldSpaceWarpSkin(); + Logger.LogInfo("Space Warp older version detected. Loading old Styles."); + Styles.SetStylesForOldSpaceWarpSkin(); } else - Logger.LogInfo("Space Warp new version detected. Loading new MicroStyles."); - - // Preserve backward compatibility with 0.7.2. If user previously saved the layout and then upgraded without deleting the original folder, then the Torque entry won't be in the loaded StageOAB window. So, we add it manually now. - MicroWindow stageOabWindow = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB); - if (stageOabWindow.Entries.Find(e => e.Name == "Torque") == null) - { - stageOabWindow.Entries.Add(this.MicroEntries.Find(e => e.Name == "Torque")); - MicroUtility.SaveLayout(this.MicroWindows); - } - } - - /// - /// Subscribe to Messages KSP2 is using - /// - private void SubscribeToMessages() - { - MicroUtility.RefreshGameManager(); - - // While in OAB we use the VesselDeltaVCalculationMessage event to refresh data as it's triggered a lot less frequently than Update() - MicroUtility.MessageCenter.Subscribe(new Action(this.RefreshStagingDataOAB)); - - // We are loading layout state when entering Flight or OAB game state - MicroUtility.MessageCenter.Subscribe(new Action(this.GameStateEntered)); - - // We are saving layout state when exiting from Flight or OAB game state - MicroUtility.MessageCenter.Subscribe(new Action(this.GameStateLeft)); - } - - private void GameStateEntered(MessageCenterMessage obj) - { - Logger.LogInfo("Message triggered: GameStateEnteredMessage"); - - MicroUtility.RefreshGameManager(); - if (MicroUtility.GameState.GameState == GameState.FlightView || MicroUtility.GameState.GameState == GameState.VehicleAssemblyBuilder || MicroUtility.GameState.GameState == GameState.Map3DView) - { - MicroUtility.LoadLayout(MicroWindows); - - if(MicroUtility.GameState.GameState == GameState.FlightView || MicroUtility.GameState.GameState == GameState.Map3DView) - _showGuiFlight = MicroWindows.Find(w => w.MainWindow == MainWindow.MainGui).IsFlightActive; - - if(MicroUtility.GameState.GameState == GameState.VehicleAssemblyBuilder) - { - _showGuiOAB = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive; - InitializeCelestialBodies(); - _celestialBodySelectionStageIndex = -1; - } - } - } - - private void GameStateLeft(MessageCenterMessage obj) - { - Logger.LogInfo("Message triggered: GameStateLeftMessage"); - - MicroUtility.RefreshGameManager(); - if (MicroUtility.GameState.GameState == GameState.FlightView || MicroUtility.GameState.GameState == GameState.VehicleAssemblyBuilder || MicroUtility.GameState.GameState == GameState.Map3DView) - { - MicroUtility.SaveLayout(MicroWindows); - - if (MicroUtility.GameState.GameState == GameState.FlightView || MicroUtility.GameState.GameState == GameState.Map3DView) - _showGuiFlight = false; - - if (MicroUtility.GameState.GameState == GameState.VehicleAssemblyBuilder) - _showGuiOAB = false; - } - } - - #region Data refreshing - /// - /// Refresh all staging data while in OAB - /// - private void RefreshStagingDataOAB(MessageCenterMessage obj) - { - // 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; - - MicroUtility.RefreshGameManager(); - if (MicroUtility.GameState.GameState != GameState.VehicleAssemblyBuilder) return; - - MicroUtility.RefreshStagesOAB(); - - MicroWindow stageWindow = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB); - - if (MicroUtility.VesselDeltaVComponentOAB?.StageInfo == null) - { - stageWindow.Entries.Find(e => e.Name == "Stage Info (OAB)").EntryValue = null; - return; - } - - foreach (var entry in stageWindow.Entries) - entry.RefreshData(); + Logger.LogInfo("Space Warp new version detected. Loading new Styles."); } - + public void Update() { - MicroUtility.RefreshGameManager(); - - - // Perform OAB updates only if we're in OAB - if (MicroUtility.GameState != null && MicroUtility.GameState.IsObjectAssembly) - { - // Do updates every 1 sec - if (Time.time - _lastUpdate > 1) - { - _lastUpdate = Time.time; - - Torque torque = (Torque)MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Torque"); - if (torque.IsActive) - torque.RefreshData(); - } - } - - // Perform flight UI updates only if we're in Flight or Map view - if (MicroUtility.GameState != null && (MicroUtility.GameState.GameState == GameState.FlightView || MicroUtility.GameState.GameState == GameState.Map3DView)) - { - MicroUtility.RefreshActiveVesselAndCurrentManeuver(); - - if (MicroUtility.ActiveVessel == null) - return; - - // Grab all Flight entries from all active windows and refresh their data - foreach (MicroEntry entry in MicroWindows - .Where(w => w.IsFlightActive) - .SelectMany(w => w.Entries ?? Enumerable.Empty()).ToList()) - entry.RefreshData(); - } + _manager?.Update(); } - #endregion private void OnGUI() { - GUI.skin = MicroStyles.SpaceWarpUISkin; - - MicroUtility.RefreshGameManager(); - if (MicroUtility.GameState?.GameState == GameState.VehicleAssemblyBuilder) - OnGUI_OAB(); - else - OnGUI_Flight(); - } - - #region Flight scene UI and logic - private void OnGUI_Flight() - { - _gameInputState = MicroUtility.ToggleGameInputOnControlInFocus(_gameInputState, _showGuiFlight); - - if (!_showGuiFlight || MicroUtility.ActiveVessel == null) return; - - MicroWindow mainGui = MicroWindows.Find(window => window.MainWindow == MainWindow.MainGui); - - // Draw main GUI that contains docked windows - mainGui.FlightRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - mainGui.FlightRect, - FillMainGUI, - "// MICRO ENGINEER", - MicroStyles.MainWindowStyle, - GUILayout.Height(0) - ); - mainGui.FlightRect.position = MicroUtility.ClampToScreen(mainGui.FlightRect.position, mainGui.FlightRect.size); - - // Draw all other popped out windows - foreach (var (window, index) in MicroWindows - .Select((window, index) => (window, index)) - .Where(x => x.window.IsFlightActive && x.window.IsFlightPoppedOut) // must be active & popped out - .Where(x => x.window.MainWindow != MainWindow.Settings && x.window.MainWindow != MainWindow.Stage && x.window.MainWindow != MainWindow.MainGui)) // MainGUI, Settings and Stage are special, they'll be drawn separately - { - // Skip drawing of Target window if there's no active target - if (window.MainWindow == MainWindow.Target && !MicroUtility.TargetExists()) - continue; - - // Skip drawing of Maneuver window if there's no active maneuver - if (window.MainWindow == MainWindow.Maneuver && !MicroUtility.ManeuverExists()) - continue; - - // If window is locked set alpha to 80% - if (window.IsLocked) - GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.8f); - - window.FlightRect = GUILayout.Window( - index, - window.FlightRect, - DrawPopoutWindow, - "", - MicroStyles.PopoutWindowStyle, - GUILayout.Height(0), - GUILayout.Width(MicroStyles.WindowWidth - )); - - // Set alpha back to 100% - if (window.IsLocked) - GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1); - - window.FlightRect.position = MicroUtility.ClampToScreen(window.FlightRect.position, window.FlightRect.size); - } - - // Draw popped out Settings - int settingsIndex = MicroWindows.FindIndex(window => window.MainWindow == MainWindow.Settings); - if (MicroWindows[settingsIndex].IsFlightActive && MicroWindows[settingsIndex].IsFlightPoppedOut) - { - MicroWindows[settingsIndex].FlightRect = GUILayout.Window( - settingsIndex, - MicroWindows[settingsIndex].FlightRect, - DrawSettingsWindow, - "", - MicroStyles.PopoutWindowStyle, - GUILayout.Height(0), - GUILayout.Width(MicroStyles.WindowWidth) - ); - - MicroWindows[settingsIndex].FlightRect.position = MicroUtility.ClampToScreen(MicroWindows[settingsIndex].FlightRect.position, MicroWindows[settingsIndex].FlightRect.size); - } - - // Draw popped out Stages - int stageIndex = MicroWindows.FindIndex(window => window.MainWindow == MainWindow.Stage); - if (MicroWindows[stageIndex].IsFlightActive && MicroWindows[stageIndex].IsFlightPoppedOut) - { - MicroWindows[stageIndex].FlightRect = GUILayout.Window( - stageIndex, - MicroWindows[stageIndex].FlightRect, - DrawStages, - "", - MicroStyles.PopoutWindowStyle, - GUILayout.Height(0), - GUILayout.Width(MicroStyles.WindowWidth) - ); - - MicroWindows[stageIndex].FlightRect.position = MicroUtility.ClampToScreen(MicroWindows[stageIndex].FlightRect.position, MicroWindows[stageIndex].FlightRect.size); - } - - // Draw Edit Window - if (showEditWindow) - { - MicroStyles.EditWindowRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - MicroStyles.EditWindowRect, - DrawEditWindow, - "", - MicroStyles.EditWindowStyle, - GUILayout.Height(0) - ); - } - } - - /// - /// Draws the main GUI with all windows that are toggled and docked - /// - /// - private void FillMainGUI(int windowID) - { - try - { - if (CloseButton(MicroStyles.CloseBtnRect)) - { - CloseWindow(); - } - - GUILayout.Space(5); - - GUILayout.BeginHorizontal(); - - int toggleIndex = -1; - // Draw toggles for all windows except MainGui and StageInfoOAB - foreach (MicroWindow window in MicroWindows.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, MicroStyles.SectionToggleStyle); - } - GUILayout.EndHorizontal(); - GUILayout.Space(5); - - // Draw Settings window first - int settingsIndex = MicroWindows.FindIndex(window => window.MainWindow == MainWindow.Settings); - if (MicroWindows[settingsIndex].IsFlightActive && !MicroWindows[settingsIndex].IsFlightPoppedOut) - DrawSettingsWindow(settingsIndex); - - // Draw Stage window next - int stageIndex = MicroWindows.FindIndex(window => window.MainWindow == MainWindow.Stage); - if (MicroWindows[stageIndex].IsFlightActive && !MicroWindows[stageIndex].IsFlightPoppedOut) - DrawStages(stageIndex); - - // Draw all other windows - foreach (var (window, index) in MicroWindows - .Select((window, index) => (window, index)) - .Where(x => x.window.IsFlightActive && !x.window.IsFlightPoppedOut) // must be active & docked - .Where(x => x.window.MainWindow != MainWindow.Settings && x.window.MainWindow != MainWindow.Stage && x.window.MainWindow != MainWindow.MainGui)) // MainGUI, Settings and Stage are special, they'll be drawn separately - - { - // Skip drawing of Target window if there's no active target - if (window.MainWindow == MainWindow.Target && !MicroUtility.TargetExists()) - continue; - - // Skip drawing of Maneuver window if there's no active maneuver - if (window.MainWindow == MainWindow.Maneuver && !MicroUtility.ManeuverExists()) - continue; - - DrawSectionHeader(window.Name, ref window.IsFlightPoppedOut, window.IsLocked, ""); - - foreach (MicroEntry entry in window.Entries) - DrawEntry(entry.Name, entry.ValueDisplay, entry.Unit); - - DrawSectionEnd(window); - } - - GUI.DragWindow(new Rect(0, 0, MicroStyles.WindowWidth, MicroStyles.WindowHeight)); - - } - catch (Exception ex) - { - Logger.LogError(ex); - } - } - - /// - /// Draws all windows that are toggled and popped out - /// - /// - private void DrawPopoutWindow(int windowIndex) - { - MicroWindow windowToDraw = MicroWindows[windowIndex]; - - DrawSectionHeader(windowToDraw.Name, ref windowToDraw.IsFlightPoppedOut, windowToDraw.IsLocked, ""); - - foreach (MicroEntry entry in windowToDraw.Entries) - DrawEntry(entry.Name, entry.ValueDisplay, entry.Unit); - - DrawSectionEnd(windowToDraw); - } - - private void DrawSettingsWindow(int windowIndex) - { - MicroWindow windowToDraw = MicroWindows[windowIndex]; - - DrawSectionHeader(windowToDraw.Name, ref windowToDraw.IsFlightPoppedOut, windowToDraw.IsLocked, ""); - - GUILayout.Space(10); - GUILayout.BeginHorizontal(); - if (GUILayout.Button("SAVE LAYOUT", MicroStyles.NormalBtnStyle)) - MicroUtility.SaveLayout(MicroWindows); - GUILayout.Space(5); - if (GUILayout.Button("LOAD LAYOUT", MicroStyles.NormalBtnStyle)) - MicroUtility.LoadLayout(MicroWindows); - GUILayout.Space(5); - if (GUILayout.Button("RESET", MicroStyles.NormalBtnStyle)) - ResetLayout(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - if (GUILayout.Button("Edit Windows", MicroStyles.NormalBtnStyle)) - { - showEditWindow = !showEditWindow; - } - GUILayout.EndHorizontal(); - - DrawSectionEnd(windowToDraw); - } - - private void DrawStages(int windowIndex) - { - MicroWindow windowToDraw = MicroWindows[windowIndex]; - - DrawStagesHeader(windowToDraw); - - List stages = (List)windowToDraw.Entries.Find(entry => entry.Name == "Stage Info").EntryValue; - - int stageCount = stages?.Count ?? 0; - if (stages != null && stageCount > 0) - { - float highestTwr = Mathf.Floor(stages.Max(stage => stage.TWRActual)); - int preDecimalDigits = Mathf.FloorToInt(Mathf.Log10(highestTwr)) + 1; - string twrFormatString = "N2"; - - if (preDecimalDigits == 3) - { - twrFormatString = "N1"; - } - else if (preDecimalDigits == 4) - { - twrFormatString = "N0"; - } - - for (int i = stages.Count - 1; i >= 0; i--) - { - - DeltaVStageInfo stageInfo = stages[i]; - if (stageInfo.DeltaVinVac > 0.0001 || stageInfo.DeltaVatASL > 0.0001) - { - int stageNum = stageCount - stageInfo.Stage; - DrawStageEntry(stageNum, stageInfo, twrFormatString); - } - } - } - - DrawSectionEnd(windowToDraw); - } - - private void DrawSectionHeader(string sectionName, ref bool isPopout, bool isLocked, string value = "") - { - GUILayout.BeginHorizontal(); - - // If window is popped out and it's not locked => show the close button. If it's not popped out => show to popup arrow - isPopout = isPopout && !isLocked ? !CloseButton(MicroStyles.CloseBtnRect) : !isPopout ? GUILayout.Button("⇖", MicroStyles.PopoutBtnStyle) : isPopout; - - GUILayout.Label($"{sectionName}"); - GUILayout.FlexibleSpace(); - GUILayout.Label(value, MicroStyles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label("", MicroStyles.UnitLabelStyle); - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterHeader); - } - - private void DrawStagesHeader(MicroWindow stageWindow) - { - GUILayout.BeginHorizontal(); - stageWindow.IsFlightPoppedOut = stageWindow.IsFlightPoppedOut ? !CloseButton(MicroStyles.CloseBtnRect) : GUILayout.Button("⇖", MicroStyles.PopoutBtnStyle); - - GUILayout.Label($"{stageWindow.Name}"); - GUILayout.FlexibleSpace(); - GUILayout.Label("∆v", MicroStyles.TableHeaderLabelStyle); - GUILayout.Space(16); - GUILayout.Label($"TWR", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(40)); - GUILayout.Space(16); - if (stageWindow.IsFlightPoppedOut) - { - GUILayout.Label($"Burn", GUILayout.Width(56)); - } - else - { - GUILayout.Label($"Burn", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(56)); - } - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterHeader); - } - - private void DrawEntry(string entryName, string value, string unit = "") - { - GUILayout.BeginHorizontal(); - GUILayout.Label(entryName, MicroStyles.NameLabelStyle); - GUILayout.FlexibleSpace(); - GUILayout.Label(value, MicroStyles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label(unit, MicroStyles.UnitLabelStyle); - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterEntry); - } - - private void DrawStageEntry(int stageID, DeltaVStageInfo stageInfo, string twrFormatString) - { - GUILayout.BeginHorizontal(); - GUILayout.Label($"{stageID:00.}", MicroStyles.NameLabelStyle, GUILayout.Width(24)); - GUILayout.FlexibleSpace(); - GUILayout.Label($"{stageInfo.DeltaVActual:N0} m/s", MicroStyles.ValueLabelStyle); - GUILayout.Space(16); - GUILayout.Label($"{stageInfo.TWRActual.ToString(twrFormatString)}", MicroStyles.ValueLabelStyle, GUILayout.Width(40)); - GUILayout.Space(16); - string burnTime = MicroUtility.SecondsToTimeString(stageInfo.StageBurnTime, false); - string lastUnit = "s"; - if (burnTime.Contains('h')) - { - burnTime = burnTime.Remove(burnTime.LastIndexOf("{lastUnit}", MicroStyles.ValueLabelStyle, GUILayout.Width(56)); - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterEntry); - } - - private void DrawSectionEnd(MicroWindow window) - { - if (window.IsFlightPoppedOut) - { - if (!window.IsLocked) - GUI.DragWindow(new Rect(0, 0, MicroStyles.WindowWidth, MicroStyles.WindowHeight)); - - GUILayout.Space(MicroStyles.SpacingBelowPopout); - } - else - { - GUILayout.Space(MicroStyles.SpacingAfterSection); - } - } - - /// - /// Window for edditing window contents. Add/Remove/Reorder entries. - /// - /// - private void DrawEditWindow(int windowIndex) - { - List editableWindows = MicroWindows.FindAll(w => w.IsEditable); // Editable windows are all except MainGUI, Settings, Stage and StageInfoOAB - List entriesByCategory = MicroEntries.FindAll(e => e.Category == selectedCategory); // All window stageInfoOabEntries belong to a category, but they can still be placed in any window - - showEditWindow = !CloseButton(MicroStyles.CloseBtnRect); - - #region Selection of window to be edited - GUILayout.BeginHorizontal(); - GUILayout.Label("EDITING WINDOW", MicroStyles.TitleLabelStyle); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("<", MicroStyles.OneCharacterBtnStyle)) - { - selectedWindowId = selectedWindowId > 0 ? selectedWindowId - 1 : editableWindows.Count - 1; - } - GUI.SetNextControlName(MicroUtility.InputDisableWindowAbbreviation); - editableWindows[selectedWindowId].Abbreviation = GUILayout.TextField(editableWindows[selectedWindowId].Abbreviation, MicroStyles.WindowSelectionAbbrevitionTextFieldStyle); - editableWindows[selectedWindowId].Abbreviation = MicroUtility.ValidateAbbreviation(editableWindows[selectedWindowId].Abbreviation); - GUI.SetNextControlName(MicroUtility.InputDisableWindowName); - editableWindows[selectedWindowId].Name = GUILayout.TextField(editableWindows[selectedWindowId].Name, MicroStyles.WindowSelectionTextFieldStyle); - if (GUILayout.Button(">", MicroStyles.OneCharacterBtnStyle)) - { - selectedWindowId = selectedWindowId < editableWindows.Count - 1 ? selectedWindowId + 1 : 0; - } - 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", MicroStyles.NormalBtnStyle)) - { - MicroWindows.Remove(editableWindows[selectedWindowId]); - editableWindows.Remove(editableWindows[selectedWindowId]); - selectedWindowId--; - } - } - if (GUILayout.Button("NEW WINDOW", MicroStyles.NormalBtnStyle)) - CreateCustomWindow(editableWindows); - GUILayout.EndHorizontal(); - - GUILayout.Space(10); - MicroStyles.DrawHorizontalLine(); - GUILayout.Space(10); - - #region Installed entries in the selected window - GUILayout.BeginHorizontal(); - GUILayout.Label("Installed", MicroStyles.NormalLabelStyle); - GUILayout.EndHorizontal(); - - var entries = editableWindows[selectedWindowId].Entries.ToList(); - foreach (var (entry, index) in entries.Select((entry, index) => (entry, index))) - { - GUILayout.BeginHorizontal(); - GUILayout.Label(entry.Name, MicroStyles.NameLabelStyle); - if (GUILayout.Button("↑", MicroStyles.OneCharacterBtnStyle)) - { - if (index > 0) - editableWindows[selectedWindowId].MoveEntryUp(index); - } - if (GUILayout.Button("↓", MicroStyles.OneCharacterBtnStyle)) - { - if (index < editableWindows[selectedWindowId].Entries.Count - 1) - editableWindows[selectedWindowId].MoveEntryDown(index); - } - if (GUILayout.Button("X", MicroStyles.OneCharacterBtnStyle)) - editableWindows[selectedWindowId].RemoveEntry(index); - GUILayout.EndHorizontal(); - } - #endregion - - GUILayout.Space(10); - MicroStyles.DrawHorizontalLine(); - GUILayout.Space(10); - - #region All entries that can be added to any IsEditable window - GUILayout.BeginHorizontal(); - GUILayout.Label("Add", MicroStyles.NormalLabelStyle); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("Category", MicroStyles.NormalLabelStyle); - GUILayout.FlexibleSpace(); - - if (GUILayout.Button("<", MicroStyles.OneCharacterBtnStyle)) - { - selectedCategory = (int)selectedCategory > 0 ? selectedCategory - 1 : Enum.GetValues(typeof(MicroEntryCategory)).Cast().Last(); - } - GUILayout.Label(selectedCategory.ToString(), MicroStyles.NormalCenteredLabelStyle); - if (GUILayout.Button(">", MicroStyles.OneCharacterBtnStyle)) - { - selectedCategory = (int)selectedCategory < (int)Enum.GetValues(typeof(MicroEntryCategory)).Cast().Last() ? selectedCategory + 1 : Enum.GetValues(typeof(MicroEntryCategory)).Cast().First(); - } - GUILayout.EndHorizontal(); - - foreach (var (entry, index) in entriesByCategory.Select((entry, index) => (entry, index))) - { - GUILayout.BeginHorizontal(); - GUILayout.Label(entry.Name, MicroStyles.NameLabelStyle); - if (GUILayout.Button("?", MicroStyles.OneCharacterBtnStyle)) - { - if (!showTooltip.condition) - showTooltip = (true, index); - else - { - if (showTooltip.index != index) - showTooltip = (true, index); - else - showTooltip = (false, index); - } - } - if (GUILayout.Button("+", MicroStyles.OneCharacterBtnStyle)) - { - editableWindows[selectedWindowId].AddEntry(entry); - } - GUILayout.EndHorizontal(); - - if (showTooltip.condition && showTooltip.index == index) - { - GUILayout.BeginHorizontal(); - GUILayout.Label(entry.Description, MicroStyles.BlueLabelStyle); - GUILayout.EndHorizontal(); - } - } - #endregion - - GUI.DragWindow(new Rect(0, 0, MicroStyles.WindowWidth, MicroStyles.WindowHeight)); - } - - /// - /// Creates a new custom window user can fill with any entry - /// - /// - private void CreateCustomWindow(List editableWindows) - { - // Default window's name will be CustomX where X represents the first not used integer - int nameID = 1; - foreach (MicroWindow window in editableWindows) - { - if (window.Name == "Custom" + nameID) - nameID++; - } - - MicroWindow newWindow = new MicroWindow() - { - Name = "Custom" + nameID, - Abbreviation = nameID.ToString().Length == 1 ? "Cu" + nameID : nameID.ToString().Length == 2 ? "C" + nameID : nameID.ToString(), - Description = "", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.None, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = new List() - }; - - MicroWindows.Add(newWindow); - editableWindows.Add(newWindow); - - selectedWindowId = editableWindows.Count - 1; - } - - private void ResetLayout() - { - InitializeWindows(); - } - - private void CloseWindow() - { - GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(false); - _showGuiFlight = false; - } - - #endregion - - #region OAB scene UI and logic - private void OnGUI_OAB() - { - if (!_showGuiOAB) return; - - MicroWindow stageInfoOAB = MicroWindows.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, - "", - MicroStyles.StageOABWindowStyle, - GUILayout.Height(0) - ); - stageInfoOAB.EditorRect.position = MicroUtility.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 = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB).EditorRect; - Rect celestialBodyRect = new Rect(stageInfoOabRect.x + stageInfoOabRect.width, stageInfoOabRect.y, 0, 0); - - celestialBodyRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - celestialBodyRect, - DrawCelestialBodySelection, - "", - MicroStyles.CelestialSelectionStyle, - GUILayout.Height(0) - ); - } - - // Draw Settings window for the StageInfoOAB - if(_showGuiSettingsOAB) - { - Rect stageInfoOabRect = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB).EditorRect; - Rect settingsRect = new Rect(stageInfoOabRect.x + stageInfoOabRect.width, stageInfoOabRect.y, 0, 0); - - settingsRect = GUILayout.Window( - GUIUtility.GetControlID(FocusType.Passive), - settingsRect, - DrawSettingsOabWindow, - "", - MicroStyles.SettingsOabStyle, - GUILayout.Height(0) - ); - } - } - - private void DrawStageInfoOAB(int windowID) - { - MicroWindow stageInfoOabWindow = MicroWindows.Find(w => w.MainWindow == MainWindow.StageInfoOAB); - List stageInfoOabEntries = stageInfoOabWindow.Entries; - - GUILayout.BeginHorizontal(); - if (SettingsButton(MicroStyles.SettingsOABRect)) - _showGuiSettingsOAB = !_showGuiSettingsOAB; - - if (CloseButton(MicroStyles.CloseBtnStagesOABRect)) - { - stageInfoOabWindow.IsEditorActive = false; - _showGuiOAB = false; - } - GUILayout.Label($"Stage Info"); - GUILayout.EndHorizontal(); - - // Draw StageInfo header - Delta V fields - GUILayout.BeginHorizontal(); - GUILayout.Label("Total ∆v (ASL, vacuum)", MicroStyles.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}", MicroStyles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label("m/s", MicroStyles.UnitLabelStyle); - GUILayout.EndHorizontal(); - - // Draw Torque - Torque torque = (Torque)stageInfoOabEntries.Find(e => e.Name == "Torque"); - if (torque.IsActive) - { - GUILayout.Space(MicroStyles.SpacingAfterEntry); - GUILayout.BeginHorizontal(); - GUILayout.Label("Torque", MicroStyles.NameLabelStyle); - GUILayout.FlexibleSpace(); - GUILayout.Label(torque.ValueDisplay, MicroStyles.ValueLabelStyle); - GUILayout.Space(5); - GUILayout.Label(torque.Unit, MicroStyles.UnitLabelStyle); - GUILayout.EndHorizontal(); - } - - // Draw Stage table header - GUILayout.BeginHorizontal(); - GUILayout.Label("Stage", MicroStyles.NameLabelStyle, GUILayout.Width(40)); - GUILayout.FlexibleSpace(); - GUILayout.Label("TWR", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(65)); - GUILayout.Label("SLT", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(30)); - GUILayout.Label("ASL ∆v", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(30)); - GUILayout.Label("Vac ∆v", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(75)); - GUILayout.Label("Burn Time", MicroStyles.TableHeaderLabelStyle, GUILayout.Width(110)); - GUILayout.Space(20); - GUILayout.Label("Body", MicroStyles.TableHeaderCenteredLabelStyle, GUILayout.Width(80)); - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterEntry); - - 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), MicroStyles.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), MicroStyles.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), MicroStyles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label(String.Format("{0:N0}", stages[stageIndex].GetDeltaVelAtSeaLevel(cel)), MicroStyles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label("m/s", MicroStyles.UnitLabelStyleStageOAB, GUILayout.Width(30)); - - GUILayout.Label(String.Format("{0:N0}", stages[stageIndex].DeltaVVac), MicroStyles.ValueLabelStyle, GUILayout.Width(75)); - GUILayout.Label("m/s", MicroStyles.UnitLabelStyleStageOAB, GUILayout.Width(30)); - GUILayout.Label(MicroUtility.SecondsToTimeString(stages[stageIndex].StageBurnTime, true, true), MicroStyles.ValueLabelStyle, GUILayout.Width(110)); - GUILayout.Space(20); - GUILayout.BeginVertical(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button(stageInfoOab.CelestialBodyForStage[celestialIndex], MicroStyles.CelestialBodyBtnStyle)) - { - _celestialBodySelectionStageIndex = celestialIndex; - } - GUILayout.EndVertical(); - GUILayout.EndHorizontal(); - GUILayout.Space(MicroStyles.SpacingAfterEntry); - } - - GUILayout.Space(MicroStyles.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, MicroStyles.CelestialSelectionBtnStyle)) - { - StageInfo_OAB stageInfoOab = (StageInfo_OAB)MicroWindows.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) - { - if (CloseButton(MicroStyles.CloseBtnSettingsOABRect)) - _showGuiSettingsOAB = false; - - MicroWindow stageInfoOabWindow = MicroWindows.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", MicroStyles.SectionToggleStyle); - } - #endregion - - /// - /// Draws a close button (X) - /// - /// Where to position the close button - /// - private bool CloseButton(Rect rect) - { - return GUI.Button(rect, "X", MicroStyles.CloseBtnStyle); - } - - /// - /// Draws a Settings butoon (≡) - /// - /// - /// - private bool SettingsButton(Rect rect) - { - return GUI.Button(rect, "≡", MicroStyles.SettingsBtnStyle); - } - - #region Window and data initialization - /// - /// Builds the list of all Entries - /// - private void InitializeEntries() - { - MicroEntries = new List(); - - #region Vessel entries - MicroEntries.Add(new Vessel()); - MicroEntries.Add(new Mass()); - MicroEntries.Add(new DeltaV()); - MicroEntries.Add(new Thrust()); - MicroEntries.Add(new TWR()); - #endregion - #region Orbital entries - MicroEntries.Add(new Apoapsis()); - MicroEntries.Add(new TimeToApoapsis()); - MicroEntries.Add(new Periapsis()); - MicroEntries.Add(new TimeToPeriapsis()); - MicroEntries.Add(new Inclination()); - MicroEntries.Add(new Eccentricity()); - MicroEntries.Add(new Period()); - MicroEntries.Add(new SoiTransition()); - #endregion - #region Surface entries - MicroEntries.Add(new Body()); - MicroEntries.Add(new Situation()); - MicroEntries.Add(new Latitude()); - MicroEntries.Add(new Longitude()); - MicroEntries.Add(new Biome()); - MicroEntries.Add(new AltitudeAsl()); - MicroEntries.Add(new AltitudeAgl()); - MicroEntries.Add(new HorizontalVelocity()); - MicroEntries.Add(new VerticalVelocity()); - #endregion - #region Flight entries - MicroEntries.Add(new Speed()); - MicroEntries.Add(new MachNumber()); - MicroEntries.Add(new AtmosphericDensity()); - MicroEntries.Add(new TotalLift()); - MicroEntries.Add(new TotalDrag()); - MicroEntries.Add(new LiftDivDrag()); - #endregion - #region Flight entries - MicroEntries.Add(new TargetApoapsis()); - MicroEntries.Add(new TargetPeriapsis()); - MicroEntries.Add(new DistanceToTarget()); - MicroEntries.Add(new RelativeSpeed()); - MicroEntries.Add(new RelativeInclination()); - #endregion - #region Maneuver entries - MicroEntries.Add(new ProjectedAp()); - MicroEntries.Add(new ProjectedPe()); - MicroEntries.Add(new DeltaVRequired()); - MicroEntries.Add(new TimeToNode()); - MicroEntries.Add(new BurnTime()); - #endregion - #region Stage entries - MicroEntries.Add(new TotalDeltaVVac()); - MicroEntries.Add(new TotalDeltaVAsl()); - MicroEntries.Add(new TotalDeltaVActual()); - MicroEntries.Add(new StageInfo()); - #endregion - #region Misc entries - MicroEntries.Add(new Separator()); - #endregion - #region OAB entries - MicroEntries.Add(new TotalBurnTime_OAB()); - MicroEntries.Add(new TotalDeltaVASL_OAB()); - MicroEntries.Add(new TotalDeltaVActual_OAB()); - MicroEntries.Add(new TotalDeltaVVac_OAB()); - MicroEntries.Add(new Torque()); - MicroEntries.Add(new StageInfo_OAB()); - #endregion - } - - /// - /// Builds the default Windows and fills them with default Entries - /// - private void InitializeWindows() - { - MicroWindows = new List(); - - try - { - MicroWindows.Add(new MicroWindow - { - Name = "MainGui", - Abbreviation = null, - Description = "Main GUI", - IsEditorActive = false, - IsFlightActive = false, - IsMapActive = false, - IsEditorPoppedOut = false, // not relevant to Main GUI - IsFlightPoppedOut = false, // not relevant to Main GUI - IsMapPoppedOut = false, // not relevant to Main GUI - IsLocked = false, - MainWindow = MainWindow.MainGui, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.MainGuiX, MicroStyles.MainGuiY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = null - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Settings", - Abbreviation = "SET", - Description = "Settings", - IsEditorActive = false, - IsFlightActive = false, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Settings, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = null - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Vessel", - Abbreviation = "VES", - Description = "Vessel entries", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Vessel, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Vessel).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Orbital", - Abbreviation = "ORB", - Description = "Orbital entries", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Orbital, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Orbital).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Surface", - Abbreviation = "SUR", - Description = "Surface entries", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Surface, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Surface).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Flight", - Abbreviation = "FLT", - Description = "Flight entries", - IsEditorActive = false, - IsFlightActive = false, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Flight, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Flight).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Target", - Abbreviation = "TGT", - Description = "Flight entries", - IsEditorActive = false, - IsFlightActive = false, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Target, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Target).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Maneuver", - Abbreviation = "MAN", - Description = "Maneuver entries", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Maneuver, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Maneuver).ToList() - }); - - MicroWindows.Add(new MicroWindow - { - Name = "Stage", - Abbreviation = "STG", - Description = "Stage entries", - IsEditorActive = false, - IsFlightActive = true, - IsMapActive = false, - IsEditorPoppedOut = false, - IsFlightPoppedOut = false, - IsMapPoppedOut = false, - IsLocked = false, - MainWindow = MainWindow.Stage, - //EditorRect = null, - FlightRect = new Rect(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, MicroStyles.WindowWidth, MicroStyles.WindowHeight), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.Stage).ToList() - }); - - InitializeStageInfoOABWindow(); - } - catch (Exception ex) - { - Logger.LogError("Error creating a MicroWindow. Full exception: " + ex); - } - } - - private void InitializeStageInfoOABWindow() - { - MicroWindows.Add(new MicroWindow - { - Name = "Stage (OAB)", - Abbreviation = "SOAB", - Description = "Stage Info window for OAB", - IsEditorActive = false, - 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(MicroStyles.PoppedOutX, MicroStyles.PoppedOutY, 0, 0), - Entries = Enumerable.Where(MicroEntries, entry => entry.Category == MicroEntryCategory.OAB).ToList() - }); - } - - private void InitializeCelestialBodies() - { - if (_celestialBodies.Bodies.Count > 0) - return; - - _celestialBodies.GetBodies(); + _ui?.OnGUI(); } - #endregion } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroEntries.cs b/MicroEngineerProject/MicroEngineer/MicroEntries.cs deleted file mode 100644 index d6c25a6..0000000 --- a/MicroEngineerProject/MicroEngineer/MicroEntries.cs +++ /dev/null @@ -1,1538 +0,0 @@ -using KSP.Game; -using KSP.Sim.DeltaV; -using KSP.Sim.impl; -using Newtonsoft.Json; -using static KSP.Rendering.Planets.PQSData; - -namespace MicroMod -{ - /// - /// Base class for all Entries (values that can be attached to windows) - /// - [JsonObject(MemberSerialization.OptIn)] - public class MicroEntry - { - [JsonProperty] - public string Name; - [JsonProperty] - public string Description; - [JsonProperty] - public MicroEntryCategory Category; - [JsonProperty] - public string Unit; - [JsonProperty] - public string Formatting; - - public virtual object EntryValue { get; set; } - - /// - /// Controls how the value should be displayed. Should be overriden in a inheritet class for a concrete implementation. - /// - public virtual string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - - public virtual void RefreshData() { } - } - - #region Flight scene entries - public class Vessel : MicroEntry - { - public Vessel() - { - Name = "Vessel"; - Description = "Name of the current vessel."; - Category = MicroEntryCategory.Vessel; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.DisplayName; - } - - public override string ValueDisplay => EntryValue?.ToString(); - } - - public class Mass : MicroEntry - { - public Mass() - { - Name = "Mass"; - Description = "Shows the total mass of the vessel."; - Category = MicroEntryCategory.Vessel; - Unit = "kg"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.totalMass * 1000; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class DeltaV : MicroEntry - { - public DeltaV() - { - Name = "∆v"; - Description = "Shows the vessel's total delta velocity."; - Category = MicroEntryCategory.Vessel; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.TotalDeltaVActual; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Thrust : MicroEntry - { - public Thrust() - { - Name = "Thrust"; - Description = "Shows the vessel's actual thrust."; - Category = MicroEntryCategory.Vessel; - Unit = "N"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.StageInfo.FirstOrDefault()?.ThrustActual * 1000; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class TWR : MicroEntry - { - public TWR() - { - Name = "TWR"; - Description = "Shows the vessel's Thrust to Weight Ratio."; - Category = MicroEntryCategory.Vessel; - Unit = null; - Formatting = "{0:N2}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.StageInfo.FirstOrDefault()?.TWRActual; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Apoapsis : MicroEntry - { - public Apoapsis() - { - Name = "Apoapsis"; - Description = "Vessel's apoapsis height relative to the sea level. Apoapsis is the highest point of an orbit."; - Category = MicroEntryCategory.Orbital; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.ApoapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class TimeToApoapsis : MicroEntry - { - public TimeToApoapsis() - { - Name = "Time to Ap."; - Description = "Shows the time until the vessel reaches apoapsis, the highest point of the orbit."; - Category = MicroEntryCategory.Orbital; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = (MicroUtility.ActiveVessel.Situation == VesselSituations.Landed || MicroUtility.ActiveVessel.Situation == VesselSituations.PreLaunch) ? 0f : MicroUtility.ActiveVessel.Orbit.TimeToAp; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SecondsToTimeString((double)EntryValue); - } - } - } - - public class Periapsis : MicroEntry - { - public Periapsis() - { - Name = "Periapsis"; - Description = "Vessel's periapsis height relative to the sea level. Periapsis is the lowest point of an orbit."; - Category = MicroEntryCategory.Orbital; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.PeriapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class TimeToPeriapsis : MicroEntry - { - public TimeToPeriapsis() - { - Name = "Time to Pe."; - Description = "Shows the time until the vessel reaches periapsis, the lowest point of the orbit."; - Category = MicroEntryCategory.Orbital; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = EntryValue = MicroUtility.ActiveVessel.Orbit.TimeToPe; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SecondsToTimeString((double)EntryValue); - } - } - } - - public class Inclination : MicroEntry - { - public Inclination() - { - Name = "Inclination"; - Description = "Shows the vessel's orbital inclination relative to the equator."; - Category = MicroEntryCategory.Orbital; - Unit = "°"; - Formatting = "{0:N3}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.inclination; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Eccentricity : MicroEntry - { - public Eccentricity() - { - Name = "Eccentricity"; - Description = "Shows the vessel's orbital eccentricity which is a measure of how much an elliptical orbit is 'squashed'."; - Category = MicroEntryCategory.Orbital; - Unit = null; - Formatting = "{0:N3}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.eccentricity; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Period : MicroEntry - { - public Period() - { - Name = "Period"; - Description = "Shows the amount of time it will take to complete a full orbit."; - Category = MicroEntryCategory.Orbital; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.period; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SecondsToTimeString((double)EntryValue); - } - } - } - - public class SoiTransition : MicroEntry - { - public SoiTransition() - { - Name = "SOI Trans."; - Description = "Shows the amount of time it will take to transition to another Sphere of Influence."; - Category = MicroEntryCategory.Orbital; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbit.UniversalTimeAtSoiEncounter - GameManager.Instance.Game.UniverseModel.UniversalTime; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return (double)EntryValue >= 0 ? MicroUtility.SecondsToTimeString((double)EntryValue) : "-"; - } - } - } - - public class Body : MicroEntry - { - public Body() - { - Name = "Body"; - Description = "Shows the body that vessel is currently at."; - Category = MicroEntryCategory.Surface; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.mainBody.bodyName; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Situation : MicroEntry - { - public Situation() - { - Name = "Situation"; - Description = "Shows the vessel's current situation: Landed, Flying, Orbiting, etc."; - Category = MicroEntryCategory.Surface; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Situation; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SituationToString((VesselSituations)EntryValue); - } - } - } - - public class Latitude : MicroEntry - { - 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."; - Category = MicroEntryCategory.Surface; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Latitude; - Unit = MicroUtility.ActiveVessel.Latitude < 0 ? "S" : "N"; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.DegreesToDMS((double)EntryValue); - } - } - } - - public class Longitude : MicroEntry - { - 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."; - Category = MicroEntryCategory.Surface; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Longitude; - Unit = MicroUtility.ActiveVessel.Longitude < 0 ? "W" : "E"; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.DegreesToDMS((double)EntryValue); - } - } - } - - public class Biome : MicroEntry - { - public Biome() - { - Name = "Biome"; - Description = "Shows the biome currently below the vessel."; - Category = MicroEntryCategory.Surface; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.SimulationObject.Telemetry.SurfaceBiome; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.BiomeToString((BiomeSurfaceData)EntryValue); - } - } - } - - public class AltitudeAsl : MicroEntry - { - public AltitudeAsl() - { - Name = "Altitude (ASL)"; - Description = "Shows the vessel's altitude Above Sea Level"; - Category = MicroEntryCategory.Surface; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.AltitudeFromSeaLevel; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class AltitudeAgl : MicroEntry - { - public AltitudeAgl() - { - Name = "Altitude (AGL)"; - Description = "Shows the vessel's altitude Above Ground Level"; - Category = MicroEntryCategory.Surface; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.AltitudeFromTerrain; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class HorizontalVelocity : MicroEntry - { - public HorizontalVelocity() - { - Name = "Horizontal Vel."; - Description = "Shows the vessel's horizontal velocity across a celestial body's surface."; - Category = MicroEntryCategory.Surface; - Unit = "m/s"; - Formatting = "{0:N1}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.HorizontalSrfSpeed; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class VerticalVelocity : MicroEntry - { - public VerticalVelocity() - { - Name = "Vertical Vel."; - Description = "Shows the vessel's vertical velocity (up/down)."; - Category = MicroEntryCategory.Surface; - Unit = "m/s"; - Formatting = "{0:N1}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VerticalSrfSpeed; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class Speed : MicroEntry - { - public Speed() - { - Name = "Speed"; - Description = "Shows the vessel's total velocity."; - Category = MicroEntryCategory.Flight; - Unit = "m/s"; - Formatting = "{0:N1}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.SurfaceVelocity.magnitude; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class MachNumber : MicroEntry - { - public MachNumber() - { - Name = "Mach Number"; - Description = "Shows the ratio of vessel's speed and local speed of sound."; - Category = MicroEntryCategory.Flight; - Unit = null; - Formatting = "{0:N2}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.SimulationObject.Telemetry.MachNumber; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class AtmosphericDensity : MicroEntry - { - public AtmosphericDensity() - { - Name = "Atm. Density"; - Description = "Shows the atmospheric density."; - Category = MicroEntryCategory.Flight; - Unit = "g/L"; - Formatting = "{0:N3}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.SimulationObject.Telemetry.AtmosphericDensity; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class TotalLift : MicroEntry - { - public TotalLift() - { - Name = "Total Lift"; - Description = "Shows the total lift force produced by the vessel."; - Category = MicroEntryCategory.Flight; - Unit = "N"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = AeroForces.TotalLift; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - double toReturn = (double)EntryValue * 1000; - return String.IsNullOrEmpty(base.Formatting) ? toReturn.ToString() : String.Format(base.Formatting, toReturn); - } - } - } - - public class TotalDrag : MicroEntry - { - public TotalDrag() - { - Name = "Total Drag"; - Description = "Shows the total drag force exerted on the vessel."; - Category = MicroEntryCategory.Flight; - Unit = "N"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = AeroForces.TotalDrag; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - double toReturn = (double)EntryValue * 1000; - return String.IsNullOrEmpty(base.Formatting) ? toReturn.ToString() : String.Format(base.Formatting, toReturn); - } - } - } - - public class LiftDivDrag : MicroEntry - { - public LiftDivDrag() - { - Name = "Lift / Drag"; - Description = "Shows the ratio of total lift and drag forces."; - Category = MicroEntryCategory.Flight; - Unit = null; - Formatting = "{0:N3}"; - } - - public override void RefreshData() - { - EntryValue = AeroForces.TotalLift / AeroForces.TotalDrag; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - double toReturn = (double)EntryValue * 1000; - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class TargetApoapsis : MicroEntry - { - public TargetApoapsis() - { - Name = "Target Ap."; - Description = "Shows the target's apoapsis height relative to the sea level."; - Category = MicroEntryCategory.Target; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.TargetObject?.Orbit?.ApoapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class TargetPeriapsis : MicroEntry - { - public TargetPeriapsis() - { - Name = "Target Pe."; - Description = "Shows the target's periapsis height relative to the sea level."; - Category = MicroEntryCategory.Target; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.TargetObject?.Orbit?.PeriapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class DistanceToTarget : MicroEntry - { - public DistanceToTarget() - { - Name = "Distance to Target"; - Description = "Shows the current distance between the vessel and the target."; - Category = MicroEntryCategory.Target; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.TargetObject?.Orbit != null ? (MicroUtility.ActiveVessel.Orbit.Position - MicroUtility.ActiveVessel.TargetObject.Orbit.Position).magnitude : null; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - // return value only if vessel and target are in the same SOI - return MicroUtility.ActiveVessel.Orbit.referenceBody == MicroUtility.ActiveVessel.TargetObject.Orbit.referenceBody ? - MicroUtility.MetersToDistanceString((double)EntryValue) : "-"; - } - } - } - - public class RelativeSpeed : MicroEntry - { - public RelativeSpeed() - { - Name = "Rel. Speed"; - Description = "Shows the relative velocity between the vessel and the target."; - Category = MicroEntryCategory.Target; - Unit = "m/s"; - Formatting = "{0:N1}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.TargetObject?.Orbit != null ? (MicroUtility.ActiveVessel.Orbit.relativeVelocity - MicroUtility.ActiveVessel.TargetObject.Orbit.relativeVelocity).magnitude : null; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - // return value only if vessel and target are in the same SOI - if (MicroUtility.ActiveVessel.Orbit.referenceBody != MicroUtility.ActiveVessel.TargetObject.Orbit.referenceBody) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class RelativeInclination : MicroEntry - { - public RelativeInclination() - { - Name = "Rel. Inclination"; - Description = "Shows the relative inclination between the vessel and the target."; - Category = MicroEntryCategory.Target; - Unit = "°"; - Formatting = "{0:N3}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbiter?.OrbitTargeter?.AscendingNodeTarget.Inclination; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - // return value only if vessel and target are in the same SOI - if (MicroUtility.ActiveVessel.Orbit.referenceBody != MicroUtility.ActiveVessel.TargetObject?.Orbit?.referenceBody) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class ProjectedAp : MicroEntry - { - public ProjectedAp() - { - Name = "Projected Ap."; - Description = "Shows the projected apoapsis vessel will have after completing the maneuver."; - Category = MicroEntryCategory.Maneuver; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList.FirstOrDefault().ApoapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class ProjectedPe : MicroEntry - { - public ProjectedPe() - { - Name = "Projected Pe."; - Description = "Shows the projected periapsis vessel will have after completing the maneuver."; - Category = MicroEntryCategory.Maneuver; - Unit = "m"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.Orbiter?.ManeuverPlanSolver?.PatchedConicsList.FirstOrDefault().PeriapsisArl; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.MetersToDistanceString((double)EntryValue); - } - } - } - - public class DeltaVRequired : MicroEntry - { - public DeltaVRequired() - { - Name = "∆v required"; - Description = "Shows the delta velocity needed to complete the maneuver."; - Category = MicroEntryCategory.Maneuver; - Unit = "m/s"; - Formatting = "{0:N1}"; - } - - public override void RefreshData() - { - EntryValue = (MicroUtility.ActiveVessel.Orbiter.ManeuverPlanSolver.GetVelocityAfterFirstManeuver(out double ut).vector - MicroUtility.ActiveVessel.Orbit.GetOrbitalVelocityAtUTZup(ut)).magnitude; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class TimeToNode : MicroEntry - { - public TimeToNode() - { - Name = "Time to Node"; - Description = "Shows the time until vessel reaches the maneuver node."; - Category = MicroEntryCategory.Maneuver; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.CurrentManeuver != null ? MicroUtility.CurrentManeuver.Time - GameManager.Instance.Game.UniverseModel.UniversalTime : null; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SecondsToTimeString((double)EntryValue); - } - } - } - - public class BurnTime : MicroEntry - { - public BurnTime() - { - Name = "Burn Time"; - Description = "Shows the length of time needed to complete the maneuver node."; - Category = MicroEntryCategory.Maneuver; - Unit = "s"; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.CurrentManeuver?.BurnDuration; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return MicroUtility.SecondsToTimeString((double)EntryValue); - } - } - } - - public class TotalDeltaVVac : MicroEntry - { - public TotalDeltaVVac() - { - Name = "Total ∆v Vac"; - Description = "Shows the total delta velocity of the vessel in vacuum."; - Category = MicroEntryCategory.Stage; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.TotalDeltaVVac; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class TotalDeltaVAsl : MicroEntry - { - public TotalDeltaVAsl() - { - Name = "Total ∆v ASL"; - Description = "Shows the total delta velocity of the vessel At Sea Level."; - Category = MicroEntryCategory.Stage; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.TotalDeltaVASL; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class TotalDeltaVActual : MicroEntry - { - public TotalDeltaVActual() - { - Name = "Total ∆v Actual"; - Description = "Shows the current total delta velocity."; - Category = MicroEntryCategory.Stage; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.TotalDeltaVActual; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class StageInfo : MicroEntry - { - public StageInfo() - { - Name = "Stage Info"; - Description = "Stage Info object, not implemented yet."; // TODO Stage Info display and description - Category = MicroEntryCategory.Stage; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.ActiveVessel.VesselDeltaV?.StageInfo; - } - - public override string ValueDisplay - { - get - { - //TODO: stageinfo display - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(base.Formatting) ? EntryValue.ToString() : String.Format(base.Formatting, EntryValue); - } - } - } - - public class Separator : MicroEntry - { - public Separator() - { - Name = "--------------"; - Description = "It's a separator!"; - Category = MicroEntryCategory.Misc; - Unit = "---"; - Formatting = null; - EntryValue = "---------------"; - } - } - #endregion - - #region OAB scene entries - public class TotalBurnTime_OAB : MicroEntry - { - public bool UseDHMSFormatting; // TODO: implement - - public TotalBurnTime_OAB() - { - Name = "Total Burn Time (OAB)"; - Description = "Shows the total length of burn the vessel can mantain."; - Category = MicroEntryCategory.OAB; - Unit = "s"; - Formatting = "{0:N1}"; - UseDHMSFormatting = true; - } - - public override void RefreshData() - { - EntryValue = MicroUtility.VesselDeltaVComponentOAB?.TotalBurnTime; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - if (UseDHMSFormatting) - return MicroUtility.SecondsToTimeString((double)EntryValue); - else - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class TotalDeltaVASL_OAB : MicroEntry - { - public TotalDeltaVASL_OAB() - { - Name = "Total ∆v ASL (OAB)"; - Description = "Shows the vessel's total delta velocity At Sea Level."; - Category = MicroEntryCategory.OAB; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - public override void RefreshData() - { - EntryValue = MicroUtility.VesselDeltaVComponentOAB?.TotalDeltaVASL; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class TotalDeltaVActual_OAB : MicroEntry - { - public TotalDeltaVActual_OAB() - { - Name = "Total ∆v Actual (OAB)"; - Description = "Shows the vessel's actual total delta velocity (not used in OAB)."; - Category = MicroEntryCategory.OAB; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - public override void RefreshData() - { - EntryValue = MicroUtility.VesselDeltaVComponentOAB?.TotalDeltaVActual; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - public class TotalDeltaVVac_OAB : MicroEntry - { - public TotalDeltaVVac_OAB() - { - Name = "Total ∆v Vac (OAB)"; - Description = "Shows the vessel's total delta velocity in Vacuum."; - Category = MicroEntryCategory.OAB; - Unit = "m/s"; - Formatting = "{0:N0}"; - } - public override void RefreshData() - { - EntryValue = MicroUtility.VesselDeltaVComponentOAB?.TotalDeltaVVac; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null) - return "-"; - - return String.IsNullOrEmpty(this.Formatting) ? EntryValue.ToString() : String.Format(Formatting, EntryValue); - } - } - } - - /// - /// Calculates torque from the Center of Thrust and Center of Mass - /// - public class Torque : MicroEntry - { - [JsonProperty] - internal bool IsActive = false; - - public Torque() - { - Name = "Torque"; - Description = "Thrust torque that is generated by not having Thrust Vector and Center of Mass aligned. Turn on the Center of Thrust and Center of Mass VAB indicators to get an accurate value."; - Category = MicroEntryCategory.OAB; - Unit = null; - Formatting = null; - } - - 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; - - if (com == Vector3d.zero || cot == Vector3d.zero) - return; - - List engines = GameManager.Instance?.Game?.OAB?.Current?.Stats?.MainAssembly?.VesselDeltaV?.EngineInfo; - if (engines == null || engines.Count == 0) - return; - - Vector3d force = new Vector3d(); - - foreach (var engine in engines) - { - force += engine.ThrustVectorVac; - } - - var leverArm = cot - com; - - Vector3d torque = Vector3d.Cross(force, (Vector3d)leverArm); - - this.EntryValue = torque.magnitude; - this.Unit = (double)EntryValue >= 1.0 ? "kNm" : "Nm"; - } - - public override string ValueDisplay - { - get - { - if (EntryValue == null || !this.IsActive) - return "-"; - - if ((double)EntryValue >= 1.0) - return $"{String.Format("{0:F2}", EntryValue)}"; - - return Math.Abs((double)EntryValue) > double.Epsilon ? $"{String.Format("{0:F2}", (double)EntryValue * 1000.0)}" : $"{String.Format("{0:F0}", (double)EntryValue)}"; - } - } - } - - /// - /// Holds stage info parameters for each stage. Also keeps information about the celestial body user selected in the window. - /// - public class StageInfo_OAB : MicroEntry - { - public List CelestialBodyForStage = new(); - - public StageInfo_OAB() - { - Name = "Stage Info (OAB)"; - Description = "Holds a list of stage info parameters."; - Category = MicroEntryCategory.OAB; - Unit = null; - Formatting = null; - } - - public override void RefreshData() - { - EntryValue ??= new List(); - - ((List)EntryValue).Clear(); - - if (MicroUtility.VesselDeltaVComponentOAB?.StageInfo == null) return; - - foreach (var stage in MicroUtility.VesselDeltaVComponentOAB.StageInfo) - { - ((List)EntryValue).Add(new DeltaVStageInfo_OAB - { - 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 - }); - } - } - - public override string ValueDisplay - { - get - { - return "-"; - } - } - - /// - /// Adds a new string to the CelestialBodyForStage list that corresponds to the HomeWorld, i.e. Kerbin - /// - /// - internal void AddNewCelestialBody(MicroCelestialBodies celestialBodies) - { - this.CelestialBodyForStage.Add(celestialBodies.Bodies.Find(b => b.IsHomeWorld).Name); - } - } - - /// - /// Parameters for one stage - /// - internal 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; - - 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) - { - float sum = 0; - foreach (DeltaVEngineInfo engInfo in this.DeltaVStageInfo.EnginesActiveInStage) - sum += engInfo.Engine.MaxThrustOutputAtm(atmPressure: cel.GetPressure(altitude) / 101.325) / - engInfo.Engine.currentEngineModeData.atmosphereCurve.Evaluate((float)cel.GetPressure(altitude) / 101.325f); - return GetThrustAtAltitude(altitude, cel) / sum; - } - 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); - } - #endregion -} diff --git a/MicroEngineerProject/MicroEngineer/MicroStyles.cs b/MicroEngineerProject/MicroEngineer/MicroStyles.cs deleted file mode 100644 index 443ea23..0000000 --- a/MicroEngineerProject/MicroEngineer/MicroStyles.cs +++ /dev/null @@ -1,248 +0,0 @@ -using SpaceWarp.API.UI; -using UnityEngine; - -namespace MicroMod -{ - public static class MicroStyles - { - public static int WindowWidth = 290; - public static int WindowHeight = 1440; - public static int WindowWidthStageOAB = 645; - public static int WindowWidthSettingsOAB = 300; - - public static GUISkin SpaceWarpUISkin; - public static GUIStyle MainWindowStyle; - public static GUIStyle PopoutWindowStyle; - public static GUIStyle EditWindowStyle; - public static GUIStyle StageOABWindowStyle; - public static GUIStyle CelestialSelectionStyle; - public static GUIStyle SettingsOabStyle; - public static GUIStyle PopoutBtnStyle; - public static GUIStyle SectionToggleStyle; - public static GUIStyle NameLabelStyle; - public static GUIStyle ValueLabelStyle; - public static GUIStyle BlueLabelStyle; - public static GUIStyle UnitLabelStyle; - public static GUIStyle UnitLabelStyleStageOAB; - public static GUIStyle NormalLabelStyle; - public static GUIStyle TitleLabelStyle; - public static GUIStyle NormalCenteredLabelStyle; - public static GUIStyle WindowSelectionTextFieldStyle; - public static GUIStyle WindowSelectionAbbrevitionTextFieldStyle; - public static GUIStyle CloseBtnStyle; - public static GUIStyle SettingsBtnStyle; - public static GUIStyle CloseBtnStageOABStyle; - public static GUIStyle NormalBtnStyle; - public static GUIStyle CelestialBodyBtnStyle; - public static GUIStyle CelestialSelectionBtnStyle; - public static GUIStyle OneCharacterBtnStyle; - public static GUIStyle TableHeaderLabelStyle; - public static GUIStyle TableHeaderCenteredLabelStyle; - - public static string UnitColorHex { get => ColorUtility.ToHtmlStringRGBA(UnitLabelStyle.normal.textColor); } - - public static int SpacingAfterHeader = -12; - public static int SpacingAfterEntry = -12; - public static int SpacingAfterSection = 5; - public static float SpacingBelowPopout = 10; - - public static float PoppedOutX = Screen.width * 0.6f; - public static float PoppedOutY = Screen.height * 0.2f; - public static float MainGuiX = Screen.width * 0.8f; - public static float MainGuiY = Screen.height * 0.2f; - - public static Rect CloseBtnRect = new Rect(MicroStyles.WindowWidth - 23, 6, 16, 16); - public static Rect CloseBtnStagesOABRect = new Rect(MicroStyles.WindowWidthStageOAB - 23, 6, 16, 16); - public static Rect CloseBtnSettingsOABRect = new Rect(MicroStyles.WindowWidthSettingsOAB - 23, 6, 16, 16); - public static Rect SettingsOABRect = new Rect(MicroStyles.WindowWidthStageOAB - 50, 6, 16, 16); - public static Rect EditWindowRect = new Rect(Screen.width * 0.5f - MicroStyles.WindowWidth / 2, Screen.height * 0.2f, MicroStyles.WindowWidth, 0); - - public static void InitializeStyles() - { - SpaceWarpUISkin = Skins.ConsoleSkin; - - MainWindowStyle = new GUIStyle(SpaceWarpUISkin.window) - { - padding = new RectOffset(8, 8, 20, 8), - contentOffset = new Vector2(0, -22), - fixedWidth = WindowWidth - }; - - PopoutWindowStyle = new GUIStyle(MainWindowStyle) - { - padding = new RectOffset(MainWindowStyle.padding.left, MainWindowStyle.padding.right, 0, MainWindowStyle.padding.bottom - 5), - fixedWidth = WindowWidth - }; - - EditWindowStyle = new GUIStyle(PopoutWindowStyle) - { - padding = new RectOffset(8, 8, 30, 8) - }; - - StageOABWindowStyle = new GUIStyle(SpaceWarpUISkin.window) - { - padding = new RectOffset(8, 8, 0, 8), - contentOffset = new Vector2(0, -22), - fixedWidth = WindowWidthStageOAB - }; - - CelestialSelectionStyle = new GUIStyle(SpaceWarpUISkin.window) - { - padding = new RectOffset(8, 8, 0, 8), - contentOffset = new Vector2(0, -22) - }; - - SettingsOabStyle = new GUIStyle(SpaceWarpUISkin.window) - { - padding = new RectOffset(8, 8, 0, 16), - contentOffset = new Vector2(0, -22), - fixedWidth = WindowWidthSettingsOAB - }; - - PopoutBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - alignment = TextAnchor.MiddleCenter, - contentOffset = new Vector2(0, 2), - fixedHeight = 15, - fixedWidth = 15, - fontSize = 28, - clipping = TextClipping.Overflow, - margin = new RectOffset(0, 0, 10, 0) - }; - - SectionToggleStyle = new GUIStyle(SpaceWarpUISkin.toggle) - { - padding = new RectOffset(0, 18, -5, 0), - contentOffset= new Vector2(17, 8) - }; - - NameLabelStyle = new GUIStyle(SpaceWarpUISkin.label); - NameLabelStyle.normal.textColor = new Color(.7f, .75f, .75f, 1); - - ValueLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - alignment = TextAnchor.MiddleRight - }; - ValueLabelStyle.normal.textColor = new Color(.6f, .7f, 1, 1); - - UnitLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - fixedWidth = 24, - alignment = TextAnchor.MiddleLeft - }; - UnitLabelStyle.normal.textColor = new Color(.7f, .75f, .75f, 1); - - UnitLabelStyleStageOAB = new GUIStyle(SpaceWarpUISkin.label) - { - alignment = TextAnchor.MiddleRight - }; - UnitLabelStyleStageOAB.normal.textColor = new Color(.7f, .75f, .75f, 1); - - NormalLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - fixedWidth = 120 - }; - - TitleLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - fontSize = 18, - fixedWidth = 100, - fixedHeight = 50, - contentOffset = new Vector2(0, -20), - }; - - NormalCenteredLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - fixedWidth = 80, - alignment = TextAnchor.MiddleCenter - }; - - BlueLabelStyle = new GUIStyle(SpaceWarpUISkin.label) - { - alignment = TextAnchor.MiddleLeft, - wordWrap = true - }; - BlueLabelStyle.normal.textColor = new Color(.6f, .7f, 1, 1); - - WindowSelectionTextFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) - { - alignment = TextAnchor.MiddleCenter, - fixedWidth = 80 - }; - - WindowSelectionAbbrevitionTextFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) - { - alignment = TextAnchor.MiddleCenter, - fixedWidth = 40 - }; - - CloseBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - fontSize = 8 - }; - - SettingsBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - fontSize = 24 - }; - - NormalBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - alignment = TextAnchor.MiddleCenter - }; - - CelestialBodyBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - alignment = TextAnchor.MiddleCenter, - fixedWidth = 80, - fixedHeight = 20 - }; - - CelestialSelectionBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - alignment = TextAnchor.MiddleLeft, - fixedWidth = 120 - }; - - OneCharacterBtnStyle = new GUIStyle(SpaceWarpUISkin.button) - { - fixedWidth = 20, - alignment = TextAnchor.MiddleCenter - }; - - TableHeaderLabelStyle = new GUIStyle(NameLabelStyle) - { - alignment = TextAnchor.MiddleRight - }; - TableHeaderCenteredLabelStyle = new GUIStyle(NameLabelStyle) - { - alignment = TextAnchor.MiddleCenter - }; - } - - /// - /// Draws a white horizontal line accross the container it's put in - /// - /// Height/thickness of the line - public static void DrawHorizontalLine(float height) - { - Texture2D horizontalLineTexture = new Texture2D(1, 1); - horizontalLineTexture.SetPixel(0, 0, Color.white); - horizontalLineTexture.Apply(); - GUI.DrawTexture(GUILayoutUtility.GetRect(Screen.width, height), horizontalLineTexture); - } - - /// - /// Draws a white horizontal line accross the container it's put in with height of 1 px - /// - public static void DrawHorizontalLine() { MicroStyles.DrawHorizontalLine(1); } - - internal static void SetStylesForOldSpaceWarpSkin() - { - SectionToggleStyle = new GUIStyle(SpaceWarpUISkin.toggle) - { - margin = new RectOffset(0, 30, 0, 5) - }; - } - } -} diff --git a/MicroEngineerProject/MicroEngineer/MicroWindow.cs b/MicroEngineerProject/MicroEngineer/MicroWindow.cs deleted file mode 100644 index 91a479d..0000000 --- a/MicroEngineerProject/MicroEngineer/MicroWindow.cs +++ /dev/null @@ -1,149 +0,0 @@ -using UnityEngine; -using Newtonsoft.Json; - -namespace MicroMod -{ - /// - /// Window that can hold a list of Entries - /// - [JsonObject(MemberSerialization.OptIn)] - public class MicroWindow - { - [JsonProperty] - public string Name; - [JsonProperty] - public string Abbreviation; - [JsonProperty] - public string Description; // not used - - [JsonProperty] - public bool IsEditorActive; - [JsonProperty] - public bool IsFlightActive; - [JsonProperty] - public bool IsMapActive; // TODO: implement - - [JsonProperty] - public bool IsEditorPoppedOut; - [JsonProperty] - public bool IsFlightPoppedOut; - [JsonProperty] - public bool IsMapPoppedOut; - - /// - /// Can the window be dragged or closed - /// - [JsonProperty] - public bool IsLocked; - - /// - /// Window can be deleted if it's not one of main windows - /// - [JsonProperty] - public bool IsDeletable { get => MainWindow == MainWindow.None; } - - /// - /// Can the window be edited (add, remove & arrange entries) - /// - [JsonProperty] - public bool IsEditable { get => MainWindow != MainWindow.MainGui && MainWindow != MainWindow.Settings && MainWindow != MainWindow.Stage && MainWindow != MainWindow.StageInfoOAB; } - - [JsonProperty] - public MainWindow MainWindow; - [JsonProperty] - public Rect EditorRect; - [JsonProperty] - public Rect FlightRect; - [JsonProperty] - public List Entries; - - /// - /// Moves entry upwards in the window. Does nothing if it's already first. - /// - /// Entry's current index - public void MoveEntryUp(int entryIndex) - { - // check if entry exists and it's not first - if (entryIndex < Entries.Count && entryIndex > 0) - { - var temp = Entries[entryIndex-1]; - Entries[entryIndex - 1] = Entries[entryIndex]; - Entries[entryIndex] = temp; - } - } - - /// - /// Moves entry downwards in the window. Does nothing if it's already last. - /// - /// Entry's current index - public void MoveEntryDown(int entryIndex) - { - // check if entry is not last - if (entryIndex < Entries.Count - 1) - { - var temp = Entries[entryIndex + 1]; - Entries[entryIndex + 1] = Entries[entryIndex]; - Entries[entryIndex] = temp; - } - } - - /// - /// Removes entry from the window - /// - /// Entry's index - public void RemoveEntry(int entryIndex) - { - if (entryIndex < Entries.Count) - Entries.RemoveAt(entryIndex); - } - - /// - /// Adds an entry to the window to the last position - /// - /// - public void AddEntry(MicroEntry entry) => Entries.Add(entry); - - /// - /// Grabs new data for each entry in the window - /// - public void RefreshEntryData() - { - foreach (MicroEntry entry in Entries) - entry.RefreshData(); - } - } - - /// - /// Each entry has a category we assign to it depending on where it fits best - /// - public enum MicroEntryCategory - { - Vessel, - Orbital, - Surface, - Flight, - Target, - Maneuver, - Stage, - Misc, - OAB - } - - /// - /// Main windows cannot be deleted. Value None indicated that the window is not a main window - /// - public enum MainWindow - { - None = 0, - MainGui, - Vessel, - Stage, - Orbital, - Surface, - Flight, - Target, - Maneuver, - Settings, - StageInfoOAB - } -} diff --git a/MicroEngineerProject/MicroEngineer/Utilities/AeroForces.cs b/MicroEngineerProject/MicroEngineer/Utilities/AeroForces.cs new file mode 100644 index 0000000..1550d1d --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Utilities/AeroForces.cs @@ -0,0 +1,134 @@ +using KSP.Game; +using KSP.Sim.impl; +using KSP.Sim; +using KSP.UI.Flight; +using UnityEngine; + +namespace MicroMod +{ + public static class AeroForces + { + private static readonly List liftForces = new() + { + PhysicsForceDisplaySystem.MODULE_DRAG_BODY_LIFT_TYPE, + PhysicsForceDisplaySystem.MODULE_LIFTINGSURFACE_LIFT_TYPE + }; + + private static readonly List dragForces = new() + { + PhysicsForceDisplaySystem.MODULE_DRAG_DRAG_TYPE, + PhysicsForceDisplaySystem.MODULE_LIFTINGSURFACE_DRAG_TYPE + }; + + public static double TotalLift + { + get + { + double toReturn = 0.0; + + IEnumerable parts = Utility.ActiveVessel?.SimulationObject?.PartOwner?.Parts; + if (parts == null || !Utility.ActiveVessel.IsInAtmosphere) + { + return toReturn; + } + + foreach (PartComponent part in parts) + { + foreach (IForce force in part.SimulationObject.Rigidbody.Forces) + { + if (liftForces.Contains(force.GetType())) + { + toReturn += force.RelativeForce.magnitude; + } + } + } + + return toReturn; + } + } + + public static double TotalDrag + { + get + { + double toReturn = 0.0; + + IEnumerable parts = Utility.ActiveVessel?.SimulationObject?.PartOwner?.Parts; + if (parts == null || !Utility.ActiveVessel.IsInAtmosphere) + return toReturn; + + foreach (PartComponent part in parts) + { + foreach (IForce force in part.SimulationObject.Rigidbody.Forces) + { + if (dragForces.Contains(force.GetType())) + { + toReturn += force.RelativeForce.magnitude; + } + } + } + + return toReturn; + } + } + + public static double AngleOfAttack + { + get + { + double aoe = 0.0; + + ISimulationObjectView simulationViewIfLoaded = GameManager.Instance.Game.ViewController.GetSimulationViewIfLoaded(Utility.ActiveVessel.SimulationObject); + if (simulationViewIfLoaded != null) + { + Vector3d normalized = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(Utility.ActiveVessel.SurfaceVelocity).normalized; + Vector up = simulationViewIfLoaded.Model.Vessel.ControlTransform.up; + Vector3 lhs = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(up); + Vector right = simulationViewIfLoaded.Model.Vessel.ControlTransform.right; + Vector3 rhs = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(right); + Vector3 lhs2 = normalized; + Vector3 normalized2 = Vector3.Cross(lhs2, rhs).normalized; + Vector3 rhs2 = Vector3.Cross(lhs2, normalized2); + aoe = Vector3.Dot(lhs, normalized2); + aoe = Math.Asin(aoe) * 57.295780181884766; + if (double.IsNaN(aoe)) + { + aoe = 0.0; + } + } + + return aoe; + } + } + + public static double SideSlip + { + get + { + double sideSlip = 0.0; + + ISimulationObjectView simulationViewIfLoaded = GameManager.Instance.Game.ViewController.GetSimulationViewIfLoaded(Utility.ActiveVessel.SimulationObject); + if (simulationViewIfLoaded != null) + { + Vector3d normalized = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(Utility.ActiveVessel.SurfaceVelocity).normalized; + Vector up = simulationViewIfLoaded.Model.Vessel.ControlTransform.up; + Vector3 lhs = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(up); + Vector right = simulationViewIfLoaded.Model.Vessel.ControlTransform.right; + Vector3 rhs = GameManager.Instance.Game.UniverseView.PhysicsSpace.VectorToPhysics(right); + Vector3 lhs2 = normalized; + Vector3 normalized2 = Vector3.Cross(lhs2, rhs).normalized; + Vector3 rhs2 = Vector3.Cross(lhs2, normalized2); + + sideSlip = Vector3.Dot(lhs, rhs2); + sideSlip = Math.Asin(sideSlip) * 57.295780181884766; + if (double.IsNaN(sideSlip)) + { + sideSlip = 0.0; + } + } + + return sideSlip; + } + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs b/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs new file mode 100644 index 0000000..50e8bb5 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs @@ -0,0 +1,470 @@ +using BepInEx.Logging; +using SpaceWarp.API.Assets; +using SpaceWarp.API.UI; +using UnityEngine; + +namespace MicroMod +{ + // MARGIN: how much the element is offset from other elements + // PADDING: how much the text inside the element is offset from the default alignment + + public static class Styles + { + private static MicroEngineerMod _plugin; + + private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Styles"); + + public static int WindowWidth = 290; + public static int WindowHeight = 1440; + public static int WindowWidthStageOAB = 645; + public static int WindowWidthSettingsOAB = 300; + public static int WindowWidthSettingsFlight = WindowWidth; + + public static GUISkin SpaceWarpUISkin; + public static GUIStyle MainWindowStyle; + public static GUIStyle PopoutWindowStyle; + public static GUIStyle EditWindowStyle; + public static GUIStyle StageOABWindowStyle; + + public static GUIStyle CelestialSelectionStyle; + public static GUIStyle SettingsOabStyle; + public static GUIStyle SettingsFlightStyle; + public static GUIStyle PopoutBtnStyle; + public static GUIStyle SectionToggleStyle; + + public static GUIStyle NameLabelStyle; + public static GUIStyle ValueLabelStyle; + public static GUIStyle BlueLabelStyle; + public static GUIStyle UnitLabelStyle; + public static GUIStyle UnitLabelStyleStageOAB; + public static GUIStyle NormalLabelStyle; + public static GUIStyle TitleLabelStyle; + public static GUIStyle WindowTitleLabelStyle; + public static GUIStyle NormalCenteredLabelStyle; + + public static GUIStyle WindowSelectionTextFieldStyle; + public static GUIStyle WindowSelectionAbbrevitionTextFieldStyle; + + public static GUIStyle CloseMainGuiBtnStyle; + public static GUIStyle CloseBtnStyle; + public static GUIStyle SettingsBtnStyle; + public static GUIStyle SettingsMainGuiBtnStyle; + public static GUIStyle CloseBtnStageOABStyle; + public static GUIStyle NormalBtnStyle; + public static GUIStyle CelestialBodyBtnStyle; + public static GUIStyle CelestialSelectionBtnStyle; + public static GUIStyle OneCharacterBtnStyle; + public static GUIStyle OneCharacterHighBtnStyle; + + public static GUIStyle TableHeaderLabelStyle; + public static GUIStyle TableHeaderCenteredLabelStyle; + + public static GUIStyle EntryBackground_WhiteTheme_First; + public static GUIStyle EntryBackground_WhiteTheme_Middle; + public static GUIStyle EntryBackground_WhiteTheme_Last; + public static GUIStyle EntryBackground_GrayTheme_First; + public static GUIStyle EntryBackground_GrayTheme_Middle; + public static GUIStyle EntryBackground_GrayTheme_Last; + public static GUIStyle EntryBackground_BlackTheme_First; + public static GUIStyle EntryBackground_BlackTheme_Middle; + public static GUIStyle EntryBackground_BlackTheme_Last; + public static GUIStyle EntryBackground_First; + public static GUIStyle EntryBackground_Middle; + public static GUIStyle EntryBackground_Last; + + public static string UnitColorHex { get => ColorUtility.ToHtmlStringRGBA(_unitColor); } + + public static int NegativeSpacingAfterHeader = -12; + public static int NegativeSpacingAfterEntry = -12; + public static int SpacingAfterSection = 10; + public static float SpacingBelowPopout = 15; + + public static float PoppedOutX = Screen.width * 0.6f; + public static float PoppedOutY = Screen.height * 0.2f; + public static float MainGuiX = Screen.width * 0.7f; + public static float MainGuiY = Screen.height * 0.2f; + + public static Rect CloseBtnRect = new Rect(Styles.WindowWidth - 23, 6, 16, 16); // TODO check if we need this + public static Rect SettingsMainGuiBtnRect = new Rect(6, 6, 30, 20); + public static Rect SettingsFlightBtnRect = new Rect(Styles.WindowWidth - 45, 6, 16, 16); // TODO check if we need this + public static Rect PopoutBtnRect = new Rect(Styles.WindowWidth - 23, 6, 16, 16); // TODO check if we need this + public static Rect SettingsWindowBtnRect = new Rect(Styles.WindowWidth - 23, 6, 20, 20); + public static Rect CloseBtnStagesOABRect = new Rect(Styles.WindowWidthStageOAB - 23, 6, 16, 16); + public static Rect CloseBtnSettingsOABRect = new Rect(Styles.WindowWidthSettingsOAB - 23, 6, 16, 16); + public static Rect SettingsOABRect = new Rect(Styles.WindowWidthStageOAB - 50, 6, 16, 16); + public static Rect EditWindowRect = new Rect(Screen.width * 0.5f - Styles.WindowWidth / 2, Screen.height * 0.2f, Styles.WindowWidth, 0); + + public static Texture2D Settings20Texture; + public static Texture2D Settings15Texture; + public static Texture2D CloseButtonTexture; + public static Texture2D PopoutTexture; + public static Texture2D EntryBackgroundTexture_WhiteTheme_First; + public static Texture2D EntryBackgroundTexture_WhiteTheme_Middle; + public static Texture2D EntryBackgroundTexture_WhiteTheme_Last; + public static Texture2D EntryBackgroundTexture_GrayTheme_First; + public static Texture2D EntryBackgroundTexture_GrayTheme_Middle; + public static Texture2D EntryBackgroundTexture_GrayTheme_Last; + public static Texture2D EntryBackgroundTexture_BlackTheme_First; + public static Texture2D EntryBackgroundTexture_BlackTheme_Middle; + public static Texture2D EntryBackgroundTexture_BlackTheme_Last; + public static Texture2D IncreaseDecimalDigitsTexture; + public static Texture2D DecreaseDecimalDigitsTexture; + + private static Color _nameColor_DarkThemes = new Color(.7f, .75f, .75f, 1); + private static Color _valueColor_DarkThemes = new Color(.6f, .7f, 1, 1); + private static Color _unitColor_DarkThemes = new Color(.7f, .75f, .75f, 1); + + private static Color _nameColor_LightThemes = new Color(.0f, .0f, .0f, 1); + private static Color _valueColor_LightThemes = new Color(.2f, .3f, 1, 1); + private static Color _unitColor_LightThemes = new Color(.0f, .0f, .0f, 1); + + private static Color _nameColor = _nameColor_DarkThemes; + private static Color _valueColor = _valueColor_DarkThemes; + private static Color _unitColor = _unitColor_DarkThemes; + + public static Theme ActiveTheme; + + public static void Initialize(MicroEngineerMod plugin) + { + _plugin = plugin; + + InitializeTextures(); + InitializeStyles(); + SetActiveTheme(Theme.Gray); + } + + private static void InitializeStyles() + { + SpaceWarpUISkin = Skins.ConsoleSkin; + + MainWindowStyle = new GUIStyle(SpaceWarpUISkin.window) + { + padding = new RectOffset(8, 8, 20, 8), + contentOffset = new Vector2(0, -22), + fixedWidth = WindowWidth + }; + + PopoutWindowStyle = new GUIStyle(MainWindowStyle) + { + padding = new RectOffset(MainWindowStyle.padding.left, MainWindowStyle.padding.right, 0, MainWindowStyle.padding.bottom - 5), + fixedWidth = WindowWidth + }; + + EditWindowStyle = new GUIStyle(PopoutWindowStyle) + { + padding = new RectOffset(8, 8, 10, 8) + }; + + StageOABWindowStyle = new GUIStyle(SpaceWarpUISkin.window) + { + padding = new RectOffset(8, 8, 0, 8), + contentOffset = new Vector2(0, -22), + fixedWidth = WindowWidthStageOAB + }; + + CelestialSelectionStyle = new GUIStyle(SpaceWarpUISkin.window) + { + padding = new RectOffset(8, 8, 0, 8), + contentOffset = new Vector2(0, -22) + }; + + SettingsOabStyle = new GUIStyle(SpaceWarpUISkin.window) + { + padding = new RectOffset(8, 8, 0, 16), + contentOffset = new Vector2(0, -22), + fixedWidth = WindowWidthSettingsOAB + }; + + SettingsFlightStyle = new GUIStyle(SpaceWarpUISkin.window) + { + padding = new RectOffset(8, 8, 0, 16), + contentOffset = new Vector2(0, -22), + fixedWidth = WindowWidthSettingsFlight + }; + + SectionToggleStyle = new GUIStyle(SpaceWarpUISkin.toggle) + { + fixedHeight = 22, + margin = new RectOffset(0, 4, 0, 0) + }; + + NameLabelStyle = new GUIStyle(SpaceWarpUISkin.label); + NameLabelStyle.normal.textColor = _nameColor; + NameLabelStyle.contentOffset = new Vector2(0, -1); // Background texture is hiding entry's bottom pixel, so this is needed + + ValueLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + alignment = TextAnchor.MiddleRight + }; + ValueLabelStyle.normal.textColor = _valueColor; + ValueLabelStyle.contentOffset = new Vector2(0, -1); // Background texture is hiding entry's bottom pixel, so this is needed + + UnitLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + fixedWidth = 35, + alignment = TextAnchor.MiddleLeft + }; + UnitLabelStyle.normal.textColor = _unitColor; + UnitLabelStyle.contentOffset = new Vector2(0, -1); // Background texture is hiding entry's bottom pixel, so this is needed + + UnitLabelStyleStageOAB = new GUIStyle(SpaceWarpUISkin.label) + { + alignment = TextAnchor.MiddleRight + }; + UnitLabelStyleStageOAB.normal.textColor = _unitColor; + + NormalLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + fixedWidth = 120 + }; + + TitleLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + fontSize = 18, + fixedWidth = 100, + fixedHeight = 50, + contentOffset = new Vector2(0, -20), + }; + + WindowTitleLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + fontStyle = FontStyle.Bold, + contentOffset = new Vector2(0, -5) + }; + + NormalCenteredLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + fixedWidth = 80, + alignment = TextAnchor.MiddleCenter + }; + + BlueLabelStyle = new GUIStyle(SpaceWarpUISkin.label) + { + alignment = TextAnchor.MiddleLeft, + wordWrap = true + }; + BlueLabelStyle.normal.textColor = _valueColor; + + WindowSelectionTextFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) + { + alignment = TextAnchor.MiddleCenter, + fixedWidth = 80 + }; + + WindowSelectionAbbrevitionTextFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) + { + alignment = TextAnchor.MiddleCenter, + fixedWidth = 40 + }; + + ///// BUTTONS ///// + + CloseMainGuiBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 20, + fixedHeight = 20, + padding = new RectOffset(-2, -2, -2, -2) + }; + + CloseBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 25, + fixedHeight = 15, + padding = new RectOffset(-2, -2, -2, -2) + }; + + SettingsBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 25, + fixedHeight = 15, + padding = new RectOffset(-2, -2, -2, -2) + }; + + PopoutBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 25, + fixedHeight = 15, + padding = new RectOffset(-2, -2, -2, -2) + }; + + SettingsMainGuiBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 30, + fixedHeight = 20, + padding = new RectOffset(-2, -2, -2, -2) + }; + + NormalBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + alignment = TextAnchor.MiddleCenter + }; + + CelestialBodyBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + alignment = TextAnchor.MiddleCenter, + fixedWidth = 80, + fixedHeight = 20 + }; + + CelestialSelectionBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + alignment = TextAnchor.MiddleLeft, + fixedWidth = 120 + }; + + OneCharacterBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 20, + fixedHeight = 19, + alignment = TextAnchor.MiddleCenter, + margin = new RectOffset(0, 5, 9, 0), + padding = new RectOffset(0, 0, 0, 0) + }; + + OneCharacterHighBtnStyle = new GUIStyle(SpaceWarpUISkin.button) + { + fixedWidth = 20, + alignment = TextAnchor.MiddleCenter, + }; + + TableHeaderLabelStyle = new GUIStyle(NameLabelStyle) + { + alignment = TextAnchor.MiddleRight + }; + TableHeaderCenteredLabelStyle = new GUIStyle(NameLabelStyle) + { + alignment = TextAnchor.MiddleCenter + }; + + EntryBackground_WhiteTheme_First = new GUIStyle { name = "WhiteFirst" }; + EntryBackground_WhiteTheme_First.normal.background = EntryBackgroundTexture_WhiteTheme_First; + EntryBackground_WhiteTheme_Middle = new GUIStyle { name = "WhiteMiddle" }; + EntryBackground_WhiteTheme_Middle.normal.background = EntryBackgroundTexture_WhiteTheme_Middle; + EntryBackground_WhiteTheme_Last = new GUIStyle { name = "WhiteLast" }; + EntryBackground_WhiteTheme_Last.normal.background = EntryBackgroundTexture_WhiteTheme_Last; + + EntryBackground_GrayTheme_First = new GUIStyle { name = "GrayFirst" }; + EntryBackground_GrayTheme_First.normal.background = EntryBackgroundTexture_GrayTheme_First; + EntryBackground_GrayTheme_Middle = new GUIStyle { name = "GrayMiddle" }; + EntryBackground_GrayTheme_Middle.normal.background = EntryBackgroundTexture_GrayTheme_Middle; + EntryBackground_GrayTheme_Last = new GUIStyle { name = "GrayLast" }; + EntryBackground_GrayTheme_Last.normal.background = EntryBackgroundTexture_GrayTheme_Last; + + EntryBackground_BlackTheme_First = new GUIStyle { name = "BlackFirst" }; + EntryBackground_BlackTheme_First.normal.background = EntryBackgroundTexture_BlackTheme_First; + EntryBackground_BlackTheme_Middle = new GUIStyle { name = "BlackMiddle" }; + EntryBackground_BlackTheme_Middle.normal.background = EntryBackgroundTexture_BlackTheme_Middle; + EntryBackground_BlackTheme_Last = new GUIStyle { name = "BlackLast" }; + EntryBackground_BlackTheme_Last.normal.background = EntryBackgroundTexture_BlackTheme_Last; + } + + private static void InitializeTextures() + { + // Icons from https://icons8.com + + Settings20Texture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/settings-20.png"); + Settings15Texture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/settings-15.png"); + CloseButtonTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/close-15.png"); + PopoutTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/popout-15.png"); + + EntryBackgroundTexture_WhiteTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_first.png"); + EntryBackgroundTexture_WhiteTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_middle.png"); + EntryBackgroundTexture_WhiteTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_last.png"); + + EntryBackgroundTexture_GrayTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_first.png"); + EntryBackgroundTexture_GrayTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_middle.png"); + EntryBackgroundTexture_GrayTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_last.png"); + + EntryBackgroundTexture_BlackTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_first.png"); + EntryBackgroundTexture_BlackTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_middle.png"); + EntryBackgroundTexture_BlackTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_last.png"); + + IncreaseDecimalDigitsTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/increase-decimal-19.png"); + DecreaseDecimalDigitsTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/decrease-decimal-19.png"); + } + + private static Texture2D LoadTexture(string path) + { + try + { + return AssetManager.GetAsset(path); + } + catch (Exception ex) + { + _logger.LogError($"Error loading texture with path: {path}. Full error: \n{ex}"); + return new Texture2D(20, 20); + } + } + + public static void SetActiveTheme(Theme theme) + { + if (ActiveTheme == theme) return; + + switch (theme) + { + case Theme.munix: + EntryBackground_First = EntryBackground_WhiteTheme_First; + EntryBackground_Middle = EntryBackground_WhiteTheme_Middle; + EntryBackground_Last = EntryBackground_WhiteTheme_Last; + _nameColor = _nameColor_LightThemes; + _valueColor = _valueColor_LightThemes; + _unitColor = _unitColor_LightThemes; + break; + case Theme.Gray: + EntryBackground_First = EntryBackground_GrayTheme_First; + EntryBackground_Middle = EntryBackground_GrayTheme_Middle; + EntryBackground_Last = EntryBackground_GrayTheme_Last; + _nameColor = _nameColor_DarkThemes; + _valueColor = _valueColor_DarkThemes; + _unitColor = _unitColor_DarkThemes; + break; + case Theme.Black: + EntryBackground_First = EntryBackground_BlackTheme_First; + EntryBackground_Middle = EntryBackground_BlackTheme_Middle; + EntryBackground_Last = EntryBackground_BlackTheme_Last; + _nameColor = _nameColor_DarkThemes; + _valueColor = _valueColor_DarkThemes; + _unitColor = _unitColor_DarkThemes; + break; + default: + SetActiveTheme(Theme.Gray); + break; + } + + ActiveTheme = theme; + InitializeStyles(); + } + + /// + /// Draws a white horizontal line accross the container it's put in + /// + /// Height/thickness of the line + public static void DrawHorizontalLine(float height) + { + Texture2D horizontalLineTexture = new Texture2D(1, 1); + horizontalLineTexture.SetPixel(0, 0, Color.white); + horizontalLineTexture.Apply(); + GUI.DrawTexture(GUILayoutUtility.GetRect(Screen.width, height), horizontalLineTexture); + } + + /// + /// Draws a white horizontal line accross the container it's put in with height of 1 px + /// + public static void DrawHorizontalLine() { Styles.DrawHorizontalLine(1); } + + internal static void SetStylesForOldSpaceWarpSkin() + { + SectionToggleStyle = new GUIStyle(SpaceWarpUISkin.toggle) + { + margin = new RectOffset(0, 30, 0, 5) + }; + } + } + + public enum Theme + { + munix, + Gray, + Black + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Utilities/TransferInfo.cs b/MicroEngineerProject/MicroEngineer/Utilities/TransferInfo.cs new file mode 100644 index 0000000..b596ccf --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Utilities/TransferInfo.cs @@ -0,0 +1,121 @@ +using KSP.Sim.impl; +using KSP.Sim; +using UnityEngine; + +namespace MicroMod +{ + /// + /// Original code by: + /// https://github.com/ABritInSpace/TransferCalculator-KSP2 + /// License: https://raw.githubusercontent.com/ABritInSpace/TransferCalculator-KSP2/master/LICENSE.md + /// + public static class TransferInfo + { + private static Vector3? _fromLocalPosition; + private static IKeplerOrbit _fromOrbit; + private static Vector3? _toLocalPosition; + private static IKeplerOrbit _toOrbit; + + private static bool CalculateParameters() + { + // If Target is the body that vessel is orbiting, there is no phase angle + if (Utility.ActiveVessel.Orbit.referenceBody == Utility.ActiveVessel.TargetObject.CelestialBody) + { + _fromLocalPosition = null; + _toLocalPosition = null; + _fromOrbit = null; + _toOrbit = null; + return false; + } + + (CelestialBodyComponent referenceBody, Vector3 localPosition, IKeplerOrbit currentOrbit) from = (Utility.ActiveVessel.Orbit.referenceBody, Utility.ActiveVessel.Orbit.Position.localPosition, Utility.ActiveVessel.Orbit); + (CelestialBodyComponent referenceBody, Vector3 localPosition, IKeplerOrbit currentOrbit) to = (Utility.ActiveVessel.TargetObject.Orbit.referenceBody, Utility.ActiveVessel.TargetObject.Orbit.Position.localPosition, Utility.ActiveVessel.TargetObject.Orbit); + + // We search for the common celestial body that both ActiveVessel and TargetObject are orbiting and then calculate the phase angle + bool commonReferenceBodyFound = false; + + // Set a limit for common reference body lookups. There should always be a common reference body so this shouldn't be needed, but just to be safe. + int numberOfLoopTries = 3; + + // Outer loop => TargetObject (to) + for (int i = 0; i < numberOfLoopTries; i++) + { + from.referenceBody = Utility.ActiveVessel.Orbit.referenceBody; + from.localPosition = Utility.ActiveVessel.Orbit.Position.localPosition; + from.currentOrbit = Utility.ActiveVessel.Orbit; + + // Inner lookp => ActiveVessel (from) + for (int j = 0; j < numberOfLoopTries; j++) + { + if (from.referenceBody == to.referenceBody) + { + commonReferenceBodyFound = true; + break; + } + + // referenceBody.Orbit is null when referenceBody is a star (i.e. Kerbol). Lookup should end here since the star isn't orbiting anything (yet!) + if (from.referenceBody.Orbit == null) + break; + + // Set the reference body one level up + from.localPosition = from.referenceBody.Position.localPosition + from.localPosition; + from.currentOrbit = from.referenceBody.Orbit; + from.referenceBody = from.referenceBody.referenceBody; + } + + if (commonReferenceBodyFound) + break; + + if (to.referenceBody.Orbit == null) + break; + + // Set the reference body one level up + to.localPosition = to.referenceBody.Position.localPosition + to.localPosition; + to.currentOrbit = to.referenceBody.Orbit; + to.referenceBody = to.referenceBody.referenceBody; + } + + if (commonReferenceBodyFound) + { + _fromLocalPosition = from.localPosition; + _fromOrbit = from.currentOrbit; + _toLocalPosition = to.localPosition; + _toOrbit = to.currentOrbit; + return true; + } + else + { + _fromLocalPosition = null; + _fromOrbit = null; + _toLocalPosition = null; + _toOrbit = null; + return false; + } + } + + public static double? GetPhaseAngle() + { + if (CalculateParameters()) + { + double phase = Vector3d.SignedAngle((Vector3d)_toLocalPosition, (Vector3d)_fromLocalPosition, Vector3d.up); + return Math.Round(phase, 1); + } + else + return null; + } + + public static double? GetTransferAngle() + { + if (CalculateParameters()) + { + double ellipseA = (_toOrbit.semiMajorAxis + _fromOrbit.semiMajorAxis) / 2; + double time = Mathf.PI * Mathf.Sqrt((float)((ellipseA) * (ellipseA) * (ellipseA)) / ((float)_toOrbit.referenceBody.Mass * 6.67e-11f)); + double transfer = 180 - ((time / _toOrbit.period) * 360); + while (transfer < -180) { transfer += 360; } + return Math.Round(transfer, 1); + } + else + return null; + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroUtility.cs b/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs similarity index 66% rename from MicroEngineerProject/MicroEngineer/MicroUtility.cs rename to MicroEngineerProject/MicroEngineer/Utilities/Utility.cs index 2835c99..a505775 100644 --- a/MicroEngineerProject/MicroEngineer/MicroUtility.cs +++ b/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs @@ -1,9 +1,7 @@ using System.Reflection; using KSP.Game; -using KSP.Sim; using KSP.Sim.impl; using KSP.Sim.Maneuver; -using KSP.UI.Flight; using Newtonsoft.Json; using UnityEngine; using static KSP.Rendering.Planets.PQSData; @@ -15,17 +13,19 @@ namespace MicroMod { - public static class MicroUtility + public static class Utility { public static VesselComponent ActiveVessel; public static ManeuverNodeData CurrentManeuver; public static string LayoutPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "MicroLayout.json"); - private static ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.MicroUtility"); + public static int CurrentLayoutVersion = 10; + private static ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Utility"); public static GameStateConfiguration GameState; public static MessageCenter MessageCenter; public static VesselDeltaVComponent VesselDeltaVComponentOAB; public static string InputDisableWindowAbbreviation = "WindowAbbreviation"; public static string InputDisableWindowName = "WindowName"; + public static double UniversalTime => GameManager.Instance.Game.UniverseModel.UniversalTime; /// /// Refreshes the ActiveVessel and CurrentManeuver @@ -33,7 +33,7 @@ public static class MicroUtility public static void RefreshActiveVesselAndCurrentManeuver() { ActiveVessel = GameManager.Instance?.Game?.ViewController?.GetActiveVehicle(true)?.GetSimVessel(true); - CurrentManeuver = ActiveVessel != null ? GameManager.Instance?.Game?.SpaceSimulation.Maneuvers.GetNodesForVessel(ActiveVessel.GlobalId).FirstOrDefault(): null; + CurrentManeuver = ActiveVessel != null ? GameManager.Instance?.Game?.SpaceSimulation.Maneuvers.GetNodesForVessel(ActiveVessel.GlobalId).FirstOrDefault() : null; } public static void RefreshGameManager() @@ -54,23 +54,18 @@ public static string DegreesToDMS(double degreeD) int minutes = ts.Minutes; int seconds = ts.Seconds; - string result = $"{degrees:N0}° {minutes:00}' {seconds:00}\""; + string result = $"{degrees:N0}° {minutes:00}' {seconds:00}\""; return result; } - public static string MetersToDistanceString(double heightInMeters) - { - return $"{heightInMeters:N0}"; - } - public static string SecondsToTimeString(double seconds, bool addSpacing = true, bool returnLastUnit = false) { - if (seconds == Double.PositiveInfinity) + if (seconds == double.PositiveInfinity) { return "∞"; } - else if (seconds == Double.NegativeInfinity) + else if (seconds == double.NegativeInfinity) { return "-∞"; } @@ -91,19 +86,19 @@ public static string SecondsToTimeString(double seconds, bool addSpacing = true, } int days = (int)(seconds / 21600); - int hours = (int)((seconds - (days * 21600)) / 3600); - int minutes = (int)((seconds - (hours * 3600) - (days * 21600)) / 60); - int secs = (int)(seconds - (days * 21600) - (hours * 3600) - (minutes * 60)); + int hours = (int)((seconds - days * 21600) / 3600); + int minutes = (int)((seconds - hours * 3600 - days * 21600) / 60); + int secs = (int)(seconds - days * 21600 - hours * 3600 - minutes * 60); if (days > 0) { - result += $"{days}{spacing}d "; + result += $"{days}{spacing}d "; } if (hours > 0 || days > 0) { { - result += $"{hours}{spacing}h "; + result += $"{hours}{spacing}h "; } } @@ -111,21 +106,21 @@ public static string SecondsToTimeString(double seconds, bool addSpacing = true, { if (hours > 0 || days > 0) { - result += $"{minutes:00.}{spacing}m "; + result += $"{minutes:00.}{spacing}m "; } else { - result += $"{minutes}{spacing}m "; + result += $"{minutes}{spacing}m "; } } if (minutes > 0 || hours > 0 || days > 0) { - result += returnLastUnit ? $"{secs:00.}{spacing}s" : $"{secs:00.}"; + result += returnLastUnit ? $"{secs:00.}{spacing}s" : $"{secs:00.}"; } else { - result += returnLastUnit ? $"{secs}{spacing}s" : $"{secs}"; + result += returnLastUnit ? $"{secs}{spacing}s" : $"{secs}"; } return result; @@ -152,6 +147,11 @@ public static string BiomeToString(BiomeSurfaceData biome) return result.Substring(0, 1).ToUpper() + result.Substring(1); } + public static double RadiansToDegrees(double radians) + { + return radians * PatchedConicsOrbit.Rad2Deg; + } + /// /// Validates if user entered a 3 character string /// @@ -159,19 +159,16 @@ public static string BiomeToString(BiomeSurfaceData biome) /// Uppercase string shortened to 3 characters. If abbreviation is empty returns "CUS" public static string ValidateAbbreviation(string abbreviation) { - if (String.IsNullOrEmpty(abbreviation)) + if (string.IsNullOrEmpty(abbreviation)) return "CUS"; return abbreviation.Substring(0, Math.Min(abbreviation.Length, 3)).ToUpperInvariant(); } - public static void SaveLayout(List windows) + internal static void SaveLayout(List windows) { try { - // Deactivate the Settings window before saving, because it doesn't make sense to save it in an active state since user cannot click the save button without having the Settings window active - windows.Find(w => w.MainWindow == MainWindow.Settings).IsFlightActive = false; - File.WriteAllText(LayoutPath, JsonConvert.SerializeObject(windows)); Logger.LogInfo("SaveLayout successful"); } @@ -181,15 +178,26 @@ public static void SaveLayout(List windows) } } - public static void LoadLayout(List windows) + internal static void LoadLayout(List windows) { try { - List deserializedWindows = JsonConvert.DeserializeObject>(File.ReadAllText(LayoutPath)); + List deserializedWindows = JsonConvert.DeserializeObject>(File.ReadAllText(LayoutPath)); + + // Check if user has an old layout version. If it's older, it's not supported, so the default layout will remain active. Once the new layout is saved, it will persist. + var MainGui = deserializedWindows.OfType().FirstOrDefault(); + if (MainGui.LayoutVersion < Utility.CurrentLayoutVersion) + { + Logger.LogInfo("Loaded layout version is older than the current supported version. Layout will be reset."); + return; + } windows.Clear(); - windows.AddRange(deserializedWindows); - + windows.AddRange(deserializedWindows); + + var settingsWindow = windows.Find(w => w.GetType() == typeof(SettingsWIndow)) as SettingsWIndow; + settingsWindow.LoadSettings(); + Logger.LogInfo("LoadLayout successful"); } catch (FileNotFoundException ex) @@ -209,7 +217,7 @@ public static void LoadLayout(List windows) /// public static bool TargetExists() { - try { return (MicroUtility.ActiveVessel.TargetObject != null); } + try { return ActiveVessel.TargetObject != null; } catch { return false; } } @@ -219,7 +227,7 @@ public static bool TargetExists() /// public static bool ManeuverExists() { - try { return (GameManager.Instance?.Game?.SpaceSimulation.Maneuvers.GetNodesForVessel(MicroUtility.ActiveVessel.GlobalId).FirstOrDefault() != null); } + try { return GameManager.Instance?.Game?.SpaceSimulation.Maneuvers.GetNodesForVessel(ActiveVessel.GlobalId).FirstOrDefault() != null; } catch { return false; } } @@ -240,7 +248,7 @@ internal static bool ToggleGameInputOnControlInFocus(bool gameInputState, bool s { if (gameInputState) { - if (MicroUtility.InputDisableWindowAbbreviation == GUI.GetNameOfFocusedControl() || MicroUtility.InputDisableWindowName == GUI.GetNameOfFocusedControl()) + if (InputDisableWindowAbbreviation == GUI.GetNameOfFocusedControl() || InputDisableWindowName == GUI.GetNameOfFocusedControl()) { GameManager.Instance.Game.Input.Disable(); return false; @@ -250,7 +258,7 @@ internal static bool ToggleGameInputOnControlInFocus(bool gameInputState, bool s } else { - if ((MicroUtility.InputDisableWindowAbbreviation != GUI.GetNameOfFocusedControl() && MicroUtility.InputDisableWindowName != GUI.GetNameOfFocusedControl()) || !showGuiFlight) + if (InputDisableWindowAbbreviation != GUI.GetNameOfFocusedControl() && InputDisableWindowName != GUI.GetNameOfFocusedControl() || !showGuiFlight) { GameManager.Instance.Game.Input.Enable(); return true; @@ -295,9 +303,9 @@ internal static (int major, int minor, int patch)? GetModVersion(string modId) /// Specified minor version (0.X.0) /// Specified patch version (0.0.X) /// True = installed mod is older. False = installed mod has the same version or it's newer or version isn't declared or version declared is gibberish that cannot be parsed - internal static bool IsModOlderThan (string modId, int major, int minor, int patch) + internal static bool IsModOlderThan(string modId, int major, int minor, int patch) { - var modVersion = MicroUtility.GetModVersion(modId); + var modVersion = GetModVersion(modId); if (!modVersion.HasValue || modVersion.Value == (0, 0, 0)) return false; @@ -317,72 +325,5 @@ internal static bool IsModOlderThan (string modId, int major, int minor, int pat else return false; } - } - - public static class AeroForces - { - private static readonly List liftForces = new() - { - PhysicsForceDisplaySystem.MODULE_DRAG_BODY_LIFT_TYPE, - PhysicsForceDisplaySystem.MODULE_LIFTINGSURFACE_LIFT_TYPE - }; - - private static readonly List dragForces = new() - { - PhysicsForceDisplaySystem.MODULE_DRAG_DRAG_TYPE, - PhysicsForceDisplaySystem.MODULE_LIFTINGSURFACE_DRAG_TYPE - }; - - public static double TotalLift - { - get - { - double toReturn = 0.0; - - IEnumerable parts = MicroUtility.ActiveVessel?.SimulationObject?.PartOwner?.Parts; - if (parts == null || !MicroUtility.ActiveVessel.IsInAtmosphere) - { - return toReturn; - } - - foreach (PartComponent part in parts) - { - foreach (IForce force in part.SimulationObject.Rigidbody.Forces) - { - if (liftForces.Contains(force.GetType())) - { - toReturn += force.RelativeForce.magnitude; - } - } - } - - return toReturn; - } - } - - public static double TotalDrag - { - get - { - double toReturn = 0.0; - - IEnumerable parts = MicroUtility.ActiveVessel?.SimulationObject?.PartOwner?.Parts; - if (parts == null || !MicroUtility.ActiveVessel.IsInAtmosphere) - return toReturn; - - foreach (PartComponent part in parts) - { - foreach (IForce force in part.SimulationObject.Rigidbody.Forces) - { - if (dragForces.Contains(force.GetType())) - { - toReturn += force.RelativeForce.magnitude; - } - } - } - - return toReturn; - } - } - } -} + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/BaseWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/BaseWindow.cs new file mode 100644 index 0000000..34b5bcd --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/BaseWindow.cs @@ -0,0 +1,63 @@ +using UnityEngine; +using Newtonsoft.Json; + +namespace MicroMod +{ + /// + /// Window that can hold a list of Entries + /// + [JsonObject(MemberSerialization.OptIn)] + internal class BaseWindow + { + [JsonProperty] + internal bool IsEditorActive; + [JsonProperty] + internal bool IsFlightActive; + [JsonProperty] + internal bool IsMapActive; // TODO: implement + + [JsonProperty] + internal Rect EditorRect; + [JsonProperty] + internal Rect FlightRect; + + internal virtual void DrawWindowHeader() { } + + internal virtual void DrawWindowFooter() { } + } + + /// + /// Each entry has a category we assign to it depending on where it fits best + /// + public enum MicroEntryCategory + { + Vessel, + Orbital, + Surface, + Flight, + Target, + Maneuver, + Stage, + Body, + Misc, + OAB + } + + /// + /// Main windows cannot be deleted. Value None indicated that the window is not a main window + /// + public enum MainWindow + { + None = 0, + MainGui, + Vessel, + Stage, + Orbital, + Surface, + Flight, + Target, + Maneuver, + Settings, + StageInfoOAB + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs new file mode 100644 index 0000000..9231152 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs @@ -0,0 +1,109 @@ +using Newtonsoft.Json; + +namespace MicroMod +{ + internal class EntryWindow: BaseWindow + { + [JsonProperty] + internal string Name; + [JsonProperty] + internal string Abbreviation; + [JsonProperty] + internal string Description; // not used + + [JsonProperty] + internal bool IsEditorPoppedOut; + [JsonProperty] + internal bool IsFlightPoppedOut; + [JsonProperty] + internal bool IsMapPoppedOut; + + /// + /// Can the window be dragged or closed + /// + [JsonProperty] + internal bool IsLocked; + + /// + /// Window can be deleted if it's not one of main windows + /// + [JsonProperty] + internal bool IsDeletable { get => MainWindow == MainWindow.None; } + + /// + /// Can the window be edited (add, remove & arrange entries) + /// + [JsonProperty] + internal bool IsEditable { get => MainWindow != MainWindow.Stage && MainWindow != MainWindow.StageInfoOAB; } + + [JsonProperty] + internal MainWindow MainWindow; + + [JsonProperty] + internal List Entries; + + /// + /// Moves entry upwards in the window. Does nothing if it's already first. + /// + /// Entry's current index + internal void MoveEntryUp(int entryIndex) + { + // check if entry exists and it's not first + if (entryIndex < Entries.Count && entryIndex > 0) + { + var temp = Entries[entryIndex - 1]; + Entries[entryIndex - 1] = Entries[entryIndex]; + Entries[entryIndex] = temp; + } + } + + /// + /// Moves entry downwards in the window. Does nothing if it's already last. + /// + /// Entry's current index + internal void MoveEntryDown(int entryIndex) + { + // check if entry is not last + if (entryIndex < Entries.Count - 1) + { + var temp = Entries[entryIndex + 1]; + Entries[entryIndex + 1] = Entries[entryIndex]; + Entries[entryIndex] = temp; + } + } + + /// + /// Removes entry from the window + /// + /// Entry's index + internal void RemoveEntry(int entryIndex) + { + if (entryIndex < Entries.Count) + Entries.RemoveAt(entryIndex); + } + + /// + /// Adds an entry to the window to the last position + /// + /// + internal void AddEntry(BaseEntry entry) => Entries.Add(entry); + + /// + /// Grabs new data for each entry in the window + /// + internal void RefreshEntryData() + { + foreach (BaseEntry entry in Entries) + entry.RefreshData(); + } + + internal virtual void RefreshData() + { + if (Entries == null || Entries.Count == 0) + return; + + foreach (BaseEntry entry in Entries) + entry.RefreshData(); + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/MainGuiWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/MainGuiWindow.cs new file mode 100644 index 0000000..345e92c --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/MainGuiWindow.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace MicroMod +{ + internal class MainGuiWindow : BaseWindow + { + [JsonProperty] + internal int LayoutVersion; + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/ManeuverWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/ManeuverWindow.cs new file mode 100644 index 0000000..f8ac4ca --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/ManeuverWindow.cs @@ -0,0 +1,103 @@ +using KSP.Game; +using KSP.Messages; +using KSP.Sim.impl; +using KSP.Sim.Maneuver; +using UnityEngine; + +namespace MicroMod +{ + internal class ManeuverWindow : EntryWindow + { + private int _selectedNodeIndex = 0; + private List _nodes = new(); + + override internal void DrawWindowHeader() + { + if (_nodes == null || _nodes.Count <= 1) + return; + + GUILayout.Space(5); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("<", Styles.NormalBtnStyle) && _selectedNodeIndex > 0) + _selectedNodeIndex--; + + GUILayout.Label($"Node #{_selectedNodeIndex + 1}", Styles.TableHeaderCenteredLabelStyle); + + if (GUILayout.Button(">", Styles.NormalBtnStyle) && _selectedNodeIndex + 1 < _nodes.Count) + _selectedNodeIndex++; + + GUILayout.EndHorizontal(); + GUILayout.Space(5); + } + + override internal void DrawWindowFooter() + { + if (_nodes == null || _nodes.Count == 0) + return; + + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Delete", Styles.NormalBtnStyle)) + DeleteNodes(); + + GUILayout.EndHorizontal(); + GUILayout.Space(-10); + } + + private void DeleteNodes() + { + var nodes = Utility.ActiveVessel.SimulationObject?.FindComponent()?.GetNodes(); + List nodesToDelete = new List(); + + // This should never happen, but better be safe + if (_selectedNodeIndex + 1 > nodes.Count) + _selectedNodeIndex = Math.Max(0, nodes.Count - 1); + + var nodeToDelete = nodes[_selectedNodeIndex]; + nodesToDelete.Add(nodeToDelete); + + foreach (ManeuverNodeData node in nodes) + { + if (!nodesToDelete.Contains(node) && (!nodeToDelete.IsOnManeuverTrajectory || nodeToDelete.Time < node.Time)) + nodesToDelete.Add(node); + } + GameManager.Instance.Game.SpaceSimulation.Maneuvers.RemoveNodesFromVessel(Utility.ActiveVessel.GlobalId, nodesToDelete); + _selectedNodeIndex = 0; + } + + internal override void RefreshData() + { + base.RefreshData(); + RefreshManeuverNodes(); + + // Add _selectedNodeIndex to entries as well. They will show the correct node's info. + List entries = Entries.OfType().ToList(); + + foreach (var entry in entries) + entry.SelectedNodeIndex = _selectedNodeIndex; + } + + private void RefreshManeuverNodes() + { + ManeuverPlanComponent activeVesselPlan = Utility.ActiveVessel.SimulationObject.FindComponent(); + if (activeVesselPlan != null) + { + _nodes = activeVesselPlan.GetNodes(); + } + } + + internal void OnManeuverCreatedMessage(MessageCenterMessage message) + { + var nodeData = Utility.ActiveVessel.SimulationObject?.FindComponent()?.GetNodes(); + _selectedNodeIndex = nodeData != null ? nodeData.Count > 0 ? nodeData.Count - 1 : 0 : 0; + } + + internal void OnManeuverRemovedMessage(MessageCenterMessage message) + { + _selectedNodeIndex = 0; + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs b/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs new file mode 100644 index 0000000..1ce2215 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace MicroMod +{ + [JsonObject(MemberSerialization.OptIn)] + internal class SettingsWIndow : BaseWindow + { + [JsonProperty] + internal Theme ActiveTheme { get; set; } + + internal void LoadSettings() + { + Styles.SetActiveTheme(ActiveTheme); + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs new file mode 100644 index 0000000..4d6cb09 --- /dev/null +++ b/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs @@ -0,0 +1,139 @@ +using KSP.Sim.DeltaV; +using UnityEngine; + +namespace MicroMod +{ + internal class StageWindow : EntryWindow + { + private UI _ui; + + internal void DrawWindow(UI ui) + { + _ui = ui; + + if (this.IsFlightPoppedOut) + { + this.FlightRect = GUILayout.Window( + GUIUtility.GetControlID(FocusType.Passive), + this.FlightRect, + DrawStages, + "", + Styles.PopoutWindowStyle, + GUILayout.Width(Styles.WindowWidth), + GUILayout.Height(0) + ); + + this.FlightRect.position = Utility.ClampToScreen(this.FlightRect.position, this.FlightRect.size); + } + else + { + DrawStages(int.MinValue); + } + } + + private void DrawStages(int id) + { + DrawStagesHeader(); + + List stages = (List)this.Entries.Find(entry => entry.Name == "Stage Info").EntryValue; + + int stageCount = stages?.Count ?? 0; + if (stages != null && stageCount > 0) + { + float highestTwr = Mathf.Floor(stages.Max(stage => stage.TWRActual)); + int preDecimalDigits = Mathf.FloorToInt(Mathf.Log10(highestTwr)) + 1; + string twrFormatString = "N2"; + + if (preDecimalDigits == 3) + { + twrFormatString = "N1"; + } + else if (preDecimalDigits == 4) + { + twrFormatString = "N0"; + } + + int numberOfNonEmptyStagesToDraw = stages.Where(s => s.DeltaVinVac > 0.0001 || s.DeltaVatASL > 0.0001).Count(); + int stageBeingDrawn = 0; + for (int i = stages.Count - 1; i >= 0; i--) + { + DeltaVStageInfo stageInfo = stages[i]; + if (stageInfo.DeltaVinVac > 0.0001 || stageInfo.DeltaVatASL > 0.0001) + { + GUIStyle style = stageBeingDrawn++ < numberOfNonEmptyStagesToDraw - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; + int stageNum = stageCount - stageInfo.Stage; + DrawStageEntry(style, stageNum, stageInfo, twrFormatString); + } + } + } + + DrawSectionEnd(); + } + + private void DrawStagesHeader() + { + GUILayout.Space(10); + GUILayout.BeginHorizontal(); + GUILayout.Label($"{this.Name}", Styles.WindowTitleLabelStyle); + GUILayout.FlexibleSpace(); + GUILayout.Button(Styles.Settings15Texture, Styles.SettingsBtnStyle); + // If window is popped out and it's not locked => show the close button. If it's not popped out => show to popup arrow + this.IsFlightPoppedOut = this.IsFlightPoppedOut && !this.IsLocked ? !_ui.CloseButton(Styles.CloseBtnStyle) : !this.IsFlightPoppedOut ? GUILayout.Button(Styles.PopoutTexture, Styles.PopoutBtnStyle) : this.IsFlightPoppedOut; + GUILayout.EndHorizontal(); + GUILayout.Space(Styles.NegativeSpacingAfterHeader); + + GUILayout.BeginHorizontal(Styles.EntryBackground_First); + GUILayout.FlexibleSpace(); + GUILayout.Label("∆v", Styles.TableHeaderLabelStyle); + GUILayout.Space(16); + GUILayout.Label($"TWR", Styles.TableHeaderLabelStyle, GUILayout.Width(40)); + GUILayout.Space(16); + GUILayout.Label($"Burn", Styles.TableHeaderLabelStyle, GUILayout.Width(56)); + GUILayout.Space(5); + GUILayout.EndHorizontal(); + GUILayout.Space(Styles.NegativeSpacingAfterEntry); + } + + private void DrawStageEntry(GUIStyle horizontalStyle, int stageID, DeltaVStageInfo stageInfo, string twrFormatString) + { + GUILayout.BeginHorizontal(horizontalStyle); + GUILayout.Label($"{stageID:00.}", Styles.NameLabelStyle, GUILayout.Width(24)); + GUILayout.FlexibleSpace(); + GUILayout.Label($"{stageInfo.DeltaVActual:N0} m/s", Styles.ValueLabelStyle); + GUILayout.Space(16); + GUILayout.Label($"{stageInfo.TWRActual.ToString(twrFormatString)}", Styles.ValueLabelStyle, GUILayout.Width(40)); + GUILayout.Space(16); + string burnTime = Utility.SecondsToTimeString(stageInfo.StageBurnTime, false); + string lastUnit = "s"; + if (burnTime.Contains('h')) + { + burnTime = burnTime.Remove(burnTime.LastIndexOf("{lastUnit}", Styles.ValueLabelStyle, GUILayout.Width(56)); + GUILayout.EndHorizontal(); + GUILayout.Space(Styles.NegativeSpacingAfterEntry); + } + + private void DrawSectionEnd() + { + if (this.IsFlightPoppedOut) + { + if (!this.IsLocked) + GUI.DragWindow(new Rect(0, 0, Styles.WindowWidth, Styles.WindowHeight)); + + GUILayout.Space(Styles.SpacingBelowPopout); + } + else + { + GUILayout.Space(Styles.SpacingAfterSection); + } + } + } +} \ No newline at end of file diff --git a/MicroEngineerProject/Other/background.psd b/MicroEngineerProject/Other/background.psd new file mode 100644 index 0000000..6bace50 Binary files /dev/null and b/MicroEngineerProject/Other/background.psd differ diff --git a/MicroEngineerProject/Other/close-15.png b/MicroEngineerProject/Other/close-15.png new file mode 100644 index 0000000..60bd1c1 Binary files /dev/null and b/MicroEngineerProject/Other/close-15.png differ diff --git a/MicroEngineerProject/Other/close-15.psd b/MicroEngineerProject/Other/close-15.psd new file mode 100644 index 0000000..24aac17 Binary files /dev/null and b/MicroEngineerProject/Other/close-15.psd differ diff --git a/MicroEngineerProject/Other/decimalDigits.psd b/MicroEngineerProject/Other/decimalDigits.psd new file mode 100644 index 0000000..691ad76 Binary files /dev/null and b/MicroEngineerProject/Other/decimalDigits.psd differ diff --git a/MicroEngineerProject/Other/popout-15.png b/MicroEngineerProject/Other/popout-15.png new file mode 100644 index 0000000..2b4a4ef Binary files /dev/null and b/MicroEngineerProject/Other/popout-15.png differ diff --git a/MicroEngineerProject/Other/popout-15.psd b/MicroEngineerProject/Other/popout-15.psd new file mode 100644 index 0000000..a4d68e5 Binary files /dev/null and b/MicroEngineerProject/Other/popout-15.psd differ diff --git a/MicroEngineerProject/Other/settings-15.png b/MicroEngineerProject/Other/settings-15.png new file mode 100644 index 0000000..2813d86 Binary files /dev/null and b/MicroEngineerProject/Other/settings-15.png differ diff --git a/MicroEngineerProject/Other/settings-15.psd b/MicroEngineerProject/Other/settings-15.psd new file mode 100644 index 0000000..8580f4d Binary files /dev/null and b/MicroEngineerProject/Other/settings-15.psd differ diff --git a/MicroEngineerProject/Other/settings-30.psd b/MicroEngineerProject/Other/settings-30.psd new file mode 100644 index 0000000..a5345d8 Binary files /dev/null and b/MicroEngineerProject/Other/settings-30.psd differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_first.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_first.png new file mode 100644 index 0000000..71e4ebb Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_first.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_last.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_last.png new file mode 100644 index 0000000..b3f331e Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_last.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_middle.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_middle.png new file mode 100644 index 0000000..e1c4486 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_black_middle.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_first.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_first.png new file mode 100644 index 0000000..f6841d4 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_first.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_last.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_last.png new file mode 100644 index 0000000..06b5f66 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_last.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_middle.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_middle.png new file mode 100644 index 0000000..ab73bf2 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_darkgray_middle.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_first.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_first.png new file mode 100644 index 0000000..bb0122e Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_first.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_last.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_last.png new file mode 100644 index 0000000..261db87 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_last.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_middle.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_middle.png new file mode 100644 index 0000000..4f495dc Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/background_white_middle.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/close-15.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/close-15.png new file mode 100644 index 0000000..60bd1c1 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/close-15.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/decrease-decimal-19.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/decrease-decimal-19.png new file mode 100644 index 0000000..749a41d Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/decrease-decimal-19.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/icon.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/icon.png index 4136552..f39df0c 100644 Binary files a/Staging/BepInEx/plugins/micro_engineer/assets/images/icon.png and b/Staging/BepInEx/plugins/micro_engineer/assets/images/icon.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/increase-decimal-19.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/increase-decimal-19.png new file mode 100644 index 0000000..cacdc4d Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/increase-decimal-19.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/popout-15.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/popout-15.png new file mode 100644 index 0000000..2b4a4ef Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/popout-15.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-15.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-15.png new file mode 100644 index 0000000..2813d86 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-15.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-20.png b/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-20.png new file mode 100644 index 0000000..656d942 Binary files /dev/null and b/Staging/BepInEx/plugins/micro_engineer/assets/images/settings-20.png differ diff --git a/Staging/BepInEx/plugins/micro_engineer/swinfo.json b/Staging/BepInEx/plugins/micro_engineer/swinfo.json index 5a87043..24c59de 100644 --- a/Staging/BepInEx/plugins/micro_engineer/swinfo.json +++ b/Staging/BepInEx/plugins/micro_engineer/swinfo.json @@ -4,7 +4,8 @@ "name": "Micro Engineer", "description": "Get in-flight and VAB information about your current vessel", "source": "https://github.com/Micrologist/MicroEngineer", - "version": "0.8.0", + "version": "1.0.0", + "version_check": "https://raw.githubusercontent.com/Falki-git/MicroEngineer/main/Staging/BepInEx/plugins/micro_engineer/swinfo.json", "dependencies": [ { "id": "SpaceWarp",