Actually added VOID_ConfigWindow, because apparently I forgot?
Actually added VOID_ConfigWindow, because apparently I forgot?

// VOID // VOID
// //
// IVOID_Core.cs // IVOID_Core.cs
// //
// Copyright © 2015, toadicus // Copyright © 2015, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public abstract class VOIDCore : VOID_Module, IVOID_Module public abstract class VOIDCore : VOID_WindowModule, IVOID_Module
{ {
public const double Constant_G = 6.674e-11; public const double Constant_G = 6.674e-11;
public const int CONFIG_VERSION = 2; public const int CONFIG_VERSION = 2;
   
public static bool useToolbarManager;  
   
public abstract int configVersion { get; } public abstract int configVersion { get; }
public virtual bool configNeedsUpdate { get; set; } public virtual bool configNeedsUpdate { get; set; }
   
public abstract int windowID { get; } public abstract int windowID { get; }
public abstract bool configDirty { get; set; } public abstract bool configDirty { get; set; }
public abstract bool powerAvailable { get; protected set; } public abstract bool powerAvailable { get; protected set; }
   
public abstract List<IVOID_Module> Modules { get; } public abstract List<IVOID_Module> Modules { get; }
   
public abstract float updateTimer { get; protected set; } public abstract float updateTimer { get; protected set; }
public abstract double updatePeriod { get; } public abstract double updatePeriod { get; }
   
public virtual float saveTimer { get; protected set; } public virtual float saveTimer { get; protected set; }
   
public abstract GUISkin Skin { get; } public abstract GUISkin Skin { get; }
   
public abstract CelestialBody HomeBody { get; } public abstract CelestialBody HomeBody { get; }
public abstract List<CelestialBody> allBodies { get; } public abstract List<CelestialBody> allBodies { get; }
public abstract List<CelestialBody> sortedBodyList { get; protected set; } public abstract List<CelestialBody> sortedBodyList { get; protected set; }
   
public abstract List<VesselType> allVesselTypes { get; } public abstract List<VesselType> allVesselTypes { get; }
   
public abstract Stage LastStage { get; protected set; } public abstract Stage LastStage { get; protected set; }
public abstract Stage[] Stages { get; protected set; } public abstract Stage[] Stages { get; protected set; }
   
public abstract event VOIDEventHandler onApplicationQuit; public abstract event VOIDEventHandler onApplicationQuit;
public abstract event VOIDEventHandler onSkinChanged; public abstract event VOIDEventHandler onSkinChanged;
   
public virtual void OnGUI() {} public virtual void OnGUI() {}
   
public override void LoadConfig() public override void LoadConfig()
{ {
var config = KSP.IO.PluginConfiguration.CreateForType<VOIDCore>(null);  
   
useToolbarManager = config.GetValue("UseToolbarManager", useToolbarManager);  
   
base.LoadConfig(); base.LoadConfig();
} }
   
public abstract void SaveConfig(); public abstract void SaveConfig();
   
public override void _SaveToConfig(KSP.IO.PluginConfiguration config) public override void _SaveToConfig(KSP.IO.PluginConfiguration config)
{ {
config.SetValue("UseToolbarManager", useToolbarManager);  
   
base._SaveToConfig(config); base._SaveToConfig(config);
} }
} }
   
public delegate void VOIDEventHandler(object sender); public delegate void VOIDEventHandler(object sender);
} }
   
   
// VOID // VOID
// //
// VOID_HUDModule.cs // VOID_HUDModule.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public abstract class VOID_HUDModule : VOID_Module public abstract class VOID_HUDModule : VOID_Module
{ {
[AVOID_SaveValue("colorIndex")] [AVOID_SaveValue("colorIndex")]
protected VOID_SaveValue<int> _colorIndex; protected VOID_SaveValue<int> _colorIndex;
   
protected List<Color> textColors; protected List<Color> textColors;
   
[AVOID_SaveValue("positionsLocked")] [AVOID_SaveValue("positionsLocked")]
protected VOID_SaveValue<bool> positionsLocked; protected VOID_SaveValue<bool> positionsLocked;
   
public virtual int ColorIndex public virtual int ColorIndex
{ {
get get
{ {
return this._colorIndex; return this._colorIndex;
} }
set set
{ {
if (this._colorIndex >= this.textColors.Count - 1) if (this._colorIndex >= this.textColors.Count - 1)
{ {
this._colorIndex = 0; this._colorIndex.value = 0;
return; return;
} }
   
this._colorIndex = value; this._colorIndex.value = value;
} }
} }
   
public virtual List<HUDWindow> Windows public virtual List<HUDWindow> Windows
{ {
get; get;
protected set; protected set;
} }
   
public VOID_HUDModule() : base() public VOID_HUDModule() : base()
{ {
this._colorIndex = 0; this._colorIndex = (VOID_SaveValue<int>)0;
   
this.textColors = new List<Color>(); this.textColors = new List<Color>();
   
this.textColors.Add(Color.green); this.textColors.Add(Color.green);
this.textColors.Add(Color.black); this.textColors.Add(Color.black);
this.textColors.Add(Color.white); this.textColors.Add(Color.white);
this.textColors.Add(Color.red); this.textColors.Add(Color.red);
this.textColors.Add(Color.blue); this.textColors.Add(Color.blue);
this.textColors.Add(Color.yellow); this.textColors.Add(Color.yellow);
this.textColors.Add(Color.gray); this.textColors.Add(Color.gray);
this.textColors.Add(Color.cyan); this.textColors.Add(Color.cyan);
this.textColors.Add(Color.magenta); this.textColors.Add(Color.magenta);
   
this.positionsLocked = true; this.positionsLocked = (VOID_SaveValue<bool>)true;
   
this.Windows = new List<HUDWindow>(); this.Windows = new List<HUDWindow>();
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex]; VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex];
   
GUI.skin = this.core.Skin; GUI.skin = this.core.Skin;
   
if (HighLogic.LoadedSceneIsEditor || if (HighLogic.LoadedSceneIsEditor ||
(TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate) (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
) )
{ {
SimManager.RequestSimulation(); SimManager.RequestSimulation();
} }
   
foreach (HUDWindow window in this.Windows) foreach (HUDWindow window in this.Windows)
{ {
window.WindowPos = GUILayout.Window( window.WindowPos = GUILayout.Window(
this.core.windowID, this.core.windowID,
window.WindowPos, window.WindowPos,
VOID_Tools.GetWindowHandler(window.WindowFunction), VOID_Tools.GetWindowHandler(window.WindowFunction),
GUIContent.none, GUIContent.none,
GUIStyle.none GUIStyle.none
); );
} }
} }
   
public override void DrawConfigurables() public override void DrawConfigurables()
{ {
base.DrawConfigurables(); base.DrawConfigurables();
   
if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false))) if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
{ {
++this.ColorIndex; ++this.ColorIndex;
} }
   
if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false))) if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
{ {
foreach (HUDWindow window in this.Windows) foreach (HUDWindow window in this.Windows)
{ {
window.WindowPos = new Rect(window.defaultWindowPos); window.WindowPos = new Rect(window.defaultWindowPos);
} }
} }
   
this.positionsLocked = GUILayout.Toggle(this.positionsLocked, this.positionsLocked.value = GUITools.Toggle(this.positionsLocked, "Lock HUD Positions");
string.Intern("Lock HUD Positions"),  
GUILayout.ExpandWidth(false));  
} }
   
public override void LoadConfig() public override void LoadConfig()
{ {
base.LoadConfig(); base.LoadConfig();
   
var config = KSP.IO.PluginConfiguration.CreateForType<VOID_HUDModule>(); var config = KSP.IO.PluginConfiguration.CreateForType<VOID_HUDModule>();
config.load(); config.load();
   
foreach (HUDWindow window in this.Windows) foreach (HUDWindow window in this.Windows)
{ {
string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName); string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName);
Rect loadedPos = config.GetValue(saveName, window.defaultWindowPos); Rect loadedPos = config.GetValue(saveName, window.defaultWindowPos);
   
window.WindowPos = loadedPos; window.WindowPos = loadedPos;
} }
} }
   
public override void _SaveToConfig(KSP.IO.PluginConfiguration config) public override void _SaveToConfig(KSP.IO.PluginConfiguration config)
{ {
base._SaveToConfig(config); base._SaveToConfig(config);
   
foreach (HUDWindow window in this.Windows) foreach (HUDWindow window in this.Windows)
{ {
string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName); string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName);
config.SetValue(saveName, window.WindowPos); config.SetValue(saveName, window.WindowPos);
} }
} }
} }
   
public class HUDWindow public class HUDWindow
{ {
public readonly Rect defaultWindowPos; public readonly Rect defaultWindowPos;
   
private Rect _windowPos; private Rect _windowPos;
   
public Action<int> WindowFunction public Action<int> WindowFunction
{ {
get; get;
private set; private set;
} }
   
public Rect WindowPos public Rect WindowPos
{ {
get get
{ {
return this._windowPos; return this._windowPos;
} }
set set
{ {
if (value != this._windowPos) if (value != this._windowPos)
{ {
this._windowPos = value; this._windowPos = value;
   
if (VOID_Data.Core != null) if (VOID_Data.Core != null)
{ {
VOID_Data.Core.configDirty = true; VOID_Data.Core.configDirty = true;
} }
} }
} }
} }
   
public string WindowName public string WindowName
{ {
get; get;
private set; private set;
} }
   
private HUDWindow() {} private HUDWindow() {}
   
public HUDWindow(string name, Action<int> windowFunc, Rect defaultPos) public HUDWindow(string name, Action<int> windowFunc, Rect defaultPos)
{ {
this.WindowName = name; this.WindowName = name;
this.WindowFunction = windowFunc; this.WindowFunction = windowFunc;
this.defaultWindowPos = defaultPos; this.defaultWindowPos = defaultPos;
this.WindowPos = new Rect(this.defaultWindowPos); this.WindowPos = new Rect(this.defaultWindowPos);
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_Module.cs // VOID_Module.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public abstract class VOID_Module : IVOID_Module public abstract class VOID_Module : IVOID_Module
{ {
/* /*
* Fields * Fields
* */ * */
[AVOID_SaveValue("Active")] [AVOID_SaveValue("Active")]
protected VOID_SaveValue<bool> _Active = false; protected VOID_SaveValue<bool> _Active = (VOID_SaveValue<bool>)false;
private GameScenes[] validScenes; private GameScenes[] validScenes;
private Game.Modes[] validModes; private Game.Modes[] validModes;
   
protected float lastUpdate = 0; protected float lastUpdate = 0;
   
/* /*
* Properties * Properties
* */ * */
protected virtual VOIDCore core protected virtual VOIDCore core
{ {
get get
{ {
return VOID_Data.Core; return VOID_Data.Core;
} }
} }
   
protected virtual bool timeToUpdate protected virtual bool timeToUpdate
{ {
get get
{ {
return ( return (
(this.core.updateTimer - this.lastUpdate) > this.core.updatePeriod || (this.core.updateTimer - this.lastUpdate) > this.core.updatePeriod ||
this.lastUpdate > this.core.updateTimer this.lastUpdate > this.core.updateTimer
); );
} }
} }
   
public virtual bool toggleActive public virtual bool toggleActive
{ {
get get
{ {
return this._Active && this.inValidGame && this.inValidScene; return this._Active && this.inValidGame && this.inValidScene;
} }
set set
{ {
this._Active = value && this.inValidGame && this.inValidScene; this._Active.value = value && this.inValidGame && this.inValidScene;
} }
} }
   
public virtual bool guiRunning public virtual bool guiRunning
{ {
get get
{ {
if ( if (
RenderingManager.fetch == null || RenderingManager.fetch == null ||
RenderingManager.fetch.postDrawQueue == null || RenderingManager.fetch.postDrawQueue == null ||
RenderingManager.fetch.postDrawQueue.Length < 4 RenderingManager.fetch.postDrawQueue.Length < 4
) )
{ {
return false; return false;
} }
else else
{ {
Delegate callback = RenderingManager.fetch.postDrawQueue[3]; Delegate callback = RenderingManager.fetch.postDrawQueue[3];
if (callback == null) if (callback == null)
{ {
return false; return false;
} }
   
return callback.GetInvocationList().Contains((Callback)this.DrawGUI); return callback.GetInvocationList().Contains((Callback)this.DrawGUI);
} }
} }
} }
   
public virtual GameScenes[] ValidScenes public virtual GameScenes[] ValidScenes
{ {
get get
{ {
if (this.validScenes == null) if (this.validScenes == null)
{ {
Tools.PostDebugMessage(this, "validScenes is null when checking inValidScene; fetching attribute."); Tools.PostDebugMessage(this, "validScenes is null when checking inValidScene; fetching attribute.");
foreach (var attr in this.GetType().GetCustomAttributes(false)) foreach (var attr in this.GetType().GetCustomAttributes(false))
{ {
if (attr is VOID_ScenesAttribute) if (attr is VOID_ScenesAttribute)
{ {
VOID_ScenesAttribute addonAttr = (VOID_ScenesAttribute)attr; VOID_ScenesAttribute addonAttr = (VOID_ScenesAttribute)attr;
   
this.validScenes = addonAttr.ValidScenes; this.validScenes = addonAttr.ValidScenes;
   
Tools.PostDebugMessage("Found VOID_ScenesAttribute; validScenes set."); Tools.PostDebugMessage("Found VOID_ScenesAttribute; validScenes set.");
   
break; break;
} }
} }
   
if (this.validScenes == null) if (this.validScenes == null)
{ {
this.validScenes = new GameScenes[] { GameScenes.FLIGHT }; this.validScenes = new GameScenes[] { GameScenes.FLIGHT };
Tools.PostDebugMessage("No VOID_ScenesAttribute found; validScenes defaulted to flight."); Tools.PostDebugMessage("No VOID_ScenesAttribute found; validScenes defaulted to flight.");
} }
} }
   
return this.validScenes; return this.validScenes;
} }
} }
   
public virtual bool inValidScene public virtual bool inValidScene
{ {
get get
{ {
   
Tools.PostDebugMessage(  
this,  
"Checking if scene is valid: LoadedScene={0}, ValidScenes={1}, inValidScene={2}",  
Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene),  
string.Join(", ", this.ValidScenes.Select(s => Enum.GetName(typeof(GameScenes), s)).ToArray()),  
this.ValidScenes.Contains(HighLogic.LoadedScene)  
);  
   
return this.ValidScenes.Contains(HighLogic.LoadedScene); return this.ValidScenes.Contains(HighLogic.LoadedScene);
} }
} }
   
public virtual Game.Modes[] ValidModes public virtual Game.Modes[] ValidModes
{ {
get get
{ {
if (this.validModes == null) if (this.validModes == null)
{ {
Tools.PostDebugMessage(this, "validModes is null when checking inValidGame; fetching attribute."); Tools.PostDebugMessage(this, "validModes is null when checking inValidGame; fetching attribute.");
foreach (var attr in this.GetType().GetCustomAttributes(false)) foreach (var attr in this.GetType().GetCustomAttributes(false))
{ {
if (attr is VOID_GameModesAttribute) if (attr is VOID_GameModesAttribute)
{ {
VOID_GameModesAttribute addonAttr = (VOID_GameModesAttribute)attr; VOID_GameModesAttribute addonAttr = (VOID_GameModesAttribute)attr;
   
this.validModes = addonAttr.ValidModes; this.validModes = addonAttr.ValidModes;
   
Tools.PostDebugMessage("Found VOID_GameModesAttribute; validScenes set."); Tools.PostDebugMessage("Found VOID_GameModesAttribute; validScenes set.");
   
break; break;
} }
} }
   
if (this.validModes == null) if (this.validModes == null)
{ {
this.validModes = new Game.Modes[] this.validModes = new Game.Modes[]
{ {
Game.Modes.CAREER, Game.Modes.CAREER,
Game.Modes.SANDBOX, Game.Modes.SANDBOX,
Game.Modes.SCENARIO, Game.Modes.SCENARIO,
Game.Modes.SCENARIO_NON_RESUMABLE, Game.Modes.SCENARIO_NON_RESUMABLE,
Game.Modes.SCIENCE_SANDBOX Game.Modes.SCIENCE_SANDBOX
}; };
   
Tools.PostDebugMessage("No VOID_GameModesAttribute found; validScenes defaulted to flight."); Tools.PostDebugMessage("No VOID_GameModesAttribute found; validScenes defaulted to flight.");
} }
} }
   
return this.validModes; return this.validModes;
} }
} }
   
public virtual bool inValidGame public virtual bool inValidGame
{ {
get get
{ {
   
Tools.PostDebugMessage(  
this,  
"Checking if mode is valid: CurrentGame.Mode={0}, ValidModes={1}, inValidGame={2}",  
Enum.GetName(typeof(Game.Modes), HighLogic.CurrentGame.Mode),  
string.Join(", ", this.ValidModes.Select(m => Enum.GetName(typeof(Game.Modes), m)).ToArray()),  
this.ValidModes.Contains(HighLogic.CurrentGame.Mode)  
);  
   
return this.ValidModes.Contains(HighLogic.CurrentGame.Mode); return this.ValidModes.Contains(HighLogic.CurrentGame.Mode);
} }
} }
   
public virtual string Name public virtual string Name
{ {
get; get;
protected set; protected set;
} }
   
public virtual Vessel vessel public virtual Vessel vessel
{ {
get get
{ {
return FlightGlobals.ActiveVessel; return FlightGlobals.ActiveVessel;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public void StartGUI() public virtual void StartGUI()
{ {
if (!this.toggleActive || this.guiRunning) if (!this.toggleActive || this.guiRunning)
{ {
return; return;
} }
   
Tools.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name)); Tools.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name));
RenderingManager.AddToPostDrawQueue (3, this.DrawGUI); RenderingManager.AddToPostDrawQueue (3, this.DrawGUI);
} }
   
public void StopGUI() public virtual void StopGUI()
{ {
if (!this.guiRunning) if (!this.guiRunning)
{ {
return; return;
} }
Tools.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name)); Tools.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name));
RenderingManager.RemoveFromPostDrawQueue (3, this.DrawGUI); RenderingManager.RemoveFromPostDrawQueue (3, this.DrawGUI);
} }
   
public abstract void DrawGUI(); public abstract void DrawGUI();
   
public virtual void DrawConfigurables() {} public virtual void DrawConfigurables() {}
   
public virtual void LoadConfig() public virtual void LoadConfig()
{ {
var config = KSP.IO.PluginConfiguration.CreateForType<VOID_Module> (); var config = KSP.IO.PluginConfiguration.CreateForType<VOID_Module> ();
config.load (); config.load ();
   
if (this is VOIDCore) if (this is VOIDCore)
{ {
int configVersion = config.GetValue("VOID_Core_configValue", 2); int configVersion = config.GetValue("VOID_Core_configValue", 2);
   
if (configVersion < VOIDCore.CONFIG_VERSION) if (configVersion < VOIDCore.CONFIG_VERSION)
{ {
((VOIDCore)this).configNeedsUpdate = true; ((VOIDCore)this).configNeedsUpdate = true;
} }
} }
   
foreach (var field in this.GetType().GetMembers( foreach (var field in this.GetType().GetMembers(
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Public |
BindingFlags.Instance | BindingFlags.Instance |
BindingFlags.FlattenHierarchy BindingFlags.FlattenHierarchy
)) ))
{ {
if (!(field is FieldInfo || field is PropertyInfo)) if (!(field is FieldInfo || field is PropertyInfo))
{ {
continue; continue;
} }
   
if (field is PropertyInfo && (field as PropertyInfo).GetIndexParameters().Length > 0) if (field is PropertyInfo && (field as PropertyInfo).GetIndexParameters().Length > 0)
{ {
continue; continue;
} }
   
object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false); object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false);
   
if (attrs.Length == 0) { if (attrs.Length == 0) {
continue; continue;
} }
   
AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue; AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue;
   
string fieldName = string.Empty; string fieldName = string.Empty;
   
if (this is VOIDCore || this.core.configNeedsUpdate) if (this is VOIDCore || this.core.configNeedsUpdate)
{ {
string typeName = this.GetType().Name;; string typeName = this.GetType().Name;;
   
if (this is VOIDCore && ((VOIDCore)this).configNeedsUpdate) if (this is VOIDCore && ((VOIDCore)this).configNeedsUpdate)
{ {
if (this is VOIDCore_Flight) if (this is VOIDCore_Flight)
{ {
typeName = "VOID_Core"; typeName = "VOID_Core";
} }
else if (this is VOIDCore_Editor) else if (this is VOIDCore_Editor)
{ {
typeName = "VOID_EditorCore"; typeName = "VOID_EditorCore";
} }
} }
   
fieldName = string.Format("{0}_{1}", typeName, attr.Name); fieldName = string.Format("{0}_{1}", typeName, attr.Name);
} }
else else
{ {
fieldName = string.Format( fieldName = string.Format(
"{0}_{1}_{2}", "{0}_{1}_{2}",
this.GetType().Name, this.GetType().Name,
Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene), Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene),
attr.Name attr.Name
); );
} }
   
Tools.PostDebugMessage(string.Format("{0}: Loading field {1}.", this.GetType().Name, fieldName)); Tools.PostDebugMessage(string.Format("{0}: Loading field {1}.", this.GetType().Name, fieldName));
   
object fieldValue; object fieldValue;
   
if (field is FieldInfo) if (field is FieldInfo)
{ {
fieldValue = (field as FieldInfo).GetValue(this); fieldValue = (field as FieldInfo).GetValue(this);
} }
else else
{ {
fieldValue = (field as PropertyInfo).GetValue(this, null); fieldValue = (field as PropertyInfo).GetValue(this, null);
} }
   
bool convertBack = false; bool convertBack = false;
if (fieldValue is IVOID_SaveValue) if (fieldValue is IVOID_SaveValue)
{ {
fieldValue = (fieldValue as IVOID_SaveValue).value; fieldValue = (fieldValue as IVOID_SaveValue).value;
convertBack = true; convertBack = true;
} }
   
fieldValue = config.GetValue(fieldName, fieldValue); fieldValue = config.GetValue(fieldName, fieldValue);
   
if (convertBack) if (convertBack)
{ {
Type type = typeof(VOID_SaveValue<>).MakeGenericType (fieldValue.GetType ()); Type type = typeof(VOID_SaveValue<>).MakeGenericType (fieldValue.GetType ());
IVOID_SaveValue convertValue = Activator.CreateInstance (type) as IVOID_SaveValue; IVOID_SaveValue convertValue = Activator.CreateInstance (type) as IVOID_SaveValue;
convertValue.SetValue (fieldValue); convertValue.SetValue (fieldValue);
fieldValue = convertValue; fieldValue = convertValue;
} }
   
if (field is FieldInfo) if (field is FieldInfo)
{ {
(field as FieldInfo).SetValue(this, fieldValue); (field as FieldInfo).SetValue(this, fieldValue);
} }
else else
{ {
(field as PropertyInfo).SetValue(this, fieldValue, null); (field as PropertyInfo).SetValue(this, fieldValue, null);
} }
   
Tools.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName)); Tools.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName));
} }
} }
   
public virtual void _SaveToConfig(KSP.IO.PluginConfiguration config) public virtual void _SaveToConfig(KSP.IO.PluginConfiguration config)
{ {
foreach (var field in this.GetType().GetMembers( foreach (var field in this.GetType().GetMembers(
BindingFlags.Instance | BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Public |
BindingFlags.FlattenHierarchy BindingFlags.FlattenHierarchy
)) ))
{ {
object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false); object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false);
   
if (attrs.Length == 0) { if (attrs.Length == 0) {
continue; continue;
} }
   
AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue; AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue;
   
string fieldName; string fieldName;
   
if (this is VOIDCore) if (this is VOIDCore)
{ {
fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name); fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name);
} }
else else
{ {
fieldName = string.Format( fieldName = string.Format(
"{0}_{1}_{2}", "{0}_{1}_{2}",
this.GetType().Name, this.GetType().Name,
Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene), Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene),
attr.Name attr.Name
); );
} }
   
object fieldValue; object fieldValue;
   
if (field is FieldInfo) if (field is FieldInfo)
{ {
fieldValue = (field as FieldInfo).GetValue(this); fieldValue = (field as FieldInfo).GetValue(this);
} }
else else
{ {
fieldValue = (field as PropertyInfo).GetValue(this, null); fieldValue = (field as PropertyInfo).GetValue(this, null);
} }
   
if (fieldValue is IVOID_SaveValue) if (fieldValue is IVOID_SaveValue)
{ {
fieldValue = (fieldValue as IVOID_SaveValue).value; fieldValue = (fieldValue as IVOID_SaveValue).value;
} }
   
config.SetValue(fieldName, fieldValue); config.SetValue(fieldName, fieldValue);
   
Tools.PostDebugMessage(string.Format("{0}: Saved field {1}.", this.GetType().Name, fieldName)); Tools.PostDebugMessage(string.Format("{0}: Saved field {1}.", this.GetType().Name, fieldName));
} }
} }
} }
   
