VOID_EditorTWR: Works fine in flight but goes belly-up in the editor. What gives?
--- a/VOID.csproj
+++ b/VOID.csproj
@@ -94,6 +94,7 @@
<Compile Include="VOID_Localization.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VOID_HUDAdvanced.cs" />
+ <Compile Include="VOID_EditorTWR.cs" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
--- /dev/null
+++ b/VOID_EditorTWR.cs
@@ -1,1 +1,187 @@
+// VOID © 2014 toadicus
+//
+// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
+// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
+using KSP;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ToadicusTools;
+using UnityEngine;
+
+namespace VOID
+{
+ public class VOID_EditorTWR : VOID_WindowModule, IVOID_EditorModule
+ {
+ private Dictionary<string, double> bodyGeeValues;
+ private List<CelestialBody> sortedBodyList;
+
+ public VOID_EditorTWR() : base()
+ {
+ this._Name = "IP Thrust-to-Weight Ratios";
+ }
+
+ public override void ModuleWindow(int _)
+ {
+ if (Event.current.type != EventType.Layout)
+ {
+ return;
+ }
+
+ Engineer.VesselSimulator.SimManager.RequestSimulation();
+
+ GUILayout.Label(
+ this._Name,
+ VOID_EditorCore.Instance.LabelStyles["center_bold"],
+ GUILayout.ExpandWidth(true));
+
+ if (bodyGeeValues == null)
+ {
+ if (FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
+ {
+ this.bodyGeeValues = new Dictionary<string, double>();
+
+ foreach (CelestialBody body in FlightGlobals.Bodies)
+ {
+ this.bodyGeeValues[body.name] = body.GeeASL;
+ }
+
+ this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
+ this.sortedBodyList.Sort(new CBListComparer());
+ this.sortedBodyList.Reverse();
+
+ Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
+ }
+ else
+ {
+ GUILayout.BeginVertical();
+ GUILayout.BeginHorizontal();
+ GUILayout.Label("Unavailable.");
+ GUILayout.EndHorizontal();
+ GUILayout.EndVertical();
+ }
+ }
+ else
+ {
+ GUILayout.BeginVertical();
+
+ foreach (CelestialBody body in this.sortedBodyList)
+ {
+ Tools.PostDebugMessage(this, "Doing label for {0}", body.bodyName);
+ GUILayout.BeginHorizontal();
+
+ GUILayout.Label(body.bodyName);
+ GUILayout.FlexibleSpace();
+ GUILayout.Label(
+ (VOID_Data.currThrustWeight.Value / this.bodyGeeValues[body.bodyName]).ToString("0.0##"),
+ GUILayout.ExpandWidth(true)
+ );
+
+ GUILayout.EndHorizontal();
+ }
+
+ GUILayout.EndVertical();
+ }
+
+ GUI.DragWindow();
+ }
+ }
+
+ public class CBListComparer : IComparer<CelestialBody>
+ {
+ public int Compare(CelestialBody bodyA, CelestialBody bodyB)
+ {
+ Tools.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB);
+
+ if (bodyA == null && bodyB == null)
+ {
+ Tools.PostDebugMessage(this, "both bodies are null, returning 0");
+ return 0;
+ }
+ if (bodyA == null)
+ {
+ Tools.PostDebugMessage(this, "bodyA is null, returning -1");
+ return -1;
+ }
+ if (bodyB == null)
+ {
+ Tools.PostDebugMessage(this, "bodyB is null, returning 1");
+ return 1;
+ }
+
+ Tools.PostDebugMessage(this, "bodies are not null, carrying on");
+
+ if (object.ReferenceEquals(bodyA, bodyB))
+ {
+ Tools.PostDebugMessage(this, "bodies are equal, returning 0");
+ return 0;
+ }
+
+ Tools.PostDebugMessage(this, "bodies are not equal, carrying on");
+
+ if (bodyA.orbitDriver == null)
+ {
+ Tools.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1");
+ return 1;
+ }
+ if (bodyB.orbitDriver == null)
+ {
+ Tools.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1");
+ return -1;
+ }
+
+ Tools.PostDebugMessage(this, "orbits are not null, carrying on");
+
+ if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody)
+ {
+ Tools.PostDebugMessage(this, "bodies share a parent, comparing SMAs");
+ return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis);
+ }
+
+ Tools.PostDebugMessage(this, "orbits do not share a parent, carrying on");
+
+ if (bodyA.hasAncestor(bodyB))
+ {
+ Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1");
+ return -1;
+ }
+ if (bodyB.hasAncestor(bodyA))
+ {
+ Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1");
+ return 1;
+ }
+
+ Tools.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one");
+
+ if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB))
+ {
+ Tools.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName);
+ return this.Compare(bodyA, bodyB);
+ }
+
+ Tools.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName);
+
+ return 0;
+ }
+ }
+
+ public static partial class VOID_Data
+ {
+ public static readonly VOID_DoubleValue nominalThrustWeight = new VOID_DoubleValue(
+ "Thrust-to-Weight Ratio",
+ delegate()
+ {
+ if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
+ {
+ return maxThrustWeight.Value;
+ }
+
+ return currThrustWeight.Value;
+ },
+ ""
+ );
+ }
+}
+
+
--- a/VOID_HUDAdvanced.cs
+++ b/VOID_HUDAdvanced.cs
@@ -134,7 +134,7 @@
VOID_Data.vesselAngularVelocity.ToSIString(2)
);
- if (VOID_Data.stageNominalThrust != 0)
+ if (VOID_Data.stageNominalThrust != 0d)
{
leftHUD.AppendFormat(
string.Intern("Thrust Offset: {0}\n"),
@@ -239,7 +239,7 @@
this.leftHUDPos.value = GUI.Window(
VOID_Core.Instance.windowID,
this.leftHUDPos,
- this.leftHUDWindow,
+ VOID_Tools.GetWindowHandler(this.leftHUDWindow),
GUIContent.none,
GUIStyle.none
);
@@ -249,7 +249,7 @@
this.rightHUDPos.value = GUI.Window(
VOID_Core.Instance.windowID,
this.rightHUDPos,
- this.rightHUDWindow,
+ VOID_Tools.GetWindowHandler(this.leftHUDWindow),
GUIContent.none,
GUIStyle.none
);
--- a/VOID_Module.cs
+++ b/VOID_Module.cs
@@ -214,42 +214,7 @@
protected float defWidth = 250f;
protected float defHeight = 50f;
- public virtual void ModuleWindow(int _)
- {
-// if (VOID_Core.Instance.updateTimer - this.lastUpdate > VOID_Core.Instance.updatePeriod) {
-// foreach (var fieldinfo in this.GetType().GetFields(
-// BindingFlags.Instance |
-// BindingFlags.NonPublic |
-// BindingFlags.Public |
-// BindingFlags.FlattenHierarchy
-// ))
-// {
-// object field = null;
-//
-// try
-// {
-// field = fieldinfo.GetValue (this);
-// }
-// catch (NullReferenceException) {
-// Tools.PostDebugMessage(string.Format(
-// "{0}: caught NullReferenceException, could not get value for field {1}.",
-// this.GetType().Name,
-// fieldinfo.Name
-// ));
-// }
-//
-// if (field == null) {
-// continue;
-// }
-//
-// if (typeof(IVOID_DataValue).IsAssignableFrom (field.GetType ())) {
-// (field as IVOID_DataValue).Refresh ();
-// }
-// }
-//
-// this.lastUpdate = VOID_Core.Instance.updateTimer;
-// }
- }
+ public abstract void ModuleWindow(int _);
public override void DrawGUI()
{
--- a/VOID_Orbital.cs
+++ b/VOID_Orbital.cs
@@ -52,8 +52,6 @@
public override void ModuleWindow(int _)
{
- base.ModuleWindow (_);
-
int idx = 0;
GUILayout.BeginVertical();
--- a/VOID_SurfAtmo.cs
+++ b/VOID_SurfAtmo.cs
@@ -49,8 +49,6 @@
public override void ModuleWindow(int _)
{
- base.ModuleWindow (_);
-
int idx = 0;
GUILayout.BeginVertical();
--- a/VOID_Tools.cs
+++ b/VOID_Tools.cs
@@ -28,12 +28,71 @@
using KSP;
using System;
+using System.Collections.Generic;
using UnityEngine;
namespace VOID
{
public static partial class VOID_Tools
{
+ #region CelestialBody Utilities
+ public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB)
+ {
+ if (bodyA == null || bodyB == null)
+ {
+ return false;
+ }
+
+ while (bodyA.orbitDriver != null)
+ {
+ if (bodyA.orbit.referenceBody == bodyB)
+ {
+ return true;
+ }
+
+ bodyA = bodyA.orbit.referenceBody;
+ }
+
+ return false;
+ }
+
+ public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB)
+ {
+ if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null)
+ {
+ throw new ArgumentException(string.Concat(
+ "CelestialBody::FindRelatedParents: ",
+ "Neither body may be null, and both bodies must have orbits."
+ ));
+ }
+
+ CelestialBody a, b;
+
+ a = bodyA;
+
+ while (bodyA.orbitDriver != null)
+ {
+ b = bodyB;
+
+ while (b.orbitDriver != null)
+ {
+ if (a.orbit.referenceBody == b.orbit.referenceBody)
+ {
+ bodyA = a;
+ bodyB = b;
+ return true;
+ }
+
+ b = b.orbit.referenceBody;
+ }
+
+ a = a.orbit.referenceBody;
+ }
+
+ return false;
+ }
+ #endregion
+
#region VESSEL_EXTENSIONS_SCIENCE
public static CBAttributeMap.MapAttribute GetBiome(this Vessel vessel)
{
@@ -256,6 +315,39 @@
}
#endregion
+ private static Dictionary<int, GUI.WindowFunction> functionCache;
+ public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action<int> func)
+ {
+ if (functionCache == null)
+ {
+ functionCache = new Dictionary<int, GUI.WindowFunction>();
+ }
+
+ int hashCode = func.GetHashCode();
+
+ if (!functionCache.ContainsKey(hashCode))
+ {
+ functionCache[hashCode] = delegate (int id)
+ {
+ try
+ {
+ func(id);
+ }
+ catch (ArgumentException ex)
+ {
+ Debug.LogWarning(
+ string.Format("[{0}]: ArgumentException caught during window call.", func.Target.GetType().Name)
+ );
+ #if DEBUG
+ Debug.LogException(ex);
+ #endif
+ }
+ };
+ }
+
+ return functionCache[hashCode];
+ }
+
/// <summary>
/// Converts the interval given in seconds to a human-friendly
/// time period in [years], [days], hours, minutes, and seconds.
--- a/VOID_VesselInfo.cs
+++ b/VOID_VesselInfo.cs
@@ -48,8 +48,6 @@
public override void ModuleWindow(int _)
{
- base.ModuleWindow (_);
-
if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate))
{
SimManager.RequestSimulation();
@@ -127,7 +125,7 @@
return double.NaN;
}
- return SimManager.LastStage.totalBaseMass;
+ return SimManager.LastStage.totalMass - SimManager.LastStage.totalBaseMass;
},
"tons"
);