From: toadicus Date: Mon, 07 Mar 2016 19:52:09 +0000 Subject: Convert Screen sizes to float before doing math on them. X-Git-Tag: 0.19 X-Git-Url: http://git.toad.homelinux.net/projects/VOID.git/commitdiff/b647053 --- Convert Screen sizes to float before doing math on them. --- --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,13 @@ * text=auto * eol=lf +# These files are text and should be normalized (convert crlf => lf) +*.cs text diff=csharp +*.cfg text +*.csproj text +*.sln text + +# Images should be treated as binary +# (binary is a macro for -text -diff) +*.png binary + --- /dev/null +++ b/API/Attributes/AVOID_SaveValue.cs @@ -1,1 +1,48 @@ +// VOID +// +// AVOID_SaveValue.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 System; +namespace VOID +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class AVOID_SaveValue : Attribute + { + public string Name + { + get; + private set; + } + + public AVOID_SaveValue(string fieldName) + { + this.Name = fieldName; + } + } +} + + --- /dev/null +++ b/API/Attributes/VOID_GameModesAttribute.cs @@ -1,1 +1,48 @@ +// VOID +// +// VOID_ScenesAttribute.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 System; +namespace VOID +{ + [AttributeUsage(AttributeTargets.Class)] + public class VOID_ScenesAttribute : Attribute + { + public GameScenes[] ValidScenes + { + get; + private set; + } + + public VOID_ScenesAttribute(params GameScenes[] validScenes) + { + this.ValidScenes = validScenes; + } + } +} + + --- /dev/null +++ b/API/Attributes/VOID_ScenesAttribute.cs @@ -1,1 +1,48 @@ +// VOID +// +// VOID_ScenesAttribute.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 System; +namespace VOID +{ + [AttributeUsage(AttributeTargets.Class)] + public class VOID_GameModesAttribute : Attribute + { + public Game.Modes[] ValidModes + { + get; + private set; + } + + public VOID_GameModesAttribute(params Game.Modes[] validModes) + { + this.ValidModes = validModes; + } + } +} + + --- /dev/null +++ b/API/Enums.cs @@ -1,1 +1,25 @@ +// VOID © 2015 toadicus +// +// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a +// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ +using System; +namespace VOID +{ + public enum VOID_TimeScale : UInt32 + { + KERBIN_TIME = 1, // Earth if 0 + SOLAR_DAY = 4, // Sidereal if 0 + ROUNDED_SCALE = 1024 // Real values if 0 + } + + public enum IconState : UInt32 + { + PowerOff = 1, + PowerOn = 2, + Inactive = 4, + Active = 8 + } +} + + --- /dev/null +++ b/API/IVOID_DataValue.cs @@ -1,1 +1,44 @@ +// VOID +// +// IVOID_DataValue.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 System; +namespace VOID +{ + public interface IVOID_DataValue + { + string Label { get; } + string Units { get; } + object Value { get; } + + void Refresh(); + string ValueUnitString(); + void DoGUIHorizontal(); + } +} + + --- /dev/null +++ b/API/IVOID_Module.cs @@ -1,1 +1,60 @@ +// VOID +// +// IVOID_Module.cs +// +// Copyright © 2014, 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 System; + +namespace VOID +{ + public interface IVOID_Module + { + string Name { get; } + bool Active { get; set; } + bool GUIRunning { get; } + bool InValidScene { get; } + bool InValidGame { get; } + + void DrawGUI(object sender); + void StartGUI(); + void StopGUI(); + + void DrawConfigurables(); + + // void LoadConfig(); + void LoadConfig(KSP.IO.PluginConfiguration config); + + void Save(KSP.IO.PluginConfiguration config, string sceneKey); + } + + public interface IVOID_BehaviorModule : IVOID_Module + { + void Update(); + void FixedUpdate(); + void OnDestroy(); + } +} + --- /dev/null +++ b/API/IVOID_SaveValue.cs @@ -1,1 +1,40 @@ +// VOID +// +// IVOID_SaveValue.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 System; +namespace VOID +{ + public interface IVOID_SaveValue + { + Type type { get; } + object value { get; } + void SetValue(object v); + } +} + + --- /dev/null +++ b/API/VOIDCore.cs @@ -1,1 +1,136 @@ +// VOID +// +// IVOID_Core.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 KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Linq; +using System.Collections.Generic; +using UnityEngine; + +namespace VOID +{ + public abstract class VOIDCore : VOID_WindowModule, IVOID_Module + { + public const double Constant_G = 6.674e-11; + public const int CONFIG_VERSION = 2; + + public abstract int ConfigVersion { get; } + public virtual bool configNeedsUpdate { get; set; } + + public virtual string SaveGamePath { get; protected set; } + public virtual string VOIDSettingsPath { get; protected set; } + + public abstract string SceneKey { get; } + + public abstract int WindowID { get; } + public abstract bool configDirty { get; set; } + public abstract bool powerAvailable { get; protected set; } + + public abstract IList Modules { get; } + + public abstract float UpdateTimer { get; protected set; } + public abstract double UpdatePeriod { get; } + + public virtual float saveTimer { get; protected set; } + + public abstract GUISkin Skin { get; } + + public abstract CelestialBody HomeBody { get; } + public abstract List SortedBodyList { get; protected set; } + + public abstract VesselType[] AllVesselTypes { get; protected set; } + public abstract Stage LastStage { get; protected set; } + public abstract Stage[] Stages { get; protected set; } + + public abstract VOID_TimeScale TimeScale { get; protected set; } + + public abstract event VOIDEventHandler onApplicationQuit; + public abstract event VOIDEventHandler onSkinChanged; + public abstract event VOIDEventHandler onUpdate; + public virtual event VOIDEventHandler onPreRender; + public virtual event VOIDEventHandler onPostRender; + + public virtual bool MethodInPostRenderQueue(VOIDEventHandler method) + { + if (this.onPostRender != null) + { + ToadicusTools.Logging.PostDebugMessage(this, "Looking for method {0} in onGui", method); + + foreach (Delegate invoker in this.onPostRender.GetInvocationList()) + { + ToadicusTools.Logging.PostDebugMessage(this, "Checking invoker {0}", invoker); + + if (invoker == method) + { + ToadicusTools.Logging.PostDebugMessage(this, "Found match."); + return true; + } + } + } + #if DEBUG + else + { + ToadicusTools.Logging.PostDebugMessage(this, "this.onPostRender == null"); + } + #endif + + + return false; + } + + public void OnGUI() + { + if (Event.current.type == EventType.Repaint || Event.current.isMouse) + { + if (this.onPreRender != null) + { + ToadicusTools.Logging.PostDebugMessage(this, "In OnGUI; doing 'pre draw' stuff"); + this.onPreRender(this); + } + } + + if (this.onPostRender != null) + { + ToadicusTools.Logging.PostDebugMessage(this, "In OnGUI; doing 'post draw' stuff"); + this.onPostRender(this); + } + } + + public abstract void SaveConfig(); + + public override void Save(KSP.IO.PluginConfiguration config, string sceneKey) + { + base.Save(config, sceneKey); + } + } + + public delegate void VOIDEventHandler(object sender); +} + + --- /dev/null +++ b/API/VOIDMaster.cs @@ -1,1 +1,165 @@ +// VOID +// +// VOIDMaster.cs +// +// Copyright © 2014, 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. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors +// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some +// invaluable functions and making your nicely written code available to learn from. +// +/////////////////////////////////////////////////////////////////////////////// +// +// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. +// Engineer Redux (c) 2013 cybutek +// Used by permission. +// +/////////////////////////////////////////////////////////////////////////////// +using System; +using UnityEngine; +using KerbalEngineer.VesselSimulator; +using ToadicusTools.Extensions; + +namespace VOID +{ + public abstract class VOIDMaster : MonoBehaviour + where T : VOIDCore_Generic, new() + { + protected T Core; + + public abstract void Awake(); + + public virtual void Update() + { + if (this.Core != null && !this.InValidScene()) + { + this.LogDebug("We have a Core but the scene is not valid for this master. Saving and disposing."); + + this.Core.SaveConfig (); + this.Core.Dispose(); + this.Core = null; + return; + } + + if (this.Core == null && this.InValidScene()) + { + this.LogDebug("We have no Core and the scene is valid for this master; re-trying Awake."); + this.Awake(); + return; + } + + this.Core.Update (); + + if (this.Core.FactoryReset) + { + this.LogDebug("Factory reset is true; deleting config and disposing!"); + + KSP.IO.File.Delete("config.xml"); + System.IO.File.Delete(this.Core.VOIDSettingsPath); + + this.Core.Dispose(); + this.Core = null; + } + } + + public virtual void FixedUpdate() + { + if (this.Core == null) + { + return; + } + + this.Core.FixedUpdate (); + } + + public virtual void OnGUI() + { + if (this.Core == null) + { + return; + } + + this.Core.OnGUI(); + } + + public virtual void OnDestroy() + { + if (this.Core == null) + { + return; + } + + this.Core.OnDestroy(); + } + + public virtual void OnApplicationQuit() + { + if (this.Core == null) + { + return; + } + + this.Core.OnApplicationQuit(); + } + + protected virtual bool InValidScene() + { + object[] attributes = this.GetType().GetCustomAttributes(true); + object attr; + for (int idx = 0; idx < attributes.Length; idx++) + { + attr = attributes[idx]; + if (attr is KSPAddon) + { + KSPAddon addonAttr = (KSPAddon)attr; + + switch (addonAttr.startup) + { + case KSPAddon.Startup.EveryScene: + return true; + case KSPAddon.Startup.EditorAny: + return HighLogic.LoadedSceneIsEditor; + case KSPAddon.Startup.Flight: + return HighLogic.LoadedSceneIsFlight; + case KSPAddon.Startup.MainMenu: + return HighLogic.LoadedScene == GameScenes.MAINMENU; + case KSPAddon.Startup.SpaceCentre: + return HighLogic.LoadedScene == GameScenes.SPACECENTER; + case KSPAddon.Startup.TrackingStation: + return HighLogic.LoadedScene == GameScenes.TRACKSTATION; + default: + return false; + } + } + } + + return false; + } + } +} + --- /dev/null +++ b/API/VOID_HUDModule.cs @@ -1,1 +1,233 @@ - +// VOID +// +// VOID_HUDModule.cs +// +// Copyright © 2014, 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 KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using System.Text; +using ToadicusTools.GUIUtils; +using UnityEngine; + +namespace VOID +{ + public abstract class VOID_HUDModule : VOID_Module + { + [AVOID_SaveValue("colorIndex")] + protected VOID_SaveValue _colorIndex; + + protected List textColors; + + [AVOID_SaveValue("positionsLocked")] + protected VOID_SaveValue positionsLocked; + + public virtual int ColorIndex + { + get + { + return this._colorIndex; + } + set + { + if (this._colorIndex >= this.textColors.Count - 1) + { + this._colorIndex.value = 0; + return; + } + + this._colorIndex.value = value; + } + } + + public virtual List Windows + { + get; + protected set; + } + + public VOID_HUDModule() : base() + { + this._colorIndex = (VOID_SaveValue)0; + + this.textColors = new List(); + + this.textColors.Add(Color.green); + this.textColors.Add(Color.black); + this.textColors.Add(Color.white); + this.textColors.Add(Color.red); + this.textColors.Add(Color.blue); + this.textColors.Add(Color.yellow); + this.textColors.Add(Color.gray); + this.textColors.Add(Color.cyan); + this.textColors.Add(Color.magenta); + + this.positionsLocked = (VOID_SaveValue)true; + + this.Windows = new List(); + } + + public override void DrawGUI(object sender) + { + if (this.core == null) + { + return; + } + + VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex]; + + GUI.skin = this.core.Skin; + + if (HighLogic.LoadedSceneIsEditor || + (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate) + ) + { + SimManager.RequestSimulation(); + } + + HUDWindow window; + for (int idx = 0; idx < this.Windows.Count; idx++) + { + window = this.Windows[idx]; + + window.WindowPos = GUILayout.Window( + this.core.WindowID, + window.WindowPos, + VOID_Tools.GetWindowHandler(window.WindowFunction), + GUIContent.none, + GUIStyle.none + ); + } + } + + public override void DrawConfigurables() + { + base.DrawConfigurables(); + + if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false))) + { + ++this.ColorIndex; + } + + if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false))) + { + HUDWindow window; + for (int idx = 0; idx < this.Windows.Count; idx++) + { + window = this.Windows[idx]; + + window.WindowPos = new Rect(window.defaultWindowPos); + } + } + + this.positionsLocked.value = Layout.Toggle(this.positionsLocked, "Lock HUD Positions"); + } + + public override void LoadConfig(KSP.IO.PluginConfiguration config) + { + base.LoadConfig(config); + + config.load(); + + HUDWindow window; + for (int idx = 0; idx < this.Windows.Count; idx++) + { + window = this.Windows[idx]; + + string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName); + Rect loadedPos = config.GetValue(saveName, window.defaultWindowPos); + + window.WindowPos = loadedPos; + } + } + + public override void Save(KSP.IO.PluginConfiguration config, string sceneKey) + { + base.Save(config, sceneKey); + + HUDWindow window; + for (int idx = 0; idx < this.Windows.Count; idx++) + { + window = this.Windows[idx]; + + string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName); + config.SetValue(saveName, window.WindowPos); + } + } + } + + public class HUDWindow + { + public readonly Rect defaultWindowPos; + + private Rect _windowPos; + + public Action WindowFunction + { + get; + private set; + } + + public Rect WindowPos + { + get + { + return this._windowPos; + } + set + { + if (value != this._windowPos) + { + this._windowPos = value; + + if (VOID_Data.Core != null) + { + VOID_Data.Core.configDirty = true; + } + } + } + } + + public string WindowName + { + get; + private set; + } + + private HUDWindow() {} + + public HUDWindow(string name, Action windowFunc, Rect defaultPos) + { + this.WindowName = name; + this.WindowFunction = windowFunc; + this.defaultWindowPos = defaultPos; + this.WindowPos = new Rect(this.defaultWindowPos); + } + } +} + + --- /dev/null +++ b/API/VOID_Module.cs @@ -1,1 +1,619 @@ - +// VOID +// +// VOID_Module.cs +// +// Copyright © 2014, 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. + +// TODO: Remove ToadicusTools. prefixes after refactor is done. + +using System; +using System.Collections.Generic; +using System.Reflection; +using ToadicusTools.Extensions; +using ToadicusTools.GUIUtils; +using UnityEngine; + +namespace VOID +{ + public abstract class VOID_Module : IVOID_Module + { + /* + * Fields + * */ + [AVOID_SaveValue("Active")] + protected VOID_SaveValue active = (VOID_SaveValue)false; + + protected float lastUpdate = 0; + + private GameScenes[] validScenes; + private Game.Modes[] validModes; + + /* + * Properties + * */ + + public virtual bool Active + { + get + { + return this.active && this.InValidGame && this.InValidScene; + } + set + { + this.active.value = value && this.InValidGame && this.InValidScene; + } + } + + public virtual bool GUIRunning + { + get + { + /*if ( + RenderingManager.fetch == null || + RenderingManager.fetch.postDrawQueue == null || + RenderingManager.fetch.postDrawQueue.Length < 4 + ) + { + return false; + } + else + { + Delegate callback = RenderingManager.fetch.postDrawQueue[3]; + if (callback == null) + { + return false; + } + + return callback.GetInvocationList().Contains((Callback)this.DrawGUI); + }*/ + + using (var log = ToadicusTools.DebugTools.PooledDebugLogger.New(this)) + { + log.AppendFormat("this.core: {0}\n", this.core != null ? this.core.ToString() : "null"); + if (this.core != null) + { + log.AppendFormat("this.core.MethodInPostRenderQueue(this.DrawGUI): {0}\n", + this.core.MethodInPostRenderQueue(this.DrawGUI)); + } + + log.AppendFormat("this.GUIRunning: {0}\n", + this.core != null && this.core.MethodInPostRenderQueue(this.DrawGUI)); + + log.Print(false); + } + + return this.core != null && this.core.MethodInPostRenderQueue(this.DrawGUI); + } + } + + public virtual bool InValidGame + { + get + { + return this.ValidModes.Contains(HighLogic.CurrentGame.Mode); + } + } + + public virtual bool InValidScene + { + get + { + return this.ValidScenes.Contains(HighLogic.LoadedScene); + } + } + + public virtual string Name + { + get; + protected set; + } + + public virtual Game.Modes[] ValidModes + { + get + { + if (this.validModes == null) + { + ToadicusTools.Logging.PostDebugMessage(this, "validModes is null when checking inValidGame; fetching attribute."); + + object[] attributes = this.GetType().GetCustomAttributes(false); + object attr; + for (int idx = 0; idx < attributes.Length; idx++) + { + attr = attributes[idx]; + + if (attr is VOID_GameModesAttribute) + { + VOID_GameModesAttribute addonAttr = (VOID_GameModesAttribute)attr; + + this.validModes = addonAttr.ValidModes; + + ToadicusTools.Logging.PostDebugMessage("Found VOID_GameModesAttribute; validScenes set."); + + break; + } + } + + if (this.validModes == null) + { + this.validModes = new Game.Modes[] + { + Game.Modes.CAREER, + Game.Modes.SANDBOX, + Game.Modes.SCENARIO, + Game.Modes.SCENARIO_NON_RESUMABLE, + Game.Modes.SCIENCE_SANDBOX + }; + + ToadicusTools.Logging.PostDebugMessage("No VOID_GameModesAttribute found; validScenes defaulted to flight."); + } + } + + return this.validModes; + } + } + + public virtual GameScenes[] ValidScenes + { + get + { + if (this.validScenes == null) + { + ToadicusTools.Logging.PostDebugMessage(this, "validScenes is null when checking inValidScene; fetching attribute."); + object[] attributes = this.GetType().GetCustomAttributes(false); + object attr; + for (int idx = 0; idx < attributes.Length; idx++) + { + attr = attributes[idx]; + + if (attr is VOID_ScenesAttribute) + { + VOID_ScenesAttribute addonAttr = (VOID_ScenesAttribute)attr; + + this.validScenes = addonAttr.ValidScenes; + + ToadicusTools.Logging.PostDebugMessage("Found VOID_ScenesAttribute; validScenes set."); + + break; + } + } + + if (this.validScenes == null) + { + this.validScenes = new GameScenes[] { GameScenes.FLIGHT }; + ToadicusTools.Logging.PostDebugMessage("No VOID_ScenesAttribute found; validScenes defaulted to flight."); + } + } + + return this.validScenes; + } + } + + public virtual Vessel Vessel + { + get + { + return FlightGlobals.ActiveVessel; + } + } + + protected virtual VOIDCore core + { + get + { + return VOID_Data.Core; + } + } + + protected virtual bool timeToUpdate + { + get + { + return ( + (this.core.UpdateTimer - this.lastUpdate) > this.core.UpdatePeriod || + this.lastUpdate > this.core.UpdateTimer + ); + } + } + + /* + * Methods + * */ + public virtual void StartGUI() + { + if (!this.Active || this.GUIRunning) + { + return; + } + + ToadicusTools.Logging.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name)); + // RenderingManager.AddToPostDrawQueue (3, this.DrawGUI); + this.core.onPostRender += this.DrawGUI; + } + + public virtual void StopGUI() + { + if (!this.GUIRunning) + { + return; + } + ToadicusTools.Logging.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name)); + this.core.onPostRender -= this.DrawGUI; + } + + public abstract void DrawGUI(object sender); + + public virtual void DrawConfigurables() {} + + public virtual void LoadConfig(KSP.IO.PluginConfiguration config) + { + config.load (); + + if (this is VOIDCore) + { + int configVersion = config.GetValue("VOID_Core_configValue", 2); + + if (configVersion < VOIDCore.CONFIG_VERSION) + { + ((VOIDCore)this).configNeedsUpdate = true; + } + } + + MemberInfo[] members = this.GetType().GetMembers( + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.FlattenHierarchy + ); + MemberInfo member; + + for (int fIdx = 0; fIdx < members.Length; fIdx++) + { + member = members[fIdx]; + + if (!(member is FieldInfo || member is PropertyInfo)) + { + continue; + } + + if (member is PropertyInfo && (member as PropertyInfo).GetIndexParameters().Length > 0) + { + continue; + } + + object[] attrs = member.GetCustomAttributes(typeof(AVOID_SaveValue), false); + + AVOID_SaveValue attr; + + if (attrs.Length > 0) + { + attr = (AVOID_SaveValue)attrs[0]; + } + else + { + continue; + } + + string fieldName = string.Empty; + + if (this is VOIDCore || this.core.configNeedsUpdate) + { + string typeName = this.GetType().Name;; + + if (this is VOIDCore && ((VOIDCore)this).configNeedsUpdate) + { + if (this is VOIDCore_Flight) + { + typeName = "VOID_Core"; + } + else if (this is VOIDCore_Editor) + { + typeName = "VOID_EditorCore"; + } + } + + fieldName = string.Format("{0}_{1}", typeName, attr.Name); + } + else + { + fieldName = string.Format( + "{0}_{1}_{2}", + this.GetType().Name, + Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene), + attr.Name + ); + } + + ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Loading field {1}.", this.GetType().Name, fieldName)); + + object fieldValue; + + if (member is FieldInfo) + { + fieldValue = (member as FieldInfo).GetValue(this); + } + else + { + fieldValue = (member as PropertyInfo).GetValue(this, null); + } + + bool convertBack = false; + if (fieldValue is IVOID_SaveValue) + { + fieldValue = (fieldValue as IVOID_SaveValue).value; + convertBack = true; + } + + fieldValue = config.GetValue(fieldName, fieldValue); + + if (convertBack) + { + Type type = typeof(VOID_SaveValue<>).MakeGenericType (fieldValue.GetType ()); + IVOID_SaveValue convertValue = Activator.CreateInstance (type) as IVOID_SaveValue; + convertValue.SetValue (fieldValue); + fieldValue = convertValue; + } + + if (member is FieldInfo) + { + (member as FieldInfo).SetValue(this, fieldValue); + } + else + { + (member as PropertyInfo).SetValue(this, fieldValue, null); + } + + ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName)); + } + } + + public virtual void Save(KSP.IO.PluginConfiguration config, string sceneKey) + { + if (config == null) + { + ToadicusTools.Logging.PostErrorMessage( + "{0}: config argument was null, bailing out.", + this.GetType().Name + ); + } + + if (sceneKey == null) + { + ToadicusTools.Logging.PostErrorMessage( + "{0}: sceneKey argument was null, bailing out.", + this.GetType().Name + ); + } + + MemberInfo[] members = this.GetType().GetMembers( + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.FlattenHierarchy + ); + MemberInfo member; + + for (int fIdx = 0; fIdx < members.Length; fIdx++) + { + member = members[fIdx]; + + object[] attrs = member.GetCustomAttributes(typeof(AVOID_SaveValue), false); + + AVOID_SaveValue attr; + + if (attrs.Length > 0) + { + attr = (AVOID_SaveValue)attrs[0]; + } + else + { + continue; + } + + string fieldName; + + if (this is VOIDCore) + { + fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name); + } + else + { + fieldName = string.Format( + "{0}_{1}_{2}", + this.GetType().Name, + sceneKey, + attr.Name + ); + } + + object fieldValue; + + if (member is FieldInfo) + { + fieldValue = (member as FieldInfo).GetValue(this); + } + else + { + fieldValue = (member as PropertyInfo).GetValue(this, null); + } + + if (fieldValue is IVOID_SaveValue) + { + fieldValue = (fieldValue as IVOID_SaveValue).value; + } + + config.SetValue(fieldName, fieldValue); + + ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Saved field {1}.", this.GetType().Name, fieldName)); + } + } + } + + public abstract class VOID_WindowModule : VOID_Module + { + [AVOID_SaveValue("WindowPos")] + protected Rect WindowPos; + protected float defWidth; + protected float defHeight; + + protected bool decorateWindow; + + protected string inputLockName; + + public VOID_WindowModule() : base() + { + this.defWidth = 250f; + this.defHeight = 50f; + + this.decorateWindow = true; + + this.inputLockName = string.Concat(this.Name, "_edlock"); + + this.WindowPos = new Rect(Screen.width / 2, Screen.height / 2, this.defWidth, this.defHeight); + } + + 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.Active = false; + this.removeUILock(); + } + } + + GUI.DragWindow(); + } + + public override void DrawGUI(object sender) + { + if (this.core == null) + { + return; + } + + GUI.skin = this.core.Skin; + + Rect _Pos = this.WindowPos; + + _Pos = GUILayout.Window( + this.core.WindowID, + _Pos, + VOID_Tools.GetWindowHandler(this.ModuleWindow), + this.Name, + GUILayout.Width(this.defWidth), + GUILayout.Height(this.defHeight) + ); + + bool cursorInWindow = _Pos.Contains(Mouse.screenPos); + + if (cursorInWindow) + { + this.setUILock(); + } + else + { + this.removeUILock(); + } + + if (HighLogic.LoadedSceneIsEditor) + { + _Pos = WindowTools.ClampRectToEditorPad(_Pos); + } + else + { + _Pos = WindowTools.ClampRectToScreen(_Pos); + } + + if (_Pos != this.WindowPos) + { + this.WindowPos = _Pos; + this.core.configDirty = true; + } + } + + protected void setUILock() + { + switch (HighLogic.LoadedScene) + { + case GameScenes.EDITOR: + InputLockManager.SetControlLock( + ControlTypes.EDITOR_ICON_HOVER | ControlTypes.EDITOR_ICON_PICK | + ControlTypes.EDITOR_PAD_PICK_COPY | ControlTypes.EDITOR_PAD_PICK_COPY, + this.inputLockName + ); + EditorLogic.fetch.Lock(false, false, false, this.inputLockName); + break; + case GameScenes.FLIGHT: + InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS, this.inputLockName); + break; + case GameScenes.SPACECENTER: + InputLockManager.SetControlLock( + ControlTypes.KSC_FACILITIES | ControlTypes.CAMERACONTROLS, + this.inputLockName + ); + break; + } + } + + protected void removeUILock() + { + switch (HighLogic.LoadedScene) + { + case GameScenes.EDITOR: + EditorLogic.fetch.Unlock(this.inputLockName); + break; + case GameScenes.FLIGHT: + InputLockManager.RemoveControlLock(this.inputLockName); + break; + case GameScenes.SPACECENTER: + InputLockManager.RemoveControlLock(this.inputLockName); + break; + } + } + } +} + + --- /dev/null +++ b/API/VOID_SingletonCore.cs @@ -1,1 +1,71 @@ +// VOID +// +// VOID_SingletonModule.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 System; +using UnityEngine; + +namespace VOID +{ + public abstract class VOID_SingletonCore : VOIDCore, IVOID_Module, IDisposable + where T : VOID_Module, new() + { + #region Singleton Members + /* + * Static Members + * */ + protected static bool _initialized = false; + + public static bool Initialized + { + get + { + return _initialized; + } + } + + protected static T _instance; + + public static T Instance + { + get + { + if (_instance == null) + { + _instance = new T(); + _initialized = true; + } + return _instance; + } + } + + public abstract void Dispose(); + #endregion + } +} + + --- /dev/null +++ b/API/VOID_SingletonWindow.cs @@ -1,1 +1,73 @@ +// VOID +// +// VOID_SingletonModule.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 System; +namespace VOID +{ + public abstract class VOID_SingletonWindow : VOID_WindowModule, IVOID_Module, IDisposable + where T : VOID_WindowModule, new() + { + #region Singleton Members + /* + * Static Members + * */ + protected static bool _initialized = false; + + public static bool Initialized + { + get + { + return _initialized; + } + } + + protected static T _instance; + + public static T Instance + { + get + { + if (_instance == null) + { + _instance = new T(); + _initialized = true; + } + return _instance; + } + } + + public virtual void Dispose() + { + _instance = null; + _initialized = false; + } + #endregion + } +} + + --- /dev/null +++ b/GameData/VOID/Textures/ATM_VOID.cfg @@ -1,1 +1,16 @@ +ACTIVE_TEXTURE_MANAGER_CONFIG +{ + folder = VOID + enabled = true + OVERRIDES + { + VOID/Textures/.* + { + compress = false + mipmaps = false + scale = 1 + max_size = 0 + } + } +} --- a/IVOID_Module.cs +++ /dev/null @@ -1,58 +1,1 @@ -// VOID -// -// IVOID_Module.cs -// -// Copyright © 2014, 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 System; - -namespace VOID -{ - public interface IVOID_Module - { - string Name { get; } - bool toggleActive { get; set; } - bool guiRunning { get; } - - void DrawGUI(); - void StartGUI(); - void StopGUI(); - - void DrawConfigurables(); - - void LoadConfig(); - - void _SaveToConfig(KSP.IO.PluginConfiguration config); - } - - public interface IVOID_BehaviorModule : IVOID_Module - { - void Update(); - void FixedUpdate(); - } - - public interface IVOID_EditorModule : IVOID_Module {} -} - --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -39,10 +39,9 @@ // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("0.13.*")] +[assembly: AssemblyVersion("0.18.5.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] - --- /dev/null +++ b/Tools/VOID_DataValue.cs @@ -1,1 +1,359 @@ - +// VOID +// +// VOID_DataValue.cs +// +// Copyright © 2014, 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. + +// TODO: Remove ToadicusTools. prefixes after refactor is done. + +using System; +using ToadicusTools.MuMechTools; +using ToadicusTools.Text; +using UnityEngine; + +namespace VOID +{ + public class VOID_DataValue : IVOID_DataValue + { + /* + * Static Members + * */ + public static implicit operator T(VOID_DataValue v) + { + return (T)v.Value; + } + + /* + * Instance Members + * */ + /* + * Fields + * */ + protected T cache; + protected Func ValueFunc; + protected float lastUpdate; + + /* + * Properties + * */ + public string Label { get; protected set; } + public string Units { get; protected set; } + + object IVOID_DataValue.Value + { + get + { + return this.Value; + } + } + + public T Value + { + get + { + if ( + (VOID_Data.Core.UpdateTimer - this.lastUpdate > VOID_Data.Core.UpdatePeriod) || + (this.lastUpdate > VOID_Data.Core.UpdateTimer) + ) + { + this.Refresh(); + } + return (T)this.cache; + } + } + + /* + * Methods + * */ + public VOID_DataValue(string Label, Func ValueFunc, string Units = "") + { + this.Label = Label; + this.Units = Units; + this.ValueFunc = ValueFunc; + this.lastUpdate = 0; + + VOID_Data.DataValues[this.GetHashCode()] = this; + } + + public void Refresh() + { + this.cache = this.ValueFunc.Invoke (); + this.lastUpdate = VOID_Data.Core.UpdateTimer; + } + + public T GetFreshValue() + { + this.Refresh (); + return (T)this.cache; + } + + public virtual string ValueUnitString() { + return this.Value.ToString() + this.Units; + } + + public virtual void DoGUIHorizontal() + { + GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); + GUILayout.Label (this.Label + ":"); + GUILayout.FlexibleSpace (); + GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false)); + GUILayout.EndHorizontal (); + } + + public override int GetHashCode() + { + int hash; + unchecked + { + hash = 79999; + + hash = hash * 104399 + this.Label.GetHashCode(); + hash = hash * 104399 + this.ValueFunc.GetHashCode(); + hash = hash * 104399 + this.Units.GetHashCode(); + } + + return hash; + } + + public override string ToString() + { + return string.Format ( + "{0}: {1}{2}", + this.Label, + this.Value.ToString (), + this.Units + ); + } + } + + public abstract class VOID_NumValue : VOID_DataValue, IFormattable + where T : IFormattable, IConvertible, IComparable + { + public static IFormatProvider formatProvider = SIFormatProvider.SIFormatter; + + public static implicit operator Double(VOID_NumValue v) + { + return v.ToDouble(); + } + + public static implicit operator Int32(VOID_NumValue v) + { + return v.ToInt32(); + } + + public static implicit operator Single(VOID_NumValue v) + { + return v.ToSingle(); + } + + public VOID_NumValue(string Label, Func ValueFunc, string Units = "") : base(Label, ValueFunc, Units) + { + + } + + public virtual double ToDouble(IFormatProvider provider) + { + return this.Value.ToDouble(provider); + } + + public virtual double ToDouble() + { + return this.ToDouble(formatProvider); + } + + public virtual int ToInt32(IFormatProvider provider) + { + return this.Value.ToInt32(provider); + } + + public virtual int ToInt32() + { + return this.ToInt32(formatProvider); + } + + public virtual float ToSingle(IFormatProvider provider) + { + return this.Value.ToSingle(provider); + } + + public virtual float ToSingle() + { + return this.ToSingle(formatProvider); + } + + public virtual string ToString(string format) + { + return this.ToString(format, formatProvider); + } + + public virtual string ToString(string format, IFormatProvider provider) + { + return string.Format ( + "{0}{1}", + this.Value.ToString(format, provider), + this.Units + ); + } + + public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue) + { + return string.Format ( + "{0}{1}", + MuMechTools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude), + this.Units + ); + } + + public virtual string ValueUnitString(string format) + { + return this.Value.ToString(format, formatProvider) + this.Units; + } + + public virtual string ValueUnitString(int digits) { + return string.Format("{0}{1}", SIFormatProvider.ToSI(this, digits), Units); + } + + public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude) + { + return MuMechTools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units; + } + + public virtual void DoGUIHorizontal(string format) + { + GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); + GUILayout.Label (this.Label + ":"); + GUILayout.FlexibleSpace (); + GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false)); + GUILayout.EndHorizontal (); + } + + public virtual int DoGUIHorizontal(int digits, bool precisionButton = true) + { + if (precisionButton) + { + return this.DoGUIHorizontalPrec(digits); + } + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true)); + GUILayout.FlexibleSpace(); + GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + + return digits; + } + + public virtual int DoGUIHorizontalPrec(int digits) + { + if (digits < 0 || digits > 8) + { + digits = 5; + } + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true)); + GUILayout.FlexibleSpace(); + + GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false)); + + GUILayout.EndHorizontal(); + + if (Event.current.type == EventType.mouseUp) + { + Rect lastRect = GUILayoutUtility.GetLastRect(); + if (lastRect.Contains(Event.current.mousePosition)) + { + ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Changing digits from {1}", + this.GetType().Name, + digits + )); + + if (Event.current.button == 0) + { + digits = (digits + 3) % 9; + } + else if (Event.current.button == 1) + { + digits = (digits - 3) % 9; + } + + if (digits < 0) + { + digits += 9; + } + + ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Changed digits to {1}.", + this.GetType().Name, + digits + )); + } + } + + return digits; + } + } + + public class VOID_DoubleValue : VOID_NumValue + { + public VOID_DoubleValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} + } + + public class VOID_FloatValue : VOID_NumValue + { + public VOID_FloatValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} + } + + public class VOID_IntValue : VOID_NumValue + { + public VOID_IntValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} + } + + public class VOID_StrValue : VOID_DataValue + { + public VOID_StrValue(string Label, Func ValueFunc) : base(Label, ValueFunc, "") {} + } + + public class VOID_Vector3Value : VOID_DataValue + { + public VOID_Vector3Value(string Label, Func ValueFunc, string Units) + : base(Label, ValueFunc, Units) + {} + + public string ToString(string format) + { + return string.Format("{0}: {1}{2}", + this.Label, + this.Value.ToString(format), + this.Units + ); + } + + public string ValueUnitString(string format) { + return this.Value.ToString(format) + this.Units; + } + } +} + + --- /dev/null +++ b/Tools/VOID_Localization.cs @@ -1,1 +1,36 @@ +// VOID +// +// VOID_Localization.cs +// +// Copyright © 2014, 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. +public static class VOID_Localization +{ + public static string void_primary = "Primary"; + public static string void_altitude_asl = "Altitude (ASL)"; + public static string void_velocity = "Velocity"; + public static string void_apoapsis = "Apoapsis"; + public static string void_periapsis = "Periapsis"; +} --- /dev/null +++ b/Tools/VOID_SaveValue.cs @@ -1,1 +1,126 @@ +// VOID +// +// VOID_SaveValue.cs +// +// Copyright © 2014, 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. +// TODO: Remove ToadicusTools. prefixes after refactor is done. + +using KSP; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VOID +{ + public struct VOID_SaveValue : IVOID_SaveValue + { + private T _value; + private Type _type; + + private VOIDCore Core + { + get + { + return VOID_Data.Core; + } + } + + object IVOID_SaveValue.value + { + get + { + return this.value; + } + } + + public T value + { + get + { + return this._value; + } + set + { + if (this.Core != null && !System.Object.Equals(this._value, value)) + { + ToadicusTools.Logging.PostDebugMessage (string.Format ( + "VOID: Dirtying config for type {0}." + + "\n\t Old Value: {1}, New Value: {2}" + + "\n\t Object.Equals(New, Old): {3}\n" + + this._type, + this._value, + value, + System.Object.Equals(this._value, value) + )); + this.Core.configDirty = true; + } + this._value = value; + } + } + + public Type type + { + get + { + if (this._type == null && this._value != null) + { + this._type = this._value.GetType (); + } + return this._type; + } + set + { + this._type = value; + } + } + + public void SetValue(object v) + { + this.value = (T)v; + } + + public static implicit operator T(VOID_SaveValue v) + { + return (T)v.value; + } + + public static explicit operator VOID_SaveValue(T v) + { + VOID_SaveValue r = new VOID_SaveValue(); + r.type = v.GetType(); + r.value = v; + + return r; + } + + public override string ToString() + { + return this.value.ToString(); + } + } +} + + --- /dev/null +++ b/Tools/VOID_StageExtensions.cs @@ -1,1 +1,38 @@ +// VOID © 2015 toadicus +// +// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a +// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ +using KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VOID +{ + public static class VOID_StageExtensions + { + public static double NominalThrust(this Stage stage) + { + if (stage.actualThrust == 0d) + { + return stage.thrust; + } + else + { + return stage.actualThrust; + } + } + + public static double MassFlow(this Stage stage) + { + double stageIsp = VOID_Data.Core.LastStage.isp; + double stageThrust = stage.NominalThrust(); + + return stageThrust / (stageIsp * VOID_Data.KerbinGee); + } + } +} + + --- /dev/null +++ b/Tools/VOID_Tools.cs @@ -1,1 +1,1094 @@ - +// VOID +// +// VOID_Tools.cs +// +// Copyright © 2014, 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 System.Collections.Generic; +using ToadicusTools; +using UnityEngine; + +namespace VOID +{ + public static class VOID_Tools + { + #region CelestialBody Utilities + public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB) + { + if (bodyA == null || bodyB == null) + { + return false; + } + + while (bodyA.orbitDriver != null) + { + if (bodyA.orbit.referenceBody == bodyB) + { + return true; + } + + bodyA = bodyA.orbit.referenceBody; + } + + return false; + } + + public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB) + { + if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null) + { + throw new ArgumentException(string.Concat( + "CelestialBody::FindRelatedParents: ", + "Neither body may be null, and both bodies must have orbits." + )); + } + + CelestialBody a, b; + + a = bodyA; + + while (bodyA.orbitDriver != null) + { + b = bodyB; + + while (b.orbitDriver != null) + { + if (a.orbit.referenceBody == b.orbit.referenceBody) + { + bodyA = a; + bodyB = b; + return true; + } + + b = b.orbit.referenceBody; + } + + a = a.orbit.referenceBody; + } + + return false; + } + #endregion + + #region VESSEL_EXTENSIONS_SCIENCE + public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel) + { + CBAttributeMapSO.MapAttribute mapAttribute; + + try + { + CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap; + + double lat = vessel.latitude * Math.PI / 180d; + double lon = vessel.longitude * Math.PI / 180d; + + mapAttribute = BiomeMap.GetAtt(lat, lon); + + /* + lon -= Math.PI / 2d; + + if (lon < 0d) + { + lon += 2d * Math.PI; + } + + float v = (float)(lat / Math.PI) + 0.5f; + float u = (float)(lon / (2d * Math.PI)); + + Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v); + mapAttribute = BiomeMap.defaultAttribute; + + if (BiomeMap.Map != null) + { + if (BiomeMap.exactSearch) + { + for (int i = 0; i < BiomeMap.Attributes.Length; ++i) + { + if (pixelBilinear == BiomeMap.Attributes[i].mapColor) + { + mapAttribute = BiomeMap.Attributes[i]; + } + } + } + else + { + float zero = 0; + float num = 1 / zero; + for (int j = 0; j < BiomeMap.Attributes.Length; ++j) + { + Color mapColor = BiomeMap.Attributes[j].mapColor; + float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude; + if (sqrMagnitude < num) + { + bool testCase = true; + if (BiomeMap.nonExactThreshold != -1) + { + testCase = (sqrMagnitude < BiomeMap.nonExactThreshold); + } + if (testCase) + { + mapAttribute = BiomeMap.Attributes[j]; + num = sqrMagnitude; + } + } + } + } + } + */ + } + catch (NullReferenceException) + { + mapAttribute = new CBAttributeMapSO.MapAttribute(); + mapAttribute.name = "N/A"; + } + + return mapAttribute; + } + + public static ExperimentSituations GetExperimentSituation(this Vessel vessel) + { + if (vessel == null) + { + return ExperimentSituations.SrfSplashed; + } + + Vessel.Situations situation = vessel.situation; + + switch (situation) + { + case Vessel.Situations.PRELAUNCH: + case Vessel.Situations.LANDED: + return ExperimentSituations.SrfLanded; + case Vessel.Situations.SPLASHED: + return ExperimentSituations.SrfSplashed; + case Vessel.Situations.FLYING: + if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold) + { + return ExperimentSituations.FlyingLow; + } + else + { + return ExperimentSituations.FlyingHigh; + } + } + + if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold) + { + return ExperimentSituations.InSpaceLow; + } + else + { + return ExperimentSituations.InSpaceHigh; + } + } + + public static string HumanString(this ExperimentSituations situation) + { + switch (situation) + { + case ExperimentSituations.FlyingHigh: + return "Upper Atmosphere"; + case ExperimentSituations.FlyingLow: + return "Flying"; + case ExperimentSituations.SrfLanded: + return "Surface"; + case ExperimentSituations.InSpaceLow: + return "Near in Space"; + case ExperimentSituations.InSpaceHigh: + return "High in Space"; + case ExperimentSituations.SrfSplashed: + return "Splashed Down"; + default: + return "Unknown"; + } + } + #endregion + + #region VESSEL_EXTENSIONS_LAT_LONG + public static string GetLongitudeString(this Vessel vessel, string format = "F4") + { + string dir_long = "W"; + double v_long = vessel.longitude; + + v_long = FixDegreeDomain(v_long); + + if (v_long < -180d) + { + v_long += 360d; + } + if (v_long >= 180) + { + v_long -= 360d; + } + + if (v_long > 0) + dir_long = "E"; + + return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long); + } + + public static string GetLatitudeString(this Vessel vessel, string format = "F4") + { + string dir_lat = "S"; + double v_lat = vessel.latitude; + if (v_lat > 0) + dir_lat = "N"; + + return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat); + } + #endregion + + #region VESSEL_EXTENSIONS_GENERAL + public static double TrueAltitude(Vessel vessel) + { + double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude; + + // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, + // and water covers the whole surface at 0 m. + if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean) + { + trueAltitude = vessel.orbit.altitude; + } + + return trueAltitude; + } + + public static double Radius(this Vessel vessel) + { + double radius; + + radius = vessel.altitude; + + if (vessel.mainBody != null) + { + radius += vessel.mainBody.Radius; + } + + return radius; + } + #endregion + + #region GEOMETRY_UTILS + public static double FixAngleDomain(double Angle, bool Degrees = false) + { + double Extent = 2d * Math.PI; + if (Degrees) + { + Extent = 360d; + } + + Angle = Angle % (Extent); + if (Angle < 0d) + { + Angle += Extent; + } + + return Angle; + } + + public static double FixDegreeDomain(double Angle) + { + return FixAngleDomain(Angle, true); + } + #endregion + + #region WINDOW_UTILS + private static Dictionary functionCache; + public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action func) + { + if (functionCache == null) + { + functionCache = new Dictionary(); + } + + int hashCode = func.GetHashCode(); + + if (!functionCache.ContainsKey(hashCode)) + { + functionCache[hashCode] = delegate (int id) + { + try + { + func(id); + } + #if !DEBUG + catch (ArgumentException) + { + Debug.LogWarning( + string.Format("[{0}]: ArgumentException caught during window call." + + " This may not be a bug when occuring during scene changes.", + func.Target.GetType().Name + )); + } + #endif + catch (Exception ex) + { + Debug.LogError( + string.Format("[{0}]: {1} caught during window call.\nMessage:\n{2}\nStackTrace:\n{3}", + func.Target.GetType().Name, + ex.GetType().Name, + ex.Message, + ex.StackTrace + )); + } + }; + } + + return functionCache[hashCode]; + } + + public static void UncacheWindow(Action func) + { + if (functionCache != null) + { + int hashCode = func.GetHashCode(); + + if (functionCache.ContainsKey(hashCode)) + { + functionCache.Remove(hashCode); + } + } + } + #endregion + + #region TIME_UTILS + /// + /// Formats the interval given in seconds as a human-friendly + /// time period in [[[[years, ]days, ]hours, ]minutes, and ]seconds. + /// + /// Uses sidereal days, since "6 hours per day" is the Kerbal standard. + /// + /// Human readable interval + /// + public static string FormatInterval(double seconds) + { + return UnpackedTime.FromSeconds(seconds).FormatAsSpan(); + } + + /// + /// Formats the date given in seconds since epoch as a human-friendly + /// date in the format YY, DD, HH:MM:SS + /// + /// The date. + /// Seconds. + public static string FormatDate(double seconds) + { + return UnpackedTime.FromSeconds(seconds).FormatAsDate(); + } + + public class UnpackedTime + { + public const double SecondsPerMinute = 60d; + public const double SecondsPerHour = 3600d; + + public static double SecondsPerDay + { + get + { + VOID_TimeScale flags = VOID_Data.Core.TimeScale & + (VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE); + + switch (flags) + { + // Earth day, sidereal + case 0: + return 86164.1d; + // Earth day, solar (also rounded) + case VOID_TimeScale.ROUNDED_SCALE | VOID_TimeScale.SOLAR_DAY: + case VOID_TimeScale.ROUNDED_SCALE: + case VOID_TimeScale.SOLAR_DAY: + return 86400d; + // Kerbin day, solar + case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY: + return 21650.813d; + // Kerbin day, sidereal (also rounded) + default: + return 21600d; + } + } + } + + public static double SecondsPerYear + { + get + { + VOID_TimeScale flags = VOID_Data.Core.TimeScale & + (VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE); + + switch (flags) + { + // Earth year, rounded + case VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE: + case VOID_TimeScale.ROUNDED_SCALE: + return 60 * 60 * 24 * 365; + // Kerbin year, rounded + case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE: + case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.ROUNDED_SCALE: + return 60 * 60 * 6 * 426; + // Earth year, solar time + case VOID_TimeScale.SOLAR_DAY: + return 31556925.2507328; + // Earth year, sidereal time + case 0: + return 31558149.7635456d; + // Kerbin year, solar & sidereal time + default: + return 9203544.61750141d; + } + } + } + + public static UnpackedTime FromSeconds(double seconds) + { + UnpackedTime time = new UnpackedTime(); + + time.years = (int)(seconds / SecondsPerYear); + + seconds %= SecondsPerYear; + + time.days = (int)(seconds / SecondsPerDay); + + seconds %= SecondsPerDay; + + time.hours = (int)(seconds / SecondsPerHour); + + seconds %= SecondsPerHour; + + time.minutes = (int)(seconds / SecondsPerMinute); + + seconds %= SecondsPerMinute; + + time.seconds = seconds; + + return time; + } + + public static explicit operator UnpackedTime(double seconds) + { + return FromSeconds(seconds); + } + + public static implicit operator double(UnpackedTime time) + { + return time.ToSeconds(); + } + + public static UnpackedTime operator+ (UnpackedTime lhs, UnpackedTime rhs) + { + return FromSeconds(lhs.ToSeconds() + rhs.ToSeconds()); + } + + public static UnpackedTime operator- (UnpackedTime lhs, UnpackedTime rhs) + { + return FromSeconds(lhs.ToSeconds() - rhs.ToSeconds()); + } + + public int years; + public int days; + public int hours; + public int minutes; + public double seconds; + + public double ToSeconds() + { + return (double)years * SecondsPerYear + + (double)days * SecondsPerDay + + (double)hours * SecondsPerHour + + (double)minutes * SecondsPerMinute + + seconds; + } + + public string FormatAsSpan() + { + 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_3 = "{0:D2}h {1:D2}m {2:00.0}s"; + string format_4 = "{0:D2}m {1:00.0}s"; + string format_5 = "{0:00.0}s"; + + if (this.years > 0) + { + return string.Format(format_1, this.years, this.days, this.hours, this.minutes, this.seconds); + } + else if (this.days > 0) + { + return string.Format(format_2, this.days, this.hours, this.minutes, this.seconds); + } + else if (this.hours > 0) + { + return string.Format(format_3, this.hours, this.minutes, this.seconds); + } + else if (this.minutes > 0) + { + return string.Format(format_4, this.minutes, this.seconds); + } + else + { + return string.Format(format_5, this.seconds); + } + } + + public string FormatAsDate() + { + 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); + } + + public UnpackedTime(int years, int days, int hours, int minutes, double seconds) + { + this.years = years; + this.days = days; + this.hours = hours; + this.minutes = minutes; + this.seconds = seconds; + } + + public UnpackedTime() : this(0, 0, 0, 0, 0d) {} + } + #endregion + + public static string UppercaseFirst(string s) + { + if (string.IsNullOrEmpty(s)) + { + return string.Empty; + } + char[] a = s.ToCharArray(); + a[0] = char.ToUpper(a[0]); + return new string(a); + } + + //transfer angles + public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param) + { + r_target /= 1000; + r_current /= 1000; + grav_param /= 1000000000; + + 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_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param); + return 360 * (0.5 - (T_transfer / (2 * T_target))); + } + + public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2) + { + /* + def deltaVToGetToOtherBody(mu, r1, r2): + # mu = gravity param of common orbiting body of r1 and r2 + # (e.g. for mun to minmus, mu is kerbin's gravity param + # r1 = initial body's orbit radius + # r2 = target body's orbit radius + + # return value is km/s + sur1 = math.sqrt(mu / r1) + sr1r2 = math.sqrt(float(2*r2)/float(r1+r2)) + mult = sr1r2 - 1 + return sur1 * mult + */ + double sur1, sr1r2, mult; + sur1 = Math.Sqrt(mu / r1); + sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2)); + mult = sr1r2 - 1; + return sur1 * mult; + } + + public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v) + { + /* + def deltaVToExitSOI(mu, r1, r2, v): + # mu = gravity param of current body + # r1 = current orbit radius + # r2 = SOI radius + # v = SOI exit velocity + foo = r2 * (v**2) - 2 * mu + bar = r1 * foo + (2 * r2 * mu) + r = r1*r2 + return math.sqrt(bar / r) + */ + double foo = r2 * (v * v) - 2 * mu; + double bar = r1 * foo + (2 * r2 * mu); + double r = r1 * r2; + return Math.Sqrt(bar / r); + } + + public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu) + { + /* + def transferBurnPoint(r, v, angle, mu): + # r = parking orbit radius + # v = ejection velocity + # angle = phase angle (from function phaseAngle()) + # mu = gravity param of current body. + epsilon = ((v**2)/2) - (mu / r) + h = r * v * math.sin(angle) + e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2))) + theta = math.acos(1.0 / e) + degrees = theta * (180.0 / math.pi) + return 180 - degrees + */ + double epsilon, h, ee, theta, degrees; + epsilon = ((v * v) / 2) - (mu / r); + h = r * v * Math.Sin(angle); + ee = Math.Sqrt(1 + ((2 * epsilon * (h * h)) / (mu * mu))); + theta = Math.Acos(1.0 / ee); + degrees = theta * (180.0 / Math.PI); + return 180 - degrees; + // returns the ejection angle + } + + public static double Adammada_CurrrentPhaseAngle( + double body_LAN, + double body_orbitPct, + double origin_LAN, + double origin_orbitPct + ) + { + double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct); + if (angle > 1) + angle = angle - 1; + if (angle < 0) + angle = angle + 1; + if (angle > 0.5) + angle = angle - 1; + angle = angle * 360; + return angle; + } + + public static double Adammada_CurrentEjectionAngle( + double vessel_long, + double origin_rotAngle, + double origin_LAN, + double origin_orbitPct + ) + { + //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); + + while (eangle < 0) + eangle = eangle + 360; + while (eangle > 360) + eangle = eangle - 360; + if (eangle < 270) + eangle = 90 - eangle; + else + eangle = 450 - eangle; + return eangle; + } + + public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body + { + Vector3 vecthis = new Vector3(); + Vector3 vectarget = new Vector3(); + vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); + + if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun")) + { + vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); + } + else + { + vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); + } + + vecthis = Vector3.Project(new Vector3(vecthis.x, 0, vecthis.z), vecthis); + vectarget = Vector3.Project(new Vector3(vectarget.x, 0, vectarget.z), vectarget); + + Vector3 prograde = new Vector3(); + prograde = Quaternion.AngleAxis(90, Vector3.forward) * vecthis; + + double phase = Vector3.Angle(vecthis, vectarget); + + if (Vector3.Angle(prograde, vectarget) > 90) + phase = 360 - phase; + + return (phase + 360) % 360; + } + + public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase) + { + if (transfer_angle < 0) + { + if (curr_phase > 0) + return (-1 * (360 - curr_phase)); + else if (curr_phase < 0) + return curr_phase; + } + else if (transfer_angle > 0) + { + if (curr_phase > 0) + return curr_phase; + else if (curr_phase < 0) + return (360 + curr_phase); + } + return curr_phase; + } + + 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 + // need 0-360 instead + // + // ie i have -17 in the screenshot + // need it to show 343 + // + // do this + // + // if < 0, add curr to 360 // 360 + (-17) = 343 + // else its good as it is + + if (curr_ejection < 0) + return 360 + curr_ejection; + else + return curr_ejection; + + } + + public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase) + { + // if transfer_phase_angle < 0 its a lower transfer + //180 + curr_ejection + // else if transfer_phase_angle > 0 its good as it is + + if (trans_phase < 0) + return 180 + trans_ejection; + else + return trans_ejection; + + } + + public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel) + { + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Phase angle (curr/trans):"); + GUILayout.Label( + VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + VOID_Tools.Nivvy_CalcTransferPhaseAngle( + vessel.orbit.semiMajorAxis, + body.orbit.semiMajorAxis, + vessel.mainBody.gravParameter + ).ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Transfer velocity:"); + GUILayout.Label( + (VOID_Tools.Younata_DeltaVToGetToOtherBody( + (vessel.mainBody.gravParameter / 1000000000), + (vessel.orbit.semiMajorAxis / 1000), + (body.orbit.semiMajorAxis / 1000) + ) * 1000).ToString("F2") + "m/s", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + } + + public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel) + { + double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( + (vessel.mainBody.referenceBody.gravParameter / 1000000000), + (vessel.mainBody.orbit.semiMajorAxis / 1000), + (body.orbit.semiMajorAxis / 1000) + ); + double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( + (vessel.mainBody.gravParameter / 1000000000), + (vessel.orbit.semiMajorAxis / 1000), + (vessel.mainBody.sphereOfInfluence / 1000), + Math.Abs(dv1) + ); + + double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( + (vessel.orbit.semiMajorAxis / 1000), + dv2, + (Math.PI / 2.0), + (vessel.mainBody.gravParameter / 1000000000) + ); + double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( + FlightGlobals.ActiveVessel.longitude, + FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent + ); + + double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( + vessel.mainBody.orbit.semiMajorAxis, + body.orbit.semiMajorAxis, + vessel.mainBody.referenceBody.gravParameter + ) % 360; + double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( + body.orbit.LAN, + body.orbit.orbitPercent, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent + ); + + 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_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Phase angle (curr/trans):"); + GUILayout.Label( + adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Ejection angle (curr/trans):"); + GUILayout.Label( + adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Transfer velocity:"); + GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + } + + public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel) + { + double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( + (vessel.mainBody.gravParameter / 1000000000), + (vessel.orbit.semiMajorAxis / 1000), + (body.orbit.semiMajorAxis / 1000) + ); + + double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( + vessel.orbit.semiMajorAxis, + body.orbit.semiMajorAxis, + vessel.mainBody.gravParameter + ); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Phase angle (curr/trans):"); + GUILayout.Label( + VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Transfer velocity:"); + GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + } + + public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel) + { + double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( + (vessel.mainBody.referenceBody.gravParameter / 1000000000), + (vessel.mainBody.orbit.semiMajorAxis / 1000), + (body.orbit.semiMajorAxis / 1000) + ); + double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( + (vessel.mainBody.gravParameter / 1000000000), + (vessel.orbit.semiMajorAxis / 1000), + (vessel.mainBody.sphereOfInfluence / 1000), + Math.Abs(dv1) + ); + double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( + (vessel.orbit.semiMajorAxis / 1000), + dv2, + (Math.PI / 2.0), + (vessel.mainBody.gravParameter / 1000000000) + ); + + double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( + body.orbit.LAN, + body.orbit.orbitPercent, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent + ); + double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( + FlightGlobals.ActiveVessel.longitude, + FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, + FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent + ); + + double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( + vessel.mainBody.orbit.semiMajorAxis, + body.orbit.semiMajorAxis, + vessel.mainBody.referenceBody.gravParameter + ) % 360; + + double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); + //double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle); + + //new stuff + // + 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); + // + // + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Phase angle (curr/trans):"); + GUILayout.Label( + adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Ejection angle (curr/trans):"); + GUILayout.Label( + adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", + GUILayout.ExpandWidth(false) + ); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label("Transfer velocity:"); + GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + } + + public static string get_heading_text(double heading) + { + if (heading > 348.75 || heading <= 11.25) + return "N"; + else if (heading > 11.25 && heading <= 33.75) + return "NNE"; + else if (heading > 33.75 && heading <= 56.25) + return "NE"; + else if (heading > 56.25 && heading <= 78.75) + return "ENE"; + else if (heading > 78.75 && heading <= 101.25) + return "E"; + else if (heading > 101.25 && heading <= 123.75) + return "ESE"; + else if (heading > 123.75 && heading <= 146.25) + return "SE"; + else if (heading > 146.25 && heading <= 168.75) + return "SSE"; + else if (heading > 168.75 && heading <= 191.25) + return "S"; + else if (heading > 191.25 && heading <= 213.75) + return "SSW"; + else if (heading > 213.75 && heading <= 236.25) + return "SW"; + else if (heading > 236.25 && heading <= 258.75) + return "WSW"; + else if (heading > 258.75 && heading <= 281.25) + return "W"; + else if (heading > 281.25 && heading <= 303.75) + return "WNW"; + else if (heading > 303.75 && heading <= 326.25) + return "NW"; + else if (heading > 326.25 && heading <= 348.75) + return "NNW"; + else + return ""; + } + } + + public class CBListComparer : IComparer + { + public int Compare(CelestialBody bodyA, CelestialBody bodyB) + { + Logging.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB); + + if (bodyA == null && bodyB == null) + { + Logging.PostDebugMessage(this, "both bodies are null, returning 0"); + return 0; + } + if (bodyA == null) + { + Logging.PostDebugMessage(this, "bodyA is null, returning -1"); + return -1; + } + if (bodyB == null) + { + Logging.PostDebugMessage(this, "bodyB is null, returning 1"); + return 1; + } + + Logging.PostDebugMessage(this, "bodies are not null, carrying on"); + + if (object.ReferenceEquals(bodyA, bodyB)) + { + Logging.PostDebugMessage(this, "bodies are equal, returning 0"); + return 0; + } + + Logging.PostDebugMessage(this, "bodies are not equal, carrying on"); + + if (bodyA.orbitDriver == null) + { + Logging.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1"); + return 1; + } + if (bodyB.orbitDriver == null) + { + Logging.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1"); + return -1; + } + + Logging.PostDebugMessage(this, "orbits are not null, carrying on"); + + if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody) + { + Logging.PostDebugMessage(this, "bodies share a parent, comparing SMAs"); + return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis); + } + + Logging.PostDebugMessage(this, "orbits do not share a parent, carrying on"); + + if (bodyA.hasAncestor(bodyB)) + { + Logging.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1"); + return -1; + } + if (bodyB.hasAncestor(bodyA)) + { + Logging.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1"); + return 1; + } + + Logging.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one"); + + if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB)) + { + Logging.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName); + return this.Compare(bodyA, bodyB); + } + + Logging.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName); + + return 0; + } + } +} + --- a/VOID.csproj +++ b/VOID.csproj @@ -26,7 +26,7 @@ false - + @@ -39,7 +39,7 @@ TRACE - + @@ -54,7 +54,7 @@ false - + @@ -67,18 +67,13 @@ false - + - - - - - @@ -87,15 +82,40 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -116,6 +136,15 @@ ..\_KSPAssemblies\UnityEngine.dll + + ..\_KSPAssemblies\KSPUtil.dll + + + ..\_KSPAssemblies\UnityEngine.UI.dll + + + ..\_KSPAssemblies\Assembly-CSharp-firstpass.dll + @@ -127,5 +156,13 @@ VesselSimulator + + + + + + + + --- /dev/null +++ b/VOIDCore_Editor.cs @@ -1,1 +1,53 @@ +// VOID +// +// VOID_EditorCore.cs +// +// Copyright © 2014, 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 KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VOID +{ + [VOID_Scenes(GameScenes.EDITOR)] + public class VOIDCore_Editor : VOIDCore_Generic + { + public override string SceneKey + { + get + { + return "EDITOR"; + } + } + + + public override void FixedUpdate() {} + } +} + + --- /dev/null +++ b/VOIDCore_Flight.cs @@ -1,1 +1,60 @@ +// VOID +// +// VOIDCore_Flight.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 UnityEngine; +using ToadicusTools.GUIUtils; + +namespace VOID +{ + [VOID_Scenes(GameScenes.FLIGHT)] + public class VOIDCore_Flight : VOIDCore_Generic + { + public override string SceneKey + { + get + { + return "FLIGHT"; + } + } + + + public override void DrawConfigurables() + { + if (HighLogic.LoadedSceneIsFlight) + { + this.consumeResource.value = Layout.Toggle(this.consumeResource, "Consume Resources"); + } + + base.DrawConfigurables(); + } + } +} + + --- /dev/null +++ b/VOIDCore_Generic.cs @@ -1,1 +1,1224 @@ - +// VOID +// +// VOIDCore_Generic.cs +// +// Copyright © 2014, 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 KerbalEngineer.Editor; +using KerbalEngineer.Helpers; +using KerbalEngineer.VesselSimulator; +using KSP; +using KSP.UI.Screens; +using System; +using System.Collections.Generic; +using System.Text; +using ToadicusTools; +using ToadicusTools.DebugTools; +using ToadicusTools.Extensions; +using ToadicusTools.GUIUtils; +using ToadicusTools.Wrappers; +using UnityEngine; + +namespace VOID +{ + public abstract class VOIDCore_Generic : VOID_SingletonCore, IVOID_Module, IDisposable + where T : VOID_Module, new() + { + /* + * Fields + * */ + protected string VoidName = "VOID"; + protected string VoidVersion; + + [AVOID_SaveValue("configValue")] + protected VOID_SaveValue configVersion = (VOID_SaveValue)VOIDCore.CONFIG_VERSION; + + protected List modules = new List(); + protected bool modulesLoaded = false; + + protected Texture2D VOIDIconTexture; + protected string VOIDIconOnActivePath; + protected string VOIDIconOnInactivePath; + protected string VOIDIconOffActivePath; + protected string VOIDIconOffInactivePath; + + [AVOID_SaveValue("useToolbarManager")] + protected VOID_SaveValue useToolbarManager; + + protected GUIStyle iconStyle; + + protected int windowBaseID = -96518722; + protected int windowID = 0; + + protected bool GUIStylesLoaded = false; + + protected CelestialBody homeBody; + + [AVOID_SaveValue("togglePower")] + public VOID_SaveValue togglePower = (VOID_SaveValue)true; + + public override bool powerAvailable { get; protected set; } + + [AVOID_SaveValue("consumeResource")] + protected VOID_SaveValue consumeResource = (VOID_SaveValue)false; + + [AVOID_SaveValue("resourceName")] + protected VOID_SaveValue resourceName = (VOID_SaveValue)"ElectricCharge"; + + [AVOID_SaveValue("resourceRate")] + protected VOID_SaveValue resourceRate = (VOID_SaveValue)0.2f; + + [AVOID_SaveValue("updatePeriod")] + protected VOID_SaveValue updatePeriod = (VOID_SaveValue)(1001f / 15000f); + protected string stringFrequency; + + [AVOID_SaveValue("vesselSimActive")] + protected VOID_SaveValue vesselSimActive; + + [AVOID_SaveValue("timeScaleFlags")] + protected VOID_SaveValue timeScaleFlags; + + // Load-up housekeeping + protected bool vesselTypesLoaded = false; + protected bool simManagerLoaded = false; + + protected string defaultSkin = "KSP window 2"; + + [AVOID_SaveValue("defaultSkin")] + protected VOID_SaveValue skinName; + protected int skinIdx; + + protected Dictionary validSkins; + protected List skinNames; + protected string[] forbiddenSkins = + { + "PlaqueDialogSkin", + "FlagBrowserSkin", + "SSUITextAreaDefault", + "ExperimentsDialogSkin", + "ExpRecoveryDialogSkin", + "KSP window 1", + "KSP window 3", + "KSP window 5", + "KSP window 6", + "PartTooltipSkin", + "KSCContextMenuSkin" + }; + protected bool skinsLoaded = false; + + public override bool configDirty { get; set; } + + protected IButton ToolbarButton; + protected ApplicationLauncherButton AppLauncherButton; + protected IconState iconState; + + /* + * Properties + * */ + public override bool Active + { + get + { + return base.Active; + } + set + { + if (value != base.Active) + { + this.SetIconTexture(this.powerState | this.activeState); + } + + base.Active = value; + } + } + + public override VesselType[] AllVesselTypes + { + get; + protected set; + } + + public override int ConfigVersion + { + get + { + return this.configVersion; + } + } + + public bool FactoryReset + { + get; + protected set; + } + + public override CelestialBody HomeBody + { + get + { + if (this.homeBody == null) + { + if (Planetarium.fetch != null) + { + this.homeBody = Planetarium.fetch.Home; + } + } + + return this.homeBody; + } + } + + public override IList Modules + { + get + { + return this.modules.AsReadOnly(); + } + } + + public override GUISkin Skin + { + get + { + if (this.skinsLoaded) + { + try + { + return this.validSkins[this.skinName]; + } + catch + { + } + } + + return AssetBase.GetGUISkin(this.defaultSkin); + } + } + + public override List SortedBodyList + { + get; + protected set; + } + + public override double UpdatePeriod + { + get + { + return this.updatePeriod; + } + } + + public override float UpdateTimer + { + get; + protected set; + } + + public override int WindowID + { + get + { + if (this.windowID == 0) + { + this.windowID = this.windowBaseID; + } + return this.windowID++; + } + } + + public override Stage[] Stages + { + get; + protected set; + } + + public override Stage LastStage + { + get; + protected set; + } + + public override VOID_TimeScale TimeScale + { + get + { + return (VOID_TimeScale)this.timeScaleFlags.value; + } + protected set + { + this.timeScaleFlags.value = (UInt32)value; + } + } + + protected IconState activeState + { + get + { + if (this.Active) + { + return IconState.Inactive; + } + else + { + return IconState.Active; + } + + } + } + + protected IconState powerState + { + get + { + if (this.togglePower && this.powerAvailable) + { + return IconState.PowerOn; + } + else + { + return IconState.PowerOff; + } + + } + } + + protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes + { + get + { + return HighLogic.LoadedScene.ToAppScenes(); + } + } + + /* + * Events + * */ + // public + public override event VOIDEventHandler onApplicationQuit; + public override event VOIDEventHandler onSkinChanged; + public override event VOIDEventHandler onUpdate; + + /* + * Methods + * */ + public override void DrawGUI(object sender) + { + this.windowID = this.windowBaseID; + + if (!this.modulesLoaded) + { + this.LoadModulesOfType(); + } + + if (!this.skinsLoaded) + { + this.LoadSkins(); + } + + GUI.skin = this.Skin; + + if (!this.GUIStylesLoaded) + { + this.LoadGUIStyles(); + + Logging.PostDebugMessage( + this, + "ToolbarAvailable: {0}, UseToobarManager: {1}", + ToolbarManager.ToolbarAvailable, + this.useToolbarManager); + } + + if ( + this.iconState != (this.powerState | this.activeState) || + (this.VOIDIconTexture == null && this.AppLauncherButton != null) + ) + { + this.iconState = this.powerState | this.activeState; + + this.SetIconTexture(this.iconState); + } + + if (this.Active) + { + base.DrawGUI(sender); + } + } + + public virtual void Update() + { + this.LoadBeforeUpdate(); + + if ( + this.vesselSimActive && + ( + this.Vessel != null || + ( + HighLogic.LoadedSceneIsEditor && + EditorLogic.RootPart != null && + EditorLogic.SortedShipList.Count > 0 + ) + ) + ) + { + Logging.PostDebugMessage(this, "Updating SimManager."); + this.UpdateSimManager(); + } + + if (!this.GUIRunning) + { + this.StartGUI(); + } + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + if ( + !module.GUIRunning && + module.Active && + module.InValidScene && + ( + !HighLogic.LoadedSceneIsEditor || + (EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0) + ) + ) + { + module.StartGUI(); + } + if ( + module.GUIRunning && + ( + !module.Active || + !this.togglePower || + !module.InValidScene || + this.FactoryReset || + ( + HighLogic.LoadedSceneIsEditor && + (EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0) + ) + ) + ) + { + module.StopGUI(); + } + + if (module is IVOID_BehaviorModule) + { + ((IVOID_BehaviorModule)module).Update(); + } + } + + if (this.useToolbarManager) + { + if (this.AppLauncherButton != null) + { + ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); + this.AppLauncherButton = null; + } + + if (this.ToolbarButton == null) + { + this.InitializeToolbarButton(); + } + } + else + { + if (this.ToolbarButton != null) + { + this.ToolbarButton.Destroy(); + this.ToolbarButton = null; + } + + if (this.AppLauncherButton == null) + { + this.InitializeAppLauncherButton(); + } + + } + + this.saveTimer += Time.deltaTime; + + if (this.modulesLoaded && this.saveTimer > 2f) + { + if (this.configDirty) + { + + Logging.PostDebugMessage(string.Format( + "{0}: Time to save, checking if configDirty: {1}", + this.GetType().Name, + this.configDirty + )); + + this.SaveConfig(); + this.saveTimer = 0; + } + } + + this.UpdateTimer += Time.deltaTime; + + if (this.onUpdate != null) + { + this.onUpdate(this); + } + } + + public virtual void FixedUpdate() + { + bool newPowerState = this.powerAvailable; + + if (this.togglePower && this.consumeResource && + this.Vessel.vesselType != VesselType.EVA && + TimeWarp.deltaTime != 0) + { + float powerReceived = this.Vessel.rootPart.RequestResource( + this.resourceName, + this.resourceRate * TimeWarp.fixedDeltaTime + ); + + if (powerReceived > 0) + { + newPowerState = true; + } + else + { + newPowerState = false; + } + + if (this.powerAvailable != newPowerState) + { + this.powerAvailable = newPowerState; + } + } + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + if (module is IVOID_BehaviorModule) + { + ((IVOID_BehaviorModule)module).FixedUpdate(); + } + } + } + + public void OnDestroy() + { + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + if (module is IVOID_BehaviorModule) + { + ((IVOID_BehaviorModule)module).OnDestroy(); + } + } + + this.Dispose(); + } + + public virtual void OnApplicationQuit() + { + if (this.onApplicationQuit != null) + { + this.onApplicationQuit(this); + } + + this.OnDestroy(); + } + + public override void StartGUI() + { + if (!this.GUIRunning) + { + // RenderingManager.AddToPostDrawQueue(3, this.DrawGUI); + Logging.PostDebugMessage(this, "Adding DrawGUI to onGui"); + this.onPostRender += this.DrawGUI; + } + } + + public void ResetGUI() + { + this.StopGUI(); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.StopGUI(); + module.StartGUI(); + } + + this.StartGUI(); + } + + public override void ModuleWindow(int id) + { + GUILayout.BeginVertical(); + + if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight) + { + if (!HighLogic.LoadedSceneIsEditor) + { + string str = string.Intern("ON"); + if (togglePower) + str = string.Intern("OFF"); + if (GUILayout.Button("Power " + str)) + { + togglePower.value = !togglePower; + } + } + + if (togglePower || !HighLogic.LoadedSceneIsFlight) + { + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + if (module is VOID_ConfigWindow) + { + continue; + } + + module.Active = Layout.Toggle(module.Active, module.Name); + } + } + } + else + { + GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed); + } + + VOID_ConfigWindow.Instance.Active = Layout.Toggle( + VOID_ConfigWindow.Instance.Active, + "Configuration" + ); + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + + public override void DrawConfigurables() + { + GUIContent _content; + + this.useToolbarManager.value = Layout.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available"); + + this.vesselSimActive.value = Layout.Toggle(this.vesselSimActive.value, + "Enable Engineering Calculations"); + + bool useEarthTime = (this.TimeScale & VOID_TimeScale.KERBIN_TIME) == 0u; + bool useSiderealTime = (this.TimeScale & VOID_TimeScale.SOLAR_DAY) == 0u; + bool useRoundedScale = (this.TimeScale & VOID_TimeScale.ROUNDED_SCALE) != 0u; + + useEarthTime = Layout.Toggle(useEarthTime, "Use Earth Time (changes KSP option)"); + + GameSettings.KERBIN_TIME = !useEarthTime; + + useSiderealTime = Layout.Toggle( + useSiderealTime, + string.Format( + "Time Scale: {0}", + useSiderealTime ? "Sidereal" : "Solar" + ) + ); + + useRoundedScale = Layout.Toggle( + useRoundedScale, + string.Format( + "Time Scale: {0}", + useRoundedScale ? "Rounded" : "True" + ) + ); + + if (useEarthTime) + { + this.TimeScale &= ~VOID_TimeScale.KERBIN_TIME; + } + else + { + this.TimeScale |= VOID_TimeScale.KERBIN_TIME; + } + + if (useSiderealTime) + { + this.TimeScale &= ~VOID_TimeScale.SOLAR_DAY; + } + else + { + this.TimeScale |= VOID_TimeScale.SOLAR_DAY; + } + + if (useRoundedScale) + { + this.TimeScale |= VOID_TimeScale.ROUNDED_SCALE; + } + else + { + this.TimeScale &= ~VOID_TimeScale.ROUNDED_SCALE; + } + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); + + _content = new GUIContent(); + + _content.text = "◄"; + _content.tooltip = "Select previous skin"; + if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) + { + this.skinIdx--; + Logging.PostDebugMessage(string.Format( + "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}", + this.GetType().Name, + this.skinName, + this.validSkins.Count + )); + } + + _content.text = this.Skin.name; + _content.tooltip = "Current skin"; + GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true)); + + _content.text = "►"; + _content.tooltip = "Select next skin"; + if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) + { + this.skinIdx++; + Logging.PostDebugMessage(string.Format( + "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}", + this.GetType().Name, + this.skinName, + this.validSkins.Count + )); + } + + this.skinIdx %= this.skinNames.Count; + if (this.skinIdx < 0) + { + this.skinIdx += this.skinNames.Count; + } + + if (this.skinName != skinNames[this.skinIdx]) + { + this.skinName.value = skinNames[this.skinIdx]; + this.GUIStylesLoaded = false; + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Update Rate (Hz):"); + if (this.stringFrequency == null) + { + this.stringFrequency = (1f / this.UpdatePeriod).ToString(); + } + this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true)); + + if (GUILayout.Button("Apply")) + { + double updateFreq = 1f / this.UpdatePeriod; + double.TryParse(stringFrequency, out updateFreq); + this.updatePeriod.value = 1 / updateFreq; + } + GUILayout.EndHorizontal(); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.DrawConfigurables(); + } + + this.FactoryReset = Layout.Toggle(this.FactoryReset, "Factory Reset"); + } + + protected void UpdateSimManager() + { + if (HighLogic.LoadedSceneIsFlight) + { + double radius = this.Vessel.Radius(); + SimManager.Gravity = this.Vessel.mainBody.gravParameter / (radius * radius); + SimManager.Atmosphere = this.Vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres; + SimManager.Mach = this.Vessel.mach; + BuildAdvanced.Altitude = this.Vessel.altitude; + CelestialBodies.SelectedBody = this.Vessel.mainBody; + } + + #if DEBUG + SimManager.logOutput = true; + #endif + + SimManager.TryStartSimulation(); + + Logging.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²", + SimManager.Atmosphere, + SimManager.Gravity + ); + } + + protected void GetSimManagerResults() + { + Logging.PostDebugMessage(this, "VesselSimulator results ready, setting Stages."); + + this.Stages = SimManager.Stages; + + if (this.Stages != null && this.Stages.Length > 0) + { + this.LastStage = this.Stages[this.Stages.Length - 1]; + } + } + + protected void LoadModulesOfType() + { + using (PooledDebugLogger sb = PooledDebugLogger.New(this)) + { + sb.AppendLine("Loading modules..."); + + AssemblyLoader.LoadedAssembly assy; + for (int aIdx = 0; aIdx < AssemblyLoader.loadedAssemblies.Count; aIdx++) + { + assy = AssemblyLoader.loadedAssemblies[aIdx]; + + Type[] loadedTypes = assy.assembly.GetExportedTypes(); + Type loadedType; + for (int tIdx = 0; tIdx < loadedTypes.Length; tIdx++) + { + loadedType = loadedTypes[tIdx]; + + if ( + loadedType.IsInterface || + loadedType.IsAbstract || + !typeof(U).IsAssignableFrom(loadedType) || + typeof(VOIDCore).IsAssignableFrom(loadedType)) + { + continue; + } + + sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name); + + try + { + this.LoadModule(loadedType); + sb.AppendLine("Success."); + } + catch (Exception ex) + { + sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name); + + #if DEBUG + Debug.LogException(ex); + #endif + } + } + } + + this.LoadConfig(); + + this.modulesLoaded = true; + + sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count); + + sb.Print(); + } + } + + protected void LoadModule(Type T) + { + /*var existingModules = this.modules.Where(mod => mod.GetType().Name == T.Name); + if (existingModules.Any())*/ + for (int mIdx = 0; mIdx < this.modules.Count; mIdx++) + { + if (this.modules[mIdx].Name == T.Name) + { + Logging.PostErrorMessage("{0}: refusing to load {1}: already loaded", this.GetType().Name, T.Name); + return; + } + } + + var InstanceProperty = T.GetProperty( + "Instance", + System.Reflection.BindingFlags.Static | + System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.FlattenHierarchy + ); + + object modInstance = null; + IVOID_Module module; + + if (InstanceProperty != null) + { + modInstance = InstanceProperty.GetValue(null, null); + } + + if (modInstance != null) + { + module = modInstance as IVOID_Module; + } + else + { + module = Activator.CreateInstance(T) as IVOID_Module; + } + + if (module.InValidGame && module.InValidScene) + { + this.modules.Add(module); + + Logging.PostDebugMessage(string.Format( + "{0}: loaded module {1}.", + this.GetType().Name, + T.Name + )); + } + else + { + if (module is IDisposable) + { + (module as IDisposable).Dispose(); + } + } + } + + protected void LoadSkins() + { + this.validSkins = new Dictionary(); + this.skinNames = new List(); + + UnityEngine.Object[] skins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)); + GUISkin skin; + for (int sIdx = 0; sIdx < skins.Length; sIdx++) + { + skin = (GUISkin)skins[sIdx]; + + if (!this.forbiddenSkins.Contains(skin.name)) + { + this.validSkins[skin.name] = skin; + this.skinNames.Add(skin.name); + } + } + + Logging.PostDebugMessage(string.Format( + "{0}: loaded {1} GUISkins.", + this.GetType().Name, + this.validSkins.Count + )); + + this.skinNames.Sort(); + + int defaultIdx = int.MinValue; + + for (int i = 0; i < this.skinNames.Count; i++) + { + if (this.skinNames[i] == this.skinName) + { + this.skinIdx = i; + } + if (this.skinNames[i] == this.defaultSkin) + { + defaultIdx = i; + } + if (this.skinIdx != int.MinValue && defaultIdx != int.MinValue) + { + break; + } + } + + if (this.skinIdx == int.MinValue) + { + this.skinIdx = defaultIdx; + } + + Logging.PostDebugMessage(string.Format( + "{0}: _skinIdx = {1}.", + this.GetType().Name, + this.skinName.ToString() + )); + + this.skinsLoaded = true; + } + + protected void LoadGUIStyles() + { + VOID_Styles.OnSkinChanged(); + + if (this.onSkinChanged != null) + { + this.onSkinChanged(this); + } + + this.GUIStylesLoaded = true; + } + + protected void LoadBeforeUpdate() + { + if (!this.vesselTypesLoaded) + { + Array typeObjs = Enum.GetValues(typeof(VesselType)); + this.AllVesselTypes = new VesselType[typeObjs.Length]; + + for (int idx = 0; idx < typeObjs.Length; idx++) + { + this.AllVesselTypes[idx] = (VesselType)typeObjs.GetValue(idx); + } + + this.vesselTypesLoaded = true; + } + + if (this.SortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0) + { + this.SortedBodyList = new List(FlightGlobals.Bodies); + this.SortedBodyList.Sort(new CBListComparer()); + this.SortedBodyList.Reverse(); + } + + // SimManager initialization that we don't necessarily want to repeat every Update. + if (!this.simManagerLoaded && this.HomeBody != null) + { + SimManager.Gravity = VOID_Data.KerbinGee; + SimManager.Atmosphere = 0d; + SimManager.Mach = 1d; + CelestialBodies.SelectedBody = this.HomeBody; + BuildAdvanced.Altitude = 0d; + SimManager.OnReady += this.GetSimManagerResults; + + this.simManagerLoaded = true; + } + } + + protected void InitializeToolbarButton() + { + // Do nothing if (the Toolbar is not available. + if (!ToolbarManager.ToolbarAvailable) + { + Logging.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false"); + return; + } + + this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); + this.ToolbarButton.Text = this.VoidName; + this.SetIconTexture(this.powerState | this.activeState); + + this.ToolbarButton.Visible = true; + + this.ToolbarButton.OnClick += + (e) => + { + this.ToggleMainWindow(); + }; + + Logging.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); + } + + protected void InitializeAppLauncherButton() + { + if (ApplicationLauncher.Ready) + { + this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( + this.ToggleMainWindow, this.ToggleMainWindow, + this.appIconVisibleScenes, + this.VOIDIconTexture + ); + + Logging.PostDebugMessage( + this, + "AppLauncherButton initialized in {0}", + Enum.GetName( + typeof(GameScenes), + HighLogic.LoadedScene + ) + ); + } + } + + protected void ToggleMainWindow() + { + this.Active = !this.Active; + } + + protected void SetIconTexture(IconState state) + { + switch (state) + { + case (IconState.PowerOff | IconState.Inactive): + this.SetIconTexture(this.VOIDIconOffInactivePath); + break; + case (IconState.PowerOff | IconState.Active): + this.SetIconTexture(this.VOIDIconOffActivePath); + break; + case (IconState.PowerOn | IconState.Inactive): + this.SetIconTexture(this.VOIDIconOnInactivePath); + break; + case (IconState.PowerOn | IconState.Active): + this.SetIconTexture(this.VOIDIconOnActivePath); + break; + default: + throw new NotImplementedException(); + } + } + + protected void SetIconTexture(string texturePath) + { + if (texturePath == null) + { + return; + } + + if (this.ToolbarButton != null) + { + this.ToolbarButton.TexturePath = texturePath; + } + + if (this.AppLauncherButton != null) + { + this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false); + + this.AppLauncherButton.SetTexture(VOIDIconTexture); + } + } + + public void LoadConfig() + { + + if (!System.IO.File.Exists(this.VOIDSettingsPath) && KSP.IO.File.Exists("config.xml")) + { + Logging.PostLogMessage( + "VOID: No per-save config file but old file detected; copying from old file." + ); + + System.IO.File.Copy( + KSP.IO.IOUtils.GetFilePathFor(typeof(VOID_Module), "config.xml"), + this.VOIDSettingsPath + ); + } + + this.LoadConfig(new PluginConfiguration(this.VOIDSettingsPath)); + } + + public override void LoadConfig(KSP.IO.PluginConfiguration config) + { + base.LoadConfig(config); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.LoadConfig(config); + } + + this.TimeScale |= GameSettings.KERBIN_TIME ? VOID_TimeScale.KERBIN_TIME : 0u; + } + + public override void SaveConfig() + { + if (this.configNeedsUpdate && this is VOIDCore_Flight) + { + KSP.IO.File.Delete("config.xml"); + System.IO.File.Delete(this.VOIDSettingsPath); + } + + KSP.IO.PluginConfiguration config = new PluginConfiguration(this.VOIDSettingsPath); + + config.load(); + + this.Save(config, this.SceneKey); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.Save(config, this.SceneKey); + } + + config.save(); + + this.configDirty = false; + } + + public VOIDCore_Generic() + { + System.Version version = this.GetType().Assembly.GetName().Version; + + 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.Active = true; + + this.skinName = (VOID_SaveValue)this.defaultSkin; + this.skinIdx = int.MinValue; + + this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow"; + this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow"; + this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light"; + this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark"; + + this.saveTimer = 0f; + this.UpdateTimer = 0f; + + this.vesselSimActive = (VOID_SaveValue)true; + + this.useToolbarManager = (VOID_SaveValue)ToolbarManager.ToolbarAvailable; + + this.SaveGamePath = string.Format("{0}saves/{1}", IOTools.KSPRootPath, HighLogic.SaveFolder); + this.VOIDSettingsPath = string.Format("{0}/VOIDConfig.xml", this.SaveGamePath); + + this.FactoryReset = false; + } + + public override void Dispose() + { + this.StopGUI(); + + this.onSkinChanged(this); + + if (this.AppLauncherButton != null) + { + ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); + this.AppLauncherButton = null; + } + if (this.ToolbarButton != null) + { + this.ToolbarButton.Destroy(); + this.ToolbarButton = null; + } + + _instance = null; + _initialized = false; + } + } +} + --- /dev/null +++ b/VOIDCore_SpaceCentre.cs @@ -1,1 +1,47 @@ +// VOID +// +// VOIDCore_SpaceCentre.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 System; +namespace VOID +{ + [VOID_Scenes(GameScenes.SPACECENTER)] + public class VOIDCore_SpaceCentre : VOIDCore_Generic + { + public override string SceneKey + { + get + { + return "SPACECENTER"; + } + } + + public override void FixedUpdate() {} + } +} + + --- a/VOIDEditorMaster.cs +++ /dev/null @@ -1,110 +1,1 @@ -// VOID -// -// VOIDEditorMaster.cs -// -// Copyright © 2014, 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. -// -/////////////////////////////////////////////////////////////////////////////// -// -// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors -// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some -// invaluable functions and making your nicely written code available to learn from. -// -/////////////////////////////////////////////////////////////////////////////// -// -// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. -// Engineer Redux (c) 2013 cybutek -// Used by permission. -// -/////////////////////////////////////////////////////////////////////////////// -using Engineer.VesselSimulator; -using KSP; -using System; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - [KSPAddon(KSPAddon.Startup.EditorAny, false)] - public class VOIDEditorMaster : MonoBehaviour - { - protected VOID_EditorCore Core; - - public void Awake() - { - Tools.PostDebugMessage ("VOIDEditorMaster: Waking up."); - this.Core = VOID_EditorCore.Instance; - this.Core.ResetGUI (); - Tools.PostDebugMessage ("VOIDEditorMaster: Awake."); - } - - public void Update() - { - if (!HighLogic.LoadedSceneIsEditor && this.Core != null) - { - this.Core.SaveConfig (); - this.Core = null; - VOID_EditorCore.Reset(); - return; - } - - if (this.Core == null) - { - this.Awake(); - } - - this.Core.Update (); - - if (this.Core.factoryReset) - { - KSP.IO.File.Delete("config.xml"); - this.Core = null; - VOID_EditorCore.Reset(); - } - } - - public void FixedUpdate() - { - if (this.Core == null || !HighLogic.LoadedSceneIsEditor) - { - return; - } - - this.Core.FixedUpdate (); - } - - public void OnGUI() - { - if (this.Core == null) - { - return; - } - - this.Core.OnGUI(); - } - } -} - --- a/VOIDFlightMaster.cs +++ /dev/null @@ -1,109 +1,1 @@ -// VOID -// -// VOIDFlightMaster.cs -// -// Copyright © 2014, 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. -// -/////////////////////////////////////////////////////////////////////////////// -// -// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors -// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some -// invaluable functions and making your nicely written code available to learn from. -// -/////////////////////////////////////////////////////////////////////////////// -// -// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. -// Engineer Redux (c) 2013 cybutek -// Used by permission. -// -/////////////////////////////////////////////////////////////////////////////// -using System; -using UnityEngine; -using Engineer.VesselSimulator; -using ToadicusTools; - -namespace VOID -{ - [KSPAddon(KSPAddon.Startup.Flight, false)] - public class VOIDFlightMaster : MonoBehaviour - { - protected VOID_Core Core; - - public void Awake() - { - Tools.PostDebugMessage ("VOIDFlightMaster: Waking up."); - this.Core = (VOID_Core)VOID_Core.Instance; - this.Core.ResetGUI (); - Tools.PostDebugMessage ("VOIDFlightMaster: Awake."); - } - - public void Update() - { - if (!HighLogic.LoadedSceneIsFlight && this.Core != null) - { - this.Core.SaveConfig (); - this.Core = null; - VOID_Core.Reset(); - return; - } - - if (this.Core == null) - { - this.Awake(); - } - - this.Core.Update (); - - if (this.Core.factoryReset) - { - KSP.IO.File.Delete("config.xml"); - this.Core = null; - VOID_Core.Reset(); - } - } - - public void FixedUpdate() - { - if (this.Core == null || !HighLogic.LoadedSceneIsFlight) - { - return; - } - - this.Core.FixedUpdate (); - } - - public void OnGUI() - { - if (this.Core == null) - { - return; - } - - this.Core.OnGUI(); - } - } -} - --- /dev/null +++ b/VOIDMaster_Editor.cs @@ -1,1 +1,63 @@ +// VOID +// +// VOIDEditorMaster.cs +// +// Copyright © 2014, 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. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors +// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some +// invaluable functions and making your nicely written code available to learn from. +// +/////////////////////////////////////////////////////////////////////////////// +// +// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. +// Engineer Redux (c) 2013 cybutek +// Used by permission. +// +/////////////////////////////////////////////////////////////////////////////// +using KerbalEngineer.VesselSimulator; +using KSP; +using System; +using ToadicusTools.Extensions; +using UnityEngine; + +namespace VOID +{ + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + public class VOIDMaster_Editor : VOIDMaster + { + public override void Awake() + { + this.LogDebug("VOIDEditorMaster: Waking up."); + this.Core = VOIDCore_Editor.Instance; + this.Core.ResetGUI (); + this.LogDebug("VOIDEditorMaster: Awake."); + } + } +} + --- /dev/null +++ b/VOIDMaster_Flight.cs @@ -1,1 +1,62 @@ +// VOID +// +// VOIDFlightMaster.cs +// +// Copyright © 2014, 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. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors +// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some +// invaluable functions and making your nicely written code available to learn from. +// +/////////////////////////////////////////////////////////////////////////////// +// +// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. +// Engineer Redux (c) 2013 cybutek +// Used by permission. +// +/////////////////////////////////////////////////////////////////////////////// +using System; +using UnityEngine; +using KerbalEngineer.VesselSimulator; +using ToadicusTools.Extensions; + +namespace VOID +{ + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class VOIDMaster_Flight : VOIDMaster + { + public override void Awake() + { + this.LogDebug("Waking up."); + this.Core = VOIDCore_Flight.Instance; + this.Core.ResetGUI (); + this.LogDebug("Awake."); + } + } +} + --- /dev/null +++ b/VOIDMaster_SpaceCentre.cs @@ -1,1 +1,62 @@ +// VOID +// +// VOIDFlightMaster.cs +// +// Copyright © 2014, 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. +// +/////////////////////////////////////////////////////////////////////////////// +// +// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors +// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some +// invaluable functions and making your nicely written code available to learn from. +// +/////////////////////////////////////////////////////////////////////////////// +// +// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. +// Engineer Redux (c) 2013 cybutek +// Used by permission. +// +/////////////////////////////////////////////////////////////////////////////// +using System; +using UnityEngine; +using KerbalEngineer.VesselSimulator; +using ToadicusTools.Extensions; + +namespace VOID +{ + [KSPAddon(KSPAddon.Startup.SpaceCentre, false)] + public class VOIDMaster_SpaceCentre : VOIDMaster + { + public override void Awake() + { + this.LogDebug("Waking up."); + this.Core = VOIDCore_SpaceCentre.Instance; + this.Core.ResetGUI (); + this.LogDebug("Awake."); + } + } +} + --- a/VOID_CBInfoBrowser.cs +++ b/VOID_CBInfoBrowser.cs @@ -29,7 +29,7 @@ using KSP; using System; using System.Collections.Generic; -using ToadicusTools; +using ToadicusTools.Text; using UnityEngine; namespace VOID @@ -37,31 +37,47 @@ public class VOID_CBInfoBrowser : VOID_WindowModule { [AVOID_SaveValue("selectedBodyIdx1")] - protected VOID_SaveValue selectedBodyIdx1 = 1; + protected VOID_SaveValue selectedBodyIdx1; [AVOID_SaveValue("selectedBodyIdx2")] - protected VOID_SaveValue selectedBodyIdx2 = 2; + protected VOID_SaveValue selectedBodyIdx2; protected CelestialBody selectedBody1; protected CelestialBody selectedBody2; [AVOID_SaveValue("toggleOrbital")] - protected VOID_SaveValue toggleOrbital = false; + protected VOID_SaveValue toggleOrbital; [AVOID_SaveValue("togglePhysical")] - protected VOID_SaveValue togglePhysical = false; + protected VOID_SaveValue togglePhysical; + + [AVOID_SaveValue("toggleScience")] + protected VOID_SaveValue toggleScience; public VOID_CBInfoBrowser() { - this._Name = "Celestial Body Information Browser"; + this.Name = "Celestial Body Information Browser"; this.WindowPos.x = 10; this.WindowPos.y = 85; + + this.selectedBodyIdx1 = (VOID_SaveValue)1; + this.selectedBodyIdx2 = (VOID_SaveValue)2; + + this.toggleOrbital = (VOID_SaveValue)false; + this.togglePhysical = (VOID_SaveValue)false; + this.toggleScience = (VOID_SaveValue)false; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + if (this.core.SortedBodyList.Count < 1) + { + GUILayout.Label("Non-positive number of CelestialBodies here, bailing out."); + GUILayout.EndHorizontal(); + } GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); @@ -72,20 +88,46 @@ GUILayout.BeginVertical(GUILayout.Width(150)); - selectedBody1 = this.core.allBodies[selectedBodyIdx1]; - selectedBody2 = this.core.allBodies[selectedBodyIdx2]; + if (selectedBodyIdx1 >= this.core.SortedBodyList.Count) + { + selectedBodyIdx1.value %= this.core.SortedBodyList.Count; + } + + if (selectedBodyIdx1 < 0) + { + selectedBodyIdx1.value += this.core.SortedBodyList.Count; + } + + if (selectedBodyIdx2 >= this.core.SortedBodyList.Count) + { + selectedBodyIdx2.value %= this.core.SortedBodyList.Count; + } + + if (selectedBodyIdx2 < 0) + { + selectedBodyIdx2.value += this.core.SortedBodyList.Count; + } + + selectedBody1 = this.core.SortedBodyList[selectedBodyIdx1]; + selectedBody2 = this.core.SortedBodyList[selectedBodyIdx2]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) { - selectedBodyIdx1--; - if (selectedBodyIdx1 < 0) selectedBodyIdx1 = this.core.allBodies.Count - 1; - } - GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + selectedBodyIdx1.value--; + if (selectedBodyIdx1 < 0) + { + selectedBodyIdx1.value = this.core.SortedBodyList.Count - 1; + } + } + GUILayout.Label(this.core.SortedBodyList[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) { - selectedBodyIdx1++; - if (selectedBodyIdx1 > this.core.allBodies.Count - 1) selectedBodyIdx1 = 0; + selectedBodyIdx1.value++; + if (selectedBodyIdx1 > this.core.SortedBodyList.Count - 1) + { + selectedBodyIdx1.value = 0; + } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); @@ -94,14 +136,20 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) { - selectedBodyIdx2--; - if (selectedBodyIdx2 < 0) selectedBodyIdx2 = this.core.allBodies.Count - 1; - } - GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + selectedBodyIdx2.value--; + if (selectedBodyIdx2 < 0) + { + selectedBodyIdx2.value = this.core.SortedBodyList.Count - 1; + } + } + GUILayout.Label(this.core.SortedBodyList[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) { - selectedBodyIdx2++; - if (selectedBodyIdx2 > this.core.allBodies.Count - 1) selectedBodyIdx2 = 0; + selectedBodyIdx2.value++; + if (selectedBodyIdx2 > this.core.SortedBodyList.Count - 1) + { + selectedBodyIdx2.value = 0; + } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); @@ -181,7 +229,7 @@ GUILayout.Label("Natural satellites:"); GUILayout.Label("Artificial satellites:"); GUILayout.Label("Surface gravity:"); - GUILayout.Label("Atmosphere altitude:"); + GUILayout.Label("Atmosphere Depth:"); GUILayout.Label("Atmospheric O\u2082:"); GUILayout.Label("Has ocean:"); @@ -208,120 +256,246 @@ GUILayout.EndHorizontal(); } - GUI.DragWindow(); + if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true))) + { + toggleScience.value = !toggleScience; + } + + if (toggleScience) + { + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + //begin physical info value label column + GUILayout.BeginVertical(GUILayout.Width(150)); + + + /* + * public float RecoveryValue = 1f; + + public float InSpaceHighDataValue = 1f; + + public float spaceAltitudeThreshold = 250000f; + + public float flyingAltitudeThreshold = 18000f; + + public float InSpaceLowDataValue = 1f; + + public float SplashedDataValue = 1f; + + public float LandedDataValue = 1f; + + public float FlyingHighDataValue = 1f; + + public float FlyingLowDataValue = 1f; + */ + + GUILayout.Label("Surface Multiplier:"); + GUILayout.Label("Ocean Multiplier:"); + GUILayout.Label("Flying-Low Multiplier:"); + GUILayout.Label("Flying-High Multiplier:"); + GUILayout.Label("Low Orbit Multiplier:"); + GUILayout.Label("High Orbit Multiplier:"); + GUILayout.Label("'Flying-High' Altitude:"); + GUILayout.Label("'High Orbit' Altitude:"); + GUILayout.Label("Recovery Multiplier:"); + + //end physical info value label column + GUILayout.EndVertical(); + + //begin primary physical values column + GUILayout.BeginVertical(GUILayout.Width(150)); + + this.cbColumnScience(selectedBody1); + + //end primary physical column + GUILayout.EndVertical(); + + //begin secondary physical values column + GUILayout.BeginVertical(GUILayout.Width(150)); + + this.cbColumnScience(selectedBody2); + + //end target physical values column + GUILayout.EndVertical(); + + //end physical value horizontal chunk + GUILayout.EndHorizontal(); + } + + base.ModuleWindow(id); } private void body_OP_show_orbital_info(CelestialBody body) { - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToAp), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToPe), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.period), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(VOID_Tools.ConvertInterval(body.rotationPeriod), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", this.core.LabelStyles["right"], 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)); + + 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)); + + 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)); + + 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)); + + 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)); + + 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)); + + 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)); + + 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)); + + 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)); // Toadicus edit: convert mean anomaly into degrees. - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", this.core.LabelStyles["right"], 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)); + + 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)); // Toadicus edit: convert eccentric anomaly into degrees. - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], 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)); + + 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)); + + 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)); + + 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)); + + if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else { string body_tidally_locked = "No"; if (body.tidallyLocked) body_tidally_locked = "Yes"; - GUILayout.Label(body_tidally_locked, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); } } private void body_OP_show_physical_info(CelestialBody body) { - GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", this.core.LabelStyles["right"], 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)); // 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³", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", this.core.LabelStyles["right"], 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)); double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI); - GUILayout.Label(p.ToString("##,#") + "kg/m³", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label(body.orbitingBodies.Count.ToString(), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + + if (body.bodyName == "Sun") GUILayout.Label(SIFormatProvider.ToSI(body.sphereOfInfluence, 3), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + else GUILayout.Label(SIFormatProvider.ToSI(body.sphereOfInfluence, 3), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + + GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); //show # artificial satellites int num_art_sats = 0; - foreach (Vessel v in FlightGlobals.Vessels) - { + + Vessel v; + for (int idx = 0; idx < FlightGlobals.Vessels.Count; idx++) + { + v = FlightGlobals.Vessels[idx]; + if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++; } - GUILayout.Label(num_art_sats.ToString(), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - double g_ASL = (VOID_Core.Constant_G * body.Mass) / (body.Radius * body.Radius); - - GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", this.core.LabelStyles["right"], 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); + + GUILayout.Label(SIFormatProvider.ToSI(g_ASL, 3) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.atmosphere) { - GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", - this.core.LabelStyles["right"], + GUILayout.Label("≈ " + SIFormatProvider.ToSI(body.atmosphereDepth, 3) + "m", + VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); string O2 = "No"; if (body.atmosphereContainsOxygen == true) O2 = "Yes"; - GUILayout.Label(O2, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); } else { - GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); - GUILayout.Label("N/A", this.core.LabelStyles["right"], 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"; if (body.ocean == true) ocean = "Yes"; - GUILayout.Label(ocean, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + } + + private void cbColumnScience(CelestialBody body) + { + /*GUILayout.Label("Surface Science Multiplier:"); + GUILayout.Label("Ocean Science Multiplier:"); + GUILayout.Label("Low-Atmosphere Science Multiplier:"); + GUILayout.Label("High-Atmosphere Science Multiplier:"); + GUILayout.Label("Low Orbit Science Multiplier:"); + GUILayout.Label("High Orbit Science Multiplier:"); + GUILayout.Label("'In Space' Altitude:"); + GUILayout.Label("'Flying' Altitude:"); + GUILayout.Label("Recovery Multiplier:");*/ + + var scienceValues = body.scienceValues; + + GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"), + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label( + body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A", + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label( + body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A", + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label( + body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A", + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"), + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"), + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label( + body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A", + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label( + scienceValues.spaceAltitudeThreshold.ToString("N0"), + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); + + GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"), + VOID_Styles.labelRight, + GUILayout.ExpandWidth(true)); } } } --- /dev/null +++ b/VOID_CareerStatus.cs @@ -1,1 +1,279 @@ - +// VOID +// +// VOID_CareerStatus.cs +// +// Copyright © 2014, 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 System.Text; +using ToadicusTools; +using ToadicusTools.Text; +using UnityEngine; + +namespace VOID +{ + [VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)] + [VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)] + public class VOID_CareerStatus : VOID_SingletonWindow + { + public static string formatDelta(double delta, string numberFormat) + { + if (delta > 0) + { + return string.Format("{0}↑", delta.ToString(numberFormat, SIFormatProvider.SIFormatter)); + } + else if (delta < 0) + { + return string.Format("{0}↓", delta.ToString(numberFormat, SIFormatProvider.SIFormatter)); + } + else + { + return "0"; + } + } + + public static string formatDelta(double delta) + { + return formatDelta(delta, "#,##0.##"); + } + + public static string formatDelta(float delta) + { + return formatDelta((double)delta); + } + + private GUIContent fundsContent; + private GUIContent repContent; + private GUIContent scienceContent; + + #pragma warning disable 0414 + private Texture2D fundsIconGreen; + private Texture2D fundsIconRed; + private Texture2D reputationIconGreen; + private Texture2D reputationIconRed; + private Texture2D scienceIcon; + #pragma warning restore 0414 + + public double lastFundsChange + { + get; + private set; + } + + public float lastRepChange + { + get; + private set; + } + + public float lastScienceChange + { + get; + private set; + } + + public double currentFunds + { + get; + private set; + } + + public float currentReputation + { + get; + private set; + } + + public float currentScience + { + get; + private set; + } + + private bool currenciesInitialized + { + get + { + Logging.PostDebugMessage( + this, + "Checking init state:" + + "\n\tcurrentFunds={0}" + + "\n\tcurrentScience={1}" + + "\n\tcurrentReputation={2}", + this.currentFunds, + this.currentScience, + this.currentReputation + ); + + return !( + double.IsNaN(this.currentFunds) || + float.IsNaN(this.currentScience) || + float.IsNaN(this.currentReputation) + ); + } + } + + public override void DrawGUI(object sender) + { + if (Event.current.type != EventType.Layout && !this.currenciesInitialized) + { + this.initCurrencies(); + } + + base.DrawGUI(sender); + } + + public override void ModuleWindow(int id) + { + GUILayout.BeginVertical(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label(VOID_Data.fundingStatus.Label); + GUILayout.FlexibleSpace(); + this.fundsContent.text = VOID_Data.fundingStatus.Value; + GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label(VOID_Data.reputationStatus.Label); + GUILayout.FlexibleSpace(); + this.repContent.text = VOID_Data.reputationStatus.Value; + GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + GUILayout.Label(VOID_Data.scienceStatus.Label); + GUILayout.FlexibleSpace(); + this.scienceContent.text = VOID_Data.scienceStatus.Value; + GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + + // TODO: Update event handlers to do something useful with the new "reasons" parameter. + private void onFundsChange(double newValue, TransactionReasons reasons) + { + this.lastFundsChange = newValue - this.currentFunds; + this.currentFunds = newValue; + } + + private void onRepChange(float newValue, TransactionReasons reasons) + { + this.lastRepChange = newValue - this.currentReputation; + this.currentReputation = newValue; + } + + private void onScienceChange(float newValue, TransactionReasons reasons) + { + this.lastScienceChange = newValue - this.currentScience; + this.currentScience = newValue; + } + + private void onGameStateLoad(ConfigNode node) + { + this.initCurrencies(); + } + + private void initCurrencies() + { + Logging.PostDebugMessage( + this, + "Initializing currencies." + + "\n\tFunding.Instance={0}" + + "ResearchAndDevelopment.Instance={1}" + + "Reputation.Instance={2}", + Funding.Instance == null ? "NULL" : Funding.Instance.ToString(), + ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(), + Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString() + ); + + this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN; + this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN; + this.currentScience = ResearchAndDevelopment.Instance != null ? + ResearchAndDevelopment.Instance.Science : float.NaN; + } + + /* + * MissionRecoveryDialog::fundsIconGreen.name: UiElements_05 + * MissionRecoveryDialog::fundsIconRed.name: UiElements_06 + * MissionRecoveryDialog::reputationIconGreen.name: UiElements_07 + * MissionRecoveryDialog::reputationIconRed.name: UiElements_08 + * MissionRecoveryDialog::scienceIcon.name: UiElements_12 + * */ + public VOID_CareerStatus() : base() + { + this.Name = "Career Status"; + + GameEvents.OnFundsChanged.Add(this.onFundsChange); + GameEvents.OnReputationChanged.Add(this.onRepChange); + GameEvents.OnScienceChanged.Add(this.onScienceChange); + GameEvents.onGameStateLoad.Add(this.onGameStateLoad); + + bool texturesLoaded; + + 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.reputationIconGreen, "VOID/Textures/repgreen.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); + + this.fundsContent = new GUIContent(); + this.repContent = new GUIContent(); + this.scienceContent = new GUIContent(); + + if (texturesLoaded) + { + this.fundsContent.image = this.fundsIconGreen; + this.repContent.image = this.reputationIconGreen; + this.scienceContent.image = this.scienceIcon; + } + + this.currentFunds = double.NaN; + this.currentScience = float.NaN; + this.currentReputation = float.NaN; + } + + public override void Dispose() + { + GameEvents.OnFundsChanged.Remove(this.onFundsChange); + GameEvents.OnReputationChanged.Remove(this.onRepChange); + GameEvents.OnScienceChanged.Remove(this.onScienceChange); + GameEvents.onGameStateLoad.Remove(this.onGameStateLoad); + + base.Dispose(); + } + + ~VOID_CareerStatus() + { + this.Dispose(); + } + } +} + + --- /dev/null +++ b/VOID_ConfigWindow.cs @@ -1,1 +1,75 @@ +// 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 UnityEngine; + +namespace VOID +{ + public class VOID_ConfigWindow : VOID_SingletonWindow + { + public override bool InValidScene + { + get + { + return true; + } + } + + public override bool InValidGame + { + get + { + return true; + } + } + + public VOID_ConfigWindow() : base() + { + this.Name = "VOID Configuration"; + } + + public override void ModuleWindow(int id) + { + GUILayout.BeginVertical(); + + this.core.DrawConfigurables(); + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + + ~VOID_ConfigWindow() + { + this.Dispose(); + } + } +} + --- a/VOID_Core.cs +++ /dev/null @@ -1,1110 +1,1 @@ -// VOID -// -// VOID_Core.cs -// -// Copyright © 2014, 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 Engineer.VesselSimulator; -using KSP; -using System; -using System.Collections.Generic; -using System.Linq; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public class VOID_Core : VOID_Module, IVOID_Module - { - #region Singleton Members - /* - * Static Members - * */ - protected static bool _initialized = false; - - public static bool Initialized - { - get - { - return _initialized; - } - } - - protected static VOID_Core _instance; - - public static VOID_Core Instance - { - get - { - if (_instance == null) - { - _instance = new VOID_Core(); - _initialized = true; - } - return _instance; - } - } - - public static void Reset() - { - _instance.StopGUI(); - _instance = null; - _initialized = false; - } - #endregion - - public static readonly double Constant_G = 6.674e-11; - - /* - * Fields - * */ - protected string VoidName = "VOID"; - protected string VoidVersion; - - protected bool _factoryReset = false; - - [AVOID_SaveValue("configValue")] - protected VOID_SaveValue configVersion = 1; - - protected List _modules = new List(); - protected bool _modulesLoaded = false; - - [AVOID_SaveValue("mainWindowPos")] - protected VOID_SaveValue mainWindowPos = new Rect(475, 575, 10f, 10f); - [AVOID_SaveValue("mainGuiMinimized")] - protected VOID_SaveValue mainGuiMinimized = false; - - [AVOID_SaveValue("configWindowPos")] - protected VOID_SaveValue configWindowPos = new Rect(825, 625, 10f, 10f); - [AVOID_SaveValue("configWindowMinimized")] - - protected VOID_SaveValue configWindowMinimized = true; - [AVOID_SaveValue("VOIDIconPos")] - protected VOID_SaveValue VOIDIconPos = new Rect(Screen.width / 2 - 200, Screen.height - 32, 32f, 32f); - - protected Texture2D VOIDIconTexture; - protected string VOIDIconOnActivePath; - protected string VOIDIconOnInactivePath; - protected string VOIDIconOffActivePath; - protected string VOIDIconOffInactivePath; - - protected bool VOIDIconLocked = true; - - protected GUIStyle iconStyle; - - protected int windowBaseID = -96518722; - protected int _windowID = 0; - - protected bool GUIStylesLoaded = false; - protected Dictionary _LabelStyles = new Dictionary(); - - protected CelestialBody _Kerbin; - - [AVOID_SaveValue("togglePower")] - public VOID_SaveValue togglePower = true; - public bool powerAvailable = true; - - [AVOID_SaveValue("consumeResource")] - protected VOID_SaveValue consumeResource = false; - - [AVOID_SaveValue("resourceName")] - protected VOID_SaveValue resourceName = "ElectricCharge"; - - [AVOID_SaveValue("resourceRate")] - protected VOID_SaveValue resourceRate = 0.2f; - - [AVOID_SaveValue("updatePeriod")] - protected VOID_SaveValue _updatePeriod = 1001f / 15000f; - protected float _updateTimer = 0f; - protected string stringFrequency; - - [AVOID_SaveValue("vesselSimActive")] - protected VOID_SaveValue vesselSimActive; - - // Vessel Type Housekeeping - protected List _allVesselTypes = new List(); - protected bool vesselTypesLoaded = false; - public float saveTimer = 0; - - protected string defaultSkin = "KSP window 2"; - - [AVOID_SaveValue("defaultSkin")] - protected VOID_SaveValue _skinName; - protected int _skinIdx; - - protected Dictionary validSkins; - protected string[] skinNames; - protected string[] forbiddenSkins = - { - "PlaqueDialogSkin", - "FlagBrowserSkin", - "SSUITextAreaDefault", - "ExperimentsDialogSkin", - "ExpRecoveryDialogSkin", - "KSP window 5", - "KSP window 6", - "PartTooltipSkin" - }; - protected bool skinsLoaded = false; - - public bool configDirty; - - [AVOID_SaveValue("UseBlizzyToolbar")] - protected VOID_SaveValue _UseToolbarManager; - internal IButton ToolbarButton; - - internal ApplicationLauncherButton AppLauncherButton; - - /* - * Properties - * */ - public bool factoryReset - { - get - { - return this._factoryReset; - } - } - - public List Modules - { - get - { - return this._modules; - } - } - - public GUISkin Skin - { - get - { - if (this.skinsLoaded) - { - try - { - return this.validSkins[this._skinName]; - } - catch - { - } - } - - return AssetBase.GetGUISkin(this.defaultSkin); - } - } - - public int windowID - { - get - { - if (this._windowID == 0) - { - this._windowID = this.windowBaseID; - } - return this._windowID++; - } - } - - public Dictionary LabelStyles - { - get - { - return this._LabelStyles; - } - } - - public List allBodies - { - get - { - return FlightGlobals.Bodies; - } - } - - public CelestialBody Kerbin - { - get - { - if (this._Kerbin == null) - { - if (FlightGlobals.Bodies != null) - { - this._Kerbin = FlightGlobals.Bodies.First(b => b.name == "Kerbin"); - } - } - - return this._Kerbin; - } - } - - public List allVesselTypes - { - get - { - return this._allVesselTypes; - } - } - - public float updateTimer - { - get - { - return this._updateTimer; - } - } - - public double updatePeriod - { - get - { - return this._updatePeriod; - } - } - - protected IconState powerState - { - get - { - if (this.togglePower && this.powerAvailable) - { - return IconState.PowerOn; - } - else - { - return IconState.PowerOff; - } - - } - } - - protected IconState activeState - { - get - { - if (this.mainGuiMinimized) - { - return IconState.Inactive; - } - else - { - return IconState.Active; - } - - } - } - - protected bool UseToolbarManager - { - get - { - return _UseToolbarManager & ToolbarManager.ToolbarAvailable; - } - set - { - if (this._UseToolbarManager == value) - { - return; - } - - if (value == false && this.ToolbarButton != null) - { - this.ToolbarButton.Destroy(); - this.ToolbarButton = null; - } - if (value == true) - { - if (this.AppLauncherButton != null) - { - ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); - this.AppLauncherButton = null; - } - - this.InitializeToolbarButton(); - } - - _UseToolbarManager.value = value; - } - } - - /* - * Methods - * */ - public override void DrawGUI() - { - this._windowID = this.windowBaseID; - - if (!this._modulesLoaded) - { - this.LoadModulesOfType(); - } - - if (!this.skinsLoaded) - { - this.LoadSkins(); - } - - GUI.skin = this.Skin; - - if (!this.GUIStylesLoaded) - { - this.LoadGUIStyles(); - } - - if (!this.UseToolbarManager) - { - if (this.AppLauncherButton == null) - { - this.InitializeAppLauncherButton(); - } - } - else if (this.ToolbarButton == null) - { - this.InitializeToolbarButton(); - } - - if (!this.mainGuiMinimized) - { - - 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(250), - GUILayout.Height(50) - ); - - _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) - ); - - _configWindowPos = Tools.ClampRectToScreen(_configWindowPos); - - if (_configWindowPos != this.configWindowPos) - { - this.configWindowPos = _configWindowPos; - } - } - } - - public void OnGUI() - { - if (Event.current.type == EventType.Repaint) - { - return; - } - - /* - Tools.PostDebugMessage(string.Format( - "Event.current.type: {0}" + - "\nthis.VOIDIconLocked: {1}" + - "\nEvent.current.mousePosition: {2}" + - "\nVOIDIconPos: ({3}, {4}),({5}, {6})", - Event.current.type, - this.VOIDIconLocked, - Event.current.mousePosition, - this.VOIDIconPos.value.xMin, - this.VOIDIconPos.value.yMin, - this.VOIDIconPos.value.xMax, - this.VOIDIconPos.value.yMax - )); - */ - - if (!this.VOIDIconLocked && - VOIDIconPos.value.Contains(Event.current.mousePosition) - && Event.current.type == EventType.mouseDrag) - { - Tools.PostDebugMessage(string.Format( - "Event.current.type: {0}" + - "\ndelta.x: {1}; delta.y: {2}", - Event.current.type, - Event.current.delta.x, - Event.current.delta.y - )); - - Rect tmp = new Rect(VOIDIconPos); - - tmp.x = Event.current.mousePosition.x - tmp.width / 2; - tmp.y = Event.current.mousePosition.y - tmp.height / 2; - - if (tmp.x > Screen.width - tmp.width) - { - tmp.x = Screen.width - tmp.width; - } - - if (tmp.y > Screen.height - tmp.height) - { - tmp.y = Screen.height - tmp.height; - } - - VOIDIconPos = tmp; - } - } - - public void Update() - { - this.LoadBeforeUpdate(); - - if (this.vessel != null && this.vesselSimActive) - { - double radius = this.vessel.Radius(); - SimManager.Gravity = this.vessel.mainBody.gravParameter / - (radius * radius); - SimManager.minSimTime = (long)(this.updatePeriod * 1000); - SimManager.TryStartSimulation(); - } - else if (!this.vesselSimActive) - { - SimManager.ClearResults(); - } - - if (!this.guiRunning) - { - this.StartGUI(); - } - - if (!HighLogic.LoadedSceneIsFlight && this.guiRunning) - { - this.StopGUI(); - } - - foreach (IVOID_Module module in this.Modules) - { - if (!module.guiRunning && module.toggleActive) - { - module.StartGUI(); - } - if (module.guiRunning && !module.toggleActive || - !this.togglePower || - !HighLogic.LoadedSceneIsFlight || - this.factoryReset) - { - module.StopGUI(); - } - - if (module is IVOID_BehaviorModule) - { - ((IVOID_BehaviorModule)module).Update(); - } - } - - this.CheckAndSave(); - this._updateTimer += Time.deltaTime; - } - - public void FixedUpdate() - { - bool newPowerState = this.powerAvailable; - - if (this.togglePower && this.consumeResource && - this.vessel.vesselType != VesselType.EVA && - TimeWarp.deltaTime != 0) - { - float powerReceived = this.vessel.rootPart.RequestResource( - this.resourceName, - this.resourceRate * TimeWarp.fixedDeltaTime - ); - - if (powerReceived > 0) - { - newPowerState = true; - } - else - { - newPowerState = false; - } - - if (this.powerAvailable != newPowerState) - { - this.powerAvailable = newPowerState; - this.SetIconTexture(this.powerState | this.activeState); - } - } - - foreach (IVOID_BehaviorModule module in - this._modules.OfType().Where(m => !m.GetType().IsAbstract)) - { - module.FixedUpdate(); - } - } - - public void ResetGUI() - { - this.StopGUI(); - - foreach (IVOID_Module module in this.Modules) - { - module.StopGUI(); - module.StartGUI(); - } - - this.StartGUI(); - } - - public void VOIDMainWindow(int _) - { - GUILayout.BeginVertical(); - - if (this.powerAvailable || HighLogic.LoadedSceneIsEditor) - { - if (!HighLogic.LoadedSceneIsEditor) - { - string str = string.Intern("ON"); - if (togglePower) - str = string.Intern("OFF"); - if (GUILayout.Button("Power " + str)) - { - togglePower.value = !togglePower; - this.SetIconTexture(this.powerState | this.activeState); - } - } - - if (togglePower || HighLogic.LoadedSceneIsEditor) - { - foreach (IVOID_Module module in this.Modules) - { - module.toggleActive = GUILayout.Toggle(module.toggleActive, module.Name); - } - } - } - else - { - GUILayout.Label("-- POWER LOST --", this.LabelStyles["red"]); - } - - this.configWindowMinimized.value = !GUILayout.Toggle(!this.configWindowMinimized, "Configuration"); - - GUILayout.EndVertical(); - GUI.DragWindow(); - } - - public void VOIDConfigWindow(int _) - { - GUILayout.BeginVertical(); - - this.DrawConfigurables(); - - GUILayout.EndVertical(); - GUI.DragWindow(); - } - - public override void DrawConfigurables() - { - GUIContent _content; - - if (HighLogic.LoadedSceneIsFlight) - { - this.consumeResource.value = GUILayout.Toggle(this.consumeResource, "Consume Resources"); - - this.VOIDIconLocked = GUILayout.Toggle(this.VOIDIconLocked, "Lock Icon Position"); - } - - this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available"); - - this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value, - "Enable Engineering Calculations"); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - - GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); - - _content = new GUIContent(); - - _content.text = "◄"; - _content.tooltip = "Select previous skin"; - if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) - { - this.GUIStylesLoaded = false; - this._skinIdx--; - Tools.PostDebugMessage(string.Format( - "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", - this.GetType().Name, - this._skinName, - this.validSkins.Count - )); - } - - _content.text = this.Skin.name; - _content.tooltip = "Current skin"; - GUILayout.Label(_content, this.LabelStyles["center"], GUILayout.ExpandWidth(true)); - - _content.text = "►"; - _content.tooltip = "Select next skin"; - if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) - { - this.GUIStylesLoaded = false; - this._skinIdx++; - Tools.PostDebugMessage(string.Format( - "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", - this.GetType().Name, - this._skinName, - this.validSkins.Count - )); - } - - this._skinIdx %= this.skinNames.Length; - if (this._skinIdx < 0) - { - this._skinIdx += this.skinNames.Length; - } - - if (this._skinName != skinNames[this._skinIdx]) - { - this._skinName.value = skinNames[this._skinIdx]; - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("Update Rate (Hz):"); - if (this.stringFrequency == null) - { - this.stringFrequency = (1f / this.updatePeriod).ToString(); - } - this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true)); - // GUILayout.FlexibleSpace(); - if (GUILayout.Button("Apply")) - { - double updateFreq = 1f / this.updatePeriod; - double.TryParse(stringFrequency, out updateFreq); - this._updatePeriod = 1 / updateFreq; - } - GUILayout.EndHorizontal(); - - foreach (IVOID_Module mod in this.Modules) - { - mod.DrawConfigurables(); - } - - this._factoryReset = GUILayout.Toggle(this._factoryReset, "Factory Reset"); - } - - protected void LoadModulesOfType() - { - var types = AssemblyLoader.loadedAssemblies - .Select(a => a.assembly.GetExportedTypes()) - .SelectMany(t => t) - .Where(v => typeof(T).IsAssignableFrom(v) - && !(v.IsInterface || v.IsAbstract) && - !typeof(VOID_Core).IsAssignableFrom(v) - ); - - Tools.PostDebugMessage(string.Format( - "{0}: Found {1} modules to check.", - this.GetType().Name, - types.Count() - )); - foreach (var voidType in types) - { - if (!HighLogic.LoadedSceneIsEditor && - typeof(IVOID_EditorModule).IsAssignableFrom(voidType)) - { - continue; - } - - Tools.PostDebugMessage(string.Format( - "{0}: found Type {1}", - this.GetType().Name, - voidType.Name - )); - - this.LoadModule(voidType); - } - - this._modulesLoaded = true; - - Tools.PostDebugMessage(string.Format( - "{0}: Loaded {1} modules.", - this.GetType().Name, - this.Modules.Count - )); - } - - protected void LoadModule(Type T) - { - var existingModules = this._modules.Where(mod => mod.GetType().Name == T.Name); - if (existingModules.Any()) - { - Tools.PostDebugMessage(string.Format( - "{0}: refusing to load {1}: already loaded", - this.GetType().Name, - T.Name - )); - return; - } - IVOID_Module module = Activator.CreateInstance(T) as IVOID_Module; - module.LoadConfig(); - this._modules.Add(module); - - Tools.PostDebugMessage(string.Format( - "{0}: loaded module {1}.", - this.GetType().Name, - T.Name - )); - } - - protected void LoadSkins() - { - Tools.PostDebugMessage("AssetBase has skins: \n" + - string.Join("\n\t", - Resources.FindObjectsOfTypeAll(typeof(GUISkin)) - .Select(s => s.ToString()) - .ToArray() - ) - ); - - this.validSkins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)) - .Where(s => !this.forbiddenSkins.Contains(s.name)) - .Select(s => s as GUISkin) - .GroupBy(s => s.name) - .Select(g => g.First()) - .ToDictionary(s => s.name); - - Tools.PostDebugMessage(string.Format( - "{0}: loaded {1} GUISkins.", - this.GetType().Name, - this.validSkins.Count - )); - - this.skinNames = this.validSkins.Keys.ToArray(); - Array.Sort(this.skinNames); - - int defaultIdx = int.MinValue; - - for (int i = 0; i < this.skinNames.Length; i++) - { - if (this.skinNames[i] == this._skinName) - { - this._skinIdx = i; - } - if (this.skinNames[i] == this.defaultSkin) - { - defaultIdx = i; - } - if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue) - { - break; - } - } - - if (this._skinIdx == int.MinValue) - { - this._skinIdx = defaultIdx; - } - - Tools.PostDebugMessage(string.Format( - "{0}: _skinIdx = {1}.", - this.GetType().Name, - this._skinName.ToString() - )); - - this.skinsLoaded = true; - } - - protected void LoadGUIStyles() - { - this.LabelStyles["link"] = new GUIStyle(GUI.skin.label); - this.LabelStyles["link"].fontStyle = FontStyle.Bold; - - this.LabelStyles["center"] = new GUIStyle(GUI.skin.label); - this.LabelStyles["center"].normal.textColor = Color.white; - this.LabelStyles["center"].alignment = TextAnchor.UpperCenter; - - this.LabelStyles["center_bold"] = new GUIStyle(GUI.skin.label); - this.LabelStyles["center_bold"].normal.textColor = Color.white; - this.LabelStyles["center_bold"].alignment = TextAnchor.UpperCenter; - this.LabelStyles["center_bold"].fontStyle = FontStyle.Bold; - - this.LabelStyles["right"] = new GUIStyle(GUI.skin.label); - this.LabelStyles["right"].normal.textColor = Color.white; - this.LabelStyles["right"].alignment = TextAnchor.UpperRight; - - this.LabelStyles["red"] = new GUIStyle(GUI.skin.label); - this.LabelStyles["red"].normal.textColor = Color.red; - this.LabelStyles["red"].alignment = TextAnchor.MiddleCenter; - - this.iconStyle = new GUIStyle(GUI.skin.button); - this.iconStyle.padding = new RectOffset(0, 0, 0, 0); - // this.iconStyle.margin = new RectOffset(0, 0, 0, 0); - // this.iconStyle.contentOffset = new Vector2(0, 0); - this.iconStyle.overflow = new RectOffset(0, 0, 0, 0); - // this.iconStyle.border = new RectOffset(0, 0, 0, 0); - - this.GUIStylesLoaded = true; - } - - protected void LoadVesselTypes() - { - this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType().ToList(); - this.vesselTypesLoaded = true; - } - - protected void LoadBeforeUpdate() - { - if (!this.vesselTypesLoaded) - { - this.LoadVesselTypes(); - } - } - - protected void InitializeToolbarButton() - { - // Do nothing if the Toolbar is not available. - if (!ToolbarManager.ToolbarAvailable) - { - return; - } - - this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); - this.ToolbarButton.Text = this.VoidName; - this.SetIconTexture(this.powerState | this.activeState); - - this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH); - - this.ToolbarButton.OnClick += - (e) => - { - this.ToggleMainWindow(); - }; - - Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); - } - - protected void InitializeAppLauncherButton() - { - if (ApplicationLauncher.Ready) - { - this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( - this.ToggleMainWindow, this.ToggleMainWindow, - HighLogic.LoadedScene.ToAppScenes(), - this.VOIDIconTexture - ); - - Tools.PostDebugMessage( - this, - "AppLauncherButton initialized in {0}", - Enum.GetName( - typeof(GameScenes), - HighLogic.LoadedScene - ) - ); - } - } - - protected void ToggleMainWindow() - { - this.mainGuiMinimized = !this.mainGuiMinimized; - this.SetIconTexture(this.powerState | this.activeState); - } - - protected void SetIconTexture(IconState state) - { - switch (state) - { - case (IconState.PowerOff | IconState.Inactive): - this.SetIconTexture(this.VOIDIconOffInactivePath); - break; - case (IconState.PowerOff | IconState.Active): - this.SetIconTexture(this.VOIDIconOffActivePath); - break; - case (IconState.PowerOn | IconState.Inactive): - this.SetIconTexture(this.VOIDIconOnInactivePath); - break; - case (IconState.PowerOn | IconState.Active): - this.SetIconTexture(this.VOIDIconOnActivePath); - break; - default: - throw new NotImplementedException(); - } - } - - protected void SetIconTexture(string texturePath) - { - if (this.ToolbarButton != null) - { - this.ToolbarButton.TexturePath = texturePath; - } - - this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath, false); - - if (this.AppLauncherButton != null) - { - this.AppLauncherButton.SetTexture(VOIDIconTexture); - } - } - - protected void CheckAndSave() - { - this.saveTimer += Time.deltaTime; - - if (this.saveTimer > 2f) - { - if (!this.configDirty) - { - return; - } - - Tools.PostDebugMessage(string.Format( - "{0}: Time to save, checking if configDirty: {1}", - this.GetType().Name, - this.configDirty - )); - - this.SaveConfig(); - this.saveTimer = 0; - } - } - - public override void LoadConfig() - { - base.LoadConfig(); - - foreach (IVOID_Module module in this.Modules) - { - module.LoadConfig(); - } - } - - public void SaveConfig() - { - var config = KSP.IO.PluginConfiguration.CreateForType(); - config.load(); - - this._SaveToConfig(config); - - foreach (IVOID_Module module in this.Modules) - { - module._SaveToConfig(config); - } - - config.save(); - - this.configDirty = false; - } - - public void onSceneChangeRequested(GameScenes scene) - { - if (this.AppLauncherButton != null) - { - if (this is VOID_EditorCore) - { - if (!HighLogic.LoadedSceneIsEditor) - { - ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); - } - } - else - { - if (!HighLogic.LoadedSceneIsFlight) - { - ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); - } - } - } - } - - protected VOID_Core() - { - this._Name = "VOID Core"; - - System.Version version = this.GetType().Assembly.GetName().Version; - - this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision); - - this._Active.value = true; - - this._skinName = this.defaultSkin; - this._skinIdx = int.MinValue; - - this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_light_glow"; - this.VOIDIconOnActivePath = "VOID/Textures/void_icon_dark_glow"; - this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_light"; - this.VOIDIconOffActivePath = "VOID/Textures/void_icon_dark"; - - this.vesselSimActive = true; - - this.UseToolbarManager = false; - - this.LoadConfig(); - - this.SetIconTexture(this.powerState | this.activeState); - } - - protected enum IconState - { - PowerOff = 1, - PowerOn = 2, - Inactive = 4, - Active = 8 - } - } - - public static partial class VOID_Data - { - public static VOID_Core core - { - get - { - if (HighLogic.LoadedSceneIsEditor) - { - return VOID_EditorCore.Instance; - } - else - { - return VOID_Core.Instance; - } - } - } - - public static double KerbinGee - { - get - { - return core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius); - } - } - } -} - - --- /dev/null +++ b/VOID_Data.cs @@ -1,1 +1,1346 @@ - +// VOID +// +// VOID_Data.cs +// +// Copyright © 2014, 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 KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using ToadicusTools; +using ToadicusTools.Extensions; +using ToadicusTools.MuMechTools; +using UnityEngine; + +namespace VOID +{ + public static class VOID_Data + { + private static Dictionary dataValues = new Dictionary(); + + public static Dictionary DataValues + { + get + { + return dataValues; + } + } + + #region Constants + + private static double kerbinGee; + + public static double KerbinGee + { + get + { + if (kerbinGee == default(double)) + { + kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius); + } + + return kerbinGee; + } + } + + #endregion + + #region Core Data + + public static VOIDCore Core + { + get + { + if (!CoreInitialized) + { + return null; + } + + switch (HighLogic.LoadedScene) + { + case GameScenes.EDITOR: + return (VOIDCore)VOIDCore_Editor.Instance; + case GameScenes.FLIGHT: + return (VOIDCore)VOIDCore_Flight.Instance; + case GameScenes.SPACECENTER: + return (VOIDCore)VOIDCore_SpaceCentre.Instance; + default: + return null; + } + } + } + + public static bool CoreInitialized + { + get + { + switch (HighLogic.LoadedScene) + { + case GameScenes.EDITOR: + return VOIDCore_Editor.Initialized; + case GameScenes.FLIGHT: + return VOIDCore_Flight.Initialized; + case GameScenes.SPACECENTER: + return VOIDCore_SpaceCentre.Initialized; + default: + return false; + } + } + } + + #endregion + + #region Atmosphere + + public static readonly VOID_DoubleValue atmDensity = + new VOID_DoubleValue( + "Atmosphere Density", + new Func(() => Core.Vessel.atmDensity * 1000d), + "g/m³" + ); + + public static readonly VOID_DoubleValue atmLimit = + new VOID_DoubleValue( + "Atmosphere Depth", + new Func(() => Core.Vessel.mainBody.atmosphereDepth), + "m" + ); + + public static readonly VOID_DoubleValue atmPressure = + new VOID_DoubleValue( + "Static Pressure", + new Func(() => Core.Vessel.staticPressurekPa * 1000d), + "Pa" + ); + + public static readonly VOID_DoubleValue temperature = + new VOID_DoubleValue( + "Temperature", + new Func(() => Core.Vessel.atmosphericTemperature), + "K" + ); + + #endregion + + #region Attitude + + public static readonly VOID_StrValue vesselHeading = + new VOID_StrValue( + "Heading", + delegate() + { + double heading = Core.Vessel.getSurfaceHeading(); + string cardinal = VOID_Tools.get_heading_text(heading); + + return string.Format( + "{0}° {1}", + heading.ToString("F2"), + cardinal + ); + } + ); + + public static readonly VOID_DoubleValue vesselPitch = + new VOID_DoubleValue( + "Pitch", + () => Core.Vessel.getSurfacePitch(), + "°" + ); + + #endregion + + #region Career + + public static readonly VOID_StrValue fundingStatus = + new VOID_StrValue( + string.Intern("Funds"), + delegate() + { + if (VOID_CareerStatus.Instance == null) + { + return string.Empty; + } + + return string.Format("{0} ({1})", + VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"), + VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange) + ); + } + ); + + public static readonly VOID_StrValue reputationStatus = + new VOID_StrValue( + string.Intern("Reputation"), + delegate() + { + if (VOID_CareerStatus.Instance == null) + { + return string.Empty; + } + + return string.Format("{0} ({1})", + VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"), + VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange) + ); + } + ); + + public static readonly VOID_StrValue scienceStatus = + new VOID_StrValue( + string.Intern("Science"), + delegate() + { + if (VOID_CareerStatus.Instance == null) + { + return string.Empty; + } + + return string.Format("{0} ({1})", + VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"), + VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange) + ); + } + ); + + #endregion + + #region Control + + public static readonly VOID_FloatValue mainThrottle = + new VOID_FloatValue( + "Throttle", + new Func(() => Core.Vessel.ctrlState.mainThrottle), + "" + ); + + #endregion + + #region Engineering + + public static readonly VOID_IntValue partCount = + new VOID_IntValue( + "Parts", + new Func(() => Core.Vessel.Parts.Count), + "" + ); + + #region Mass + + public static readonly VOID_StrValue comboResourceMass = + new VOID_StrValue( + "Resource Mass (curr / total)", + delegate() + { + return string.Format("{0} / {1}", + stageResourceMass.ValueUnitString("F3"), + resourceMass.ValueUnitString("F3") + ); + } + ); + + public static readonly VOID_DoubleValue resourceMass = + new VOID_DoubleValue( + "Resource Mass", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.totalResourceMass; + }, + "tons" + ); + + public static readonly VOID_DoubleValue stageResourceMass = + new VOID_DoubleValue( + "Resource Mass (Stage)", + delegate() + { + if (Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.resourceMass; + }, + "tons" + ); + + public static readonly VOID_DoubleValue totalMass = + new VOID_DoubleValue( + "Total Mass", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.totalMass; + }, + "tons" + ); + + #endregion + + #region DeltaV + + public static readonly VOID_DoubleValue stageDeltaV = + new VOID_DoubleValue( + "DeltaV (Current Stage)", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return double.NaN; + return Core.LastStage.deltaV; + }, + "m/s" + ); + + public static readonly VOID_DoubleValue totalDeltaV = + new VOID_DoubleValue( + "DeltaV (Total)", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return double.NaN; + return Core.LastStage.totalDeltaV; + }, + "m/s" + ); + + #endregion + + #region Propulsion + + public static readonly VOID_StrValue currmaxThrustWeight = + new VOID_StrValue( + "T:W (curr/max)", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return "N/A"; + + return string.Format( + "{0} / {1}", + (VOID_Data.currThrustWeight.Value).ToString("F2"), + (VOID_Data.maxThrustWeight.Value).ToString("F2") + ); + } + ); + + public static readonly VOID_DoubleValue currThrust = + new VOID_DoubleValue( + "Current Thrust", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return double.NaN; + + return Core.LastStage.actualThrust; + }, + "kN" + ); + + public static readonly VOID_StrValue currmaxThrust = + new VOID_StrValue( + "Thrust (curr/max)", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return "N/A"; + + double currThrust = Core.LastStage.actualThrust; + double maxThrust = Core.LastStage.thrust; + + return string.Format( + "{0} / {1}", + currThrust.ToString("F1"), + maxThrust.ToString("F1") + ); + } + ); + + public static readonly VOID_DoubleValue stageMassFlow = + new VOID_DoubleValue( + "Stage Mass Flow", + delegate() + { + if (Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.MassFlow(); + }, + "Mg/s" + ); + + public static readonly VOID_DoubleValue stageNominalThrust = + new VOID_DoubleValue( + "Nominal Stage Thrust", + delegate() + { + if (Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.NominalThrust(); + }, + "kN" + ); + + #endregion + + #region Kinetics + + public static readonly VOID_DoubleValue currThrustWeight = + new VOID_DoubleValue( + "T:W Ratio", + delegate() + { + if (Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.actualThrustToWeight; + }, + "" + ); + + + + public static readonly VOID_DoubleValue maxThrustWeight = + new VOID_DoubleValue( + "T:W Ratio", + delegate() + { + if (Core.LastStage == null) + { + return double.NaN; + } + + return Core.LastStage.thrustToWeight; + }, + "" + ); + + public static readonly VOID_DoubleValue nominalThrustWeight = + new VOID_DoubleValue( + "Thrust-to-Weight Ratio", + delegate() + { + if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d) + { + return maxThrustWeight.Value; + } + + return currThrustWeight.Value; + }, + "" + ); + + public static readonly VOID_DoubleValue surfaceThrustWeight = + new VOID_DoubleValue( + "Max T:W @ surface", + delegate() + { + if (Core.Stages == null || Core.LastStage == null) + return double.NaN; + + double maxThrust = Core.LastStage.thrust; + double mass = Core.LastStage.totalMass; + double gravity = (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) / + (Core.Vessel.mainBody.Radius * Core.Vessel.mainBody.Radius); + double weight = mass * gravity; + + return maxThrust / weight; + }, + "" + ); + + public static readonly VOID_Vector3Value vesselThrustOffset = + new VOID_Vector3Value( + "Thrust Offset", + delegate() + { + if (Core.Vessel == null) + { + return Vector3.zero; + } + + IList engineModules = Core.Vessel.getModulesOfType(); + + Vector3 thrustPos = Vector3.zero; + Vector3 thrustDir = Vector3.zero; + float thrust = 0; + + PartModule engine; + for (int idx = 0; idx < engineModules.Count; idx++) + { + engine = engineModules[idx]; + float moduleThrust = 0; + + switch (engine.moduleName) + { + case "ModuleEngines": + case "ModuleEnginesFX": + break; + default: + continue; + } + + if (!engine.isEnabled) + { + continue; + } + + CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); + + if (engine is ModuleEngines) + { + ModuleEngines engineModule = engine as ModuleEngines; + + moduleThrust = engineModule.finalThrust; + + engineModule.OnCenterOfThrustQuery(cotQuery); + } + else // engine is ModuleEnginesFX + { + ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; + + moduleThrust = engineFXModule.finalThrust; + + engineFXModule.OnCenterOfThrustQuery(cotQuery); + } + + if (moduleThrust != 0d) + { + cotQuery.thrust = moduleThrust; + } + + thrustPos += cotQuery.pos * cotQuery.thrust; + thrustDir += cotQuery.dir * cotQuery.thrust; + thrust += cotQuery.thrust; + } + + if (thrust != 0) + { + thrustPos /= thrust; + thrustDir /= thrust; + } + + Transform vesselTransform = Core.Vessel.transform; + + thrustPos = vesselTransform.InverseTransformPoint(thrustPos); + thrustDir = vesselTransform.InverseTransformDirection(thrustDir); + + Vector3 thrustOffset = VectorTools.PointDistanceToLine( + thrustPos, thrustDir.normalized, Core.Vessel.findLocalCenterOfMass()); + + Logging.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + + "\tthrustPos: {0}\n" + + "\tthrustDir: {1}\n" + + "\tthrustOffset: {2}\n" + + "\tvessel.CoM: {3}", + thrustPos, + thrustDir.normalized, + thrustOffset, + Core.Vessel.findWorldCenterOfMass() + ); + + return thrustOffset; + }, + "m" + ); + + #endregion + + #region Air Breathing + + public static readonly VOID_StrValue intakeAirStatus = + new VOID_StrValue( + "Intake Air (Curr / Req)", + delegate() + { + double currentAmount; + double currentRequirement; + + currentAmount = 0d; + currentRequirement = 0d; + + Part part; + for (int idx = 0; idx < Core.Vessel.Parts.Count; idx++) + { + part = Core.Vessel.Parts[idx]; + + if (part.enabled) + { + ModuleEngines engineModule; + ModuleEnginesFX enginesFXModule; + List propellantList = null; + + if (part.tryGetFirstModuleOfType(out engineModule)) + { + propellantList = engineModule.propellants; + } + else if (part.tryGetFirstModuleOfType(out enginesFXModule)) + { + propellantList = enginesFXModule.propellants; + } + + if (propellantList != null) + { + Propellant propellant; + for (int propIdx = 0; propIdx < propellantList.Count; propIdx++) + { + propellant = propellantList[propIdx]; + + if (propellant.name == "IntakeAir") + { + currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; + break; + } + } + } + } + + ModuleResourceIntake intakeModule; + + if (part.enabled && part.tryGetFirstModuleOfType(out intakeModule)) + { + if (intakeModule.resourceName == "IntakeAir") + { + currentAmount += intakeModule.airFlow; + } + } + } + + if (currentAmount == 0 && currentRequirement == 0) + { + return "N/A"; + } + + return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement); + } + ); + + #endregion + + #region Crew + + public static readonly VOID_IntValue vesselCrewCount = + new VOID_IntValue( + "Crew Onboard", + delegate() + { + if (Core.Vessel != null) + { + return Core.Vessel.GetCrewCount(); + } + else + { + return 0; + } + }, + "" + ); + + public static readonly VOID_IntValue vesselCrewCapacity = + new VOID_IntValue( + "Crew Capacity", + delegate() + { + if (Core.Vessel != null) + { + return Core.Vessel.GetCrewCapacity(); + } + else + { + return 0; + } + }, + "" + ); + + #endregion + + #endregion + + #region Location + + public const double kscLongitude = 285.442323427289 * Math.PI / 180d; + public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d; + + public static readonly VOID_DoubleValue downrangeDistance = + new VOID_DoubleValue( + "Downrange Distance", + delegate() + { + + if (Core.Vessel == null || + Planetarium.fetch == null || + Core.Vessel.mainBody != Planetarium.fetch.Home) + { + return double.NaN; + } + + double vesselLongitude = Core.Vessel.longitude * Math.PI / 180d; + double vesselLatitude = Core.Vessel.latitude * Math.PI / 180d; + + double diffLon = Math.Abs(vesselLongitude - kscLongitude); + + double cosVesselLatitude = Math.Cos(vesselLatitude); + double sinDiffLon = Math.Sin(diffLon); + + double term1 = cosVesselLatitude * sinDiffLon; + + double cosKSCLatitude = Math.Cos(kscLatitude); + double sinVesselLatitude = Math.Sin(vesselLatitude); + double sinKSCLatitude = Math.Sin(kscLatitude); + double cosDiffLon = Math.Cos(diffLon); + + double term2 = cosKSCLatitude * sinVesselLatitude - sinKSCLatitude * cosVesselLatitude * cosDiffLon; + + double term3 = sinKSCLatitude * sinVesselLatitude + cosKSCLatitude * cosVesselLatitude * cosDiffLon; + + double arc = Math.Atan2(Math.Sqrt(term1 * term1 + term2 * term2), term3); + + return arc * Core.Vessel.mainBody.Radius; + }, + "m" + ); + + public static readonly VOID_StrValue surfLatitudeString = + new VOID_StrValue( + "Latitude", + new Func(() => VOID_Tools.GetLatitudeString(Core.Vessel)) + ); + + public static readonly VOID_DoubleValue surfLatitude = + new VOID_DoubleValue( + "Latitude", + delegate() + { + if (CoreInitialized && Core.Vessel != null) + { + return Core.Vessel.latitude; + } + return double.NaN; + }, + "°" + ); + + public static readonly VOID_StrValue surfLongitudeString = + new VOID_StrValue( + "Longitude", + new Func(() => VOID_Tools.GetLongitudeString(Core.Vessel)) + ); + + public static readonly VOID_DoubleValue surfLongitude = + new VOID_DoubleValue( + "Longitude", + delegate() + { + if (CoreInitialized && Core.Vessel != null) + { + double longitude = Core.Vessel.longitude; + + longitude = VOID_Tools.FixDegreeDomain(longitude); + + if (longitude < -180d) + { + longitude += 360d; + } + if (longitude >= 180) + { + longitude -= 360d; + } + + return longitude; + } + return double.NaN; + }, + "°" + ); + + public static readonly VOID_DoubleValue trueAltitude = + new VOID_DoubleValue( + "Altitude (true)", + delegate() + { + 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, + // and water covers the whole surface at 0 m. + if (Core.Vessel.terrainAltitude < 0 && Core.Vessel.mainBody.ocean) + alt_true = Core.Vessel.orbit.altitude; + return alt_true; + }, + "m" + ); + + #endregion + + #region Kinematics + + public static readonly VOID_DoubleValue geeForce = + new VOID_DoubleValue( + "G-force", + new Func(() => Core.Vessel.geeForce), + "gees" + ); + + public static readonly VOID_DoubleValue horzVelocity = + new VOID_DoubleValue( + "Horizontal speed", + delegate + { + return Core.Vessel.horizontalSrfSpeed; + }, + "m/s" + ); + + public static readonly VOID_DoubleValue surfVelocity = + new VOID_DoubleValue( + "Surface velocity", + new Func(() => Core.Vessel.srf_velocity.magnitude), + "m/s" + ); + + public static readonly VOID_DoubleValue vertVelocity = + new VOID_DoubleValue( + "Vertical speed", + new Func(() => Core.Vessel.verticalSpeed), + "m/s" + ); + + public static readonly VOID_DoubleValue vesselAccel = + new VOID_DoubleValue( + "Acceleration", + () => geeForce * KerbinGee, + "m/s²" + ); + + public static readonly VOID_DoubleValue vesselAngularVelocity = + new VOID_DoubleValue( + "Angular Velocity", + delegate() + { + if (Core.Vessel != null) + { + return Core.Vessel.angularVelocity.magnitude; + } + else + { + return double.NaN; + } + }, + "rad/s" + ); + + #endregion + + #region Navigation + + public static int upcomingManeuverNodes + { + get + { + if (Core.Vessel == null || + Core.Vessel.patchedConicSolver == null || + Core.Vessel.patchedConicSolver.maneuverNodes == null) + { + return 0; + } + + return Core.Vessel.patchedConicSolver.maneuverNodes.Count; + } + } + + public static readonly VOID_StrValue burnTimeDoneAtNode = + new VOID_StrValue( + "Full burn time to be half done at node", + delegate() + { + if (Core.LastStage == null && upcomingManeuverNodes < 1) + { + return "N/A"; + } + + ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0]; + + if ((node.UT - Planetarium.GetUniversalTime()) < 0) + { + return string.Empty; + } + + double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); + + if (double.IsNaN(interval)) + { + return string.Intern("NaN"); + } + + int sign = Math.Sign(interval); + interval = Math.Abs(interval); + + string format; + + if (sign >= 0) + { + format = string.Intern("T - {0}"); + } + else + { + format = string.Intern("T + {0}"); + } + + return string.Format(format, VOID_Tools.FormatInterval(interval)); + } + ); + + public static readonly VOID_StrValue burnTimeHalfDoneAtNode = + new VOID_StrValue( + "Full burn time to be half done at node", + delegate() + { + if (Core.LastStage == null && upcomingManeuverNodes < 1) + { + return "N/A"; + } + + ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0]; + + if ((node.UT - Planetarium.GetUniversalTime()) < 0) + { + return string.Empty; + } + + double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); + + if (double.IsNaN(interval)) + { + return string.Intern("NaN"); + } + + int sign = Math.Sign(interval); + interval = Math.Abs(interval); + + string format; + + if (sign >= 0) + { + format = string.Intern("T - {0}"); + } + else + { + format = string.Intern("T + {0}"); + } + + return string.Format(format, VOID_Tools.FormatInterval(interval)); + } + ); + + public static readonly VOID_DoubleValue currManeuverDeltaV = + new VOID_DoubleValue( + "Current Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 0) + { + return Core.Vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + public static readonly VOID_DoubleValue currManeuverDVRemaining = + new VOID_DoubleValue( + "Remaining Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 0) + { + return Core.Vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Core.Vessel.orbit).magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + public static readonly VOID_DoubleValue currentNodeBurnDuration = + new VOID_DoubleValue( + "Total Burn Time", + delegate() + { + if (currManeuverDeltaV.Value == double.NaN) + { + return double.NaN; + } + + return realVesselBurnTime(currManeuverDeltaV.Value); + }, + "s" + ); + + public static readonly VOID_DoubleValue currentNodeBurnRemaining = + new VOID_DoubleValue( + "Burn Time Remaining", + delegate() + { + if (currManeuverDVRemaining.Value == double.NaN) + { + return double.NaN; + } + + return realVesselBurnTime(currManeuverDVRemaining.Value); + }, + "s" + ); + + public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = + new VOID_DoubleValue( + "Half Burn Time", + delegate() + { + if (currManeuverDeltaV.Value == double.NaN) + { + return double.NaN; + } + + return realVesselBurnTime(currManeuverDeltaV.Value / 2d); + }, + "s" + ); + + public static readonly VOID_DoubleValue nextManeuverDeltaV = + new VOID_DoubleValue( + "Current Maneuver Delta-V", + delegate() + { + if (upcomingManeuverNodes > 1) + { + return Core.Vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude; + } + else + { + return double.NaN; + } + }, + "m/s" + ); + + #endregion + + #region Orbits + + public static readonly VOID_StrValue primaryName = + new VOID_StrValue( + VOID_Localization.void_primary, + delegate() + { + if (Core.Vessel == null) + { + return string.Empty; + } + return Core.Vessel.mainBody.name; + } + ); + + public static readonly VOID_DoubleValue orbitAltitude = + new VOID_DoubleValue( + "Altitude (ASL)", + new Func(() => Core.Vessel.orbit.altitude), + "m" + ); + + public static readonly VOID_DoubleValue orbitVelocity = + new VOID_DoubleValue( + VOID_Localization.void_velocity, + new Func(() => Core.Vessel.orbit.vel.magnitude), + "m/s" + ); + + public static readonly VOID_DoubleValue orbitApoAlt = + new VOID_DoubleValue( + VOID_Localization.void_apoapsis, + new Func(() => Core.Vessel.orbit.ApA), + "m" + ); + + public static readonly VOID_DoubleValue oribtPeriAlt = + new VOID_DoubleValue( + VOID_Localization.void_periapsis, + new Func(() => Core.Vessel.orbit.PeA), + "m" + ); + + public static readonly VOID_StrValue timeToApo = + new VOID_StrValue( + "Time to Apoapsis", + new Func(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToAp)) + ); + + public static readonly VOID_StrValue timeToPeri = + new VOID_StrValue( + "Time to Periapsis", + new Func(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToPe)) + ); + + public static readonly VOID_DoubleValue orbitInclination = + new VOID_DoubleValue( + "Inclination", + new Func(() => Core.Vessel.orbit.inclination), + "°" + ); + + public static readonly VOID_DoubleValue gravityAccel = + new VOID_DoubleValue( + "Gravity", + delegate() + { + double orbitRadius = Core.Vessel.mainBody.Radius + + Core.Vessel.mainBody.GetAltitude(Core.Vessel.findWorldCenterOfMass()); + return (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) / + (orbitRadius * orbitRadius); + }, + "m/s²" + ); + + public static readonly VOID_StrValue orbitPeriod = + new VOID_StrValue( + "Period", + new Func(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.period)) + ); + + public static readonly VOID_DoubleValue semiMajorAxis = + new VOID_DoubleValue( + "Semi-Major Axis", + new Func(() => Core.Vessel.orbit.semiMajorAxis), + "m" + ); + + public static readonly VOID_DoubleValue eccentricity = + new VOID_DoubleValue( + "Eccentricity", + new Func(() => Core.Vessel.orbit.eccentricity), + "" + ); + + public static readonly VOID_DoubleValue meanAnomaly = + new VOID_DoubleValue( + "Mean Anomaly", + new Func(() => Core.Vessel.orbit.meanAnomaly * 180d / Math.PI), + "°" + ); + + public static readonly VOID_DoubleValue trueAnomaly = + new VOID_DoubleValue( + "True Anomaly", + new Func(() => Core.Vessel.orbit.trueAnomaly), + "°" + ); + + public static readonly VOID_DoubleValue eccAnomaly = + new VOID_DoubleValue( + "Eccentric Anomaly", + new Func(() => Core.Vessel.orbit.eccentricAnomaly * 180d / Math.PI), + "°" + ); + + public static readonly VOID_DoubleValue longitudeAscNode = + new VOID_DoubleValue( + "Long. Ascending Node", + new Func(() => Core.Vessel.orbit.LAN), + "°" + ); + + public static readonly VOID_DoubleValue argumentPeriapsis = + new VOID_DoubleValue( + "Argument of Periapsis", + new Func(() => 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 = + new VOID_DoubleValue( + "Local Sidereal Longitude", + new Func(() => VOID_Tools.FixDegreeDomain( + Core.Vessel.longitude + Core.Vessel.orbit.referenceBody.rotationAngle)), + "°" + ); + + #endregion + + #region Science + + public static readonly VOID_StrValue expSituation = + new VOID_StrValue( + "Situation", + new Func(() => Core.Vessel.GetExperimentSituation().HumanString()) + ); + + public static readonly VOID_StrValue currBiome = + new VOID_StrValue( + "Biome", + delegate() + { + if (Core.Vessel.landedAt == string.Empty) + { + return VOID_Tools.GetBiome(Core.Vessel).name; + } + else + { + return Core.Vessel.landedAt; + } + } + ); + + #endregion + + #region Surface + + public static readonly VOID_DoubleValue terrainElevation = + new VOID_DoubleValue( + "Terrain elevation", + new Func(() => Core.Vessel.terrainAltitude), + "m" + ); + + #endregion + + private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) + { + Logging.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + + "\tdeltaV: {0}\n" + + "\tinitialMass: {1}\n" + + "\tmassFlow: {2}\n" + + "\tthrust: {3}\n", + deltaV, + initialMass, + massFlow, + thrust + ); + return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust)); + } + + private static double dVfromBurnTime(double time, double initialMass, double massFlow, double thrust) + { + return -thrust / massFlow * Math.Log(1d - time * massFlow / initialMass); + } + + private static double realVesselBurnTime(double deltaV) + { + if (Core.Stages == null || Core.Stages.Length < 1) + { + return double.NaN; + } + + double burntime = 0d; + double dVRemaining = deltaV; + + int stageIdx = Core.Stages.Length - 1; + + while (dVRemaining > double.Epsilon) + { + if (stageIdx < 0) + { + return double.PositiveInfinity; + } + + Stage stage = Core.Stages[stageIdx]; + + if (stage.deltaV > 0) + { + double stageDVUsed = Math.Min(stage.deltaV, dVRemaining); + + burntime += burnTime(stageDVUsed, stage.totalMass, stage.MassFlow(), stage.NominalThrust()); + dVRemaining -= stageDVUsed; + } + + stageIdx--; + } + + return burntime; + } + } +} + --- a/VOID_DataLogger.cs +++ b/VOID_DataLogger.cs @@ -29,7 +29,12 @@ using KSP; using System; using System.Collections.Generic; +using System.IO; +using System.Text; using ToadicusTools; +using ToadicusTools.DebugTools; +using ToadicusTools.GUIUtils; +using ToadicusTools.Text; using UnityEngine; namespace VOID @@ -39,208 +44,492 @@ /* * Fields * */ - protected bool stopwatch1_running; - - protected bool csv_logging; - protected bool first_write; - - protected double stopwatch1; - - protected string csv_log_interval_str; - - protected float csv_log_interval; - - protected double csvWriteTimer; - protected double csvCollectTimer; - - protected List csvList = new List(); + #region Fields + + protected bool _loggingActive; + protected bool firstWrite; + + [AVOID_SaveValue("waitForLaunch")] + protected VOID_SaveValue waitForLaunch; + + [AVOID_SaveValue("logInterval")] + protected VOID_SaveValue logInterval; + protected string logIntervalStr; + + protected float csvCollectTimer; + + protected List csvBytes; + + protected string _fileName; + protected FileStream _outputFile; + + protected uint outstandingWrites; + + protected System.Text.UTF8Encoding _utf8Encoding; + + #endregion /* * Properties * */ + #region Properties + + // TODO: Add configurable or incremental file names. + protected bool loggingActive + { + get + { + return this._loggingActive; + } + set + { + if (value != this._loggingActive) + { + if (value) + { + this.csvCollectTimer = 0f; + } + else + { + this.CloseFileIfOpen(); + } + + this._loggingActive = value; + } + } + } + + protected string fileName + { + get + { + if (this._fileName == null || this._fileName == string.Empty) + { + this._fileName = string.Format( + "{0}/{1}_{2}", + this.core.SaveGamePath, + this.Vessel.vesselName, + "data.csv" + ); + } + + return this._fileName; + } + } + + protected FileStream outputFile + { + get + { + if (this._outputFile == null) + { + using (PooledDebugLogger logger = PooledDebugLogger.New(this)) + { + logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName); + + if (File.Exists(this.fileName)) + { + logger.Append("append"); + this._outputFile = new FileStream( + this.fileName, + FileMode.Append, + FileAccess.Write, + FileShare.Read, + 512, + true + ); + } + else + { + logger.Append("create"); + this._outputFile = new FileStream( + this.fileName, + FileMode.Create, + FileAccess.Write, + FileShare.Read, + 512, + true + ); + + byte[] byteOrderMark = utf8Encoding.GetPreamble(); + + logger.Append(" and writing preamble"); + this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length); + } + + logger.Append('.'); + + logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not "); + + logger.Print(); + } + } + + return this._outputFile; + } + } + + public UTF8Encoding utf8Encoding + { + get + { + if (this._utf8Encoding == null) + { + this._utf8Encoding = new UTF8Encoding(true); + } + + return this._utf8Encoding; + } + } + + #endregion /* * Methods * */ - public VOID_DataLogger() - { - this._Name = "CSV Data Logger"; - - this.stopwatch1_running = false; - - this.csv_logging = false; - this.first_write = true; - - this.stopwatch1 = 0; - this.csv_log_interval_str = "0.5"; - - this.csvWriteTimer = 0; - this.csvCollectTimer = 0; - - this.WindowPos.x = Screen.width - 520; - this.WindowPos.y = 85; - } - - public override void ModuleWindow(int _) - { - GUIStyle txt_white = new GUIStyle(GUI.skin.label); - txt_white.normal.textColor = txt_white.focused.textColor = Color.white; - txt_white.alignment = TextAnchor.UpperRight; - GUIStyle txt_green = new GUIStyle(GUI.skin.label); - txt_green.normal.textColor = txt_green.focused.textColor = Color.green; - txt_green.alignment = TextAnchor.UpperRight; - GUIStyle txt_yellow = new GUIStyle(GUI.skin.label); - txt_yellow.normal.textColor = txt_yellow.focused.textColor = Color.yellow; - txt_yellow.alignment = TextAnchor.UpperRight; - - GUILayout.BeginVertical(); - - GUILayout.Label("System time: " + DateTime.Now.ToString("HH:mm:ss")); - GUILayout.Label(VOID_Tools.ConvertInterval(stopwatch1)); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - if (GUILayout.Button("Start")) - { - if (stopwatch1_running == false) stopwatch1_running = true; - } - if (GUILayout.Button("Stop")) - { - if (stopwatch1_running == true) stopwatch1_running = false; - } - if (GUILayout.Button("Reset")) - { - if (stopwatch1_running == true) stopwatch1_running = false; - stopwatch1 = 0; - } - GUILayout.EndHorizontal(); - - GUIStyle label_style = txt_white; - string log_label = "Inactive"; - if (csv_logging && vessel.situation.ToString() == "PRELAUNCH") - { - log_label = "Awaiting launch"; - label_style = txt_yellow; - } - if (csv_logging && vessel.situation.ToString() != "PRELAUNCH") - { - log_label = "Active"; - label_style = txt_green; - } - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - csv_logging = GUILayout.Toggle(csv_logging, "Data logging: ", GUILayout.ExpandWidth(false)); - GUILayout.Label(log_label, label_style, GUILayout.ExpandWidth(true)); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false)); - csv_log_interval_str = GUILayout.TextField(csv_log_interval_str, GUILayout.ExpandWidth(true)); - GUILayout.Label("s", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - - float new_log_interval; - if (Single.TryParse(csv_log_interval_str, out new_log_interval)) csv_log_interval = new_log_interval; - - GUILayout.EndVertical(); - GUI.DragWindow(); - } - + #region Monobehaviour Lifecycle public void Update() { + if (this.csvBytes != null && this.csvBytes.Count > 0) + { + // csvList is not empty, write it + this.AsyncWriteData(); + } + // CSV Logging // from ISA MapSat - if (csv_logging) + if (loggingActive && (!waitForLaunch || this.Vessel.situation != Vessel.Situations.PRELAUNCH)) { //data logging is on //increment timers - csvWriteTimer += Time.deltaTime; - csvCollectTimer += Time.deltaTime; - - if (csvCollectTimer >= csv_log_interval && vessel.situation != Vessel.Situations.PRELAUNCH) + this.csvCollectTimer += Time.deltaTime; + + if (this.csvCollectTimer >= this.logInterval) { //data logging is on, vessel is not prelaunch, and interval has passed //write a line to the list - line_to_csvList(); //write to the csv - } - - if (csvList.Count != 0 && csvWriteTimer >= 15f) - { - // csvList is not empty and interval between writings to file has elapsed - //write it - string[] csvData; - csvData = (string[])csvList.ToArray(); - Innsewerants_writeData(csvData); - csvList.Clear(); - csvWriteTimer = 0f; - } - } - else - { - //data logging is off - //reset any timers and clear anything from csvList - csvWriteTimer = 0f; - csvCollectTimer = 0f; - if (csvList.Count > 0) csvList.Clear(); - } - - if (stopwatch1_running) - { - stopwatch1 += Time.deltaTime; + this.CollectLogData(); + } } } public void FixedUpdate() {} - private void Innsewerants_writeData(string[] csvArray) - { - var efile = KSP.IO.File.AppendText(vessel.vesselName + "_data.csv", null); - foreach (string line in csvArray) - { - efile.Write(line); - } - efile.Close(); - } - - private void line_to_csvList() - { + public void OnDestroy() + { + using (PooledDebugLogger logger = PooledDebugLogger.New(this)) + { + logger.Append("Destroying..."); + + this.CloseFileIfOpen(); + + logger.Append(" Done."); + logger.Print(false); + } + } + + #endregion + + #region VOID_Module Overrides + + public override void LoadConfig(KSP.IO.PluginConfiguration config) + { + base.LoadConfig(config); + + this.logIntervalStr = this.logInterval.value.ToString("#.0##"); + } + + public override void ModuleWindow(int id) + { + GUILayout.BeginVertical(); + + GUILayout.Label( + string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")), + GUILayout.ExpandWidth(true) + ); + GUILayout.Label( + string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())), + GUILayout.ExpandWidth(true) + ); + + GUIStyle activeLabelStyle = VOID_Styles.labelRed; + string activeLabelText = "Inactive"; + if (loggingActive) + { + activeLabelText = "Active"; + activeLabelStyle = VOID_Styles.labelGreen; + } + + this.loggingActive = Layout.Toggle( + loggingActive, + string.Format("Data logging: {0}", activeLabelText), + null, + activeLabelStyle + ); + + this.waitForLaunch.value = Layout.Toggle( + this.waitForLaunch, + "Wait for launch" + ); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false)); + + logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true)); + GUILayout.Label("s", GUILayout.ExpandWidth(false)); + + GUILayout.EndHorizontal(); + + float newLogInterval; + if (float.TryParse(logIntervalStr, out newLogInterval)) + { + logInterval.value = newLogInterval; + this.logIntervalStr = this.logInterval.value.ToString("#.0##"); + } + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + + #endregion + + #region Data Collection + + private void CollectLogData() + { + if (this.csvBytes == null) + { + this.csvBytes = new List(); + } + //called if logging is on and interval has passed //writes one line to the csvList - string line = ""; - if (first_write && !KSP.IO.File.Exists(vessel.vesselName + "_data.csv", null)) - { - first_write = false; - line += "Mission Elapsed Time (s);Altitude ASL (m);Altitude above terrain (m);Orbital Velocity (m/s);Surface Velocity (m/s);Vertical Speed (m/s);Horizontal Speed (m/s);Gee Force (gees);Temperature (°C);Gravity (m/s²);Atmosphere Density (g/m³);\n"; - } - //Mission time - line += vessel.missionTime.ToString("F3") + ";"; - //Altitude ASL - line += vessel.orbit.altitude.ToString("F3") + ";"; - //Altitude (true) - double alt_true = vessel.orbit.altitude - vessel.terrainAltitude; - if (vessel.terrainAltitude < 0) alt_true = vessel.orbit.altitude; - line += alt_true.ToString("F3") + ";"; - //Orbital velocity - line += vessel.orbit.vel.magnitude.ToString("F3") + ";"; - //surface velocity - line += vessel.srf_velocity.magnitude.ToString("F3") + ";"; - //vertical speed - line += vessel.verticalSpeed.ToString("F3") + ";"; - //horizontal speed - line += vessel.horizontalSrfSpeed.ToString("F3") + ";"; - //gee force - line += vessel.geeForce.ToString("F3") + ";"; - //temperature - line += vessel.flightIntegrator.getExternalTemperature().ToString("F2") + ";"; - //gravity - double r_vessel = vessel.mainBody.Radius + vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); - double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / (r_vessel * r_vessel); - line += g_vessel.ToString("F3") + ";"; - //atm density - line += (vessel.atmDensity * 1000).ToString("F3") + ";"; - line += "\n"; - if (csvList.Contains(line) == false) csvList.Add(line); - csvCollectTimer = 0f; - } + using (PooledStringBuilder line = PooledStringBuilder.Get()) + { + if (firstWrite) + { + firstWrite = false; + line.Append( + "\"Kerbin Universal Time (s)\"," + + "\"Mission Elapsed Time (s)\t\"," + + "\"Altitude ASL (m)\"," + + "\"Altitude above terrain (m)\"," + + "\"Surface Latitude (°)\"," + + "\"Surface Longitude (°)\"," + + "\"Apoapsis Altitude (m)\"," + + "\"Periapsis Altitude (m)\"," + + "\"Orbital Inclination (°)\"," + + "\"Orbital Velocity (m/s)\"," + + "\"Surface Velocity (m/s)\"," + + "\"Vertical Speed (m/s)\"," + + "\"Horizontal Speed (m/s)\"," + + "\"Current Thrust (kN)\"," + + "\"Gee Force (gees)\"," + + "\"Temperature (°C)\"," + + "\"Gravity (m/s²)\"," + + "\"Atmosphere Density (g/m³)\"," + + "\"Downrange Distance (m)\"," + + "\"Main Throttle\"," + + "\n" + ); + } + + // Universal time + line.Append(Planetarium.GetUniversalTime().ToString("F2")); + line.Append(','); + + //Mission time + line.Append(Vessel.missionTime.ToString("F3")); + line.Append(','); + + //Altitude ASL + line.Append(VOID_Data.orbitAltitude.Value.ToString("G9")); + line.Append(','); + + //Altitude (true) + line.Append(VOID_Data.trueAltitude.Value.ToString("G9")); + line.Append(','); + + // Surface Latitude + line.Append('"'); + line.Append(VOID_Data.surfLatitude.Value.ToString("F3")); + line.Append('"'); + line.Append(','); + + // Surface Longitude + line.Append('"'); + line.Append(VOID_Data.surfLongitude.Value.ToString("F3")); + line.Append('"'); + line.Append(','); + + // Apoapsis Altitude + line.Append(VOID_Data.orbitApoAlt.Value.ToString("G9")); + line.Append(','); + + // Periapsis Altitude + line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G9")); + line.Append(','); + + // Orbital Inclination + line.Append(VOID_Data.orbitInclination.Value.ToString("F2")); + line.Append(','); + + //Orbital velocity + line.Append(VOID_Data.orbitVelocity.Value.ToString("G9")); + line.Append(','); + + //surface velocity + line.Append(VOID_Data.surfVelocity.Value.ToString("G9")); + line.Append(','); + + //vertical speed + line.Append(VOID_Data.vertVelocity.Value.ToString("G9")); + line.Append(','); + + //horizontal speed + line.Append(VOID_Data.horzVelocity.Value.ToString("G9")); + line.Append(','); + + // Current Thrust + line.Append(VOID_Data.currThrust.Value.ToString("G9")); + line.Append(','); + + //gee force + line.Append(VOID_Data.geeForce.Value.ToString("G9")); + line.Append(','); + + //temperature + line.Append(VOID_Data.temperature.Value.ToString("F3")); + line.Append(','); + + //gravity + line.Append(VOID_Data.gravityAccel.Value.ToString("G9")); + line.Append(','); + + //atm density + line.Append(VOID_Data.atmDensity.Value.ToString("G9")); + line.Append(','); + + // Downrange Distance + line.Append((VOID_Data.downrangeDistance.Value.ToString("G9"))); + line.Append(','); + + // Main Throttle + line.Append(VOID_Data.mainThrottle.Value.ToString("P2")); + + line.Append('\n'); + + csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString())); + + this.csvCollectTimer = 0f; + } + } + + #endregion + + #region File IO Methods + + protected void AsyncWriteCallback(IAsyncResult result) + { + Logging.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted); + + this.outputFile.EndWrite(result); + this.outstandingWrites--; + } + + private void AsyncWriteData() + { + WriteState state = new WriteState(); + + state.bytes = this.csvBytes.ToArray(); + state.stream = this.outputFile; + + this.outstandingWrites++; + var writeCallback = new AsyncCallback(this.AsyncWriteCallback); + + this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state); + + this.csvBytes.Clear(); + } + + private void CloseFileIfOpen() + { + using (PooledDebugLogger logger = PooledDebugLogger.New(this)) + { + logger.AppendFormat("Cleaning up file {0}...", this.fileName); + + if (this.csvBytes != null && this.csvBytes.Count > 0) + { + logger.Append(" Writing remaining data..."); + this.AsyncWriteData(); + } + + logger.Append(" Waiting for writes to finish."); + while (this.outstandingWrites > 0) + { + logger.Append('.'); + System.Threading.Thread.Sleep(10); + } + + if (this._outputFile != null) + { + this._outputFile.Close(); + this._outputFile = null; + logger.Append(" File closed."); + } + + logger.Print(false); + } + } + + #endregion + + #region Constructors & Destructors + + public VOID_DataLogger() + { + this.Name = "CSV Data Logger"; + + this.loggingActive = false; + this.firstWrite = true; + + this.waitForLaunch = (VOID_SaveValue)true; + + this.logInterval = (VOID_SaveValue)0.5f; + this.csvCollectTimer = (VOID_SaveValue)0f; + + this.outstandingWrites = 0; + + this.WindowPos.x = Screen.width - 520f; + this.WindowPos.y = 85f; + + this.core.onApplicationQuit += delegate(object sender) + { + this.CloseFileIfOpen(); + }; + } + + ~VOID_DataLogger() + { + this.OnDestroy(); + } + + #endregion + + #region Subclasses + + private class WriteState + { + public byte[] bytes; + public FileStream stream; + } + + #endregion } } + + --- a/VOID_DataValue.cs +++ /dev/null @@ -1,350 +1,1 @@ -// VOID -// -// VOID_DataValue.cs -// -// Copyright © 2014, 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 System; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public interface IVOID_DataValue - { - void Refresh(); - string ValueUnitString(); - void DoGUIHorizontal(); - } - - public class VOID_DataValue : IVOID_DataValue - { - /* - * Static Members - * */ - public static implicit operator T(VOID_DataValue v) - { - return (T)v.Value; - } - - /* - * Instance Members - * */ - /* - * Fields - * */ - protected T cache; - protected Func ValueFunc; - protected float lastUpdate; - - /* - * Properties - * */ - public string Label { get; protected set; } - public string Units { get; protected set; } - - public T Value - { - get - { - if ( - HighLogic.LoadedSceneIsEditor || - (VOID_Core.Instance.updateTimer - this.lastUpdate > VOID_Core.Instance.updatePeriod) || - (this.lastUpdate > VOID_Core.Instance.updateTimer) - ) - { - this.Refresh(); - } - return (T)this.cache; - } - } - - /* - * Methods - * */ - public VOID_DataValue(string Label, Func ValueFunc, string Units = "") - { - this.Label = Label; - this.Units = Units; - this.ValueFunc = ValueFunc; - this.lastUpdate = 0; - } - - public void Refresh() - { - this.cache = this.ValueFunc.Invoke (); - this.lastUpdate = VOID_Core.Instance.updateTimer; - } - - public T GetFreshValue() - { - this.Refresh (); - return (T)this.cache; - } - - public virtual string ValueUnitString() { - return this.Value.ToString() + this.Units; - } - - public virtual void DoGUIHorizontal() - { - GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); - GUILayout.Label (this.Label + ":"); - GUILayout.FlexibleSpace (); - GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false)); - GUILayout.EndHorizontal (); - } - - public override string ToString() - { - return string.Format ( - "{0}: {1}{2}", - this.Label, - this.Value.ToString (), - this.Units - ); - } - } - - public abstract class VOID_NumValue : VOID_DataValue - where T : IFormattable, IConvertible, IComparable - { - public static implicit operator Double(VOID_NumValue v) - { - return v.ToDouble(); - } - - public static implicit operator Int32(VOID_NumValue v) - { - return v.ToInt32(); - } - - - public static implicit operator Single(VOID_NumValue v) - { - return v.ToSingle(); - } - - protected IFormatProvider formatProvider; - - public VOID_NumValue(string Label, Func ValueFunc, string Units = "") : base(Label, ValueFunc, Units) - { - this.formatProvider = System.Globalization.CultureInfo.CurrentUICulture; - } - - public virtual double ToDouble(IFormatProvider provider) - { - return this.Value.ToDouble(provider); - } - - public virtual double ToDouble() - { - return this.ToDouble(this.formatProvider); - } - - public virtual int ToInt32(IFormatProvider provider) - { - return this.Value.ToInt32(provider); - } - - public virtual int ToInt32() - { - return this.ToInt32(this.formatProvider); - } - - public virtual float ToSingle(IFormatProvider provider) - { - return this.Value.ToSingle(provider); - } - - public virtual float ToSingle() - { - return this.ToSingle(this.formatProvider); - } - - public virtual string ToString(string Format) - { - return string.Format ( - "{0}: {1}{2}", - this.Label, - this.Value.ToString(Format, this.formatProvider), - this.Units - ); - } - - public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue) - { - return string.Format ( - "{0}{1}", - Tools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude), - this.Units - ); - } - - public virtual string ValueUnitString(string format) - { - return this.Value.ToString(format, this.formatProvider) + this.Units; - } - - public virtual string ValueUnitString(int digits) { - return Tools.MuMech_ToSI(this, digits) + this.Units; - } - - public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude) - { - return Tools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units; - } - - public virtual void DoGUIHorizontal(string format) - { - GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); - GUILayout.Label (this.Label + ":"); - GUILayout.FlexibleSpace (); - GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false)); - GUILayout.EndHorizontal (); - } - - public virtual int DoGUIHorizontal(int digits, bool precisionButton = true) - { - if (precisionButton) - { - return this.DoGUIHorizontalPrec(digits); - } - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true)); - GUILayout.FlexibleSpace(); - GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - - return digits; - } - - public virtual int DoGUIHorizontalPrec(int digits) - { - double magnitude; - double magLimit; - - magnitude = Math.Log10(Math.Abs((double)this)); - - magLimit = Math.Max(Math.Abs(magnitude), 3d) + 3d; - magLimit = Math.Round(Math.Ceiling(magLimit / 3f)) * 3d; - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true)); - GUILayout.FlexibleSpace(); - - if (magnitude >= 0) - { - GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false)); - } - else - { - GUILayout.Label(this.ValueUnitString(3, (int)magnitude + digits, int.MaxValue), GUILayout.ExpandWidth(false)); - } - GUILayout.EndHorizontal(); - - if (Event.current.type == EventType.mouseUp) - { - Rect lastRect = GUILayoutUtility.GetLastRect(); - if (lastRect.Contains(Event.current.mousePosition)) - { - Tools.PostDebugMessage(string.Format("{0}: Changing digits from {1} within magLimit {2}.", - this.GetType().Name, - digits, - magLimit)); - - if (Event.current.button == 0) - { - digits = (digits + 3) % (int)magLimit; - } - else if (Event.current.button == 1) - { - digits = (digits - 3) % (int)magLimit; - } - - if (digits < 0) - { - digits += (int)magLimit; - } - - Tools.PostDebugMessage(string.Format("{0}: Changed digits to {1}." + - "\n\tNew minMagnitude: {2}, maxMagnitude: {3}" + - "\n\tMagnitude: {4}", - this.GetType().Name, - digits, - magnitude >= 0 ? int.MinValue : (int)magnitude - 4 + digits, - magnitude >= 0 ? (int)magnitude - digits : int.MaxValue, - magnitude - )); - } - } - - return digits; - } - } - - public class VOID_DoubleValue : VOID_NumValue - { - public VOID_DoubleValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} - } - - public class VOID_FloatValue : VOID_NumValue - { - public VOID_FloatValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} - } - - public class VOID_IntValue : VOID_NumValue - { - public VOID_IntValue(string Label, Func ValueFunc, string Units) : base(Label, ValueFunc, Units) {} - } - - public class VOID_StrValue : VOID_DataValue - { - public VOID_StrValue(string Label, Func ValueFunc) : base(Label, ValueFunc, "") {} - } - - public class VOID_Vector3dValue : VOID_DataValue - { - public VOID_Vector3dValue(string Label, Func ValueFunc, string Units) - : base(Label, ValueFunc, Units) - {} - - public string ToString(string format) - { - return string.Format("{0}: {1}{2}", - this.Label, - this.Value.ToString(format), - this.Units - ); - } - - public string ValueUnitString(string format) { - return this.Value.ToString(format) + this.Units; - } - } -} - - --- a/VOID_EditorCore.cs +++ /dev/null @@ -1,149 +1,1 @@ -// VOID -// -// VOID_EditorCore.cs -// -// Copyright © 2014, 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 Engineer.VesselSimulator; -using KSP; -using System; -using System.Collections.Generic; -using System.Linq; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public class VOID_EditorCore : VOID_Core - { - /* - * Static Members - * */ - protected new static bool _initialized = false; - public new static bool Initialized - { - get - { - return _initialized; - } - } - - protected new static VOID_EditorCore _instance; - public new static VOID_EditorCore Instance - { - get - { - if (_instance == null) - { - _instance = new VOID_EditorCore(); - _initialized = true; - } - return _instance; - } - } - - public new static void Reset() - { - if (_initialized) - { - _instance.StopGUI(); - _instance = null; - _initialized = false; - } - } - - public VOID_EditorCore() : base() - { - this._Name = "VOID Editor Core"; - } - - public new void OnGUI() {} - - public override void DrawGUI() - { - if (!this._modulesLoaded) - { - this.LoadModulesOfType(); - } - - Rect _iconPos = Tools.DockToWindow (this.VOIDIconPos, this.mainWindowPos); - - _iconPos = Tools.ClampRectToScreen (_iconPos, (int)_iconPos.width, (int)_iconPos.height); - - if (_iconPos != this.VOIDIconPos) - { - this.VOIDIconPos = _iconPos; - } - - base.DrawGUI(); - } - - public new void Update() - { - foreach (IVOID_EditorModule module in this.Modules) - { - if (EditorLogic.startPod == null) - { - module.StopGUI(); - continue; - } - if (HighLogic.LoadedSceneIsEditor && module.toggleActive && EditorLogic.SortedShipList.Any()) - { - module.StartGUI(); - } - if (!HighLogic.LoadedSceneIsEditor || !module.toggleActive || !EditorLogic.SortedShipList.Any()) - { - module.StopGUI(); - } - } - - if (EditorLogic.startPod == null || !HighLogic.LoadedSceneIsEditor) - { - this.StopGUI(); - return; - } - else if (!this.guiRunning && HighLogic.LoadedSceneIsEditor) - { - this.StartGUI(); - } - - if (EditorLogic.SortedShipList.Count > 0 && this.vesselSimActive) - { - SimManager.Gravity = VOID_Data.KerbinGee; - SimManager.TryStartSimulation(); - } - else if (!this.vesselSimActive) - { - SimManager.ClearResults(); - } - - this.CheckAndSave (); - } - - public new void FixedUpdate() {} - } -} - - --- a/VOID_EditorHUD.cs +++ b/VOID_EditorHUD.cs @@ -26,61 +26,44 @@ // 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 Engineer.VesselSimulator; +using KerbalEngineer.VesselSimulator; using KSP; using System; using System.Collections.Generic; -using System.Linq; using System.Text; using ToadicusTools; +using ToadicusTools.Text; using UnityEngine; namespace VOID { - public class VOID_EditorHUD : VOID_Module, IVOID_EditorModule + [VOID_Scenes(GameScenes.EDITOR)] + public class VOID_EditorHUD : VOID_HUDModule { /* * Fields * */ - [AVOID_SaveValue("colorIndex")] - protected VOID_SaveValue _colorIndex = 0; - - protected List textColors = new List(); - - protected GUIStyle labelStyle; - + protected HUDWindow ehudWindow; protected EditorVesselOverlays _vesselOverlays; + + [AVOID_SaveValue("snapToLeft")] + protected VOID_SaveValue snapToLeft; /* * Properties * */ - public int ColorIndex + protected EditorVesselOverlays vesselOverlays { get { - return this._colorIndex; - } - set - { - if (this._colorIndex >= this.textColors.Count - 1) - { - this._colorIndex = 0; - return; - } - - this._colorIndex = value; - } - } - - protected EditorVesselOverlays vesselOverlays - { - get - { if (this._vesselOverlays == null) { - this._vesselOverlays = (EditorVesselOverlays)Resources - .FindObjectsOfTypeAll(typeof(EditorVesselOverlays)) - .FirstOrDefault(); + UnityEngine.Object[] overlayObjs = Resources.FindObjectsOfTypeAll(typeof(EditorVesselOverlays)); + + if (overlayObjs.Length > 0) + { + this._vesselOverlays = (EditorVesselOverlays)overlayObjs[0]; + } } return this._vesselOverlays; @@ -118,110 +101,150 @@ * */ public VOID_EditorHUD() : base() { - this._Name = "Heads-Up Display"; - - this._Active.value = true; - - this.textColors.Add(Color.green); - this.textColors.Add(Color.black); - this.textColors.Add(Color.white); - this.textColors.Add(Color.red); - this.textColors.Add(Color.blue); - this.textColors.Add(Color.yellow); - this.textColors.Add(Color.gray); - this.textColors.Add(Color.cyan); - this.textColors.Add(Color.magenta); - - this.labelStyle = new GUIStyle (); - // this.labelStyle.alignment = TextAnchor.UpperRight; - this.labelStyle.normal.textColor = this.textColors [this.ColorIndex]; - - Tools.PostDebugMessage (this.GetType().Name + ": Constructed."); - } - - public override void DrawGUI() - { - SimManager.RequestSimulation(); - - if (SimManager.LastStage == null) + this.Name = "Heads-Up Display"; + + this.Active = true; + + this.snapToLeft.value = true; + + this.ehudWindow = new HUDWindow( + "editorHUD", + this.ehudWindowFunc, + new Rect(/*EditorPanels.Instance.partsPanelWidth + */10f, 125f, 300f, 64f) + ); + this.Windows.Add(this.ehudWindow); + + Logging.PostDebugMessage (this.GetType().Name + ": Constructed."); + } + + public void ehudWindowFunc(int id) + { + using (PooledStringBuilder hudString = PooledStringBuilder.Get()) + { + if (this.core.LastStage == null) + { + return; + } + + VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; + + hudString.Append("Total Mass: "); + hudString.Append(this.core.LastStage.totalMass.ToString("F3")); + hudString.Append('t'); + + hudString.Append(' '); + + hudString.Append("Part Count: "); + hudString.Append(EditorLogic.SortedShipList.Count); + + hudString.Append('\n'); + + hudString.Append("Total Delta-V: "); + hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.totalDeltaV)); + hudString.Append("m/s"); + + hudString.Append('\n'); + + hudString.Append("Bottom Stage Delta-V: "); + hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.deltaV)); + hudString.Append("m/s"); + + hudString.Append('\n'); + + hudString.Append("Bottom Stage T/W Ratio: "); + hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3")); + + Logging.PostDebugMessage(this, + "CoMmarker.gameObject.activeInHierarchy: {0};" + + "CoTmarker.gameObject.activeInHierarchy: {1}", + this.CoMmarker.gameObject.activeInHierarchy, + this.CoTmarker.gameObject.activeInHierarchy + ); + + if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy) + { + Logging.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset."); + hudString.Append('\n'); + + hudString.Append("Thrust Offset: "); + hudString.Append( + Vector3.Cross( + this.CoTmarker.dirMarkerObject.transform.forward, + this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position + ).ToString("F3")); + } + #if DEBUG + else + { + Logging.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped."); + } + #endif + + GUILayout.Label( + hudString.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); + + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + } + } + + public override void DrawGUI(object sender) + { + float hudLeft; + + if (EditorLogic.fetch.editorScreen == EditorScreen.Parts) + { + hudLeft = /*EditorPanels.Instance.partsPanelWidth + */10f; + hudLeft += /*EditorPartList.Instance.transformTopLeft.position.x -*/ + /*EditorPartList.Instance.transformTopLeft.parent.parent.position.x -*/ + 72f; + } + else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions) + { + hudLeft = /*EditorPanels.Instance.actionsPanelWidth +*/ 10f; + } + else { return; } - float hudLeft; - StringBuilder hudString; - - if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Parts) - { - hudLeft = EditorPanels.Instance.partsPanelWidth + 10; - } - else if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions) - { - hudLeft = EditorPanels.Instance.actionsPanelWidth + 10; + /*Logging.PostDebugMessage(this, + "EditorPartList topLeft.parent.parent.position: {0}\n" + + "EditorPartList topLeft.parent.position: {1}\n" + + "EditorPartList topLeft.position: {2}\n" + + "snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})", + EditorPartList.Instance.transformTopLeft.parent.parent.position, + EditorPartList.Instance.transformTopLeft.parent.position, + EditorPartList.Instance.transformTopLeft.position, + this.snapToLeft, this.ehudWindow.WindowPos.xMin, hudLeft + );*/ + + base.DrawGUI(this); + + Rect hudPos = this.ehudWindow.WindowPos; + + if (this.snapToLeft && this.positionsLocked) + { + hudPos.xMin = hudLeft; } else { - return; - } - - Rect hudPos = new Rect (hudLeft, 48, 300, 32); - - hudString = new StringBuilder(); - - // GUI.skin = AssetBase.GetGUISkin("KSP window 2"); - - labelStyle.normal.textColor = textColors [ColorIndex]; - - hudString.Append("Total Mass: "); - hudString.Append(SimManager.LastStage.totalMass.ToString("F3")); - hudString.Append('t'); - - hudString.Append(' '); - - hudString.Append("Part Count: "); - hudString.Append(EditorLogic.SortedShipList.Count); - - hudString.Append('\n'); - - hudString.Append("Total Delta-V: "); - hudString.Append(Tools.MuMech_ToSI(SimManager.LastStage.totalDeltaV)); - hudString.Append("m/s"); - - hudString.Append('\n'); - - hudString.Append("Bottom Stage Delta-V"); - hudString.Append(Tools.MuMech_ToSI(SimManager.LastStage.deltaV)); - hudString.Append("m/s"); - - hudString.Append('\n'); - - hudString.Append("Bottom Stage T/W Ratio: "); - hudString.Append(SimManager.LastStage.thrustToWeight.ToString("F3")); - - if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy) - { - hudString.Append('\n'); - - hudString.Append("Thrust Offset: "); - hudString.Append( - Vector3.Cross( - this.CoTmarker.dirMarkerObject.transform.forward, - this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position - ).ToString("F3")); - } - - GUI.Label ( - hudPos, - hudString.ToString(), - labelStyle); - } - - public override void DrawConfigurables() - { - if (GUILayout.Button ("Change HUD color", GUILayout.ExpandWidth (false))) - { - ++this.ColorIndex; - } + hudPos.xMin = Mathf.Max(hudLeft, hudPos.xMin); + } + + hudPos.width = this.ehudWindow.defaultWindowPos.width; + + this.ehudWindow.WindowPos = hudPos; + + this.snapToLeft.value = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f; } } } --- a/VOID_HUD.cs +++ b/VOID_HUD.cs @@ -26,249 +26,161 @@ // 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 Engineer.VesselSimulator; +using KerbalEngineer.VesselSimulator; using KSP; using System; using System.Collections.Generic; using System.Text; using ToadicusTools; +using ToadicusTools.Text; using UnityEngine; namespace VOID { - public class VOID_HUD : VOID_Module, IVOID_Module + public class VOID_HUD : VOID_HUDModule, IVOID_Module { /* * Fields * */ - [AVOID_SaveValue("colorIndex")] - protected VOID_SaveValue _colorIndex; - - protected List textColors; - - protected Rect leftHUDdefaultPos; - protected Rect rightHUDdefaultPos; - - [AVOID_SaveValue("leftHUDPos")] - protected VOID_SaveValue leftHUDPos; - [AVOID_SaveValue("rightHUDPos")] - protected VOID_SaveValue rightHUDPos; - - [AVOID_SaveValue("positionsLocked")] - protected VOID_SaveValue positionsLocked; + protected HUDWindow leftHUD; + protected HUDWindow rightHUD; /* * Properties * */ - public int ColorIndex - { - get - { - return this._colorIndex; - } - set - { - if (this._colorIndex >= this.textColors.Count - 1) - { - this._colorIndex = 0; - return; - } - - this._colorIndex = value; - } - } /* * Methods * */ public VOID_HUD() : base() { - this._Name = "Heads-Up Display"; + this.Name = "Heads-Up Display"; - this._Active.value = true; + this.Active = true; - this._colorIndex = 0; + this.leftHUD = new HUDWindow("leftHUD", this.leftHUDWindow, new Rect((float)Screen.width * .375f - 300f, 0f, 300f, 90f)); + this.Windows.Add(this.leftHUD); - this.textColors = new List(); + this.rightHUD = new HUDWindow("rightHUD", this.rightHUDWindow, new Rect((float)Screen.width * .625f, 0f, 300f, 90f)); + this.Windows.Add(this.rightHUD); - this.textColors.Add(Color.green); - this.textColors.Add(Color.black); - this.textColors.Add(Color.white); - this.textColors.Add(Color.red); - this.textColors.Add(Color.blue); - this.textColors.Add(Color.yellow); - this.textColors.Add(Color.gray); - this.textColors.Add(Color.cyan); - this.textColors.Add(Color.magenta); - - this.leftHUDdefaultPos = new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f); - this.leftHUDPos = new Rect(this.leftHUDdefaultPos); - - this.rightHUDdefaultPos = new Rect(Screen.width * .625f, 0f, 300f, 90f); - this.rightHUDPos = new Rect(this.rightHUDdefaultPos); - - this.positionsLocked = true; - - Tools.PostDebugMessage ("VOID_HUD: Constructed."); + Logging.PostDebugMessage ("VOID_HUD: Constructed."); } protected void leftHUDWindow(int id) { - StringBuilder leftHUD; + using (PooledStringBuilder leftHUD = PooledStringBuilder.Get()) + { + VOID_Styles.labelHud.alignment = TextAnchor.UpperRight; - leftHUD = new StringBuilder(); + if (this.core.powerAvailable) + { + leftHUD.AppendFormat("Primary: {0} Inc: {1}", + VOID_Data.primaryName.ValueUnitString(), + VOID_Data.orbitInclination.ValueUnitString("F3") + ); + leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}", + VOID_Data.orbitAltitude.ToSIString(), + VOID_Data.orbitVelocity.ToSIString() + ); + leftHUD.AppendFormat("\nAp: {0} ETA {1}", + VOID_Data.orbitApoAlt.ToSIString(), + VOID_Data.timeToApo.ValueUnitString() + ); + leftHUD.AppendFormat("\nPe: {0} ETA {1}", + VOID_Data.oribtPeriAlt.ToSIString(), + VOID_Data.timeToPeri.ValueUnitString() + ); + leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}", + VOID_Data.totalDeltaV.ToSIString(2), + VOID_Data.stageDeltaV.ToSIString(2) + ); + } + else + { + VOID_Styles.labelHud.normal.textColor = Color.red; + leftHUD.Append(string.Intern("-- POWER LOST --")); + } - this.core.LabelStyles["hud"].alignment = TextAnchor.UpperRight; + GUILayout.Label( + leftHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); - if (this.core.powerAvailable) - { - leftHUD.AppendFormat("Primary: {0} Inc: {1}", - VOID_Data.primaryName.ValueUnitString(), - VOID_Data.orbitInclination.ValueUnitString("F3") - ); - leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}", - VOID_Data.orbitAltitude.ToSIString(), - VOID_Data.orbitVelocity.ToSIString() - ); - leftHUD.AppendFormat("\nAp: {0} ETA {1}", - VOID_Data.orbitApoAlt.ToSIString(), - VOID_Data.timeToApo.ValueUnitString() - ); - leftHUD.AppendFormat("\nPe: {0} ETA {1}", - VOID_Data.oribtPeriAlt.ToSIString(), - VOID_Data.timeToPeri.ValueUnitString() - ); - leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}", - VOID_Data.totalDeltaV.ToSIString(2), - VOID_Data.stageDeltaV.ToSIString(2) - ); + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); } - else - { - this.core.LabelStyles["hud"].normal.textColor = Color.red; - leftHUD.Append(string.Intern("-- POWER LOST --")); - } - - GUILayout.Label(leftHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); - - if (!this.positionsLocked) - { - GUI.DragWindow(); - } - - GUI.BringWindowToBack(id); } protected void rightHUDWindow(int id) { - StringBuilder rightHUD; + using (PooledStringBuilder rightHUD = PooledStringBuilder.Get()) + { + VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; - rightHUD = new StringBuilder(); + if (this.core.powerAvailable) + { + rightHUD.AppendFormat("Biome: {0} Sit: {1}", + VOID_Data.currBiome.ValueUnitString(), + VOID_Data.expSituation.ValueUnitString() + ); + rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}", + VOID_Data.trueAltitude.ToSIString(), + VOID_Data.surfVelocity.ToSIString() + ); + rightHUD.AppendFormat("\nVer: {0} Hor: {1}", + VOID_Data.vertVelocity.ToSIString(), + VOID_Data.horzVelocity.ToSIString() + ); + rightHUD.AppendFormat("\nLat: {0} Lon: {1}", + VOID_Data.surfLatitudeString.ValueUnitString(), + VOID_Data.surfLongitudeString.ValueUnitString() + ); + rightHUD.AppendFormat("\nHdg: {0} Pit: {1}", + VOID_Data.vesselHeading.ValueUnitString(), + VOID_Data.vesselPitch.ToSIString(2) + ); - this.core.LabelStyles["hud"].alignment = TextAnchor.UpperLeft; - - if (this.core.powerAvailable) - { - rightHUD.AppendFormat("Biome: {0} Sit: {1}", - VOID_Data.currBiome.ValueUnitString(), - VOID_Data.expSituation.ValueUnitString() - ); - rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}", - VOID_Data.trueAltitude.ToSIString(), - VOID_Data.surfVelocity.ToSIString() - ); - rightHUD.AppendFormat("\nVer: {0} Hor: {1}", - VOID_Data.vertVelocity.ToSIString(), - VOID_Data.horzVelocity.ToSIString() - ); - rightHUD.AppendFormat("\nLat: {0} Lon: {1}", - VOID_Data.surfLatitude.ValueUnitString(), - VOID_Data.surfLongitude.ValueUnitString() - ); - rightHUD.AppendFormat("\nHdg: {0} Pit: {1}", - VOID_Data.vesselHeading.ValueUnitString(), - VOID_Data.vesselPitch.ToSIString(2) - ); - } - else - { - this.core.LabelStyles["hud"].normal.textColor = Color.red; - rightHUD.Append(string.Intern("-- POWER LOST --")); - } + if ( + this.core.Vessel.mainBody == this.core.HomeBody && + ( + this.core.Vessel.situation == Vessel.Situations.FLYING || + this.core.Vessel.situation == Vessel.Situations.SUB_ORBITAL || + this.core.Vessel.situation == Vessel.Situations.LANDED || + this.core.Vessel.situation == Vessel.Situations.SPLASHED + )) + { + rightHUD.AppendFormat("\nRange to KSC: {0}", VOID_Data.downrangeDistance.ValueUnitString(2)); + } + } + else + { + VOID_Styles.labelHud.normal.textColor = Color.red; + rightHUD.Append(string.Intern("-- POWER LOST --")); + } - GUILayout.Label(rightHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); + GUILayout.Label( + rightHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); - if (!this.positionsLocked) - { - GUI.DragWindow(); + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); } - - GUI.BringWindowToBack(id); } - - public override void DrawGUI() - { - if (!this.core.LabelStyles.ContainsKey("hud")) - { - this.core.LabelStyles["hud"] = new GUIStyle(GUI.skin.label); - } - - this.core.LabelStyles["hud"].normal.textColor = textColors [ColorIndex]; - - if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) - { - SimManager.RequestSimulation(); - } - - this.leftHUDPos.value = GUI.Window( - this.core.windowID, - this.leftHUDPos, - this.leftHUDWindow, - GUIContent.none, - GUIStyle.none - ); - - this.rightHUDPos.value = GUI.Window( - this.core.windowID, - this.rightHUDPos, - this.rightHUDWindow, - GUIContent.none, - GUIStyle.none - ); - } - - public override void DrawConfigurables() - { - if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false))) - { - ++this.ColorIndex; - } - - if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false))) - { - this.leftHUDPos = new Rect(this.leftHUDdefaultPos); - this.rightHUDPos = new Rect(this.rightHUDdefaultPos); - } - - this.positionsLocked = GUILayout.Toggle(this.positionsLocked, - string.Intern("Lock HUD Positions"), - GUILayout.ExpandWidth(false)); - } - } - - public static partial class VOID_Data - { - public static readonly VOID_StrValue expSituation = new VOID_StrValue( - "Situation", - new Func (() => core.vessel.GetExperimentSituation().HumanString()) - ); - - public static readonly VOID_DoubleValue vesselPitch = new VOID_DoubleValue( - "Pitch", - () => core.vessel.getSurfacePitch(), - "°" - ); } } --- a/VOID_HUDAdvanced.cs +++ b/VOID_HUDAdvanced.cs @@ -26,48 +26,45 @@ // 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 Engineer.VesselSimulator; +using KerbalEngineer.VesselSimulator; using KSP; using System; using System.Collections.Generic; -using System.Linq; using System.Text; using ToadicusTools; +using ToadicusTools.GUIUtils; +using ToadicusTools.Text; using UnityEngine; namespace VOID { - public class VOID_HUDAdvanced : VOID_Module, IVOID_Module + public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module { /* * Fields * */ protected VOID_HUD primaryHUD; - protected Rect leftHUDdefaultPos; - protected Rect rightHUDdefaultPos; - - [AVOID_SaveValue("leftHUDPos")] - protected VOID_SaveValue leftHUDPos; - [AVOID_SaveValue("rightHUDPos")] - protected VOID_SaveValue rightHUDPos; - - [AVOID_SaveValue("positionsLocked")] - protected VOID_SaveValue positionsLocked; + protected HUDWindow leftHUD; + protected HUDWindow rightHUD; /* * Properties * */ - public int ColorIndex + public override int ColorIndex { get { - if (this.primaryHUD == null) - { - return 0; - } - - return this.primaryHUD.ColorIndex; + if (this.primaryHUD != null) + { + return this.primaryHUD.ColorIndex; + } + + return base.ColorIndex; + } + set + { + base.ColorIndex = value; } } @@ -76,592 +73,204 @@ * */ public VOID_HUDAdvanced() : base() { - this._Name = "Advanced Heads-Up Display"; - - this._Active.value = true; - - this.leftHUDdefaultPos = new Rect( - Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f, - Screen.height - 200f, - 300f, 90f + this.Name = "Advanced Heads-Up Display"; + + this.Active = true; + + this.leftHUD = new HUDWindow("leftHUD", + this.leftHUDWindow, + new Rect( + Screen.width * .5f - (float)GameSettings.UI_SCALE * .25f - 300f, + Screen.height - 200f, + 300f, 90f) ); - this.leftHUDPos = new Rect(this.leftHUDdefaultPos); - - this.rightHUDdefaultPos = new Rect( - Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f, - Screen.height - 200f, - 300f, 90f + this.Windows.Add(this.leftHUD); + + this.rightHUD = new HUDWindow( + "rightHUD", + this.rightHUDWindow, + new Rect( + Screen.width * .5f + (float)GameSettings.UI_SCALE * .25f, + Screen.height - 200f, + 300f, 90f) ); - this.rightHUDPos = new Rect(this.rightHUDdefaultPos); - - this.positionsLocked = true; - - Tools.PostDebugMessage (this, "Constructed."); + this.Windows.Add(this.rightHUD); + + this.positionsLocked.value = true; + + Logging.PostDebugMessage (this, "Constructed."); } protected void leftHUDWindow(int id) { - StringBuilder leftHUD; - - leftHUD = new StringBuilder(); - - this.core.LabelStyles["hud"].alignment = TextAnchor.UpperRight; - - if (this.core.powerAvailable) - { - leftHUD.AppendFormat( - string.Intern("Mass: {0}\n"), - VOID_Data.totalMass.ToSIString(2) + using (PooledStringBuilder leftHUD = PooledStringBuilder.Get()) + { + VOID_Styles.labelHud.alignment = TextAnchor.UpperRight; + + if (this.core.powerAvailable) + { + leftHUD.AppendFormat( + string.Intern("Mass: {0}\n"), + VOID_Data.totalMass.ToSIString(2) + ); + + if (VOID_Data.vesselCrewCapacity > 0) + { + leftHUD.AppendFormat( + string.Intern("Crew: {0} / {1}\n"), + VOID_Data.vesselCrewCount.Value, + VOID_Data.vesselCrewCapacity.Value + ); + } + + leftHUD.AppendFormat( + string.Intern("Acc: {0} T:W: {1}\n"), + VOID_Data.vesselAccel.ToSIString(2), + VOID_Data.currThrustWeight.Value.ToString("f2") + ); + + leftHUD.AppendFormat( + string.Intern("Ang Vel: {0}\n"), + VOID_Data.vesselAngularVelocity.ToSIString(2) + ); + + if (VOID_Data.stageNominalThrust != 0d) + { + leftHUD.AppendFormat( + string.Intern("Thrust Offset: {0}\n"), + VOID_Data.vesselThrustOffset.Value.ToString("F1") + ); + } + } + else + { + VOID_Styles.labelHud.normal.textColor = Color.red; + leftHUD.Append(string.Intern("-- POWER LOST --")); + } + + GUILayout.Label( + leftHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) ); - if (VOID_Data.vesselCrewCapacity > 0) - { - leftHUD.AppendFormat( - string.Intern("Crew: {0} / {1}\n"), - VOID_Data.vesselCrewCount.Value, - VOID_Data.vesselCrewCapacity.Value - ); - } - - leftHUD.AppendFormat( - string.Intern("Acc: {0} T:W: {1}\n"), - VOID_Data.vesselAccel.ToSIString(2), - VOID_Data.currThrustWeight.Value.ToString("f2") + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + } + } + + protected void rightHUDWindow(int id) + { + using (PooledStringBuilder rightHUD = PooledStringBuilder.Get()) + { + VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; + + if (this.core.powerAvailable) + { + rightHUD.AppendFormat( + "Burn Δv (Rem/Tot): {0} / {1}\n", + VOID_Data.currManeuverDVRemaining.ValueUnitString("f2"), + VOID_Data.currManeuverDeltaV.ValueUnitString("f2") + ); + + if (VOID_Data.upcomingManeuverNodes > 1) + { + rightHUD.AppendFormat("Next Burn Δv: {0}\n", + VOID_Data.nextManeuverDeltaV.ValueUnitString("f2") + ); + } + + rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n", + VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnRemaining.Value), + VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnDuration.Value) + ); + + if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty) + { + rightHUD.AppendFormat("{0} (done @ node)\n", + VOID_Data.burnTimeDoneAtNode.Value + ); + + rightHUD.AppendFormat("{0} (½ done @ node)", + VOID_Data.burnTimeHalfDoneAtNode.Value + ); + } + else + { + rightHUD.Append("Node is past"); + } + } + else + { + VOID_Styles.labelHud.normal.textColor = Color.red; + rightHUD.Append(string.Intern("-- POWER LOST --")); + } + + GUILayout.Label( + rightHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) ); - leftHUD.AppendFormat( - string.Intern("Ang Vel: {0}\n"), - VOID_Data.vesselAngularVelocity.ToSIString(2) - ); - - if (VOID_Data.stageNominalThrust != 0d) - { - leftHUD.AppendFormat( - string.Intern("Thrust Offset: {0}\n"), - VOID_Data.vesselThrustOffset.Value.ToString("F1") - ); - } - } - else - { - this.core.LabelStyles["hud"].normal.textColor = Color.red; - leftHUD.Append(string.Intern("-- POWER LOST --")); - } - - GUILayout.Label(leftHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); - - if (!this.positionsLocked) - { - GUI.DragWindow(); - } - - GUI.BringWindowToBack(id); - } - - protected void rightHUDWindow(int id) - { - StringBuilder rightHUD; - - rightHUD = new StringBuilder(); - - this.core.LabelStyles["hud"].alignment = TextAnchor.UpperLeft; - - if (this.core.powerAvailable) - { - rightHUD.AppendFormat( - "Burn Δv (Rem/Tot): {0} / {1}\n", - VOID_Data.currManeuverDVRemaining.ValueUnitString("f2"), - VOID_Data.currManeuverDeltaV.ValueUnitString("f2") - ); - - if (VOID_Data.upcomingManeuverNodes > 1) - { - rightHUD.AppendFormat("Next Burn Δv: {0}\n", - VOID_Data.nextManeuverDeltaV.ValueUnitString("f2") - ); - } - - rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n", - VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnRemaining.Value), - VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnDuration.Value) - ); - - if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty) - { - rightHUD.AppendFormat("{0} (done @ node)\n", - VOID_Data.burnTimeDoneAtNode.Value - ); - - rightHUD.AppendFormat("{0} (½ done @ node)", - VOID_Data.burnTimeHalfDoneAtNode.Value - ); - } - else - { - rightHUD.Append("Node is past"); - } - } - else - { - this.core.LabelStyles["hud"].normal.textColor = Color.red; - rightHUD.Append(string.Intern("-- POWER LOST --")); - } - - GUILayout.Label(rightHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); - - if (!this.positionsLocked) - { - GUI.DragWindow(); - } - - GUI.BringWindowToBack(id); - } - - public override void DrawGUI() + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + } + } + + public override void DrawGUI(object sender) { if (this.primaryHUD == null) { - foreach (IVOID_Module module in this.core.Modules) - { + IVOID_Module module; + for (int idx = 0; idx < this.core.Modules.Count; idx++) + { + module = this.core.Modules[idx]; + if (module is VOID_HUD) { this.primaryHUD = module as VOID_HUD; } } } - else - { - if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) - { - SimManager.RequestSimulation(); - } - - this.leftHUDPos.value = GUI.Window( - this.core.windowID, - this.leftHUDPos, - VOID_Tools.GetWindowHandler(this.leftHUDWindow), - GUIContent.none, - GUIStyle.none - ); - - if (VOID_Data.upcomingManeuverNodes > 0) - { - this.rightHUDPos.value = GUI.Window( - this.core.windowID, - this.rightHUDPos, - VOID_Tools.GetWindowHandler(this.rightHUDWindow), - GUIContent.none, - GUIStyle.none - ); - } - } + + if (VOID_Data.upcomingManeuverNodes < 1 && this.Windows.Contains(this.rightHUD)) + { + this.Windows.Remove(this.rightHUD); + } + else if (VOID_Data.upcomingManeuverNodes > 0 && !this.Windows.Contains(this.rightHUD)) + { + this.Windows.Add(this.rightHUD); + } + + base.DrawGUI(sender); } public override void DrawConfigurables() { - this.positionsLocked = GUILayout.Toggle(this.positionsLocked, - string.Intern("Lock Advanced HUD Positions"), - GUILayout.ExpandWidth(false)); - } - } - - public static partial class VOID_Data - { - public static int upcomingManeuverNodes - { - get - { - if (core.vessel == null || - core.vessel.patchedConicSolver == null || - core.vessel.patchedConicSolver.maneuverNodes == null - ) - { - return 0; - } - - return core.vessel.patchedConicSolver.maneuverNodes.Count; - } - } - - public static readonly VOID_Vector3dValue vesselThrustOffset = new VOID_Vector3dValue( - "Thrust Offset", - delegate() - { - if (core.vessel == null) - { - return Vector3d.zero; - } - - List engineModules = core.vessel.getModulesOfType(); - - Vector3d thrustPos = Vector3d.zero; - Vector3d thrustDir = Vector3d.zero; - float thrust = 0; - - foreach (PartModule engine in engineModules) - { - float moduleThrust = 0; - - switch (engine.moduleName) - { - case "ModuleEngines": - case "ModuleEnginesFX": - break; - default: - continue; - } - - if (!engine.isEnabled) - { - continue; - } - - CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); - - if (engine is ModuleEngines) - { - ModuleEngines engineModule = engine as ModuleEngines; - - moduleThrust = engineModule.finalThrust; - - engineModule.OnCenterOfThrustQuery(cotQuery); - } - else // engine is ModuleEnginesFX - { - ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; - - moduleThrust = engineFXModule.finalThrust; - - engineFXModule.OnCenterOfThrustQuery(cotQuery); - } - - if (moduleThrust != 0d) - { - cotQuery.thrust = moduleThrust; - } - - thrustPos += cotQuery.pos * cotQuery.thrust; - thrustDir += cotQuery.dir * cotQuery.thrust; - thrust += cotQuery.thrust; - } - - if (thrust != 0) - { - thrustPos /= thrust; - thrustDir /= thrust; - } - - Transform vesselTransform = core.vessel.transform; - - thrustPos = vesselTransform.InverseTransformPoint(thrustPos); - thrustDir = vesselTransform.InverseTransformDirection(thrustDir); - - Vector3d thrustOffset = VectorTools.PointDistanceToLine( - thrustPos, thrustDir.normalized, core.vessel.findLocalCenterOfMass()); - - Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + - "\tthrustPos: {0}\n" + - "\tthrustDir: {1}\n" + - "\tthrustOffset: {2}\n" + - "\tvessel.CoM: {3}", - thrustPos, - thrustDir.normalized, - thrustOffset, - core.vessel.findWorldCenterOfMass() - ); - - return thrustOffset; - }, - "m" - ); - - public static readonly VOID_DoubleValue vesselAccel = new VOID_DoubleValue( - "Acceleration", - () => geeForce * KerbinGee, - "m/s²" - ); - - public static readonly VOID_IntValue vesselCrewCount = new VOID_IntValue( - "Crew Onboard", - delegate() - { - if (core.vessel != null) - { - return core.vessel.GetCrewCount(); - } - else - { - return 0; - } - }, - "" - ); - - public static readonly VOID_IntValue vesselCrewCapacity = new VOID_IntValue( - "Crew Capacity", - delegate() - { - if (core.vessel != null) - { - return core.vessel.GetCrewCapacity(); - } - else - { - return 0; - } - }, - "" - ); - - public static readonly VOID_DoubleValue vesselAngularVelocity = new VOID_DoubleValue( - "Angular Velocity", - delegate() - { - if (core.vessel != null) - { - return core.vessel.angularVelocity.magnitude; - } - else - { - return double.NaN; - } - }, - "rad/s" - ); - - public static readonly VOID_DoubleValue stageNominalThrust = new VOID_DoubleValue( - "Nominal Stage Thrust", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - if (SimManager.LastStage.actualThrust == 0d) - { - return SimManager.LastStage.thrust; - } - else - { - return SimManager.LastStage.actualThrust; - } - }, - "kN" - ); - - public static readonly VOID_DoubleValue stageMassFlow = new VOID_DoubleValue( - "Stage Mass Flow", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - double stageIsp = SimManager.LastStage.isp; - double stageThrust = stageNominalThrust; - - Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" + - "\tstageIsp: {0}\n" + - "\tstageThrust: {1}\n" + - "\tKerbinGee: {2}\n", - stageIsp, - stageThrust, - KerbinGee - ); - - return stageThrust / (stageIsp * KerbinGee); - }, - "Mg/s" - ); - - public static readonly VOID_DoubleValue currManeuverDeltaV = new VOID_DoubleValue( - "Current Maneuver Delta-V", - delegate() - { - if (upcomingManeuverNodes > 0) - { - return core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; - } - else - { - return double.NaN; - } - }, - "m/s" - ); - - public static readonly VOID_DoubleValue currManeuverDVRemaining = new VOID_DoubleValue( - "Remaining Maneuver Delta-V", - delegate() - { - if (upcomingManeuverNodes > 0) - { - return core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(core.vessel.orbit).magnitude; - } - else - { - return double.NaN; - } - }, - "m/s" - ); - - public static readonly VOID_DoubleValue nextManeuverDeltaV = new VOID_DoubleValue( - "Current Maneuver Delta-V", - delegate() - { - if (upcomingManeuverNodes > 1) - { - return core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude; - } - else - { - return double.NaN; - } - }, - "m/s" - ); - - public static readonly VOID_DoubleValue currentNodeBurnDuration = new VOID_DoubleValue( - "Total Burn Time", - delegate() - { - if (SimManager.LastStage == null || currManeuverDeltaV.Value == double.NaN) - { - return double.NaN; - } - - double stageThrust = stageNominalThrust; - - return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust); - }, - "s" - ); - - public static readonly VOID_DoubleValue currentNodeBurnRemaining = new VOID_DoubleValue( - "Burn Time Remaining", - delegate() - { - if (SimManager.LastStage == null || currManeuverDVRemaining == double.NaN) - { - return double.NaN; - } - - double stageThrust = stageNominalThrust; - - return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust); - }, - "s" - ); - - public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = new VOID_DoubleValue( - "Half Burn Time", - delegate() - { - if (SimManager.LastStage == null || currManeuverDeltaV.Value == double.NaN) - { - return double.NaN; - } - - double stageThrust = stageNominalThrust; - - return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust); - }, - "s" - ); - - public static readonly VOID_StrValue burnTimeDoneAtNode = new VOID_StrValue( - "Full burn time to be half done at node", - delegate() - { - if (SimManager.LastStage == null && upcomingManeuverNodes < 1) - { - return "N/A"; - } - - ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; - - if ((node.UT - Planetarium.GetUniversalTime()) < 0) - { - return string.Empty; - } - - double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); - - if (double.IsNaN(interval)) - { - return string.Intern("NaN"); - } - - int sign = Math.Sign(interval); - interval = Math.Abs(interval); - - string format; - - if (sign >= 0) - { - format = string.Intern("T - {0}"); - } - else - { - format = string.Intern("T + {0}"); - } - - return string.Format(format, VOID_Tools.ConvertInterval(interval)); - } - ); - - public static readonly VOID_StrValue burnTimeHalfDoneAtNode = new VOID_StrValue( - "Full burn time to be half done at node", - delegate() - { - if (SimManager.LastStage == null && upcomingManeuverNodes < 1) - { - return "N/A"; - } - - ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; - - if ((node.UT - Planetarium.GetUniversalTime()) < 0) - { - return string.Empty; - } - - double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); - - int sign = Math.Sign(interval); - interval = Math.Abs(interval); - - string format; - - if (sign >= 0) - { - format = string.Intern("T - {0}"); - } - else - { - format = string.Intern("T + {0}"); - } - - return string.Format(format, VOID_Tools.ConvertInterval(interval)); - } - ); - - private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) - { - Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + - "\tdeltaV: {0}\n" + - "\tinitialMass: {1}\n" + - "\tmassFlow: {2}\n" + - "\tthrust: {3}\n", - deltaV, - initialMass, - massFlow, - thrust - ); - return initialMass / massFlow * (Math.Exp(deltaV * massFlow / thrust) - 1d); + base.DrawConfigurables(); + + if (GUILayout.Button(string.Intern("Reset Advanced HUD Positions"), GUILayout.ExpandWidth(false))) + { + HUDWindow window; + for (int idx = 0; idx < this.Windows.Count; idx++) + { + window = this.Windows[idx]; + + window.WindowPos = new Rect(window.defaultWindowPos); + } + } + + this.positionsLocked.value = Layout.Toggle(this.positionsLocked, string.Intern("Lock Advanced HUD Positions")); } } } --- a/VOID_Localization.cs +++ /dev/null @@ -1,36 +1,1 @@ -// VOID -// -// VOID_Localization.cs -// -// Copyright © 2014, 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. -public static class VOID_Localization -{ - public static string void_primary = "Primary"; - public static string void_altitude_asl = "Altitude (ASL)"; - public static string void_velocity = "Velocity"; - public static string void_apoapsis = "Apoapsis"; - public static string void_periapsis = "Periapsis"; -} --- a/VOID_Module.cs +++ /dev/null @@ -1,250 +1,1 @@ -// VOID -// -// VOID_Module.cs -// -// Copyright © 2014, 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 System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public abstract class VOID_Module : IVOID_Module - { - /* - * Fields - * */ - [AVOID_SaveValue("Active")] - protected VOID_SaveValue _Active = false; - protected bool _Running = false; - - protected string _Name; - - protected float lastUpdate = 0; - - /* - * Properties - * */ - protected virtual VOID_Core core - { - get - { - if (HighLogic.LoadedSceneIsEditor) - { - return VOID_EditorCore.Instance as VOID_Core; - } - - return VOID_Core.Instance; - } - } - - public virtual bool toggleActive - { - get - { - return this._Active; - } - set - { - this._Active.value = value; - } - } - - public virtual bool guiRunning - { - get - { - return this._Running; - } - } - - public virtual string Name - { - get - { - return this._Name; - } - } - - public virtual Vessel vessel - { - get - { - return FlightGlobals.ActiveVessel; - } - } - - /* - * Methods - * */ - public void StartGUI() - { - if (!this.toggleActive || this.guiRunning) - { - return; - } - - Tools.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name)); - RenderingManager.AddToPostDrawQueue (3, this.DrawGUI); - this._Running = true; - } - - public void StopGUI() - { - if (!this.guiRunning) - { - return; - } - Tools.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name)); - RenderingManager.RemoveFromPostDrawQueue (3, this.DrawGUI); - this._Running = false; - } - - public abstract void DrawGUI(); - - public virtual void DrawConfigurables() {} - - public virtual void LoadConfig() - { - var config = KSP.IO.PluginConfiguration.CreateForType (); - config.load (); - - foreach (var field in this.GetType().GetFields( - BindingFlags.NonPublic | - BindingFlags.Public | - BindingFlags.Instance | - BindingFlags.FlattenHierarchy - )) - { - object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false); - - if (attrs.Length == 0) { - continue; - } - - AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue; - - string fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name); - - Tools.PostDebugMessage(string.Format("{0}: Loading field {1}.", this.GetType().Name, fieldName)); - - object fieldValue = field.GetValue(this); - - bool convertBack = false; - if (fieldValue is IVOID_SaveValue) - { - fieldValue = (fieldValue as IVOID_SaveValue).AsType; - convertBack = true; - } - - fieldValue = config.GetValue(fieldName, fieldValue); - - if (convertBack) - { - Type type = typeof(VOID_SaveValue<>).MakeGenericType (fieldValue.GetType ()); - IVOID_SaveValue convertValue = Activator.CreateInstance (type) as IVOID_SaveValue; - convertValue.SetValue (fieldValue); - fieldValue = convertValue; - } - - field.SetValue (this, fieldValue); - - Tools.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName)); - } - } - - public virtual void _SaveToConfig(KSP.IO.PluginConfiguration config) - { - foreach (var field in this.GetType().GetFields( - BindingFlags.Instance | - BindingFlags.NonPublic | - BindingFlags.Public | - BindingFlags.FlattenHierarchy - )) - { - object[] attrs = field.GetCustomAttributes(typeof(AVOID_SaveValue), false); - - if (attrs.Length == 0) { - continue; - } - - AVOID_SaveValue attr = attrs.FirstOrDefault () as AVOID_SaveValue; - - string fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name); - - object fieldValue = field.GetValue(this); - - if (fieldValue is IVOID_SaveValue) - { - fieldValue = (fieldValue as IVOID_SaveValue).AsType; - } - - config.SetValue(fieldName, fieldValue); - - Tools.PostDebugMessage(string.Format("{0}: Saved field {1}.", this.GetType().Name, fieldName)); - } - } - } - - public abstract class VOID_WindowModule : VOID_Module - { - [AVOID_SaveValue("WindowPos")] - protected Rect WindowPos = new Rect(Screen.width / 2, Screen.height / 2, 250f, 50f); - protected float defWidth = 250f; - protected float defHeight = 50f; - - public abstract void ModuleWindow(int _); - - public override void DrawGUI() - { - GUI.skin = this.core.Skin; - - Rect _Pos = this.WindowPos; - - _Pos = GUILayout.Window( - this.core.windowID, - _Pos, - VOID_Tools.GetWindowHandler(this.ModuleWindow), - this.Name, - GUILayout.Width(this.defWidth), - GUILayout.Height(this.defHeight) - ); - - _Pos = Tools.ClampRectToScreen (_Pos); - - if (_Pos != this.WindowPos) - { - this.WindowPos = _Pos; - this.core.configDirty = true; - } - } - } -} - - --- a/VOID_Orbital.cs +++ b/VOID_Orbital.cs @@ -29,6 +29,7 @@ using KSP; using System; using ToadicusTools; +using ToadicusTools.GUIUtils; using UnityEngine; namespace VOID @@ -36,21 +37,25 @@ public class VOID_Orbital : VOID_WindowModule { [AVOID_SaveValue("toggleExtended")] - protected VOID_SaveValue toggleExtended = false; + protected VOID_SaveValue toggleExtended; [AVOID_SaveValue("precisionValues")] - protected long _precisionValues = 230584300921369395; + protected VOID_SaveValue _precisionValues; protected IntCollection precisionValues; public VOID_Orbital() { - this._Name = "Orbital Information"; + this.Name = "Orbital Information"; this.WindowPos.x = Screen.width - 520f; this.WindowPos.y = 250f; + + this.toggleExtended = (VOID_SaveValue)false; + + this._precisionValues = (VOID_SaveValue)384307168202282325; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { int idx = 0; @@ -79,7 +84,7 @@ this.precisionValues [idx]= (ushort)VOID_Data.gravityAccel.DoGUIHorizontal (this.precisionValues [idx]); idx++; - this.toggleExtended.value = GUILayout.Toggle(this.toggleExtended, "Extended info"); + this.toggleExtended.value = Layout.Toggle(this.toggleExtended, "Extended info"); if (this.toggleExtended) { @@ -98,150 +103,33 @@ VOID_Data.longitudeAscNode.DoGUIHorizontal("F3"); + VOID_Data.timeToAscendingNode.DoGUIHorizontal(); + + VOID_Data.timeToDescendingNode.DoGUIHorizontal(); + VOID_Data.argumentPeriapsis.DoGUIHorizontal("F3"); VOID_Data.localSiderealLongitude.DoGUIHorizontal("F3"); } GUILayout.EndVertical(); - GUI.DragWindow(); + + base.ModuleWindow(id); } - public override void LoadConfig () + public override void LoadConfig(KSP.IO.PluginConfiguration config) { - base.LoadConfig (); + base.LoadConfig(config); this.precisionValues = new IntCollection (4, this._precisionValues); } - public override void _SaveToConfig (KSP.IO.PluginConfiguration config) + public override void Save (KSP.IO.PluginConfiguration config, string sceneKey) { - this._precisionValues = this.precisionValues.collection; + this._precisionValues.value = this.precisionValues.collection; - base._SaveToConfig (config); + base.Save (config, sceneKey); } - } - - - public static partial class VOID_Data - { - public static readonly VOID_StrValue primaryName = new VOID_StrValue ( - VOID_Localization.void_primary, - delegate() - { - if (core.vessel == null) - { - return string.Empty; - } - return core.vessel.mainBody.name; - } - ); - - public static readonly VOID_DoubleValue orbitAltitude = new VOID_DoubleValue ( - "Altitude (ASL)", - new Func (() => core.vessel.orbit.altitude), - "m" - ); - - public static readonly VOID_DoubleValue orbitVelocity = new VOID_DoubleValue ( - VOID_Localization.void_velocity, - new Func (() => core.vessel.orbit.vel.magnitude), - "m/s" - ); - - public static readonly VOID_DoubleValue orbitApoAlt = new VOID_DoubleValue( - VOID_Localization.void_apoapsis, - new Func(() => core.vessel.orbit.ApA), - "m" - ); - - public static readonly VOID_DoubleValue oribtPeriAlt = new VOID_DoubleValue( - VOID_Localization.void_periapsis, - new Func(() => core.vessel.orbit.PeA), - "m" - ); - - public static readonly VOID_StrValue timeToApo = new VOID_StrValue( - "Time to Apoapsis", - new Func(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToAp)) - ); - - public static readonly VOID_StrValue timeToPeri = new VOID_StrValue( - "Time to Periapsis", - new Func(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToPe)) - ); - - public static readonly VOID_DoubleValue orbitInclination = new VOID_DoubleValue( - "Inclination", - new Func(() => core.vessel.orbit.inclination), - "°" - ); - - public static readonly VOID_DoubleValue gravityAccel = new VOID_DoubleValue( - "Gravity", - delegate() - { - double orbitRadius = core.vessel.mainBody.Radius + - core.vessel.mainBody.GetAltitude(core.vessel.findWorldCenterOfMass()); - return (VOID_Core.Constant_G * core.vessel.mainBody.Mass) / - (orbitRadius * orbitRadius); - }, - "m/s²" - ); - - public static readonly VOID_StrValue orbitPeriod = new VOID_StrValue( - "Period", - new Func(() => VOID_Tools.ConvertInterval(core.vessel.orbit.period)) - ); - - public static readonly VOID_DoubleValue semiMajorAxis = new VOID_DoubleValue( - "Semi-Major Axis", - new Func(() => core.vessel.orbit.semiMajorAxis), - "m" - ); - - public static readonly VOID_DoubleValue eccentricity = new VOID_DoubleValue( - "Eccentricity", - new Func(() => core.vessel.orbit.eccentricity), - "" - ); - - public static readonly VOID_DoubleValue meanAnomaly = new VOID_DoubleValue( - "Mean Anomaly", - new Func(() => core.vessel.orbit.meanAnomaly * 180d / Math.PI), - "°" - ); - - public static readonly VOID_DoubleValue trueAnomaly = new VOID_DoubleValue( - "True Anomaly", - new Func(() => core.vessel.orbit.trueAnomaly), - "°" - ); - - public static readonly VOID_DoubleValue eccAnomaly = new VOID_DoubleValue( - "Eccentric Anomaly", - new Func(() => core.vessel.orbit.eccentricAnomaly * 180d / Math.PI), - "°" - ); - - public static readonly VOID_DoubleValue longitudeAscNode = new VOID_DoubleValue( - "Long. Ascending Node", - new Func(() => core.vessel.orbit.LAN), - "°" - ); - - public static readonly VOID_DoubleValue argumentPeriapsis = new VOID_DoubleValue( - "Argument of Periapsis", - new Func(() => core.vessel.orbit.argumentOfPeriapsis), - "°" - ); - - public static readonly VOID_DoubleValue localSiderealLongitude = new VOID_DoubleValue( - "Local Sidereal Longitude", - new Func(() => VOID_Tools.FixDegreeDomain( - core.vessel.longitude + core.vessel.orbit.referenceBody.rotationAngle)), - "°" - ); } } --- a/VOID_Rendezvous.cs +++ b/VOID_Rendezvous.cs @@ -29,8 +29,9 @@ using KSP; using System; using System.Collections.Generic; -using System.Linq; using ToadicusTools; +using ToadicusTools.GUIUtils; +using ToadicusTools.Text; using UnityEngine; namespace VOID @@ -38,43 +39,53 @@ public class VOID_Rendezvous : VOID_WindowModule { [AVOID_SaveValue("untoggleRegisterInfo")] - protected VOID_SaveValue untoggleRegisterInfo = false; + protected VOID_SaveValue untoggleRegisterInfo; [AVOID_SaveValue("toggleExtendedOrbital")] - protected VOID_SaveValue toggleExtendedOrbital = false; + protected VOID_SaveValue toggleExtendedOrbital; protected VOID_VesselRegister RegisterModule; public VOID_Rendezvous() { - this._Name = "Rendezvous Information"; + this.Name = "Rendezvous Information"; this.WindowPos.x = 845; this.WindowPos.y = 85; + + this.untoggleRegisterInfo = (VOID_SaveValue)false; + this.toggleExtendedOrbital = (VOID_SaveValue)false; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { - Vessel rendezvessel = new Vessel(); - CelestialBody rendezbody = new CelestialBody(); + Vessel rendezvessel; + CelestialBody rendezbody; if (this.RegisterModule == null) { - this.RegisterModule = this.core.Modules.Where(m => typeof(VOID_VesselRegister).IsAssignableFrom(m.GetType())).FirstOrDefault() as VOID_VesselRegister; + for (int idx = 0; idx < this.core.Modules.Count; idx++) + { + if (this.core.Modules[idx] is VOID_VesselRegister) + { + this.RegisterModule = this.core.Modules[idx] as VOID_VesselRegister; + break; + } + } } GUILayout.BeginVertical(); //display both //Show Target Info - GUILayout.Label("Target:", this.core.LabelStyles["center_bold"]); + GUILayout.Label("Target:", VOID_Styles.labelCenterBold); if (FlightGlobals.fetch.VesselTarget != null) { //a KSP Target (body or vessel) is selected if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.Direction) { //a Body is selected - rendezbody = vessel.patchedConicSolver.targetBody; + rendezbody = Vessel.patchedConicSolver.targetBody; display_rendezvous_info(null, rendezbody); } else if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.DirectionAndVelocity) @@ -87,20 +98,20 @@ if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false))) { FlightGlobals.fetch.SetVesselTarget(null); - Tools.PostDebugMessage("VOID_Rendezvous: KSP Target set to null"); + Logging.PostDebugMessage("VOID_Rendezvous: KSP Target set to null"); } } else { //no KSP Target selected - GUILayout.Label("No Target Selected", this.core.LabelStyles["center_bold"]); + GUILayout.Label("No Target Selected", VOID_Styles.labelCenterBold); } //Show Vessel Register vessel info if (untoggleRegisterInfo == false && this.RegisterModule != default(IVOID_Module)) { - GUILayout.Label("Vessel Register:", this.core.LabelStyles["center_bold"]); + GUILayout.Label("Vessel Register:", VOID_Styles.labelCenterBold); if (this.RegisterModule.selectedVessel != null) { rendezvessel = this.RegisterModule.selectedVessel; @@ -114,7 +125,7 @@ if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) { FlightGlobals.fetch.SetVesselTarget(rendezvessel); - Tools.PostDebugMessage("[VOID] KSP Target set to " + rendezvessel.vesselName); + Logging.PostDebugMessage("[VOID] KSP Target set to " + rendezvessel.vesselName); } } } @@ -122,19 +133,20 @@ { //vesreg Vessel is null //targ = null; - GUILayout.Label("No Vessel Selected", this.core.LabelStyles["center_bold"]); - } - } - - untoggleRegisterInfo.value = GUILayout.Toggle(untoggleRegisterInfo, "Hide Vessel Register Info"); + GUILayout.Label("No Vessel Selected", VOID_Styles.labelCenterBold); + } + } + + untoggleRegisterInfo.value = Layout.Toggle(untoggleRegisterInfo, "Hide Vessel Register Info"); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label(" ", GUILayout.ExpandWidth(true)); - if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) this._Active = false; + if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) this.Active = false; GUILayout.EndHorizontal(); GUILayout.EndVertical(); - GUI.DragWindow(); + + base.ModuleWindow(id); } private void display_rendezvous_info(Vessel v, CelestialBody cb) @@ -143,7 +155,7 @@ { //Display vessel rendezvous info GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label(v.vesselName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + GUILayout.Label(v.vesselName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); if (v.situation == Vessel.Situations.ESCAPING || v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.ORBITING || v.situation == Vessel.Situations.SUB_ORBITAL) @@ -156,12 +168,12 @@ //display orbital info for orbiting/flying/suborbital/escaping vessels only GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Ap/Pe:"); - GUILayout.Label(Tools.MuMech_ToSI(v.orbit.ApA) + "m / " + Tools.MuMech_ToSI(v.orbit.PeA) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI(v.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(v.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Altitude:"); - GUILayout.Label(Tools.MuMech_ToSI(v.orbit.altitude) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI(v.orbit.altitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); @@ -169,43 +181,43 @@ GUILayout.Label(v.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); - if (vessel.mainBody == v.mainBody) + if (Vessel.mainBody == v.mainBody) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Relative inclination:"); - GUILayout.Label(Vector3d.Angle(vessel.orbit.GetOrbitNormal(), v.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); + GUILayout.Label(Vector3.Angle(Vessel.orbit.GetOrbitNormal(), v.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } //if (debugging) Debug.Log("[CHATR] v -> v relative incl OK"); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Velocity:"); - GUILayout.Label(Tools.MuMech_ToSI(v.orbit.vel.magnitude) + "m/s", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Relative velocity:"); - GUILayout.Label(Tools.MuMech_ToSI(v.orbit.vel.magnitude - vessel.orbit.vel.magnitude) + "m/s", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude - Vessel.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Distance:"); - GUILayout.Label(Tools.MuMech_ToSI((vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); // Toadicus edit: added local sidereal longitude. GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Local Sidereal Longitude:"); - GUILayout.Label(LSL.ToString("F3") + "°", this.core.LabelStyles["right"]); - GUILayout.EndHorizontal(); - - toggleExtendedOrbital.value = GUILayout.Toggle(toggleExtendedOrbital, "Extended info"); + GUILayout.Label(LSL.ToString("F3") + "°", VOID_Styles.labelRight); + GUILayout.EndHorizontal(); + + toggleExtendedOrbital.value = Layout.Toggle(toggleExtendedOrbital, "Extended info"); if (toggleExtendedOrbital) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Period:"); - GUILayout.Label(VOID_Tools.ConvertInterval(v.orbit.period), GUILayout.ExpandWidth(false)); + GUILayout.Label(VOID_Tools.FormatInterval(v.orbit.period), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); @@ -250,28 +262,28 @@ { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Latitude:"); - GUILayout.Label(VOID_Tools.GetLatitudeString(vessel), GUILayout.ExpandWidth(false)); + GUILayout.Label(VOID_Tools.GetLatitudeString(Vessel), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Longitude:"); - GUILayout.Label(VOID_Tools.GetLongitudeString(vessel), GUILayout.ExpandWidth(false)); + GUILayout.Label(VOID_Tools.GetLongitudeString(Vessel), GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Distance:"); - GUILayout.Label(Tools.MuMech_ToSI((vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } else if (cb != null && v == null) { //Display CelstialBody rendezvous info - GUILayout.Label(cb.bodyName, this.core.LabelStyles["center_bold"]); + GUILayout.Label(cb.bodyName, VOID_Styles.labelCenterBold); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Ap/Pe:"); - GUILayout.Label(Tools.MuMech_ToSI(cb.orbit.ApA) + "m / " + Tools.MuMech_ToSI(cb.orbit.PeA) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI(cb.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(cb.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); //if (debugging) Debug.Log("[VOID] Ap/Pe OK"); @@ -281,47 +293,47 @@ GUILayout.EndHorizontal(); //if (debugging) Debug.Log("[VOID] Inclination OK"); - if (cb.referenceBody == vessel.mainBody) + if (cb.referenceBody == Vessel.mainBody) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Relative inclination:"); - GUILayout.Label(Vector3d.Angle(vessel.orbit.GetOrbitNormal(), cb.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); + GUILayout.Label(Vector3.Angle(Vessel.orbit.GetOrbitNormal(), cb.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); //if (debugging) Debug.Log("[VOID] cb Relative inclination OK"); } GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Distance:"); - GUILayout.Label(Tools.MuMech_ToSI((vessel.mainBody.position - cb.position).magnitude) + "m", GUILayout.ExpandWidth(false)); + GUILayout.Label(SIFormatProvider.ToSI((Vessel.mainBody.position - cb.position).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); //if (debugging) Debug.Log("[VOID] Distance OK"); //SUN2PLANET: - if (vessel.mainBody.bodyName == "Sun" && cb.referenceBody == vessel.mainBody) - { - VOID_Tools.display_transfer_angles_SUN2PLANET(cb, vessel); + if (Vessel.mainBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody) + { + VOID_Tools.display_transfer_angles_SUN2PLANET(cb, Vessel); //if (debugging) Debug.Log("[VOID] SUN2PLANET OK"); } //PLANET2PLANET - else if (vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == vessel.mainBody.referenceBody) - { - VOID_Tools.display_transfer_angles_PLANET2PLANET(cb, vessel); + else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody) + { + VOID_Tools.display_transfer_angles_PLANET2PLANET(cb, Vessel); //if (debugging) Debug.Log("[VOID] PLANET2PLANET OK"); } //PLANET2MOON - else if (vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == vessel.mainBody) - { - VOID_Tools.display_transfer_angles_PLANET2MOON(cb, vessel); + else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody) + { + VOID_Tools.display_transfer_angles_PLANET2MOON(cb, Vessel); //if (debugging) Debug.Log("[VOID] PLANET2MOON OK"); } //MOON2MOON - else if (vessel.mainBody.referenceBody.referenceBody.bodyName == "Sun" && cb.referenceBody == vessel.mainBody.referenceBody) - { - VOID_Tools.display_transfer_angles_MOON2MOON(cb, vessel); + else if (Vessel.mainBody.referenceBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody) + { + VOID_Tools.display_transfer_angles_MOON2MOON(cb, Vessel); //if (debugging) Debug.Log("[VOID] MOON2MOON OK"); } --- a/VOID_SaveValue.cs +++ /dev/null @@ -1,166 +1,1 @@ -// VOID -// -// VOID_SaveValue.cs -// -// Copyright © 2014, 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 System.Collections.Generic; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public struct VOID_SaveValue : IVOID_SaveValue - { - private T _value; - private Type _type; - - private VOID_Core Core - { - get - { - if (HighLogic.LoadedSceneIsEditor) - { - if (VOID_EditorCore.Initialized) - { - return VOID_EditorCore.Instance; - } - } - else if (HighLogic.LoadedSceneIsFlight) - { - if (VOID_Core.Initialized) - { - return VOID_Core.Instance; - } - } - return null; - } - } - - public T value - { - get - { - return this._value; - } - set - { - if (this.Core != null && !System.Object.Equals(this._value, value)) - { - Tools.PostDebugMessage (string.Format ( - "VOID: Dirtying config for type {0} in method {1}." + - "\n\t Old Value: {2}, New Value: {3}" + - "\n\t Object.Equals(New, Old): {4}", - this._type, - new System.Diagnostics.StackTrace().GetFrame(1).GetMethod(), - this._value, - value, - System.Object.Equals(this._value, value) - )); - this.Core.configDirty = true; - } - this._value = value; - } - } - - public Type type - { - get - { - if (this._type == null && this._value != null) - { - this._type = this._value.GetType (); - } - return this._type; - } - set - { - this._type = value; - } - } - - public object AsType - { - get - { - return (T)this._value; - } - } - - public void SetValue(object v) - { - this.value = (T)v; - } - - public static implicit operator T(VOID_SaveValue v) - { - return (T)v.value; - } - - public static implicit operator VOID_SaveValue(T v) - { - VOID_SaveValue r = new VOID_SaveValue(); - r.type = v.GetType(); - r.value = v; - - return r; - } - - public override string ToString() - { - return this.value.ToString(); - } - } - - public interface IVOID_SaveValue - { - Type type { get; } - object AsType { get; } - void SetValue(object v); - } - - [AttributeUsage(AttributeTargets.Field)] - public class AVOID_SaveValue : Attribute - { - protected string _name; - - public string Name - { - get - { - return this._name; - } - } - - public AVOID_SaveValue(string fieldName) - { - this._name = fieldName; - } - } -} - - --- /dev/null +++ b/VOID_StageInfo.cs @@ -1,1 +1,308 @@ - +// VOID © 2014 toadicus +// +// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a +// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ + +using KerbalEngineer.VesselSimulator; +using KSP; +using System; +using System.Collections.Generic; +using ToadicusTools.GUIUtils; +using UnityEngine; + +namespace VOID +{ + [VOID_Scenes(GameScenes.EDITOR, GameScenes.FLIGHT)] + public class VOID_StageInfo : VOID_WindowModule + { + private Table stageTable; + + private Table.Column stageNumberCol; + private Table.Column stageDeltaVCol; + private Table.Column stageTotalDVCol; + private Table.Column stageInvertDVCol; + private Table.Column stageMassCol; + private Table.Column stageTotalMassCol; + private Table.Column stageThrustCol; + private Table.Column stageTWRCol; + private Table.Column stageTimeCol; + + private bool stylesApplied; + + private bool showBodyList; + private Rect bodyListPos; + + private bool showColumnSelection; + + private CelestialBody _selectedBody; + [AVOID_SaveValue("bodyIdx")] + private VOID_SaveValue bodyIdx; + private int lastIdx; + + private bool showAdvanced; + + [AVOID_SaveValue("UseSealLevel")] + private VOID_SaveValue useSeaLevel; + private GUIContent seaLevelToggle; + + private CelestialBody selectedBody + { + get + { + return this._selectedBody; + } + set + { + this._selectedBody = value; + KerbalEngineer.Helpers.CelestialBodies.SelectedBody = value; + } + } + + public VOID_StageInfo() : base() + { + this.Name = "Stage Information"; + this.defWidth = 20f; + this.bodyIdx = (VOID_SaveValue)4; + + this.stylesApplied = false; + this.showBodyList = false; + this.showColumnSelection = false; + + this.bodyListPos = new Rect(); + + this.stageTable = new Table(); + + this.stageNumberCol = new Table.Column("Stage", 20f); + this.stageTable.Add(this.stageNumberCol); + + this.stageDeltaVCol = new Table.Column("DeltaV [m/s]", 20f); + this.stageDeltaVCol.Format = "S2"; + this.stageTable.Add(this.stageDeltaVCol); + + this.stageTotalDVCol = new Table.Column("Total ΔV [m/s]", 20f); + this.stageTotalDVCol.Format = "S2"; + this.stageTable.Add(this.stageTotalDVCol); + + this.stageInvertDVCol = new Table.Column("Invert ΔV [m/s]", 20f); + this.stageInvertDVCol.Format = "S2"; + this.stageTable.Add(this.stageInvertDVCol); + + this.stageMassCol = new Table.Column("Mass [Mg]", 20f); + this.stageMassCol.Format = "#.#"; + this.stageTable.Add(this.stageMassCol); + + this.stageTotalMassCol = new Table.Column("Total [Mg]", 20f); + this.stageTotalMassCol.Format = "#.#"; + this.stageTable.Add(this.stageTotalMassCol); + + this.stageThrustCol = new Table.Column("Thrust [N]", 20f); + this.stageThrustCol.Format = "S2"; + this.stageTable.Add(this.stageThrustCol); + + this.stageTWRCol = new Table.Column("T/W Ratio", 20f); + this.stageTWRCol.Format = "#.#"; + this.stageTable.Add(this.stageTWRCol); + + this.stageTimeCol = new Table.Column("Burn Time", 20f); + this.stageTable.Add(this.stageTimeCol); + + this.showAdvanced = false; + + this.useSeaLevel = (VOID_SaveValue)false; + + seaLevelToggle = new GUIContent( + "Use Sea Level", + "Use 'sea' level atmospheric conditions on bodies with atmospheres." + ); + } + + public override void DrawGUI(object sender) + { + base.DrawGUI(sender); + + if (this.showBodyList) + { + GUILayout.Window(core.WindowID, this.bodyListPos, this.BodyPickerWindow, string.Empty); + } + } + + public override void ModuleWindow(int id) + { + if (this.selectedBody == null) + { + this.selectedBody = core.HomeBody; + } + + if ( + !HighLogic.LoadedSceneIsFlight || + (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || + (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate) + ) + { + KerbalEngineer.VesselSimulator.SimManager.RequestSimulation(); + } + + if (!this.stylesApplied) + { + this.stageTable.ApplyCellStyle(VOID_Styles.labelCenter); + this.stageTable.ApplyHeaderStyle(VOID_Styles.labelCenterBold); + } + + this.stageTable.ClearColumns(); + + if (core.Stages == null || core.Stages.Length == 0) + { + GUILayout.BeginVertical(); + + GUILayout.Label("No stage data!"); + + GUILayout.EndVertical(); + + return; + } + + if (HighLogic.LoadedSceneIsEditor && this.selectedBody.atmosphere && this.useSeaLevel) + { + SimManager.Atmosphere = this.selectedBody.GetPressure(0) * PhysicsGlobals.KpaToAtmospheres; + } + else + { + SimManager.Atmosphere = 0d; + } + + Stage stage; + for (int idx = 0; idx < core.Stages.Length; idx++) + { + stage = core.Stages[idx]; + + if (stage.deltaV == 0 && stage.mass == 0) + { + continue; + } + + this.stageNumberCol.Add(stage.number); + + this.stageDeltaVCol.Add(stage.deltaV); + this.stageTotalDVCol.Add(stage.totalDeltaV); + this.stageInvertDVCol.Add(stage.inverseTotalDeltaV); + + this.stageMassCol.Add(stage.mass); + this.stageTotalMassCol.Add(stage.totalMass); + + this.stageThrustCol.Add(stage.thrust * 1000f); + this.stageTWRCol.Add(stage.thrustToWeight / (this.selectedBody ?? core.HomeBody).GeeASL); + + this.stageTimeCol.Add(VOID_Tools.FormatInterval(stage.time)); + } + + this.stageTable.Render(); + + if (core.SortedBodyList != null) + { + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("◄")) + { + this.bodyIdx.value--; + } + + this.showBodyList = GUILayout.Toggle( + this.showBodyList, + (this.selectedBody ?? core.HomeBody).bodyName, + GUI.skin.button + ); + + Rect bodyButtonPos = GUILayoutUtility.GetLastRect(); + + if (Event.current.type == EventType.Repaint) + { + this.bodyListPos.width = bodyButtonPos.width; + this.bodyListPos.x = bodyButtonPos.xMin + this.WindowPos.xMin; + this.bodyListPos.y = bodyButtonPos.yMax + this.WindowPos.yMin; + } + + if (GUILayout.Button("►")) + { + this.bodyIdx.value++; + } + + this.bodyIdx.value %= core.SortedBodyList.Count; + + if (this.bodyIdx < 0) + { + this.bodyIdx.value += core.SortedBodyList.Count; + } + + if (this.lastIdx != this.bodyIdx) + { + this.lastIdx = this.bodyIdx; + this.selectedBody = core.SortedBodyList[this.bodyIdx]; + } + + if (HighLogic.LoadedSceneIsEditor) + { + if ( + GUILayout.Button( + this.showAdvanced ? "▲" : "▼", + GUILayout.ExpandWidth(false) + ) + ) + { + this.showAdvanced = !this.showAdvanced; + } + } + + GUILayout.EndHorizontal(); + } + + if (this.showAdvanced && HighLogic.LoadedSceneIsEditor) + { + GUILayout.BeginHorizontal(); + + this.useSeaLevel.value = Layout.Toggle(this.useSeaLevel, this.seaLevelToggle, false); + + GUILayout.EndHorizontal(); + } + + GUILayout.BeginHorizontal(); + + if ( + GUILayout.Button("Engineering data powered by VesselSimulator from KER.", + VOID_Styles.labelLink) + ) + { + Application.OpenURL("http://forum.kerbalspaceprogram.com/threads/18230"); + } + + GUILayout.EndHorizontal(); + + base.ModuleWindow(id); + } + + public override void DrawConfigurables() + { + this.showColumnSelection = GUILayout.Toggle( + this.showColumnSelection, + "Select StageInfo Columns", + GUI.skin.button + ); + } + + private void BodyPickerWindow(int _) + { + CelestialBody body; + for (int idx = 0; idx < core.SortedBodyList.Count; idx++) + { + body = core.SortedBodyList[idx]; + if (GUILayout.Button(body.bodyName, VOID_Styles.labelDefault)) + { + Debug.Log("Picked new body focus: " + body.bodyName); + this.bodyIdx.value = core.SortedBodyList.IndexOf(body); + this.showBodyList = false; + } + } + } + } +} + + --- /dev/null +++ b/VOID_Styles.cs @@ -1,1 +1,131 @@ +// VOID +// +// cs +// +// Copyright © 2014, 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 System; +using UnityEngine; + +namespace VOID +{ + public static class VOID_Styles + { + public static bool Ready + { + get; + private set; + } + + public static GUIStyle labelDefault + { + get; + private set; + } + + public static GUIStyle labelLink + { + get; + private set; + } + + public static GUIStyle labelCenter + { + get; + private set; + } + + public static GUIStyle labelCenterBold + { + get; + private set; + } + + public static GUIStyle labelGreen + { + get; + private set; + } + + public static GUIStyle labelHud + { + get; + private set; + } + + public static GUIStyle labelRight + { + get; + private set; + } + + public static GUIStyle labelRed + { + get; + private set; + } + + public static void OnSkinChanged() + { + labelDefault = new GUIStyle(GUI.skin.label); + + labelLink = new GUIStyle(GUI.skin.label); + labelLink.fontStyle = FontStyle.Italic; + labelLink.fontSize = (int)((float)labelLink.fontSize * .8f); + + labelCenter = new GUIStyle(GUI.skin.label); + labelCenter.normal.textColor = Color.white; + labelCenter.alignment = TextAnchor.UpperCenter; + + labelCenterBold = new GUIStyle(GUI.skin.label); + labelCenterBold.normal.textColor = Color.white; + labelCenterBold.alignment = TextAnchor.UpperCenter; + labelCenterBold.fontStyle = FontStyle.Bold; + + labelHud = new GUIStyle(labelDefault); + + labelRight = new GUIStyle(GUI.skin.label); + labelRight.normal.textColor = Color.white; + labelRight.alignment = TextAnchor.UpperRight; + + labelRed = new GUIStyle(GUI.skin.label); + labelRed.normal.textColor = Color.red; + + labelGreen = new GUIStyle(GUI.skin.label); + labelGreen.normal.textColor = Color.green; + + Ready = true; + } + + static VOID_Styles() + { + OnSkinChanged(); + + Ready = false; + } + } +} + + --- a/VOID_SurfAtmo.cs +++ b/VOID_SurfAtmo.cs @@ -36,168 +36,80 @@ public class VOID_SurfAtmo : VOID_WindowModule { [AVOID_SaveValue("precisionValues")] - protected long _precisionValues = 230584300921369395; + protected VOID_SaveValue _precisionValues; protected IntCollection precisionValues; public VOID_SurfAtmo() { - this._Name = "Surface & Atmospheric Information"; + this.Name = "Surface & Atmospheric Info"; this.WindowPos.x = Screen.width - 260f; this.WindowPos.y = 85; + + this._precisionValues = (VOID_SaveValue)384307168202282325; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { int idx = 0; GUILayout.BeginVertical(); - this.precisionValues [idx]= (ushort)VOID_Data.trueAltitude.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.trueAltitude.DoGUIHorizontal(this.precisionValues[idx]); idx++; - VOID_Data.surfLatitude.DoGUIHorizontal (); + VOID_Data.surfLatitudeString.DoGUIHorizontal(); - VOID_Data.surfLongitude.DoGUIHorizontal (); + VOID_Data.surfLongitudeString.DoGUIHorizontal(); - VOID_Data.vesselHeading.DoGUIHorizontal (); + VOID_Data.vesselHeading.DoGUIHorizontal(); - this.precisionValues [idx]= (ushort)VOID_Data.terrainElevation.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.terrainElevation.DoGUIHorizontal(this.precisionValues[idx]); idx++; - this.precisionValues [idx]= (ushort)VOID_Data.surfVelocity.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.downrangeDistance.DoGUIHorizontal(this.precisionValues[idx]); idx++; - this.precisionValues [idx]= (ushort)VOID_Data.vertVelocity.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.surfVelocity.DoGUIHorizontal(this.precisionValues[idx]); idx++; - this.precisionValues [idx]= (ushort)VOID_Data.horzVelocity.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.vertVelocity.DoGUIHorizontal(this.precisionValues[idx]); idx++; - VOID_Data.temperature.DoGUIHorizontal ("F2"); + this.precisionValues[idx] = (ushort)VOID_Data.horzVelocity.DoGUIHorizontal(this.precisionValues[idx]); + idx++; - VOID_Data.atmDensity.DoGUIHorizontal (3); + VOID_Data.temperature.DoGUIHorizontal("F2"); - VOID_Data.atmPressure.DoGUIHorizontal ("F2"); + this.precisionValues[idx] = (ushort)VOID_Data.atmDensity.DoGUIHorizontal(this.precisionValues[idx]); + idx++; - this.precisionValues [idx]= (ushort)VOID_Data.atmLimit.DoGUIHorizontal (this.precisionValues [idx]); + this.precisionValues[idx] = (ushort)VOID_Data.atmPressure.DoGUIHorizontal(this.precisionValues[idx]); + idx++; + + this.precisionValues[idx] = (ushort)VOID_Data.atmLimit.DoGUIHorizontal(this.precisionValues[idx]); idx++; // Toadicus edit: added Biome - VOID_Data.currBiome.DoGUIHorizontal (); + VOID_Data.currBiome.DoGUIHorizontal(); GUILayout.EndVertical(); - GUI.DragWindow(); + + base.ModuleWindow(id); } - public override void LoadConfig () + public override void LoadConfig(KSP.IO.PluginConfiguration config) { - base.LoadConfig (); + base.LoadConfig(config); - this.precisionValues = new IntCollection (4, this._precisionValues); + this.precisionValues = new IntCollection(4, this._precisionValues); } - public override void _SaveToConfig (KSP.IO.PluginConfiguration config) + public override void Save(KSP.IO.PluginConfiguration config, string sceneKey) { - this._precisionValues = this.precisionValues.collection; + this._precisionValues.value = this.precisionValues.collection; - base._SaveToConfig (config); + base.Save(config, sceneKey); } } - - public static partial class VOID_Data - { - public static readonly VOID_DoubleValue trueAltitude = new VOID_DoubleValue( - "Altitude (true)", - delegate() - { - 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, - // and water covers the whole surface at 0 m. - if (core.vessel.terrainAltitude < 0 && core.vessel.mainBody.ocean ) - alt_true = core.vessel.orbit.altitude; - return alt_true; - }, - "m" - ); - - public static readonly VOID_StrValue surfLatitude = new VOID_StrValue( - "Latitude", - new Func (() => VOID_Tools.GetLatitudeString(core.vessel)) - ); - - public static readonly VOID_StrValue surfLongitude = new VOID_StrValue( - "Longitude", - new Func (() => VOID_Tools.GetLongitudeString(core.vessel)) - ); - - public static readonly VOID_StrValue vesselHeading = new VOID_StrValue( - "Heading", - delegate() - { - double heading = core.vessel.getSurfaceHeading(); - string cardinal = VOID_Tools.get_heading_text(heading); - - return string.Format( - "{0}° {1}", - heading.ToString("F2"), - cardinal - ); - } - ); - - public static readonly VOID_DoubleValue terrainElevation = new VOID_DoubleValue( - "Terrain elevation", - new Func (() => core.vessel.terrainAltitude), - "m" - ); - - public static readonly VOID_DoubleValue surfVelocity = new VOID_DoubleValue( - "Surface velocity", - new Func (() => core.vessel.srf_velocity.magnitude), - "m/s" - ); - - public static readonly VOID_DoubleValue vertVelocity = new VOID_DoubleValue( - "Vertical speed", - new Func (() => core.vessel.verticalSpeed), - "m/s" - ); - - public static readonly VOID_DoubleValue horzVelocity = new VOID_DoubleValue( - "Horizontal speed", - new Func (() => core.vessel.horizontalSrfSpeed), - "m/s" - ); - - public static readonly VOID_FloatValue temperature = new VOID_FloatValue( - "Temperature", - new Func (() => core.vessel.flightIntegrator.getExternalTemperature()), - "°C" - ); - - public static readonly VOID_DoubleValue atmDensity = new VOID_DoubleValue ( - "Atmosphere Density", - new Func (() => core.vessel.atmDensity * 1000f), - "g/m³" - ); - - public static readonly VOID_DoubleValue atmPressure = new VOID_DoubleValue ( - "Pressure", - new Func (() => core.vessel.staticPressure), - "atm" - ); - - public static readonly VOID_FloatValue atmLimit = new VOID_FloatValue( - "Atmosphere Limit", - new Func (() => core.vessel.mainBody.maxAtmosphereAltitude), - "m" - ); - - public static readonly VOID_StrValue currBiome = new VOID_StrValue( - "Biome", - new Func (() => VOID_Tools.GetBiome(core.vessel).name) - ); - - } } --- a/VOID_TWR.cs +++ b/VOID_TWR.cs @@ -3,58 +3,49 @@ // This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a // copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ +using KerbalEngineer.VesselSimulator; using KSP; using System; -using System.Collections.Generic; -using System.Linq; -using ToadicusTools; using UnityEngine; namespace VOID { + [VOID_Scenes(GameScenes.EDITOR, GameScenes.FLIGHT)] public class VOID_TWR : VOID_WindowModule { - private List sortedBodyList; - public VOID_TWR() : base() { - this._Name = "IP Thrust-to-Weight Ratios"; + this.Name = "IP Thrust-to-Weight Ratios"; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { if ( - HighLogic.LoadedSceneIsEditor || + !HighLogic.LoadedSceneIsFlight || (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate) ) { - Engineer.VesselSimulator.SimManager.RequestSimulation(); + SimManager.RequestSimulation(); } GUILayout.BeginVertical(); - if (this.sortedBodyList == null) + if (core.SortedBodyList == null) { - if (FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0) - { - this.sortedBodyList = new List(FlightGlobals.Bodies); - this.sortedBodyList.Sort(new CBListComparer()); - this.sortedBodyList.Reverse(); + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray()))); - } - else - { - GUILayout.BeginHorizontal(); - GUILayout.Label("Unavailable."); - GUILayout.EndHorizontal(); - } + GUILayout.Label("Unavailable"); + + GUILayout.EndHorizontal(); } else { - foreach (CelestialBody body in this.sortedBodyList) + CelestialBody body; + for (int idx = 0; idx < core.SortedBodyList.Count; idx++) { + body = core.SortedBodyList[idx]; + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label(body.bodyName); @@ -70,27 +61,8 @@ GUILayout.EndVertical(); - GUI.DragWindow(); + base.ModuleWindow(id); } - } - - public class VOID_EditorTWR : VOID_TWR, IVOID_EditorModule {} - - public static partial class VOID_Data - { - public static readonly VOID_DoubleValue nominalThrustWeight = new VOID_DoubleValue( - "Thrust-to-Weight Ratio", - delegate() - { - if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d) - { - return maxThrustWeight.Value; - } - - return currThrustWeight.Value; - }, - "" - ); } } --- a/VOID_Tools.cs +++ /dev/null @@ -1,950 +1,1 @@ -// VOID -// -// VOID_Tools.cs -// -// Copyright © 2014, 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 System.Collections.Generic; -using ToadicusTools; -using UnityEngine; - -namespace VOID -{ - public static partial class VOID_Tools - { - #region CelestialBody Utilities - public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB) - { - if (bodyA == null || bodyB == null) - { - return false; - } - - while (bodyA.orbitDriver != null) - { - if (bodyA.orbit.referenceBody == bodyB) - { - return true; - } - - bodyA = bodyA.orbit.referenceBody; - } - - return false; - } - - public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB) - { - if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null) - { - throw new ArgumentException(string.Concat( - "CelestialBody::FindRelatedParents: ", - "Neither body may be null, and both bodies must have orbits." - )); - } - - CelestialBody a, b; - - a = bodyA; - - while (bodyA.orbitDriver != null) - { - b = bodyB; - - while (b.orbitDriver != null) - { - if (a.orbit.referenceBody == b.orbit.referenceBody) - { - bodyA = a; - bodyB = b; - return true; - } - - b = b.orbit.referenceBody; - } - - a = a.orbit.referenceBody; - } - - return false; - } - #endregion - - #region VESSEL_EXTENSIONS_SCIENCE - public static CBAttributeMap.MapAttribute GetBiome(this Vessel vessel) - { - CBAttributeMap.MapAttribute mapAttribute; - - try - { - CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap; - - double lat = vessel.latitude * Math.PI / 180d; - double lon = vessel.longitude * Math.PI / 180d; - - mapAttribute = BiomeMap.GetAtt(lat, lon); - - /* - lon -= Math.PI / 2d; - - if (lon < 0d) - { - lon += 2d * Math.PI; - } - - float v = (float)(lat / Math.PI) + 0.5f; - float u = (float)(lon / (2d * Math.PI)); - - Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v); - mapAttribute = BiomeMap.defaultAttribute; - - if (BiomeMap.Map != null) - { - if (BiomeMap.exactSearch) - { - for (int i = 0; i < BiomeMap.Attributes.Length; ++i) - { - if (pixelBilinear == BiomeMap.Attributes[i].mapColor) - { - mapAttribute = BiomeMap.Attributes[i]; - } - } - } - else - { - float zero = 0; - float num = 1 / zero; - for (int j = 0; j < BiomeMap.Attributes.Length; ++j) - { - Color mapColor = BiomeMap.Attributes[j].mapColor; - float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude; - if (sqrMagnitude < num) - { - bool testCase = true; - if (BiomeMap.nonExactThreshold != -1) - { - testCase = (sqrMagnitude < BiomeMap.nonExactThreshold); - } - if (testCase) - { - mapAttribute = BiomeMap.Attributes[j]; - num = sqrMagnitude; - } - } - } - } - } - */ - } - catch (NullReferenceException) - { - mapAttribute = new CBAttributeMap.MapAttribute(); - mapAttribute.name = "N/A"; - } - - return mapAttribute; - } - - public static ExperimentSituations GetExperimentSituation(this Vessel vessel) - { - if (vessel == null) - { - return ExperimentSituations.SrfSplashed; - } - - Vessel.Situations situation = vessel.situation; - - switch (situation) - { - case Vessel.Situations.PRELAUNCH: - case Vessel.Situations.LANDED: - return ExperimentSituations.SrfLanded; - case Vessel.Situations.SPLASHED: - return ExperimentSituations.SrfSplashed; - case Vessel.Situations.FLYING: - if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold) - { - return ExperimentSituations.FlyingLow; - } - else - { - return ExperimentSituations.FlyingHigh; - } - } - - if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold) - { - return ExperimentSituations.InSpaceLow; - } - else - { - return ExperimentSituations.InSpaceHigh; - } - } - - public static string HumanString(this ExperimentSituations situation) - { - switch (situation) - { - case ExperimentSituations.FlyingHigh: - return "Upper Atmosphere"; - case ExperimentSituations.FlyingLow: - return "Flying"; - case ExperimentSituations.SrfLanded: - return "Surface"; - case ExperimentSituations.InSpaceLow: - return "Near in Space"; - case ExperimentSituations.InSpaceHigh: - return "High in Space"; - case ExperimentSituations.SrfSplashed: - return "Splashed Down"; - default: - return "Unknown"; - } - } - #endregion - - #region VESSEL_EXTENSIONS_LAT_LONG - public static string GetLongitudeString(this Vessel vessel, string format = "F4") - { - string dir_long = "W"; - double v_long = vessel.longitude; - - v_long = FixDegreeDomain(v_long); - - if (v_long < -180d) - { - v_long += 360d; - } - if (v_long >= 180) - { - v_long -= 360d; - } - - if (v_long > 0) - dir_long = "E"; - - return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long); - } - - public static string GetLatitudeString(this Vessel vessel, string format = "F4") - { - string dir_lat = "S"; - double v_lat = vessel.latitude; - if (v_lat > 0) - dir_lat = "N"; - - return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat); - } - #endregion - - #region VESSEL_EXTENSIONS_GENERAL - public static double TrueAltitude(Vessel vessel) - { - double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude; - - // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, - // and water covers the whole surface at 0 m. - if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean) - { - trueAltitude = vessel.orbit.altitude; - } - - return trueAltitude; - } - - public static double Radius(this Vessel vessel) - { - double radius; - - radius = vessel.altitude; - - if (vessel.mainBody != null) - { - radius += vessel.mainBody.Radius; - } - - return radius; - } - #endregion - - #region GEOMETRY_UTILS - public static double FixAngleDomain(double Angle, bool Degrees = false) - { - double Extent = 2d * Math.PI; - if (Degrees) - { - Extent = 360d; - } - - Angle = Angle % (Extent); - if (Angle < 0d) - { - Angle += Extent; - } - - return Angle; - } - - public static double FixDegreeDomain(double Angle) - { - return FixAngleDomain(Angle, true); - } - #endregion - - private static Dictionary functionCache; - public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action func) - { - if (functionCache == null) - { - functionCache = new Dictionary(); - } - - int hashCode = func.GetHashCode(); - - if (!functionCache.ContainsKey(hashCode)) - { - functionCache[hashCode] = delegate (int id) - { - try - { - func(id); - } - #if DEBUG - catch (ArgumentException ex) - #else - catch (ArgumentException) - #endif - { - Debug.LogWarning( - string.Format("[{0}]: ArgumentException caught during window call.", func.Target.GetType().Name) - ); - /*#if DEBUG - Debug.LogException(ex); - #endif*/ - } - }; - } - - return functionCache[hashCode]; - } - - /// - /// Converts the interval given in seconds to a human-friendly - /// time period in [years], [days], hours, minutes, and seconds. - /// - /// Uses sidereal days, since "6 hours per day" is the Kerbal standard. - /// - /// Human readable interval - /// - public static string ConvertInterval(double seconds) - { - double SecondsPerMinute = 60d; - double SecondsPerHour = 3600d; - double SecondsPerDay; - double SecondsPerYear; - - if (GameSettings.KERBIN_TIME) - { - SecondsPerDay = 21600d; - SecondsPerYear = 9203545d; - } - else - { - SecondsPerDay = 86164.1d; - SecondsPerYear = 31558149d; - } - - int years; - int days; - int hours; - int minutes; - - years = (int)(seconds / SecondsPerYear); - - seconds %= SecondsPerYear; - - days = (int)(seconds / SecondsPerDay); - - seconds %= SecondsPerDay; - - hours = (int)(seconds / SecondsPerHour); - - seconds %= SecondsPerHour; - - minutes = (int)(seconds / SecondsPerMinute); - - seconds %= SecondsPerMinute; - - string format_1 = string.Intern("{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s"); - string format_2 = string.Intern("{0:D1}d {1:D2}h {2:D2}m {3:00.0}s"); - string format_3 = string.Intern("{0:D2}h {1:D2}m {2:00.0}s"); - string format_4 = string.Intern("{0:D2}m {1:00.0}s"); - string format_5 = string.Intern("{0:00.0}s"); - - if (years > 0) - { - return string.Format(format_1, years, days, hours, minutes, seconds); - } - else if (days > 0) - { - return string.Format(format_2, days, hours, minutes, seconds); - } - else if (hours > 0) - { - return string.Format(format_3, hours, minutes, seconds); - } - else if (minutes > 0) - { - return string.Format(format_4, minutes, seconds); - } - else - { - return string.Format(format_5, seconds); - } - } - - public static string UppercaseFirst(string s) - { - if (string.IsNullOrEmpty(s)) - { - return string.Empty; - } - char[] a = s.ToCharArray(); - a[0] = char.ToUpper(a[0]); - return new string(a); - } - - //transfer angles - public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param) - { - r_target /= 1000; - r_current /= 1000; - grav_param /= 1000000000; - - 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_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param); - return 360 * (0.5 - (T_transfer / (2 * T_target))); - } - - public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2) - { - /* - def deltaVToGetToOtherBody(mu, r1, r2): - # mu = gravity param of common orbiting body of r1 and r2 - # (e.g. for mun to minmus, mu is kerbin's gravity param - # r1 = initial body's orbit radius - # r2 = target body's orbit radius - - # return value is km/s - sur1 = math.sqrt(mu / r1) - sr1r2 = math.sqrt(float(2*r2)/float(r1+r2)) - mult = sr1r2 - 1 - return sur1 * mult - */ - double sur1, sr1r2, mult; - sur1 = Math.Sqrt(mu / r1); - sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2)); - mult = sr1r2 - 1; - return sur1 * mult; - } - - public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v) - { - /* - def deltaVToExitSOI(mu, r1, r2, v): - # mu = gravity param of current body - # r1 = current orbit radius - # r2 = SOI radius - # v = SOI exit velocity - foo = r2 * (v**2) - 2 * mu - bar = r1 * foo + (2 * r2 * mu) - r = r1*r2 - return math.sqrt(bar / r) - */ - double foo = r2 * (v * v) - 2 * mu; - double bar = r1 * foo + (2 * r2 * mu); - double r = r1 * r2; - return Math.Sqrt(bar / r); - } - - public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu) - { - /* - def transferBurnPoint(r, v, angle, mu): - # r = parking orbit radius - # v = ejection velocity - # angle = phase angle (from function phaseAngle()) - # mu = gravity param of current body. - epsilon = ((v**2)/2) - (mu / r) - h = r * v * math.sin(angle) - e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2))) - theta = math.acos(1.0 / e) - degrees = theta * (180.0 / math.pi) - return 180 - degrees - */ - double epsilon, h, ee, theta, degrees; - epsilon = ((v * v) / 2) - (mu / r); - h = r * v * Math.Sin(angle); - ee = Math.Sqrt(1 + ((2 * epsilon * (h * h)) / (mu * mu))); - theta = Math.Acos(1.0 / ee); - degrees = theta * (180.0 / Math.PI); - return 180 - degrees; - // returns the ejection angle - } - - public static double Adammada_CurrrentPhaseAngle( - double body_LAN, - double body_orbitPct, - double origin_LAN, - double origin_orbitPct - ) - { - double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct); - if (angle > 1) - angle = angle - 1; - if (angle < 0) - angle = angle + 1; - if (angle > 0.5) - angle = angle - 1; - angle = angle * 360; - return angle; - } - - public static double Adammada_CurrentEjectionAngle( - double vessel_long, - double origin_rotAngle, - double origin_LAN, - double origin_orbitPct - ) - { - //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); - - while (eangle < 0) - eangle = eangle + 360; - while (eangle > 360) - eangle = eangle - 360; - if (eangle < 270) - eangle = 90 - eangle; - else - eangle = 450 - eangle; - return eangle; - } - - public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body - { - Vector3d vecthis = new Vector3d(); - Vector3d vectarget = new Vector3d(); - vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); - - if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun")) - { - vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); - } - else - { - vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime()); - } - - vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis); - vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget); - - Vector3d prograde = new Vector3d(); - prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis; - - double phase = Vector3d.Angle(vecthis, vectarget); - - if (Vector3d.Angle(prograde, vectarget) > 90) - phase = 360 - phase; - - return (phase + 360) % 360; - } - - public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase) - { - if (transfer_angle < 0) - { - if (curr_phase > 0) - return (-1 * (360 - curr_phase)); - else if (curr_phase < 0) - return curr_phase; - } - else if (transfer_angle > 0) - { - if (curr_phase > 0) - return curr_phase; - else if (curr_phase < 0) - return (360 + curr_phase); - } - return curr_phase; - } - - 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 - // need 0-360 instead - // - // ie i have -17 in the screenshot - // need it to show 343 - // - // do this - // - // if < 0, add curr to 360 // 360 + (-17) = 343 - // else its good as it is - - if (curr_ejection < 0) - return 360 + curr_ejection; - else - return curr_ejection; - - } - - public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase) - { - // if transfer_phase_angle < 0 its a lower transfer - //180 + curr_ejection - // else if transfer_phase_angle > 0 its good as it is - - if (trans_phase < 0) - return 180 + trans_ejection; - else - return trans_ejection; - - } - - public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel) - { - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Phase angle (curr/trans):"); - GUILayout.Label( - VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + VOID_Tools.Nivvy_CalcTransferPhaseAngle( - vessel.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.gravParameter - ).ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Transfer velocity:"); - GUILayout.Label( - (VOID_Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ) * 1000).ToString("F2") + "m/s", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - } - - public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel) - { - double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.referenceBody.gravParameter / 1000000000), - (vessel.mainBody.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (vessel.mainBody.sphereOfInfluence / 1000), - Math.Abs(dv1) - ); - - double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( - (vessel.orbit.semiMajorAxis / 1000), - dv2, - (Math.PI / 2.0), - (vessel.mainBody.gravParameter / 1000000000) - ); - double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( - FlightGlobals.ActiveVessel.longitude, - FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent - ); - - double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( - vessel.mainBody.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.referenceBody.gravParameter - ) % 360; - double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( - body.orbit.LAN, - body.orbit.orbitPercent, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent - ); - - 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_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Phase angle (curr/trans):"); - GUILayout.Label( - adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Ejection angle (curr/trans):"); - GUILayout.Label( - adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Transfer velocity:"); - GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - } - - public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel) - { - double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - - double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( - vessel.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.gravParameter - ); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Phase angle (curr/trans):"); - GUILayout.Label( - VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Transfer velocity:"); - GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - } - - public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel) - { - double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.referenceBody.gravParameter / 1000000000), - (vessel.mainBody.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - double dv2 = VOID_Tools.Younata_DeltaVToExitSOI( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (vessel.mainBody.sphereOfInfluence / 1000), - Math.Abs(dv1) - ); - double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint( - (vessel.orbit.semiMajorAxis / 1000), - dv2, - (Math.PI / 2.0), - (vessel.mainBody.gravParameter / 1000000000) - ); - - double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle( - body.orbit.LAN, - body.orbit.orbitPercent, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent - ); - double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle( - FlightGlobals.ActiveVessel.longitude, - FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN, - FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent - ); - - double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle( - vessel.mainBody.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.referenceBody.gravParameter - ) % 360; - - double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); - //double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle); - - //new stuff - // - 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); - // - // - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Phase angle (curr/trans):"); - GUILayout.Label( - adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Ejection angle (curr/trans):"); - GUILayout.Label( - adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°", - GUILayout.ExpandWidth(false) - ); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Transfer velocity:"); - GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - } - - public static string get_heading_text(double heading) - { - if (heading > 348.75 || heading <= 11.25) - return "N"; - else if (heading > 11.25 && heading <= 33.75) - return "NNE"; - else if (heading > 33.75 && heading <= 56.25) - return "NE"; - else if (heading > 56.25 && heading <= 78.75) - return "ENE"; - else if (heading > 78.75 && heading <= 101.25) - return "E"; - else if (heading > 101.25 && heading <= 123.75) - return "ESE"; - else if (heading > 123.75 && heading <= 146.25) - return "SE"; - else if (heading > 146.25 && heading <= 168.75) - return "SSE"; - else if (heading > 168.75 && heading <= 191.25) - return "S"; - else if (heading > 191.25 && heading <= 213.75) - return "SSW"; - else if (heading > 213.75 && heading <= 236.25) - return "SW"; - else if (heading > 236.25 && heading <= 258.75) - return "WSW"; - else if (heading > 258.75 && heading <= 281.25) - return "W"; - else if (heading > 281.25 && heading <= 303.75) - return "WNW"; - else if (heading > 303.75 && heading <= 326.25) - return "NW"; - else if (heading > 326.25 && heading <= 348.75) - return "NNW"; - else - return ""; - } - } - - public class CBListComparer : IComparer - { - public int Compare(CelestialBody bodyA, CelestialBody bodyB) - { - Tools.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB); - - if (bodyA == null && bodyB == null) - { - Tools.PostDebugMessage(this, "both bodies are null, returning 0"); - return 0; - } - if (bodyA == null) - { - Tools.PostDebugMessage(this, "bodyA is null, returning -1"); - return -1; - } - if (bodyB == null) - { - Tools.PostDebugMessage(this, "bodyB is null, returning 1"); - return 1; - } - - Tools.PostDebugMessage(this, "bodies are not null, carrying on"); - - if (object.ReferenceEquals(bodyA, bodyB)) - { - Tools.PostDebugMessage(this, "bodies are equal, returning 0"); - return 0; - } - - Tools.PostDebugMessage(this, "bodies are not equal, carrying on"); - - if (bodyA.orbitDriver == null) - { - Tools.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1"); - return 1; - } - if (bodyB.orbitDriver == null) - { - Tools.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1"); - return -1; - } - - Tools.PostDebugMessage(this, "orbits are not null, carrying on"); - - if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody) - { - Tools.PostDebugMessage(this, "bodies share a parent, comparing SMAs"); - return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis); - } - - Tools.PostDebugMessage(this, "orbits do not share a parent, carrying on"); - - if (bodyA.hasAncestor(bodyB)) - { - Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1"); - return -1; - } - if (bodyB.hasAncestor(bodyA)) - { - Tools.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1"); - return 1; - } - - Tools.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one"); - - if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB)) - { - Tools.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName); - return this.Compare(bodyA, bodyB); - } - - Tools.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName); - - return 0; - } - } -} - --- a/VOID_Transfer.cs +++ b/VOID_Transfer.cs @@ -29,7 +29,6 @@ using KSP; using System; using System.Collections.Generic; -using System.Linq; using ToadicusTools; using UnityEngine; @@ -39,23 +38,27 @@ { protected List selectedBodies = new List(); - public VOID_Transfer() + public VOID_Transfer() : base() { - this._Name = "Transfer Angle Information"; + this.Name = "Transfer Angle Information"; this.WindowPos.x = 475; this.WindowPos.y = 85; this.defWidth = 315; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { + CelestialBody body; + GUILayout.BeginVertical(); - if (vessel.mainBody.name == "Sun") //Vessel is orbiting the Sun + if (Vessel.mainBody.name == "Sun") //Vessel is orbiting the Sun { - foreach (CelestialBody body in vessel.mainBody.orbitingBodies) + for (int idx = 0; idx < Vessel.mainBody.orbitingBodies.Count; idx++) { + body = Vessel.mainBody.orbitingBodies[idx]; + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button(body.bodyName)) { @@ -68,16 +71,17 @@ if (selectedBodies.Contains(body)) { - VOID_Tools.display_transfer_angles_SUN2PLANET(body, vessel); //show phase angles for each selected body + VOID_Tools.display_transfer_angles_SUN2PLANET(body, Vessel); //show phase angles for each selected body tad_targeting(body); //display Set/Unset Target button for each selected body } } } - else if (vessel.mainBody.referenceBody.name == "Sun") //Vessel is orbiting a planet + else if (Vessel.mainBody.referenceBody.name == "Sun") //Vessel is orbiting a planet { - foreach (CelestialBody body in vessel.mainBody.referenceBody.orbitingBodies) - { - if (body.name != vessel.mainBody.name) // show other planets + for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++) + { + body = Vessel.mainBody.referenceBody.orbitingBodies[idx]; + if (body.name != Vessel.mainBody.name) // show other planets { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button(body.bodyName)) @@ -91,13 +95,15 @@ if (selectedBodies.Contains(body)) { - VOID_Tools.display_transfer_angles_PLANET2PLANET(body, vessel); + VOID_Tools.display_transfer_angles_PLANET2PLANET(body, Vessel); tad_targeting(body); //display Set/Unset Target button } } } - foreach (CelestialBody body in vessel.mainBody.orbitingBodies) // show moons + for (int moonIdx = 0; moonIdx < Vessel.mainBody.orbitingBodies.Count; moonIdx++) { + body = Vessel.mainBody.orbitingBodies[moonIdx]; + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button(body.bodyName)) { @@ -110,16 +116,18 @@ if (selectedBodies.Contains(body)) { - VOID_Tools.display_transfer_angles_PLANET2MOON(body, vessel); + VOID_Tools.display_transfer_angles_PLANET2MOON(body, Vessel); tad_targeting(body); //display Set/Unset Target button } } } - else if (vessel.mainBody.referenceBody.referenceBody.name == "Sun") // Vessel is orbiting a moon + else if (Vessel.mainBody.referenceBody.referenceBody.name == "Sun") // Vessel is orbiting a moon { - foreach (CelestialBody body in vessel.mainBody.referenceBody.orbitingBodies) + for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++) { - if (body.name != vessel.mainBody.name) // show other moons + body = Vessel.mainBody.referenceBody.orbitingBodies[idx]; + + if (body.name != Vessel.mainBody.name) // show other moons { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button(body.bodyName)) @@ -133,14 +141,15 @@ if (selectedBodies.Contains(body)) { - VOID_Tools.display_transfer_angles_MOON2MOON(body, vessel); + VOID_Tools.display_transfer_angles_MOON2MOON(body, Vessel); tad_targeting(body); //display Set/Unset Target button } } } } GUILayout.EndVertical(); - GUI.DragWindow(); + + base.ModuleWindow(id); } private void tad_targeting(CelestialBody body) @@ -154,7 +163,7 @@ if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) { FlightGlobals.fetch.SetVesselTarget(body); - Tools.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); + Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); } } else if ((CelestialBody)FlightGlobals.fetch.VesselTarget == body) @@ -162,7 +171,7 @@ if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false))) { FlightGlobals.fetch.SetVesselTarget(null); - Tools.PostDebugMessage("[VOID] KSP Target set to null"); + Logging.PostDebugMessage("[VOID] KSP Target set to null"); } } } @@ -172,7 +181,7 @@ if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) { FlightGlobals.fetch.SetVesselTarget(body); - Tools.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); + Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); } } } --- a/VOID_VesselInfo.cs +++ b/VOID_VesselInfo.cs @@ -26,12 +26,11 @@ // 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 Engineer.VesselSimulator; -using Engineer.Extensions; +using KerbalEngineer.VesselSimulator; +using KerbalEngineer.Extensions; using KSP; using System; using System.Collections.Generic; -using ToadicusTools; using UnityEngine; namespace VOID @@ -40,13 +39,13 @@ { public VOID_VesselInfo() : base() { - this._Name = "Vessel Information"; + this.Name = "Vessel Information"; this.WindowPos.x = Screen.width - 260; this.WindowPos.y = 450; } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) { @@ -56,271 +55,38 @@ GUILayout.BeginVertical(); GUILayout.Label( - vessel.vesselName, - core.LabelStyles["center_bold"], + Vessel.vesselName, + VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); - VOID_Data.geeForce.DoGUIHorizontal ("F2"); + VOID_Data.geeForce.DoGUIHorizontal("F2"); - VOID_Data.partCount.DoGUIHorizontal (); + VOID_Data.partCount.DoGUIHorizontal(); - VOID_Data.totalMass.DoGUIHorizontal ("F3"); + VOID_Data.totalMass.DoGUIHorizontal("F3"); - VOID_Data.comboResourceMass.DoGUIHorizontal (); + VOID_Data.stageResourceMass.DoGUIHorizontal("F3"); - VOID_Data.stageDeltaV.DoGUIHorizontal (3, false); + VOID_Data.resourceMass.DoGUIHorizontal("F3"); - VOID_Data.totalDeltaV.DoGUIHorizontal (3, false); + VOID_Data.stageDeltaV.DoGUIHorizontal(3, false); - VOID_Data.mainThrottle.DoGUIHorizontal ("F0"); + VOID_Data.totalDeltaV.DoGUIHorizontal(3, false); - VOID_Data.currmaxThrust.DoGUIHorizontal (); + VOID_Data.mainThrottle.DoGUIHorizontal("P0"); - VOID_Data.currmaxThrustWeight.DoGUIHorizontal (); + VOID_Data.currmaxThrust.DoGUIHorizontal(); - VOID_Data.surfaceThrustWeight.DoGUIHorizontal ("F2"); + VOID_Data.currmaxThrustWeight.DoGUIHorizontal(); + + VOID_Data.surfaceThrustWeight.DoGUIHorizontal("F2"); VOID_Data.intakeAirStatus.DoGUIHorizontal(); GUILayout.EndVertical(); - GUI.DragWindow(); + base.ModuleWindow(id); } - } - - public static partial class VOID_Data - { - public static readonly VOID_DoubleValue geeForce = new VOID_DoubleValue( - "G-force", - new Func(() => core.vessel.geeForce), - "gees" - ); - - public static readonly VOID_IntValue partCount = new VOID_IntValue( - "Parts", - new Func(() => core.vessel.Parts.Count), - "" - ); - - public static readonly VOID_DoubleValue totalMass = new VOID_DoubleValue( - "Total Mass", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - { - return double.NaN; - } - - return SimManager.LastStage.totalMass; - }, - "tons" - ); - - public static readonly VOID_DoubleValue resourceMass = new VOID_DoubleValue( - "Resource Mass", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - { - return double.NaN; - } - - return SimManager.LastStage.totalMass - SimManager.LastStage.totalBaseMass; - }, - "tons" - ); - - public static readonly VOID_DoubleValue stageResourceMass = new VOID_DoubleValue( - "Resource Mass (Current Stage)", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - return SimManager.LastStage.mass - SimManager.LastStage.baseMass; - }, - "tons" - ); - - public static readonly VOID_StrValue comboResourceMass = new VOID_StrValue( - "Resource Mass (curr / total)", - delegate() - { - return string.Format("{0} / {1}", - stageResourceMass.ValueUnitString("F3"), - resourceMass.ValueUnitString("F3") - ); - } - ); - - public static readonly VOID_DoubleValue stageDeltaV = new VOID_DoubleValue( - "DeltaV (Current Stage)", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - return double.NaN; - return SimManager.LastStage.deltaV; - }, - "m/s" - ); - - public static readonly VOID_DoubleValue totalDeltaV = new VOID_DoubleValue( - "DeltaV (Total)", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - return double.NaN; - return SimManager.LastStage.totalDeltaV; - }, - "m/s" - ); - - public static readonly VOID_FloatValue mainThrottle = new VOID_FloatValue( - "Throttle", - new Func(() => core.vessel.ctrlState.mainThrottle * 100f), - "%" - ); - - public static readonly VOID_StrValue currmaxThrust = new VOID_StrValue( - "Thrust (curr/max)", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - return "N/A"; - - double currThrust = SimManager.LastStage.actualThrust; - double maxThrust = SimManager.LastStage.thrust; - - return string.Format( - "{0} / {1}", - currThrust.ToString("F1"), - maxThrust.ToString("F1") - ); - } - ); - - public static readonly VOID_DoubleValue currThrustWeight = new VOID_DoubleValue( - "T:W Ratio", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - return SimManager.LastStage.actualThrustToWeight; - }, - "" - ); - - public static readonly VOID_DoubleValue maxThrustWeight = new VOID_DoubleValue( - "T:W Ratio", - delegate() - { - if (SimManager.LastStage == null) - { - return double.NaN; - } - - return SimManager.LastStage.thrustToWeight; - }, - "" - ); - - public static readonly VOID_StrValue currmaxThrustWeight = new VOID_StrValue( - "T:W (curr/max)", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - return "N/A"; - - return string.Format( - "{0} / {1}", - (VOID_Data.currThrustWeight.Value).ToString("F2"), - (VOID_Data.maxThrustWeight.Value).ToString("F2") - ); - } - ); - - public static readonly VOID_DoubleValue surfaceThrustWeight = new VOID_DoubleValue( - "Max T:W @ surface", - delegate() - { - if (SimManager.Stages == null || SimManager.LastStage == null) - return double.NaN; - - double maxThrust = SimManager.LastStage.thrust; - double mass = SimManager.LastStage.totalMass; - double gravity = (VOID_Core.Constant_G * core.vessel.mainBody.Mass) / - (core.vessel.mainBody.Radius * core.vessel.mainBody.Radius); - double weight = mass * gravity; - - return maxThrust / weight; - }, - "" - ); - - public static readonly VOID_StrValue intakeAirStatus = new VOID_StrValue( - "Intake Air (Curr / Req)", - delegate() - { - double currentAmount; - double currentRequirement; - - currentAmount = 0d; - currentRequirement = 0d; - - foreach (Part part in core.vessel.Parts) - { - if (part.enabled) - { - ModuleEngines engineModule; - ModuleEnginesFX enginesFXModule; - List propellantList = null; - - if (part.tryGetFirstModuleOfType(out engineModule)) - { - propellantList = engineModule.propellants; - } - else if (part.tryGetFirstModuleOfType(out enginesFXModule)) - { - propellantList = enginesFXModule.propellants; - } - - if (propellantList != null) - { - foreach (Propellant propellant in propellantList) - { - if (propellant.name == "IntakeAir") - { - currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; - break; - } - } - } - } - - ModuleResourceIntake intakeModule; - - if (part.enabled && part.tryGetFirstModuleOfType(out intakeModule)) - { - if (intakeModule.resourceName == "IntakeAir") - { - currentAmount += intakeModule.airFlow; - } - } - } - - if (currentAmount == 0 && currentRequirement == 0) - { - return "N/A"; - } - - return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement); - } - ); } } --- a/VOID_VesselRegister.cs +++ b/VOID_VesselRegister.cs @@ -28,8 +28,6 @@ using KSP; using System; -using System.Linq; -using ToadicusTools; using UnityEngine; namespace VOID @@ -37,16 +35,16 @@ public class VOID_VesselRegister : VOID_WindowModule { [AVOID_SaveValue("selectedBodyIdx")] - protected VOID_SaveValue selectedBodyIdx = 0; + protected VOID_SaveValue selectedBodyIdx; protected CelestialBody seletedBody; [AVOID_SaveValue("selectedVesselTypeIdx")] - protected VOID_SaveValue selectedVesselTypeIdx = 0; + protected VOID_SaveValue selectedVesselTypeIdx; protected VesselType selectedVesselType; - protected string vesselSituation = "Orbiting"; + protected string vesselSituation; - protected Vector2 selectorScrollPos = new Vector2(); + protected Vector2 selectorScrollPos; protected Vessel _selectedVessel; @@ -58,20 +56,37 @@ } } - public VOID_VesselRegister() + public VOID_VesselRegister() : base() { - this._Name = "Vessel Register"; + this.Name = "Vessel Register"; this.WindowPos.x = 845; this.WindowPos.y = 275; this.defHeight = 375; + + this.selectedBodyIdx = (VOID_SaveValue)0; + this.selectedVesselTypeIdx = (VOID_SaveValue)0; + + this.vesselSituation = "Orbiting"; + + this.selectorScrollPos = new Vector2(); } - public override void ModuleWindow(int _) + public override void ModuleWindow(int id) { - if (!this.core.allVesselTypes.Any()) + if (this.core.AllVesselTypes.Length < 1) { return; + } + + if (selectedBodyIdx >= this.core.SortedBodyList.Count) + { + selectedBodyIdx.value %= this.core.SortedBodyList.Count; + } + + if (selectedBodyIdx < 0) + { + selectedBodyIdx.value += this.core.SortedBodyList.Count; } GUILayout.BeginVertical(); @@ -79,34 +94,46 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<")) { - selectedBodyIdx--; - if (selectedBodyIdx < 0) selectedBodyIdx = this.core.allBodies.Count - 1; + selectedBodyIdx.value--; + if (selectedBodyIdx < 0) + { + selectedBodyIdx.value = this.core.SortedBodyList.Count - 1; + } } - GUILayout.Label(this.core.allBodies[selectedBodyIdx].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + GUILayout.Label(this.core.SortedBodyList[selectedBodyIdx].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">")) { - selectedBodyIdx++; - if (selectedBodyIdx > this.core.allBodies.Count - 1) selectedBodyIdx = 0; + selectedBodyIdx.value++; + if (selectedBodyIdx > this.core.SortedBodyList.Count - 1) + { + selectedBodyIdx.value = 0; + } } GUILayout.EndHorizontal(); - seletedBody = this.core.allBodies[selectedBodyIdx]; + seletedBody = this.core.SortedBodyList[selectedBodyIdx]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<")) { - selectedVesselTypeIdx--; - if (selectedVesselTypeIdx < 0) selectedVesselTypeIdx = this.core.allVesselTypes.Count - 1; + selectedVesselTypeIdx.value--; + if (selectedVesselTypeIdx < 0) + { + selectedVesselTypeIdx.value = this.core.AllVesselTypes.Length - 1; + } } - GUILayout.Label(this.core.allVesselTypes[selectedVesselTypeIdx].ToString(), this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + GUILayout.Label(this.core.AllVesselTypes[selectedVesselTypeIdx].ToString(), VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">")) { - selectedVesselTypeIdx++; - if (selectedVesselTypeIdx > this.core.allVesselTypes.Count - 1) selectedVesselTypeIdx = 0; + selectedVesselTypeIdx.value++; + if (selectedVesselTypeIdx > this.core.AllVesselTypes.Length - 1) + { + selectedVesselTypeIdx.value = 0; + } } GUILayout.EndHorizontal(); - selectedVesselType = this.core.allVesselTypes[selectedVesselTypeIdx]; + selectedVesselType = this.core.AllVesselTypes[selectedVesselTypeIdx]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Landed", GUILayout.ExpandWidth(true))) vesselSituation = "Landed"; @@ -116,15 +143,18 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label( VOID_Tools.UppercaseFirst(vesselSituation) + " " + selectedVesselType.ToString() + "s @ " + seletedBody.bodyName, - this.core.LabelStyles["center"], + VOID_Styles.labelCenter, GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); selectorScrollPos = GUILayout.BeginScrollView(selectorScrollPos, false, false); - foreach (Vessel v in FlightGlobals.Vessels) + Vessel v; + for (int idx = 0; idx < FlightGlobals.Vessels.Count; idx++) { - if (v != vessel && v.vesselType == selectedVesselType && v.mainBody == seletedBody) + v = FlightGlobals.Vessels[idx]; + + if (v != Vessel && v.vesselType == selectedVesselType && v.mainBody == seletedBody) { if ((vesselSituation == "Landed" && (v.situation == Vessel.Situations.LANDED || @@ -142,7 +172,7 @@ if (_selectedVessel != v) { _selectedVessel = v; //set clicked vessel as selected_vessel - this._Active.value = true; //turn bool on to open the window if closed + this.Active = true; //turn bool on to open the window if closed } else { @@ -157,7 +187,7 @@ GUILayout.EndVertical(); - GUI.DragWindow(); + base.ModuleWindow(id); } } }