public abstract class VOID_WindowModule : VOID_Module public abstract class VOID_WindowModule : VOID_Module
{ {
[AVOID_SaveValue("WindowPos")] [AVOID_SaveValue("WindowPos")]
protected Rect WindowPos; protected Rect WindowPos;
protected float defWidth; protected float defWidth;
protected float defHeight; protected float defHeight;
   
  protected bool decorateWindow;
   
protected string inputLockName; protected string inputLockName;
   
public VOID_WindowModule() : base() public VOID_WindowModule() : base()
{ {
this.defWidth = 250f; this.defWidth = 250f;
this.defHeight = 50f; this.defHeight = 50f;
   
  this.decorateWindow = true;
   
this.inputLockName = string.Concat(this.Name, "_edlock"); this.inputLockName = string.Concat(this.Name, "_edlock");
   
this.WindowPos = new Rect(Screen.width / 2, Screen.height / 2, this.defWidth, this.defHeight); this.WindowPos = new Rect(Screen.width / 2, Screen.height / 2, this.defWidth, this.defHeight);
} }
   
public abstract void ModuleWindow(int _); public virtual void ModuleWindow(int id)
  {
  GUIStyle buttonStyle = this.core.Skin.button;
  RectOffset padding = buttonStyle.padding;
  RectOffset border = buttonStyle.border;
   
  Rect closeRect = new Rect(
  0f,
  0f,
  border.left + border.right,
  border.top + border.bottom
  );
   
  closeRect.width = Mathf.Max(closeRect.width, 16f);
  closeRect.height = Mathf.Max(closeRect.height, 16f);
   
  closeRect.x = this.WindowPos.width - closeRect.width - 2f;
  closeRect.y = 2f;
   
  GUI.Button(closeRect, GUIContent.none, buttonStyle);
   
  if (Event.current.type == EventType.repaint && Input.GetMouseButtonUp(0))
  {
  if (closeRect.Contains(Event.current.mousePosition))
  {
  this.toggleActive = false;
  }
  }
   
  GUI.DragWindow();
  }
   
public override void DrawGUI() public override void DrawGUI()
{ {
GUI.skin = this.core.Skin; GUI.skin = this.core.Skin;
   
Rect _Pos = this.WindowPos; Rect _Pos = this.WindowPos;
   
_Pos = GUILayout.Window( _Pos = GUILayout.Window(
this.core.windowID, this.core.windowID,
_Pos, _Pos,
VOID_Tools.GetWindowHandler(this.ModuleWindow), VOID_Tools.GetWindowHandler(this.ModuleWindow),
this.Name, this.Name,
GUILayout.Width(this.defWidth), GUILayout.Width(this.defWidth),
GUILayout.Height(this.defHeight), GUILayout.Height(this.defHeight)
GUILayout.ExpandWidth(true),  
GUILayout.ExpandHeight(true)  
); );
   
bool cursorInWindow = _Pos.Contains(Mouse.screenPos); bool cursorInWindow = _Pos.Contains(Mouse.screenPos);
   
switch (HighLogic.LoadedScene) switch (HighLogic.LoadedScene)
{ {
case GameScenes.EDITOR: case GameScenes.EDITOR:
if (cursorInWindow) if (cursorInWindow)
{ {
InputLockManager.SetControlLock( InputLockManager.SetControlLock(
ControlTypes.EDITOR_ICON_HOVER | ControlTypes.EDITOR_ICON_PICK | ControlTypes.EDITOR_ICON_HOVER | ControlTypes.EDITOR_ICON_PICK |
ControlTypes.EDITOR_PAD_PICK_COPY | ControlTypes.EDITOR_PAD_PICK_COPY, ControlTypes.EDITOR_PAD_PICK_COPY | ControlTypes.EDITOR_PAD_PICK_COPY,
this.inputLockName this.inputLockName
); );
EditorLogic.fetch.Lock(false, false, false, this.inputLockName); EditorLogic.fetch.Lock(false, false, false, this.inputLockName);
} }
else else
{ {
EditorLogic.fetch.Unlock(this.inputLockName); EditorLogic.fetch.Unlock(this.inputLockName);
} }
break; break;
case GameScenes.FLIGHT: case GameScenes.FLIGHT:
if (cursorInWindow) if (cursorInWindow)
{ {
InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS, this.inputLockName); InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS, this.inputLockName);
} }
else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None) else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None)
{ {
InputLockManager.RemoveControlLock(this.inputLockName); InputLockManager.RemoveControlLock(this.inputLockName);
} }
break; break;
case GameScenes.SPACECENTER: case GameScenes.SPACECENTER:
if (cursorInWindow) if (cursorInWindow)
{ {
InputLockManager.SetControlLock( InputLockManager.SetControlLock(
ControlTypes.KSC_FACILITIES | ControlTypes.CAMERACONTROLS, ControlTypes.KSC_FACILITIES | ControlTypes.CAMERACONTROLS,
this.inputLockName this.inputLockName
); );
} }
else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None) else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None)
{ {
InputLockManager.RemoveControlLock(this.inputLockName); InputLockManager.RemoveControlLock(this.inputLockName);
} }
break; break;
} }
   
if (HighLogic.LoadedSceneIsEditor) if (HighLogic.LoadedSceneIsEditor)
{ {
_Pos = Tools.ClampRectToEditorPad(_Pos); _Pos = Tools.ClampRectToEditorPad(_Pos);
} }
else else
{ {
_Pos = Tools.ClampRectToScreen(_Pos); _Pos = Tools.ClampRectToScreen(_Pos);
} }
   
if (_Pos != this.WindowPos) if (_Pos != this.WindowPos)
{ {
this.WindowPos = _Pos; this.WindowPos = _Pos;
this.core.configDirty = true; this.core.configDirty = true;
} }
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_DataValue.cs // VOID_DataValue.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using System; using System;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_DataValue<T> : IVOID_DataValue public class VOID_DataValue<T> : IVOID_DataValue
{ {
/* /*
* Static Members * Static Members
* */ * */
public static implicit operator T(VOID_DataValue<T> v) public static implicit operator T(VOID_DataValue<T> v)
{ {
return (T)v.Value; return (T)v.Value;
} }
   
/* /*
* Instance Members * Instance Members
* */ * */
/* /*
* Fields * Fields
* */ * */
protected T cache; protected T cache;
protected Func<T> ValueFunc; protected Func<T> ValueFunc;
protected float lastUpdate; protected float lastUpdate;
   
/* /*
* Properties * Properties
* */ * */
public string Label { get; protected set; } public string Label { get; protected set; }
public string Units { get; protected set; } public string Units { get; protected set; }
   
object IVOID_DataValue.Value object IVOID_DataValue.Value
{ {
get get
{ {
return this.Value; return this.Value;
} }
} }
   
public T Value public T Value
{ {
get get
{ {
if ( if (
(VOID_Data.Core.updateTimer - this.lastUpdate > VOID_Data.Core.updatePeriod) || (VOID_Data.Core.updateTimer - this.lastUpdate > VOID_Data.Core.updatePeriod) ||
(this.lastUpdate > VOID_Data.Core.updateTimer) (this.lastUpdate > VOID_Data.Core.updateTimer)
) )
{ {
this.Refresh(); this.Refresh();
} }
return (T)this.cache; return (T)this.cache;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_DataValue(string Label, Func<T> ValueFunc, string Units = "") public VOID_DataValue(string Label, Func<T> ValueFunc, string Units = "")
{ {
this.Label = Label; this.Label = Label;
this.Units = Units; this.Units = Units;
this.ValueFunc = ValueFunc; this.ValueFunc = ValueFunc;
this.lastUpdate = 0; this.lastUpdate = 0;
   
VOID_Data.DataValues[this.GetHashCode()] = this; VOID_Data.DataValues[this.GetHashCode()] = this;
} }
   
public void Refresh() public void Refresh()
{ {
this.cache = this.ValueFunc.Invoke (); this.cache = this.ValueFunc.Invoke ();
this.lastUpdate = VOID_Data.Core.updateTimer; this.lastUpdate = VOID_Data.Core.updateTimer;
} }
   
public T GetFreshValue() public T GetFreshValue()
{ {
this.Refresh (); this.Refresh ();
return (T)this.cache; return (T)this.cache;
} }
   
public virtual string ValueUnitString() { public virtual string ValueUnitString() {
return this.Value.ToString() + this.Units; return this.Value.ToString() + this.Units;
} }
   
public virtual void DoGUIHorizontal() public virtual void DoGUIHorizontal()
{ {
GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
GUILayout.Label (this.Label + ":"); GUILayout.Label (this.Label + ":");
GUILayout.FlexibleSpace (); GUILayout.FlexibleSpace ();
GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false)); GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false));
GUILayout.EndHorizontal (); GUILayout.EndHorizontal ();
} }
   
public override int GetHashCode() public override int GetHashCode()
{ {
int hash; int hash;
unchecked unchecked
{ {
hash = 79999; hash = 79999;
   
hash = hash * 104399 + this.Label.GetHashCode(); hash = hash * 104399 + this.Label.GetHashCode();
hash = hash * 104399 + this.ValueFunc.GetHashCode(); hash = hash * 104399 + this.ValueFunc.GetHashCode();
hash = hash * 104399 + this.Units.GetHashCode(); hash = hash * 104399 + this.Units.GetHashCode();
} }
   
return hash; return hash;
} }
   
public override string ToString() public override string ToString()
{ {
return string.Format ( return string.Format (
"{0}: {1}{2}", "{0}: {1}{2}",
this.Label, this.Label,
this.Value.ToString (), this.Value.ToString (),
this.Units this.Units
); );
} }
} }
   
public abstract class VOID_NumValue<T> : VOID_DataValue<T> public abstract class VOID_NumValue<T> : VOID_DataValue<T>, IFormattable
where T : IFormattable, IConvertible, IComparable where T : IFormattable, IConvertible, IComparable
{ {
  public static IFormatProvider formatProvider = Tools.SIFormatter;
   
public static implicit operator Double(VOID_NumValue<T> v) public static implicit operator Double(VOID_NumValue<T> v)
{ {
return v.ToDouble(); return v.ToDouble();
} }
   
public static implicit operator Int32(VOID_NumValue<T> v) public static implicit operator Int32(VOID_NumValue<T> v)
{ {
return v.ToInt32(); return v.ToInt32();
} }
   
   
public static implicit operator Single(VOID_NumValue<T> v) public static implicit operator Single(VOID_NumValue<T> v)
{ {
return v.ToSingle(); return v.ToSingle();
} }
   
protected IFormatProvider formatProvider;  
   
public VOID_NumValue(string Label, Func<T> ValueFunc, string Units = "") : base(Label, ValueFunc, Units) public VOID_NumValue(string Label, Func<T> ValueFunc, string Units = "") : base(Label, ValueFunc, Units)
{ {
this.formatProvider = System.Globalization.CultureInfo.CurrentUICulture;  
} }
   
public virtual double ToDouble(IFormatProvider provider) public virtual double ToDouble(IFormatProvider provider)
{ {
return this.Value.ToDouble(provider); return this.Value.ToDouble(provider);
} }
   
public virtual double ToDouble() public virtual double ToDouble()
{ {
return this.ToDouble(this.formatProvider); return this.ToDouble(formatProvider);
} }
   
public virtual int ToInt32(IFormatProvider provider) public virtual int ToInt32(IFormatProvider provider)
{ {
return this.Value.ToInt32(provider); return this.Value.ToInt32(provider);
} }
   
public virtual int ToInt32() public virtual int ToInt32()
{ {
return this.ToInt32(this.formatProvider); return this.ToInt32(formatProvider);
} }
   
public virtual float ToSingle(IFormatProvider provider) public virtual float ToSingle(IFormatProvider provider)
{ {
return this.Value.ToSingle(provider); return this.Value.ToSingle(provider);
} }
   
public virtual float ToSingle() public virtual float ToSingle()
{ {
return this.ToSingle(this.formatProvider); return this.ToSingle(formatProvider);
} }
   
public virtual string ToString(string Format) public virtual string ToString(string format)
  {
  return this.ToString(format, formatProvider);
  }
   
  public virtual string ToString(string format, IFormatProvider provider)
{ {
return string.Format ( return string.Format (
"{0}: {1}{2}", "{0}{1}",
this.Label, this.Value.ToString(format, provider),
this.Value.ToString(Format, this.formatProvider),  
this.Units this.Units
); );
} }
   
public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue) public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue)
{ {
return string.Format ( return string.Format (
"{0}{1}", "{0}{1}",
Tools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude), Tools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude),
this.Units this.Units
); );
} }
   
public virtual string ValueUnitString(string format) public virtual string ValueUnitString(string format)
{ {
return this.Value.ToString(format, this.formatProvider) + this.Units; return this.Value.ToString(format, formatProvider) + this.Units;
} }
public virtual string ValueUnitString(int digits) { public virtual string ValueUnitString(int digits) {
return Tools.MuMech_ToSI(this, digits) + this.Units; return Tools.MuMech_ToSI(this, digits) + this.Units;
} }
   
public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude) public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude)
{ {
return Tools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units; return Tools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units;
} }
   
public virtual void DoGUIHorizontal(string format) public virtual void DoGUIHorizontal(string format)
{ {
GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
GUILayout.Label (this.Label + ":"); GUILayout.Label (this.Label + ":");
GUILayout.FlexibleSpace (); GUILayout.FlexibleSpace ();
GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false)); GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false));
GUILayout.EndHorizontal (); GUILayout.EndHorizontal ();
} }
   
public virtual int DoGUIHorizontal(int digits, bool precisionButton = true) public virtual int DoGUIHorizontal(int digits, bool precisionButton = true)
{ {
if (precisionButton) if (precisionButton)
{ {
return this.DoGUIHorizontalPrec(digits); return this.DoGUIHorizontalPrec(digits);
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true)); GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
return digits; return digits;
} }
   
public virtual int DoGUIHorizontalPrec(int digits) public virtual int DoGUIHorizontalPrec(int digits)
{ {
double magnitude; double magnitude;
double magLimit; double magLimit;
   
magnitude = Math.Log10(Math.Abs((double)this)); magnitude = Math.Log10(Math.Abs((double)this));
   
magLimit = Math.Max(Math.Abs(magnitude), 3d) + 3d; magLimit = Math.Max(Math.Abs(magnitude), 3d) + 3d;
magLimit = Math.Round(Math.Ceiling(magLimit / 3f)) * 3d; magLimit = Math.Round(Math.Ceiling(magLimit / 3f)) * 3d;
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true)); GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
   
if (magnitude >= 0) if (magnitude >= 0)
{ {
GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false));
} }
else else
{ {
GUILayout.Label(this.ValueUnitString(3, (int)magnitude + digits, int.MaxValue), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(3, (int)magnitude + digits, int.MaxValue), GUILayout.ExpandWidth(false));
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (Event.current.type == EventType.mouseUp) if (Event.current.type == EventType.mouseUp)
{ {
Rect lastRect = GUILayoutUtility.GetLastRect(); Rect lastRect = GUILayoutUtility.GetLastRect();
if (lastRect.Contains(Event.current.mousePosition)) if (lastRect.Contains(Event.current.mousePosition))
{ {
Tools.PostDebugMessage(string.Format("{0}: Changing digits from {1} within magLimit {2}.", Tools.PostDebugMessage(string.Format("{0}: Changing digits from {1} within magLimit {2}.",
this.GetType().Name, this.GetType().Name,
digits, digits,
magLimit)); magLimit));
   
if (Event.current.button == 0) if (Event.current.button == 0)
{ {
digits = (digits + 3) % (int)magLimit; digits = (digits + 3) % (int)magLimit;
} }
else if (Event.current.button == 1) else if (Event.current.button == 1)
{ {
digits = (digits - 3) % (int)magLimit; digits = (digits - 3) % (int)magLimit;
} }
   
if (digits < 0) if (digits < 0)
{ {
digits += (int)magLimit; digits += (int)magLimit;
} }
   
Tools.PostDebugMessage(string.Format("{0}: Changed digits to {1}." + Tools.PostDebugMessage(string.Format("{0}: Changed digits to {1}." +
"\n\tNew minMagnitude: {2}, maxMagnitude: {3}" + "\n\tNew minMagnitude: {2}, maxMagnitude: {3}" +
"\n\tMagnitude: {4}", "\n\tMagnitude: {4}",
this.GetType().Name, this.GetType().Name,
digits, digits,
magnitude >= 0 ? int.MinValue : (int)magnitude - 4 + digits, magnitude >= 0 ? int.MinValue : (int)magnitude - 4 + digits,
magnitude >= 0 ? (int)magnitude - digits : int.MaxValue, magnitude >= 0 ? (int)magnitude - digits : int.MaxValue,
magnitude magnitude
)); ));
} }
} }
   
return digits; return digits;
} }
} }
   
