--- a/VOID_Core.cs +++ b/VOID_Core.cs @@ -1,34 +1,44 @@ +// VOID // -// VOID_Core.cs +// VOID_Core.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 <http://www.gnu.org/licenses/>. +// 3. Neither the name of the copyright holder nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using Engineer.VesselSimulator; +using KSP; using System; using System.Collections.Generic; using System.Linq; -using KSP; +using ToadicusTools; using UnityEngine; -using Engineer.VesselSimulator; namespace VOID { public class VOID_Core : VOID_Module, IVOID_Module { + #region Singleton Members /* * Static Members * */ @@ -60,16 +70,19 @@ public static void Reset() { _instance.StopGUI(); + _instance.Dispose(); _instance = null; _initialized = false; } - - public static double Constant_G = 6.674e-11; + #endregion + + public static readonly double Constant_G = 6.674e-11; + /* * Fields * */ protected string VoidName = "VOID"; - protected string VoidVersion = "0.9.20"; + protected string VoidVersion; protected bool _factoryReset = false; @@ -128,16 +141,22 @@ protected float _updateTimer = 0f; protected string stringFrequency; + [AVOID_SaveValue("vesselSimActive")] + protected VOID_SaveValue<bool> vesselSimActive; + // Vessel Type Housekeeping protected List<VesselType> _allVesselTypes = new List<VesselType>(); protected bool vesselTypesLoaded = false; public float saveTimer = 0; protected string defaultSkin = "KSP window 2"; + [AVOID_SaveValue("defaultSkin")] protected VOID_SaveValue<string> _skinName; - protected Dictionary<string, GUISkin> skin_list; - protected List<string> skinNames; + protected int _skinIdx; + + protected Dictionary<string, GUISkin> validSkins; + protected string[] skinNames; protected string[] forbiddenSkins = { "PlaqueDialogSkin", @@ -157,6 +176,8 @@ protected VOID_SaveValue<bool> _UseToolbarManager; internal IButton ToolbarButton; + internal ApplicationLauncherButton AppLauncherButton; + /* * Properties * */ @@ -180,11 +201,18 @@ { get { - if (!this.skinsLoaded || this._skinName == null) - { - return AssetBase.GetGUISkin(this.defaultSkin); - } - return this.skin_list[this._skinName]; + if (this.skinsLoaded) + { + try + { + return this.validSkins[this._skinName]; + } + catch + { + } + } + + return AssetBase.GetGUISkin(this.defaultSkin); } } @@ -256,6 +284,18 @@ } } + public Stage[] Stages + { + get; + protected set; + } + + public Stage LastStage + { + get; + protected set; + } + protected IconState powerState { get @@ -292,7 +332,7 @@ { get { - return _UseToolbarManager; + return _UseToolbarManager & ToolbarManager.ToolbarAvailable; } set { @@ -306,14 +346,26 @@ this.ToolbarButton.Destroy(); this.ToolbarButton = null; } - if (value == true && this.ToolbarButton == null) - { + if (value == true) + { + if (this.AppLauncherButton != null) + { + ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); + this.AppLauncherButton = null; + } + this.InitializeToolbarButton(); } - this.SetIconTexture(this.powerState | this.activeState); - _UseToolbarManager.value = value; + } + } + + protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes + { + get + { + return ApplicationLauncher.AppScenes.FLIGHT; } } @@ -343,9 +395,9 @@ if (!this.UseToolbarManager) { - if (GUI.Button(VOIDIconPos, VOIDIconTexture, this.iconStyle) && this.VOIDIconLocked) - { - this.ToggleMainWindow(); + if (this.AppLauncherButton == null) + { + this.InitializeAppLauncherButton(); } } else if (this.ToolbarButton == null) @@ -361,7 +413,7 @@ _mainWindowPos = GUILayout.Window( this.windowID, _mainWindowPos, - this.VOIDMainWindow, + VOID_Tools.GetWindowHandler(this.VOIDMainWindow), string.Join(" ", new string[] { this.VoidName, this.VoidVersion }), GUILayout.Width(250), GUILayout.Height(50) @@ -382,7 +434,7 @@ _configWindowPos = GUILayout.Window( this.windowID, _configWindowPos, - this.VOIDConfigWindow, + VOID_Tools.GetWindowHandler(this.VOIDConfigWindow), string.Join(" ", new string[] { this.VoidName, "Configuration" }), GUILayout.Width(250), GUILayout.Height(50) @@ -397,7 +449,7 @@ } } - public void OnGUI() + public virtual void OnGUI() { if (Event.current.type == EventType.Repaint) { @@ -451,15 +503,14 @@ } } - public void Update() + public virtual 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.vessel != null && this.vesselSimActive) + { + Tools.PostDebugMessage(this, "Updating SimManager."); + this.UpdateSimManager(); } if (!this.guiRunning) @@ -496,7 +547,7 @@ this._updateTimer += Time.deltaTime; } - public void FixedUpdate() + public virtual void FixedUpdate() { bool newPowerState = this.powerAvailable; @@ -594,8 +645,6 @@ public override void DrawConfigurables() { - int skinIdx; - GUIContent _content; if (HighLogic.LoadedSceneIsFlight) @@ -607,38 +656,26 @@ this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available"); + this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value, + "Enable Engineering Calculations"); + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); _content = new GUIContent(); - - 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; + this._skinIdx--; Tools.PostDebugMessage(string.Format( "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", this.GetType().Name, this._skinName, - this.skin_list.Count + this.validSkins.Count )); } @@ -651,20 +688,24 @@ if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) { this.GUIStylesLoaded = false; - skinIdx++; - if (skinIdx >= skinNames.Count) - skinIdx = 0; + this._skinIdx++; Tools.PostDebugMessage(string.Format( "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", this.GetType().Name, this._skinName, - this.skin_list.Count + this.validSkins.Count )); } - if (this._skinName != skinNames[skinIdx]) - { - this._skinName = skinNames[skinIdx]; + this._skinIdx %= this.skinNames.Length; + if (this._skinIdx < 0) + { + this._skinIdx += this.skinNames.Length; + } + + if (this._skinName != skinNames[this._skinIdx]) + { + this._skinName.value = skinNames[this._skinIdx]; } GUILayout.EndHorizontal(); @@ -691,6 +732,41 @@ } this._factoryReset = GUILayout.Toggle(this._factoryReset, "Factory Reset"); + } + + protected void UpdateSimManager() + { + if (SimManager.ResultsReady()) + { + Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages."); + + this.Stages = SimManager.Stages; + + if (this.Stages != null) + { + this.LastStage = this.Stages.Last(); + } + + if (HighLogic.LoadedSceneIsEditor) + { + SimManager.Gravity = VOID_Data.KerbinGee; + } + else + { + double radius = this.vessel.Radius(); + SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius); + } + + SimManager.minSimTime = (long)(this.updatePeriod * 1000); + + SimManager.TryStartSimulation(); + } + #if DEBUG + else + { + Tools.PostDebugMessage(this, "VesselSimulator results not ready."); + } + #endif } protected void LoadModulesOfType<T>() @@ -767,7 +843,7 @@ ) ); - this.skin_list = Resources.FindObjectsOfTypeAll(typeof(GUISkin)) + this.validSkins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)) .Where(s => !this.forbiddenSkins.Contains(s.name)) .Select(s => s as GUISkin) .GroupBy(s => s.name) @@ -777,19 +853,33 @@ Tools.PostDebugMessage(string.Format( "{0}: loaded {1} GUISkins.", this.GetType().Name, - this.skin_list.Count + this.validSkins.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 - )); + this.skinNames = this.validSkins.Keys.ToArray(); + Array.Sort(this.skinNames); + + int defaultIdx = int.MinValue; + + for (int i = 0; i < this.skinNames.Length; i++) + { + if (this.skinNames[i] == this._skinName) + { + this._skinIdx = i; + } + if (this.skinNames[i] == this.defaultSkin) + { + defaultIdx = i; + } + if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue) + { + break; + } + } + + if (this._skinIdx == int.MinValue) + { + this._skinIdx = defaultIdx; } Tools.PostDebugMessage(string.Format( @@ -849,24 +939,46 @@ protected void InitializeToolbarButton() { - this.ToolbarButton = ToolbarManager.Instance.add(this.GetType().Name, "coreToggle"); + // Do nothing if (the Toolbar is not available. + if (!ToolbarManager.ToolbarAvailable) + { + return; + } + + this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); this.ToolbarButton.Text = this.VoidName; this.SetIconTexture(this.powerState | this.activeState); - if (this is VOID_EditorCore) - { - this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR); - } - else - { - this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT); - } + this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH); this.ToolbarButton.OnClick += (e) => { this.ToggleMainWindow(); }; + + Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); + } + + protected void InitializeAppLauncherButton() + { + if (ApplicationLauncher.Ready) + { + this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( + this.ToggleMainWindow, this.ToggleMainWindow, + this.appIconVisibleScenes, + this.VOIDIconTexture + ); + + Tools.PostDebugMessage( + this, + "AppLauncherButton initialized in {0}", + Enum.GetName( + typeof(GameScenes), + HighLogic.LoadedScene + ) + ); + } } protected void ToggleMainWindow() @@ -898,13 +1010,16 @@ protected void SetIconTexture(string texturePath) { - if (this.UseToolbarManager && this.ToolbarButton != null) + if (this.ToolbarButton != null) { this.ToolbarButton.TexturePath = texturePath; } - else - { - this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath, false); + + this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false); + + if (this.AppLauncherButton != null) + { + this.AppLauncherButton.SetTexture(VOIDIconTexture); } } @@ -961,20 +1076,41 @@ { this._Name = "VOID Core"; - this._Active.value = true; + System.Version version = this.GetType().Assembly.GetName().Version; + + this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision); + + this.toggleActive = 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._skinIdx = int.MinValue; + + this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_light_glow"; + this.VOIDIconOnActivePath = "VOID/Textures/void_icon_dark_glow"; + this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_light"; + this.VOIDIconOffActivePath = "VOID/Textures/void_icon_dark"; + + this.vesselSimActive = true; this.UseToolbarManager = false; this.LoadConfig(); this.SetIconTexture(this.powerState | this.activeState); + } + + public virtual void Dispose() + { + if (this.AppLauncherButton != null) + { + ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); + this.AppLauncherButton = null; + } + if (this.ToolbarButton != null) + { + this.ToolbarButton.Destroy(); + this.ToolbarButton = null; + } } protected enum IconState @@ -985,6 +1121,39 @@ Active = 8 } } + + public static partial class VOID_Data + { + public static VOID_Core core + { + get + { + if (HighLogic.LoadedSceneIsEditor) + { + return VOID_EditorCore.Instance; + } + else + { + return VOID_Core.Instance; + } + } + } + + public static double KerbinGee + { + get + { + if (kerbinGee == default(double)) + { + kerbinGee = core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius); + } + + return kerbinGee; + } + } + + private static double kerbinGee; + } }