From: toadicus Date: Tue, 19 May 2015 00:08:45 +0000 Subject: Stop allocating a new Vessel and CelestialBody every window frame because WTF. X-Git-Tag: 0.18.3 X-Git-Url: http://git.toad.homelinux.net/projects/VOID.git/commitdiff/c093e2e --- Stop allocating a new Vessel and CelestialBody every window frame because WTF. --- --- 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,59 @@ +// 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(); + void StartGUI(); + void StopGUI(); + + void DrawConfigurables(); + + void LoadConfig(); + + void Save(KSP.IO.PluginConfiguration config); + } + + 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,91 @@ +// 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.Collections.Generic; +using ToadicusTools; +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 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 IList AllBodies { 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 void OnGUI() {} + + public override void LoadConfig() + { + base.LoadConfig(); + } + + public abstract void SaveConfig(); + + public override void Save(KSP.IO.PluginConfiguration config) + { + base.Save(config); + } + } + + public delegate void VOIDEventHandler(object sender); +} + + --- /dev/null +++ b/API/VOIDMaster.cs @@ -1,1 +1,163 @@ +// 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; + +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"); + 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,229 @@ - +// 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; +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() + { + 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 = GUITools.Toggle(this.positionsLocked, "Lock HUD Positions"); + } + + public override void LoadConfig() + { + base.LoadConfig(); + + var config = KSP.IO.PluginConfiguration.CreateForType(); + 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) + { + base.Save(config); + + 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,578 @@ - +// 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.Reflection; +using ToadicusTools; +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); + } + } + } + + 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) + { + Tools.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; + + Tools.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 + }; + + Tools.PostDebugMessage("No VOID_GameModesAttribute found; validScenes defaulted to flight."); + } + } + + return this.validModes; + } + } + + public virtual GameScenes[] ValidScenes + { + get + { + if (this.validScenes == null) + { + Tools.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; + + Tools.PostDebugMessage("Found VOID_ScenesAttribute; validScenes set."); + + break; + } + } + + if (this.validScenes == null) + { + this.validScenes = new GameScenes[] { GameScenes.FLIGHT }; + Tools.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; + } + + Tools.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name)); + RenderingManager.AddToPostDrawQueue (3, this.DrawGUI); + } + + public virtual void StopGUI() + { + if (!this.GUIRunning) + { + return; + } + Tools.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name)); + RenderingManager.RemoveFromPostDrawQueue (3, this.DrawGUI); + } + + public abstract void DrawGUI(); + + public virtual void DrawConfigurables() {} + + public virtual void LoadConfig() + { + var config = KSP.IO.PluginConfiguration.CreateForType (); + 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 + ); + } + + Tools.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); + } + + Tools.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName)); + } + } + + public virtual void Save(KSP.IO.PluginConfiguration config) + { + 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, + Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene), + 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); + + 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; + 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() + { + 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 = Tools.ClampRectToEditorPad(_Pos); + } + else + { + _Pos = Tools.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,69 @@ +// 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_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,50 +1,1 @@ -// -// IVOID_Module.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -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/IntCollection.cs +++ /dev/null @@ -1,81 +1,1 @@ -// -// IntCollection.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -namespace VOID -{ - public class IntCollection - { - public static implicit operator long(IntCollection c) - { - return c.collection; - } - - protected long mask; - - public long collection { get; protected set; } - public ushort maxCount { get; protected set; } - public ushort wordLength { get; protected set; } - - public IntCollection (ushort wordLength = 4, long initialCollection = 0) - { - this.collection = initialCollection; - this.wordLength = wordLength; - this.maxCount = (ushort)((sizeof(long) * 8 - 1) / wordLength); - this.mask = ((1 << this.wordLength) - 1); - } - - public ushort this[int idx] - { - get { - if (idx < 0) { - idx += this.maxCount; - } - - if (idx >= maxCount || idx < 0) { - throw new IndexOutOfRangeException (); - } - - idx *= wordLength; - - return (ushort)((this.collection & (this.mask << idx)) >> idx); - } - set { - if (idx < 0) { - idx += this.maxCount; - } - - if (idx >= maxCount || idx < 0) { - throw new IndexOutOfRangeException (); - } - - idx *= wordLength; - - long packvalue = value & this.mask; - - this.collection &= ~(this.mask << idx); - this.collection |= packvalue << idx; - } - } - } -} - - --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -1,1 +1,48 @@ +// VOID +// +// AssemblyInfo.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.Reflection; +using System.Runtime.CompilerServices; +[assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)] +[assembly: KSPAssemblyDependency("VesselSimulator", 0, 0)] + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("VOID")] +[assembly: AssemblyDescription("A KSP mod that provides at-a-glance information about Vessels, Orbits, and their states.")] +[assembly: AssemblyCopyright("toadicus")] +// 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.18.2.*")] +// 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("")] + + --- a/Tools.cs +++ /dev/null @@ -1,1063 +1,1 @@ -// -// Tools.cs -// -// Author: -// toadicus -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux. -// Engineer Redux (c) 2013 cybutek -// Used by permission. -// -/////////////////////////////////////////////////////////////////////////////// -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace VOID -{ - public static class VOIDLabels - { - 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"; - } - - public static class Tools - { - // Toadicus edit: Added re-implementation of the CBAttributeMap.GetAtt function that does not fire a debug message to the game screen. - public static CBAttributeMap.MapAttribute Toadicus_GetAtt(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 string GetLongitudeString(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(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); - } - - /////////////////////////////////////////////////////////////////////////////// - - //For MuMech_get_heading() - public class MuMech_MovingAverage - { - private double[] store; - private int storeSize; - private int nextIndex = 0; - - public double value - { - get - { - double tmp = 0; - foreach (double i in store) - { - tmp += i; - } - return tmp / storeSize; - } - set - { - store[nextIndex] = value; - nextIndex = (nextIndex + 1) % storeSize; - } - } - - public MuMech_MovingAverage(int size = 10, double startingValue = 0) - { - storeSize = size; - store = new double[size]; - force(startingValue); - } - - public void force(double newValue) - { - for (int i = 0; i < storeSize; i++) - { - store[i] = newValue; - } - } - - public static implicit operator double(MuMech_MovingAverage v) - { - return v.value; - } - - public override string ToString() - { - return value.ToString(); - } - - public string ToString(string format) - { - return value.ToString(format); - } - } - //From http://svn.mumech.com/KSP/trunk/MuMechLib/VOID.vesselState.cs - public static double MuMech_get_heading(Vessel vessel) - { - Vector3d CoM; - - try - { - CoM = vessel.findWorldCenterOfMass(); - } - catch - { - return double.NaN; - } - - Vector3d up = (CoM - vessel.mainBody.position).normalized; - Vector3d north = Vector3d.Exclude( - up, - (vessel.mainBody.position + - vessel.mainBody.transform.up * (float)vessel.mainBody.Radius - ) - CoM).normalized; - - Quaternion rotationSurface = Quaternion.LookRotation(north, up); - Quaternion rotationvesselSurface = Quaternion.Inverse( - Quaternion.Euler(90, 0, 0) * - Quaternion.Inverse(vessel.transform.rotation) * - rotationSurface); - - return rotationvesselSurface.eulerAngles.y; - } - //From http://svn.mumech.com/KSP/trunk/MuMechLib/MuUtils.cs - public static string MuMech_ToSI( - double d, int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue - ) - { - float exponent = (float)Math.Log10(Math.Abs(d)); - exponent = Mathf.Clamp(exponent, (float)MinMagnitude, (float)MaxMagnitude); - - if (exponent >= 0) - { - switch ((int)Math.Floor(exponent)) - { - case 0: - case 1: - case 2: - return d.ToString("F" + digits); - case 3: - case 4: - case 5: - return (d / 1e3).ToString("F" + digits) + "k"; - case 6: - case 7: - case 8: - return (d / 1e6).ToString("F" + digits) + "M"; - case 9: - case 10: - case 11: - return (d / 1e9).ToString("F" + digits) + "G"; - case 12: - case 13: - case 14: - return (d / 1e12).ToString("F" + digits) + "T"; - case 15: - case 16: - case 17: - return (d / 1e15).ToString("F" + digits) + "P"; - case 18: - case 19: - case 20: - return (d / 1e18).ToString("F" + digits) + "E"; - case 21: - case 22: - case 23: - return (d / 1e21).ToString("F" + digits) + "Z"; - default: - return (d / 1e24).ToString("F" + digits) + "Y"; - } - } - else if (exponent < 0) - { - switch ((int)Math.Floor(exponent)) - { - case -1: - case -2: - case -3: - return (d * 1e3).ToString("F" + digits) + "m"; - case -4: - case -5: - case -6: - return (d * 1e6).ToString("F" + digits) + "μ"; - case -7: - case -8: - case -9: - return (d * 1e9).ToString("F" + digits) + "n"; - case -10: - case -11: - case -12: - return (d * 1e12).ToString("F" + digits) + "p"; - case -13: - case -14: - case -15: - return (d * 1e15).ToString("F" + digits) + "f"; - case -16: - case -17: - case -18: - return (d * 1e18).ToString("F" + digits) + "a"; - case -19: - case -20: - case -21: - return (d * 1e21).ToString("F" + digits) + "z"; - default: - return (d * 1e24).ToString("F" + digits) + "y"; - } - } - else - { - return "0"; - } - } - - public static string ConvertInterval(double seconds) - { - string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:D2}.{5:D1}s"; - string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:D2}.{4:D1}s"; - string format_3 = "{0:D2}h {1:D2}m {2:D2}.{3:D1}s"; - - TimeSpan interval; - - try - { - interval = TimeSpan.FromSeconds(seconds); - } - catch (OverflowException) - { - return "NaN"; - } - - int years = interval.Days / 365; - - string output; - if (years > 0) - { - output = string.Format(format_1, - years, - interval.Days - (years * 365), // subtract years * 365 for accurate day count - interval.Hours, - interval.Minutes, - interval.Seconds, - interval.Milliseconds.ToString().Substring(0, 1)); - } - else if (interval.Days > 0) - { - output = string.Format(format_2, - interval.Days, - interval.Hours, - interval.Minutes, - interval.Seconds, - interval.Milliseconds.ToString().Substring(0, 1)); - } - else - { - output = string.Format(format_3, - interval.Hours, - interval.Minutes, - interval.Seconds, - interval.Milliseconds.ToString().Substring(0, 1)); - } - return output; - } - - 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) - { - double T_target = (2 * Math.PI) * Math.Sqrt(Math.Pow((r_target / 1000), 3) / (grav_param / 1000000000)); - double T_transfer = (2 * Math.PI) * Math.Sqrt(Math.Pow((((r_target / 1000) + (r_current / 1000)) / 2), 3) / (grav_param / 1000000000)); - 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 * Math.Pow(v, 2) - 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 = (Math.Pow(v, 2) / 2) - (mu / r); - h = r * v * Math.Sin(angle); - ee = Math.Sqrt(1 + ((2 * epsilon * Math.Pow(h, 2)) / Math.Pow(mu, 2))); - 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 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); - } - - 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 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 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 static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel) - { - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label("Phase angle (curr/trans):"); - GUILayout.Label( - Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + 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( - (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 = Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.referenceBody.gravParameter / 1000000000), - (vessel.mainBody.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - double dv2 = Tools.Younata_DeltaVToExitSOI( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (vessel.mainBody.sphereOfInfluence / 1000), - Math.Abs(dv1) - ); - - double trans_ejection_angle = Tools.Younata_TransferBurnPoint( - (vessel.orbit.semiMajorAxis / 1000), - dv2, - (Math.PI / 2.0), - (vessel.mainBody.gravParameter / 1000000000) - ); - double curr_ejection_angle = 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 = Tools.Nivvy_CalcTransferPhaseAngle( - vessel.mainBody.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.referenceBody.gravParameter - ) % 360; - double curr_phase_angle = 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 = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle); - double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); - double adj_curr_ejection_angle = 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 = Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - - double trans_phase_angle = 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( - 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 = Tools.Younata_DeltaVToGetToOtherBody( - (vessel.mainBody.referenceBody.gravParameter / 1000000000), - (vessel.mainBody.orbit.semiMajorAxis / 1000), - (body.orbit.semiMajorAxis / 1000) - ); - double dv2 = Tools.Younata_DeltaVToExitSOI( - (vessel.mainBody.gravParameter / 1000000000), - (vessel.orbit.semiMajorAxis / 1000), - (vessel.mainBody.sphereOfInfluence / 1000), - Math.Abs(dv1) - ); - double trans_ejection_angle = Tools.Younata_TransferBurnPoint( - (vessel.orbit.semiMajorAxis / 1000), - dv2, - (Math.PI / 2.0), - (vessel.mainBody.gravParameter / 1000000000) - ); - - double curr_phase_angle = 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 = 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 = Tools.Nivvy_CalcTransferPhaseAngle( - vessel.mainBody.orbit.semiMajorAxis, - body.orbit.semiMajorAxis, - vessel.mainBody.referenceBody.gravParameter - ) % 360; - - double adj_phase_angle = 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 = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle); - double adj_curr_ejection_angle = 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(); - } - // This implementation is adapted from FARGUIUtils.ClampToScreen - public static Rect ClampRectToScreen(Rect window, int xMargin, int yMargin) - { - window.x = Mathf.Clamp(window.x, xMargin - window.width, Screen.width - xMargin); - window.y = Mathf.Clamp(window.y, yMargin - window.height, Screen.height - yMargin); - - return window; - } - - public static Rect ClampRectToScreen(Rect window, int Margin) - { - return ClampRectToScreen(window, Margin, Margin); - } - - public static Rect ClampRectToScreen(Rect window) - { - return ClampRectToScreen(window, 30); - } - - public static Vector2 ClampV2ToScreen(Vector2 vec, uint xMargin, uint yMargin) - { - vec.x = Mathf.Clamp(vec.x, xMargin, Screen.width - xMargin); - vec.y = Mathf.Clamp(vec.y, yMargin, Screen.height - yMargin); - - return vec; - } - - public static Vector2 ClampV2ToScreen(Vector2 vec, uint Margin) - { - return ClampV2ToScreen(vec, Margin, Margin); - } - - public static Vector2 ClampV2ToScreen(Vector2 vec) - { - return ClampV2ToScreen(vec, 15); - } - // UNDONE: This seems messy. Can we clean it up? - public static Rect DockToWindow(Rect icon, Rect window) - { - // We can't set the x and y of the center point directly, so build a new vector. - Vector2 center = new Vector2(); - - // If we are near the top or bottom of the screen... - if (window.yMax > Screen.height - icon.height || - window.yMin < icon.height) - { - // If we are in a corner... - if (window.xMax > Screen.width - icon.width || - window.xMin < icon.width) - { - // If it is a top corner, put the icon below the window. - if (window.yMax < Screen.height / 2) - { - center.y = window.yMax + icon.height / 2; - } - // If it is a bottom corner, put the icon above the window. - else - { - center.y = window.yMin - icon.height / 2; - } - } - // If we are not in a corner... - else - { - // If we are along the top edge, align the icon's top edge with the top edge of the window - if (window.yMax > Screen.height / 2) - { - center.y = window.yMax - icon.height / 2; - } - // If we are along the bottom edge, align the icon's bottom edge with the bottom edge of the window - else - { - center.y = window.yMin + icon.height / 2; - } - } - - // At the top or bottom, if we are towards the right, put the icon to the right of the window - if (window.center.x < Screen.width / 2) - { - center.x = window.xMin - icon.width / 2; - } - // At the top or bottom, if we are towards the left, put the icon to the left of the window - else - { - center.x = window.xMax + icon.width / 2; - } - - } - // If we are not along the top or bottom of the screen... - else - { - // By default, center the icon above the window - center.y = window.yMin - icon.height / 2; - center.x = window.center.x; - - // If we are along a side... - if (window.xMax > Screen.width - icon.width || - window.xMin < icon.width) - { - // UNDONE: I'm not sure I like the feel of this part. - // If we are along a side towards the bottom, put the icon below the window - if (window.center.y > Screen.height / 2) - { - center.y = window.yMax + icon.height / 2; - } - - // Along the left side, align the left edge of the icon with the left edge of the window. - if (window.xMax > Screen.width - icon.width) - { - center.x = window.xMax - icon.width / 2; - } - // Along the right side, align the right edge of the icon with the right edge of the window. - else if (window.xMin < icon.width) - { - center.x = window.xMin + icon.width / 2; - } - } - } - - // Assign the vector to the center of the rect. - icon.center = center; - - // Return the icon's position. - return icon; - } - - public static ExperimentSituations GetExperimentSituation(this Vessel vessel) - { - 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 double Radius(this Vessel vessel) - { - double radius; - - radius = vessel.altitude; - - if (vessel.mainBody != null) - { - radius += vessel.mainBody.Radius; - } - - return radius; - } - - public static double TryGetLastMass(this Engineer.VesselSimulator.SimManager simManager) - { - if (simManager.Stages == null || simManager.Stages.Length <= Staging.lastStage) - { - return double.NaN; - } - - return simManager.Stages[Staging.lastStage].totalMass; - } - - 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"; - } - } - - private static ScreenMessage debugmsg = new ScreenMessage("", 2f, ScreenMessageStyle.UPPER_RIGHT); - - [System.Diagnostics.Conditional("DEBUG")] - public static void PostDebugMessage(string Msg) - { - if (HighLogic.LoadedScene > GameScenes.SPACECENTER) - { - debugmsg.message = Msg; - ScreenMessages.PostScreenMessage(debugmsg, true); - } - - KSPLog.print(Msg); - } - } -} --- /dev/null +++ b/Tools/VOID_DataValue.cs @@ -1,1 +1,356 @@ - +// 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 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 = Tools.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}", + Tools.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 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) + { + 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)) + { + Tools.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; + } + + Tools.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_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; + } + } +} + + --- /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,127 @@ +// 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 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)) + { + Tools.PostDebugMessage (string.Format ( + "VOID: Dirtying config for type {0}." + + "\n\t Old Value: {2}, New Value: {3}" + + "\n\t Object.Equals(New, Old): {4}\n" + + "{1}", + this._type, + new System.Diagnostics.StackTrace().ToString(), + 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,1099 @@ - +// 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) + #else + catch (ArgumentException) + #endif + { + Debug.LogWarning( + string.Format("[{0}]: ArgumentException caught during window call. This is not a bug.", + func.Target.GetType().Name + )); + + /*#if DEBUG + Debug.LogException(ex); + #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 + { + 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; + } + } +} + --- /dev/null +++ b/VOID.csproj @@ -1,1 +1,159 @@ + + + + Debug_win + 8.0.30703 + 2.0 + {45ACC1CC-942C-4A66-BFC7-8BE375938B18} + Library + VOID + VOID + 65001 + False + v3.5 + AnyCPU + 0.11 + false + + + true + full + false + bin\Debug + DEBUG; TRACE + prompt + 4 + false + + + + + + + + false + bin\Release + prompt + 4 + false + TRACE + + + + + + + + true + full + false + bin\Debug + DEBUG; TRACE + prompt + 4 + false + + + + + + + + false + bin\Release + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\_KSPAssemblies\System.dll + + + ..\_KSPAssemblies\Assembly-CSharp.dll + + + ..\_KSPAssemblies\UnityEngine.dll + + + + + {D48A5542-6655-4149-BC27-B27DF0466F1C} + ToadicusTools + + + {30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF} + VesselSimulator + + + + + + + + + + + --- /dev/null +++ b/VOIDCore_Editor.cs @@ -1,1 +1,45 @@ +// 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 ToadicusTools; +using UnityEngine; + +namespace VOID +{ + [VOID_Scenes(GameScenes.EDITOR)] + public class VOIDCore_Editor : VOIDCore_Generic + { + public override void FixedUpdate() {} + } +} + + --- /dev/null +++ b/VOIDCore_Flight.cs @@ -1,1 +1,51 @@ +// 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; + +namespace VOID +{ + [VOID_Scenes(GameScenes.FLIGHT)] + public class VOIDCore_Flight : VOIDCore_Generic + { + public override void DrawConfigurables() + { + if (HighLogic.LoadedSceneIsFlight) + { + this.consumeResource.value = GUITools.Toggle(this.consumeResource, "Consume Resources"); + } + + base.DrawConfigurables(); + } + } +} + + --- /dev/null +++ b/VOIDCore_Generic.cs @@ -1,1 +1,1204 @@ - +// 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 System; +using System.Collections.Generic; +using System.Text; +using ToadicusTools; +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 IList AllBodies + { + get + { + return FlightGlobals.Bodies.AsReadOnly(); + } + } + + 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() + { + this.windowID = this.windowBaseID; + + if (!this.modulesLoaded) + { + this.LoadModulesOfType(); + } + + if (!this.skinsLoaded) + { + this.LoadSkins(); + } + + GUI.skin = this.Skin; + + if (!this.GUIStylesLoaded) + { + this.LoadGUIStyles(); + + Tools.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(); + } + } + + public virtual void Update() + { + this.LoadBeforeUpdate(); + + if ( + this.vesselSimActive && + ( + this.Vessel != null || + ( + HighLogic.LoadedSceneIsEditor && + EditorLogic.RootPart != null && + EditorLogic.SortedShipList.Count > 0 + ) + ) + ) + { + Tools.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.saveTimer > 2f) + { + if (this.configDirty) + { + + Tools.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); + } + } + + 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 = GUITools.Toggle(module.Active, module.Name); + } + } + } + else + { + GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed); + } + + VOID_ConfigWindow.Instance.Active = GUITools.Toggle( + VOID_ConfigWindow.Instance.Active, + "Configuration" + ); + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + + public override void DrawConfigurables() + { + GUIContent _content; + + this.useToolbarManager.value = GUITools.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available"); + + this.vesselSimActive.value = GUITools.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 = GUITools.Toggle(useEarthTime, "Use Earth Time (changes KSP option)"); + + GameSettings.KERBIN_TIME = !useEarthTime; + + useSiderealTime = GUITools.Toggle( + useSiderealTime, + string.Format( + "Time Scale: {0}", + useSiderealTime ? "Sidereal" : "Solar" + ) + ); + + useRoundedScale = GUITools.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--; + 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, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true)); + + _content.text = "►"; + _content.tooltip = "Select next skin"; + if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) + { + 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.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 = GUITools.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(); + + Tools.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²", + SimManager.Atmosphere, + SimManager.Gravity + ); + } + + protected void GetSimManagerResults() + { + Tools.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() + { + Tools.DebugLogger sb = Tools.DebugLogger.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.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) + { + Tools.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) + { + module.LoadConfig(); + this.modules.Add(module); + + Tools.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); + } + } + + Tools.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; + } + + Tools.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) + { + Tools.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(); + }; + + 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, + this.appIconVisibleScenes, + this.VOIDIconTexture + ); + + Tools.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 override void LoadConfig() + { + base.LoadConfig(); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.LoadConfig(); + } + + 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"); + } + + var config = KSP.IO.PluginConfiguration.CreateForType(); + + config.load(); + + this.Save(config); + + IVOID_Module module; + for (int idx = 0; idx < this.modules.Count; idx++) + { + module = this.modules[idx]; + + module.Save(config); + } + + 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.LoadConfig(); + + this.configVersion = (VOID_SaveValue)VOIDCore.CONFIG_VERSION; + + 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,39 @@ +// 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 void FixedUpdate() {} + } +} + + --- a/VOIDEditorMaster.cs +++ /dev/null @@ -1,100 +1,1 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// VOID - Vessel Orbital Information Display for Kerbal Space Program -// Copyright (C) 2012 Iannic-ann-od -// Copyright (C) 2013 Toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -/////////////////////////////////////////////////////////////////////////////// -// -// 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; - -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 (); - SimManager.HardReset(); - 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,100 +1,1 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// VOID - Vessel Orbital Information Display for Kerbal Space Program -// Copyright (C) 2012 Iannic-ann-od -// Copyright (C) 2013 Toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -/////////////////////////////////////////////////////////////////////////////// -// -// 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; - -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 (); - SimManager.HardReset(); - 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; +using UnityEngine; + +namespace VOID +{ + [KSPAddon(KSPAddon.Startup.EditorAny, false)] + public class VOIDMaster_Editor : VOIDMaster + { + public override void Awake() + { + Tools.PostDebugMessage ("VOIDEditorMaster: Waking up."); + this.Core = VOIDCore_Editor.Instance; + this.Core.ResetGUI (); + Tools.PostDebugMessage ("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; + +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; + +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 @@ -1,26 +1,35 @@ -// -// VOID_Orbital.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// VOID +// +// VOID_CBInfoBrowser.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 @@ -28,29 +37,39 @@ 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)); @@ -63,20 +82,26 @@ GUILayout.BeginVertical(GUILayout.Width(150)); - selectedBody1 = VOID_Core.Instance.allBodies[selectedBodyIdx1]; - selectedBody2 = VOID_Core.Instance.allBodies[selectedBodyIdx2]; + selectedBody1 = this.core.AllBodies[selectedBodyIdx1]; + selectedBody2 = this.core.AllBodies[selectedBodyIdx2]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) { - selectedBodyIdx1--; - if (selectedBodyIdx1 < 0) selectedBodyIdx1 = VOID_Core.Instance.allBodies.Count - 1; - } - GUILayout.Label(VOID_Core.Instance.allBodies[selectedBodyIdx1].bodyName, VOID_Core.Instance.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + selectedBodyIdx1.value--; + if (selectedBodyIdx1 < 0) + { + selectedBodyIdx1.value = this.core.AllBodies.Count - 1; + } + } + GUILayout.Label(this.core.AllBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) { - selectedBodyIdx1++; - if (selectedBodyIdx1 > VOID_Core.Instance.allBodies.Count - 1) selectedBodyIdx1 = 0; + selectedBodyIdx1.value++; + if (selectedBodyIdx1 > this.core.AllBodies.Count - 1) + { + selectedBodyIdx1.value = 0; + } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); @@ -85,14 +110,20 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) { - selectedBodyIdx2--; - if (selectedBodyIdx2 < 0) selectedBodyIdx2 = VOID_Core.Instance.allBodies.Count - 1; - } - GUILayout.Label(VOID_Core.Instance.allBodies[selectedBodyIdx2].bodyName, VOID_Core.Instance.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + selectedBodyIdx2.value--; + if (selectedBodyIdx2 < 0) + { + selectedBodyIdx2.value = this.core.AllBodies.Count - 1; + } + } + GUILayout.Label(this.core.AllBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) { - selectedBodyIdx2++; - if (selectedBodyIdx2 > VOID_Core.Instance.allBodies.Count - 1) selectedBodyIdx2 = 0; + selectedBodyIdx2.value++; + if (selectedBodyIdx2 > this.core.AllBodies.Count - 1) + { + selectedBodyIdx2.value = 0; + } } GUILayout.EndHorizontal(); GUILayout.EndVertical(); @@ -172,7 +203,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:"); @@ -199,120 +230,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", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToAp), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToPe), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.ConvertInterval(body.orbit.period), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.ConvertInterval(body.rotationPeriod), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Core.Instance.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", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Core.Instance.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", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.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, VOID_Core.Instance.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", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label(((Math.Pow((body.Radius), 2) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Core.Instance.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 * Math.Pow(body.Radius, 3)) / 1000).ToString("0.00e+00") + "km³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - double p = body.Mass / (Math.Pow(body.Radius, 3) * (4d / 3) * Math.PI); - - GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Core.Instance.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³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + + if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); + + 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(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - - double g_ASL = (VOID_Core.Constant_G * body.Mass) / Math.Pow(body.Radius, 2); - - GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Core.Instance.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(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.atmosphere) { - GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", - VOID_Core.Instance.LabelStyles["right"], + GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.atmosphereDepth) + "m", + VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); string O2 = "No"; if (body.atmosphereContainsOxygen == true) O2 = "Yes"; - GUILayout.Label(O2, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); + GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); } else { - GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); - GUILayout.Label("N/A", VOID_Core.Instance.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, VOID_Core.Instance.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,278 @@ - +// 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 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, Tools.SIFormatter)); + } + else if (delta < 0) + { + return string.Format("{0}↓", delta.ToString(numberFormat, Tools.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 + { + Tools.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() + { + if (Event.current.type != EventType.Layout && !this.currenciesInitialized) + { + this.initCurrencies(); + } + + base.DrawGUI(); + } + + 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() + { + Tools.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,76 @@ +// VOID +// +// VOID_ConfigModule.cs +// +// Copyright © 2015, toadicus +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using KSP; +using System; +using ToadicusTools; +using UnityEngine; + +namespace VOID +{ + public class VOID_ConfigWindow : VOID_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,983 +1,1 @@ -// -// VOID_Core.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -using System.Collections.Generic; -using System.Linq; -using KSP; -using UnityEngine; -using Engineer.VesselSimulator; -namespace VOID -{ - public class VOID_Core : VOID_Module, IVOID_Module - { - /* - * 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; - } - - public static double Constant_G = 6.674e-11; - /* - * Fields - * */ - protected string VoidName = "VOID"; - protected string VoidVersion = "0.9.20"; - - 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; - - // 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 Dictionary skin_list; - protected List 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; - - /* - * Properties - * */ - public bool factoryReset - { - get - { - return this._factoryReset; - } - } - - public List Modules - { - get - { - return this._modules; - } - } - - public GUISkin Skin - { - get - { - if (!this.skinsLoaded || this._skinName == null) - { - return AssetBase.GetGUISkin(this.defaultSkin); - } - return this.skin_list[this._skinName]; - } - } - - 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; - } - set - { - if (this._UseToolbarManager == value) - { - return; - } - - if (value == false && this.ToolbarButton != null) - { - this.ToolbarButton.Destroy(); - this.ToolbarButton = null; - } - if (value == true && this.ToolbarButton == null) - { - this.InitializeToolbarButton(); - } - - this.SetIconTexture(this.powerState | this.activeState); - - _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 (GUI.Button(VOIDIconPos, VOIDIconTexture, this.iconStyle) && this.VOIDIconLocked) - { - this.ToggleMainWindow(); - } - } - else if (this.ToolbarButton == null) - { - this.InitializeToolbarButton(); - } - - if (!this.mainGuiMinimized) - { - - Rect _mainWindowPos = this.mainWindowPos; - - _mainWindowPos = GUILayout.Window( - this.windowID, - _mainWindowPos, - 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, - 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) - { - SimManager.Instance.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / - Math.Pow(VOID_Core.Instance.vessel.Radius(), 2); - SimManager.Instance.TryStartSimulation(); - } - - 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() - { - int skinIdx; - - 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"); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - - GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); - - _content = new GUIContent(); - - if (skinNames.Contains(this._skinName)) - { - skinIdx = skinNames.IndexOf(this._skinName); - } - else if (skinNames.Contains(this.defaultSkin)) - { - skinIdx = skinNames.IndexOf(this.defaultSkin); - } - else - { - skinIdx = 0; - } - - _content.text = "◄"; - _content.tooltip = "Select previous skin"; - if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) - { - this.GUIStylesLoaded = false; - skinIdx--; - if (skinIdx < 0) - skinIdx = skinNames.Count - 1; - Tools.PostDebugMessage(string.Format( - "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", - this.GetType().Name, - this._skinName, - this.skin_list.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; - skinIdx++; - if (skinIdx >= skinNames.Count) - skinIdx = 0; - Tools.PostDebugMessage(string.Format( - "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", - this.GetType().Name, - this._skinName, - this.skin_list.Count - )); - } - - if (this._skinName != skinNames[skinIdx]) - { - this._skinName = skinNames[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.skin_list = 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.skin_list.Count - )); - - this.skinNames = this.skin_list.Keys.ToList(); - this.skinNames.Sort(); - - if (this._skinName == null || !this.skinNames.Contains(this._skinName)) - { - this._skinName = this.defaultSkin; - Tools.PostDebugMessage(string.Format( - "{0}: resetting _skinIdx to default.", - this.GetType().Name - )); - } - - 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() - { - 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(); - }; - } - - 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.UseToolbarManager && this.ToolbarButton != null) - { - this.ToolbarButton.TexturePath = texturePath; - } - else - { - this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath, false); - } - } - - 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; - } - - protected VOID_Core() - { - this._Name = "VOID Core"; - - this._Active.value = true; - - this._skinName = this.defaultSkin; - - 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.UseToolbarManager = false; - - this.LoadConfig(); - - this.SetIconTexture(this.powerState | this.activeState); - } - - protected enum IconState - { - PowerOff = 1, - PowerOn = 2, - Inactive = 4, - Active = 8 - } - } -} - - --- /dev/null +++ b/VOID_Data.cs @@ -1,1 +1,1287 @@ - +// 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 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 * 100f), + "%" + ); + + #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_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_Vector3dValue vesselThrustOffset = + new VOID_Vector3dValue( + "Thrust Offset", + delegate() + { + if (Core.Vessel == null) + { + return Vector3d.zero; + } + + IList engineModules = Core.Vessel.getModulesOfType(); + + Vector3d thrustPos = Vector3d.zero; + Vector3d thrustDir = Vector3d.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); + + 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" + ); + + #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 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_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", + new Func(() => 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) + { + 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 * (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 @@ -1,26 +1,37 @@ -// -// VOID_Orbital.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// VOID +// +// VOID_DataLogger.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 System.IO; +using System.Text; +using ToadicusTools; using UnityEngine; namespace VOID @@ -30,208 +41,477 @@ /* * 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 = KSP.IO.IOUtils.GetFilePathFor( + typeof(VOIDCore), + string.Format( + "{0}_{1}", + this.Vessel.vesselName, + "data.csv" + ), + null + ); + } + + return this._fileName; + } + } + + protected FileStream outputFile + { + get + { + if (this._outputFile == null) + { + Tools.DebugLogger logger = Tools.DebugLogger.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(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 + this.CollectLogData(); } - - 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; } } 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() + { + Tools.DebugLogger logger = Tools.DebugLogger.New(this); + + logger.Append("Destroying..."); + + this.CloseFileIfOpen(); + + logger.Append(" Done."); + logger.Print(false); + } + + #endregion + + #region VOID_Module Overrides + + public override void LoadConfig() + { + base.LoadConfig(); + + 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 = GUITools.Toggle( + loggingActive, + string.Format("Data logging: {0}", activeLabelText), + null, + activeLabelStyle + ); + + this.waitForLaunch.value = GUITools.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"; - } + StringBuilder line = Tools.GetStringBuilder(); + + 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 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³)\"," + + "\"Downrange Distance (m)\"," + + "\n" + ); + } + + // Universal time + line.Append(Planetarium.GetUniversalTime().ToString("F2")); + line.Append(','); + //Mission time - line += vessel.missionTime.ToString("F3") + ";"; + line.Append(Vessel.missionTime.ToString("F3")); + line.Append(','); + //Altitude ASL - line += vessel.orbit.altitude.ToString("F3") + ";"; + line.Append(VOID_Data.orbitAltitude.Value.ToString("F3")); + line.Append(','); + //Altitude (true) - double alt_true = vessel.orbit.altitude - vessel.terrainAltitude; - if (vessel.terrainAltitude < 0) alt_true = vessel.orbit.altitude; - line += alt_true.ToString("F3") + ";"; + line.Append(VOID_Data.trueAltitude.Value.ToString("F3")); + line.Append(','); + + // Surface Latitude + line.Append('"'); + line.Append(VOID_Data.surfLatitude.Value); + line.Append('"'); + line.Append(','); + + // Surface Longitude + line.Append('"'); + line.Append(VOID_Data.surfLongitude.Value); + line.Append('"'); + line.Append(','); + + // Apoapsis Altitude + line.Append(VOID_Data.orbitApoAlt.Value.ToString("G3")); + line.Append(','); + + // Periapsis Altitude + line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G3")); + line.Append(','); + //Orbital velocity - line += vessel.orbit.vel.magnitude.ToString("F3") + ";"; + line.Append(VOID_Data.orbitVelocity.Value.ToString("F3")); + line.Append(','); + //surface velocity - line += vessel.srf_velocity.magnitude.ToString("F3") + ";"; + line.Append(VOID_Data.surfVelocity.Value.ToString("F3")); + line.Append(','); + //vertical speed - line += vessel.verticalSpeed.ToString("F3") + ";"; + line.Append(VOID_Data.vertVelocity.Value.ToString("F3")); + line.Append(','); + //horizontal speed - line += vessel.horizontalSrfSpeed.ToString("F3") + ";"; + line.Append(VOID_Data.horzVelocity.Value.ToString("F3")); + line.Append(','); + //gee force - line += vessel.geeForce.ToString("F3") + ";"; + line.Append(VOID_Data.geeForce.Value.ToString("F3")); + line.Append(','); + //temperature - line += vessel.flightIntegrator.getExternalTemperature().ToString("F2") + ";"; + line.Append(VOID_Data.temperature.Value.ToString("F2")); + line.Append(','); + //gravity - double r_vessel = vessel.mainBody.Radius + vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); - double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / Math.Pow(r_vessel, 2); - line += g_vessel.ToString("F3") + ";"; + line.Append(VOID_Data.gravityAccel.Value.ToString("F3")); + line.Append(','); + //atm density - line += (vessel.atmDensity * 1000).ToString("F3") + ";"; - line += "\n"; - if (csvList.Contains(line) == false) csvList.Add(line); - csvCollectTimer = 0f; - } + line.Append(VOID_Data.atmDensity.Value.ToString("G3")); + line.Append(','); + + // Downrange Distance + line.Append((VOID_Data.downrangeDistance.Value.ToString("G3"))); + + line.Append('\n'); + + csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString())); + + this.csvCollectTimer = 0f; + + Tools.PutStringBuilder(line); + } + + #endregion + + #region File IO Methods + + protected void AsyncWriteCallback(IAsyncResult result) + { + Tools.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() + { + Tools.DebugLogger logger = Tools.DebugLogger.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,298 +1,1 @@ -// -// VOID_DataValue.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -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 ( - (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 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) - { - float magnitude; - float magLimit; - - magnitude = (float)Math.Log10(Math.Abs(this)); - - magLimit = Mathf.Max(magnitude, 6f); - magLimit = Mathf.Round((float)Math.Ceiling(magLimit / 3f) * 3f); - - GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true)); - GUILayout.FlexibleSpace(); - - GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - - if (Event.current.type == EventType.mouseUp) - { - Rect lastRect = GUILayoutUtility.GetLastRect(); - if (lastRect.Contains(Event.current.mousePosition)) - { - 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 - 3; - } - } - } - } - - 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, "") {} - } -} - - --- a/VOID_EditorCore.cs +++ /dev/null @@ -1,137 +1,1 @@ -// -// VOID_EditorCore.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using Engineer.VesselSimulator; -using KSP; -using System; -using System.Collections.Generic; -using System.Linq; -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) - { - SimManager.Instance.Gravity = this.Kerbin.gravParameter / - Math.Pow(this.Kerbin.Radius, 2); - SimManager.Instance.TryStartSimulation(); - } - - this.CheckAndSave (); - } - - public new void FixedUpdate() {} - } -} - - --- a/VOID_EditorHUD.cs +++ b/VOID_EditorHUD.cs @@ -1,79 +1,68 @@ -// -// VOID_Hud.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Engineer.VesselSimulator; +// VOID +// +// VOID_EditorHUD.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.Linq; using System.Text; +using ToadicusTools; 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 - { - 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; @@ -111,62 +100,35 @@ * */ 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]; + 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); Tools.PostDebugMessage (this.GetType().Name + ": Constructed."); } - public override void DrawGUI() - { - SimManager.Instance.RequestSimulation(); - - if (SimManager.Instance.LastStage == null) + public void ehudWindowFunc(int id) + { + StringBuilder hudString = Tools.GetStringBuilder(); + + if (this.core.LastStage == null) { 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; - } - 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]; + VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; hudString.Append("Total Mass: "); - hudString.Append(SimManager.Instance.LastStage.totalMass.ToString("F3")); + hudString.Append(this.core.LastStage.totalMass.ToString("F3")); hudString.Append('t'); hudString.Append(' '); @@ -177,22 +139,30 @@ hudString.Append('\n'); hudString.Append("Total Delta-V: "); - hudString.Append(Tools.MuMech_ToSI(SimManager.Instance.LastStage.totalDeltaV)); + hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.totalDeltaV)); hudString.Append("m/s"); hudString.Append('\n'); hudString.Append("Bottom Stage Delta-V"); - hudString.Append(Tools.MuMech_ToSI(SimManager.Instance.LastStage.deltaV)); + hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.deltaV)); hudString.Append("m/s"); hudString.Append('\n'); hudString.Append("Bottom Stage T/W Ratio: "); - hudString.Append(SimManager.Instance.LastStage.thrustToWeight.ToString("F3")); + hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3")); + + Tools.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) { + Tools.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset."); hudString.Append('\n'); hudString.Append("Thrust Offset: "); @@ -202,19 +172,79 @@ this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position ).ToString("F3")); } - - GUI.Label ( - hudPos, + #if DEBUG + else + { + Tools.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped."); + } + #endif + + GUILayout.Label( hudString.ToString(), - labelStyle); - } - - public override void DrawConfigurables() - { - if (GUILayout.Button ("Change HUD color", GUILayout.ExpandWidth (false))) - { - ++this.ColorIndex; - } + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); + + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + + Tools.PutStringBuilder(hudString); + } + + public override void DrawGUI() + { + 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; + } + + Tools.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(); + + Rect hudPos = this.ehudWindow.WindowPos; + + if (this.snapToLeft && this.positionsLocked) + { + hudPos.xMin = hudLeft; + } + else + { + 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 @@ -1,108 +1,67 @@ +// VOID // -// VOID_Hud.cs +// VOID_HUD.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 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 UnityEngine; using System; using System.Collections.Generic; using System.Text; +using ToadicusTools; +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(Screen.width * .375f - 300f, 0f, 300f, 90f)); + this.Windows.Add(this.leftHUD); - 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); - - VOID_Core.Instance.LabelStyles["hud"] = new GUIStyle(); - VOID_Core.Instance.LabelStyles["hud"].normal.textColor = this.textColors [this.ColorIndex]; - - this.leftHUDdefaultPos = new Rect(Screen.width * .2083f, 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; + this.rightHUD = new HUDWindow("rightHUD", this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f)); + this.Windows.Add(this.rightHUD); Tools.PostDebugMessage ("VOID_HUD: Constructed."); } @@ -111,11 +70,17 @@ { StringBuilder leftHUD; - leftHUD = new StringBuilder(); + leftHUD = Tools.GetStringBuilder(); - if (VOID_Core.Instance.powerAvailable) + VOID_Styles.labelHud.alignment = TextAnchor.UpperRight; + + if (this.core.powerAvailable) { - leftHUD.AppendFormat("Obt Alt: {0} Obt Vel: {1}", + 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() ); @@ -127,15 +92,23 @@ VOID_Data.oribtPeriAlt.ToSIString(), VOID_Data.timeToPeri.ValueUnitString() ); - leftHUD.AppendFormat("\nInc: {0}", VOID_Data.orbitInclination.ValueUnitString("F3")); - leftHUD.AppendFormat("\nPrimary: {0}", VOID_Data.primaryName.ValueUnitString()); - - GUILayout.Label(leftHUD.ToString(), VOID_Core.Instance.LabelStyles["hud"], GUILayout.ExpandWidth(true)); + 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 --")); } + + GUILayout.Label( + leftHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); if (!this.positionsLocked) { @@ -143,17 +116,25 @@ } GUI.BringWindowToBack(id); + + Tools.PutStringBuilder(leftHUD); } protected void rightHUDWindow(int id) { StringBuilder rightHUD; - rightHUD = new StringBuilder(); + rightHUD = Tools.GetStringBuilder(); - if (VOID_Core.Instance.powerAvailable) + VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; + + if (this.core.powerAvailable) { - rightHUD.AppendFormat("Srf Alt: {0} Srf Vel: {1}", + 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() ); @@ -165,19 +146,37 @@ VOID_Data.surfLatitude.ValueUnitString(), VOID_Data.surfLongitude.ValueUnitString() ); - rightHUD.AppendFormat("\nHdg: {0}", VOID_Data.vesselHeading.ValueUnitString()); - rightHUD.AppendFormat("\nBiome: {0} Sit: {1}", - VOID_Data.currBiome.ValueUnitString(), - VOID_Data.expSituation.ValueUnitString() + rightHUD.AppendFormat("\nHdg: {0} Pit: {1}", + VOID_Data.vesselHeading.ValueUnitString(), + VOID_Data.vesselPitch.ToSIString(2) ); + + 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(), VOID_Core.Instance.LabelStyles["hud"], GUILayout.ExpandWidth(true)); + GUILayout.Label( + rightHUD.ToString(), + VOID_Styles.labelHud, + GUILayout.ExpandWidth(true), + GUILayout.ExpandHeight(true) + ); if (!this.positionsLocked) { @@ -185,54 +184,9 @@ } GUI.BringWindowToBack(id); + + Tools.PutStringBuilder(rightHUD); } - - public override void DrawGUI() - { - VOID_Core.Instance.LabelStyles["hud"].normal.textColor = textColors [ColorIndex]; - - this.leftHUDPos = GUI.Window( - VOID_Core.Instance.windowID, - this.leftHUDPos, - this.leftHUDWindow, - GUIContent.none, - GUIStyle.none - ); - - this.rightHUDPos = GUI.Window( - VOID_Core.Instance.windowID, - this.rightHUDPos, - this.leftHUDWindow, - 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 VOID_StrValue expSituation = new VOID_StrValue( - "Situation", - new Func (() => VOID_Core.Instance.vessel.GetExperimentSituation().HumanString()) - ); } } --- /dev/null +++ b/VOID_HUDAdvanced.cs @@ -1,1 +1,281 @@ - +// VOID +// +// VOID_HUD.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; +using UnityEngine; + +namespace VOID +{ + public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module + { + /* + * Fields + * */ + protected VOID_HUD primaryHUD; + + protected HUDWindow leftHUD; + protected HUDWindow rightHUD; + + /* + * Properties + * */ + public override int ColorIndex + { + get + { + if (this.primaryHUD != null) + { + return this.primaryHUD.ColorIndex; + } + + return base.ColorIndex; + } + set + { + base.ColorIndex = value; + } + } + + /* + * Methods + * */ + public VOID_HUDAdvanced() : base() + { + this.Name = "Advanced Heads-Up Display"; + + this.Active = true; + + this.leftHUD = new HUDWindow("leftHUD", + this.leftHUDWindow, + new Rect( + Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f, + 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_SIZE * .25f, + Screen.height - 200f, + 300f, 90f) + ); + this.Windows.Add(this.rightHUD); + + this.positionsLocked.value = true; + + Tools.PostDebugMessage (this, "Constructed."); + } + + protected void leftHUDWindow(int id) + { + StringBuilder leftHUD; + + leftHUD = Tools.GetStringBuilder(); + + 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 (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + + Tools.PutStringBuilder(leftHUD); + } + + protected void rightHUDWindow(int id) + { + StringBuilder rightHUD; + + rightHUD = Tools.GetStringBuilder(); + + 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) + ); + + if (!this.positionsLocked) + { + GUI.DragWindow(); + } + + GUI.BringWindowToBack(id); + + Tools.PutStringBuilder(rightHUD); + } + + public override void DrawGUI() + { + if (this.primaryHUD == null) + { + 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; + } + } + } + + 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(); + } + + public override void DrawConfigurables() + { + 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 = GUITools.Toggle(this.positionsLocked, string.Intern("Lock Advanced HUD Positions")); + } + } +} + --- a/VOID_Module.cs +++ /dev/null @@ -1,263 +1,1 @@ -// -// VOID_Module.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -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 - * */ - 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 virtual void ModuleWindow(int _) - { -// if (VOID_Core.Instance.updateTimer - this.lastUpdate > VOID_Core.Instance.updatePeriod) { -// foreach (var fieldinfo in this.GetType().GetFields( -// BindingFlags.Instance | -// BindingFlags.NonPublic | -// BindingFlags.Public | -// BindingFlags.FlattenHierarchy -// )) -// { -// object field = null; -// -// try -// { -// field = fieldinfo.GetValue (this); -// } -// catch (NullReferenceException) { -// Tools.PostDebugMessage(string.Format( -// "{0}: caught NullReferenceException, could not get value for field {1}.", -// this.GetType().Name, -// fieldinfo.Name -// )); -// } -// -// if (field == null) { -// continue; -// } -// -// if (typeof(IVOID_DataValue).IsAssignableFrom (field.GetType ())) { -// (field as IVOID_DataValue).Refresh (); -// } -// } -// -// this.lastUpdate = VOID_Core.Instance.updateTimer; -// } - } - - public override void DrawGUI() - { - GUI.skin = VOID_Core.Instance.Skin; - - Rect _Pos = this.WindowPos; - - _Pos = GUILayout.Window( - VOID_Core.Instance.windowID, - _Pos, - this.ModuleWindow, - this.Name, - GUILayout.Width(this.defWidth), - GUILayout.Height(this.defHeight) - ); - - _Pos = Tools.ClampRectToScreen (_Pos); - - if (_Pos != this.WindowPos) - { - this.WindowPos = _Pos; - VOID_Core.Instance.configDirty = true; - } - } - } -} - - --- a/VOID_Orbital.cs +++ b/VOID_Orbital.cs @@ -1,25 +1,34 @@ +// VOID // -// VOID_Orbital.cs +// VOID_Orbital.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 3. Neither the name of the copyright holder nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + using KSP; using System; +using ToadicusTools; using UnityEngine; namespace VOID @@ -27,24 +36,26 @@ 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) { - base.ModuleWindow (_); - int idx = 0; GUILayout.BeginVertical(); @@ -72,7 +83,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 = GUITools.Toggle(this.toggleExtended, "Extended info"); if (this.toggleExtended) { @@ -91,13 +102,18 @@ 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 () @@ -107,127 +123,12 @@ this.precisionValues = new IntCollection (4, this._precisionValues); } - public override void _SaveToConfig (KSP.IO.PluginConfiguration config) + public override void Save (KSP.IO.PluginConfiguration config) { - this._precisionValues = this.precisionValues.collection; + this._precisionValues.value = this.precisionValues.collection; - base._SaveToConfig (config); + base.Save (config); } - } - - - public static partial class VOID_Data - { - public static VOID_StrValue primaryName = new VOID_StrValue ( - VOIDLabels.void_primary, - new Func (() => VOID_Core.Instance.vessel.mainBody.name) - ); - - public static VOID_DoubleValue orbitAltitude = new VOID_DoubleValue ( - "Altitude (ASL)", - new Func (() => VOID_Core.Instance.vessel.orbit.altitude), - "m" - ); - - public static VOID_DoubleValue orbitVelocity = new VOID_DoubleValue ( - VOIDLabels.void_velocity, - new Func (() => VOID_Core.Instance.vessel.orbit.vel.magnitude), - "m/s" - ); - - public static VOID_DoubleValue orbitApoAlt = new VOID_DoubleValue( - VOIDLabels.void_apoapsis, - new Func(() => VOID_Core.Instance.vessel.orbit.ApA), - "m" - ); - - public static VOID_DoubleValue oribtPeriAlt = new VOID_DoubleValue( - VOIDLabels.void_periapsis, - new Func(() => VOID_Core.Instance.vessel.orbit.PeA), - "m" - ); - - public static VOID_StrValue timeToApo = new VOID_StrValue( - "Time to Apoapsis", - new Func(() => Tools.ConvertInterval(VOID_Core.Instance.vessel.orbit.timeToAp)) - ); - - public static VOID_StrValue timeToPeri = new VOID_StrValue( - "Time to Periapsis", - new Func(() => Tools.ConvertInterval(VOID_Core.Instance.vessel.orbit.timeToPe)) - ); - - public static VOID_DoubleValue orbitInclination = new VOID_DoubleValue( - "Inclination", - new Func(() => VOID_Core.Instance.vessel.orbit.inclination), - "°" - ); - - public static VOID_DoubleValue gravityAccel = new VOID_DoubleValue( - "Gravity", - delegate() - { - double orbitRadius = VOID_Core.Instance.vessel.mainBody.Radius + - VOID_Core.Instance.vessel.mainBody.GetAltitude(VOID_Core.Instance.vessel.findWorldCenterOfMass()); - return (VOID_Core.Constant_G * VOID_Core.Instance.vessel.mainBody.Mass) / - Math.Pow(orbitRadius, 2); - }, - "m/s²" - ); - - public static VOID_StrValue orbitPeriod = new VOID_StrValue( - "Period", - new Func(() => Tools.ConvertInterval(VOID_Core.Instance.vessel.orbit.period)) - ); - - public static VOID_DoubleValue semiMajorAxis = new VOID_DoubleValue( - "Semi-Major Axis", - new Func(() => VOID_Core.Instance.vessel.orbit.semiMajorAxis), - "m" - ); - - public static VOID_DoubleValue eccentricity = new VOID_DoubleValue( - "Eccentricity", - new Func(() => VOID_Core.Instance.vessel.orbit.eccentricity), - "" - ); - - public static VOID_DoubleValue meanAnomaly = new VOID_DoubleValue( - "Mean Anomaly", - new Func(() => VOID_Core.Instance.vessel.orbit.meanAnomaly * 180d / Math.PI), - "°" - ); - - public static VOID_DoubleValue trueAnomaly = new VOID_DoubleValue( - "True Anomaly", - new Func(() => VOID_Core.Instance.vessel.orbit.trueAnomaly), - "°" - ); - - public static VOID_DoubleValue eccAnomaly = new VOID_DoubleValue( - "Eccentric Anomaly", - new Func(() => VOID_Core.Instance.vessel.orbit.eccentricAnomaly * 180d / Math.PI), - "°" - ); - - public static VOID_DoubleValue longitudeAscNode = new VOID_DoubleValue( - "Long. Ascending Node", - new Func(() => VOID_Core.Instance.vessel.orbit.LAN), - "°" - ); - - public static VOID_DoubleValue argumentPeriapsis = new VOID_DoubleValue( - "Argument of Periapsis", - new Func(() => VOID_Core.Instance.vessel.orbit.argumentOfPeriapsis), - "°" - ); - - public static VOID_DoubleValue localSiderealLongitude = new VOID_DoubleValue( - "Local Sidereal Longitude", - new Func(() => Tools.FixDegreeDomain( - VOID_Core.Instance.vessel.longitude + VOID_Core.Instance.vessel.orbit.referenceBody.rotationAngle)), - "°" - ); } } --- a/VOID_Rendezvous.cs +++ b/VOID_Rendezvous.cs @@ -1,27 +1,35 @@ -// -// VOID_Orbital.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// VOID +// +// VOID_Rendezvous.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 System.Linq; +using ToadicusTools; using UnityEngine; namespace VOID @@ -29,43 +37,56 @@ 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(); - - this.RegisterModule = VOID_Core.Instance.Modules.Where(m => typeof(VOID_VesselRegister).IsAssignableFrom(m.GetType())).FirstOrDefault() as VOID_VesselRegister; + Vessel rendezvessel; + CelestialBody rendezbody; + + if (this.RegisterModule == null) + { + 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:", VOID_Core.Instance.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 == FlightGlobals.VesselTargetModes.Direction) + 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 == FlightGlobals.VesselTargetModes.DirectionAndVelocity) + else if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.DirectionAndVelocity) { //a Vessel is selected rendezvessel = FlightGlobals.fetch.VesselTarget.GetVessel(); @@ -82,13 +103,13 @@ else { //no KSP Target selected - GUILayout.Label("No Target Selected", VOID_Core.Instance.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:", VOID_Core.Instance.LabelStyles["center_bold"]); + GUILayout.Label("Vessel Register:", VOID_Styles.labelCenterBold); if (this.RegisterModule.selectedVessel != null) { rendezvessel = this.RegisterModule.selectedVessel; @@ -110,19 +131,20 @@ { //vesreg Vessel is null //targ = null; - GUILayout.Label("No Vessel Selected", VOID_Core.Instance.LabelStyles["center_bold"]); - } - } - - untoggleRegisterInfo.value = GUILayout.Toggle(untoggleRegisterInfo, "Hide Vessel Register Info"); + GUILayout.Label("No Vessel Selected", VOID_Styles.labelCenterBold); + } + } + + untoggleRegisterInfo.value = GUITools.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) @@ -131,7 +153,7 @@ { //Display vessel rendezvous info GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); - GUILayout.Label(v.vesselName, VOID_Core.Instance.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) @@ -139,7 +161,7 @@ // Toadicus edit: added local sidereal longitude. // Toadicus edit: added local sidereal longitude. double LSL = v.longitude + v.orbit.referenceBody.rotationAngle; - LSL = Tools.FixDegreeDomain (LSL); + LSL = VOID_Tools.FixDegreeDomain (LSL); //display orbital info for orbiting/flying/suborbital/escaping vessels only GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); @@ -157,11 +179,11 @@ 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(Vector3d.Angle(Vessel.orbit.GetOrbitNormal(), v.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } //if (debugging) Debug.Log("[CHATR] v -> v relative incl OK"); @@ -173,21 +195,27 @@ 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(Tools.MuMech_ToSI(v.orbit.vel.magnitude - Vessel.orbit.vel.magnitude) + "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.EndHorizontal(); - - //target_vessel_extended_orbital_info = GUILayout.Toggle(target_vessel_extended_orbital_info, "Extended info"); + GUILayout.Label(Tools.MuMech_ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude) + "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") + "°", VOID_Styles.labelRight); + GUILayout.EndHorizontal(); + + toggleExtendedOrbital.value = GUITools.Toggle(toggleExtendedOrbital, "Extended info"); if (toggleExtendedOrbital) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Period:"); - GUILayout.Label(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)); @@ -226,36 +254,30 @@ GUILayout.Label("Arg. of periapsis:"); GUILayout.Label(v.orbit.argumentOfPeriapsis.ToString("F3") + "°", 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") + "°", VOID_Core.Instance.LabelStyles["right"]); - GUILayout.EndHorizontal(); } } else { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Latitude:"); - GUILayout.Label(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(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(Tools.MuMech_ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } } else if (cb != null && v == null) { //Display CelstialBody rendezvous info - GUILayout.Label(cb.bodyName, VOID_Core.Instance.LabelStyles["center_bold"]); + GUILayout.Label(cb.bodyName, VOID_Styles.labelCenterBold); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Ap/Pe:"); @@ -269,47 +291,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(Vector3d.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(Tools.MuMech_ToSI((Vessel.mainBody.position - cb.position).magnitude) + "m", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); //if (debugging) Debug.Log("[VOID] Distance OK"); //SUN2PLANET: - if (vessel.mainBody.bodyName == "Sun" && cb.referenceBody == vessel.mainBody) - { - 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) - { - 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) - { - 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) - { - 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,157 +1,1 @@ -// -// VOID_Config.cs -// -// Author: -// toadicus <> -// -// Copyright (c) 2013 toadicus -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -using System.Collections.Generic; -using KSP; -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; +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() + { + base.DrawGUI(); + + 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 = GUITools.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 @@ -1,25 +1,34 @@ +// VOID // -// VOID_Orbital.cs +// VOID_SurfAtmo.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 3. Neither the name of the copyright holder nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + using KSP; using System; +using ToadicusTools; using UnityEngine; namespace VOID @@ -27,170 +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) { - base.ModuleWindow (_); - 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.surfLatitude.DoGUIHorizontal(); - VOID_Data.surfLongitude.DoGUIHorizontal (); + VOID_Data.surfLongitude.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() { - base.LoadConfig (); + base.LoadConfig(); - 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) { - this._precisionValues = this.precisionValues.collection; + this._precisionValues.value = this.precisionValues.collection; - base._SaveToConfig (config); + base.Save(config); } } - - public static partial class VOID_Data - { - public static VOID_DoubleValue trueAltitude = new VOID_DoubleValue( - "Altitude (true)", - delegate() - { - double alt_true = VOID_Core.Instance.vessel.orbit.altitude - VOID_Core.Instance.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 (VOID_Core.Instance.vessel.terrainAltitude < 0 && VOID_Core.Instance.vessel.mainBody.ocean ) - alt_true = VOID_Core.Instance.vessel.orbit.altitude; - return alt_true; - }, - "m" - ); - - public static VOID_StrValue surfLatitude = new VOID_StrValue( - "Latitude", - new Func (() => Tools.GetLatitudeString(VOID_Core.Instance.vessel)) - ); - - public static VOID_StrValue surfLongitude = new VOID_StrValue( - "Longitude", - new Func (() => Tools.GetLongitudeString(VOID_Core.Instance.vessel)) - ); - - public static VOID_StrValue vesselHeading = new VOID_StrValue( - "Heading", - delegate() - { - double heading = Tools.MuMech_get_heading(VOID_Core.Instance.vessel); - string cardinal = Tools.get_heading_text(heading); - - return string.Format( - "{0}° {1}", - heading.ToString("F2"), - cardinal - ); - } - ); - - public static VOID_DoubleValue terrainElevation = new VOID_DoubleValue( - "Terrain elevation", - new Func (() => VOID_Core.Instance.vessel.terrainAltitude), - "m" - ); - - public static VOID_DoubleValue surfVelocity = new VOID_DoubleValue( - "Surface velocity", - new Func (() => VOID_Core.Instance.vessel.srf_velocity.magnitude), - "m/s" - ); - - public static VOID_DoubleValue vertVelocity = new VOID_DoubleValue( - "Vertical speed", - new Func (() => VOID_Core.Instance.vessel.verticalSpeed), - "m/s" - ); - - public static VOID_DoubleValue horzVelocity = new VOID_DoubleValue( - "Horizontal speed", - new Func (() => VOID_Core.Instance.vessel.horizontalSrfSpeed), - "m/s" - ); - - public static VOID_FloatValue temperature = new VOID_FloatValue( - "Temperature", - new Func (() => VOID_Core.Instance.vessel.flightIntegrator.getExternalTemperature()), - "°C" - ); - - public static VOID_DoubleValue atmDensity = new VOID_DoubleValue ( - "Atmosphere Density", - new Func (() => VOID_Core.Instance.vessel.atmDensity * 1000f), - "g/m³" - ); - - public static VOID_DoubleValue atmPressure = new VOID_DoubleValue ( - "Pressure", - new Func (() => VOID_Core.Instance.vessel.staticPressure), - "atm" - ); - - public static VOID_FloatValue atmLimit = new VOID_FloatValue( - "Atmosphere Limit", - new Func (() => VOID_Core.Instance.vessel.mainBody.maxAtmosphereAltitude), - "m" - ); - - public static VOID_StrValue currBiome = new VOID_StrValue( - "Biome", - new Func (() => Tools.Toadicus_GetAtt(VOID_Core.Instance.vessel).name) - ); - - } } --- /dev/null +++ b/VOID_TWR.cs @@ -1,1 +1,69 @@ +// 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 UnityEngine; + +namespace VOID +{ + [VOID_Scenes(GameScenes.EDITOR, GameScenes.FLIGHT)] + public class VOID_TWR : VOID_WindowModule + { + public VOID_TWR() : base() + { + this.Name = "IP Thrust-to-Weight Ratios"; + } + + public override void ModuleWindow(int id) + { + if ( + !HighLogic.LoadedSceneIsFlight || + (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || + (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate) + ) + { + SimManager.RequestSimulation(); + } + + GUILayout.BeginVertical(); + + if (core.SortedBodyList == null) + { + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + GUILayout.Label("Unavailable"); + + GUILayout.EndHorizontal(); + } + else + { + CelestialBody body; + for (int idx = 0; idx < core.SortedBodyList.Count; idx++) + { + body = core.SortedBodyList[idx]; + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + GUILayout.Label(body.bodyName); + GUILayout.FlexibleSpace(); + GUILayout.Label( + (VOID_Data.nominalThrustWeight.Value / body.GeeASL).ToString("0.0##"), + GUILayout.ExpandWidth(true) + ); + + GUILayout.EndHorizontal(); + } + } + + GUILayout.EndVertical(); + + base.ModuleWindow(id); + } + } +} + + --- a/VOID_Transfer.cs +++ b/VOID_Transfer.cs @@ -1,27 +1,35 @@ +// VOID // -// VOID_Orbital.cs +// VOID_Transfer.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 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 System.Linq; +using ToadicusTools; using UnityEngine; namespace VOID @@ -30,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)) { @@ -59,16 +71,17 @@ if (selectedBodies.Contains(body)) { - 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)) @@ -82,13 +95,15 @@ if (selectedBodies.Contains(body)) { - 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)) { @@ -101,16 +116,18 @@ if (selectedBodies.Contains(body)) { - 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)) @@ -124,14 +141,15 @@ if (selectedBodies.Contains(body)) { - 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) --- a/VOID_VesselInfo.cs +++ b/VOID_VesselInfo.cs @@ -1,29 +1,38 @@ +// VOID // -// VOID_Orbital.cs +// VOID_VesselInfo.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 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 KerbalEngineer.Extensions; using KSP; using System; using System.Collections.Generic; +using ToadicusTools; using UnityEngine; -using Engineer.VesselSimulator; -using Engineer.Extensions; namespace VOID { @@ -31,251 +40,54 @@ { 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) { - base.ModuleWindow (_); - if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)) { - SimManager.Instance.RequestSimulation(); + SimManager.RequestSimulation(); } GUILayout.BeginVertical(); GUILayout.Label( - vessel.vesselName, - VOID_Core.Instance.LabelStyles["center_bold"], + Vessel.vesselName, + VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); - - Tools.PostDebugMessage("Starting VesselInfo window."); VOID_Data.geeForce.DoGUIHorizontal ("F2"); - Tools.PostDebugMessage("GeeForce done."); - VOID_Data.partCount.DoGUIHorizontal (); - Tools.PostDebugMessage("PartCount done."); + VOID_Data.totalMass.DoGUIHorizontal ("F3"); - VOID_Data.totalMass.DoGUIHorizontal ("F1"); + VOID_Data.stageResourceMass.DoGUIHorizontal("F3"); - Tools.PostDebugMessage("TotalMass done."); - - VOID_Data.resourceMass.DoGUIHorizontal ("F1"); - - Tools.PostDebugMessage("ResourceMass done."); + VOID_Data.resourceMass.DoGUIHorizontal("F3"); VOID_Data.stageDeltaV.DoGUIHorizontal (3, false); - Tools.PostDebugMessage("Stage deltaV done."); - VOID_Data.totalDeltaV.DoGUIHorizontal (3, false); - - Tools.PostDebugMessage("Total deltaV done."); VOID_Data.mainThrottle.DoGUIHorizontal ("F0"); - Tools.PostDebugMessage("MainThrottle done."); - VOID_Data.currmaxThrust.DoGUIHorizontal (); - - Tools.PostDebugMessage("CurrMaxThrust done."); VOID_Data.currmaxThrustWeight.DoGUIHorizontal (); - Tools.PostDebugMessage("CurrMaxTWR done."); - VOID_Data.surfaceThrustWeight.DoGUIHorizontal ("F2"); - - Tools.PostDebugMessage("surfaceTWR done."); VOID_Data.intakeAirStatus.DoGUIHorizontal(); - Tools.PostDebugMessage("intakeAirStatus done."); - GUILayout.EndVertical(); - Tools.PostDebugMessage("VesselInfo window done."); - - GUI.DragWindow(); + base.ModuleWindow(id); } - } - - public static partial class VOID_Data - { - public static VOID_DoubleValue geeForce = new VOID_DoubleValue( - "G-force", - new Func(() => VOID_Core.Instance.vessel.geeForce), - "gees" - ); - - public static VOID_IntValue partCount = new VOID_IntValue( - "Parts", - new Func(() => VOID_Core.Instance.vessel.Parts.Count), - "" - ); - - public static VOID_DoubleValue totalMass = new VOID_DoubleValue( - "Total Mass", - new Func (() => SimManager.Instance.TryGetLastMass()), - "tons" - ); - - public static VOID_DoubleValue resourceMass = new VOID_DoubleValue( - "Resource Mass", - delegate() - { - double rscMass = 0; - foreach (Part part in VOID_Core.Instance.vessel.Parts) - { - rscMass += part.GetResourceMass(); - } - return rscMass; - }, - "tons" - ); - - public static VOID_DoubleValue stageDeltaV = new VOID_DoubleValue( - "DeltaV (Current Stage)", - delegate() - { - if (SimManager.Instance.Stages == null || - SimManager.Instance.Stages.Length <= Staging.lastStage - ) - return double.NaN; - return SimManager.Instance.Stages[Staging.lastStage].deltaV; - }, - "m/s" - ); - - public static VOID_DoubleValue totalDeltaV = new VOID_DoubleValue( - "DeltaV (Total)", - delegate() - { - if (SimManager.Instance.Stages == null) - return double.NaN; - return SimManager.Instance.LastStage.totalDeltaV; - }, - "m/s" - ); - - public static VOID_FloatValue mainThrottle = new VOID_FloatValue( - "Throttle", - new Func(() => VOID_Core.Instance.vessel.ctrlState.mainThrottle * 100f), - "%" - ); - - public static VOID_StrValue currmaxThrust = new VOID_StrValue( - "Thrust (curr/max)", - delegate() - { - if (SimManager.Instance.Stages == null) - return "N/A"; - - double currThrust = SimManager.Instance.LastStage.actualThrust; - double maxThrust = SimManager.Instance.LastStage.thrust; - - return string.Format( - "{0} / {1}", - currThrust.ToString("F1"), - maxThrust.ToString("F1") - ); - } - ); - - public static VOID_StrValue currmaxThrustWeight = new VOID_StrValue( - "T:W (curr/max)", - delegate() - { - if (SimManager.Instance.Stages == null) - return "N/A"; - - double currThrust = SimManager.Instance.LastStage.actualThrust; - double maxThrust = SimManager.Instance.LastStage.thrust; - double mass = SimManager.Instance.TryGetLastMass(); - double gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / - Math.Pow( - VOID_Core.Instance.vessel.mainBody.Radius + VOID_Core.Instance.vessel.altitude, - 2 - ); - double weight = mass * gravity; - - return string.Format( - "{0} / {1}", - (currThrust / weight).ToString("F2"), - (maxThrust / weight).ToString("F2") - ); - } - ); - - public static VOID_DoubleValue surfaceThrustWeight = new VOID_DoubleValue( - "Max T:W @ surface", - delegate() - { - if (SimManager.Instance.Stages == null) - return double.NaN; - - double maxThrust = SimManager.Instance.LastStage.thrust; - double mass = SimManager.Instance.TryGetLastMass(); - double gravity = (VOID_Core.Constant_G * VOID_Core.Instance.vessel.mainBody.Mass) / - Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2); - double weight = mass * gravity; - - return maxThrust / weight; - }, - "" - ); - - public static VOID_StrValue intakeAirStatus = new VOID_StrValue( - "Intake Air (Curr / Req)", - delegate() - { - double currentAmount; - double currentRequirement; - - currentAmount = 0d; - currentRequirement = 0d; - - foreach (Part part in VOID_Core.Instance.vessel.Parts) - { - if (part.HasModule() && part.enabled) - { - foreach (Propellant propellant in part.GetModule().propellants) - { - if (propellant.name == "IntakeAir") - { - // currentAmount += propellant.currentAmount; - currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; - break; - } - } - } - - if (part.HasModule() && part.enabled) - { - ModuleResourceIntake intakeModule = part.GetModule(); - - 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 @@ -1,26 +1,34 @@ +// VOID // -// VOID_Orbital.cs +// VOID_VesselRegister.cs // -// Author: -// toadicus <> +// Copyright © 2014, toadicus +// All rights reserved. // -// Copyright (c) 2013 toadicus +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// 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. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// 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.Linq; +using ToadicusTools; using UnityEngine; namespace VOID @@ -28,16 +36,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; @@ -49,18 +57,25 @@ } } - 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 (!VOID_Core.Instance.allVesselTypes.Any()) + if (this.core.AllVesselTypes.Length < 1) { return; } @@ -70,34 +85,46 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<")) { - selectedBodyIdx--; - if (selectedBodyIdx < 0) selectedBodyIdx = VOID_Core.Instance.allBodies.Count - 1; + selectedBodyIdx.value--; + if (selectedBodyIdx < 0) + { + selectedBodyIdx.value = this.core.AllBodies.Count - 1; + } } - GUILayout.Label(VOID_Core.Instance.allBodies[selectedBodyIdx].bodyName, VOID_Core.Instance.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); + GUILayout.Label(this.core.AllBodies[selectedBodyIdx].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); if (GUILayout.Button(">")) { - selectedBodyIdx++; - if (selectedBodyIdx > VOID_Core.Instance.allBodies.Count - 1) selectedBodyIdx = 0; + selectedBodyIdx.value++; + if (selectedBodyIdx > this.core.AllBodies.Count - 1) + { + selectedBodyIdx.value = 0; + } } GUILayout.EndHorizontal(); - seletedBody = VOID_Core.Instance.allBodies[selectedBodyIdx]; + seletedBody = this.core.AllBodies[selectedBodyIdx]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("<")) { - selectedVesselTypeIdx--; - if (selectedVesselTypeIdx < 0) selectedVesselTypeIdx = VOID_Core.Instance.allVesselTypes.Count - 1; + selectedVesselTypeIdx.value--; + if (selectedVesselTypeIdx < 0) + { + selectedVesselTypeIdx.value = this.core.AllVesselTypes.Length - 1; + } } - GUILayout.Label(VOID_Core.Instance.allVesselTypes[selectedVesselTypeIdx].ToString(), VOID_Core.Instance.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 > VOID_Core.Instance.allVesselTypes.Count - 1) selectedVesselTypeIdx = 0; + selectedVesselTypeIdx.value++; + if (selectedVesselTypeIdx > this.core.AllVesselTypes.Length - 1) + { + selectedVesselTypeIdx.value = 0; + } } GUILayout.EndHorizontal(); - selectedVesselType = VOID_Core.Instance.allVesselTypes[selectedVesselTypeIdx]; + selectedVesselType = this.core.AllVesselTypes[selectedVesselTypeIdx]; GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (GUILayout.Button("Landed", GUILayout.ExpandWidth(true))) vesselSituation = "Landed"; @@ -106,16 +133,19 @@ GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label( - Tools.UppercaseFirst(vesselSituation) + " " + selectedVesselType.ToString() + "s @ " + seletedBody.bodyName, - VOID_Core.Instance.LabelStyles["center"], + VOID_Tools.UppercaseFirst(vesselSituation) + " " + selectedVesselType.ToString() + "s @ " + seletedBody.bodyName, + 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 || @@ -133,7 +163,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 { @@ -148,7 +178,7 @@ GUILayout.EndVertical(); - GUI.DragWindow(); + base.ModuleWindow(id); } } } --- a/Wrapper/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,37 +1,1 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("Toolbar Wrapper for Kerbal Space Program")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ToolbarWrapper")] -[assembly: AssemblyCopyright("Copyright © 2013-2014 Maik Schreiber")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("bfd95a60-6335-4a59-a29e-438d806d8f2d")] - -// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -// -// Hauptversion -// Nebenversion -// Buildnummer -// Revision -// -// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern -// übernehmen, indem Sie "*" eingeben: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] - --- a/Wrapper/ToolbarWrapper.cs +++ /dev/null @@ -1,793 +1,1 @@ -/* -Copyright (c) 2013-2014, Maik Schreiber -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. - -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 System.Text; -using UnityEngine; - - -namespace VOID { - - - - /**********************************************************\ - * --- DO NOT EDIT BELOW THIS COMMENT --- * - * * - * This file contains classes and interfaces to use the * - * Toolbar Plugin without creating a hard dependency on it. * - * * - * There is nothing in this file that needs to be edited * - * by hand. * - * * - * --- DO NOT EDIT BELOW THIS COMMENT --- * - \**********************************************************/ - - - - /// - /// The global tool bar manager. - /// - public partial class ToolbarManager : IToolbarManager { - /// - /// Whether the Toolbar Plugin is available. - /// - public static bool ToolbarAvailable { - get { - if (toolbarAvailable == null) { - toolbarAvailable = Instance != null; - } - return (bool) toolbarAvailable; - } - } - - /// - /// The global tool bar manager instance. - /// - public static IToolbarManager Instance { - get { - if ((toolbarAvailable != false) && (instance_ == null)) { - Type type = ToolbarTypes.getType("Toolbar.ToolbarManager"); - if (type != null) { - object realToolbarManager = ToolbarTypes.getStaticProperty(type, "Instance").GetValue(null, null); - instance_ = new ToolbarManager(realToolbarManager); - } - } - return instance_; - } - } - } - - #region interfaces - - /// - /// A toolbar manager. - /// - public interface IToolbarManager { - /// - /// Adds a new button. - /// - /// - /// To replace an existing button, just add a new button using the old button's namespace and ID. - /// Note that the new button will inherit the screen position of the old button. - /// - /// The new button's namespace. This is usually the plugin's name. Must not include special characters like '.' - /// The new button's ID. This ID must be unique across all buttons in the namespace. Must not include special characters like '.' - /// The button created. - IButton add(string ns, string id); - } - - /// - /// Represents a clickable button. - /// - public interface IButton { - /// - /// The text displayed on the button. Set to null to hide text. - /// - /// - /// The text can be changed at any time to modify the button's appearance. Note that since this will also - /// modify the button's size, this feature should be used sparingly, if at all. - /// - /// - string Text { - set; - get; - } - - /// - /// The color the button text is displayed with. Defaults to Color.white. - /// - /// - /// The text color can be changed at any time to modify the button's appearance. - /// - Color TextColor { - set; - get; - } - - /// - /// The path of a texture file to display an icon on the button. Set to null to hide icon. - /// - /// - /// - /// A texture path on a button will have precedence over text. That is, if both text and texture path - /// have been set on a button, the button will show the texture, not the text. - /// - /// - /// The texture size must not exceed 24x24 pixels. - /// - /// - /// The texture path must be relative to the "GameData" directory, and must not specify a file name suffix. - /// Valid example: MyAddon/Textures/icon_mybutton - /// - /// - /// The texture path can be changed at any time to modify the button's appearance. - /// - /// - /// - string TexturePath { - set; - get; - } - - /// - /// The button's tool tip text. Set to null if no tool tip is desired. - /// - /// - /// Tool Tip Text Should Always Use Headline Style Like This. - /// - string ToolTip { - set; - get; - } - - /// - /// Whether this button is currently visible or not. Can be used in addition to or as a replacement for . - /// - /// - /// Setting this property to true does not affect the player's ability to hide the button using the configuration. - /// Conversely, setting this property to false does not enable the player to show the button using the configuration. - /// - bool Visible { - set; - get; - } - - /// - /// Determines this button's visibility. Can be used in addition to or as a replacement for . - /// - /// - /// The return value from IVisibility.Visible is subject to the same rules as outlined for - /// . - /// - IVisibility Visibility { - set; - get; - } - - /// - /// Whether this button is currently effectively visible or not. This is a combination of - /// and . - /// - /// - /// Note that the toolbar is not visible in certain game scenes, for example the loading screens. This property - /// does not reflect button invisibility in those scenes. In addition, this property does not reflect the - /// player's configuration of the button's visibility. - /// - bool EffectivelyVisible { - get; - } - - /// - /// Whether this button is currently enabled (clickable) or not. This does not affect the player's ability to - /// position the button on their toolbar. - /// - bool Enabled { - set; - get; - } - - /// - /// Whether this button is currently "important." Set to false to return to normal button behaviour. - /// - /// - /// - /// This can be used to temporarily force the button to be shown on screen regardless of the toolbar being - /// currently in auto-hidden mode. For example, a button that signals the arrival of a private message in - /// a chat room could mark itself as "important" as long as the message has not been read. - /// - /// - /// Setting this property does not change the appearance of the button. Use to - /// change the button's icon. - /// - /// - /// Setting this property to true does not affect the player's ability to hide the button using the - /// configuration. - /// - /// - /// This feature should be used only sparingly, if at all, since it forces the button to be displayed on - /// screen even when it normally wouldn't. - /// - /// - bool Important { - set; - get; - } - - /// - /// A drawable that is tied to the current button. This can be anything from a popup menu to - /// an informational window. Set to null to hide the drawable. - /// - IDrawable Drawable { - set; - get; - } - - /// - /// Event handler that can be registered with to receive "on click" events. - /// - /// - /// - /// IButton button = ... - /// button.OnClick += (e) => { - /// Debug.Log("button clicked, mouseButton: " + e.MouseButton); - /// }; - /// - /// - event ClickHandler OnClick; - - /// - /// Event handler that can be registered with to receive "on mouse enter" events. - /// - /// - /// - /// IButton button = ... - /// button.OnMouseEnter += (e) => { - /// Debug.Log("mouse entered button"); - /// }; - /// - /// - event MouseEnterHandler OnMouseEnter; - - /// - /// Event handler that can be registered with to receive "on mouse leave" events. - /// - /// - /// - /// IButton button = ... - /// button.OnMouseLeave += (e) => { - /// Debug.Log("mouse left button"); - /// }; - /// - /// - event MouseLeaveHandler OnMouseLeave; - - /// - /// Permanently destroys this button so that it is no longer displayed. - /// Should be used when a plugin is stopped to remove leftover buttons. - /// - void Destroy(); - } - - /// - /// A drawable that is tied to a particular button. This can be anything from a popup menu - /// to an informational window. - /// - public interface IDrawable { - /// - /// Update any information. This is called once per frame. - /// - void Update(); - - /// - /// Draws GUI widgets for this drawable. This is the equivalent to the OnGUI() message in - /// . - /// - /// - /// The drawable will be positioned near its parent toolbar according to the drawable's current - /// width/height. - /// - /// The left/top position of where to draw this drawable. - /// The current width/height of this drawable. - Vector2 Draw(Vector2 position); - } - - #endregion - - #region events - - /// - /// Event describing a click on a button. - /// - public partial class ClickEvent : EventArgs { - /// - /// The button that has been clicked. - /// - public readonly IButton Button; - - /// - /// The mouse button which the button was clicked with. - /// - /// - /// Is 0 for left mouse button, 1 for right mouse button, and 2 for middle mouse button. - /// - public readonly int MouseButton; - } - - /// - /// An event handler that is invoked whenever a button has been clicked. - /// - /// An event describing the button click. - public delegate void ClickHandler(ClickEvent e); - - /// - /// Event describing the mouse pointer moving about a button. - /// - public abstract partial class MouseMoveEvent { - /// - /// The button in question. - /// - public readonly IButton button; - } - - /// - /// Event describing the mouse pointer entering a button's area. - /// - public partial class MouseEnterEvent : MouseMoveEvent { - } - - /// - /// Event describing the mouse pointer leaving a button's area. - /// - public partial class MouseLeaveEvent : MouseMoveEvent { - } - - /// - /// An event handler that is invoked whenever the mouse pointer enters a button's area. - /// - /// An event describing the mouse pointer entering. - public delegate void MouseEnterHandler(MouseEnterEvent e); - - /// - /// An event handler that is invoked whenever the mouse pointer leaves a button's area. - /// - /// An event describing the mouse pointer leaving. - public delegate void MouseLeaveHandler(MouseLeaveEvent e); - - #endregion - - #region visibility - - /// - /// Determines visibility of a button. - /// - /// - public interface IVisibility { - /// - /// Whether a button is currently visible or not. - /// - /// - bool Visible { - get; - } - } - - /// - /// Determines visibility of a button in relation to the currently running game scene. - /// - /// - /// - /// IButton button = ... - /// button.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.SPH); - /// - /// - /// - public class GameScenesVisibility : IVisibility { - private GameScenes[] gameScenes; - - public bool Visible { - get { - return (bool) visibleProperty.GetValue(realGameScenesVisibility, null); - } - } - - private object realGameScenesVisibility; - private PropertyInfo visibleProperty; - - public GameScenesVisibility(params GameScenes[] gameScenes) { - Type gameScenesVisibilityType = ToolbarTypes.getType("Toolbar.GameScenesVisibility"); - realGameScenesVisibility = Activator.CreateInstance(gameScenesVisibilityType, new object[] { gameScenes }); - visibleProperty = ToolbarTypes.getProperty(gameScenesVisibilityType, "Visible"); - this.gameScenes = gameScenes; - } - } - - #endregion - - #region drawable - - /// - /// A drawable that draws a popup menu. - /// - public partial class PopupMenuDrawable : IDrawable { - /// - /// Event handler that can be registered with to receive "any menu option clicked" events. - /// - public event Action OnAnyOptionClicked { - add { - onAnyOptionClickedEvent.AddEventHandler(realPopupMenuDrawable, value); - } - remove { - onAnyOptionClickedEvent.RemoveEventHandler(realPopupMenuDrawable, value); - } - } - - private object realPopupMenuDrawable; - private MethodInfo updateMethod; - private MethodInfo drawMethod; - private MethodInfo addOptionMethod; - private MethodInfo addSeparatorMethod; - private MethodInfo destroyMethod; - private EventInfo onAnyOptionClickedEvent; - - public PopupMenuDrawable() { - Type popupMenuDrawableType = ToolbarTypes.getType("Toolbar.PopupMenuDrawable"); - realPopupMenuDrawable = Activator.CreateInstance(popupMenuDrawableType, null); - updateMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Update"); - drawMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Draw"); - addOptionMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddOption"); - addSeparatorMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddSeparator"); - destroyMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Destroy"); - onAnyOptionClickedEvent = ToolbarTypes.getEvent(popupMenuDrawableType, "OnAnyOptionClicked"); - } - - public void Update() { - updateMethod.Invoke(realPopupMenuDrawable, null); - } - - public Vector2 Draw(Vector2 position) { - return (Vector2) drawMethod.Invoke(realPopupMenuDrawable, new object[] { position }); - } - - /// - /// Adds a new option to the popup menu. - /// - /// The text of the option. - /// A button that can be used to register clicks on the menu option. - public IButton AddOption(string text) { - object realButton = addOptionMethod.Invoke(realPopupMenuDrawable, new object[] { text }); - return new Button(realButton, new ToolbarTypes()); - } - - /// - /// Adds a separator to the popup menu. - /// - public void AddSeparator() { - addSeparatorMethod.Invoke(realPopupMenuDrawable, null); - } - - /// - /// Destroys this drawable. This must always be called before disposing of this drawable. - /// - public void Destroy() { - destroyMethod.Invoke(realPopupMenuDrawable, null); - } - } - - #endregion - - #region private implementations - - public partial class ToolbarManager : IToolbarManager { - private static bool? toolbarAvailable = null; - private static IToolbarManager instance_; - - private object realToolbarManager; - private MethodInfo addMethod; - private Dictionary buttons = new Dictionary(); - private ToolbarTypes types = new ToolbarTypes(); - - private ToolbarManager(object realToolbarManager) { - this.realToolbarManager = realToolbarManager; - - addMethod = ToolbarTypes.getMethod(types.iToolbarManagerType, "add"); - } - - public IButton add(string ns, string id) { - object realButton = addMethod.Invoke(realToolbarManager, new object[] { ns, id }); - IButton button = new Button(realButton, types); - buttons.Add(realButton, button); - return button; - } - } - - internal class Button : IButton { - private object realButton; - private ToolbarTypes types; - private Delegate realClickHandler; - private Delegate realMouseEnterHandler; - private Delegate realMouseLeaveHandler; - - internal Button(object realButton, ToolbarTypes types) { - this.realButton = realButton; - this.types = types; - - realClickHandler = attachEventHandler(types.button.onClickEvent, "clicked", realButton); - realMouseEnterHandler = attachEventHandler(types.button.onMouseEnterEvent, "mouseEntered", realButton); - realMouseLeaveHandler = attachEventHandler(types.button.onMouseLeaveEvent, "mouseLeft", realButton); - } - - private Delegate attachEventHandler(EventInfo @event, string methodName, object realButton) { - MethodInfo method = GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); - Delegate d = Delegate.CreateDelegate(@event.EventHandlerType, this, method); - @event.AddEventHandler(realButton, d); - return d; - } - - public string Text { - set { - types.button.textProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.textProperty.GetValue(realButton, null); - } - } - - public Color TextColor { - set { - types.button.textColorProperty.SetValue(realButton, value, null); - } - get { - return (Color) types.button.textColorProperty.GetValue(realButton, null); - } - } - - public string TexturePath { - set { - types.button.texturePathProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.texturePathProperty.GetValue(realButton, null); - } - } - - public string ToolTip { - set { - types.button.toolTipProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.toolTipProperty.GetValue(realButton, null); - } - } - - public bool Visible { - set { - types.button.visibleProperty.SetValue(realButton, value, null); - } - get { - return (bool) types.button.visibleProperty.GetValue(realButton, null); - } - } - - public IVisibility Visibility { - set { - object functionVisibility = null; - if (value != null) { - functionVisibility = Activator.CreateInstance(types.functionVisibilityType, new object[] { new Func(() => value.Visible) }); - } - types.button.visibilityProperty.SetValue(realButton, functionVisibility, null); - visibility_ = value; - } - get { - return visibility_; - } - } - private IVisibility visibility_; - - public bool EffectivelyVisible { - get { - return (bool) types.button.effectivelyVisibleProperty.GetValue(realButton, null); - } - } - - public bool Enabled { - set { - types.button.enabledProperty.SetValue(realButton, value, null); - } - get { - return (bool) types.button.enabledProperty.GetValue(realButton, null); - } - } - - public bool Important { - set { - types.button.importantProperty.SetValue(realButton, value, null); - } - get { - return (bool) types.button.importantProperty.GetValue(realButton, null); - } - } - - public IDrawable Drawable { - set { - object functionDrawable = null; - if (value != null) { - functionDrawable = Activator.CreateInstance(types.functionDrawableType, new object[] { - new Action(() => value.Update()), - new Func((pos) => value.Draw(pos)) - }); - } - types.button.drawableProperty.SetValue(realButton, functionDrawable, null); - drawable_ = value; - } - get { - return drawable_; - } - } - private IDrawable drawable_; - - public event ClickHandler OnClick; - - private void clicked(object realEvent) { - if (OnClick != null) { - OnClick(new ClickEvent(realEvent, this)); - } - } - - public event MouseEnterHandler OnMouseEnter; - - private void mouseEntered(object realEvent) { - if (OnMouseEnter != null) { - OnMouseEnter(new MouseEnterEvent(this)); - } - } - - public event MouseLeaveHandler OnMouseLeave; - - private void mouseLeft(object realEvent) { - if (OnMouseLeave != null) { - OnMouseLeave(new MouseLeaveEvent(this)); - } - } - - public void Destroy() { - detachEventHandler(types.button.onClickEvent, realClickHandler, realButton); - detachEventHandler(types.button.onMouseEnterEvent, realMouseEnterHandler, realButton); - detachEventHandler(types.button.onMouseLeaveEvent, realMouseLeaveHandler, realButton); - - types.button.destroyMethod.Invoke(realButton, null); - } - - private void detachEventHandler(EventInfo @event, Delegate d, object realButton) { - @event.RemoveEventHandler(realButton, d); - } - } - - public partial class ClickEvent : EventArgs { - internal ClickEvent(object realEvent, IButton button) { - Type type = realEvent.GetType(); - Button = button; - MouseButton = (int) type.GetField("MouseButton", BindingFlags.Public | BindingFlags.Instance).GetValue(realEvent); - } - } - - public abstract partial class MouseMoveEvent : EventArgs { - internal MouseMoveEvent(IButton button) { - this.button = button; - } - } - - public partial class MouseEnterEvent : MouseMoveEvent { - internal MouseEnterEvent(IButton button) - : base(button) { - } - } - - public partial class MouseLeaveEvent : MouseMoveEvent { - internal MouseLeaveEvent(IButton button) - : base(button) { - } - } - - internal class ToolbarTypes { - internal readonly Type iToolbarManagerType; - internal readonly Type functionVisibilityType; - internal readonly Type functionDrawableType; - internal readonly ButtonTypes button; - - internal ToolbarTypes() { - iToolbarManagerType = getType("Toolbar.IToolbarManager"); - functionVisibilityType = getType("Toolbar.FunctionVisibility"); - functionDrawableType = getType("Toolbar.FunctionDrawable"); - - Type iButtonType = getType("Toolbar.IButton"); - button = new ButtonTypes(iButtonType); - } - - internal static Type getType(string name) { - return AssemblyLoader.loadedAssemblies - .SelectMany(a => a.assembly.GetExportedTypes()) - .SingleOrDefault(t => t.FullName == name); - } - - internal static PropertyInfo getProperty(Type type, string name) { - return type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); - } - - internal static PropertyInfo getStaticProperty(Type type, string name) { - return type.GetProperty(name, BindingFlags.Public | BindingFlags.Static); - } - - internal static EventInfo getEvent(Type type, string name) { - return type.GetEvent(name, BindingFlags.Public | BindingFlags.Instance); - } - - internal static MethodInfo getMethod(Type type, string name) { - return type.GetMethod(name, BindingFlags.Public | BindingFlags.Instance); - } - } - - internal class ButtonTypes { - internal readonly Type iButtonType; - internal readonly PropertyInfo textProperty; - internal readonly PropertyInfo textColorProperty; - internal readonly PropertyInfo texturePathProperty; - internal readonly PropertyInfo toolTipProperty; - internal readonly PropertyInfo visibleProperty; - internal readonly PropertyInfo visibilityProperty; - internal readonly PropertyInfo effectivelyVisibleProperty; - internal readonly PropertyInfo enabledProperty; - internal readonly PropertyInfo importantProperty; - internal readonly PropertyInfo drawableProperty; - internal readonly EventInfo onClickEvent; - internal readonly EventInfo onMouseEnterEvent; - internal readonly EventInfo onMouseLeaveEvent; - internal readonly MethodInfo destroyMethod; - - internal ButtonTypes(Type iButtonType) { - this.iButtonType = iButtonType; - - textProperty = ToolbarTypes.getProperty(iButtonType, "Text"); - textColorProperty = ToolbarTypes.getProperty(iButtonType, "TextColor"); - texturePathProperty = ToolbarTypes.getProperty(iButtonType, "TexturePath"); - toolTipProperty = ToolbarTypes.getProperty(iButtonType, "ToolTip"); - visibleProperty = ToolbarTypes.getProperty(iButtonType, "Visible"); - visibilityProperty = ToolbarTypes.getProperty(iButtonType, "Visibility"); - effectivelyVisibleProperty = ToolbarTypes.getProperty(iButtonType, "EffectivelyVisible"); - enabledProperty = ToolbarTypes.getProperty(iButtonType, "Enabled"); - importantProperty = ToolbarTypes.getProperty(iButtonType, "Important"); - drawableProperty = ToolbarTypes.getProperty(iButtonType, "Drawable"); - onClickEvent = ToolbarTypes.getEvent(iButtonType, "OnClick"); - onMouseEnterEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseEnter"); - onMouseLeaveEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseLeave"); - destroyMethod = ToolbarTypes.getMethod(iButtonType, "Destroy"); - } - } - - #endregion -} - --- a/Wrapper/Wrapper.csproj +++ /dev/null @@ -1,59 +1,1 @@ - - - - - Debug - AnyCPU - {E258AB2C-E2BB-4ACA-B902-C98582041F69} - Library - Properties - ToolbarWrapper - ToolbarWrapper - v3.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\..\..\Programme\KSP_23_dev\KSP_Data\Managed\Assembly-CSharp.dll - - - - - - - - - ..\..\..\..\Programme\KSP_23_dev\KSP_Data\Managed\UnityEngine.dll - - - - - - - - - +