public class VOID_DoubleValue : VOID_NumValue<double> public class VOID_DoubleValue : VOID_NumValue<double>
{ {
public VOID_DoubleValue(string Label, Func<double> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_DoubleValue(string Label, Func<double> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_FloatValue : VOID_NumValue<float> public class VOID_FloatValue : VOID_NumValue<float>
{ {
public VOID_FloatValue(string Label, Func<float> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_FloatValue(string Label, Func<float> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_IntValue : VOID_NumValue<int> public class VOID_IntValue : VOID_NumValue<int>
{ {
public VOID_IntValue(string Label, Func<int> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_IntValue(string Label, Func<int> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_StrValue : VOID_DataValue<string> public class VOID_StrValue : VOID_DataValue<string>
{ {
public VOID_StrValue(string Label, Func<string> ValueFunc) : base(Label, ValueFunc, "") {} public VOID_StrValue(string Label, Func<string> ValueFunc) : base(Label, ValueFunc, "") {}
} }
   
public class VOID_Vector3dValue : VOID_DataValue<Vector3d> public class VOID_Vector3dValue : VOID_DataValue<Vector3d>
{ {
public VOID_Vector3dValue(string Label, Func<Vector3d> ValueFunc, string Units) public VOID_Vector3dValue(string Label, Func<Vector3d> ValueFunc, string Units)
: base(Label, ValueFunc, Units) : base(Label, ValueFunc, Units)
{} {}
   
public string ToString(string format) public string ToString(string format)
{ {
return string.Format("{0}: {1}{2}", return string.Format("{0}: {1}{2}",
this.Label, this.Label,
this.Value.ToString(format), this.Value.ToString(format),
this.Units this.Units
); );
} }
   
public string ValueUnitString(string format) { public string ValueUnitString(string format) {
return this.Value.ToString(format) + this.Units; return this.Value.ToString(format) + this.Units;
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_SaveValue.cs // VOID_SaveValue.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public struct VOID_SaveValue<T> : IVOID_SaveValue public struct VOID_SaveValue<T> : IVOID_SaveValue
{ {
private T _value; private T _value;
private Type _type; private Type _type;
   
private VOIDCore Core private VOIDCore Core
{ {
get get
{ {
return VOID_Data.Core; return VOID_Data.Core;
} }
} }
   
object IVOID_SaveValue.value object IVOID_SaveValue.value
{ {
get get
{ {
return this.value; return this.value;
} }
} }
   
public T value public T value
{ {
get get
{ {
return this._value; return this._value;
} }
set set
{ {
if (this.Core != null && !System.Object.Equals(this._value, value)) if (this.Core != null && !System.Object.Equals(this._value, value))
{ {
Tools.PostDebugMessage (string.Format ( Tools.PostDebugMessage (string.Format (
"VOID: Dirtying config for type {0} in method {1}." + "VOID: Dirtying config for type {0}." +
"\n\t Old Value: {2}, New Value: {3}" + "\n\t Old Value: {2}, New Value: {3}" +
"\n\t Object.Equals(New, Old): {4}", "\n\t Object.Equals(New, Old): {4}\n" +
  "{1}",
this._type, this._type,
new System.Diagnostics.StackTrace().GetFrame(1).GetMethod(), new System.Diagnostics.StackTrace().ToString(),
this._value, this._value,
value, value,
System.Object.Equals(this._value, value) System.Object.Equals(this._value, value)
)); ));
this.Core.configDirty = true; this.Core.configDirty = true;
} }
this._value = value; this._value = value;
} }
} }
   
public Type type public Type type
{ {
get get
{ {
if (this._type == null && this._value != null) if (this._type == null && this._value != null)
{ {
this._type = this._value.GetType (); this._type = this._value.GetType ();
} }
return this._type; return this._type;
} }
set set
{ {
this._type = value; this._type = value;
} }
} }
   
public void SetValue(object v) public void SetValue(object v)
{ {
this.value = (T)v; this.value = (T)v;
} }
   
public static implicit operator T(VOID_SaveValue<T> v) public static implicit operator T(VOID_SaveValue<T> v)
{ {
return (T)v.value; return (T)v.value;
} }
   
public static implicit operator VOID_SaveValue<T>(T v) public static explicit operator VOID_SaveValue<T>(T v)
{ {
VOID_SaveValue<T> r = new VOID_SaveValue<T>(); VOID_SaveValue<T> r = new VOID_SaveValue<T>();
r.type = v.GetType(); r.type = v.GetType();
r.value = v; r.value = v;
   
return r; return r;
} }
   
public override string ToString() public override string ToString()
{ {
return this.value.ToString(); return this.value.ToString();
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_Tools.cs // VOID_Tools.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public static class VOID_Tools public static class VOID_Tools
{ {
#region CelestialBody Utilities #region CelestialBody Utilities
public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB) public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB)
{ {
if (bodyA == null || bodyB == null) if (bodyA == null || bodyB == null)
{ {
return false; return false;
} }
   
while (bodyA.orbitDriver != null) while (bodyA.orbitDriver != null)
{ {
if (bodyA.orbit.referenceBody == bodyB) if (bodyA.orbit.referenceBody == bodyB)
{ {
return true; return true;
} }
   
bodyA = bodyA.orbit.referenceBody; bodyA = bodyA.orbit.referenceBody;
} }
   
return false; return false;
} }
   
public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB) public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB)
{ {
if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null) if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null)
{ {
throw new ArgumentException(string.Concat( throw new ArgumentException(string.Concat(
"CelestialBody::FindRelatedParents: ", "CelestialBody::FindRelatedParents: ",
"Neither body may be null, and both bodies must have orbits." "Neither body may be null, and both bodies must have orbits."
)); ));
} }
   
CelestialBody a, b; CelestialBody a, b;
   
a = bodyA; a = bodyA;
   
while (bodyA.orbitDriver != null) while (bodyA.orbitDriver != null)
{ {
b = bodyB; b = bodyB;
   
while (b.orbitDriver != null) while (b.orbitDriver != null)
{ {
if (a.orbit.referenceBody == b.orbit.referenceBody) if (a.orbit.referenceBody == b.orbit.referenceBody)
{ {
bodyA = a; bodyA = a;
bodyB = b; bodyB = b;
return true; return true;
} }
   
b = b.orbit.referenceBody; b = b.orbit.referenceBody;
} }
   
a = a.orbit.referenceBody; a = a.orbit.referenceBody;
} }
   
return false; return false;
} }
#endregion #endregion
   
#region VESSEL_EXTENSIONS_SCIENCE #region VESSEL_EXTENSIONS_SCIENCE
public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel) public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel)
{ {
CBAttributeMapSO.MapAttribute mapAttribute; CBAttributeMapSO.MapAttribute mapAttribute;
   
try try
{ {
CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap; CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap;
   
double lat = vessel.latitude * Math.PI / 180d; double lat = vessel.latitude * Math.PI / 180d;
double lon = vessel.longitude * Math.PI / 180d; double lon = vessel.longitude * Math.PI / 180d;
   
mapAttribute = BiomeMap.GetAtt(lat, lon); mapAttribute = BiomeMap.GetAtt(lat, lon);
   
/* /*
lon -= Math.PI / 2d; lon -= Math.PI / 2d;
   
if (lon < 0d) if (lon < 0d)
{ {
lon += 2d * Math.PI; lon += 2d * Math.PI;
} }
   
float v = (float)(lat / Math.PI) + 0.5f; float v = (float)(lat / Math.PI) + 0.5f;
float u = (float)(lon / (2d * Math.PI)); float u = (float)(lon / (2d * Math.PI));
   
Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v); Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v);
mapAttribute = BiomeMap.defaultAttribute; mapAttribute = BiomeMap.defaultAttribute;
   
if (BiomeMap.Map != null) if (BiomeMap.Map != null)
{ {
if (BiomeMap.exactSearch) if (BiomeMap.exactSearch)
{ {
for (int i = 0; i < BiomeMap.Attributes.Length; ++i) for (int i = 0; i < BiomeMap.Attributes.Length; ++i)
{ {
if (pixelBilinear == BiomeMap.Attributes[i].mapColor) if (pixelBilinear == BiomeMap.Attributes[i].mapColor)
{ {
mapAttribute = BiomeMap.Attributes[i]; mapAttribute = BiomeMap.Attributes[i];
} }
} }
} }
else else
{ {
float zero = 0; float zero = 0;
float num = 1 / zero; float num = 1 / zero;
for (int j = 0; j < BiomeMap.Attributes.Length; ++j) for (int j = 0; j < BiomeMap.Attributes.Length; ++j)
{ {
Color mapColor = BiomeMap.Attributes[j].mapColor; Color mapColor = BiomeMap.Attributes[j].mapColor;
float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude; float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude;
if (sqrMagnitude < num) if (sqrMagnitude < num)
{ {
bool testCase = true; bool testCase = true;
if (BiomeMap.nonExactThreshold != -1) if (BiomeMap.nonExactThreshold != -1)
{ {
testCase = (sqrMagnitude < BiomeMap.nonExactThreshold); testCase = (sqrMagnitude < BiomeMap.nonExactThreshold);
} }
if (testCase) if (testCase)
{ {
mapAttribute = BiomeMap.Attributes[j]; mapAttribute = BiomeMap.Attributes[j];
num = sqrMagnitude; num = sqrMagnitude;
} }
} }
} }
} }
} }
*/ */
} }
catch (NullReferenceException) catch (NullReferenceException)
{ {
mapAttribute = new CBAttributeMapSO.MapAttribute(); mapAttribute = new CBAttributeMapSO.MapAttribute();
mapAttribute.name = "N/A"; mapAttribute.name = "N/A";
} }
   
return mapAttribute; return mapAttribute;
} }
   
public static ExperimentSituations GetExperimentSituation(this Vessel vessel) public static ExperimentSituations GetExperimentSituation(this Vessel vessel)
{ {
if (vessel == null) if (vessel == null)
{ {
return ExperimentSituations.SrfSplashed; return ExperimentSituations.SrfSplashed;
} }
   
Vessel.Situations situation = vessel.situation; Vessel.Situations situation = vessel.situation;
   
switch (situation) switch (situation)
{ {
case Vessel.Situations.PRELAUNCH: case Vessel.Situations.PRELAUNCH:
case Vessel.Situations.LANDED: case Vessel.Situations.LANDED:
return ExperimentSituations.SrfLanded; return ExperimentSituations.SrfLanded;
case Vessel.Situations.SPLASHED: case Vessel.Situations.SPLASHED:
return ExperimentSituations.SrfSplashed; return ExperimentSituations.SrfSplashed;
case Vessel.Situations.FLYING: case Vessel.Situations.FLYING:
if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold) if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold)
{ {
return ExperimentSituations.FlyingLow; return ExperimentSituations.FlyingLow;
} }
else else
{ {
return ExperimentSituations.FlyingHigh; return ExperimentSituations.FlyingHigh;
} }
} }
   
if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold) if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold)
{ {
return ExperimentSituations.InSpaceLow; return ExperimentSituations.InSpaceLow;
} }
else else
{ {
return ExperimentSituations.InSpaceHigh; return ExperimentSituations.InSpaceHigh;
} }
} }
   
public static string HumanString(this ExperimentSituations situation) public static string HumanString(this ExperimentSituations situation)
{ {
switch (situation) switch (situation)
{ {
case ExperimentSituations.FlyingHigh: case ExperimentSituations.FlyingHigh:
return "Upper Atmosphere"; return "Upper Atmosphere";
case ExperimentSituations.FlyingLow: case ExperimentSituations.FlyingLow:
return "Flying"; return "Flying";
case ExperimentSituations.SrfLanded: case ExperimentSituations.SrfLanded:
return "Surface"; return "Surface";
case ExperimentSituations.InSpaceLow: case ExperimentSituations.InSpaceLow:
return "Near in Space"; return "Near in Space";
case ExperimentSituations.InSpaceHigh: case ExperimentSituations.InSpaceHigh:
return "High in Space"; return "High in Space";
case ExperimentSituations.SrfSplashed: case ExperimentSituations.SrfSplashed:
return "Splashed Down"; return "Splashed Down";
default: default:
return "Unknown"; return "Unknown";
} }
} }
#endregion #endregion
   
#region VESSEL_EXTENSIONS_LAT_LONG #region VESSEL_EXTENSIONS_LAT_LONG
public static string GetLongitudeString(this Vessel vessel, string format = "F4") public static string GetLongitudeString(this Vessel vessel, string format = "F4")
{ {
string dir_long = "W"; string dir_long = "W";
double v_long = vessel.longitude; double v_long = vessel.longitude;
   
v_long = FixDegreeDomain(v_long); v_long = FixDegreeDomain(v_long);
   
if (v_long < -180d) if (v_long < -180d)
{ {
v_long += 360d; v_long += 360d;
} }
if (v_long >= 180) if (v_long >= 180)
{ {
v_long -= 360d; v_long -= 360d;
} }
   
if (v_long > 0) if (v_long > 0)
dir_long = "E"; dir_long = "E";
   
return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long); return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long);
} }
   
public static string GetLatitudeString(this Vessel vessel, string format = "F4") public static string GetLatitudeString(this Vessel vessel, string format = "F4")
{ {
string dir_lat = "S"; string dir_lat = "S";
double v_lat = vessel.latitude; double v_lat = vessel.latitude;
if (v_lat > 0) if (v_lat > 0)
dir_lat = "N"; dir_lat = "N";
   
return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat); return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat);
} }
#endregion #endregion
   
#region VESSEL_EXTENSIONS_GENERAL #region VESSEL_EXTENSIONS_GENERAL
public static double TrueAltitude(Vessel vessel) public static double TrueAltitude(Vessel vessel)
{ {
double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude; double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude;
   
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
// and water covers the whole surface at 0 m. // and water covers the whole surface at 0 m.
if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean) if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean)
{ {
trueAltitude = vessel.orbit.altitude; trueAltitude = vessel.orbit.altitude;
} }
   
return trueAltitude; return trueAltitude;
} }
   
public static double Radius(this Vessel vessel) public static double Radius(this Vessel vessel)
{ {
double radius; double radius;
   
radius = vessel.altitude; radius = vessel.altitude;
   
if (vessel.mainBody != null) if (vessel.mainBody != null)
{ {
radius += vessel.mainBody.Radius; radius += vessel.mainBody.Radius;
} }
   
return radius; return radius;
} }
#endregion #endregion
   
#region GEOMETRY_UTILS #region GEOMETRY_UTILS
public static double FixAngleDomain(double Angle, bool Degrees = false) public static double FixAngleDomain(double Angle, bool Degrees = false)
{ {
double Extent = 2d * Math.PI; double Extent = 2d * Math.PI;
if (Degrees) if (Degrees)
{ {
Extent = 360d; Extent = 360d;
} }
   
Angle = Angle % (Extent); Angle = Angle % (Extent);
if (Angle < 0d) if (Angle < 0d)
{ {
Angle += Extent; Angle += Extent;
} }
   
return Angle; return Angle;
} }
   
public static double FixDegreeDomain(double Angle) public static double FixDegreeDomain(double Angle)
{ {
return FixAngleDomain(Angle, true); return FixAngleDomain(Angle, true);
} }
#endregion #endregion
   
private static Dictionary<int, GUI.WindowFunction> functionCache; private static Dictionary<int, GUI.WindowFunction> functionCache;
public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action<int> func) public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action<int> func)
{ {
if (functionCache == null) if (functionCache == null)
{ {
functionCache = new Dictionary<int, GUI.WindowFunction>(); functionCache = new Dictionary<int, GUI.WindowFunction>();
} }
   
int hashCode = func.GetHashCode(); int hashCode = func.GetHashCode();
   
if (!functionCache.ContainsKey(hashCode)) if (!functionCache.ContainsKey(hashCode))
{ {
functionCache[hashCode] = delegate (int id) functionCache[hashCode] = delegate (int id)
{ {
try try
{ {
func(id); func(id);
} }
#if DEBUG #if DEBUG
catch (ArgumentException) catch (ArgumentException)
#else #else
catch (ArgumentException) catch (ArgumentException)
#endif #endif
{ {
Debug.LogWarning( Debug.LogWarning(
string.Format("[{0}]: ArgumentException caught during window call. This is not a bug.", string.Format("[{0}]: ArgumentException caught during window call. This is not a bug.",
func.Target.GetType().Name func.Target.GetType().Name
)); ));
   
/*#if DEBUG /*#if DEBUG
Debug.LogException(ex); Debug.LogException(ex);
#endif*/ #endif*/
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogError( Debug.LogError(
string.Format("[{0}]: {1} caught during window call.\nMessage:\n{2}\nStackTrace:\n{3}", string.Format("[{0}]: {1} caught during window call.\nMessage:\n{2}\nStackTrace:\n{3}",
func.Target.GetType().Name, func.Target.GetType().Name,
ex.GetType().Name, ex.GetType().Name,
ex.Message, ex.Message,
ex.StackTrace ex.StackTrace
)); ));
} }
}; };
} }
   
return functionCache[hashCode]; return functionCache[hashCode];
  }
   
  public static void UncacheWindow(Action<int> func)
  {
  if (functionCache != null)
  {
  int hashCode = func.GetHashCode();
   
  if (functionCache.ContainsKey(hashCode))
  {
  functionCache.Remove(hashCode);
  }
  }
} }
   
/// <summary> /// <summary>
/// Formats the interval given in seconds as a human-friendly /// Formats the interval given in seconds as a human-friendly
/// time period in [[[[years, ]days, ]hours, ]minutes, and ]seconds. /// time period in [[[[years, ]days, ]hours, ]minutes, and ]seconds.
/// ///
/// Uses sidereal days, since "6 hours per day" is the Kerbal standard. /// Uses sidereal days, since "6 hours per day" is the Kerbal standard.
/// </summary> /// </summary>
/// <returns>Human readable interval</returns> /// <returns>Human readable interval</returns>
/// <param name="seconds"></param> /// <param name="seconds"></param>
public static string FormatInterval(double seconds) public static string FormatInterval(double seconds)
{ {
return UnpackedTime.FromSeconds(seconds).FormatAsSpan(); return UnpackedTime.FromSeconds(seconds).FormatAsSpan();
} }
   
/// <summary> /// <summary>
/// Formats the date given in seconds since epoch as a human-friendly /// Formats the date given in seconds since epoch as a human-friendly
/// date in the format YY, DD, HH:MM:SS /// date in the format YY, DD, HH:MM:SS
/// </summary> /// </summary>
/// <returns>The date.</returns> /// <returns>The date.</returns>
/// <param name="seconds">Seconds.</param> /// <param name="seconds">Seconds.</param>
public static string FormatDate(double seconds) public static string FormatDate(double seconds)
{ {
return UnpackedTime.FromSeconds(seconds).FormatAsDate(); return UnpackedTime.FromSeconds(seconds).FormatAsDate();
} }
   
public class UnpackedTime public class UnpackedTime
{ {
public const double SecondsPerMinute = 60d; public const double SecondsPerMinute = 60d;
public const double SecondsPerHour = 3600d; public const double SecondsPerHour = 3600d;
   
public static double SecondsPerDay public static double SecondsPerDay
{ {
get get
{ {
if (GameSettings.KERBIN_TIME) if (GameSettings.KERBIN_TIME)
{ {
return 21600d; return 21600d;
} }
else else
{ {
return 86164.1d; return 86164.1d;
} }
} }
} }
   
public static double SecondsPerYear public static double SecondsPerYear
{ {
get get
{ {
if (GameSettings.KERBIN_TIME) if (GameSettings.KERBIN_TIME)
{ {
return 9203545d; return 9203545d;
} }
else else
{ {
return 31558149d; return 31558149d;
} }
} }
} }
   
public static UnpackedTime FromSeconds(double seconds) public static UnpackedTime FromSeconds(double seconds)
{ {
UnpackedTime time = new UnpackedTime(); UnpackedTime time = new UnpackedTime();
   
time.years = (int)(seconds / SecondsPerYear); time.years = (int)(seconds / SecondsPerYear);
   
seconds %= SecondsPerYear; seconds %= SecondsPerYear;
   
time.days = (int)(seconds / SecondsPerDay); time.days = (int)(seconds / SecondsPerDay);
   
seconds %= SecondsPerDay; seconds %= SecondsPerDay;
   
time.hours = (int)(seconds / SecondsPerHour); time.hours = (int)(seconds / SecondsPerHour);
   
seconds %= SecondsPerHour; seconds %= SecondsPerHour;
   
time.minutes = (int)(seconds / SecondsPerMinute); time.minutes = (int)(seconds / SecondsPerMinute);
   
seconds %= SecondsPerMinute; seconds %= SecondsPerMinute;
   
time.seconds = seconds; time.seconds = seconds;
   
return time; return time;
} }
   
public static explicit operator UnpackedTime(double seconds) public static explicit operator UnpackedTime(double seconds)
{ {
return FromSeconds(seconds); return FromSeconds(seconds);
} }
   
public static implicit operator double(UnpackedTime time) public static implicit operator double(UnpackedTime time)
{ {
return time.ToSeconds(); return time.ToSeconds();
} }
   
public static UnpackedTime operator+ (UnpackedTime lhs, UnpackedTime rhs) public static UnpackedTime operator+ (UnpackedTime lhs, UnpackedTime rhs)
{ {
return FromSeconds(lhs.ToSeconds() + rhs.ToSeconds()); return FromSeconds(lhs.ToSeconds() + rhs.ToSeconds());
} }
   
public static UnpackedTime operator- (UnpackedTime lhs, UnpackedTime rhs) public static UnpackedTime operator- (UnpackedTime lhs, UnpackedTime rhs)
{ {
return FromSeconds(lhs.ToSeconds() - rhs.ToSeconds()); return FromSeconds(lhs.ToSeconds() - rhs.ToSeconds());
} }
   
public int years; public int years;
public int days; public int days;
public int hours; public int hours;
public int minutes; public int minutes;
public double seconds; public double seconds;
   
public double ToSeconds() public double ToSeconds()
{ {
return (double)years * SecondsPerYear + return (double)years * SecondsPerYear +
(double)days * SecondsPerDay + (double)days * SecondsPerDay +
(double)hours * SecondsPerHour + (double)hours * SecondsPerHour +
(double)minutes * SecondsPerMinute + (double)minutes * SecondsPerMinute +
seconds; seconds;
} }
   
public string FormatAsSpan() public string FormatAsSpan()
{ {
string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s"; string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s";
string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:00.0}s"; string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:00.0}s";
string format_3 = "{0:D2}h {1:D2}m {2:00.0}s"; string format_3 = "{0:D2}h {1:D2}m {2:00.0}s";
string format_4 = "{0:D2}m {1:00.0}s"; string format_4 = "{0:D2}m {1:00.0}s";
string format_5 = "{0:00.0}s"; string format_5 = "{0:00.0}s";
   
if (this.years > 0) if (this.years > 0)
{ {
return string.Format(format_1, this.years, this.days, this.hours, this.minutes, this.seconds); return string.Format(format_1, this.years, this.days, this.hours, this.minutes, this.seconds);
} }
else if (this.days > 0) else if (this.days > 0)
{ {
return string.Format(format_2, this.days, this.hours, this.minutes, this.seconds); return string.Format(format_2, this.days, this.hours, this.minutes, this.seconds);
} }
else if (this.hours > 0) else if (this.hours > 0)
{ {
return string.Format(format_3, this.hours, this.minutes, this.seconds); return string.Format(format_3, this.hours, this.minutes, this.seconds);
} }
else if (this.minutes > 0) else if (this.minutes > 0)
{ {
return string.Format(format_4, this.minutes, this.seconds); return string.Format(format_4, this.minutes, this.seconds);
} }
else else
{ {
return string.Format(format_5, this.seconds); return string.Format(format_5, this.seconds);
} }
} }
   
public string FormatAsDate() public string FormatAsDate()
{ {
string format = "Y{0:#0}, D{1:#0} {2:00}:{3:00}:{4:00.0}s"; string format = "Y{0:#0}, D{1:#0} {2:00}:{3:00}:{4:00.0}s";
   
return string.Format(format, years + 1, days + 1, hours, minutes, seconds); return string.Format(format, years + 1, days + 1, hours, minutes, seconds);
} }
   
public UnpackedTime(int years, int days, int hours, int minutes, double seconds) public UnpackedTime(int years, int days, int hours, int minutes, double seconds)
{ {
this.years = years; this.years = years;
this.days = days; this.days = days;
this.hours = hours; this.hours = hours;
this.minutes = minutes; this.minutes = minutes;
this.seconds = seconds; this.seconds = seconds;
} }
   
public UnpackedTime() : this(0, 0, 0, 0, 0d) {} public UnpackedTime() : this(0, 0, 0, 0, 0d) {}
} }
   
public static string UppercaseFirst(string s) public static string UppercaseFirst(string s)
{ {
if (string.IsNullOrEmpty(s)) if (string.IsNullOrEmpty(s))
{ {
return string.Empty; return string.Empty;
} }
char[] a = s.ToCharArray(); char[] a = s.ToCharArray();
a[0] = char.ToUpper(a[0]); a[0] = char.ToUpper(a[0]);
return new string(a); return new string(a);
} }
   
//transfer angles //transfer angles
public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param) public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param)
{ {
r_target /= 1000; r_target /= 1000;
r_current /= 1000; r_current /= 1000;
grav_param /= 1000000000; grav_param /= 1000000000;
   
double midpoint = (r_target + r_current) / 2; double midpoint = (r_target + r_current) / 2;
   
double T_target = (2 * Math.PI) * Math.Sqrt((r_target * r_target * r_target) / grav_param); double T_target = (2 * Math.PI) * Math.Sqrt((r_target * r_target * r_target) / grav_param);
double T_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param); double T_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param);
return 360 * (0.5 - (T_transfer / (2 * T_target))); return 360 * (0.5 - (T_transfer / (2 * T_target)));
} }
   
public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2) public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2)
{ {
/* /*
def deltaVToGetToOtherBody(mu, r1, r2): def deltaVToGetToOtherBody(mu, r1, r2):
# mu = gravity param of common orbiting body of r1 and r2 # mu = gravity param of common orbiting body of r1 and r2
# (e.g. for mun to minmus, mu is kerbin's gravity param # (e.g. for mun to minmus, mu is kerbin's gravity param
# r1 = initial body's orbit radius # r1 = initial body's orbit radius
# r2 = target body's orbit radius # r2 = target body's orbit radius
# return value is km/s # return value is km/s
sur1 = math.sqrt(mu / r1) sur1 = math.sqrt(mu / r1)
sr1r2 = math.sqrt(float(2*r2)/float(r1+r2)) sr1r2 = math.sqrt(float(2*r2)/float(r1+r2))
mult = sr1r2 - 1 mult = sr1r2 - 1
return sur1 * mult return sur1 * mult
*/ */
double sur1, sr1r2, mult; double sur1, sr1r2, mult;
sur1 = Math.Sqrt(mu / r1); sur1 = Math.Sqrt(mu / r1);
sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2)); sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2));
mult = sr1r2 - 1; mult = sr1r2 - 1;
return sur1 * mult; return sur1 * mult;
} }
   
public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v) public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v)
{ {
/* /*
def deltaVToExitSOI(mu, r1, r2, v): def deltaVToExitSOI(mu, r1, r2, v):
# mu = gravity param of current body # mu = gravity param of current body
# r1 = current orbit radius # r1 = current orbit radius
# r2 = SOI radius # r2 = SOI radius
# v = SOI exit velocity # v = SOI exit velocity
foo = r2 * (v**2) - 2 * mu foo = r2 * (v**2) - 2 * mu
bar = r1 * foo + (2 * r2 * mu) bar = r1 * foo + (2 * r2 * mu)
r = r1*r2 r = r1*r2
return math.sqrt(bar / r) return math.sqrt(bar / r)
*/ */
double foo = r2 * (v * v) - 2 * mu; double foo = r2 * (v * v) - 2 * mu;
double bar = r1 * foo + (2 * r2 * mu); double bar = r1 * foo + (2 * r2 * mu);
double r = r1 * r2; double r = r1 * r2;
return Math.Sqrt(bar / r); return Math.Sqrt(bar / r);
} }
   
public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu) public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu)
{ {
/* /*
def transferBurnPoint(r, v, angle, mu): def transferBurnPoint(r, v, angle, mu):
# r = parking orbit radius # r = parking orbit radius
# v = ejection velocity # v = ejection velocity
# angle = phase angle (from function phaseAngle()) # angle = phase angle (from function phaseAngle())
# mu = gravity param of current body. # mu = gravity param of current body.
epsilon = ((v**2)/2) - (mu / r) epsilon = ((v**2)/2) - (mu / r)
h = r * v * math.sin(angle) h = r * v * math.sin(angle)
e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2))) e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2)))
theta = math.acos(1.0 / e) theta = math.acos(1.0 / e)
degrees = theta * (180.0 / math.pi) degrees = theta * (180.0 / math.pi)
return 180 - degrees return 180 - degrees
*/ */
double epsilon, h, ee, theta, degrees; double epsilon, h, ee, theta, degrees;
epsilon = ((v * v) / 2) - (mu / r); epsilon = ((v * v) / 2) - (mu / r);
h = r * v * Math.Sin(angle); h = r * v * Math.Sin(angle);
ee = Math.Sqrt(1 + ((2 * epsilon * (h * h)) / (mu * mu))); ee = Math.Sqrt(1 + ((2 * epsilon * (h * h)) / (mu * mu)));
theta = Math.Acos(1.0 / ee); theta = Math.Acos(1.0 / ee);
degrees = theta * (180.0 / Math.PI); degrees = theta * (180.0 / Math.PI);
return 180 - degrees; return 180 - degrees;
// returns the ejection angle // returns the ejection angle
} }
   
public static double Adammada_CurrrentPhaseAngle( public static double Adammada_CurrrentPhaseAngle(
double body_LAN, double body_LAN,
double body_orbitPct, double body_orbitPct,
double origin_LAN, double origin_LAN,
double origin_orbitPct double origin_orbitPct
) )
{ {
double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct); double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct);
if (angle > 1) if (angle > 1)
angle = angle - 1; angle = angle - 1;
if (angle < 0) if (angle < 0)
angle = angle + 1; angle = angle + 1;
if (angle > 0.5) if (angle > 0.5)
angle = angle - 1; angle = angle - 1;
angle = angle * 360; angle = angle * 360;
return angle; return angle;
} }
   
public static double Adammada_CurrentEjectionAngle( public static double Adammada_CurrentEjectionAngle(
double vessel_long, double vessel_long,
double origin_rotAngle, double origin_rotAngle,
double origin_LAN, double origin_LAN,
double origin_orbitPct double origin_orbitPct
) )
{ {
//double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360); //double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360);
double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360); double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360);
   
while (eangle < 0) while (eangle < 0)
eangle = eangle + 360; eangle = eangle + 360;
while (eangle > 360) while (eangle > 360)
eangle = eangle - 360; eangle = eangle - 360;
if (eangle < 270) if (eangle < 270)
eangle = 90 - eangle; eangle = 90 - eangle;
else else
eangle = 450 - eangle; eangle = 450 - eangle;
return eangle; return eangle;
} }
   
public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body
{ {
Vector3d vecthis = new Vector3d(); Vector3d vecthis = new Vector3d();
Vector3d vectarget = new Vector3d(); Vector3d vectarget = new Vector3d();
vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
   
if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun")) if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun"))
{ {
vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
} }
else else
{ {
vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
} }
   
vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis); vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis);
vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget); vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget);
   
Vector3d prograde = new Vector3d(); Vector3d prograde = new Vector3d();
prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis; prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis;
   
double phase = Vector3d.Angle(vecthis, vectarget); double phase = Vector3d.Angle(vecthis, vectarget);
   
if (Vector3d.Angle(prograde, vectarget) > 90) if (Vector3d.Angle(prograde, vectarget) > 90)
phase = 360 - phase; phase = 360 - phase;
   
return (phase + 360) % 360; return (phase + 360) % 360;
} }
   
public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase) public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase)
{ {
if (transfer_angle < 0) if (transfer_angle < 0)
{ {
if (curr_phase > 0) if (curr_phase > 0)
return (-1 * (360 - curr_phase)); return (-1 * (360 - curr_phase));
else if (curr_phase < 0) else if (curr_phase < 0)
return curr_phase; return curr_phase;
} }
else if (transfer_angle > 0) else if (transfer_angle > 0)
{ {
if (curr_phase > 0) if (curr_phase > 0)
return curr_phase; return curr_phase;
else if (curr_phase < 0) else if (curr_phase < 0)
return (360 + curr_phase); return (360 + curr_phase);
} }
return curr_phase; return curr_phase;
} }
   
public static double adjust_current_ejection_angle(double curr_ejection) public static double adjust_current_ejection_angle(double curr_ejection)
{ {
//curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180 //curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180
// need 0-360 instead // need 0-360 instead
// //
// ie i have -17 in the screenshot // ie i have -17 in the screenshot
// need it to show 343 // need it to show 343
// //
// do this // do this
// //
// if < 0, add curr to 360 // 360 + (-17) = 343 // if < 0, add curr to 360 // 360 + (-17) = 343
// else its good as it is // else its good as it is
   
if (curr_ejection < 0) if (curr_ejection < 0)
return 360 + curr_ejection; return 360 + curr_ejection;
else else
return curr_ejection; return curr_ejection;
   
} }
   
public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase) public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase)
{ {
// if transfer_phase_angle < 0 its a lower transfer // if transfer_phase_angle < 0 its a lower transfer
//180 + curr_ejection //180 + curr_ejection
// else if transfer_phase_angle > 0 its good as it is // else if transfer_phase_angle > 0 its good as it is
   
if (trans_phase < 0) if (trans_phase < 0)
return 180 + trans_ejection; return 180 + trans_ejection;
else else
return trans_ejection; return trans_ejection;
   
} }
   
public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel) public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + VOID_Tools.Nivvy_CalcTransferPhaseAngle( VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + VOID_Tools.Nivvy_CalcTransferPhaseAngle(
vessel.orbit.semiMajorAxis, vessel.orbit.semiMajorAxis,
body.orbit.semiMajorAxis, body.orbit.semiMajorAxis,
vessel.mainBody.gravParameter vessel.mainBody.gravParameter
).ToString("F3") + "°", ).ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label( GUILayout.Label(
(VOID_Tools.Younata_DeltaVToGetToOtherBody( (VOID_Tools.Younata_DeltaVToGetToOtherBody(
(vessel.mainBody.gravParameter / 1000000000), (vessel.mainBody.gravParameter / 1000000000),
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
(body.orbit.semiMajorAxis / 1000) (body.orbit.semiMajorAxis / 1000)
) * 1000).ToString("F2") + "m/s", ) * 1000).ToString("F2") + "m/s",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel) public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel)
{ {
double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
(vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.referenceBody.gravParameter / 1000000000),
(vessel.mainBody.orbit.semiMajorAxis / 1000), (vessel.mainBody.orbit.semiMajorAxis / 1000),
(body.orbit.semiMajorAxis / 1000) (body.orbit.semiMajorAxis / 1000)
); );
double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( double dv2 = VOID_Tools.Younata_DeltaVToExitSOI(
(vessel.mainBody.gravParameter / 1000000000), (vessel.mainBody.gravParameter / 1000000000),
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
(vessel.mainBody.sphereOfInfluence / 1000), (vessel.mainBody.sphereOfInfluence / 1000),
Math.Abs(dv1) Math.Abs(dv1)
); );
   
double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint(
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
dv2, dv2,
(Math.PI / 2.0), (Math.PI / 2.0),
(vessel.mainBody.gravParameter / 1000000000) (vessel.mainBody.gravParameter / 1000000000)
); );
double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle(
FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.longitude,
FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
); );
   
double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
vessel.mainBody.orbit.semiMajorAxis, vessel.mainBody.orbit.semiMajorAxis,
body.orbit.semiMajorAxis, body.orbit.semiMajorAxis,
vessel.mainBody.referenceBody.gravParameter vessel.mainBody.referenceBody.gravParameter
) % 360; ) % 360;
double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle(
body.orbit.LAN, body.orbit.LAN,
body.orbit.orbitPercent, body.orbit.orbitPercent,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
); );
   
double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle); double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle);
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ejection angle (curr/trans):"); GUILayout.Label("Ejection angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel) public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel)
{ {
double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
(vessel.mainBody.gravParameter / 1000000000), (vessel.mainBody.gravParameter / 1000000000),
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
(body.orbit.semiMajorAxis / 1000) (body.orbit.semiMajorAxis / 1000)
); );
   
double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
vessel.orbit.semiMajorAxis, vessel.orbit.semiMajorAxis,
body.orbit.semiMajorAxis, body.orbit.semiMajorAxis,
vessel.mainBody.gravParameter vessel.mainBody.gravParameter
); );
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel) public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel)
{ {
double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
(vessel.mainBody.referenceBody.gravParameter / 1000000000), (vessel.mainBody.referenceBody.gravParameter / 1000000000),
(vessel.mainBody.orbit.semiMajorAxis / 1000), (vessel.mainBody.orbit.semiMajorAxis / 1000),
(body.orbit.semiMajorAxis / 1000) (body.orbit.semiMajorAxis / 1000)
); );
double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( double dv2 = VOID_Tools.Younata_DeltaVToExitSOI(
(vessel.mainBody.gravParameter / 1000000000), (vessel.mainBody.gravParameter / 1000000000),
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
(vessel.mainBody.sphereOfInfluence / 1000), (vessel.mainBody.sphereOfInfluence / 1000),
Math.Abs(dv1) Math.Abs(dv1)
); );
double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint(
(vessel.orbit.semiMajorAxis / 1000), (vessel.orbit.semiMajorAxis / 1000),
dv2, dv2,
(Math.PI / 2.0), (Math.PI / 2.0),
(vessel.mainBody.gravParameter / 1000000000) (vessel.mainBody.gravParameter / 1000000000)
); );
   
double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle(
body.orbit.LAN, body.orbit.LAN,
body.orbit.orbitPercent, body.orbit.orbitPercent,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
); );
double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle(
FlightGlobals.ActiveVessel.longitude, FlightGlobals.ActiveVessel.longitude,
FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
); );
   
double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
vessel.mainBody.orbit.semiMajorAxis, vessel.mainBody.orbit.semiMajorAxis,
body.orbit.semiMajorAxis, body.orbit.semiMajorAxis,
vessel.mainBody.referenceBody.gravParameter vessel.mainBody.referenceBody.gravParameter
) % 360; ) % 360;
   
double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
//double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle); //double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle);
   
//new stuff //new stuff
// //
double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle); double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle);
// //
// //
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Phase angle (curr/trans):"); GUILayout.Label("Phase angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ejection angle (curr/trans):"); GUILayout.Label("Ejection angle (curr/trans):");
GUILayout.Label( GUILayout.Label(
adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",
GUILayout.ExpandWidth(false) GUILayout.ExpandWidth(false)
); );
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Transfer velocity:"); GUILayout.Label("Transfer velocity:");
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
public static string get_heading_text(double heading) public static string get_heading_text(double heading)
{ {
if (heading > 348.75 || heading <= 11.25) if (heading > 348.75 || heading <= 11.25)
return "N"; return "N";
else if (heading > 11.25 && heading <= 33.75) else if (heading > 11.25 && heading <= 33.75)
return "NNE"; return "NNE";
else if (heading > 33.75 && heading <= 56.25) else if (heading > 33.75 && heading <= 56.25)
return "NE"; return "NE";
else if (heading > 56.25 && heading <= 78.75) else if (heading > 56.25 && heading <= 78.75)
return "ENE"; return "ENE";
else if (heading > 78.75 && heading <= 101.25) else if (heading > 78.75 && heading <= 101.25)
return "E"; return "E";
else if (heading > 101.25 && heading <= 123.75) else if (heading > 101.25 && heading <= 123.75)
return "ESE"; return "ESE";
else if (heading > 123.75 && heading <= 146.25) else if (heading > 123.75 && heading <= 146.25)
return "SE"; return "SE";
else if (heading > 146.25 && heading <= 168.75) else if (heading > 146.25 && heading <= 168.75)
return "SSE"; return "SSE";
else if (heading > 168.75 && heading <= 191.25) else if (heading > 168.75 && heading <= 191.25)
return "S"; return "S";
else if (heading > 191.25 && heading <= 213.75) else if (heading > 191.25 && heading <= 213.75)
return "SSW"; return "SSW";
else if (heading > 213.75 && heading <= 236.25) else if (heading > 213.75 && heading <= 236.25)
return "SW"; return "SW";
else if (heading > 236.25 && heading <= 258.75) else if (heading > 236.25 && heading <= 258.75)
return "WSW"; return "WSW";
else if (heading > 258.75 && heading <= 281.25) else if (heading > 258.75 && heading <= 281.25)
return "W"; return "W";
else if (heading > 281.25 && heading <= 303.75) else if (heading > 281.25 && heading <= 303.75)
return "WNW"; return "WNW";
else if (heading > 303.75 && heading <= 326.25) else if (heading > 303.75 && heading <= 326.25)
return "NW"; return "NW";
else if (heading > 326.25 && heading <= 348.75) else if (heading > 326.25 && heading <= 348.75)
return "NNW"; return "NNW";
else else
return ""; return "";
} }
} }
   
