--- a/VOID_Core.cs +++ b/VOID_Core.cs @@ -1,47 +1,59 @@ +// 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 * */ protected static bool _initialized = false; + public static bool Initialized { - get - { - return _initialized; + get + { + return _initialized; } } protected static VOID_Core _instance; + public static VOID_Core Instance { get @@ -58,17 +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.17"; + protected string VoidVersion; protected bool _factoryReset = false; @@ -80,35 +94,37 @@ [AVOID_SaveValue("mainWindowPos")] protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f); - [AVOID_SaveValue("mainGuiMinimized")] protected VOID_SaveValue<bool> mainGuiMinimized = false; [AVOID_SaveValue("configWindowPos")] protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f); - [AVOID_SaveValue("configWindowMinimized")] + protected VOID_SaveValue<bool> configWindowMinimized = true; - [AVOID_SaveValue("VOIDIconPos")] - protected VOID_SaveValue<Rect> VOIDIconPos = new Rect(Screen.width / 2 - 200, Screen.height - 30, 30f, 30f); - protected Texture2D VOIDIconOff = new Texture2D(30, 30, TextureFormat.ARGB32, false); - protected Texture2D VOIDIconOn = new Texture2D(30, 30, TextureFormat.ARGB32, false); + protected VOID_SaveValue<Rect> VOIDIconPos = new Rect(Screen.width / 2 - 200, Screen.height - 32, 32f, 32f); + protected Texture2D VOIDIconTexture; - protected string VOIDIconOnPath = "VOID/Textures/void_icon_on"; - protected string VOIDIconOffPath = "VOID/Textures/void_icon_off"; + 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<string, GUIStyle> _LabelStyles = new Dictionary<string, GUIStyle>(); + + protected CelestialBody _Kerbin; [AVOID_SaveValue("togglePower")] public VOID_SaveValue<bool> togglePower = true; - public bool powerAvailable = true; [AVOID_SaveValue("consumeResource")] @@ -121,44 +137,46 @@ protected VOID_SaveValue<float> resourceRate = 0.2f; [AVOID_SaveValue("updatePeriod")] - protected VOID_SaveValue<double> _updatePeriod = 1001f/15000f; + protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f; protected float _updateTimer = 0f; protected string stringFrequency; - // Celestial Body Housekeeping - protected List<CelestialBody> _allBodies = new List<CelestialBody>(); - protected bool bodiesLoaded = false; + [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", - "FlagBrowserSkin", - "SSUITextAreaDefault", - "ExperimentsDialogSkin", - "ExpRecoveryDialogSkin", - "KSP window 5", - "KSP window 6" - }; + { + "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<bool> _UseToolbarManager; - protected bool ToolbarManagerLoaded = false; - internal ToolbarButtonWrapper ToolbarButton; + internal IButton ToolbarButton; + + internal ApplicationLauncherButton AppLauncherButton; /* * Properties @@ -183,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); } } @@ -197,7 +222,7 @@ { if (this._windowID == 0) { - this._windowID = this.windowBaseID; + this._windowID = this.windowBaseID; } return this._windowID++; } @@ -215,7 +240,23 @@ { get { - return this._allBodies; + 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; } } @@ -243,397 +284,101 @@ } } + public Stage[] Stages + { + get; + protected set; + } + + public Stage LastStage + { + get; + protected set; + } + + 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; + return _UseToolbarManager & ToolbarManager.ToolbarAvailable; } set { - if (value == false && this.ToolbarManagerLoaded && this.ToolbarButton != null) + if (this._UseToolbarManager == value) + { + return; + } + + if (value == false && this.ToolbarButton != null) { this.ToolbarButton.Destroy(); this.ToolbarButton = null; } - if (value == true && this.ToolbarManagerLoaded && this.ToolbarButton == null) - { + if (value == true) + { + if (this.AppLauncherButton != null) + { + ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); + this.AppLauncherButton = null; + } + this.InitializeToolbarButton(); } _UseToolbarManager.value = value; + } + } + + protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes + { + get + { + return ApplicationLauncher.AppScenes.FLIGHT; } } /* * Methods * */ - protected VOID_Core() - { - this._Name = "VOID Core"; - - this._Active.value = true; - - this.VOIDIconOn = GameDatabase.Instance.GetTexture (this.VOIDIconOnPath, false); - this.VOIDIconOff = GameDatabase.Instance.GetTexture (this.VOIDIconOffPath, false); - - this._skinName = this.defaultSkin; - - this.UseToolbarManager = false; - - this.LoadConfig (); - } - - protected void LoadModulesOfType<T>() - { - 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", AssetBase.FindObjectsOfTypeIncludingAssets ( - typeof(GUISkin)) - .Select(s => s.ToString()) - .ToArray() - ) - ); - - this.skin_list = AssetBase.FindObjectsOfTypeIncludingAssets(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.GUIStylesLoaded = true; - } - - protected void LoadAllBodies() - { - this._allBodies = FlightGlobals.Bodies; - this.bodiesLoaded = true; - } - - protected void LoadVesselTypes() - { - this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToList(); - this.vesselTypesLoaded = true; - } - - protected void LoadBeforeUpdate() - { - if (!this.bodiesLoaded) - { - this.LoadAllBodies(); - } - - if (!this.vesselTypesLoaded) - { - this.LoadVesselTypes(); - } - } - - protected void LoadToolbarManager() - { - Type ToolbarManager = AssemblyLoader.loadedAssemblies - .Select(a => a.assembly.GetExportedTypes()) - .SelectMany(t => t) - .FirstOrDefault(t => t.FullName == "Toolbar.ToolbarManager"); - - if (ToolbarManager == null) - { - Tools.PostDebugMessage(string.Format( - "{0}: Could not load ToolbarManager.", - this.GetType().Name - )); - - return; - } - - this.InitializeToolbarButton(); - - this.ToolbarManagerLoaded = true; - } - - protected void InitializeToolbarButton() - { - this.ToolbarButton = new ToolbarButtonWrapper(this.GetType().Name, "coreToggle"); - this.ToolbarButton.Text = this.VoidName; - this.ToolbarButton.TexturePath = this.VOIDIconOffPath + "_24x24"; - if (this is VOID_EditorCore) - { - this.ToolbarButton.SetButtonVisibility(new GameScenes[] { GameScenes.EDITOR }); - } - else - { - this.ToolbarButton.SetButtonVisibility(new GameScenes[] { GameScenes.FLIGHT }); - } - this.ToolbarButton.AddButtonClickHandler( - (e) => this.mainGuiMinimized = !this.mainGuiMinimized - ); - } - - public void VOIDMainWindow(int _) - { - GUILayout.BeginVertical(); - - if (this.powerAvailable || HighLogic.LoadedSceneIsEditor) - { - if (!HighLogic.LoadedSceneIsEditor) - { - string str = "ON"; - if (togglePower) str = "OFF"; - if (GUILayout.Button("Power " + str)) togglePower.value = !togglePower; - } - - 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))) - { - 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))) - { - 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"); - } - public override void DrawGUI() { this._windowID = this.windowBaseID; if (!this._modulesLoaded) { - this.LoadModulesOfType<IVOID_Module> (); - } - - if (this.UseToolbarManager && !this.ToolbarManagerLoaded) - { - this.LoadToolbarManager(); + this.LoadModulesOfType<IVOID_Module>(); } if (!this.skinsLoaded) @@ -645,42 +390,36 @@ if (!this.GUIStylesLoaded) { - this.LoadGUIStyles (); - } - - if (this.UseToolbarManager && this.ToolbarManagerLoaded) - { - this.ToolbarButton.TexturePath = VOIDIconOffPath + "_24x24"; - if (this.togglePower) - { - this.ToolbarButton.TexturePath = VOIDIconOnPath + "_24x24"; - } - } - else - { - this.VOIDIconTexture = this.VOIDIconOff; //icon off default - if (this.togglePower) - this.VOIDIconTexture = this.VOIDIconOn; //or on if power_toggle==true - if (GUI.Button(VOIDIconPos, VOIDIconTexture, new GUIStyle()) && this.VOIDIconLocked) - { - this.mainGuiMinimized.value = !this.mainGuiMinimized; - } + this.LoadGUIStyles(); + } + + if (!this.UseToolbarManager) + { + if (this.AppLauncherButton == null) + { + this.InitializeAppLauncherButton(); + } + } + else if (this.ToolbarButton == null) + { + this.InitializeToolbarButton(); } if (!this.mainGuiMinimized) { + Rect _mainWindowPos = this.mainWindowPos; - _mainWindowPos = GUILayout.Window ( + _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); + VOID_Tools.GetWindowHandler(this.VOIDMainWindow), + string.Join(" ", new string[] { this.VoidName, this.VoidVersion }), + GUILayout.Width(250), + GUILayout.Height(50) + ); + + _mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos); if (_mainWindowPos != this.mainWindowPos) { @@ -692,16 +431,16 @@ { Rect _configWindowPos = this.configWindowPos; - _configWindowPos = GUILayout.Window ( + _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); + VOID_Tools.GetWindowHandler(this.VOIDConfigWindow), + string.Join(" ", new string[] { this.VoidName, "Configuration" }), + GUILayout.Width(250), + GUILayout.Height(50) + ); + + _configWindowPos = Tools.ClampRectToScreen(_configWindowPos); if (_configWindowPos != this.configWindowPos) { @@ -710,7 +449,7 @@ } } - public void OnGUI() + public virtual void OnGUI() { if (Event.current.type == EventType.Repaint) { @@ -735,8 +474,7 @@ if (!this.VOIDIconLocked && VOIDIconPos.value.Contains(Event.current.mousePosition) - && Event.current.type == EventType.mouseDrag - ) + && Event.current.type == EventType.mouseDrag) { Tools.PostDebugMessage(string.Format( "Event.current.type: {0}" + @@ -765,38 +503,36 @@ } } - public void Update() - { - this.LoadBeforeUpdate (); - - if (this.vessel != null) - { - SimManager.Instance.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / - Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2); - SimManager.Instance.TryStartSimulation(); + public virtual void Update() + { + this.LoadBeforeUpdate(); + + if (this.vessel != null && this.vesselSimActive) + { + Tools.PostDebugMessage(this, "Updating SimManager."); + this.UpdateSimManager(); } if (!this.guiRunning) { - this.StartGUI (); + this.StartGUI(); } if (!HighLogic.LoadedSceneIsFlight && this.guiRunning) { - this.StopGUI (); + this.StopGUI(); } foreach (IVOID_Module module in this.Modules) { if (!module.guiRunning && module.toggleActive) { - module.StartGUI (); + module.StartGUI(); } if (module.guiRunning && !module.toggleActive || !this.togglePower || !HighLogic.LoadedSceneIsFlight || - this.factoryReset - ) + this.factoryReset) { module.StopGUI(); } @@ -807,26 +543,36 @@ } } - this.CheckAndSave (); + this.CheckAndSave(); this._updateTimer += Time.deltaTime; } - public void FixedUpdate() - { - if (this.consumeResource && + 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); + TimeWarp.deltaTime != 0) + { + float powerReceived = this.vessel.rootPart.RequestResource( + this.resourceName, + this.resourceRate * TimeWarp.fixedDeltaTime + ); + if (powerReceived > 0) { - this.powerAvailable = true; + newPowerState = true; } else { - this.powerAvailable = false; + newPowerState = false; + } + + if (this.powerAvailable != newPowerState) + { + this.powerAvailable = newPowerState; + this.SetIconTexture(this.powerState | this.activeState); } } @@ -839,15 +585,442 @@ public void ResetGUI() { - this.StopGUI (); + this.StopGUI(); foreach (IVOID_Module module in this.Modules) { - module.StopGUI (); - module.StartGUI (); - } - - this.StartGUI (); + module.StopGUI(); + module.StartGUI(); + } + + this.StartGUI(); + } + + public void VOIDMainWindow(int _) + { + GUILayout.BeginVertical(); + + if (this.powerAvailable || HighLogic.LoadedSceneIsEditor) + { + if (!HighLogic.LoadedSceneIsEditor) + { + string str = string.Intern("ON"); + if (togglePower) + str = string.Intern("OFF"); + if (GUILayout.Button("Power " + str)) + { + togglePower.value = !togglePower; + this.SetIconTexture(this.powerState | this.activeState); + } + } + + if (togglePower || HighLogic.LoadedSceneIsEditor) + { + foreach (IVOID_Module module in this.Modules) + { + module.toggleActive = GUILayout.Toggle(module.toggleActive, module.Name); + } + } + } + else + { + GUILayout.Label("-- POWER LOST --", this.LabelStyles["red"]); + } + + this.configWindowMinimized.value = !GUILayout.Toggle(!this.configWindowMinimized, "Configuration"); + + GUILayout.EndVertical(); + GUI.DragWindow(); + } + + public void VOIDConfigWindow(int _) + { + GUILayout.BeginVertical(); + + this.DrawConfigurables(); + + GUILayout.EndVertical(); + GUI.DragWindow(); + } + + public override void DrawConfigurables() + { + GUIContent _content; + + if (HighLogic.LoadedSceneIsFlight) + { + this.consumeResource.value = GUILayout.Toggle(this.consumeResource, "Consume Resources"); + + this.VOIDIconLocked = GUILayout.Toggle(this.VOIDIconLocked, "Lock Icon Position"); + } + + this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available"); + + this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value, + "Enable Engineering Calculations"); + + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); + + _content = new GUIContent(); + + _content.text = "◄"; + _content.tooltip = "Select previous skin"; + if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) + { + this.GUIStylesLoaded = false; + this._skinIdx--; + Tools.PostDebugMessage(string.Format( + "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", + this.GetType().Name, + this._skinName, + this.validSkins.Count + )); + } + + _content.text = this.Skin.name; + _content.tooltip = "Current skin"; + GUILayout.Label(_content, this.LabelStyles["center"], GUILayout.ExpandWidth(true)); + + _content.text = "►"; + _content.tooltip = "Select next skin"; + if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) + { + this.GUIStylesLoaded = false; + this._skinIdx++; + Tools.PostDebugMessage(string.Format( + "{0}: new this._skinIdx = {1} :: skin_list.Count = {2}", + this.GetType().Name, + this._skinName, + this.validSkins.Count + )); + } + + this._skinIdx %= this.skinNames.Length; + if (this._skinIdx < 0) + { + this._skinIdx += this.skinNames.Length; + } + + if (this._skinName != skinNames[this._skinIdx]) + { + this._skinName.value = skinNames[this._skinIdx]; + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Update Rate (Hz):"); + if (this.stringFrequency == null) + { + this.stringFrequency = (1f / this.updatePeriod).ToString(); + } + this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true)); + // GUILayout.FlexibleSpace(); + if (GUILayout.Button("Apply")) + { + double updateFreq = 1f / this.updatePeriod; + double.TryParse(stringFrequency, out updateFreq); + this._updatePeriod = 1 / updateFreq; + } + GUILayout.EndHorizontal(); + + foreach (IVOID_Module mod in this.Modules) + { + mod.DrawConfigurables(); + } + + this._factoryReset = GUILayout.Toggle(this._factoryReset, "Factory Reset"); + } + + protected void 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>() + { + var types = AssemblyLoader.loadedAssemblies + .Select(a => a.assembly.GetExportedTypes()) + .SelectMany(t => t) + .Where(v => typeof(T).IsAssignableFrom(v) + && !(v.IsInterface || v.IsAbstract) && + !typeof(VOID_Core).IsAssignableFrom(v) + ); + + Tools.PostDebugMessage(string.Format( + "{0}: Found {1} modules to check.", + this.GetType().Name, + types.Count() + )); + foreach (var voidType in types) + { + if (!HighLogic.LoadedSceneIsEditor && + typeof(IVOID_EditorModule).IsAssignableFrom(voidType)) + { + continue; + } + + Tools.PostDebugMessage(string.Format( + "{0}: found Type {1}", + this.GetType().Name, + voidType.Name + )); + + this.LoadModule(voidType); + } + + this._modulesLoaded = true; + + Tools.PostDebugMessage(string.Format( + "{0}: Loaded {1} modules.", + this.GetType().Name, + this.Modules.Count + )); + } + + protected void LoadModule(Type T) + { + var existingModules = this._modules.Where(mod => mod.GetType().Name == T.Name); + if (existingModules.Any()) + { + Tools.PostDebugMessage(string.Format( + "{0}: refusing to load {1}: already loaded", + this.GetType().Name, + T.Name + )); + return; + } + IVOID_Module module = Activator.CreateInstance(T) as IVOID_Module; + module.LoadConfig(); + this._modules.Add(module); + + Tools.PostDebugMessage(string.Format( + "{0}: loaded module {1}.", + this.GetType().Name, + T.Name + )); + } + + protected void LoadSkins() + { + Tools.PostDebugMessage("AssetBase has skins: \n" + + string.Join("\n\t", + Resources.FindObjectsOfTypeAll(typeof(GUISkin)) + .Select(s => s.ToString()) + .ToArray() + ) + ); + + this.validSkins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)) + .Where(s => !this.forbiddenSkins.Contains(s.name)) + .Select(s => s as GUISkin) + .GroupBy(s => s.name) + .Select(g => g.First()) + .ToDictionary(s => s.name); + + Tools.PostDebugMessage(string.Format( + "{0}: loaded {1} GUISkins.", + this.GetType().Name, + this.validSkins.Count + )); + + this.skinNames = this.validSkins.Keys.ToArray(); + Array.Sort(this.skinNames); + + int defaultIdx = int.MinValue; + + for (int i = 0; i < this.skinNames.Length; i++) + { + if (this.skinNames[i] == this._skinName) + { + this._skinIdx = i; + } + if (this.skinNames[i] == this.defaultSkin) + { + defaultIdx = i; + } + if (this._skinIdx != int.MinValue && defaultIdx != int.MinValue) + { + break; + } + } + + if (this._skinIdx == int.MinValue) + { + this._skinIdx = defaultIdx; + } + + Tools.PostDebugMessage(string.Format( + "{0}: _skinIdx = {1}.", + this.GetType().Name, + this._skinName.ToString() + )); + + this.skinsLoaded = true; + } + + protected void LoadGUIStyles() + { + this.LabelStyles["link"] = new GUIStyle(GUI.skin.label); + this.LabelStyles["link"].fontStyle = FontStyle.Bold; + + this.LabelStyles["center"] = new GUIStyle(GUI.skin.label); + this.LabelStyles["center"].normal.textColor = Color.white; + this.LabelStyles["center"].alignment = TextAnchor.UpperCenter; + + this.LabelStyles["center_bold"] = new GUIStyle(GUI.skin.label); + this.LabelStyles["center_bold"].normal.textColor = Color.white; + this.LabelStyles["center_bold"].alignment = TextAnchor.UpperCenter; + this.LabelStyles["center_bold"].fontStyle = FontStyle.Bold; + + this.LabelStyles["right"] = new GUIStyle(GUI.skin.label); + this.LabelStyles["right"].normal.textColor = Color.white; + this.LabelStyles["right"].alignment = TextAnchor.UpperRight; + + this.LabelStyles["red"] = new GUIStyle(GUI.skin.label); + this.LabelStyles["red"].normal.textColor = Color.red; + this.LabelStyles["red"].alignment = TextAnchor.MiddleCenter; + + this.iconStyle = new GUIStyle(GUI.skin.button); + this.iconStyle.padding = new RectOffset(0, 0, 0, 0); + // this.iconStyle.margin = new RectOffset(0, 0, 0, 0); + // this.iconStyle.contentOffset = new Vector2(0, 0); + this.iconStyle.overflow = new RectOffset(0, 0, 0, 0); + // this.iconStyle.border = new RectOffset(0, 0, 0, 0); + + this.GUIStylesLoaded = true; + } + + protected void LoadVesselTypes() + { + this._allVesselTypes = Enum.GetValues(typeof(VesselType)).OfType<VesselType>().ToList(); + this.vesselTypesLoaded = true; + } + + protected void LoadBeforeUpdate() + { + if (!this.vesselTypesLoaded) + { + this.LoadVesselTypes(); + } + } + + protected void InitializeToolbarButton() + { + // Do nothing if (the Toolbar is not available. + if (!ToolbarManager.ToolbarAvailable) + { + return; + } + + this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); + this.ToolbarButton.Text = this.VoidName; + this.SetIconTexture(this.powerState | this.activeState); + + this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH); + + this.ToolbarButton.OnClick += + (e) => + { + this.ToggleMainWindow(); + }; + + Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); + } + + protected void InitializeAppLauncherButton() + { + if (ApplicationLauncher.Ready) + { + this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( + this.ToggleMainWindow, this.ToggleMainWindow, + this.appIconVisibleScenes, + this.VOIDIconTexture + ); + + Tools.PostDebugMessage( + this, + "AppLauncherButton initialized in {0}", + Enum.GetName( + typeof(GameScenes), + HighLogic.LoadedScene + ) + ); + } + } + + protected void ToggleMainWindow() + { + this.mainGuiMinimized = !this.mainGuiMinimized; + this.SetIconTexture(this.powerState | this.activeState); + } + + protected void SetIconTexture(IconState state) + { + switch (state) + { + case (IconState.PowerOff | IconState.Inactive): + this.SetIconTexture(this.VOIDIconOffInactivePath); + break; + case (IconState.PowerOff | IconState.Active): + this.SetIconTexture(this.VOIDIconOffActivePath); + break; + case (IconState.PowerOn | IconState.Inactive): + this.SetIconTexture(this.VOIDIconOnInactivePath); + break; + case (IconState.PowerOn | IconState.Active): + this.SetIconTexture(this.VOIDIconOnActivePath); + break; + default: + throw new NotImplementedException(); + } + } + + protected void SetIconTexture(string texturePath) + { + if (this.ToolbarButton != null) + { + this.ToolbarButton.TexturePath = texturePath; + } + + this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false); + + if (this.AppLauncherButton != null) + { + this.AppLauncherButton.SetTexture(VOIDIconTexture); + } } protected void CheckAndSave() @@ -861,43 +1034,125 @@ return; } - Tools.PostDebugMessage (string.Format ( + Tools.PostDebugMessage(string.Format( "{0}: Time to save, checking if configDirty: {1}", - this.GetType ().Name, + this.GetType().Name, this.configDirty - )); - - this.SaveConfig (); + )); + + this.SaveConfig(); this.saveTimer = 0; } } public override void LoadConfig() { - base.LoadConfig (); + base.LoadConfig(); foreach (IVOID_Module module in this.Modules) { - module.LoadConfig (); + module.LoadConfig(); } } public void SaveConfig() { - var config = KSP.IO.PluginConfiguration.CreateForType<VOID_Core> (); - config.load (); + var config = KSP.IO.PluginConfiguration.CreateForType<VOID_Core>(); + config.load(); this._SaveToConfig(config); foreach (IVOID_Module module in this.Modules) { - module._SaveToConfig (config); + module._SaveToConfig(config); } config.save(); this.configDirty = false; } + + protected VOID_Core() + { + this._Name = "VOID Core"; + + System.Version version = this.GetType().Assembly.GetName().Version; + + this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision); + + this.toggleActive = true; + + this._skinName = this.defaultSkin; + this._skinIdx = int.MinValue; + + this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_light_glow"; + this.VOIDIconOnActivePath = "VOID/Textures/void_icon_dark_glow"; + this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_light"; + this.VOIDIconOffActivePath = "VOID/Textures/void_icon_dark"; + + this.vesselSimActive = true; + + this.UseToolbarManager = false; + + this.LoadConfig(); + + this.SetIconTexture(this.powerState | this.activeState); + } + + 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 + { + PowerOff = 1, + PowerOn = 2, + Inactive = 4, + Active = 8 + } + } + + public static partial class VOID_Data + { + public static VOID_Core core + { + get + { + if (HighLogic.LoadedSceneIsEditor) + { + return VOID_EditorCore.Instance; + } + else + { + return VOID_Core.Instance; + } + } + } + + public static double KerbinGee + { + get + { + if (kerbinGee == default(double)) + { + kerbinGee = core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius); + } + + return kerbinGee; + } + } + + private static double kerbinGee; } }