public class CBListComparer : IComparer<CelestialBody> public class CBListComparer : IComparer<CelestialBody>
{ {
public int Compare(CelestialBody bodyA, CelestialBody bodyB) public int Compare(CelestialBody bodyA, CelestialBody bodyB)
{ {
Tools.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB); Tools.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB);
   
if (bodyA == null && bodyB == null) if (bodyA == null && bodyB == null)
{ {
Tools.PostDebugMessage(this, "both bodies are null, returning 0"); Tools.PostDebugMessage(this, "both bodies are null, returning 0");
return 0; return 0;
} }
if (bodyA == null) if (bodyA == null)
{ {
Tools.PostDebugMessage(this, "bodyA is null, returning -1"); Tools.PostDebugMessage(this, "bodyA is null, returning -1");
return -1; return -1;
} }
if (bodyB == null) if (bodyB == null)
{ {
Tools.PostDebugMessage(this, "bodyB is null, returning 1"); Tools.PostDebugMessage(this, "bodyB is null, returning 1");
return 1; return 1;
} }
   
Tools.PostDebugMessage(this, "bodies are not null, carrying on"); Tools.PostDebugMessage(this, "bodies are not null, carrying on");
   
if (object.ReferenceEquals(bodyA, bodyB)) if (object.ReferenceEquals(bodyA, bodyB))
{ {
Tools.PostDebugMessage(this, "bodies are equal, returning 0"); Tools.PostDebugMessage(this, "bodies are equal, returning 0");
return 0; return 0;
} }
   
Tools.PostDebugMessage(this, "bodies are not equal, carrying on"); Tools.PostDebugMessage(this, "bodies are not equal, carrying on");
   
if (bodyA.orbitDriver == null) if (bodyA.orbitDriver == null)
{ {
Tools.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1"); Tools.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1");
return 1; return 1;
} }
if (bodyB.orbitDriver == null) if (bodyB.orbitDriver == null)
{ {
Tools.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1"); Tools.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1");
return -1; return -1;
} }
   
Tools.PostDebugMessage(this, "orbits are not null, carrying on"); Tools.PostDebugMessage(this, "orbits are not null, carrying on");
   
if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody) if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody)
{ {
Tools.PostDebugMessage(this, "bodies share a parent, comparing SMAs"); Tools.PostDebugMessage(this, "bodies share a parent, comparing SMAs");
return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis); return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis);
} }
   
Tools.PostDebugMessage(this, "orbits do not share a parent, carrying on"); Tools.PostDebugMessage(this, "orbits do not share a parent, carrying on");
   
if (bodyA.hasAncestor(bodyB)) if (bodyA.hasAncestor(bodyB))
{ {
Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1"); Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1");
return -1; return -1;
} }
if (bodyB.hasAncestor(bodyA)) if (bodyB.hasAncestor(bodyA))
{ {
Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1"); Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1");
return 1; return 1;
} }
   
Tools.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one"); Tools.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one");
   
if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB)) if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB))
{ {
Tools.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName); Tools.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName);
return this.Compare(bodyA, bodyB); return this.Compare(bodyA, bodyB);
} }
   
Tools.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName); Tools.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName);
   
return 0; return 0;
} }
} }
} }
   
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid> <ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>VOID</RootNamespace> <RootNamespace>VOID</RootNamespace>
<AssemblyName>VOID</AssemblyName> <AssemblyName>VOID</AssemblyName>
<CodePage>65001</CodePage> <CodePage>65001</CodePage>
<UseMSBuildEngine>False</UseMSBuildEngine> <UseMSBuildEngine>False</UseMSBuildEngine>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ReleaseVersion>0.11</ReleaseVersion> <ReleaseVersion>0.11</ReleaseVersion>
<SynchReleaseVersion>false</SynchReleaseVersion> <SynchReleaseVersion>false</SynchReleaseVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG; TRACE</DefineConstants> <DefineConstants>DEBUG; TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" /> <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' ">
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" /> <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG; TRACE</DefineConstants> <DefineConstants>DEBUG; TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" /> <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' ">
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" /> <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Compile Include="VOID_HUD.cs" /> <Compile Include="VOID_HUD.cs" />
<Compile Include="VOID_Orbital.cs" /> <Compile Include="VOID_Orbital.cs" />
<Compile Include="VOID_SurfAtmo.cs" /> <Compile Include="VOID_SurfAtmo.cs" />
<Compile Include="VOID_VesselInfo.cs" /> <Compile Include="VOID_VesselInfo.cs" />
<Compile Include="VOID_Transfer.cs" /> <Compile Include="VOID_Transfer.cs" />
<Compile Include="VOID_CBInfoBrowser.cs" /> <Compile Include="VOID_CBInfoBrowser.cs" />
<Compile Include="VOID_Rendezvous.cs" /> <Compile Include="VOID_Rendezvous.cs" />
<Compile Include="VOID_VesselRegister.cs" /> <Compile Include="VOID_VesselRegister.cs" />
<Compile Include="VOID_DataLogger.cs" /> <Compile Include="VOID_DataLogger.cs" />
<Compile Include="VOID_EditorHUD.cs" /> <Compile Include="VOID_EditorHUD.cs" />
<Compile Include="VOID_Localization.cs" /> <Compile Include="VOID_Localization.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VOID_HUDAdvanced.cs" /> <Compile Include="VOID_HUDAdvanced.cs" />
<Compile Include="VOID_TWR.cs" /> <Compile Include="VOID_TWR.cs" />
<Compile Include="VOID_CareerStatus.cs" /> <Compile Include="VOID_CareerStatus.cs" />
<Compile Include="VOID_StageInfo.cs" /> <Compile Include="VOID_StageInfo.cs" />
<Compile Include="VOID_Styles.cs" /> <Compile Include="VOID_Styles.cs" />
<Compile Include="VOID_Data.cs" /> <Compile Include="VOID_Data.cs" />
<Compile Include="VOIDMaster_Flight.cs" /> <Compile Include="VOIDMaster_Flight.cs" />
<Compile Include="VOIDMaster_Editor.cs" /> <Compile Include="VOIDMaster_Editor.cs" />
<Compile Include="VOIDMaster_SpaceCentre.cs" /> <Compile Include="VOIDMaster_SpaceCentre.cs" />
<Compile Include="VOIDCore_SpaceCentre.cs" /> <Compile Include="VOIDCore_SpaceCentre.cs" />
<Compile Include="VOIDCore_Flight.cs" /> <Compile Include="VOIDCore_Flight.cs" />
<Compile Include="VOIDCore_Editor.cs" /> <Compile Include="VOIDCore_Editor.cs" />
<Compile Include="VOIDCore_Generic.cs" /> <Compile Include="VOIDCore_Generic.cs" />
<Compile Include="API\IVOID_Module.cs" /> <Compile Include="API\IVOID_Module.cs" />
<Compile Include="API\VOIDCore.cs" /> <Compile Include="API\VOIDCore.cs" />
<Compile Include="API\IVOID_SaveValue.cs" /> <Compile Include="API\IVOID_SaveValue.cs" />
<Compile Include="API\IVOID_DataValue.cs" /> <Compile Include="API\IVOID_DataValue.cs" />
<Compile Include="API\VOID_Module.cs" /> <Compile Include="API\VOID_Module.cs" />
<Compile Include="Tools\VOID_Tools.cs" /> <Compile Include="Tools\VOID_Tools.cs" />
<Compile Include="Tools\VOID_DataValue.cs" /> <Compile Include="Tools\VOID_DataValue.cs" />
<Compile Include="Tools\VOID_SaveValue.cs" /> <Compile Include="Tools\VOID_SaveValue.cs" />
<Compile Include="API\VOID_HUDModule.cs" /> <Compile Include="API\VOID_HUDModule.cs" />
<Compile Include="API\VOID_SingletonModule.cs" /> <Compile Include="API\VOID_SingletonModule.cs" />
<Compile Include="API\Attributes\VOID_ScenesAttribute.cs" /> <Compile Include="API\Attributes\VOID_ScenesAttribute.cs" />
<Compile Include="API\Attributes\AVOID_SaveValue.cs" /> <Compile Include="API\Attributes\AVOID_SaveValue.cs" />
<Compile Include="API\VOIDMaster.cs" /> <Compile Include="API\VOIDMaster.cs" />
<Compile Include="API\Attributes\VOID_GameModesAttribute.cs" /> <Compile Include="API\Attributes\VOID_GameModesAttribute.cs" />
  <Compile Include="VOID_ConfigWindow.cs" />
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>
<Properties> <Properties>
<Policies> <Policies>
<TextStylePolicy FileWidth="120" TabsToSpaces="False" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" /> <TextStylePolicy FileWidth="120" TabsToSpaces="False" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
</Policies> </Policies>
</Properties> </Properties>
</MonoDevelop> </MonoDevelop>
</ProjectExtensions> </ProjectExtensions>
<ItemGroup> <ItemGroup>
<Reference Include="System"> <Reference Include="System">
<HintPath>..\_KSPAssemblies\System.dll</HintPath> <HintPath>..\_KSPAssemblies\System.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath> <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath> <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj"> <ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj">
<Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project> <Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project>
<Name>ToadicusTools</Name> <Name>ToadicusTools</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj"> <ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj">
<Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project> <Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project>
<Name>VesselSimulator</Name> <Name>VesselSimulator</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="GameData\VOID\Textures\ATM_VOID.cfg" /> <None Include="GameData\VOID\Textures\ATM_VOID.cfg" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="API\" /> <Folder Include="API\" />
<Folder Include="Tools\" /> <Folder Include="Tools\" />
<Folder Include="API\Attributes\" /> <Folder Include="API\Attributes\" />
</ItemGroup> </ItemGroup>
</Project> </Project>
   
// VOID // VOID
// //
// VOID_EditorCore.cs // VOID_EditorCore.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.EDITOR)] [VOID_Scenes(GameScenes.EDITOR)]
public class VOIDCore_Editor : VOIDCore_Generic<VOIDCore_Editor> public class VOIDCore_Editor : VOIDCore_Generic<VOIDCore_Editor>
{ {
public VOIDCore_Editor() : base()  
{  
this.Name = "VOID Core: Editor";  
}  
   
public override void FixedUpdate() {} public override void FixedUpdate() {}
} }
} }
   
   
// VOID // VOID
// //
// VOIDCore_Flight.cs // VOIDCore_Flight.cs
// //
// Copyright © 2015, toadicus // Copyright © 2015, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using UnityEngine; using UnityEngine;
  using ToadicusTools;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.FLIGHT)] [VOID_Scenes(GameScenes.FLIGHT)]
public class VOIDCore_Flight : VOIDCore_Generic<VOIDCore_Flight> public class VOIDCore_Flight : VOIDCore_Generic<VOIDCore_Flight>
{ {
public VOIDCore_Flight()  
{  
base.Name = "VOID Core: Flight";  
}  
   
public override void DrawConfigurables() public override void DrawConfigurables()
{ {
if (HighLogic.LoadedSceneIsFlight) if (HighLogic.LoadedSceneIsFlight)
{ {
this.consumeResource.value = GUILayout.Toggle(this.consumeResource, "Consume Resources"); this.consumeResource.value = GUITools.Toggle(this.consumeResource, "Consume Resources");
} }
   
base.DrawConfigurables(); base.DrawConfigurables();
} }
} }
} }
   
   
// VOID // VOID
// //
// VOIDCore_Generic.cs // VOIDCore_Generic.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public abstract class VOIDCore_Generic<T> : VOID_SingletonModule<T>, IVOID_Module, IDisposable public abstract class VOIDCore_Generic<T> : VOID_SingletonModule<T>, IVOID_Module, IDisposable
where T : VOID_Module, new() where T : VOID_Module, new()
{ {
/* /*
* Fields * Fields
* */ * */
protected string VoidName = "VOID"; protected string VoidName = "VOID";
protected string VoidVersion; protected string VoidVersion;
   
[AVOID_SaveValue("configValue")] [AVOID_SaveValue("configValue")]
protected VOID_SaveValue<int> _configVersion = VOIDCore.CONFIG_VERSION; protected VOID_SaveValue<int> _configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
   
protected List<IVOID_Module> _modules = new List<IVOID_Module>(); protected List<IVOID_Module> _modules = new List<IVOID_Module>();
protected bool _modulesLoaded = false; protected bool _modulesLoaded = false;
   
[AVOID_SaveValue("mainWindowPos")]  
protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f);  
[AVOID_SaveValue("mainGuiMinimized")]  
protected VOID_SaveValue<bool> mainGuiMinimized = false;  
   
[AVOID_SaveValue("configWindowPos")]  
protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f);  
[AVOID_SaveValue("configWindowMinimized")]  
   
protected VOID_SaveValue<bool> configWindowMinimized = true;  
   
protected Texture2D VOIDIconTexture; protected Texture2D VOIDIconTexture;
protected string VOIDIconOnActivePath; protected string VOIDIconOnActivePath;
protected string VOIDIconOnInactivePath; protected string VOIDIconOnInactivePath;
protected string VOIDIconOffActivePath; protected string VOIDIconOffActivePath;
protected string VOIDIconOffInactivePath; protected string VOIDIconOffInactivePath;
   
protected GUIStyle iconStyle; protected GUIStyle iconStyle;
   
protected int windowBaseID = -96518722; protected int windowBaseID = -96518722;
protected int _windowID = 0; protected int _windowID = 0;
   
protected bool GUIStylesLoaded = false; protected bool GUIStylesLoaded = false;
   
protected CelestialBody _homeBody; protected CelestialBody _homeBody;
   
[AVOID_SaveValue("togglePower")] [AVOID_SaveValue("togglePower")]
public VOID_SaveValue<bool> togglePower = true; public VOID_SaveValue<bool> togglePower = (VOID_SaveValue<bool>)true;
   
public override bool powerAvailable { get; protected set; } public override bool powerAvailable { get; protected set; }
   
[AVOID_SaveValue("consumeResource")] [AVOID_SaveValue("consumeResource")]
protected VOID_SaveValue<bool> consumeResource = false; protected VOID_SaveValue<bool> consumeResource = (VOID_SaveValue<bool>)false;
   
[AVOID_SaveValue("resourceName")] [AVOID_SaveValue("resourceName")]
protected VOID_SaveValue<string> resourceName = "ElectricCharge"; protected VOID_SaveValue<string> resourceName = (VOID_SaveValue<string>)"ElectricCharge";
   
[AVOID_SaveValue("resourceRate")] [AVOID_SaveValue("resourceRate")]
protected VOID_SaveValue<float> resourceRate = 0.2f; protected VOID_SaveValue<float> resourceRate = (VOID_SaveValue<float>)0.2f;
   
[AVOID_SaveValue("updatePeriod")] [AVOID_SaveValue("updatePeriod")]
protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f; protected VOID_SaveValue<double> _updatePeriod = (VOID_SaveValue<double>)(1001f / 15000f);
protected string stringFrequency; protected string stringFrequency;
   
[AVOID_SaveValue("vesselSimActive")] [AVOID_SaveValue("vesselSimActive")]
protected VOID_SaveValue<bool> vesselSimActive; protected VOID_SaveValue<bool> vesselSimActive;
   
// Vessel Type Housekeeping // Vessel Type Housekeeping
protected List<VesselType> _allVesselTypes = new List<VesselType>(); protected List<VesselType> _allVesselTypes = new List<VesselType>();
protected bool vesselTypesLoaded = false; protected bool vesselTypesLoaded = false;
   
protected string defaultSkin = "KSP window 2"; protected string defaultSkin = "KSP window 2";
   
[AVOID_SaveValue("defaultSkin")] [AVOID_SaveValue("defaultSkin")]
protected VOID_SaveValue<string> _skinName; protected VOID_SaveValue<string> _skinName;
protected int _skinIdx; protected int _skinIdx;
   
protected Dictionary<string, GUISkin> validSkins; protected Dictionary<string, GUISkin> validSkins;
protected string[] skinNames; protected string[] skinNames;
protected string[] forbiddenSkins = protected string[] forbiddenSkins =
{ {
"PlaqueDialogSkin", "PlaqueDialogSkin",
"FlagBrowserSkin", "FlagBrowserSkin",
"SSUITextAreaDefault", "SSUITextAreaDefault",
"ExperimentsDialogSkin", "ExperimentsDialogSkin",
"ExpRecoveryDialogSkin", "ExpRecoveryDialogSkin",
  "KSP window 1",
  "KSP window 3",
"KSP window 5", "KSP window 5",
"KSP window 6", "KSP window 6",
"PartTooltipSkin", "PartTooltipSkin",
"KSCContextMenuSkin" "KSCContextMenuSkin"
}; };
protected bool skinsLoaded = false; protected bool skinsLoaded = false;
   
public override bool configDirty { get; set; } public override bool configDirty { get; set; }
   
internal IButton ToolbarButton; internal IButton ToolbarButton;
   
internal ApplicationLauncherButton AppLauncherButton; internal ApplicationLauncherButton AppLauncherButton;
   
/* /*
* Properties * Properties
* */ * */
public override int configVersion public override int configVersion
{ {
get get
{ {
return this._configVersion; return this._configVersion;
} }
} }
   
public bool factoryReset public bool factoryReset
{ {
get; get;
protected set; protected set;
} }
   
public override List<IVOID_Module> Modules public override List<IVOID_Module> Modules
{ {
get get
{ {
return this._modules; return this._modules;
} }
} }
   
public override GUISkin Skin public override GUISkin Skin
{ {
get get
{ {
if (this.skinsLoaded) if (this.skinsLoaded)
{ {
try try
{ {
return this.validSkins[this._skinName]; return this.validSkins[this._skinName];
} }
catch catch
{ {
} }
} }
   
return AssetBase.GetGUISkin(this.defaultSkin); return AssetBase.GetGUISkin(this.defaultSkin);
} }
} }
   
public override int windowID public override int windowID
{ {
get get
{ {
if (this._windowID == 0) if (this._windowID == 0)
{ {
this._windowID = this.windowBaseID; this._windowID = this.windowBaseID;
} }
return this._windowID++; return this._windowID++;
} }
} }
   
public override List<CelestialBody> allBodies public override List<CelestialBody> allBodies
{ {
get get
{ {
return FlightGlobals.Bodies; return FlightGlobals.Bodies;
} }
} }
   
public override List<CelestialBody> sortedBodyList public override List<CelestialBody> sortedBodyList
{ {
get; get;
protected set; protected set;
} }
   
public override CelestialBody HomeBody public override CelestialBody HomeBody
{ {
get get
{ {
if (this._homeBody == null) if (this._homeBody == null)
{ {
if (Planetarium.fetch != null) if (Planetarium.fetch != null)
{ {
this._homeBody = Planetarium.fetch.Home; this._homeBody = Planetarium.fetch.Home;
} }
} }
   
return this._homeBody; return this._homeBody;
} }
} }
   
public override List<VesselType> allVesselTypes public override List<VesselType> allVesselTypes
{ {
get get
{ {
return this._allVesselTypes; return this._allVesselTypes;
} }
} }
   
public override float updateTimer public override float updateTimer
{ {
get; get;
protected set; protected set;
} }
   
   
public override double updatePeriod public override double updatePeriod
{ {
get get
{ {
return this._updatePeriod; return this._updatePeriod;
} }
} }
   
public override Stage[] Stages public override Stage[] Stages
{ {
get; get;
protected set; protected set;
} }
   
public override Stage LastStage public override Stage LastStage
{ {
get; get;
protected set; protected set;
} }
   
protected IconState powerState protected IconState powerState
{ {
get get
{ {
if (this.togglePower && this.powerAvailable) if (this.togglePower && this.powerAvailable)
{ {
return IconState.PowerOn; return IconState.PowerOn;
} }
else else
{ {
return IconState.PowerOff; return IconState.PowerOff;
} }
   
} }
} }
   
protected IconState activeState protected IconState activeState
{ {
get get
{ {
if (this.mainGuiMinimized) if (this.toggleActive)
{ {
return IconState.Inactive; return IconState.Inactive;
} }
else else
{ {
return IconState.Active; return IconState.Active;
} }
   
} }
} }
   
  private bool useToolbarManager;
   
protected bool UseToolbarManager protected bool UseToolbarManager
{ {
get get
{ {
return useToolbarManager & ToolbarManager.ToolbarAvailable; return useToolbarManager & ToolbarManager.ToolbarAvailable;
} }
set set
{ {
if (useToolbarManager == value) if (useToolbarManager == value)
{ {
return; return;
} }
   
if (value == false && this.ToolbarButton != null) if (value == false && this.ToolbarButton != null)
{ {
this.ToolbarButton.Destroy(); this.ToolbarButton.Destroy();
this.ToolbarButton = null; this.ToolbarButton = null;
} }
if (value == true) if (value == true)
{ {
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
this.AppLauncherButton = null; this.AppLauncherButton = null;
} }
   
this.InitializeToolbarButton(); this.InitializeToolbarButton();
} }
   
useToolbarManager = value; useToolbarManager = value;
} }
} }
   
protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes
{ {
get get
{ {
return HighLogic.LoadedScene.ToAppScenes(); return HighLogic.LoadedScene.ToAppScenes();
} }
} }
   
/* /*
* Events * Events
* */ * */
public override event VOIDEventHandler onApplicationQuit; public override event VOIDEventHandler onApplicationQuit;
public override event VOIDEventHandler onSkinChanged; public override event VOIDEventHandler onSkinChanged;
   
/* /*
* Methods * Methods
* */ * */
public override void DrawGUI() public override void DrawGUI()
{ {
this._windowID = this.windowBaseID; this._windowID = this.windowBaseID;
   
if (!this._modulesLoaded) if (!this._modulesLoaded)
{ {
this.LoadModulesOfType<IVOID_Module>(); this.LoadModulesOfType<IVOID_Module>();
} }
   
if (!this.skinsLoaded) if (!this.skinsLoaded)
{ {
this.LoadSkins(); this.LoadSkins();
} }
   
GUI.skin = this.Skin; GUI.skin = this.Skin;
   
if (!this.GUIStylesLoaded) if (!this.GUIStylesLoaded)
{ {
this.LoadGUIStyles(); this.LoadGUIStyles();
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"ToolbarAvailable: {0}, UseToobarManager: {1}", "ToolbarAvailable: {0}, UseToobarManager: {1}",
ToolbarManager.ToolbarAvailable, ToolbarManager.ToolbarAvailable,
this.UseToolbarManager); this.UseToolbarManager);
} }
   
if (!this.UseToolbarManager) if (!this.UseToolbarManager)
{ {
if (this.AppLauncherButton == null) if (this.AppLauncherButton == null)
{ {
Tools.PostDebugMessage(this, Tools.PostDebugMessage(this,
"UseToolbarManager = false (ToolbarAvailable = {0}) and " + "UseToolbarManager = false (ToolbarAvailable = {0}) and " +
"AppLauncherButton is null, making AppLauncher button.", "AppLauncherButton is null, making AppLauncher button.",
ToolbarManager.ToolbarAvailable ToolbarManager.ToolbarAvailable
); );
this.InitializeAppLauncherButton(); this.InitializeAppLauncherButton();
} }
} }
else if (this.ToolbarButton == null) else if (this.ToolbarButton == null)
{ {
Tools.PostDebugMessage(this, Tools.PostDebugMessage(this,
"UseToolbarManager = true (ToolbarAvailable = {0}) and " + "UseToolbarManager = true (ToolbarAvailable = {0}) and " +
"ToolbarButton is null, making Toolbar button.", "ToolbarButton is null, making Toolbar button.",
ToolbarManager.ToolbarAvailable ToolbarManager.ToolbarAvailable
); );
this.InitializeToolbarButton(); this.InitializeToolbarButton();
} }
   
if (!this.mainGuiMinimized) if (this.toggleActive)
{ {
  base.DrawGUI();
Rect _mainWindowPos = this.mainWindowPos;  
   
_mainWindowPos = GUILayout.Window(  
this.windowID,  
_mainWindowPos,  
VOID_Tools.GetWindowHandler(this.VOIDMainWindow),  
string.Join(" ", new string[] { this.VoidName, this.VoidVersion }),  
GUILayout.Width(250f),  
GUILayout.Height(50f),  
GUILayout.ExpandWidth(true),  
GUILayout.ExpandHeight(true)  
);  
   
if (HighLogic.LoadedSceneIsEditor)  
{  
_mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);  
}  
else  
{  
_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);  
}  
   
if (_mainWindowPos != this.mainWindowPos)  
{  
this.mainWindowPos = _mainWindowPos;  
}  
}  
   
if (!this.configWindowMinimized && !this.mainGuiMinimized)  
{  
Rect _configWindowPos = this.configWindowPos;  
   
_configWindowPos = GUILayout.Window(  
this.windowID,  
_configWindowPos,  
VOID_Tools.GetWindowHandler(this.VOIDConfigWindow),  
string.Join(" ", new string[] { this.VoidName, "Configuration" }),  
GUILayout.Width(250),  
GUILayout.Height(50)  
);  
   
if (HighLogic.LoadedSceneIsEditor)  
{  
_configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);  
}  
else  
{  
_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);  
}  
   
if (_configWindowPos != this.configWindowPos)  
{  
this.configWindowPos = _configWindowPos;  
}  
} }
} }
   
public virtual void Update() public virtual void Update()
{ {
this.LoadBeforeUpdate(); this.LoadBeforeUpdate();
   
if ( if (
this.vesselSimActive && this.vesselSimActive &&
( (
this.vessel != null || this.vessel != null ||
( (
HighLogic.LoadedSceneIsEditor && HighLogic.LoadedSceneIsEditor &&
EditorLogic.RootPart != null && EditorLogic.RootPart != null &&
EditorLogic.SortedShipList.Count > 0 EditorLogic.SortedShipList.Count > 0
) )
) )
) )
{ {
Tools.PostDebugMessage(this, "Updating SimManager."); Tools.PostDebugMessage(this, "Updating SimManager.");
this.UpdateSimManager(); this.UpdateSimManager();
} }
   
if (!this.guiRunning) if (!this.guiRunning)
{ {
this.StartGUI(); this.StartGUI();
} }
   
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
if ( if (
!module.guiRunning && !module.guiRunning &&
module.toggleActive && module.toggleActive &&
module.inValidScene && module.inValidScene &&
( (
!HighLogic.LoadedSceneIsEditor || !HighLogic.LoadedSceneIsEditor ||
(EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0) (EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0)
) )
) )
{ {
module.StartGUI(); module.StartGUI();
} }
if ( if (
module.guiRunning && module.guiRunning &&
( (
!module.toggleActive || !module.toggleActive ||
!this.togglePower || !this.togglePower ||
!module.inValidScene || !module.inValidScene ||
this.factoryReset || this.factoryReset ||
( (
HighLogic.LoadedSceneIsEditor && HighLogic.LoadedSceneIsEditor &&
(EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0) (EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)
) )
) )
) )
{ {
module.StopGUI(); module.StopGUI();
} }
   
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).Update(); ((IVOID_BehaviorModule)module).Update();
} }
} }
   
this.CheckAndSave(); this.CheckAndSave();
this.updateTimer += Time.deltaTime; this.updateTimer += Time.deltaTime;
} }
   
public virtual void FixedUpdate() public virtual void FixedUpdate()
{ {
bool newPowerState = this.powerAvailable; bool newPowerState = this.powerAvailable;
   
if (this.togglePower && this.consumeResource && if (this.togglePower && this.consumeResource &&
this.vessel.vesselType != VesselType.EVA && this.vessel.vesselType != VesselType.EVA &&
TimeWarp.deltaTime != 0) TimeWarp.deltaTime != 0)
{ {
float powerReceived = this.vessel.rootPart.RequestResource( float powerReceived = this.vessel.rootPart.RequestResource(
this.resourceName, this.resourceName,
this.resourceRate * TimeWarp.fixedDeltaTime this.resourceRate * TimeWarp.fixedDeltaTime
); );
   
if (powerReceived > 0) if (powerReceived > 0)
{ {
newPowerState = true; newPowerState = true;
} }
else else
{ {
newPowerState = false; newPowerState = false;
} }
   
if (this.powerAvailable != newPowerState) if (this.powerAvailable != newPowerState)
{ {
this.powerAvailable = newPowerState; this.powerAvailable = newPowerState;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
} }
} }
   
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).FixedUpdate(); ((IVOID_BehaviorModule)module).FixedUpdate();
} }
} }
} }
   
public void OnDestroy() public void OnDestroy()
{ {
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).OnDestroy(); ((IVOID_BehaviorModule)module).OnDestroy();
} }
} }
   
this.Dispose(); this.Dispose();
} }
   
public virtual void OnApplicationQuit() public virtual void OnApplicationQuit()
{ {
if (this.onApplicationQuit != null) if (this.onApplicationQuit != null)
{ {
this.onApplicationQuit(this); this.onApplicationQuit(this);
} }
   
this.OnDestroy(); this.OnDestroy();
} }
   
  public override void StartGUI()
  {
  if (!this.guiRunning)
  {
  RenderingManager.AddToPostDrawQueue(3, this.DrawGUI);
  }
  }
   
public void ResetGUI() public void ResetGUI()
{ {
this.StopGUI(); this.StopGUI();
   
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
module.StopGUI(); module.StopGUI();
module.StartGUI(); module.StartGUI();
} }
   
this.StartGUI(); this.StartGUI();
} }
   
public void VOIDMainWindow(int _) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight) if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight)
{ {
if (!HighLogic.LoadedSceneIsEditor) if (!HighLogic.LoadedSceneIsEditor)
{ {
string str = string.Intern("ON"); string str = string.Intern("ON");
if (togglePower) if (togglePower)
str = string.Intern("OFF"); str = string.Intern("OFF");
if (GUILayout.Button("Power " + str)) if (GUILayout.Button("Power " + str))
{ {
togglePower.value = !togglePower; togglePower.value = !togglePower;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
} }
} }
   
if (togglePower || !HighLogic.LoadedSceneIsFlight) if (togglePower || !HighLogic.LoadedSceneIsFlight)
{ {
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (module is VOID_ConfigWindow)
  {
module.toggleActive = GUILayout.Toggle( continue;
module.toggleActive, }
GUIContent.none,  
GUILayout.ExpandWidth(false) module.toggleActive = GUITools.Toggle(module.toggleActive, module.Name);
);  
   
GUILayout.Label(module.Name, GUILayout.ExpandWidth(true));  
   
GUILayout.EndHorizontal();  
} }
} }
} }
else else
{ {
GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed); GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); VOID_ConfigWindow.Instance.toggleActive = GUITools.Toggle(
  VOID_ConfigWindow.Instance.toggleActive,
this.configWindowMinimized.value = !GUILayout.Toggle( "Configuration"
!this.configWindowMinimized,  
GUIContent.none,  
GUILayout.ExpandWidth(false)  
); );
   
GUILayout.Label("Configuration", GUILayout.ExpandWidth(true));  
   
GUILayout.EndHorizontal();  
   
GUILayout.EndVertical(); GUILayout.EndVertical();
GUI.DragWindow();  
} base.ModuleWindow(id);
   
public void VOIDConfigWindow(int _)  
{  
GUILayout.BeginVertical();  
   
this.DrawConfigurables();  
   
GUILayout.EndVertical();  
GUI.DragWindow();  
} }
   
public override void DrawConfigurables() public override void DrawConfigurables()
{ {
GUIContent _content; GUIContent _content;
   
this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available"); this.UseToolbarManager = GUITools.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available");
   
this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value, this.vesselSimActive.value = GUITools.Toggle(this.vesselSimActive.value,
"Enable Engineering Calculations"); "Enable Engineering Calculations");
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); GUILayout.Label("Skin:", GUILayout.ExpandWidth(false));
   
_content = new GUIContent(); _content = new GUIContent();
   
_content.text = "◄"; _content.text = "◄";
_content.tooltip = "Select previous skin"; _content.tooltip = "Select previous skin";
if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
{ {
this._skinIdx--; this._skinIdx--;
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
this.GetType().Name, this.GetType().Name,
this._skinName, this._skinName,
this.validSkins.Count this.validSkins.Count
)); ));
} }
   
_content.text = this.Skin.name; _content.text = this.Skin.name;
_content.tooltip = "Current skin"; _content.tooltip = "Current skin";
GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true)); GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true));
   
_content.text = "►"; _content.text = "►";
_content.tooltip = "Select next skin"; _content.tooltip = "Select next skin";
if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
{ {
this._skinIdx++; this._skinIdx++;
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
this.GetType().Name, this.GetType().Name,
this._skinName, this._skinName,
this.validSkins.Count this.validSkins.Count
)); ));
} }
   
this._skinIdx %= this.skinNames.Length; this._skinIdx %= this.skinNames.Length;
if (this._skinIdx < 0) if (this._skinIdx < 0)
{ {
this._skinIdx += this.skinNames.Length; this._skinIdx += this.skinNames.Length;
} }
   
if (this._skinName != skinNames[this._skinIdx]) if (this._skinName != skinNames[this._skinIdx])
{ {
this._skinName.value = skinNames[this._skinIdx]; this._skinName.value = skinNames[this._skinIdx];
this.GUIStylesLoaded = false; this.GUIStylesLoaded = false;
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Update Rate (Hz):"); GUILayout.Label("Update Rate (Hz):");
if (this.stringFrequency == null) if (this.stringFrequency == null)
{ {
this.stringFrequency = (1f / this.updatePeriod).ToString(); this.stringFrequency = (1f / this.updatePeriod).ToString();
} }
this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true)); this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true));
   
if (GUILayout.Button("Apply")) if (GUILayout.Button("Apply"))
{ {
double updateFreq = 1f / this.updatePeriod; double updateFreq = 1f / this.updatePeriod;
double.TryParse(stringFrequency, out updateFreq); double.TryParse(stringFrequency, out updateFreq);
this._updatePeriod = 1 / updateFreq; this._updatePeriod.value = 1 / updateFreq;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
foreach (IVOID_Module mod in this.Modules) foreach (IVOID_Module mod in this.Modules)
{ {
mod.DrawConfigurables(); mod.DrawConfigurables();
} }
   
this.factoryReset = GUILayout.Toggle(this.factoryReset, "Factory Reset"); this.factoryReset = GUITools.Toggle(this.factoryReset, "Factory Reset");
} }
   
protected void UpdateSimManager() protected void UpdateSimManager()
{ {
if (SimManager.ResultsReady()) if (SimManager.ResultsReady())
{ {
Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");  
   
this.Stages = SimManager.Stages;  
   
if (this.Stages != null)  
{  
this.LastStage = this.Stages.Last();  
}  
   
if (HighLogic.LoadedSceneIsEditor) if (HighLogic.LoadedSceneIsEditor)
{ {
SimManager.Gravity = VOID_Data.KerbinGee; SimManager.Gravity = VOID_Data.KerbinGee;
} }
else else
{ {
double radius = this.vessel.Radius(); double radius = this.vessel.Radius();
SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius); SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius);
} }
   
SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d)); SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d));
   
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
} }
#if DEBUG #if DEBUG
else else
{ {
Tools.PostDebugMessage(this, "VesselSimulator results not ready."); Tools.PostDebugMessage(this, "VesselSimulator results not ready.");
} }
#endif #endif
  }
   
  protected void GetSimManagerResults()
  {
  Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
   
  this.Stages = SimManager.Stages;
   
  if (this.Stages != null)
  {
  this.LastStage = this.Stages.Last();
  }
} }
   
protected void LoadModulesOfType<U>() protected void LoadModulesOfType<U>()
{ {
Tools.DebugLogger sb = Tools.DebugLogger.New(this); Tools.DebugLogger sb = Tools.DebugLogger.New(this);
sb.AppendLine("Loading modules..."); sb.AppendLine("Loading modules...");
   
foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies) foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies)
{ {
foreach (Type loadedType in assy.assembly.GetExportedTypes()) foreach (Type loadedType in assy.assembly.GetExportedTypes())
{ {
if ( if (
loadedType.IsInterface || loadedType.IsInterface ||
loadedType.IsAbstract || loadedType.IsAbstract ||
!typeof(U).IsAssignableFrom(loadedType) || !typeof(U).IsAssignableFrom(loadedType) ||
typeof(VOIDCore).IsAssignableFrom(loadedType) typeof(VOIDCore).IsAssignableFrom(loadedType)
) )
{ {
continue; continue;
} }
   
sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name); sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name);
   
GameScenes[] validScenes = null;  
   
foreach (var attr in loadedType.GetCustomAttributes(true))  
{  
if (attr is VOID_ScenesAttribute)  
{  
validScenes = ((VOID_ScenesAttribute)attr).ValidScenes;  
   
sb.Append("VOID_ScenesAttribute found;");  
   
break;  
}  
}  
   
if (validScenes == null)  
{  
validScenes = new GameScenes[] { GameScenes.FLIGHT };  
   
   
sb.Append("VOID_ScenesAttribute not found;");  
   
}  
   
sb.AppendFormat(  
" validScenes set to {0}.",  
string.Join(  
", ",  
validScenes.Select(s => Enum.GetName(typeof(GameScenes), s)).ToArray()  
)  
);  
   
if (!validScenes.Contains(HighLogic.LoadedScene))  
{  
sb.AppendFormat(" {0} not found in validScenes, skipping.",  
Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene));  
continue;  
}  
   
sb.AppendFormat("Loading IVOID_Module type {0}...", loadedType.Name);  
   
try try
{ {
this.LoadModule(loadedType); this.LoadModule(loadedType);
sb.AppendLine("Success."); sb.AppendLine("Success.");
} }
catch (Exception ex) catch (Exception ex)
{ {
sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name); sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name);
   
#if DEBUG #if DEBUG
Debug.LogException(ex); Debug.LogException(ex);
#endif #endif
} }
} }
} }
   
this._modulesLoaded = true; this._modulesLoaded = true;
   
sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count); sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count);
   
sb.Print(); sb.Print();
} }
   
protected void LoadModule(Type T) protected void LoadModule(Type T)
{ {
var existingModules = this._modules.Where(mod => mod.GetType().Name == T.Name); var existingModules = this._modules.Where(mod => mod.GetType().Name == T.Name);
if (existingModules.Any()) if (existingModules.Any())
{ {
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: refusing to load {1}: already loaded", "{0}: refusing to load {1}: already loaded",
this.GetType().Name, this.GetType().Name,
T.Name T.Name
)); ));
return; return;
} }
   
var InstanceProperty = T.GetProperty( var InstanceProperty = T.GetProperty(
"Instance", "Instance",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
); );
   
object modInstance = null; object modInstance = null;
IVOID_Module module; IVOID_Module module;
   
if (InstanceProperty != null) if (InstanceProperty != null)
{ {
modInstance = InstanceProperty.GetValue(null, null); modInstance = InstanceProperty.GetValue(null, null);
} }
   
if (modInstance != null) if (modInstance != null)
{ {
module = modInstance as IVOID_Module; module = modInstance as IVOID_Module;
} }
else else
{ {
module = Activator.CreateInstance(T) as IVOID_Module; module = Activator.CreateInstance(T) as IVOID_Module;
} }
   
module.LoadConfig(); if (module.inValidGame && module.inValidScene)
this._modules.Add(module); {
  module.LoadConfig();
Tools.PostDebugMessage(string.Format( this._modules.Add(module);
"{0}: loaded module {1}.",  
this.GetType().Name, Tools.PostDebugMessage(string.Format(
T.Name "{0}: loaded module {1}.",
)); this.GetType().Name,
  T.Name
  ));
  }
} }
   
protected void LoadSkins() protected void LoadSkins()
{ {
Tools.PostDebugMessage("AssetBase has skins: \n" + Tools.PostDebugMessage("AssetBase has skins: \n" +
string.Join("\n\t", string.Join("\n\t",
Resources.FindObjectsOfTypeAll(typeof(GUISkin)) Resources.FindObjectsOfTypeAll(typeof(GUISkin))
.Select(s => s.ToString()) .Select(s => s.ToString())
.ToArray() .ToArray()
) )
); );
   
this.validSkins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)) this.validSkins = Resources.FindObjectsOfTypeAll(typeof(GUISkin))
.Where(s => !this.forbiddenSkins.Contains(s.name)) .Where(s => !this.forbiddenSkins.Contains(s.name))
.Select(s => s as GUISkin) .Select(s => s as GUISkin)
.GroupBy(s => s.name) .GroupBy(s => s.name)
.Select(g => g.First()) .Select(g => g.First())
.ToDictionary(s => s.name); .ToDictionary(s => s.name);
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: loaded {1} GUISkins.", "{0}: loaded {1} GUISkins.",
this.GetType().Name, this.GetType().Name,
this.validSkins.Count this.validSkins.Count
)); ));
   
this.skinNames = this.validSkins.Keys.ToArray(); this.skinNames = this.validSkins.Keys.ToArray();
Array.Sort(this.skinNames); Array.Sort(this.skinNames);
   
int defaultIdx = int.MinValue; int defaultIdx = int.MinValue;
   
for (int i = 0; i < this.skinNames.Length; i++) for (int i = 0; i < this.skinNames.Length; i++)
{ {
if (this.skinNames[i] == this._skinName) if (this.skinNames[i] == this._skinName)
{ {
this._skinIdx = i; this._skinIdx = i;
} }
if (this.skinNames[i] == this.defaultSkin) if (this.skinNames[i] == this.defaultSkin)
{ {
defaultIdx = i; defaultIdx = i;
} }
if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue) if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue)
{ {
break; break;
} }
} }
   
if (this._skinIdx == int.MinValue) if (this._skinIdx == int.MinValue)
{ {
this._skinIdx = defaultIdx; this._skinIdx = defaultIdx;
} }
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: _skinIdx = {1}.", "{0}: _skinIdx = {1}.",
this.GetType().Name, this.GetType().Name,
this._skinName.ToString() this._skinName.ToString()
)); ));
   
this.skinsLoaded = true; this.skinsLoaded = true;
} }
   
protected void LoadGUIStyles() protected void LoadGUIStyles()
{ {
VOID_Styles.OnSkinChanged(); VOID_Styles.OnSkinChanged();
   
if (this.onSkinChanged != null) if (this.onSkinChanged != null)
{ {
this.onSkinChanged(this); this.onSkinChanged(this);
} }
   
this.GUIStylesLoaded = true; this.GUIStylesLoaded = true;
} }
   
protected void LoadVesselTypes() protected void LoadVesselTypes()
{ {
this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToList(); this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToList();
this.vesselTypesLoaded = true; this.vesselTypesLoaded = true;
} }
   
protected void LoadBeforeUpdate() protected void LoadBeforeUpdate()
{ {
if (!this.vesselTypesLoaded) if (!this.vesselTypesLoaded)
{ {
this.LoadVesselTypes(); this.LoadVesselTypes();
} }
   
if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0) if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
{ {
this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies); this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
this.sortedBodyList.Sort(new CBListComparer()); this.sortedBodyList.Sort(new CBListComparer());
this.sortedBodyList.Reverse(); this.sortedBodyList.Reverse();
   
Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray()))); Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
} }
   
} }
   
protected void InitializeToolbarButton() protected void InitializeToolbarButton()
{ {
// Do nothing if (the Toolbar is not available. // Do nothing if (the Toolbar is not available.
if (!ToolbarManager.ToolbarAvailable) if (!ToolbarManager.ToolbarAvailable)
{ {
Tools.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false"); Tools.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false");
return; return;
} }
   
this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle");
this.ToolbarButton.Text = this.VoidName; this.ToolbarButton.Text = this.VoidName;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
   
this.ToolbarButton.Visible = true; this.ToolbarButton.Visible = true;
   
this.ToolbarButton.OnClick += this.ToolbarButton.OnClick +=
(e) => (e) =>
{ {
this.ToggleMainWindow(); this.ToggleMainWindow();
}; };
   
Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name));
} }
   
protected void InitializeAppLauncherButton() protected void InitializeAppLauncherButton()
{ {
if (ApplicationLauncher.Ready) if (ApplicationLauncher.Ready)
{ {
this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication(
this.ToggleMainWindow, this.ToggleMainWindow, this.ToggleMainWindow, this.ToggleMainWindow,
this.appIconVisibleScenes, this.appIconVisibleScenes,
this.VOIDIconTexture this.VOIDIconTexture
); );
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"AppLauncherButton initialized in {0}", "AppLauncherButton initialized in {0}",
Enum.GetName( Enum.GetName(
typeof(GameScenes), typeof(GameScenes),
HighLogic.LoadedScene HighLogic.LoadedScene
) )
); );
} }
} }
   
protected void ToggleMainWindow() protected void ToggleMainWindow()
{ {
this.mainGuiMinimized = !this.mainGuiMinimized; this.toggleActive = !this.toggleActive;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
} }
   
protected void SetIconTexture(IconState state) protected void SetIconTexture(IconState state)
{ {
switch (state) switch (state)
{ {
case (IconState.PowerOff | IconState.Inactive): case (IconState.PowerOff | IconState.Inactive):
this.SetIconTexture(this.VOIDIconOffInactivePath); this.SetIconTexture(this.VOIDIconOffInactivePath);
break; break;
case (IconState.PowerOff | IconState.Active): case (IconState.PowerOff | IconState.Active):
this.SetIconTexture(this.VOIDIconOffActivePath); this.SetIconTexture(this.VOIDIconOffActivePath);
break; break;
case (IconState.PowerOn | IconState.Inactive): case (IconState.PowerOn | IconState.Inactive):
this.SetIconTexture(this.VOIDIconOnInactivePath); this.SetIconTexture(this.VOIDIconOnInactivePath);
break; break;
case (IconState.PowerOn | IconState.Active): case (IconState.PowerOn | IconState.Active):
this.SetIconTexture(this.VOIDIconOnActivePath); this.SetIconTexture(this.VOIDIconOnActivePath);
break; break;
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
   
protected void SetIconTexture(string texturePath) protected void SetIconTexture(string texturePath)
{ {
if (this.ToolbarButton != null) if (this.ToolbarButton != null)
{ {
this.ToolbarButton.TexturePath = texturePath; this.ToolbarButton.TexturePath = texturePath;
} }
   
this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false); this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
   
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
this.AppLauncherButton.SetTexture(VOIDIconTexture); this.AppLauncherButton.SetTexture(VOIDIconTexture);
} }
} }
   
protected virtual void CheckAndSave() protected virtual void CheckAndSave()
{ {
this.saveTimer += Time.deltaTime; this.saveTimer += Time.deltaTime;
   
if (this.saveTimer > 2f) if (this.saveTimer > 2f)
{ {
if (!this.configDirty) if (!this.configDirty)
{ {
return; return;
} }
   
Tools.PostDebugMessage(string.Format( Tools.PostDebugMessage(string.Format(
"{0}: Time to save, checking if configDirty: {1}", "{0}: Time to save, checking if configDirty: {1}",
this.GetType().Name, this.GetType().Name,
this.configDirty this.configDirty
)); ));
   
this.SaveConfig(); this.SaveConfig();
this.saveTimer = 0; this.saveTimer = 0;
} }
} }
   
public override void LoadConfig() public override void LoadConfig()
{ {
base.LoadConfig(); base.LoadConfig();
   
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
module.LoadConfig(); module.LoadConfig();
} }
} }
   
public override void SaveConfig() public override void SaveConfig()
{ {
if (this.configNeedsUpdate && this is VOIDCore_Flight) if (this.configNeedsUpdate && this is VOIDCore_Flight)
{ {
KSP.IO.File.Delete<T>("config.xml"); KSP.IO.File.Delete<T>("config.xml");
} }
   
var config = KSP.IO.PluginConfiguration.CreateForType<T>(); var config = KSP.IO.PluginConfiguration.CreateForType<T>();
   
config.load(); config.load();
   
this._SaveToConfig(config); this._SaveToConfig(config);
   
foreach (IVOID_Module module in this.Modules) foreach (IVOID_Module module in this.Modules)
{ {
module._SaveToConfig(config); module._SaveToConfig(config);
} }
   
config.save(); config.save();
   
this.configDirty = false; this.configDirty = false;
} }
   
public VOIDCore_Generic() public VOIDCore_Generic()
{ {
this.Name = "VOID Core";  
   
System.Version version = this.GetType().Assembly.GetName().Version; System.Version version = this.GetType().Assembly.GetName().Version;
   
this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision); this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision);
   
  this.Name = string.Format("VOID {0}", this.VoidVersion.ToString());
   
this.powerAvailable = true; this.powerAvailable = true;
   
this.toggleActive = true; this.toggleActive = true;
   
this._skinName = this.defaultSkin; this._skinName = (VOID_SaveValue<string>)this.defaultSkin;
this._skinIdx = int.MinValue; this._skinIdx = int.MinValue;
   
this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow"; this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow";
this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow"; this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow";
this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light"; this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light";
this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark"; this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark";
   
this.saveTimer = 0f; this.saveTimer = 0f;
this.updateTimer = 0f; this.updateTimer = 0f;
   
this.vesselSimActive = true; this.vesselSimActive = (VOID_SaveValue<bool>)true;
  SimManager.Atmosphere = 0d;
  SimManager.OnReady += this.GetSimManagerResults;
   
this.UseToolbarManager = ToolbarManager.ToolbarAvailable; this.UseToolbarManager = ToolbarManager.ToolbarAvailable;
   
this.LoadConfig(); this.LoadConfig();
   
this._configVersion = VOIDCore.CONFIG_VERSION; this._configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
   
this.factoryReset = false; this.factoryReset = false;
} }
   
public virtual void Dispose() public virtual void Dispose()
{ {
this.StopGUI(); this.StopGUI();
   
  this.onSkinChanged(this);
   
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
this.AppLauncherButton = null; this.AppLauncherButton = null;
} }
if (this.ToolbarButton != null) if (this.ToolbarButton != null)
{ {
this.ToolbarButton.Destroy(); this.ToolbarButton.Destroy();
this.ToolbarButton = null; this.ToolbarButton = null;
} }
   
_instance = null; _instance = null;
_initialized = false; _initialized = false;
} }
   
protected enum IconState protected enum IconState
{ {
PowerOff = 1, PowerOff = 1,
PowerOn = 2, PowerOn = 2,
Inactive = 4, Inactive = 4,
Active = 8 Active = 8
} }
} }
} }
   
   
// VOID // VOID
// //
// VOIDCore_SpaceCentre.cs // VOIDCore_SpaceCentre.cs
// //
// Copyright © 2015, toadicus // Copyright © 2015, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System; using System;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.SPACECENTER)] [VOID_Scenes(GameScenes.SPACECENTER)]
public class VOIDCore_SpaceCentre : VOIDCore_Generic<VOIDCore_SpaceCentre> public class VOIDCore_SpaceCentre : VOIDCore_Generic<VOIDCore_SpaceCentre>
{ {
public VOIDCore_SpaceCentre() : base()  
{  
base.Name = "VOID Core: SpaceCentre";  
}  
   
public override void FixedUpdate() {} public override void FixedUpdate() {}
} }
} }
   
   
// VOID // VOID
// //
// VOID_CBInfoBrowser.cs // VOID_CBInfoBrowser.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_CBInfoBrowser : VOID_WindowModule public class VOID_CBInfoBrowser : VOID_WindowModule
{ {
[AVOID_SaveValue("selectedBodyIdx1")] [AVOID_SaveValue("selectedBodyIdx1")]
protected VOID_SaveValue<int> selectedBodyIdx1 = 1; protected VOID_SaveValue<int> selectedBodyIdx1;
   
[AVOID_SaveValue("selectedBodyIdx2")] [AVOID_SaveValue("selectedBodyIdx2")]
protected VOID_SaveValue<int> selectedBodyIdx2 = 2; protected VOID_SaveValue<int> selectedBodyIdx2;
   
protected CelestialBody selectedBody1; protected CelestialBody selectedBody1;
protected CelestialBody selectedBody2; protected CelestialBody selectedBody2;
   
[AVOID_SaveValue("toggleOrbital")] [AVOID_SaveValue("toggleOrbital")]
protected VOID_SaveValue<bool> toggleOrbital = false; protected VOID_SaveValue<bool> toggleOrbital;
   
[AVOID_SaveValue("togglePhysical")] [AVOID_SaveValue("togglePhysical")]
protected VOID_SaveValue<bool> togglePhysical = false; protected VOID_SaveValue<bool> togglePhysical;
   
[AVOID_SaveValue("toggleScience")] [AVOID_SaveValue("toggleScience")]
protected VOID_SaveValue<bool> toggleScience = false; protected VOID_SaveValue<bool> toggleScience;
   
public VOID_CBInfoBrowser() public VOID_CBInfoBrowser()
{ {
this.Name = "Celestial Body Information Browser"; this.Name = "Celestial Body Information Browser";
   
this.WindowPos.x = 10; this.WindowPos.x = 10;
this.WindowPos.y = 85; this.WindowPos.y = 85;
   
  this.selectedBodyIdx1 = (VOID_SaveValue<int>)1;
  this.selectedBodyIdx2 = (VOID_SaveValue<int>)2;
   
  this.toggleOrbital = (VOID_SaveValue<bool>)false;
  this.togglePhysical = (VOID_SaveValue<bool>)false;
  this.toggleScience = (VOID_SaveValue<bool>)false;
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int id)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("", GUILayout.ExpandWidth(true)); GUILayout.Label("", GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
selectedBody1 = this.core.allBodies[selectedBodyIdx1]; selectedBody1 = this.core.allBodies[selectedBodyIdx1];
selectedBody2 = this.core.allBodies[selectedBodyIdx2]; selectedBody2 = this.core.allBodies[selectedBodyIdx2];
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1--; selectedBodyIdx1.value--;
if (selectedBodyIdx1 < 0) selectedBodyIdx1 = this.core.allBodies.Count - 1; if (selectedBodyIdx1 < 0)
  {
  selectedBodyIdx1.value = this.core.allBodies.Count - 1;
  }
} }
GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1++; selectedBodyIdx1.value++;
if (selectedBodyIdx1 > this.core.allBodies.Count - 1) selectedBodyIdx1 = 0; if (selectedBodyIdx1 > this.core.allBodies.Count - 1)
  {
  selectedBodyIdx1.value = 0;
  }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2--; selectedBodyIdx2.value--;
if (selectedBodyIdx2 < 0) selectedBodyIdx2 = this.core.allBodies.Count - 1; if (selectedBodyIdx2 < 0)
  {
  selectedBodyIdx2.value = this.core.allBodies.Count - 1;
  }
} }
GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2++; selectedBodyIdx2.value++;
if (selectedBodyIdx2 > this.core.allBodies.Count - 1) selectedBodyIdx2 = 0; if (selectedBodyIdx2 > this.core.allBodies.Count - 1)
  {
  selectedBodyIdx2.value = 0;
  }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
//toggle for orbital info chunk //toggle for orbital info chunk
if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital; if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital;
   
if (toggleOrbital) if (toggleOrbital)
{ {
//begin orbital into horizontal chunk //begin orbital into horizontal chunk
//print("begin orbital info section..."); //print("begin orbital info section...");
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin orbital value labels column //begin orbital value labels column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
//print("printing row labels..."); //print("printing row labels...");
   
GUILayout.Label("Apoapsis:"); GUILayout.Label("Apoapsis:");
GUILayout.Label("Time to Ap:"); GUILayout.Label("Time to Ap:");
GUILayout.Label("Periapsis:"); GUILayout.Label("Periapsis:");
GUILayout.Label("Time to Pe:"); GUILayout.Label("Time to Pe:");
GUILayout.Label("Semi-major axis:"); GUILayout.Label("Semi-major axis:");
GUILayout.Label("Eccentricity:"); GUILayout.Label("Eccentricity:");
GUILayout.Label("Orbital period:"); GUILayout.Label("Orbital period:");
GUILayout.Label("Rotational period:"); GUILayout.Label("Rotational period:");
GUILayout.Label("Velocity:"); GUILayout.Label("Velocity:");
GUILayout.Label("Mean anomaly:"); GUILayout.Label("Mean anomaly:");
GUILayout.Label("True anomaly:"); GUILayout.Label("True anomaly:");
GUILayout.Label("Eccentric anomaly:"); GUILayout.Label("Eccentric anomaly:");
GUILayout.Label("Inclination:"); GUILayout.Label("Inclination:");
GUILayout.Label("Long. ascending node:"); GUILayout.Label("Long. ascending node:");
GUILayout.Label("Arg. of periapsis:"); GUILayout.Label("Arg. of periapsis:");
GUILayout.Label("Tidally locked:"); GUILayout.Label("Tidally locked:");
   
//end orbital value labels column //end orbital value labels column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary orbital values column //begin primary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody1); body_OP_show_orbital_info(selectedBody1);
   
//end primary orbital values column //end primary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary orbital values column //begin secondary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody2); body_OP_show_orbital_info(selectedBody2);
   
//end secondary orbital values column //end secondary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end orbital info horizontal chunk //end orbital info horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
//toggle for physical info chunk //toggle for physical info chunk
if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical; if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical;
   
if (togglePhysical) if (togglePhysical)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin physical info value label column //begin physical info value label column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
GUILayout.Label("Radius:"); GUILayout.Label("Radius:");
GUILayout.Label("Surface area:"); GUILayout.Label("Surface area:");
GUILayout.Label("Volume:"); GUILayout.Label("Volume:");
GUILayout.Label("Mass:"); GUILayout.Label("Mass:");
GUILayout.Label("Density:"); GUILayout.Label("Density:");
GUILayout.Label("Sphere of influence:"); GUILayout.Label("Sphere of influence:");
GUILayout.Label("Natural satellites:"); GUILayout.Label("Natural satellites:");
GUILayout.Label("Artificial satellites:"); GUILayout.Label("Artificial satellites:");
GUILayout.Label("Surface gravity:"); GUILayout.Label("Surface gravity:");
GUILayout.Label("Atmosphere altitude:"); GUILayout.Label("Atmosphere altitude:");
GUILayout.Label("Atmospheric O\u2082:"); GUILayout.Label("Atmospheric O\u2082:");
GUILayout.Label("Has ocean:"); GUILayout.Label("Has ocean:");
   
//end physical info value label column //end physical info value label column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary physical values column //begin primary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody1); body_OP_show_physical_info(selectedBody1);
   
//end primary physical column //end primary physical column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary physical values column //begin secondary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody2); body_OP_show_physical_info(selectedBody2);
   
//end target physical values column //end target physical values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end physical value horizontal chunk //end physical value horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true))) if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true)))
{ {
toggleScience.value = !toggleScience; toggleScience.value = !toggleScience;
} }
   
if (toggleScience) if (toggleScience)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin physical info value label column //begin physical info value label column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
   
/* /*
* public float RecoveryValue = 1f; * public float RecoveryValue = 1f;
   
public float InSpaceHighDataValue = 1f; public float InSpaceHighDataValue = 1f;
   
public float spaceAltitudeThreshold = 250000f; public float spaceAltitudeThreshold = 250000f;
   
public float flyingAltitudeThreshold = 18000f; public float flyingAltitudeThreshold = 18000f;
   
public float InSpaceLowDataValue = 1f; public float InSpaceLowDataValue = 1f;
   
public float SplashedDataValue = 1f; public float SplashedDataValue = 1f;
   
public float LandedDataValue = 1f; public float LandedDataValue = 1f;
   
public float FlyingHighDataValue = 1f; public float FlyingHighDataValue = 1f;
   
public float FlyingLowDataValue = 1f; public float FlyingLowDataValue = 1f;
*/ */
   
GUILayout.Label("Surface Multiplier:"); GUILayout.Label("Surface Multiplier:");
GUILayout.Label("Ocean Multiplier:"); GUILayout.Label("Ocean Multiplier:");
GUILayout.Label("Flying-Low Multiplier:"); GUILayout.Label("Flying-Low Multiplier:");
GUILayout.Label("Flying-High Multiplier:"); GUILayout.Label("Flying-High Multiplier:");
GUILayout.Label("Low Orbit Multiplier:"); GUILayout.Label("Low Orbit Multiplier:");
GUILayout.Label("High Orbit Multiplier:"); GUILayout.Label("High Orbit Multiplier:");
GUILayout.Label("'Flying-High' Altitude:"); GUILayout.Label("'Flying-High' Altitude:");
GUILayout.Label("'High Orbit' Altitude:"); GUILayout.Label("'High Orbit' Altitude:");
GUILayout.Label("Recovery Multiplier:"); GUILayout.Label("Recovery Multiplier:");
   
//end physical info value label column //end physical info value label column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary physical values column //begin primary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
this.cbColumnScience(selectedBody1); this.cbColumnScience(selectedBody1);
   
//end primary physical column //end primary physical column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary physical values column //begin secondary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
this.cbColumnScience(selectedBody2); this.cbColumnScience(selectedBody2);
   
//end target physical values column //end target physical values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end physical value horizontal chunk //end physical value horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUI.DragWindow(); base.ModuleWindow(id);
} }
   
private void body_OP_show_orbital_info(CelestialBody body) private void body_OP_show_orbital_info(CelestialBody body)
{ {
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert mean anomaly into degrees. // Toadicus edit: convert mean anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert eccentric anomaly into degrees. // Toadicus edit: convert eccentric anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else else
{ {
string body_tidally_locked = "No"; string body_tidally_locked = "No";
if (body.tidallyLocked) body_tidally_locked = "Yes"; if (body.tidallyLocked) body_tidally_locked = "Yes";
GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
} }
   
private void body_OP_show_physical_info(CelestialBody body) private void body_OP_show_physical_info(CelestialBody body)
{ {
   
GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// divide by 1000 to convert m to km // divide by 1000 to convert m to km
GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI); double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI);
   
GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
//show # artificial satellites //show # artificial satellites
int num_art_sats = 0; int num_art_sats = 0;
foreach (Vessel v in FlightGlobals.Vessels) foreach (Vessel v in FlightGlobals.Vessels)
{ {
if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++; if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++;
} }
   
GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double g_ASL = (VOIDCore.Constant_G * body.Mass) / (body.Radius * body.Radius); double g_ASL = (VOIDCore.Constant_G * body.Mass) / (body.Radius * body.Radius);
   
GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.atmosphere) if (body.atmosphere)
{ {
GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
string O2 = "No"; string O2 = "No";
if (body.atmosphereContainsOxygen == true) O2 = "Yes"; if (body.atmosphereContainsOxygen == true) O2 = "Yes";
GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
else else
{ {
GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
   
string ocean = "No"; string ocean = "No";
if (body.ocean == true) ocean = "Yes"; if (body.ocean == true) ocean = "Yes";
GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
   
private void cbColumnScience(CelestialBody body) private void cbColumnScience(CelestialBody body)
{ {
/*GUILayout.Label("Surface Science Multiplier:"); /*GUILayout.Label("Surface Science Multiplier:");
GUILayout.Label("Ocean Science Multiplier:"); GUILayout.Label("Ocean Science Multiplier:");
GUILayout.Label("Low-Atmosphere Science Multiplier:"); GUILayout.Label("Low-Atmosphere Science Multiplier:");
GUILayout.Label("High-Atmosphere Science Multiplier:"); GUILayout.Label("High-Atmosphere Science Multiplier:");
GUILayout.Label("Low Orbit Science Multiplier:"); GUILayout.Label("Low Orbit Science Multiplier:");
GUILayout.Label("High Orbit Science Multiplier:"); GUILayout.Label("High Orbit Science Multiplier:");
GUILayout.Label("'In Space' Altitude:"); GUILayout.Label("'In Space' Altitude:");
GUILayout.Label("'Flying' Altitude:"); GUILayout.Label("'Flying' Altitude:");
GUILayout.Label("Recovery Multiplier:");*/ GUILayout.Label("Recovery Multiplier:");*/
   
var scienceValues = body.scienceValues; var scienceValues = body.scienceValues;
   
GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A", body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A", body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A", body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A", body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
scienceValues.spaceAltitudeThreshold.ToString("N0"), scienceValues.spaceAltitudeThreshold.ToString("N0"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"), GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
} }
} }
} }
// VOID // VOID
// //
// VOID_CareerStatus.cs // VOID_CareerStatus.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)] [VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)]
[VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)] [VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)]
public class VOID_CareerStatus : VOID_WindowModule public class VOID_CareerStatus : VOID_WindowModule
{ {
public static VOID_CareerStatus Instance public static VOID_CareerStatus Instance
{ {
get; get;
private set; private set;
} }
   
public static string formatDelta(double delta, string numberFormat) public static string formatDelta(double delta, string numberFormat)
{ {
if (delta > 0) if (delta > 0)
{ {
return string.Format("<color='lime'>{0}↑</color>", delta.ToString(numberFormat, Tools.mySIFormatter)); return string.Format("<color='lime'>{0}↑</color>", delta.ToString(numberFormat, Tools.SIFormatter));
} }
else if (delta < 0) else if (delta < 0)
{ {
return string.Format("<color='red'>{0}↓</color>", delta.ToString(numberFormat, Tools.mySIFormatter)); return string.Format("<color='red'>{0}↓</color>", delta.ToString(numberFormat, Tools.SIFormatter));
} }
else else
{ {
return "0"; return "0";
} }
} }
   
public static string formatDelta(double delta) public static string formatDelta(double delta)
{ {
return formatDelta(delta, "#,##0.##"); return formatDelta(delta, "#,##0.##");
} }
   
public static string formatDelta(float delta) public static string formatDelta(float delta)
{ {
return formatDelta((double)delta); return formatDelta((double)delta);
} }
   
private GUIContent fundsContent; private GUIContent fundsContent;
private GUIContent repContent; private GUIContent repContent;
private GUIContent scienceContent; private GUIContent scienceContent;
   
#pragma warning disable 0414 #pragma warning disable 0414
private Texture2D fundsIconGreen; private Texture2D fundsIconGreen;
private Texture2D fundsIconRed; private Texture2D fundsIconRed;
private Texture2D reputationIconGreen; private Texture2D reputationIconGreen;
private Texture2D reputationIconRed; private Texture2D reputationIconRed;
private Texture2D scienceIcon; private Texture2D scienceIcon;
#pragma warning restore 0414 #pragma warning restore 0414
   
public double lastFundsChange public double lastFundsChange
{ {
get; get;
private set; private set;
} }
   
public float lastRepChange public float lastRepChange
{ {
get; get;
private set; private set;
} }
   
public float lastScienceChange public float lastScienceChange
{ {
get; get;
private set; private set;
} }
   
public double currentFunds public double currentFunds
{ {
get; get;
private set; private set;
} }
   
public float currentReputation public float currentReputation
{ {
get; get;
private set; private set;
} }
   
public float currentScience public float currentScience
{ {
get; get;
private set; private set;
} }
   
private bool currenciesInitialized private bool currenciesInitialized
{ {
get get
{ {
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"Checking init state:" + "Checking init state:" +
"\n\tcurrentFunds={0}" + "\n\tcurrentFunds={0}" +
"\n\tcurrentScience={1}" + "\n\tcurrentScience={1}" +
"\n\tcurrentReputation={2}", "\n\tcurrentReputation={2}",
this.currentFunds, this.currentFunds,
this.currentScience, this.currentScience,
this.currentReputation this.currentReputation
); );
   
return !( return !(
double.IsNaN(this.currentFunds) || double.IsNaN(this.currentFunds) ||
float.IsNaN(this.currentScience) || float.IsNaN(this.currentScience) ||
float.IsNaN(this.currentReputation) float.IsNaN(this.currentReputation)
); );
} }
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
if (Event.current.type != EventType.Layout && !this.currenciesInitialized) if (Event.current.type != EventType.Layout && !this.currenciesInitialized)
{ {
this.initCurrencies(); this.initCurrencies();
} }
   
base.DrawGUI(); base.DrawGUI();
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.fundingStatus.Label); GUILayout.Label(VOID_Data.fundingStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.fundsContent.text = VOID_Data.fundingStatus.Value; this.fundsContent.text = VOID_Data.fundingStatus.Value;
GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.reputationStatus.Label); GUILayout.Label(VOID_Data.reputationStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.repContent.text = VOID_Data.reputationStatus.Value; this.repContent.text = VOID_Data.reputationStatus.Value;
GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.scienceStatus.Label); GUILayout.Label(VOID_Data.scienceStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.scienceContent.text = VOID_Data.scienceStatus.Value; this.scienceContent.text = VOID_Data.scienceStatus.Value;
GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUI.DragWindow(); base.ModuleWindow(id);
} }
   
// TODO: Update event handlers to do something useful with the new "reasons" parameter. // TODO: Update event handlers to do something useful with the new "reasons" parameter.
private void onFundsChange(double newValue, TransactionReasons reasons) private void onFundsChange(double newValue, TransactionReasons reasons)
{ {
this.lastFundsChange = newValue - this.currentFunds; this.lastFundsChange = newValue - this.currentFunds;
this.currentFunds = newValue; this.currentFunds = newValue;
} }
   
private void onRepChange(float newValue, TransactionReasons reasons) private void onRepChange(float newValue, TransactionReasons reasons)
{ {
this.lastRepChange = newValue - this.currentReputation; this.lastRepChange = newValue - this.currentReputation;
this.currentReputation = newValue; this.currentReputation = newValue;
} }
   
private void onScienceChange(float newValue, TransactionReasons reasons) private void onScienceChange(float newValue, TransactionReasons reasons)
{ {
this.lastScienceChange = newValue - this.currentScience; this.lastScienceChange = newValue - this.currentScience;
this.currentScience = newValue; this.currentScience = newValue;
} }
   
private void onGameStateLoad(ConfigNode node) private void onGameStateLoad(ConfigNode node)
{ {
this.initCurrencies(); this.initCurrencies();
} }
   
private void initCurrencies() private void initCurrencies()
{ {
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"Initializing currencies." + "Initializing currencies." +
"\n\tFunding.Instance={0}" + "\n\tFunding.Instance={0}" +
"ResearchAndDevelopment.Instance={1}" + "ResearchAndDevelopment.Instance={1}" +
"Reputation.Instance={2}", "Reputation.Instance={2}",
Funding.Instance == null ? "NULL" : Funding.Instance.ToString(), Funding.Instance == null ? "NULL" : Funding.Instance.ToString(),
ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(), ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(),
Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString() Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString()
); );
   
this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN; this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN;
this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN; this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN;
this.currentScience = ResearchAndDevelopment.Instance != null ? this.currentScience = ResearchAndDevelopment.Instance != null ?
ResearchAndDevelopment.Instance.Science : float.NaN; ResearchAndDevelopment.Instance.Science : float.NaN;
} }
   
/* /*
* MissionRecoveryDialog::fundsIconGreen.name: UiElements_05 * MissionRecoveryDialog::fundsIconGreen.name: UiElements_05
* MissionRecoveryDialog::fundsIconRed.name: UiElements_06 * MissionRecoveryDialog::fundsIconRed.name: UiElements_06
* MissionRecoveryDialog::reputationIconGreen.name: UiElements_07 * MissionRecoveryDialog::reputationIconGreen.name: UiElements_07
* MissionRecoveryDialog::reputationIconRed.name: UiElements_08 * MissionRecoveryDialog::reputationIconRed.name: UiElements_08
* MissionRecoveryDialog::scienceIcon.name: UiElements_12 * MissionRecoveryDialog::scienceIcon.name: UiElements_12
* */ * */
public VOID_CareerStatus() : base() public VOID_CareerStatus() : base()
{ {
VOID_CareerStatus.Instance = this; if (this.inValidGame && this.inValidScene)
  {
  VOID_CareerStatus.Instance = this;
  }
   
this.Name = "Career Status"; this.Name = "Career Status";
   
GameEvents.OnFundsChanged.Add(this.onFundsChange); GameEvents.OnFundsChanged.Add(this.onFundsChange);
GameEvents.OnReputationChanged.Add(this.onRepChange); GameEvents.OnReputationChanged.Add(this.onRepChange);
GameEvents.OnScienceChanged.Add(this.onScienceChange); GameEvents.OnScienceChanged.Add(this.onScienceChange);
GameEvents.onGameStateLoad.Add(this.onGameStateLoad); GameEvents.onGameStateLoad.Add(this.onGameStateLoad);
   
bool texturesLoaded; bool texturesLoaded;
   
texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18); texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18);
texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18); texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18);
texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18);
texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18);
texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18);
   
this.fundsContent = new GUIContent(); this.fundsContent = new GUIContent();
this.repContent = new GUIContent(); this.repContent = new GUIContent();
this.scienceContent = new GUIContent(); this.scienceContent = new GUIContent();
   
if (texturesLoaded) if (texturesLoaded)
{ {
this.fundsContent.image = this.fundsIconGreen; this.fundsContent.image = this.fundsIconGreen;
this.repContent.image = this.reputationIconGreen; this.repContent.image = this.reputationIconGreen;
this.scienceContent.image = this.scienceIcon; this.scienceContent.image = this.scienceIcon;
} }
   
this.currentFunds = double.NaN; this.currentFunds = double.NaN;
this.currentScience = float.NaN; this.currentScience = float.NaN;
this.currentReputation = float.NaN; this.currentReputation = float.NaN;
} }
   
~VOID_CareerStatus() ~VOID_CareerStatus()
{ {
GameEvents.OnFundsChanged.Remove(this.onFundsChange); GameEvents.OnFundsChanged.Remove(this.onFundsChange);
GameEvents.OnReputationChanged.Remove(this.onRepChange); GameEvents.OnReputationChanged.Remove(this.onRepChange);
GameEvents.OnScienceChanged.Remove(this.onScienceChange); GameEvents.OnScienceChanged.Remove(this.onScienceChange);
GameEvents.onGameStateLoad.Remove(this.onGameStateLoad); GameEvents.onGameStateLoad.Remove(this.onGameStateLoad);
   
VOID_CareerStatus.Instance = null; VOID_CareerStatus.Instance = null;
} }
} }
} }
   
   
  // VOID
  //
  // VOID_ConfigModule.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 2. Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation and/or other
  // materials provided with the distribution.
  //
  // 3. Neither the name of the copyright holder nor the names of its contributors may be used
  // to endorse or promote products derived from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KSP;
  using System;
  using ToadicusTools;
  using UnityEngine;
 
  namespace VOID
  {
  public class VOID_ConfigWindow : VOID_WindowModule
  {
  public static VOID_ConfigWindow Instance
  {
  get;
  private set;
  }
 
  public override bool inValidScene
  {
  get
  {
  return true;
  }
  }
 
  public override bool inValidGame
  {
  get
  {
  return true;
  }
  }
 
  public VOID_ConfigWindow() : base()
  {
  VOID_ConfigWindow.Instance = this;
 
  this.Name = "VOID Configuration";
  }
 
  public override void ModuleWindow(int id)
  {
  GUILayout.BeginVertical();
 
  this.core.DrawConfigurables();
 
  GUILayout.EndVertical();
  GUI.DragWindow();
  }
 
  ~VOID_ConfigWindow()
  {
  VOID_ConfigWindow.Instance = null;
  }
  }
  }
 
// VOID // VOID
// //
// VOID_Data.cs // VOID_Data.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public static class VOID_Data public static class VOID_Data
{ {
private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>(); private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>();
public static Dictionary<int, IVOID_DataValue> DataValues public static Dictionary<int, IVOID_DataValue> DataValues
{ {
get get
{ {
return dataValues; return dataValues;
} }
} }
   
#region Constants #region Constants
   
private static double kerbinGee; private static double kerbinGee;
   
public static double KerbinGee public static double KerbinGee
{ {
get get
{ {
if (kerbinGee == default(double)) if (kerbinGee == default(double))
{ {
kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius); kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius);
} }
   
return kerbinGee; return kerbinGee;
} }
} }
   
#endregion #endregion
   
#region Core Data #region Core Data
   
public static VOIDCore Core public static VOIDCore Core
{ {
get get
{ {
if (!CoreInitialized) if (!CoreInitialized)
{ {
return null; return null;
} }
   
switch (HighLogic.LoadedScene) switch (HighLogic.LoadedScene)
{ {
case GameScenes.EDITOR: case GameScenes.EDITOR:
return (VOIDCore)VOIDCore_Editor.Instance; return (VOIDCore)VOIDCore_Editor.Instance;
case GameScenes.FLIGHT: case GameScenes.FLIGHT:
return (VOIDCore)VOIDCore_Flight.Instance; return (VOIDCore)VOIDCore_Flight.Instance;
case GameScenes.SPACECENTER: case GameScenes.SPACECENTER:
return (VOIDCore)VOIDCore_SpaceCentre.Instance; return (VOIDCore)VOIDCore_SpaceCentre.Instance;
default: default:
return null; return null;
} }
} }
} }
   
public static bool CoreInitialized public static bool CoreInitialized
{ {
get get
{ {
switch (HighLogic.LoadedScene) switch (HighLogic.LoadedScene)
{ {
case GameScenes.EDITOR: case GameScenes.EDITOR:
return VOIDCore_Editor.Initialized; return VOIDCore_Editor.Initialized;
case GameScenes.FLIGHT: case GameScenes.FLIGHT:
return VOIDCore_Flight.Initialized; return VOIDCore_Flight.Initialized;
case GameScenes.SPACECENTER: case GameScenes.SPACECENTER:
return VOIDCore_SpaceCentre.Initialized; return VOIDCore_SpaceCentre.Initialized;
default: default:
return false; return false;
} }
} }
} }
   
#endregion #endregion
   
#region Atmosphere #region Atmosphere
   
public static readonly VOID_DoubleValue atmDensity = public static readonly VOID_DoubleValue atmDensity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Atmosphere Density", "Atmosphere Density",
new Func<double>(() => Core.vessel.atmDensity * 1000f), new Func<double>(() => Core.vessel.atmDensity * 1000f),
"g/m³" "g/m³"
); );
   
public static readonly VOID_FloatValue atmLimit = public static readonly VOID_FloatValue atmLimit =
new VOID_FloatValue( new VOID_FloatValue(
"Atmosphere Limit", "Atmosphere Limit",
new Func<float>(() => Core.vessel.mainBody.maxAtmosphereAltitude), new Func<float>(() => Core.vessel.mainBody.maxAtmosphereAltitude),
"m" "m"
); );
   
public static readonly VOID_DoubleValue atmPressure = public static readonly VOID_DoubleValue atmPressure =
new VOID_DoubleValue( new VOID_DoubleValue(
"Pressure", "Pressure",
new Func<double>(() => Core.vessel.staticPressure), new Func<double>(() => Core.vessel.staticPressure),
"atm" "atm"
); );
   
public static readonly VOID_FloatValue temperature = public static readonly VOID_FloatValue temperature =
new VOID_FloatValue( new VOID_FloatValue(
"Temperature", "Temperature",
new Func<float>(() => Core.vessel.flightIntegrator.getExternalTemperature()), new Func<float>(() => Core.vessel.flightIntegrator.getExternalTemperature()),
"°C" "°C"
); );
   
#endregion #endregion
   
#region Attitude #region Attitude
   
public static readonly VOID_StrValue vesselHeading = public static readonly VOID_StrValue vesselHeading =
new VOID_StrValue( new VOID_StrValue(
"Heading", "Heading",
delegate() delegate()
{ {
double heading = Core.vessel.getSurfaceHeading(); double heading = Core.vessel.getSurfaceHeading();
string cardinal = VOID_Tools.get_heading_text(heading); string cardinal = VOID_Tools.get_heading_text(heading);
   
return string.Format( return string.Format(
"{0}° {1}", "{0}° {1}",
heading.ToString("F2"), heading.ToString("F2"),
cardinal cardinal
); );
} }
); );
   
public static readonly VOID_DoubleValue vesselPitch = public static readonly VOID_DoubleValue vesselPitch =
new VOID_DoubleValue( new VOID_DoubleValue(
"Pitch", "Pitch",
() => Core.vessel.getSurfacePitch(), () => Core.vessel.getSurfacePitch(),
"°" "°"
); );
   
#endregion #endregion
   
#region Career #region Career
   
public static readonly VOID_StrValue fundingStatus = public static readonly VOID_StrValue fundingStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Funds"), string.Intern("Funds"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"), VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange)
); );
} }
); );
   
public static readonly VOID_StrValue reputationStatus = public static readonly VOID_StrValue reputationStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Reputation"), string.Intern("Reputation"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"), VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange)
); );
} }
); );
   
public static readonly VOID_StrValue scienceStatus = public static readonly VOID_StrValue scienceStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Science"), string.Intern("Science"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"), VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange)
); );
} }
); );
   
#endregion #endregion
   
#region Control #region Control
   
public static readonly VOID_FloatValue mainThrottle = public static readonly VOID_FloatValue mainThrottle =
new VOID_FloatValue( new VOID_FloatValue(
"Throttle", "Throttle",
new Func<float>(() => Core.vessel.ctrlState.mainThrottle * 100f), new Func<float>(() => Core.vessel.ctrlState.mainThrottle * 100f),
"%" "%"
); );
   
#endregion #endregion
   
#region Engineering #region Engineering
   
public static readonly VOID_IntValue partCount = public static readonly VOID_IntValue partCount =
new VOID_IntValue( new VOID_IntValue(
"Parts", "Parts",
new Func<int>(() => Core.vessel.Parts.Count), new Func<int>(() => Core.vessel.Parts.Count),
"" ""
); );
   
#region Mass #region Mass
   
public static readonly VOID_StrValue comboResourceMass = public static readonly VOID_StrValue comboResourceMass =
new VOID_StrValue( new VOID_StrValue(
"Resource Mass (curr / total)", "Resource Mass (curr / total)",
delegate() delegate()
{ {
return string.Format("{0} / {1}", return string.Format("{0} / {1}",
stageResourceMass.ValueUnitString("F3"), stageResourceMass.ValueUnitString("F3"),
resourceMass.ValueUnitString("F3") resourceMass.ValueUnitString("F3")
); );
} }
); );
   
public static readonly VOID_DoubleValue resourceMass = public static readonly VOID_DoubleValue resourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass", "Resource Mass",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.resourceMass; return Core.LastStage.resourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue stageResourceMass = public static readonly VOID_DoubleValue stageResourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass (Stage)", "Resource Mass (Stage)",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.resourceMass; return Core.LastStage.totalResourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue totalMass = public static readonly VOID_DoubleValue totalMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Total Mass", "Total Mass",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.totalMass; return Core.LastStage.totalMass;
}, },
"tons" "tons"
); );
   
#endregion #endregion
   
#region DeltaV #region DeltaV
   
public static readonly VOID_DoubleValue stageDeltaV = public static readonly VOID_DoubleValue stageDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Current Stage)", "DeltaV (Current Stage)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return Core.LastStage.deltaV; return Core.LastStage.deltaV;
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue totalDeltaV = public static readonly VOID_DoubleValue totalDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Total)", "DeltaV (Total)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return Core.LastStage.totalDeltaV; return Core.LastStage.totalDeltaV;
}, },
"m/s" "m/s"
); );
   
#endregion #endregion
   
#region Propulsion #region Propulsion
   
public static readonly VOID_StrValue currmaxThrustWeight = public static readonly VOID_StrValue currmaxThrustWeight =
new VOID_StrValue( new VOID_StrValue(
"T:W (curr/max)", "T:W (curr/max)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
(VOID_Data.currThrustWeight.Value).ToString("F2"), (VOID_Data.currThrustWeight.Value).ToString("F2"),
(VOID_Data.maxThrustWeight.Value).ToString("F2") (VOID_Data.maxThrustWeight.Value).ToString("F2")
); );
} }
); );
   
public static readonly VOID_StrValue currmaxThrust = public static readonly VOID_StrValue currmaxThrust =
new VOID_StrValue( new VOID_StrValue(
"Thrust (curr/max)", "Thrust (curr/max)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
double currThrust = Core.LastStage.actualThrust; double currThrust = Core.LastStage.actualThrust;
double maxThrust = Core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
currThrust.ToString("F1"), currThrust.ToString("F1"),
maxThrust.ToString("F1") maxThrust.ToString("F1")
); );
} }
); );
   
public static readonly VOID_DoubleValue stageMassFlow = public static readonly VOID_DoubleValue stageMassFlow =
new VOID_DoubleValue( new VOID_DoubleValue(
"Stage Mass Flow", "Stage Mass Flow",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
double stageIsp = Core.LastStage.isp; double stageIsp = Core.LastStage.isp;
double stageThrust = stageNominalThrust; double stageThrust = stageNominalThrust;
   
Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" +
"\tstageIsp: {0}\n" + "\tstageIsp: {0}\n" +
"\tstageThrust: {1}\n" + "\tstageThrust: {1}\n" +
"\tKerbinGee: {2}\n", "\tKerbinGee: {2}\n",
stageIsp, stageIsp,
stageThrust, stageThrust,
KerbinGee KerbinGee
); );
   
return stageThrust / (stageIsp * KerbinGee); return stageThrust / (stageIsp * KerbinGee);
}, },
"Mg/s" "Mg/s"
); );
   
public static readonly VOID_DoubleValue stageNominalThrust = public static readonly VOID_DoubleValue stageNominalThrust =
new VOID_DoubleValue( new VOID_DoubleValue(
"Nominal Stage Thrust", "Nominal Stage Thrust",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
if (Core.LastStage.actualThrust == 0d) if (Core.LastStage.actualThrust == 0d)
{ {
return Core.LastStage.thrust; return Core.LastStage.thrust;
} }
else else
{ {
return Core.LastStage.actualThrust; return Core.LastStage.actualThrust;
} }
}, },
"kN" "kN"
); );
   
#endregion #endregion
   
#region Kinetics #region Kinetics
   
public static readonly VOID_DoubleValue currThrustWeight = public static readonly VOID_DoubleValue currThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.actualThrustToWeight; return Core.LastStage.actualThrustToWeight;
}, },
"" ""
); );
   
   
   
public static readonly VOID_DoubleValue maxThrustWeight = public static readonly VOID_DoubleValue maxThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.thrustToWeight; return Core.LastStage.thrustToWeight;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue nominalThrustWeight = public static readonly VOID_DoubleValue nominalThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Thrust-to-Weight Ratio", "Thrust-to-Weight Ratio",
delegate() delegate()
{ {
if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d) if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
{ {
return maxThrustWeight.Value; return maxThrustWeight.Value;
} }
   
return currThrustWeight.Value; return currThrustWeight.Value;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue surfaceThrustWeight = public static readonly VOID_DoubleValue surfaceThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Max T:W @ surface", "Max T:W @ surface",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
   
double maxThrust = Core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
double mass = Core.LastStage.totalMass; double mass = Core.LastStage.totalMass;
double gravity = (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) / double gravity = (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) /
(Core.vessel.mainBody.Radius * Core.vessel.mainBody.Radius); (Core.vessel.mainBody.Radius * Core.vessel.mainBody.Radius);
double weight = mass * gravity; double weight = mass * gravity;
   
return maxThrust / weight; return maxThrust / weight;
}, },
"" ""
); );
   
public static readonly VOID_Vector3dValue vesselThrustOffset = public static readonly VOID_Vector3dValue vesselThrustOffset =
new VOID_Vector3dValue( new VOID_Vector3dValue(
"Thrust Offset", "Thrust Offset",
delegate() delegate()
{ {
if (Core.vessel == null) if (Core.vessel == null)
{ {
return Vector3d.zero; return Vector3d.zero;
} }
   
List<PartModule> engineModules = Core.vessel.getModulesOfType<PartModule>(); List<PartModule> engineModules = Core.vessel.getModulesOfType<PartModule>();
   
Vector3d thrustPos = Vector3d.zero; Vector3d thrustPos = Vector3d.zero;
Vector3d thrustDir = Vector3d.zero; Vector3d thrustDir = Vector3d.zero;
float thrust = 0; float thrust = 0;
   
foreach (PartModule engine in engineModules) foreach (PartModule engine in engineModules)
{ {
float moduleThrust = 0; float moduleThrust = 0;
   
switch (engine.moduleName) switch (engine.moduleName)
{ {
case "ModuleEngines": case "ModuleEngines":
case "ModuleEnginesFX": case "ModuleEnginesFX":
break; break;
default: default:
continue; continue;
} }
   
if (!engine.isEnabled) if (!engine.isEnabled)
{ {
continue; continue;
} }
   
CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); CenterOfThrustQuery cotQuery = new CenterOfThrustQuery();
   
if (engine is ModuleEngines) if (engine is ModuleEngines)
{ {
ModuleEngines engineModule = engine as ModuleEngines; ModuleEngines engineModule = engine as ModuleEngines;
   
moduleThrust = engineModule.finalThrust; moduleThrust = engineModule.finalThrust;
   
engineModule.OnCenterOfThrustQuery(cotQuery); engineModule.OnCenterOfThrustQuery(cotQuery);
} }
else // engine is ModuleEnginesFX else // engine is ModuleEnginesFX
{ {
ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX;
   
moduleThrust = engineFXModule.finalThrust; moduleThrust = engineFXModule.finalThrust;
   
engineFXModule.OnCenterOfThrustQuery(cotQuery); engineFXModule.OnCenterOfThrustQuery(cotQuery);
} }
   
if (moduleThrust != 0d) if (moduleThrust != 0d)
{ {
cotQuery.thrust = moduleThrust; cotQuery.thrust = moduleThrust;
} }
   
thrustPos += cotQuery.pos * cotQuery.thrust; thrustPos += cotQuery.pos * cotQuery.thrust;
thrustDir += cotQuery.dir * cotQuery.thrust; thrustDir += cotQuery.dir * cotQuery.thrust;
thrust += cotQuery.thrust; thrust += cotQuery.thrust;
} }
   
if (thrust != 0) if (thrust != 0)
{ {
thrustPos /= thrust; thrustPos /= thrust;
thrustDir /= thrust; thrustDir /= thrust;
} }
   
Transform vesselTransform = Core.vessel.transform; Transform vesselTransform = Core.vessel.transform;
   
thrustPos = vesselTransform.InverseTransformPoint(thrustPos); thrustPos = vesselTransform.InverseTransformPoint(thrustPos);
thrustDir = vesselTransform.InverseTransformDirection(thrustDir); thrustDir = vesselTransform.InverseTransformDirection(thrustDir);
   
Vector3d thrustOffset = VectorTools.PointDistanceToLine( Vector3d thrustOffset = VectorTools.PointDistanceToLine(
thrustPos, thrustDir.normalized, Core.vessel.findLocalCenterOfMass()); thrustPos, thrustDir.normalized, Core.vessel.findLocalCenterOfMass());
   
Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" +
"\tthrustPos: {0}\n" + "\tthrustPos: {0}\n" +
"\tthrustDir: {1}\n" + "\tthrustDir: {1}\n" +
"\tthrustOffset: {2}\n" + "\tthrustOffset: {2}\n" +
"\tvessel.CoM: {3}", "\tvessel.CoM: {3}",
thrustPos, thrustPos,
thrustDir.normalized, thrustDir.normalized,
thrustOffset, thrustOffset,
Core.vessel.findWorldCenterOfMass() Core.vessel.findWorldCenterOfMass()
); );
   
return thrustOffset; return thrustOffset;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Air Breathing #region Air Breathing
   
public static readonly VOID_StrValue intakeAirStatus = public static readonly VOID_StrValue intakeAirStatus =
new VOID_StrValue( new VOID_StrValue(
"Intake Air (Curr / Req)", "Intake Air (Curr / Req)",
delegate() delegate()
{ {
double currentAmount; double currentAmount;
double currentRequirement; double currentRequirement;
   
currentAmount = 0d; currentAmount = 0d;
currentRequirement = 0d; currentRequirement = 0d;
   
foreach (Part part in Core.vessel.Parts) foreach (Part part in Core.vessel.Parts)
{ {
if (part.enabled) if (part.enabled)
{ {
ModuleEngines engineModule; ModuleEngines engineModule;
ModuleEnginesFX enginesFXModule; ModuleEnginesFX enginesFXModule;
List<Propellant> propellantList = null; List<Propellant> propellantList = null;
   
if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule)) if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule))
{ {
propellantList = engineModule.propellants; propellantList = engineModule.propellants;
} }
else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule)) else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule))
{ {
propellantList = enginesFXModule.propellants; propellantList = enginesFXModule.propellants;
} }
   
if (propellantList != null) if (propellantList != null)
{ {
foreach (Propellant propellant in propellantList) foreach (Propellant propellant in propellantList)
{ {
if (propellant.name == "IntakeAir") if (propellant.name == "IntakeAir")
{ {
currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime;
break; break;
} }
} }
} }
} }
   
ModuleResourceIntake intakeModule; ModuleResourceIntake intakeModule;
   
if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule)) if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule))
{ {
if (intakeModule.resourceName == "IntakeAir") if (intakeModule.resourceName == "IntakeAir")
{ {
currentAmount += intakeModule.airFlow; currentAmount += intakeModule.airFlow;
} }
} }
} }
   
if (currentAmount == 0 && currentRequirement == 0) if (currentAmount == 0 && currentRequirement == 0)
{ {
return "N/A"; return "N/A";
} }
   
return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement); return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement);
} }
); );
   
#endregion #endregion
   
#region Crew #region Crew
   
public static readonly VOID_IntValue vesselCrewCount = public static readonly VOID_IntValue vesselCrewCount =
new VOID_IntValue( new VOID_IntValue(
"Crew Onboard", "Crew Onboard",
delegate() delegate()
{ {
if (Core.vessel != null) if (Core.vessel != null)
{ {
return Core.vessel.GetCrewCount(); return Core.vessel.GetCrewCount();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
public static readonly VOID_IntValue vesselCrewCapacity = public static readonly VOID_IntValue vesselCrewCapacity =
new VOID_IntValue( new VOID_IntValue(
"Crew Capacity", "Crew Capacity",
delegate() delegate()
{ {
if (Core.vessel != null) if (Core.vessel != null)
{ {
return Core.vessel.GetCrewCapacity(); return Core.vessel.GetCrewCapacity();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
#endregion #endregion
   
#endregion #endregion
   
#region Location #region Location
   
public const double kscLongitude = 285.442323427289 * Math.PI / 180d; public const double kscLongitude = 285.442323427289 * Math.PI / 180d;
public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d; public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;
   
public static readonly VOID_DoubleValue downrangeDistance = public static readonly VOID_DoubleValue downrangeDistance =
new VOID_DoubleValue( new VOID_DoubleValue(
"Downrange Distance", "Downrange Distance",
delegate() delegate()
{ {
   
if (Core.vessel == null || if (Core.vessel == null ||
Planetarium.fetch == null || Planetarium.fetch == null ||
Core.vessel.mainBody != Planetarium.fetch.Home) Core.vessel.mainBody != Planetarium.fetch.Home)
{ {
return double.NaN; return double.NaN;
} }
   
double vesselLongitude = Core.vessel.longitude * Math.PI / 180d; double vesselLongitude = Core.vessel.longitude * Math.PI / 180d;
double vesselLatitude = Core.vessel.latitude * Math.PI / 180d; double vesselLatitude = Core.vessel.latitude * Math.PI / 180d;
   
double diffLon = vesselLongitude - kscLongitude; double diffLon = vesselLongitude - kscLongitude;
double diffLat = vesselLatitude - kscLatitude; double diffLat = vesselLatitude - kscLatitude;
   
double sinHalfDiffLat = Math.Sin(diffLat / 2d); double sinHalfDiffLat = Math.Sin(diffLat / 2d);
double sinHalfDiffLon = Math.Sin(diffLon / 2d); double sinHalfDiffLon = Math.Sin(diffLon / 2d);
   
double cosVesselLon = Math.Cos(vesselLongitude); double cosVesselLon = Math.Cos(vesselLongitude);
double cosKSCLon = Math.Cos(kscLongitude); double cosKSCLon = Math.Cos(kscLongitude);
   
double haversine = double haversine =
sinHalfDiffLat * sinHalfDiffLat + sinHalfDiffLat * sinHalfDiffLat +
cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon; cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon;
   
double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine)); double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine));
   
return Core.vessel.mainBody.Radius * arc; return Core.vessel.mainBody.Radius * arc;
}, },
"m" "m"
); );
   
public static readonly VOID_StrValue surfLatitude = public static readonly VOID_StrValue surfLatitude =
new VOID_StrValue( new VOID_StrValue(
"Latitude", "Latitude",
new Func<string>(() => VOID_Tools.GetLatitudeString(Core.vessel)) new Func<string>(() => VOID_Tools.GetLatitudeString(Core.vessel))
); );
   
public static readonly VOID_StrValue surfLongitude = public static readonly VOID_StrValue surfLongitude =
new VOID_StrValue( new VOID_StrValue(
"Longitude", "Longitude",
new Func<string>(() => VOID_Tools.GetLongitudeString(Core.vessel)) new Func<string>(() => VOID_Tools.GetLongitudeString(Core.vessel))
); );
   
public static readonly VOID_DoubleValue trueAltitude = public static readonly VOID_DoubleValue trueAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (true)", "Altitude (true)",
delegate() delegate()
{ {
double alt_true = Core.vessel.orbit.altitude - Core.vessel.terrainAltitude; double alt_true = Core.vessel.orbit.altitude - Core.vessel.terrainAltitude;
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
// and water covers the whole surface at 0 m. // and water covers the whole surface at 0 m.
if (Core.vessel.terrainAltitude < 0 && Core.vessel.mainBody.ocean) if (Core.vessel.terrainAltitude < 0 && Core.vessel.mainBody.ocean)
alt_true = Core.vessel.orbit.altitude; alt_true = Core.vessel.orbit.altitude;
return alt_true; return alt_true;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Kinematics #region Kinematics
   
public static readonly VOID_DoubleValue geeForce = public static readonly VOID_DoubleValue geeForce =
new VOID_DoubleValue( new VOID_DoubleValue(
"G-force", "G-force",
new Func<double>(() => Core.vessel.geeForce), new Func<double>(() => Core.vessel.geeForce),
"gees" "gees"
); );
   
public static readonly VOID_DoubleValue horzVelocity = public static readonly VOID_DoubleValue horzVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Horizontal speed", "Horizontal speed",
new Func<double>(() => Core.vessel.horizontalSrfSpeed), new Func<double>(() => Core.vessel.horizontalSrfSpeed),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue surfVelocity = public static readonly VOID_DoubleValue surfVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Surface velocity", "Surface velocity",
new Func<double>(() => Core.vessel.srf_velocity.magnitude), new Func<double>(() => Core.vessel.srf_velocity.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue vertVelocity = public static readonly VOID_DoubleValue vertVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Vertical speed", "Vertical speed",
new Func<double>(() => Core.vessel.verticalSpeed), new Func<double>(() => Core.vessel.verticalSpeed),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue vesselAccel = public static readonly VOID_DoubleValue vesselAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Acceleration", "Acceleration",
() => geeForce * KerbinGee, () => geeForce * KerbinGee,
"m/s²" "m/s²"
); );
   
public static readonly VOID_DoubleValue vesselAngularVelocity = public static readonly VOID_DoubleValue vesselAngularVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Angular Velocity", "Angular Velocity",
delegate() delegate()
{ {
if (Core.vessel != null) if (Core.vessel != null)
{ {
return Core.vessel.angularVelocity.magnitude; return Core.vessel.angularVelocity.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"rad/s" "rad/s"
); );
   
#endregion #endregion
   
#region Navigation #region Navigation
   
public static int upcomingManeuverNodes public static int upcomingManeuverNodes
{ {
get get
{ {
if (Core.vessel == null || if (Core.vessel == null ||
Core.vessel.patchedConicSolver == null || Core.vessel.patchedConicSolver == null ||
Core.vessel.patchedConicSolver.maneuverNodes == null) Core.vessel.patchedConicSolver.maneuverNodes == null)
{ {
return 0; return 0;
} }
   
return Core.vessel.patchedConicSolver.maneuverNodes.Count; return Core.vessel.patchedConicSolver.maneuverNodes.Count;
} }
} }
   
public static readonly VOID_StrValue burnTimeDoneAtNode = public static readonly VOID_StrValue burnTimeDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (Core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.FormatInterval(interval)); return string.Format(format, VOID_Tools.FormatInterval(interval));
} }
); );
   
public static readonly VOID_StrValue burnTimeHalfDoneAtNode = public static readonly VOID_StrValue burnTimeHalfDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (Core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.FormatInterval(interval)); return string.Format(format, VOID_Tools.FormatInterval(interval));
} }
); );
   
public static readonly VOID_DoubleValue currManeuverDeltaV = public static readonly VOID_DoubleValue currManeuverDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"Current Maneuver Delta-V", "Current Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 0) if (upcomingManeuverNodes > 0)
{ {
return Core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; return Core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue currManeuverDVRemaining = public static readonly VOID_DoubleValue currManeuverDVRemaining =
new VOID_DoubleValue( new VOID_DoubleValue(
"Remaining Maneuver Delta-V", "Remaining Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 0) if (upcomingManeuverNodes > 0)
{ {
return Core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Core.vessel.orbit).magnitude; return Core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Core.vessel.orbit).magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue currentNodeBurnDuration = public static readonly VOID_DoubleValue currentNodeBurnDuration =
new VOID_DoubleValue( new VOID_DoubleValue(
"Total Burn Time", "Total Burn Time",
delegate() delegate()
{ {
if (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN) if (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
double stageThrust = stageNominalThrust; double stageThrust = stageNominalThrust;
   
return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust); return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue currentNodeBurnRemaining = public static readonly VOID_DoubleValue currentNodeBurnRemaining =
new VOID_DoubleValue( new VOID_DoubleValue(
"Burn Time Remaining", "Burn Time Remaining",
delegate() delegate()
{ {
if (Core.LastStage == null || currManeuverDVRemaining == double.NaN) if (Core.LastStage == null || currManeuverDVRemaining == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
double stageThrust = stageNominalThrust; double stageThrust = stageNominalThrust;
   
return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust); return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = public static readonly VOID_DoubleValue currentNodeHalfBurnDuration =
new VOID_DoubleValue( new VOID_DoubleValue(
"Half Burn Time", "Half Burn Time",
delegate() delegate()
{ {
if (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN) if (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
double stageThrust = stageNominalThrust; double stageThrust = stageNominalThrust;
   
return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust); return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue nextManeuverDeltaV = public static readonly VOID_DoubleValue nextManeuverDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"Current Maneuver Delta-V", "Current Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 1) if (upcomingManeuverNodes > 1)
{ {
return Core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude; return Core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
#endregion #endregion
   
#region Orbits #region Orbits
   
public static readonly VOID_StrValue primaryName = public static readonly VOID_StrValue primaryName =
new VOID_StrValue( new VOID_StrValue(
VOID_Localization.void_primary, VOID_Localization.void_primary,
delegate() delegate()
{ {
if (Core.vessel == null) if (Core.vessel == null)
{ {
return string.Empty; return string.Empty;
} }
return Core.vessel.mainBody.name; return Core.vessel.mainBody.name;
} }
); );
   
public static readonly VOID_DoubleValue orbitAltitude = public static readonly VOID_DoubleValue orbitAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (ASL)", "Altitude (ASL)",
new Func<double>(() => Core.vessel.orbit.altitude), new Func<double>(() => Core.vessel.orbit.altitude),
"m" "m"
); );
   
public static readonly VOID_DoubleValue orbitVelocity = public static readonly VOID_DoubleValue orbitVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_velocity, VOID_Localization.void_velocity,
new Func<double>(() => Core.vessel.orbit.vel.magnitude), new Func<double>(() => Core.vessel.orbit.vel.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue orbitApoAlt = public static readonly VOID_DoubleValue orbitApoAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_apoapsis, VOID_Localization.void_apoapsis,
new Func<double>(() => Core.vessel.orbit.ApA), new Func<double>(() => Core.vessel.orbit.ApA),
"m" "m"
); );
   
public static readonly VOID_DoubleValue oribtPeriAlt = public static readonly VOID_DoubleValue oribtPeriAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_periapsis, VOID_Localization.void_periapsis,
new Func<double>(() => Core.vessel.orbit.PeA), new Func<double>(() => Core.vessel.orbit.PeA),
"m" "m"
); );
   
public static readonly VOID_StrValue timeToApo = public static readonly VOID_StrValue timeToApo =
new VOID_StrValue( new VOID_StrValue(
"Time to Apoapsis", "Time to Apoapsis",
new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToAp)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToAp))
); );
   
public static readonly VOID_StrValue timeToPeri = public static readonly VOID_StrValue timeToPeri =
new VOID_StrValue( new VOID_StrValue(
"Time to Periapsis", "Time to Periapsis",
new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToPe)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToPe))
); );
   
public static readonly VOID_DoubleValue orbitInclination = public static readonly VOID_DoubleValue orbitInclination =
new VOID_DoubleValue( new VOID_DoubleValue(
"Inclination", "Inclination",
new Func<double>(() => Core.vessel.orbit.inclination), new Func<double>(() => Core.vessel.orbit.inclination),
"°" "°"
); );
   
public static readonly VOID_DoubleValue gravityAccel = public static readonly VOID_DoubleValue gravityAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Gravity", "Gravity",
delegate() delegate()
{ {
double orbitRadius = Core.vessel.mainBody.Radius + double orbitRadius = Core.vessel.mainBody.Radius +
Core.vessel.mainBody.GetAltitude(Core.vessel.findWorldCenterOfMass()); Core.vessel.mainBody.GetAltitude(Core.vessel.findWorldCenterOfMass());
return (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) / return (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) /
(orbitRadius * orbitRadius); (orbitRadius * orbitRadius);
}, },
"m/s²" "m/s²"
); );
   
public static readonly VOID_StrValue orbitPeriod = public static readonly VOID_StrValue orbitPeriod =
new VOID_StrValue( new VOID_StrValue(
"Period", "Period",
new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.period)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.period))
); );
   
public static readonly VOID_DoubleValue semiMajorAxis = public static readonly VOID_DoubleValue semiMajorAxis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Semi-Major Axis", "Semi-Major Axis",
new Func<double>(() => Core.vessel.orbit.semiMajorAxis), new Func<double>(() => Core.vessel.orbit.semiMajorAxis),
"m" "m"
); );
   
public static readonly VOID_DoubleValue eccentricity = public static readonly VOID_DoubleValue eccentricity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentricity", "Eccentricity",
new Func<double>(() => Core.vessel.orbit.eccentricity), new Func<double>(() => Core.vessel.orbit.eccentricity),
"" ""
); );
   
public static readonly VOID_DoubleValue meanAnomaly = public static readonly VOID_DoubleValue meanAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Mean Anomaly", "Mean Anomaly",
new Func<double>(() => Core.vessel.orbit.meanAnomaly * 180d / Math.PI), new Func<double>(() => Core.vessel.orbit.meanAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue trueAnomaly = public static readonly VOID_DoubleValue trueAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"True Anomaly", "True Anomaly",
new Func<double>(() => Core.vessel.orbit.trueAnomaly), new Func<double>(() => Core.vessel.orbit.trueAnomaly),
"°" "°"
); );
   
public static readonly VOID_DoubleValue eccAnomaly = public static readonly VOID_DoubleValue eccAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentric Anomaly", "Eccentric Anomaly",
new Func<double>(() => Core.vessel.orbit.eccentricAnomaly * 180d / Math.PI), new Func<double>(() => Core.vessel.orbit.eccentricAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue longitudeAscNode = public static readonly VOID_DoubleValue longitudeAscNode =
new VOID_DoubleValue( new VOID_DoubleValue(
"Long. Ascending Node", "Long. Ascending Node",
new Func<double>(() => Core.vessel.orbit.LAN), new Func<double>(() => Core.vessel.orbit.LAN),
"°" "°"
); );
   
public static readonly VOID_DoubleValue argumentPeriapsis = public static readonly VOID_DoubleValue argumentPeriapsis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Argument of Periapsis", "Argument of Periapsis",
new Func<double>(() => Core.vessel.orbit.argumentOfPeriapsis), new Func<double>(() => Core.vessel.orbit.argumentOfPeriapsis),
"°" "°"
); );
   
  public static readonly VOID_StrValue timeToAscendingNode =
  new VOID_StrValue(
  "Time to Ascending Node",
  delegate()
  {
  double trueAnomalyAscNode = 360d - argumentPeriapsis;
  double dTAscNode = Core.vessel.orbit.GetDTforTrueAnomaly(
  trueAnomalyAscNode * Mathf.Deg2Rad,
  Core.vessel.orbit.period
  );
   
  dTAscNode %= Core.vessel.orbit.period;
   
  if (dTAscNode < 0d)
  {
  dTAscNode += Core.vessel.orbit.period;
  }
   
  return VOID_Tools.FormatInterval(dTAscNode);
  }
  );
   
  public static readonly VOID_StrValue timeToDescendingNode =
  new VOID_StrValue(
  "Time to Descending Node",
  delegate()
  {
  double trueAnomalyAscNode = 180d - argumentPeriapsis;
  double dTDescNode = Core.vessel.orbit.GetDTforTrueAnomaly(
  trueAnomalyAscNode * Mathf.Deg2Rad,
  Core.vessel.orbit.period
  );
   
  dTDescNode %= Core.vessel.orbit.period;
   
  if (dTDescNode < 0d)
  {
  dTDescNode += Core.vessel.orbit.period;
  }
   
  return VOID_Tools.FormatInterval(dTDescNode);
  }
  );
   
public static readonly VOID_DoubleValue localSiderealLongitude = public static readonly VOID_DoubleValue localSiderealLongitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Local Sidereal Longitude", "Local Sidereal Longitude",
new Func<double>(() => VOID_Tools.FixDegreeDomain( new Func<double>(() => VOID_Tools.FixDegreeDomain(
Core.vessel.longitude + Core.vessel.orbit.referenceBody.rotationAngle)), Core.vessel.longitude + Core.vessel.orbit.referenceBody.rotationAngle)),
"°" "°"
); );
   
#endregion #endregion
   
#region Science #region Science
   
public static readonly VOID_StrValue expSituation = public static readonly VOID_StrValue expSituation =
new VOID_StrValue( new VOID_StrValue(
"Situation", "Situation",
new Func<string>(() => Core.vessel.GetExperimentSituation().HumanString()) new Func<string>(() => Core.vessel.GetExperimentSituation().HumanString())
); );
   
public static readonly VOID_StrValue currBiome = public static readonly VOID_StrValue currBiome =
new VOID_StrValue( new VOID_StrValue(
"Biome", "Biome",
new Func<string>(() => VOID_Tools.GetBiome(Core.vessel).name) delegate()
  {
  if (Core.vessel.landedAt == string.Empty)
  {
  return VOID_Tools.GetBiome(Core.vessel).name;
  }
  else
  {
  return Core.vessel.landedAt;
  }
  }
); );
   
#endregion #endregion
   
#region Surface #region Surface
   
public static readonly VOID_DoubleValue terrainElevation = public static readonly VOID_DoubleValue terrainElevation =
new VOID_DoubleValue( new VOID_DoubleValue(
"Terrain elevation", "Terrain elevation",
new Func<double>(() => Core.vessel.terrainAltitude), new Func<double>(() => Core.vessel.terrainAltitude),
"m" "m"
); );
   
#endregion #endregion
   
private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust)
{ {
Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" +
"\tdeltaV: {0}\n" + "\tdeltaV: {0}\n" +
"\tinitialMass: {1}\n" + "\tinitialMass: {1}\n" +
"\tmassFlow: {2}\n" + "\tmassFlow: {2}\n" +
"\tthrust: {3}\n", "\tthrust: {3}\n",
deltaV, deltaV,
initialMass, initialMass,
massFlow, massFlow,
thrust thrust
); );
return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust)); return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust));
} }
} }
} }
   
// VOID // VOID
// //
// VOID_DataLogger.cs // VOID_DataLogger.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule
{ {
/* /*
* Fields * Fields
* */ * */
#region Fields #region Fields
   
protected bool _loggingActive; protected bool _loggingActive;
protected bool firstWrite; protected bool firstWrite;
   
  [AVOID_SaveValue("waitForLaunch")]
  protected VOID_SaveValue<bool> waitForLaunch;
   
[AVOID_SaveValue("logInterval")] [AVOID_SaveValue("logInterval")]
protected VOID_SaveValue<float> logInterval; protected VOID_SaveValue<float> logInterval;
protected string logIntervalStr; protected string logIntervalStr;
   
protected float csvCollectTimer; protected float csvCollectTimer;
   
protected List<byte> csvBytes; protected List<byte> csvBytes;
   
protected string _fileName; protected string _fileName;
protected FileStream _outputFile; protected FileStream _outputFile;
   
protected uint outstandingWrites; protected uint outstandingWrites;
   
protected System.Text.UTF8Encoding _utf8Encoding; protected System.Text.UTF8Encoding _utf8Encoding;
   
#endregion #endregion
   
/* /*
* Properties * Properties
* */ * */
   
#region Properties #region Properties
   
// TODO: Add configurable or incremental file names. // TODO: Add configurable or incremental file names.
protected bool loggingActive protected bool loggingActive
{ {
get get
{ {
return this._loggingActive; return this._loggingActive;
} }
set set
{ {
if (value != this._loggingActive) if (value != this._loggingActive)
{ {
if (value) if (value)
{ {
this.csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
else else
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
} }
   
this._loggingActive = value; this._loggingActive = value;
} }
} }
} }
   
protected string fileName protected string fileName
{ {
get get
{ {
if (this._fileName == null || this._fileName == string.Empty) if (this._fileName == null || this._fileName == string.Empty)
{ {
this._fileName = KSP.IO.IOUtils.GetFilePathFor( this._fileName = KSP.IO.IOUtils.GetFilePathFor(
typeof(VOIDCore), typeof(VOIDCore),
string.Format( string.Format(
"{0}_{1}", "{0}_{1}",
this.vessel.vesselName, this.vessel.vesselName,
"data.csv" "data.csv"
), ),
null null
); );
} }
   
return this._fileName; return this._fileName;
} }
} }
   
protected FileStream outputFile protected FileStream outputFile
{ {
get get
{ {
if (this._outputFile == null) if (this._outputFile == null)
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); Tools.DebugLogger logger = Tools.DebugLogger.New(this);
logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName); logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName);
   
if (File.Exists(this.fileName)) if (File.Exists(this.fileName))
{ {
logger.Append("append"); logger.Append("append");
this._outputFile = new FileStream( this._outputFile = new FileStream(
this.fileName, this.fileName,
FileMode.Append, FileMode.Append,
FileAccess.Write, FileAccess.Write,
FileShare.Read, FileShare.Read,
512, 512,
true true
); );
} }
else else
{ {
logger.Append("create"); logger.Append("create");
this._outputFile = new FileStream( this._outputFile = new FileStream(
this.fileName, this.fileName,
FileMode.Create, FileMode.Create,
FileAccess.Write, FileAccess.Write,
FileShare.Read, FileShare.Read,
512, 512,
true true
); );
   
byte[] byteOrderMark = utf8Encoding.GetPreamble(); byte[] byteOrderMark = utf8Encoding.GetPreamble();
   
logger.Append(" and writing preamble"); logger.Append(" and writing preamble");
this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length); this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);
} }
   
logger.Append('.'); logger.Append('.');
   
logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not "); logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");
   
logger.Print(); logger.Print();
} }
   
return this._outputFile; return this._outputFile;
} }
} }
   
public UTF8Encoding utf8Encoding public UTF8Encoding utf8Encoding
{ {
get get
{ {
if (this._utf8Encoding == null) if (this._utf8Encoding == null)
{ {
this._utf8Encoding = new UTF8Encoding(true); this._utf8Encoding = new UTF8Encoding(true);
} }
   
return this._utf8Encoding; return this._utf8Encoding;
} }
} }
   
#endregion #endregion
   
/* /*
* Methods * Methods
* */ * */
#region Monobehaviour Lifecycle #region Monobehaviour Lifecycle
public void Update() public void Update()
{ {
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
// csvList is not empty, write it // csvList is not empty, write it
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
// CSV Logging // CSV Logging
// from ISA MapSat // from ISA MapSat
if (loggingActive) if (loggingActive && (!waitForLaunch || this.vessel.situation != Vessel.Situations.PRELAUNCH))
{ {
//data logging is on //data logging is on
//increment timers //increment timers
this.csvCollectTimer += Time.deltaTime; this.csvCollectTimer += Time.deltaTime;
   
if (this.csvCollectTimer >= this.logInterval) if (this.csvCollectTimer >= this.logInterval)
{ {
//data logging is on, vessel is not prelaunch, and interval has passed //data logging is on, vessel is not prelaunch, and interval has passed
//write a line to the list //write a line to the list
this.CollectLogData(); this.CollectLogData();
} }
} }
} }
   
public void FixedUpdate() {} public void FixedUpdate() {}
   
public void OnDestroy() public void OnDestroy()
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); Tools.DebugLogger logger = Tools.DebugLogger.New(this);
   
logger.Append("Destroying..."); logger.Append("Destroying...");
   
this.CloseFileIfOpen(); this.CloseFileIfOpen();
   
logger.Append(" Done."); logger.Append(" Done.");
logger.Print(false); logger.Print(false);
} }
   
#endregion #endregion
   
#region VOID_Module Overrides #region VOID_Module Overrides
   
public override void LoadConfig() public override void LoadConfig()
{ {
base.LoadConfig(); base.LoadConfig();
   
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.Label( GUILayout.Label(
string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")), string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
GUILayout.Label( GUILayout.Label(
string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())), string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
   
GUIStyle activeLabelStyle = VOID_Styles.labelRed; GUIStyle activeLabelStyle = VOID_Styles.labelRed;
string activeLabelText = "Inactive"; string activeLabelText = "Inactive";
if (loggingActive) if (loggingActive)
{ {
activeLabelText = "Active"; activeLabelText = "Active";
activeLabelStyle = VOID_Styles.labelGreen; activeLabelStyle = VOID_Styles.labelGreen;
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); this.loggingActive = GUITools.Toggle(
  loggingActive,
this.loggingActive = GUILayout.Toggle(loggingActive, "Data logging: ", GUILayout.ExpandWidth(false)); string.Format("Data logging: {0}", activeLabelText),
GUILayout.Label(activeLabelText, activeLabelStyle, GUILayout.ExpandWidth(true)); null,
  activeLabelStyle
GUILayout.EndHorizontal(); );
   
  this.waitForLaunch.value = GUITools.Toggle(
  this.waitForLaunch,
  "Wait for launch"
  );
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false)); GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
   
logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true)); logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true));
GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.Label("s", GUILayout.ExpandWidth(false));
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
float newLogInterval; float newLogInterval;
if (float.TryParse(logIntervalStr, out newLogInterval)) if (float.TryParse(logIntervalStr, out newLogInterval))
{ {
logInterval.value = newLogInterval; logInterval.value = newLogInterval;
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUI.DragWindow(); base.ModuleWindow(id);
} }
   
#endregion #endregion
   
#region Data Collection #region Data Collection
   
private void CollectLogData() private void CollectLogData()
{ {
if (this.csvBytes == null) if (this.csvBytes == null)
{ {
this.csvBytes = new List<byte>(); this.csvBytes = new List<byte>();
} }
   
//called if logging is on and interval has passed //called if logging is on and interval has passed
//writes one line to the csvList //writes one line to the csvList
   
StringBuilder line = new StringBuilder(); StringBuilder line = new StringBuilder();
   
if (firstWrite) if (firstWrite)
{ {
firstWrite = false; firstWrite = false;
line.Append( line.Append(
"\"Kerbin Universal Time (s)\"," + "\"Kerbin Universal Time (s)\"," +
"\"Mission Elapsed Time (s)\t\"," + "\"Mission Elapsed Time (s)\t\"," +
"\"Altitude ASL (m)\"," + "\"Altitude ASL (m)\"," +
"\"Altitude above terrain (m)\"," + "\"Altitude above terrain (m)\"," +
"\"Surface Latitude (°)\"," + "\"Surface Latitude (°)\"," +
"\"Surface Longitude (°)\"," + "\"Surface Longitude (°)\"," +
"\"Orbital Velocity (m/s)\"," + "\"Orbital Velocity (m/s)\"," +
"\"Surface Velocity (m/s)\"," + "\"Surface Velocity (m/s)\"," +
"\"Vertical Speed (m/s)\"," + "\"Vertical Speed (m/s)\"," +
"\"Horizontal Speed (m/s)\"," + "\"Horizontal Speed (m/s)\"," +
"\"Gee Force (gees)\"," + "\"Gee Force (gees)\"," +
"\"Temperature (°C)\"," + "\"Temperature (°C)\"," +
"\"Gravity (m/s²)\"," + "\"Gravity (m/s²)\"," +
"\"Atmosphere Density (g/m³)\"," + "\"Atmosphere Density (g/m³)\"," +
"\"Downrange Distance (m)\"," + "\"Downrange Distance (m)\"," +
"\n" "\n"
); );
} }
   
// Universal time // Universal time
line.Append(Planetarium.GetUniversalTime().ToString("F2")); line.Append(Planetarium.GetUniversalTime().ToString("F2"));
line.Append(','); line.Append(',');
   
//Mission time //Mission time
line.Append(vessel.missionTime.ToString("F3")); line.Append(vessel.missionTime.ToString("F3"));
line.Append(','); line.Append(',');
   
//Altitude ASL //Altitude ASL
line.Append(VOID_Data.orbitAltitude.Value.ToString("F3")); line.Append(VOID_Data.orbitAltitude.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//Altitude (true) //Altitude (true)
line.Append(VOID_Data.trueAltitude.Value.ToString("F3")); line.Append(VOID_Data.trueAltitude.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
// Surface Latitude // Surface Latitude
line.Append('"'); line.Append('"');
line.Append(VOID_Data.surfLatitude.Value); line.Append(VOID_Data.surfLatitude.Value);
line.Append('"'); line.Append('"');
line.Append(','); line.Append(',');
   
// Surface Longitude // Surface Longitude
line.Append('"'); line.Append('"');
line.Append(VOID_Data.surfLongitude.Value); line.Append(VOID_Data.surfLongitude.Value);
line.Append('"'); line.Append('"');
line.Append(','); line.Append(',');
   
//Orbital velocity //Orbital velocity
line.Append(VOID_Data.orbitVelocity.Value.ToString("F3")); line.Append(VOID_Data.orbitVelocity.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//surface velocity //surface velocity
line.Append(VOID_Data.surfVelocity.Value.ToString("F3")); line.Append(VOID_Data.surfVelocity.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//vertical speed //vertical speed
line.Append(VOID_Data.vertVelocity.Value.ToString("F3")); line.Append(VOID_Data.vertVelocity.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//horizontal speed //horizontal speed
line.Append(VOID_Data.horzVelocity.Value.ToString("F3")); line.Append(VOID_Data.horzVelocity.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//gee force //gee force
line.Append(VOID_Data.geeForce.Value.ToString("F3")); line.Append(VOID_Data.geeForce.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//temperature //temperature
line.Append(VOID_Data.temperature.Value.ToString("F2")); line.Append(VOID_Data.temperature.Value.ToString("F2"));
line.Append(','); line.Append(',');
   
//gravity //gravity
line.Append(VOID_Data.gravityAccel.Value.ToString("F3")); line.Append(VOID_Data.gravityAccel.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//atm density //atm density
line.Append(VOID_Data.atmDensity.Value.ToString("G3")); line.Append(VOID_Data.atmDensity.Value.ToString("G3"));
line.Append(','); line.Append(',');
   
// Downrange Distance // Downrange Distance
line.Append((VOID_Data.downrangeDistance.Value.ToString("G3"))); line.Append((VOID_Data.downrangeDistance.Value.ToString("G3")));
   
line.Append('\n'); line.Append('\n');
   
csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString())); csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
   
this.csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
   
#endregion #endregion
   
#region File IO Methods #region File IO Methods
   
protected void AsyncWriteCallback(IAsyncResult result) protected void AsyncWriteCallback(IAsyncResult result)
{ {
Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted); Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
   
this.outputFile.EndWrite(result); this.outputFile.EndWrite(result);
this.outstandingWrites--; this.outstandingWrites--;
} }
   
private void AsyncWriteData() private void AsyncWriteData()
{ {
WriteState state = new WriteState(); WriteState state = new WriteState();
   
state.bytes = this.csvBytes.ToArray(); state.bytes = this.csvBytes.ToArray();
state.stream = this.outputFile; state.stream = this.outputFile;
   
this.outstandingWrites++; this.outstandingWrites++;
var writeCallback = new AsyncCallback(this.AsyncWriteCallback); var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
   
this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state); this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
   
this.csvBytes.Clear(); this.csvBytes.Clear();
} }
   
private void CloseFileIfOpen() private void CloseFileIfOpen()
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); Tools.DebugLogger logger = Tools.DebugLogger.New(this);
   
logger.AppendFormat("Cleaning up file {0}...", this.fileName); logger.AppendFormat("Cleaning up file {0}...", this.fileName);
   
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
logger.Append(" Writing remaining data..."); logger.Append(" Writing remaining data...");
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
logger.Append(" Waiting for writes to finish."); logger.Append(" Waiting for writes to finish.");
while (this.outstandingWrites > 0) while (this.outstandingWrites > 0)
{ {
logger.Append('.'); logger.Append('.');
System.Threading.Thread.Sleep(10); System.Threading.Thread.Sleep(10);
} }
   
if (this._outputFile != null) if (this._outputFile != null)
{ {
this._outputFile.Close(); this._outputFile.Close();
this._outputFile = null; this._outputFile = null;
logger.Append(" File closed."); logger.Append(" File closed.");
} }
   
logger.Print(false); logger.Print(false);
} }
   
#endregion #endregion
   
#region Constructors & Destructors #region Constructors & Destructors
   
public VOID_DataLogger() public VOID_DataLogger()
{ {
this.Name = "CSV Data Logger"; this.Name = "CSV Data Logger";
   
this.loggingActive = false; this.loggingActive = false;
this.firstWrite = true; this.firstWrite = true;
   
this.logInterval = 0.5f; this.waitForLaunch = (VOID_SaveValue<bool>)true;
this.csvCollectTimer = 0f;  
  this.logInterval = (VOID_SaveValue<float>)0.5f;
  this.csvCollectTimer = (VOID_SaveValue<float>)0f;
   
this.outstandingWrites = 0; this.outstandingWrites = 0;
   
this.WindowPos.x = Screen.width - 520f; this.WindowPos.x = Screen.width - 520f;
this.WindowPos.y = 85f; this.WindowPos.y = 85f;
   
this.core.onApplicationQuit += delegate(object sender) this.core.onApplicationQuit += delegate(object sender)
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
}; };
} }
   
~VOID_DataLogger() ~VOID_DataLogger()
{ {
this.OnDestroy(); this.OnDestroy();
} }
   
#endregion #endregion
   
#region Subclasses #region Subclasses
   
private class WriteState private class WriteState
{ {
public byte[] bytes; public byte[] bytes;
public FileStream stream; public FileStream stream;
} }
   
#endregion #endregion
} }
} }
   
   
// VOID // VOID
// //
// VOID_EditorHUD.cs // VOID_EditorHUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.EDITOR)] [VOID_Scenes(GameScenes.EDITOR)]
public class VOID_EditorHUD : VOID_HUDModule public class VOID_EditorHUD : VOID_HUDModule
{ {
/* /*
* Fields * Fields
* */ * */
protected HUDWindow ehudWindow; protected HUDWindow ehudWindow;
protected EditorVesselOverlays _vesselOverlays; protected EditorVesselOverlays _vesselOverlays;
   
[AVOID_SaveValue("snapToLeft")] [AVOID_SaveValue("snapToLeft")]
protected VOID_SaveValue<bool> snapToLeft; protected VOID_SaveValue<bool> snapToLeft;
   
/* /*
* Properties * Properties
* */ * */
protected EditorVesselOverlays vesselOverlays protected EditorVesselOverlays vesselOverlays
{ {
get get
{ {
if (this._vesselOverlays == null) if (this._vesselOverlays == null)
{ {
this._vesselOverlays = (EditorVesselOverlays)Resources this._vesselOverlays = (EditorVesselOverlays)Resources
.FindObjectsOfTypeAll(typeof(EditorVesselOverlays)) .FindObjectsOfTypeAll(typeof(EditorVesselOverlays))
.FirstOrDefault(); .FirstOrDefault();
} }
   
return this._vesselOverlays; return this._vesselOverlays;
} }
} }
   
protected EditorMarker_CoM CoMmarker protected EditorMarker_CoM CoMmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoMmarker; return this.vesselOverlays.CoMmarker;
} }
} }
   
protected EditorMarker_CoT CoTmarker protected EditorMarker_CoT CoTmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoTmarker; return this.vesselOverlays.CoTmarker;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_EditorHUD() : base() public VOID_EditorHUD() : base()
{ {
this.Name = "Heads-Up Display"; this.Name = "Heads-Up Display";
   
this.toggleActive = true; this.toggleActive = true;
   
this.snapToLeft.value = true; this.snapToLeft.value = true;
   
this.ehudWindow = new HUDWindow( this.ehudWindow = new HUDWindow(
"editorHUD", "editorHUD",
this.ehudWindowFunc, this.ehudWindowFunc,
new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f) new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f)
); );
this.Windows.Add(this.ehudWindow); this.Windows.Add(this.ehudWindow);
   
Tools.PostDebugMessage (this.GetType().Name + ": Constructed."); Tools.PostDebugMessage (this.GetType().Name + ": Constructed.");
} }
   
public void ehudWindowFunc(int id) public void ehudWindowFunc(int id)
{ {
StringBuilder hudString = new StringBuilder(); StringBuilder hudString = new StringBuilder();
   
if (this.core.LastStage == null) if (this.core.LastStage == null)
{ {
return; return;
} }
   
VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
   
hudString.Append("Total Mass: "); hudString.Append("Total Mass: ");
hudString.Append(this.core.LastStage.totalMass.ToString("F3")); hudString.Append(this.core.LastStage.totalMass.ToString("F3"));
hudString.Append('t'); hudString.Append('t');
   
hudString.Append(' '); hudString.Append(' ');
   
hudString.Append("Part Count: "); hudString.Append("Part Count: ");
hudString.Append(EditorLogic.SortedShipList.Count); hudString.Append(EditorLogic.SortedShipList.Count);
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Total Delta-V: "); hudString.Append("Total Delta-V: ");
hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.totalDeltaV)); hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.totalDeltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage Delta-V"); hudString.Append("Bottom Stage Delta-V");
hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.deltaV)); hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.deltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage T/W Ratio: "); hudString.Append("Bottom Stage T/W Ratio: ");
hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3")); hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3"));
   
Tools.PostDebugMessage(this, Tools.PostDebugMessage(this,
"CoMmarker.gameObject.activeInHierarchy: {0};" + "CoMmarker.gameObject.activeInHierarchy: {0};" +
"CoTmarker.gameObject.activeInHierarchy: {1}", "CoTmarker.gameObject.activeInHierarchy: {1}",
this.CoMmarker.gameObject.activeInHierarchy, this.CoMmarker.gameObject.activeInHierarchy,
this.CoTmarker.gameObject.activeInHierarchy this.CoTmarker.gameObject.activeInHierarchy
); );
   
if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy) if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy)
{ {
Tools.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset."); Tools.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset.");
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Thrust Offset: "); hudString.Append("Thrust Offset: ");
hudString.Append( hudString.Append(
Vector3.Cross( Vector3.Cross(
this.CoTmarker.dirMarkerObject.transform.forward, this.CoTmarker.dirMarkerObject.transform.forward,
this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position
).ToString("F3")); ).ToString("F3"));
} }
#if DEBUG #if DEBUG
else else
{ {
Tools.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped."); Tools.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped.");
} }
#endif #endif
   
GUILayout.Label( GUILayout.Label(
hudString.ToString(), hudString.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
float hudLeft; float hudLeft;
   
if (EditorLogic.fetch.editorScreen == EditorScreen.Parts) if (EditorLogic.fetch.editorScreen == EditorScreen.Parts)
{ {
hudLeft = EditorPanels.Instance.partsPanelWidth + 10f; hudLeft = EditorPanels.Instance.partsPanelWidth + 10f;
hudLeft += EditorPartList.Instance.transformTopLeft.position.x - hudLeft += EditorPartList.Instance.transformTopLeft.position.x -
EditorPartList.Instance.transformTopLeft.parent.parent.position.x - EditorPartList.Instance.transformTopLeft.parent.parent.position.x -
72f; 72f;
} }
else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions) else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions)
{ {
hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f; hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f;
} }
else else
{ {
return; return;
} }
   
Tools.PostDebugMessage(this, Tools.PostDebugMessage(this,
"EditorPartList topLeft.parent.parent.position: {0}\n" + "EditorPartList topLeft.parent.parent.position: {0}\n" +
"EditorPartList topLeft.parent.position: {1}\n" + "EditorPartList topLeft.parent.position: {1}\n" +
"EditorPartList topLeft.position: {2}\n" + "EditorPartList topLeft.position: {2}\n" +
"snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})", "snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})",
EditorPartList.Instance.transformTopLeft.parent.parent.position, EditorPartList.Instance.transformTopLeft.parent.parent.position,
EditorPartList.Instance.transformTopLeft.parent.position, EditorPartList.Instance.transformTopLeft.parent.position,
EditorPartList.Instance.transformTopLeft.position, EditorPartList.Instance.transformTopLeft.position,
this.snapToLeft, this.ehudWindow.WindowPos.xMin, hudLeft this.snapToLeft, this.ehudWindow.WindowPos.xMin, hudLeft
); );
   
base.DrawGUI(); base.DrawGUI();
   
Rect hudPos = this.ehudWindow.WindowPos; Rect hudPos = this.ehudWindow.WindowPos;
   
if (this.snapToLeft && this.positionsLocked) if (this.snapToLeft && this.positionsLocked)
{ {
hudPos.xMin = hudLeft; hudPos.xMin = hudLeft;
} }
else else
{ {
hudPos.xMin = Mathf.Max(hudLeft, hudPos.xMin); hudPos.xMin = Mathf.Max(hudLeft, hudPos.xMin);
} }
   
hudPos.width = this.ehudWindow.defaultWindowPos.width; hudPos.width = this.ehudWindow.defaultWindowPos.width;
   
this.ehudWindow.WindowPos = hudPos; this.ehudWindow.WindowPos = hudPos;
   
this.snapToLeft = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f; this.snapToLeft.value = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f;
} }
} }
} }
   
// VOID // VOID
// //
// VOID_HUD.cs // VOID_HUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE