Major changes to the way VOID_Core was implemented to allow a more-extensible core framework for use in multiple scenes.
Major changes to the way VOID_Core was implemented to allow a more-extensible core framework for use in multiple scenes.

* text=auto * text=auto
* eol=lf * 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
   
  ACTIVE_TEXTURE_MANAGER_CONFIG
  {
  folder = VOID
  enabled = true
  OVERRIDES
  {
  VOID/.*
  {
  compress = true
  mipmaps = false
  scale = 1
  max_size = 0
  }
  }
  }
 
 Binary files /dev/null and b/GameData/VOID/Textures/fundsgreen.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/fundsred.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/repgreen.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/repred.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/science.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_dark.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_dark_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_light.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_light_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_dark.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_dark_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_light.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_light_glow.png differ
// VOID // VOID
// //
// IVOID_Module.cs // IVOID_Module.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using System; using System;
   
namespace VOID namespace VOID
{ {
public interface IVOID_Module public interface IVOID_Module
{ {
string Name { get; } string Name { get; }
bool toggleActive { get; set; } bool toggleActive { get; set; }
bool guiRunning { get; } bool guiRunning { get; }
  bool inValidScene { get; }
   
void DrawGUI(); void DrawGUI();
void StartGUI(); void StartGUI();
void StopGUI(); void StopGUI();
   
void DrawConfigurables(); void DrawConfigurables();
   
void LoadConfig(); void LoadConfig();
   
void _SaveToConfig(KSP.IO.PluginConfiguration config); void _SaveToConfig(KSP.IO.PluginConfiguration config);
} }
   
public interface IVOID_BehaviorModule : IVOID_Module public interface IVOID_BehaviorModule : IVOID_Module
{ {
void Update(); void Update();
void FixedUpdate(); void FixedUpdate();
  void OnDestroy();
} }
   
public interface IVOID_EditorModule : IVOID_Module {}  
} }
   
// VOID // VOID
// //
// AssemblyInfo.cs // AssemblyInfo.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
   
[assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)] [assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)]
[assembly: KSPAssemblyDependency("VesselSimulator", 0, 0)] [assembly: KSPAssemblyDependency("VesselSimulator", 0, 0)]
   
// Information about this assembly is defined by the following attributes. // Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project. // Change them to the values specific to your project.
[assembly: AssemblyTitle("VOID")] [assembly: AssemblyTitle("VOID")]
[assembly: AssemblyDescription("A KSP mod that provides at-a-glance information about Vessels, Orbits, and their states.")] [assembly: AssemblyDescription("A KSP mod that provides at-a-glance information about Vessels, Orbits, and their states.")]
[assembly: AssemblyCopyright("toadicus")] [assembly: AssemblyCopyright("toadicus")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision, // The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision. // and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.14.3.*")] [assembly: AssemblyVersion("0.16.4.*")]
// The following attributes are used to specify the signing key for the assembly, // The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing. // if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")] //[assembly: AssemblyKeyFile("")]
   
   
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid> <ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>VOID</RootNamespace> <RootNamespace>VOID</RootNamespace>
<AssemblyName>VOID</AssemblyName> <AssemblyName>VOID</AssemblyName>
<CodePage>65001</CodePage> <CodePage>65001</CodePage>
<UseMSBuildEngine>False</UseMSBuildEngine> <UseMSBuildEngine>False</UseMSBuildEngine>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ReleaseVersion>0.11</ReleaseVersion> <ReleaseVersion>0.11</ReleaseVersion>
<SynchReleaseVersion>false</SynchReleaseVersion> <SynchReleaseVersion>false</SynchReleaseVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG; TRACE</DefineConstants> <DefineConstants>DEBUG; TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="xcopy /Y ${TargetFile} ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" /> <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' ">
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="xcopy /Y ${TargetFile} ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" /> <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG; TRACE</DefineConstants> <DefineConstants>DEBUG; TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="cp -afv ${TargetFile} /opt/games/KSP_linux/GameData/${ProjectName}/Plugins/" /> <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' ">
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<CustomCommands> <CustomCommands>
<CustomCommands> <CustomCommands>
<Command type="AfterBuild" command="cp -afv ${TargetFile} /opt/games/KSP_linux/GameData/${ProjectName}/Plugins/" /> <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Compile Include="IVOID_Module.cs" /> <Compile Include="IVOID_Module.cs" />
<Compile Include="VOIDFlightMaster.cs" />  
<Compile Include="VOID_Core.cs" />  
<Compile Include="VOID_Module.cs" /> <Compile Include="VOID_Module.cs" />
<Compile Include="VOID_HUD.cs" /> <Compile Include="VOID_HUD.cs" />
<Compile Include="VOID_SaveValue.cs" /> <Compile Include="VOID_SaveValue.cs" />
<Compile Include="VOID_Orbital.cs" /> <Compile Include="VOID_Orbital.cs" />
<Compile Include="VOID_SurfAtmo.cs" /> <Compile Include="VOID_SurfAtmo.cs" />
<Compile Include="VOID_VesselInfo.cs" /> <Compile Include="VOID_VesselInfo.cs" />
<Compile Include="VOID_Transfer.cs" /> <Compile Include="VOID_Transfer.cs" />
<Compile Include="VOID_CBInfoBrowser.cs" /> <Compile Include="VOID_CBInfoBrowser.cs" />
<Compile Include="VOID_Rendezvous.cs" /> <Compile Include="VOID_Rendezvous.cs" />
<Compile Include="VOID_VesselRegister.cs" /> <Compile Include="VOID_VesselRegister.cs" />
<Compile Include="VOID_DataLogger.cs" /> <Compile Include="VOID_DataLogger.cs" />
<Compile Include="VOID_EditorCore.cs" />  
<Compile Include="VOID_EditorHUD.cs" /> <Compile Include="VOID_EditorHUD.cs" />
<Compile Include="VOID_DataValue.cs" /> <Compile Include="VOID_DataValue.cs" />
<Compile Include="VOIDEditorMaster.cs" />  
<Compile Include="VOID_Tools.cs" /> <Compile Include="VOID_Tools.cs" />
<Compile Include="VOID_Localization.cs" /> <Compile Include="VOID_Localization.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VOID_HUDAdvanced.cs" /> <Compile Include="VOID_HUDAdvanced.cs" />
<Compile Include="VOID_TWR.cs" /> <Compile Include="VOID_TWR.cs" />
<Compile Include="VOID_CareerStatus.cs" /> <Compile Include="VOID_CareerStatus.cs" />
<Compile Include="VOID_StageInfo.cs" /> <Compile Include="VOID_StageInfo.cs" />
<Compile Include="VOID_Styles.cs" /> <Compile Include="VOID_Styles.cs" />
<Compile Include="VOID_Data.cs" /> <Compile Include="VOID_Data.cs" />
  <Compile Include="VOID_HUDModule.cs" />
  <Compile Include="VOIDMaster.cs" />
  <Compile Include="VOIDMaster_Flight.cs" />
  <Compile Include="VOIDMaster_Editor.cs" />
  <Compile Include="VOIDMaster_SpaceCentre.cs" />
  <Compile Include="VOIDCore_SpaceCentre.cs" />
  <Compile Include="VOID_ScenesAttribute.cs" />
  <Compile Include="VOID_SingletonModule.cs" />
  <Compile Include="VOIDCore_Flight.cs" />
  <Compile Include="VOIDCore_Editor.cs" />
  <Compile Include="VOIDCore_Generic.cs" />
  <Compile Include="VOIDCore.cs" />
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>
<Properties> <Properties>
<Policies> <Policies>
<TextStylePolicy FileWidth="120" TabsToSpaces="False" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" /> <TextStylePolicy FileWidth="120" TabsToSpaces="False" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
</Policies> </Policies>
</Properties> </Properties>
</MonoDevelop> </MonoDevelop>
</ProjectExtensions> </ProjectExtensions>
<ItemGroup> <ItemGroup>
<Reference Include="System"> <Reference Include="System">
<HintPath>..\_KSPAssemblies\System.dll</HintPath> <HintPath>..\_KSPAssemblies\System.dll</HintPath>
</Reference> </Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath> <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath> <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj"> <ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj">
<Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project> <Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project>
<Name>ToadicusTools</Name> <Name>ToadicusTools</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj"> <ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj">
<Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project> <Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project>
<Name>VesselSimulator</Name> <Name>VesselSimulator</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
  <ItemGroup>
  <None Include="GameData\VOID\Textures\ATM_VOID.cfg" />
  </ItemGroup>
</Project> </Project>
   
file:b/VOIDCore.cs (new)
  // 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 UnityEngine;
 
  namespace VOID
  {
  public abstract class VOIDCore : VOID_Module, IVOID_Module
  {
  public const double Constant_G = 6.674e-11;
 
  public abstract int windowID { get; }
  public abstract bool configDirty { get; set; }
  public abstract bool powerAvailable { get; protected set; }
 
  public abstract List<IVOID_Module> Modules { get; }
 
  public abstract float updateTimer { get; protected set; }
  public abstract double updatePeriod { get; }
 
  public abstract GUISkin Skin { get; }
 
  public abstract CelestialBody HomeBody { get; }
  public abstract List<CelestialBody> allBodies { get; }
  public abstract List<CelestialBody> sortedBodyList { get; protected set; }
 
  public abstract List<VesselType> allVesselTypes { get; }
 
  public abstract Stage LastStage { get; protected set; }
  public abstract Stage[] Stages { get; protected set; }
 
  public virtual event VOIDEventHandler onApplicationQuit;
 
  public virtual void OnApplicationQuit()
  {
  if (this.onApplicationQuit != null)
  {
  this.onApplicationQuit(this);
  }
  }
  }
 
  public delegate void VOIDEventHandler(object sender);
  }
 
 
  // 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 System.Linq;
  using ToadicusTools;
  using UnityEngine;
 
  namespace VOID
  {
  public class VOIDCore_Editor : VOIDCore_Generic<VOIDCore_Editor>
  {
  protected override ApplicationLauncher.AppScenes appIconVisibleScenes
  {
  get
  {
  return ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH;
  }
  }
 
  public VOIDCore_Editor() : base()
  {
  this._Name = "VOID Editor Core";
  }
 
  public override void Update()
  {
  this.LoadBeforeUpdate();
 
  foreach (IVOID_Module module in this.Modules)
  {
  if (EditorLogic.RootPart == 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.RootPart == null || !HighLogic.LoadedSceneIsEditor)
  {
  this.StopGUI();
  return;
  }
  else if (!this.guiRunning && HighLogic.LoadedSceneIsEditor)
  {
  this.StartGUI();
  }
 
  if (EditorLogic.SortedShipList.Count > 0 && this.vesselSimActive)
  {
  Tools.PostDebugMessage(this, "Updating SimManager.");
  this.UpdateSimManager();
  }
 
  this.CheckAndSave ();
  }
 
  public override void FixedUpdate() {}
  }
  }
 
 
  // 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 System;
 
  namespace VOID
  {
  public class VOIDCore_Flight : VOIDCore_Generic<VOIDCore_Flight> {}
  }
 
 
  // VOID
  //
  // VOID_Core.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 2. Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation and/or other
  // materials provided with the distribution.
  //
  // 3. Neither the name of the copyright holder nor the names of its contributors may be used
  // to endorse or promote products derived from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using ToadicusTools;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOIDCore_Generic<T> : VOID_SingletonModule<T>, IVOID_Module, IDisposable
  where T : VOID_Module, new()
  {
  /*
  * Fields
  * */
  protected string VoidName = "VOID";
  protected string VoidVersion;
 
  protected bool _factoryReset = false;
 
  [AVOID_SaveValue("configValue")]
  protected VOID_SaveValue<int> configVersion = 1;
 
  protected List<IVOID_Module> _modules = new List<IVOID_Module>();
  protected bool _modulesLoaded = false;
 
  [AVOID_SaveValue("mainWindowPos")]
  protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f);
  [AVOID_SaveValue("mainGuiMinimized")]
  protected VOID_SaveValue<bool> mainGuiMinimized = false;
 
  [AVOID_SaveValue("configWindowPos")]
  protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f);
  [AVOID_SaveValue("configWindowMinimized")]
 
  protected VOID_SaveValue<bool> configWindowMinimized = true;
 
  protected Texture2D VOIDIconTexture;
  protected string VOIDIconOnActivePath;
  protected string VOIDIconOnInactivePath;
  protected string VOIDIconOffActivePath;
  protected string VOIDIconOffInactivePath;
 
  protected GUIStyle iconStyle;
 
  protected int windowBaseID = -96518722;
  protected int _windowID = 0;
 
  protected bool GUIStylesLoaded = false;
 
  protected CelestialBody _homeBody;
 
  [AVOID_SaveValue("togglePower")]
  public VOID_SaveValue<bool> togglePower = true;
 
  public override bool powerAvailable { get; protected set; }
 
  [AVOID_SaveValue("consumeResource")]
  protected VOID_SaveValue<bool> consumeResource = false;
 
  [AVOID_SaveValue("resourceName")]
  protected VOID_SaveValue<string> resourceName = "ElectricCharge";
 
  [AVOID_SaveValue("resourceRate")]
  protected VOID_SaveValue<float> resourceRate = 0.2f;
 
  [AVOID_SaveValue("updatePeriod")]
  protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f;
  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 int _skinIdx;
 
  protected Dictionary<string, GUISkin> validSkins;
  protected string[] skinNames;
  protected string[] forbiddenSkins =
  {
  "PlaqueDialogSkin",
  "FlagBrowserSkin",
  "SSUITextAreaDefault",
  "ExperimentsDialogSkin",
  "ExpRecoveryDialogSkin",
  "KSP window 5",
  "KSP window 6",
  "PartTooltipSkin",
  "KSCContextMenuSkin"
  };
  protected bool skinsLoaded = false;
 
  public override bool configDirty { get; set; }
 
  [AVOID_SaveValue("UseBlizzyToolbar")]
  protected VOID_SaveValue<bool> _UseToolbarManager;
  internal IButton ToolbarButton;
 
  internal ApplicationLauncherButton AppLauncherButton;
 
  /*
  * Events
  * */
 
  // event VOIDEventHandler onApplicationQuit;
  /*
  * Properties
  * */
  public bool factoryReset
  {
  get
  {
  return this._factoryReset;
  }
  }
 
  public override List<IVOID_Module> Modules
  {
  get
  {
  return this._modules;
  }
  }
 
  public override GUISkin Skin
  {
  get
  {
  if (this.skinsLoaded)
  {
  try
  {
  return this.validSkins[this._skinName];
  }
  catch
  {
  }
  }
 
  return AssetBase.GetGUISkin(this.defaultSkin);
  }
  }
 
  public override int windowID
  {
  get
  {
  if (this._windowID == 0)
  {
  this._windowID = this.windowBaseID;
  }
  return this._windowID++;
  }
  }
 
  public override List<CelestialBody> allBodies
  {
  get
  {
  return FlightGlobals.Bodies;
  }
  }
 
  public override List<CelestialBody> sortedBodyList
  {
  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 List<VesselType> allVesselTypes
  {
  get
  {
  return this._allVesselTypes;
  }
  }
 
  public override float updateTimer
  {
  get;
  protected set;
  }
 
  public override double updatePeriod
  {
  get
  {
  return this._updatePeriod;
  }
  }
 
  public override Stage[] Stages
  {
  get;
  protected set;
  }
 
  public override 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 & ToolbarManager.ToolbarAvailable;
  }
  set
  {
  if (this._UseToolbarManager == value)
  {
  return;
  }
 
  if (value == false && this.ToolbarButton != null)
  {
  this.ToolbarButton.Destroy();
  this.ToolbarButton = null;
  }
  if (value == true)
  {
  if (this.AppLauncherButton != null)
  {
  ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
  this.AppLauncherButton = null;
  }
 
  this.InitializeToolbarButton();
  }
 
  _UseToolbarManager.value = value;
  }
  }
 
  protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes
  {
  get
  {
  return HighLogic.LoadedScene.ToAppScenes();
  }
  }
 
  /*
  * Methods
  * */
  public override void DrawGUI()
  {
  this._windowID = this.windowBaseID;
 
  if (!this._modulesLoaded)
  {
  this.LoadModulesOfType<IVOID_Module>();
  }
 
  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.UseToolbarManager)
  {
  if (this.AppLauncherButton == null)
  {
  Tools.PostDebugMessage(this,
  "UseToolbarManager = false (ToolbarAvailable = {0}) and " +
  "AppLauncherButton is null, making AppLauncher button.",
  ToolbarManager.ToolbarAvailable
  );
  this.InitializeAppLauncherButton();
  }
  }
  else if (this.ToolbarButton == null)
  {
  Tools.PostDebugMessage(this,
  "UseToolbarManager = true (ToolbarAvailable = {0}) and " +
  "ToolbarButton is null, making Toolbar button.",
  ToolbarManager.ToolbarAvailable
  );
  this.InitializeToolbarButton();
  }
 
  if (!this.mainGuiMinimized)
  {
 
  Rect _mainWindowPos = this.mainWindowPos;
 
  _mainWindowPos = GUILayout.Window(
  this.windowID,
  _mainWindowPos,
  VOID_Tools.GetWindowHandler(this.VOIDMainWindow),
  string.Join(" ", new string[] { this.VoidName, this.VoidVersion }),
  GUILayout.Width(250),
  GUILayout.Height(50)
  );
 
  if (HighLogic.LoadedSceneIsEditor)
  {
  _mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);
  }
  else
  {
  _mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
  }
 
  if (_mainWindowPos != this.mainWindowPos)
  {
  this.mainWindowPos = _mainWindowPos;
  }
  }
 
  if (!this.configWindowMinimized && !this.mainGuiMinimized)
  {
  Rect _configWindowPos = this.configWindowPos;
 
  _configWindowPos = GUILayout.Window(
  this.windowID,
  _configWindowPos,
  VOID_Tools.GetWindowHandler(this.VOIDConfigWindow),
  string.Join(" ", new string[] { this.VoidName, "Configuration" }),
  GUILayout.Width(250),
  GUILayout.Height(50)
  );
 
  if (HighLogic.LoadedSceneIsEditor)
  {
  _configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);
  }
  else
  {
  _configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
  }
 
  if (_configWindowPos != this.configWindowPos)
  {
  this.configWindowPos = _configWindowPos;
  }
  }
  }
 
  public virtual void OnGUI()
  {
  }
 
  public virtual void Update()
  {
  this.LoadBeforeUpdate();
 
  if (this.vessel != null && this.vesselSimActive)
  {
  Tools.PostDebugMessage(this, "Updating SimManager.");
  this.UpdateSimManager();
  }
 
  if (!this.guiRunning)
  {
  this.StartGUI();
  }
 
  foreach (IVOID_Module module in this.Modules)
  {
  if (!module.guiRunning && module.toggleActive)
  {
  module.StartGUI();
  }
  if (module.guiRunning && !module.toggleActive ||
  !this.togglePower ||
  !module.inValidScene ||
  this.factoryReset)
  {
  module.StopGUI();
  }
 
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).Update();
  }
  }
 
  this.CheckAndSave();
  this.updateTimer += Time.deltaTime;
  }
 
  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;
  this.SetIconTexture(this.powerState | this.activeState);
  }
  }
 
  foreach (IVOID_Module module in this.Modules)
  {
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).FixedUpdate();
  }
  }
  }
 
  public void OnDestroy()
  {
  foreach (IVOID_Module module in this.Modules)
  {
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).OnDestroy();
  }
  }
  }
 
  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 --", VOID_Styles.labelRed);
  }
 
  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.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._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.Length;
  if (this._skinIdx < 0)
  {
  this._skinIdx += this.skinNames.Length;
  }
 
  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 = 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 = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d));
 
  SimManager.TryStartSimulation();
  }
  #if DEBUG
  else
  {
  Tools.PostDebugMessage(this, "VesselSimulator results not ready.");
  }
  #endif
  }
 
  protected void LoadModulesOfType<U>()
  {
  Tools.DebugLogger sb = Tools.DebugLogger.New(this);
  sb.AppendLine("Loading modules...");
 
  foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies)
  {
  foreach (Type loadedType in assy.assembly.GetExportedTypes())
  {
  if (
  loadedType.IsInterface ||
  loadedType.IsAbstract ||
  !typeof(U).IsAssignableFrom(loadedType) ||
  typeof(VOIDCore).IsAssignableFrom(loadedType)
  )
  {
  continue;
  }
 
  sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name);
 
  GameScenes[] validScenes = null;
 
  foreach (var attr in loadedType.GetCustomAttributes(true))
  {
  if (attr is VOID_ScenesAttribute)
  {
  validScenes = ((VOID_ScenesAttribute)attr).ValidScenes;
 
  sb.Append("VOID_ScenesAttribute found;");
 
  break;
  }
  }
 
  if (validScenes == null)
  {
  validScenes = new GameScenes[] { GameScenes.FLIGHT };
 
 
  sb.Append("VOID_ScenesAttribute not found;");
 
  }
 
  sb.AppendFormat(
  " validScenes set to {0}.",
  string.Join(
  ", ",
  validScenes.Select(s => Enum.GetName(typeof(GameScenes), s)).ToArray()
  )
  );
 
  if (!validScenes.Contains(HighLogic.LoadedScene))
  {
  sb.AppendFormat(" {0} not found in validScenes, skipping.",
  Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene));
  continue;
  }
 
  sb.AppendFormat("Loading IVOID_Module type {0}...", loadedType.Name);
 
  try
  {
  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())
  {
  Tools.PostDebugMessage(string.Format(
  "{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
  );
 
  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;
  }
 
  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()
  {
  VOID_Styles.OnSkinChanged();
 
  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();
  }
 
  if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
  {
  this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
  this.sortedBodyList.Sort(new CBListComparer());
  this.sortedBodyList.Reverse();
 
  Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
  }
 
  }
 
  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.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT);
 
  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()
  {
  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<T>();
  config.load();
 
  this._SaveToConfig(config);
 
  foreach (IVOID_Module module in this.Modules)
  {
  module._SaveToConfig(config);
  }
 
  config.save();
 
  this.configDirty = false;
  }
 
  public VOIDCore_Generic()
  {
  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.powerAvailable = true;
 
  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 = ToolbarManager.ToolbarAvailable;
 
  this.LoadConfig();
 
  this.SetIconTexture(this.powerState | this.activeState);
  }
 
  public virtual void Dispose()
  {
  this.StopGUI();
 
  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;
  }
 
  protected enum IconState
  {
  PowerOff = 1,
  PowerOn = 2,
  Inactive = 4,
  Active = 8
  }
  }
  }
 
 
  // 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
  {
  public class VOIDCore_SpaceCentre : VOIDCore_Generic<VOIDCore_SpaceCentre>
  {
  #region Static Members
  protected new static bool _initialized = false;
  public new static bool Initialized
  {
  get
  {
  return _initialized;
  }
  }
 
  protected new static VOIDCore_SpaceCentre _instance;
  public new static VOIDCore_SpaceCentre Instance
  {
  get
  {
  if (_instance == null)
  {
  _instance = new VOIDCore_SpaceCentre();
  _initialized = true;
  }
  return _instance;
  }
  }
  #endregion
  }
  }
 
 
file:a/VOIDEditorMaster.cs (deleted)
// VOID  
//  
// VOIDEditorMaster.cs  
//  
// Copyright © 2014, toadicus  
// All rights reserved.  
//  
// Redistribution and use in source and binary forms, with or without modification,  
// are permitted provided that the following conditions are met:  
//  
// 1. Redistributions of source code must retain the above copyright notice,  
// this list of conditions and the following disclaimer.  
//  
// 2. Redistributions in binary form must reproduce the above copyright notice,  
// this list of conditions and the following disclaimer in the documentation and/or other  
// materials provided with the distribution.  
//  
// 3. Neither the name of the copyright holder nor the names of its contributors may be used  
// to endorse or promote products derived from this software without specific prior written permission.  
//  
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors  
// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some  
// invaluable functions and making your nicely written code available to learn from.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.  
// Engineer Redux (c) 2013 cybutek  
// Used by permission.  
//  
///////////////////////////////////////////////////////////////////////////////  
 
using Engineer.VesselSimulator;  
using KSP;  
using System;  
using ToadicusTools;  
using UnityEngine;  
 
namespace VOID  
{  
[KSPAddon(KSPAddon.Startup.EditorAny, false)]  
public class VOIDEditorMaster : MonoBehaviour  
{  
protected VOID_EditorCore Core;  
 
public void Awake()  
{  
Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");  
this.Core = VOID_EditorCore.Instance;  
this.Core.ResetGUI ();  
Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");  
}  
 
public void Update()  
{  
if (!HighLogic.LoadedSceneIsEditor && this.Core != null)  
{  
this.Core.SaveConfig ();  
this.Core = null;  
VOID_EditorCore.Reset();  
return;  
}  
 
if (this.Core == null)  
{  
this.Awake();  
}  
 
this.Core.Update ();  
 
if (this.Core.factoryReset)  
{  
KSP.IO.File.Delete<VOID_EditorCore>("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();  
}  
}  
}  
 
file:a/VOIDFlightMaster.cs (deleted)
// VOID  
//  
// VOIDFlightMaster.cs  
//  
// Copyright © 2014, toadicus  
// All rights reserved.  
//  
// Redistribution and use in source and binary forms, with or without modification,  
// are permitted provided that the following conditions are met:  
//  
// 1. Redistributions of source code must retain the above copyright notice,  
// this list of conditions and the following disclaimer.  
//  
// 2. Redistributions in binary form must reproduce the above copyright notice,  
// this list of conditions and the following disclaimer in the documentation and/or other  
// materials provided with the distribution.  
//  
// 3. Neither the name of the copyright holder nor the names of its contributors may be used  
// to endorse or promote products derived from this software without specific prior written permission.  
//  
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors  
// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some  
// invaluable functions and making your nicely written code available to learn from.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.  
// Engineer Redux (c) 2013 cybutek  
// Used by permission.  
//  
///////////////////////////////////////////////////////////////////////////////  
 
using System;  
using UnityEngine;  
using Engineer.VesselSimulator;  
using ToadicusTools;  
 
namespace VOID  
{  
[KSPAddon(KSPAddon.Startup.Flight, false)]  
public class VOIDFlightMaster : MonoBehaviour  
{  
protected VOID_Core Core;  
 
public void Awake()  
{  
Tools.PostDebugMessage ("VOIDFlightMaster: Waking up.");  
this.Core = (VOID_Core)VOID_Core.Instance;  
this.Core.ResetGUI ();  
Tools.PostDebugMessage ("VOIDFlightMaster: Awake.");  
}  
 
public void Update()  
{  
if (!HighLogic.LoadedSceneIsFlight && this.Core != null)  
{  
this.Core.SaveConfig ();  
this.Core = null;  
VOID_Core.Reset();  
return;  
}  
 
if (this.Core == null)  
{  
this.Awake();  
}  
 
this.Core.Update ();  
 
if (this.Core.factoryReset)  
{  
KSP.IO.File.Delete<VOID_Core>("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();  
}  
}  
}  
 
file:b/VOIDMaster.cs (new)
  // 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<T> : MonoBehaviour
  where T : VOIDCore_Generic<T>, 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<T>("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()
  {
  foreach (var attr in this.GetType().GetCustomAttributes(true))
  {
  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;
  }
  }
  }
 
  // 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<VOIDCore_Editor>
  {
  public override void Awake()
  {
  Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");
  this.Core = VOIDCore_Editor.Instance;
  this.Core.ResetGUI ();
  Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");
  }
  }
  }
 
  // 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<VOIDCore_Flight>
  {
  public override void Awake()
  {
  this.LogDebug("Waking up.");
  this.Core = VOIDCore_Flight.Instance;
  this.Core.ResetGUI ();
  this.LogDebug("Awake.");
  }
  }
  }
 
  // 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<VOIDCore_SpaceCentre>
  {
  public override void Awake()
  {
  this.LogDebug("Waking up.");
  this.Core = VOIDCore_SpaceCentre.Instance;
  this.Core.ResetGUI ();
  this.LogDebug("Awake.");
  }
  }
  }
 
// VOID // VOID
// //
// VOID_CBInfoBrowser.cs // VOID_CBInfoBrowser.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_CBInfoBrowser : VOID_WindowModule public class VOID_CBInfoBrowser : VOID_WindowModule
{ {
[AVOID_SaveValue("selectedBodyIdx1")] [AVOID_SaveValue("selectedBodyIdx1")]
protected VOID_SaveValue<int> selectedBodyIdx1 = 1; protected VOID_SaveValue<int> selectedBodyIdx1 = 1;
   
[AVOID_SaveValue("selectedBodyIdx2")] [AVOID_SaveValue("selectedBodyIdx2")]
protected VOID_SaveValue<int> selectedBodyIdx2 = 2; protected VOID_SaveValue<int> selectedBodyIdx2 = 2;
   
protected CelestialBody selectedBody1; protected CelestialBody selectedBody1;
protected CelestialBody selectedBody2; protected CelestialBody selectedBody2;
   
[AVOID_SaveValue("toggleOrbital")] [AVOID_SaveValue("toggleOrbital")]
protected VOID_SaveValue<bool> toggleOrbital = false; protected VOID_SaveValue<bool> toggleOrbital = false;
   
[AVOID_SaveValue("togglePhysical")] [AVOID_SaveValue("togglePhysical")]
protected VOID_SaveValue<bool> togglePhysical = false; protected VOID_SaveValue<bool> togglePhysical = false;
   
[AVOID_SaveValue("toggleScience")] [AVOID_SaveValue("toggleScience")]
protected VOID_SaveValue<bool> toggleScience = false; protected VOID_SaveValue<bool> toggleScience = false;
   
public VOID_CBInfoBrowser() public VOID_CBInfoBrowser()
{ {
this._Name = "Celestial Body Information Browser"; this._Name = "Celestial Body Information Browser";
   
this.WindowPos.x = 10; this.WindowPos.x = 10;
this.WindowPos.y = 85; this.WindowPos.y = 85;
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int _)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("", GUILayout.ExpandWidth(true)); GUILayout.Label("", GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
selectedBody1 = this.core.allBodies[selectedBodyIdx1]; selectedBody1 = this.core.allBodies[selectedBodyIdx1];
selectedBody2 = this.core.allBodies[selectedBodyIdx2]; selectedBody2 = this.core.allBodies[selectedBodyIdx2];
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1--; selectedBodyIdx1--;
if (selectedBodyIdx1 < 0) selectedBodyIdx1 = this.core.allBodies.Count - 1; if (selectedBodyIdx1 < 0) selectedBodyIdx1 = this.core.allBodies.Count - 1;
} }
GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1++; selectedBodyIdx1++;
if (selectedBodyIdx1 > this.core.allBodies.Count - 1) selectedBodyIdx1 = 0; if (selectedBodyIdx1 > this.core.allBodies.Count - 1) selectedBodyIdx1 = 0;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2--; selectedBodyIdx2--;
if (selectedBodyIdx2 < 0) selectedBodyIdx2 = this.core.allBodies.Count - 1; if (selectedBodyIdx2 < 0) selectedBodyIdx2 = this.core.allBodies.Count - 1;
} }
GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2++; selectedBodyIdx2++;
if (selectedBodyIdx2 > this.core.allBodies.Count - 1) selectedBodyIdx2 = 0; if (selectedBodyIdx2 > this.core.allBodies.Count - 1) selectedBodyIdx2 = 0;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
//toggle for orbital info chunk //toggle for orbital info chunk
if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital; if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital;
   
if (toggleOrbital) if (toggleOrbital)
{ {
//begin orbital into horizontal chunk //begin orbital into horizontal chunk
//print("begin orbital info section..."); //print("begin orbital info section...");
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin orbital value labels column //begin orbital value labels column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
//print("printing row labels..."); //print("printing row labels...");
   
GUILayout.Label("Apoapsis:"); GUILayout.Label("Apoapsis:");
GUILayout.Label("Time to Ap:"); GUILayout.Label("Time to Ap:");
GUILayout.Label("Periapsis:"); GUILayout.Label("Periapsis:");
GUILayout.Label("Time to Pe:"); GUILayout.Label("Time to Pe:");
GUILayout.Label("Semi-major axis:"); GUILayout.Label("Semi-major axis:");
GUILayout.Label("Eccentricity:"); GUILayout.Label("Eccentricity:");
GUILayout.Label("Orbital period:"); GUILayout.Label("Orbital period:");
GUILayout.Label("Rotational period:"); GUILayout.Label("Rotational period:");
GUILayout.Label("Velocity:"); GUILayout.Label("Velocity:");
GUILayout.Label("Mean anomaly:"); GUILayout.Label("Mean anomaly:");
GUILayout.Label("True anomaly:"); GUILayout.Label("True anomaly:");
GUILayout.Label("Eccentric anomaly:"); GUILayout.Label("Eccentric anomaly:");
GUILayout.Label("Inclination:"); GUILayout.Label("Inclination:");
GUILayout.Label("Long. ascending node:"); GUILayout.Label("Long. ascending node:");
GUILayout.Label("Arg. of periapsis:"); GUILayout.Label("Arg. of periapsis:");
GUILayout.Label("Tidally locked:"); GUILayout.Label("Tidally locked:");
   
//end orbital value labels column //end orbital value labels column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary orbital values column //begin primary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody1); body_OP_show_orbital_info(selectedBody1);
   
//end primary orbital values column //end primary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary orbital values column //begin secondary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody2); body_OP_show_orbital_info(selectedBody2);
   
//end secondary orbital values column //end secondary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end orbital info horizontal chunk //end orbital info horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
//toggle for physical info chunk //toggle for physical info chunk
if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical; if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical;
   
if (togglePhysical) if (togglePhysical)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin physical info value label column //begin physical info value label column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
GUILayout.Label("Radius:"); GUILayout.Label("Radius:");
GUILayout.Label("Surface area:"); GUILayout.Label("Surface area:");
GUILayout.Label("Volume:"); GUILayout.Label("Volume:");
GUILayout.Label("Mass:"); GUILayout.Label("Mass:");
GUILayout.Label("Density:"); GUILayout.Label("Density:");
GUILayout.Label("Sphere of influence:"); GUILayout.Label("Sphere of influence:");
GUILayout.Label("Natural satellites:"); GUILayout.Label("Natural satellites:");
GUILayout.Label("Artificial satellites:"); GUILayout.Label("Artificial satellites:");
GUILayout.Label("Surface gravity:"); GUILayout.Label("Surface gravity:");
GUILayout.Label("Atmosphere altitude:"); GUILayout.Label("Atmosphere altitude:");
GUILayout.Label("Atmospheric O\u2082:"); GUILayout.Label("Atmospheric O\u2082:");
GUILayout.Label("Has ocean:"); GUILayout.Label("Has ocean:");
   
//end physical info value label column //end physical info value label column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary physical values column //begin primary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody1); body_OP_show_physical_info(selectedBody1);
   
//end primary physical column //end primary physical column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary physical values column //begin secondary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody2); body_OP_show_physical_info(selectedBody2);
   
//end target physical values column //end target physical values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end physical value horizontal chunk //end physical value horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true))) if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true)))
{ {
toggleScience.value = !toggleScience; toggleScience.value = !toggleScience;
} }
   
if (toggleScience) if (toggleScience)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin physical info value label column //begin physical info value label column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
   
/* /*
* public float RecoveryValue = 1f; * public float RecoveryValue = 1f;
   
public float InSpaceHighDataValue = 1f; public float InSpaceHighDataValue = 1f;
   
public float spaceAltitudeThreshold = 250000f; public float spaceAltitudeThreshold = 250000f;
   
public float flyingAltitudeThreshold = 18000f; public float flyingAltitudeThreshold = 18000f;
   
public float InSpaceLowDataValue = 1f; public float InSpaceLowDataValue = 1f;
   
public float SplashedDataValue = 1f; public float SplashedDataValue = 1f;
   
public float LandedDataValue = 1f; public float LandedDataValue = 1f;
   
public float FlyingHighDataValue = 1f; public float FlyingHighDataValue = 1f;
   
public float FlyingLowDataValue = 1f; public float FlyingLowDataValue = 1f;
*/ */
   
GUILayout.Label("Surface Multiplier:"); GUILayout.Label("Surface Multiplier:");
GUILayout.Label("Ocean Multiplier:"); GUILayout.Label("Ocean Multiplier:");
GUILayout.Label("Flying-Low Multiplier:"); GUILayout.Label("Flying-Low Multiplier:");
GUILayout.Label("Flying-High Multiplier:"); GUILayout.Label("Flying-High Multiplier:");
GUILayout.Label("Low Orbit Multiplier:"); GUILayout.Label("Low Orbit Multiplier:");
GUILayout.Label("High Orbit Multiplier:"); GUILayout.Label("High Orbit Multiplier:");
GUILayout.Label("'Flying-High' Altitude:"); GUILayout.Label("'Flying-High' Altitude:");
GUILayout.Label("'High Orbit' Altitude:"); GUILayout.Label("'High Orbit' Altitude:");
GUILayout.Label("Recovery Multiplier:"); GUILayout.Label("Recovery Multiplier:");
   
//end physical info value label column //end physical info value label column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary physical values column //begin primary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
this.cbColumnScience(selectedBody1); this.cbColumnScience(selectedBody1);
   
//end primary physical column //end primary physical column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary physical values column //begin secondary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
this.cbColumnScience(selectedBody2); this.cbColumnScience(selectedBody2);
   
//end target physical values column //end target physical values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end physical value horizontal chunk //end physical value horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUI.DragWindow(); GUI.DragWindow();
} }
   
private void body_OP_show_orbital_info(CelestialBody body) private void body_OP_show_orbital_info(CelestialBody body)
{ {
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(VOID_Tools.ConvertInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert mean anomaly into degrees. // Toadicus edit: convert mean anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert eccentric anomaly into degrees. // Toadicus edit: convert eccentric anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else else
{ {
string body_tidally_locked = "No"; string body_tidally_locked = "No";
if (body.tidallyLocked) body_tidally_locked = "Yes"; if (body.tidallyLocked) body_tidally_locked = "Yes";
GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
} }
   
private void body_OP_show_physical_info(CelestialBody body) private void body_OP_show_physical_info(CelestialBody body)
{ {
   
GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// divide by 1000 to convert m to km // divide by 1000 to convert m to km
GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI); double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI);
   
GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
//show # artificial satellites //show # artificial satellites
int num_art_sats = 0; int num_art_sats = 0;
foreach (Vessel v in FlightGlobals.Vessels) foreach (Vessel v in FlightGlobals.Vessels)
{ {
if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++; if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++;
} }
   
GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double g_ASL = (VOID_Core.Constant_G * body.Mass) / (body.Radius * body.Radius); double g_ASL = (VOIDCore.Constant_G * body.Mass) / (body.Radius * body.Radius);
   
GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.atmosphere) if (body.atmosphere)
{ {
GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
string O2 = "No"; string O2 = "No";
if (body.atmosphereContainsOxygen == true) O2 = "Yes"; if (body.atmosphereContainsOxygen == true) O2 = "Yes";
GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
else else
{ {
GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
   
string ocean = "No"; string ocean = "No";
if (body.ocean == true) ocean = "Yes"; if (body.ocean == true) ocean = "Yes";
GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true)); GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
   
private void cbColumnScience(CelestialBody body) private void cbColumnScience(CelestialBody body)
{ {
/*GUILayout.Label("Surface Science Multiplier:"); /*GUILayout.Label("Surface Science Multiplier:");
GUILayout.Label("Ocean Science Multiplier:"); GUILayout.Label("Ocean Science Multiplier:");
GUILayout.Label("Low-Atmosphere Science Multiplier:"); GUILayout.Label("Low-Atmosphere Science Multiplier:");
GUILayout.Label("High-Atmosphere Science Multiplier:"); GUILayout.Label("High-Atmosphere Science Multiplier:");
GUILayout.Label("Low Orbit Science Multiplier:"); GUILayout.Label("Low Orbit Science Multiplier:");
GUILayout.Label("High Orbit Science Multiplier:"); GUILayout.Label("High Orbit Science Multiplier:");
GUILayout.Label("'In Space' Altitude:"); GUILayout.Label("'In Space' Altitude:");
GUILayout.Label("'Flying' Altitude:"); GUILayout.Label("'Flying' Altitude:");
GUILayout.Label("Recovery Multiplier:");*/ GUILayout.Label("Recovery Multiplier:");*/
   
var scienceValues = body.scienceValues; var scienceValues = body.scienceValues;
   
GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A", body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A", body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A", body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"), GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A", body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A",
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label( GUILayout.Label(
scienceValues.spaceAltitudeThreshold.ToString("N0"), scienceValues.spaceAltitudeThreshold.ToString("N0"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"), GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"),
VOID_Styles.labelRight, VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
} }
} }
} }
// VOID // VOID
// //
// VOID_CareerStatus.cs // VOID_CareerStatus.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
  [VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)]
public class VOID_CareerStatus : VOID_WindowModule public class VOID_CareerStatus : VOID_WindowModule
{ {
public static VOID_CareerStatus Instance public static VOID_CareerStatus Instance
{ {
get; get;
private set; private set;
} }
   
public static string formatDelta(double delta) public static string formatDelta(double delta)
{ {
if (delta > 0) if (delta > 0)
{ {
return string.Format("<color='green'>{0:#,#.##}↑</color>", delta); return string.Format("<color='green'>{0:#,#.##}↑</color>", delta);
} }
else if (delta < 0) else if (delta < 0)
{ {
return string.Format("<color='red'>{0:#,#.##}↓</color>", delta); return string.Format("<color='red'>{0:#,#.##}↓</color>", delta);
} }
else else
{ {
return string.Intern("0"); return string.Intern("0");
} }
} }
   
public static string formatDelta(float delta) public static string formatDelta(float delta)
{ {
return formatDelta((double)delta); return formatDelta((double)delta);
} }
   
private GUIContent fundsContent; private GUIContent fundsContent;
private GUIContent repContent; private GUIContent repContent;
private GUIContent scienceContent; private GUIContent scienceContent;
   
  #pragma warning disable 0414
private Texture2D fundsIconGreen; private Texture2D fundsIconGreen;
private Texture2D fundsIconRed; private Texture2D fundsIconRed;
private Texture2D reputationIconGreen; private Texture2D reputationIconGreen;
private Texture2D reputationIconRed; private Texture2D reputationIconRed;
private Texture2D scienceIcon; private Texture2D scienceIcon;
  #pragma warning restore 0414
   
public override bool toggleActive public override bool toggleActive
  {
  get
  {
  return base.toggleActive && this.inValidGame;
  }
  set
  {
  base.toggleActive = this.inValidGame && value;
  }
  }
   
  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 inValidGame
{ {
get get
{ {
switch (HighLogic.CurrentGame.Mode) switch (HighLogic.CurrentGame.Mode)
{ {
case Game.Modes.CAREER: case Game.Modes.CAREER:
case Game.Modes.SCIENCE_SANDBOX: case Game.Modes.SCIENCE_SANDBOX:
return base.toggleActive; return true;
default: default:
return false; return false;
} }
} }
set }
{  
switch (HighLogic.CurrentGame.Mode) private bool currenciesInitialized
{ {
case Game.Modes.CAREER: get
case Game.Modes.SCIENCE_SANDBOX: {
base.toggleActive = value; return (
break; this.currentFunds == double.NaN ||
default: this.currentScience == float.NaN ||
return; this.currentReputation == float.NaN
} );
} }
}  
   
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;  
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int _)
{ {
  if (!this.currenciesInitialized)
  {
  this.initCurrencies();
  }
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.fundingStatus.Label); GUILayout.Label(VOID_Data.fundingStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.fundsContent.text = VOID_Data.fundingStatus.Value; this.fundsContent.text = VOID_Data.fundingStatus.Value;
GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(false)); GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.reputationStatus.Label); GUILayout.Label(VOID_Data.reputationStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.repContent.text = VOID_Data.reputationStatus.Value; this.repContent.text = VOID_Data.reputationStatus.Value;
GUILayout.Label(this.repContent, GUILayout.ExpandWidth(false)); GUILayout.Label(this.repContent, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.scienceStatus.Label); GUILayout.Label(VOID_Data.scienceStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.scienceContent.text = VOID_Data.scienceStatus.Value; this.scienceContent.text = VOID_Data.scienceStatus.Value;
GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(false)); GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUI.DragWindow(); GUI.DragWindow();
} }
   
// TODO: Update event handlers to do something useful with the new "reasons" parameter. // TODO: Update event handlers to do something useful with the new "reasons" parameter.
private void onFundsChange(double newValue, TransactionReasons reasons) private void onFundsChange(double newValue, TransactionReasons reasons)
{ {
this.lastFundsChange = newValue - this.currentFunds; this.lastFundsChange = newValue - this.currentFunds;
this.currentFunds = newValue; this.currentFunds = newValue;
} }
   
private void onRepChange(float newValue, TransactionReasons reasons) private void onRepChange(float newValue, TransactionReasons reasons)
{ {
this.lastRepChange = newValue - this.currentReputation; this.lastRepChange = newValue - this.currentReputation;
this.currentReputation = newValue; this.currentReputation = newValue;
} }
   
private void onScienceChange(float newValue, TransactionReasons reasons) private void onScienceChange(float newValue, TransactionReasons reasons)
{ {
this.lastScienceChange = newValue - this.currentScience; this.lastScienceChange = newValue - this.currentScience;
this.currentScience = newValue; this.currentScience = newValue;
  }
   
  private void initCurrencies()
  {
  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::fundsIconGreen.name: UiElements_05
* MissionRecoveryDialog::fundsIconRed.name: UiElements_06 * MissionRecoveryDialog::fundsIconRed.name: UiElements_06
* MissionRecoveryDialog::reputationIconGreen.name: UiElements_07 * MissionRecoveryDialog::reputationIconGreen.name: UiElements_07
* MissionRecoveryDialog::reputationIconRed.name: UiElements_08 * MissionRecoveryDialog::reputationIconRed.name: UiElements_08
* MissionRecoveryDialog::scienceIcon.name: UiElements_12 * MissionRecoveryDialog::scienceIcon.name: UiElements_12
* */ * */
public VOID_CareerStatus() : base() public VOID_CareerStatus() : base()
{ {
VOID_CareerStatus.Instance = this; VOID_CareerStatus.Instance = this;
   
this._Name = "Career Status"; this._Name = "Career Status";
   
GameEvents.OnFundsChanged.Add(this.onFundsChange); GameEvents.OnFundsChanged.Add(this.onFundsChange);
GameEvents.OnReputationChanged.Add(this.onRepChange); GameEvents.OnReputationChanged.Add(this.onRepChange);
GameEvents.OnScienceChanged.Add(this.onScienceChange); GameEvents.OnScienceChanged.Add(this.onScienceChange);
   
bool texturesLoaded; bool texturesLoaded;
   
texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18); texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18);
texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18); texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18);
texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18);
texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18);
texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18);
   
this.fundsContent = new GUIContent(); this.fundsContent = new GUIContent();
this.repContent = new GUIContent(); this.repContent = new GUIContent();
this.scienceContent = new GUIContent(); this.scienceContent = new GUIContent();
   
if (texturesLoaded) if (texturesLoaded)
{ {
this.fundsContent.image = this.fundsIconGreen; this.fundsContent.image = this.fundsIconGreen;
this.repContent.image = this.reputationIconGreen; this.repContent.image = this.reputationIconGreen;
this.scienceContent.image = this.scienceIcon; this.scienceContent.image = this.scienceIcon;
} }
   
this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN; this.initCurrencies();
this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN;  
this.currentScience = ResearchAndDevelopment.Instance != null ?  
ResearchAndDevelopment.Instance.Science : float.NaN;  
} }
   
~VOID_CareerStatus() ~VOID_CareerStatus()
{ {
GameEvents.OnFundsChanged.Remove(this.onFundsChange); GameEvents.OnFundsChanged.Remove(this.onFundsChange);
GameEvents.OnReputationChanged.Remove(this.onRepChange); GameEvents.OnReputationChanged.Remove(this.onRepChange);
GameEvents.OnScienceChanged.Remove(this.onScienceChange); GameEvents.OnScienceChanged.Remove(this.onScienceChange);
   
VOID_CareerStatus.Instance = null; VOID_CareerStatus.Instance = null;
} }
} }
} }
   
   
file:a/VOID_Core.cs (deleted)
// VOID  
//  
// VOID_Core.cs  
//  
// Copyright © 2014, toadicus  
// All rights reserved.  
//  
// Redistribution and use in source and binary forms, with or without modification,  
// are permitted provided that the following conditions are met:  
//  
// 1. Redistributions of source code must retain the above copyright notice,  
// this list of conditions and the following disclaimer.  
//  
// 2. Redistributions in binary form must reproduce the above copyright notice,  
// this list of conditions and the following disclaimer in the documentation and/or other  
// materials provided with the distribution.  
//  
// 3. Neither the name of the copyright holder nor the names of its contributors may be used  
// to endorse or promote products derived from this software without specific prior written permission.  
//  
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 
using Engineer.VesselSimulator;  
using KSP;  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using ToadicusTools;  
using UnityEngine;  
 
namespace VOID  
{  
public class VOID_Core : VOID_Module, IVOID_Module  
{  
#region Singleton Members  
/*  
* Static Members  
* */  
protected static bool _initialized = false;  
 
public static bool Initialized  
{  
get  
{  
return _initialized;  
}  
}  
 
protected static VOID_Core _instance;  
 
public static VOID_Core Instance  
{  
get  
{  
if (_instance == null)  
{  
_instance = new VOID_Core();  
_initialized = true;  
}  
return _instance;  
}  
}  
 
public static void Reset()  
{  
_instance.StopGUI();  
_instance.Dispose();  
_instance = null;  
_initialized = false;  
}  
#endregion  
 
public static readonly double Constant_G = 6.674e-11;  
 
/*  
* Fields  
* */  
protected string VoidName = "VOID";  
protected string VoidVersion;  
 
protected bool _factoryReset = false;  
 
[AVOID_SaveValue("configValue")]  
protected VOID_SaveValue<int> configVersion = 1;  
 
protected List<IVOID_Module> _modules = new List<IVOID_Module>();  
protected bool _modulesLoaded = false;  
 
[AVOID_SaveValue("mainWindowPos")]  
protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f);  
[AVOID_SaveValue("mainGuiMinimized")]  
protected VOID_SaveValue<bool> mainGuiMinimized = false;  
 
[AVOID_SaveValue("configWindowPos")]  
protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f);  
[AVOID_SaveValue("configWindowMinimized")]  
 
protected VOID_SaveValue<bool> configWindowMinimized = true;  
[AVOID_SaveValue("VOIDIconPos")]  
protected VOID_SaveValue<Rect> 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<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")]  
protected VOID_SaveValue<bool> consumeResource = false;  
 
[AVOID_SaveValue("resourceName")]  
protected VOID_SaveValue<string> resourceName = "ElectricCharge";  
 
[AVOID_SaveValue("resourceRate")]  
protected VOID_SaveValue<float> resourceRate = 0.2f;  
 
[AVOID_SaveValue("updatePeriod")]  
protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f;  
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 int _skinIdx;  
 
protected Dictionary<string, GUISkin> validSkins;  
protected string[] skinNames;  
protected string[] forbiddenSkins =  
{  
"PlaqueDialogSkin",  
"FlagBrowserSkin",  
"SSUITextAreaDefault",  
"ExperimentsDialogSkin",  
"ExpRecoveryDialogSkin",  
"KSP window 5",  
"KSP window 6",  
"PartTooltipSkin",  
"KSCContextMenuSkin"  
};  
protected bool skinsLoaded = false;  
 
public bool configDirty;  
 
[AVOID_SaveValue("UseBlizzyToolbar")]  
protected VOID_SaveValue<bool> _UseToolbarManager;  
internal IButton ToolbarButton;  
 
internal ApplicationLauncherButton AppLauncherButton;  
 
/*  
* Properties  
* */  
public bool factoryReset  
{  
get  
{  
return this._factoryReset;  
}  
}  
 
public List<IVOID_Module> Modules  
{  
get  
{  
return this._modules;  
}  
}  
 
public GUISkin Skin  
{  
get  
{  
if (this.skinsLoaded)  
{  
try  
{  
return this.validSkins[this._skinName];  
}  
catch  
{  
}  
}  
 
return AssetBase.GetGUISkin(this.defaultSkin);  
}  
}  
 
public int windowID  
{  
get  
{  
if (this._windowID == 0)  
{  
this._windowID = this.windowBaseID;  
}  
return this._windowID++;  
}  
}  
 
public Dictionary<string, GUIStyle> LabelStyles  
{  
get  
{  
return this._LabelStyles;  
}  
}  
 
public List<CelestialBody> allBodies  
{  
get  
{  
return FlightGlobals.Bodies;  
}  
}  
 
public List<CelestialBody> sortedBodyList  
{  
get;  
private set;  
}  
 
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<VesselType> allVesselTypes  
{  
get  
{  
return this._allVesselTypes;  
}  
}  
 
public float updateTimer  
{  
get  
{  
return this._updateTimer;  
}  
}  
 
public double updatePeriod  
{  
get  
{  
return this._updatePeriod;  
}  
}  
 
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 & ToolbarManager.ToolbarAvailable;  
}  
set  
{  
if (this._UseToolbarManager == value)  
{  
return;  
}  
 
if (value == false && this.ToolbarButton != null)  
{  
this.ToolbarButton.Destroy();  
this.ToolbarButton = null;  
}  
if (value == true)  
{  
if (this.AppLauncherButton != null)  
{  
ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);  
this.AppLauncherButton = null;  
}  
 
this.InitializeToolbarButton();  
}  
 
_UseToolbarManager.value = value;  
}  
}  
 
protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes  
{  
get  
{  
return ApplicationLauncher.AppScenes.FLIGHT;  
}  
}  
 
/*  
* Methods  
* */  
public override void DrawGUI()  
{  
this._windowID = this.windowBaseID;  
 
if (!this._modulesLoaded)  
{  
this.LoadModulesOfType<IVOID_Module>();  
}  
 
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.UseToolbarManager)  
{  
if (this.AppLauncherButton == null)  
{  
Tools.PostDebugMessage(this,  
"UseToolbarManager = false (ToolbarAvailable = {0}) and " +  
"AppLauncherButton is null, making AppLauncher button.",  
ToolbarManager.ToolbarAvailable  
);  
this.InitializeAppLauncherButton();  
}  
}  
else if (this.ToolbarButton == null)  
{  
Tools.PostDebugMessage(this,  
"UseToolbarManager = true (ToolbarAvailable = {0}) and " +  
"ToolbarButton is null, making Toolbar button.",  
ToolbarManager.ToolbarAvailable  
);  
this.InitializeToolbarButton();  
}  
 
if (!this.mainGuiMinimized)  
{  
 
Rect _mainWindowPos = this.mainWindowPos;  
 
_mainWindowPos = GUILayout.Window(  
this.windowID,  
_mainWindowPos,  
VOID_Tools.GetWindowHandler(this.VOIDMainWindow),  
string.Join(" ", new string[] { this.VoidName, this.VoidVersion }),  
GUILayout.Width(250),  
GUILayout.Height(50)  
);  
 
if (HighLogic.LoadedSceneIsEditor)  
{  
_mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);  
}  
else  
{  
_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);  
}  
 
if (_mainWindowPos != this.mainWindowPos)  
{  
this.mainWindowPos = _mainWindowPos;  
}  
}  
 
if (!this.configWindowMinimized && !this.mainGuiMinimized)  
{  
Rect _configWindowPos = this.configWindowPos;  
 
_configWindowPos = GUILayout.Window(  
this.windowID,  
_configWindowPos,  
VOID_Tools.GetWindowHandler(this.VOIDConfigWindow),  
string.Join(" ", new string[] { this.VoidName, "Configuration" }),  
GUILayout.Width(250),  
GUILayout.Height(50)  
);  
 
if (HighLogic.LoadedSceneIsEditor)  
{  
_configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);  
}  
else  
{  
_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);  
}  
 
if (_configWindowPos != this.configWindowPos)  
{  
this.configWindowPos = _configWindowPos;  
}  
}  
}  
 
public virtual void 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 virtual void Update()  
{  
this.LoadBeforeUpdate();  
 
if (this.vessel != null && this.vesselSimActive)  
{  
Tools.PostDebugMessage(this, "Updating SimManager.");  
this.UpdateSimManager();  
}  
 
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 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;  
this.SetIconTexture(this.powerState | this.activeState);  
}  
}  
 
foreach (IVOID_BehaviorModule module in  
this._modules.OfType<IVOID_BehaviorModule>().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 --", VOID_Styles.labelRed);  
}  
 
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._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.Length;  
if (this._skinIdx < 0)  
{  
this._skinIdx += this.skinNames.Length;  
}  
 
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 = 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>()  
{  
StringBuilder sb = new StringBuilder("Loading modules...");  
sb.AppendLine();  
 
foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies)  
{  
foreach (Type loadedType in assy.assembly.GetExportedTypes())  
{  
if (  
loadedType.IsInterface ||  
loadedType.IsAbstract ||  
!typeof(T).IsAssignableFrom(loadedType) ||  
this.GetType().IsAssignableFrom(loadedType)  
)  
{  
continue;  
}  
 
// HACK: This stops editor modules from loading in flight. It is a dirty hack and should be fixed.  
if (!HighLogic.LoadedSceneIsEditor && typeof(IVOID_EditorModule).IsAssignableFrom(loadedType))  
{  
continue;  
}  
 
sb.AppendFormat("Loading IVOID_Module type {0}...", loadedType.Name);  
 
try  
{  
this.LoadModule(loadedType);  
sb.AppendLine("Success.");  
}  
catch (Exception ex)  
{  
sb.AppendFormat("Failed, caught {0}", ex.GetType().Name);  
sb.AppendLine();  
 
#if DEBUG  
Debug.LogException(ex);  
#endif  
}  
}  
}  
 
this._modulesLoaded = true;  
 
sb.AppendFormat("Loaded {0} modules.", this.Modules.Count);  
sb.AppendLine();  
}  
 
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()  
{  
VOID_Styles.OnSkinChanged();  
 
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();  
}  
 
if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)  
{  
this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);  
this.sortedBodyList.Sort(new CBListComparer());  
this.sortedBodyList.Reverse();  
 
Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));  
}  
 
}  
 
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.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()  
{  
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<VOID_Core>();  
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";  
 
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  
}  
}  
}  
 
 
// VOID // VOID
// //
// VOID_Data.cs // VOID_Data.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using Engineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public static class VOID_Data public static class VOID_Data
{ {
  private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>();
  public static Dictionary<int, IVOID_DataValue> DataValues
  {
  get
  {
  return dataValues;
  }
  }
   
#region Constants #region Constants
   
private static double kerbinGee; private static double kerbinGee;
   
public static double KerbinGee public static double KerbinGee
{ {
get get
{ {
if (kerbinGee == default(double)) if (kerbinGee == default(double))
{ {
kerbinGee = core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius); kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius);
} }
   
return kerbinGee; return kerbinGee;
} }
} }
   
#endregion #endregion
   
#region Core Data #region Core Data
   
public static VOID_Core core public static VOIDCore Core
{ {
get get
{ {
if (HighLogic.LoadedSceneIsEditor) if (!CoreInitialized)
{ {
return VOID_EditorCore.Instance; return null;
} }
else  
{ switch (HighLogic.LoadedScene)
return VOID_Core.Instance; {
  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 #endregion
   
#region Atmosphere #region Atmosphere
   
public static readonly VOID_DoubleValue atmDensity = public static readonly VOID_DoubleValue atmDensity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Atmosphere Density", "Atmosphere Density",
new Func<double>(() => core.vessel.atmDensity * 1000f), new Func<double>(() => Core.vessel.atmDensity * 1000f),
"g/m³" "g/m³"
); );
   
public static readonly VOID_FloatValue atmLimit = public static readonly VOID_FloatValue atmLimit =
new VOID_FloatValue( new VOID_FloatValue(
"Atmosphere Limit", "Atmosphere Limit",
new Func<float>(() => core.vessel.mainBody.maxAtmosphereAltitude), new Func<float>(() => Core.vessel.mainBody.maxAtmosphereAltitude),
"m" "m"
); );
   
public static readonly VOID_DoubleValue atmPressure = public static readonly VOID_DoubleValue atmPressure =
new VOID_DoubleValue( new VOID_DoubleValue(
"Pressure", "Pressure",
new Func<double>(() => core.vessel.staticPressure), new Func<double>(() => Core.vessel.staticPressure),
"atm" "atm"
); );
   
public static readonly VOID_FloatValue temperature = public static readonly VOID_FloatValue temperature =
new VOID_FloatValue( new VOID_FloatValue(
"Temperature", "Temperature",
new Func<float>(() => core.vessel.flightIntegrator.getExternalTemperature()), new Func<float>(() => Core.vessel.flightIntegrator.getExternalTemperature()),
"°C" "°C"
); );
   
#endregion #endregion
   
#region Attitude #region Attitude
   
public static readonly VOID_StrValue vesselHeading = public static readonly VOID_StrValue vesselHeading =
new VOID_StrValue( new VOID_StrValue(
"Heading", "Heading",
delegate() delegate()
{ {
double heading = core.vessel.getSurfaceHeading(); double heading = Core.vessel.getSurfaceHeading();
string cardinal = VOID_Tools.get_heading_text(heading); string cardinal = VOID_Tools.get_heading_text(heading);
   
return string.Format( return string.Format(
"{0}° {1}", "{0}° {1}",
heading.ToString("F2"), heading.ToString("F2"),
cardinal cardinal
); );
} }
); );
   
public static readonly VOID_DoubleValue vesselPitch = public static readonly VOID_DoubleValue vesselPitch =
new VOID_DoubleValue( new VOID_DoubleValue(
"Pitch", "Pitch",
() => core.vessel.getSurfacePitch(), () => Core.vessel.getSurfacePitch(),
"°" "°"
); );
   
#endregion #endregion
   
#region Career #region Career
   
public static readonly VOID_StrValue fundingStatus = public static readonly VOID_StrValue fundingStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Funds"), string.Intern("Funds"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"), VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange)
); );
} }
); );
   
public static readonly VOID_StrValue reputationStatus = public static readonly VOID_StrValue reputationStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Reputation"), string.Intern("Reputation"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"), VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange)
); );
} }
); );
   
public static readonly VOID_StrValue scienceStatus = public static readonly VOID_StrValue scienceStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Science"), string.Intern("Science"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"), VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange)
); );
} }
); );
   
#endregion #endregion
   
#region Control #region Control
   
public static readonly VOID_FloatValue mainThrottle = public static readonly VOID_FloatValue mainThrottle =
new VOID_FloatValue( new VOID_FloatValue(
"Throttle", "Throttle",
new Func<float>(() => core.vessel.ctrlState.mainThrottle * 100f), new Func<float>(() => Core.vessel.ctrlState.mainThrottle * 100f),
"%" "%"
); );
   
#endregion #endregion
   
#region Engineering #region Engineering
   
public static readonly VOID_IntValue partCount = public static readonly VOID_IntValue partCount =
new VOID_IntValue( new VOID_IntValue(
"Parts", "Parts",
new Func<int>(() => core.vessel.Parts.Count), new Func<int>(() => Core.vessel.Parts.Count),
"" ""
); );
   
#region Mass #region Mass
   
public static readonly VOID_StrValue comboResourceMass = public static readonly VOID_StrValue comboResourceMass =
new VOID_StrValue( new VOID_StrValue(
"Resource Mass (curr / total)", "Resource Mass (curr / total)",
delegate() delegate()
{ {
return string.Format("{0} / {1}", return string.Format("{0} / {1}",
stageResourceMass.ValueUnitString("F3"), stageResourceMass.ValueUnitString("F3"),
resourceMass.ValueUnitString("F3") resourceMass.ValueUnitString("F3")
); );
} }
); );
   
public static readonly VOID_DoubleValue resourceMass = public static readonly VOID_DoubleValue resourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass", "Resource Mass",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return core.LastStage.totalMass - core.LastStage.totalBaseMass; return Core.LastStage.resourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue stageResourceMass = public static readonly VOID_DoubleValue stageResourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass (Stage)", "Resource Mass (Stage)",
delegate() delegate()
{ {
if (core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return core.LastStage.mass - core.LastStage.baseMass; return Core.LastStage.resourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue totalMass = public static readonly VOID_DoubleValue totalMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Total Mass", "Total Mass",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return core.LastStage.totalMass; return Core.LastStage.totalMass;
}, },
"tons" "tons"
); );
   
#endregion #endregion
   
#region DeltaV #region DeltaV
   
public static readonly VOID_DoubleValue stageDeltaV = public static readonly VOID_DoubleValue stageDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Current Stage)", "DeltaV (Current Stage)",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return core.LastStage.deltaV; return Core.LastStage.deltaV;
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue totalDeltaV = public static readonly VOID_DoubleValue totalDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Total)", "DeltaV (Total)",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return core.LastStage.totalDeltaV; return Core.LastStage.totalDeltaV;
}, },
"m/s" "m/s"
); );
   
#endregion #endregion
   
#region Propulsion #region Propulsion
   
public static readonly VOID_StrValue currmaxThrustWeight = public static readonly VOID_StrValue currmaxThrustWeight =
new VOID_StrValue( new VOID_StrValue(
"T:W (curr/max)", "T:W (curr/max)",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
(VOID_Data.currThrustWeight.Value).ToString("F2"), (VOID_Data.currThrustWeight.Value).ToString("F2"),
(VOID_Data.maxThrustWeight.Value).ToString("F2") (VOID_Data.maxThrustWeight.Value).ToString("F2")
); );
} }
); );
   
public static readonly VOID_StrValue currmaxThrust = public static readonly VOID_StrValue currmaxThrust =
new VOID_StrValue( new VOID_StrValue(
"Thrust (curr/max)", "Thrust (curr/max)",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
double currThrust = core.LastStage.actualThrust; double currThrust = Core.LastStage.actualThrust;
double maxThrust = core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
currThrust.ToString("F1"), currThrust.ToString("F1"),
maxThrust.ToString("F1") maxThrust.ToString("F1")
); );
} }
); );
   
public static readonly VOID_DoubleValue stageMassFlow = public static readonly VOID_DoubleValue stageMassFlow =
new VOID_DoubleValue( new VOID_DoubleValue(
"Stage Mass Flow", "Stage Mass Flow",
delegate() delegate()
{ {
if (core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
double stageIsp = core.LastStage.isp; double stageIsp = Core.LastStage.isp;
double stageThrust = stageNominalThrust; double stageThrust = stageNominalThrust;
   
Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" +
"\tstageIsp: {0}\n" + "\tstageIsp: {0}\n" +
"\tstageThrust: {1}\n" + "\tstageThrust: {1}\n" +
"\tKerbinGee: {2}\n", "\tKerbinGee: {2}\n",
stageIsp, stageIsp,
stageThrust, stageThrust,
KerbinGee KerbinGee
); );
   
return stageThrust / (stageIsp * KerbinGee); return stageThrust / (stageIsp * KerbinGee);
}, },
"Mg/s" "Mg/s"
); );
   
public static readonly VOID_DoubleValue stageNominalThrust = public static readonly VOID_DoubleValue stageNominalThrust =
new VOID_DoubleValue( new VOID_DoubleValue(
"Nominal Stage Thrust", "Nominal Stage Thrust",
delegate() delegate()
{ {
if (core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
if (core.LastStage.actualThrust == 0d) if (Core.LastStage.actualThrust == 0d)
{ {
return core.LastStage.thrust; return Core.LastStage.thrust;
} }
else else
{ {
return core.LastStage.actualThrust; return Core.LastStage.actualThrust;
} }
}, },
"kN" "kN"
); );
   
#endregion #endregion
   
#region Kinetics #region Kinetics
   
public static readonly VOID_DoubleValue currThrustWeight = public static readonly VOID_DoubleValue currThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return core.LastStage.actualThrustToWeight; return Core.LastStage.actualThrustToWeight;
}, },
"" ""
); );
   
   
   
public static readonly VOID_DoubleValue maxThrustWeight = public static readonly VOID_DoubleValue maxThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return core.LastStage.thrustToWeight; return Core.LastStage.thrustToWeight;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue nominalThrustWeight = public static readonly VOID_DoubleValue nominalThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Thrust-to-Weight Ratio", "Thrust-to-Weight Ratio",
delegate() delegate()
{ {
if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d) if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
{ {
return maxThrustWeight.Value; return maxThrustWeight.Value;
} }
   
return currThrustWeight.Value; return currThrustWeight.Value;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue surfaceThrustWeight = public static readonly VOID_DoubleValue surfaceThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Max T:W @ surface", "Max T:W @ surface",
delegate() delegate()
{ {
if (core.Stages == null || core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
   
double maxThrust = core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
double mass = core.LastStage.totalMass; double mass = Core.LastStage.totalMass;
double gravity = (VOID_Core.Constant_G * core.vessel.mainBody.Mass) / double gravity = (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) /
(core.vessel.mainBody.Radius * core.vessel.mainBody.Radius); (Core.vessel.mainBody.Radius * Core.vessel.mainBody.Radius);
double weight = mass * gravity; double weight = mass * gravity;
   
return maxThrust / weight; return maxThrust / weight;
}, },
"" ""
); );
   
public static readonly VOID_Vector3dValue vesselThrustOffset = public static readonly VOID_Vector3dValue vesselThrustOffset =
new VOID_Vector3dValue( new VOID_Vector3dValue(
"Thrust Offset", "Thrust Offset",
delegate() delegate()
{ {
if (core.vessel == null) if (Core.vessel == null)
{ {
return Vector3d.zero; return Vector3d.zero;
} }
   
List<PartModule> engineModules = core.vessel.getModulesOfType<PartModule>(); List<PartModule> engineModules = Core.vessel.getModulesOfType<PartModule>();
   
Vector3d thrustPos = Vector3d.zero; Vector3d thrustPos = Vector3d.zero;
Vector3d thrustDir = Vector3d.zero; Vector3d thrustDir = Vector3d.zero;
float thrust = 0; float thrust = 0;
   
foreach (PartModule engine in engineModules) foreach (PartModule engine in engineModules)
{ {
float moduleThrust = 0; float moduleThrust = 0;
   
switch (engine.moduleName) switch (engine.moduleName)
{ {
case "ModuleEngines": case "ModuleEngines":
case "ModuleEnginesFX": case "ModuleEnginesFX":
break; break;
default: default:
continue; continue;
} }
   
if (!engine.isEnabled) if (!engine.isEnabled)
{ {
continue; continue;
} }
   
CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); CenterOfThrustQuery cotQuery = new CenterOfThrustQuery();
   
if (engine is ModuleEngines) if (engine is ModuleEngines)
{ {
ModuleEngines engineModule = engine as ModuleEngines; ModuleEngines engineModule = engine as ModuleEngines;
   
moduleThrust = engineModule.finalThrust; moduleThrust = engineModule.finalThrust;
   
engineModule.OnCenterOfThrustQuery(cotQuery); engineModule.OnCenterOfThrustQuery(cotQuery);
} }
else // engine is ModuleEnginesFX else // engine is ModuleEnginesFX
{ {
ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX;
   
moduleThrust = engineFXModule.finalThrust; moduleThrust = engineFXModule.finalThrust;
   
engineFXModule.OnCenterOfThrustQuery(cotQuery); engineFXModule.OnCenterOfThrustQuery(cotQuery);
} }
   
if (moduleThrust != 0d) if (moduleThrust != 0d)
{ {
cotQuery.thrust = moduleThrust; cotQuery.thrust = moduleThrust;
} }
   
thrustPos += cotQuery.pos * cotQuery.thrust; thrustPos += cotQuery.pos * cotQuery.thrust;
thrustDir += cotQuery.dir * cotQuery.thrust; thrustDir += cotQuery.dir * cotQuery.thrust;
thrust += cotQuery.thrust; thrust += cotQuery.thrust;
} }
   
if (thrust != 0) if (thrust != 0)
{ {
thrustPos /= thrust; thrustPos /= thrust;
thrustDir /= thrust; thrustDir /= thrust;
} }
   
Transform vesselTransform = core.vessel.transform; Transform vesselTransform = Core.vessel.transform;
   
thrustPos = vesselTransform.InverseTransformPoint(thrustPos); thrustPos = vesselTransform.InverseTransformPoint(thrustPos);
thrustDir = vesselTransform.InverseTransformDirection(thrustDir); thrustDir = vesselTransform.InverseTransformDirection(thrustDir);
   
Vector3d thrustOffset = VectorTools.PointDistanceToLine( Vector3d thrustOffset = VectorTools.PointDistanceToLine(
thrustPos, thrustDir.normalized, core.vessel.findLocalCenterOfMass()); thrustPos, thrustDir.normalized, Core.vessel.findLocalCenterOfMass());
   
Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" +
"\tthrustPos: {0}\n" + "\tthrustPos: {0}\n" +
"\tthrustDir: {1}\n" + "\tthrustDir: {1}\n" +
"\tthrustOffset: {2}\n" + "\tthrustOffset: {2}\n" +
"\tvessel.CoM: {3}", "\tvessel.CoM: {3}",
thrustPos, thrustPos,
thrustDir.normalized, thrustDir.normalized,
thrustOffset, thrustOffset,
core.vessel.findWorldCenterOfMass() Core.vessel.findWorldCenterOfMass()
); );
   
return thrustOffset; return thrustOffset;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Air Breathing #region Air Breathing
   
public static readonly VOID_StrValue intakeAirStatus = public static readonly VOID_StrValue intakeAirStatus =
new VOID_StrValue( new VOID_StrValue(
"Intake Air (Curr / Req)", "Intake Air (Curr / Req)",
delegate() delegate()
{ {
double currentAmount; double currentAmount;
double currentRequirement; double currentRequirement;
   
currentAmount = 0d; currentAmount = 0d;
currentRequirement = 0d; currentRequirement = 0d;
   
foreach (Part part in core.vessel.Parts) foreach (Part part in Core.vessel.Parts)
{ {
if (part.enabled) if (part.enabled)
{ {
ModuleEngines engineModule; ModuleEngines engineModule;
ModuleEnginesFX enginesFXModule; ModuleEnginesFX enginesFXModule;
List<Propellant> propellantList = null; List<Propellant> propellantList = null;
   
if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule)) if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule))
{ {
propellantList = engineModule.propellants; propellantList = engineModule.propellants;
} }
else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule)) else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule))
{ {
propellantList = enginesFXModule.propellants; propellantList = enginesFXModule.propellants;
} }
   
if (propellantList != null) if (propellantList != null)
{ {
foreach (Propellant propellant in propellantList) foreach (Propellant propellant in propellantList)
{ {
if (propellant.name == "IntakeAir") if (propellant.name == "IntakeAir")
{ {
currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime;
break; break;
} }
} }
} }
} }
   
ModuleResourceIntake intakeModule; ModuleResourceIntake intakeModule;
   
if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule)) if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule))
{ {
if (intakeModule.resourceName == "IntakeAir") if (intakeModule.resourceName == "IntakeAir")
{ {
currentAmount += intakeModule.airFlow; currentAmount += intakeModule.airFlow;
} }
} }
} }
   
if (currentAmount == 0 && currentRequirement == 0) if (currentAmount == 0 && currentRequirement == 0)
{ {
return "N/A"; return "N/A";
} }
   
return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement); return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement);
} }
); );
   
#endregion #endregion
   
#region Crew #region Crew
   
public static readonly VOID_IntValue vesselCrewCount = public static readonly VOID_IntValue vesselCrewCount =
new VOID_IntValue( new VOID_IntValue(
"Crew Onboard", "Crew Onboard",
delegate() delegate()
{ {
if (core.vessel != null) if (Core.vessel != null)
{ {
return core.vessel.GetCrewCount(); return Core.vessel.GetCrewCount();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
public static readonly VOID_IntValue vesselCrewCapacity = public static readonly VOID_IntValue vesselCrewCapacity =
new VOID_IntValue( new VOID_IntValue(
"Crew Capacity", "Crew Capacity",
delegate() delegate()
{ {
if (core.vessel != null) if (Core.vessel != null)
{ {
return core.vessel.GetCrewCapacity(); return Core.vessel.GetCrewCapacity();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
#endregion #endregion
   
#endregion #endregion
   
#region Location #region Location
   
  public const double kscLongitude = 285.442323427289 * Math.PI / 180d;
  public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;
   
public static readonly VOID_DoubleValue downrangeDistance = public static readonly VOID_DoubleValue downrangeDistance =
new VOID_DoubleValue( new VOID_DoubleValue(
"Downrange Distance", "Downrange Distance",
delegate() delegate()
{ {
   
if (core.vessel == null || if (Core.vessel == null ||
Planetarium.fetch == null || Planetarium.fetch == null ||
core.vessel.mainBody != Planetarium.fetch.Home) Core.vessel.mainBody != Planetarium.fetch.Home)
{ {
return double.NaN; return double.NaN;
} }
   
double vesselLongitude = core.vessel.longitude * Math.PI / 180d; double vesselLongitude = Core.vessel.longitude * Math.PI / 180d;
double vesselLatitude = core.vessel.latitude * Math.PI / 180d; double vesselLatitude = Core.vessel.latitude * Math.PI / 180d;
   
const double kscLongitude = 285.442323427289 * Math.PI / 180d;  
const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;  
   
double diffLon = vesselLongitude - kscLongitude; double diffLon = vesselLongitude - kscLongitude;
double diffLat = vesselLatitude - kscLatitude; double diffLat = vesselLatitude - kscLatitude;
   
double sinHalfDiffLat = Math.Sin(diffLat / 2d); double sinHalfDiffLat = Math.Sin(diffLat / 2d);
double sinHalfDiffLon = Math.Sin(diffLon / 2d); double sinHalfDiffLon = Math.Sin(diffLon / 2d);
   
double cosVesselLon = Math.Cos(vesselLongitude); double cosVesselLon = Math.Cos(vesselLongitude);
double cosKSCLon = Math.Cos(kscLongitude); double cosKSCLon = Math.Cos(kscLongitude);
   
double haversine = double haversine =
sinHalfDiffLat * sinHalfDiffLat + sinHalfDiffLat * sinHalfDiffLat +
cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon; cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon;
   
double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine)); double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine));
   
return core.vessel.mainBody.Radius * arc; return Core.vessel.mainBody.Radius * arc;
}, },
"m" "m"
); );
   
public static readonly VOID_StrValue surfLatitude = public static readonly VOID_StrValue surfLatitude =
new VOID_StrValue( new VOID_StrValue(
"Latitude", "Latitude",
new Func<string>(() => VOID_Tools.GetLatitudeString(core.vessel)) new Func<string>(() => VOID_Tools.GetLatitudeString(Core.vessel))
); );
   
public static readonly VOID_StrValue surfLongitude = public static readonly VOID_StrValue surfLongitude =
new VOID_StrValue( new VOID_StrValue(
"Longitude", "Longitude",
new Func<string>(() => VOID_Tools.GetLongitudeString(core.vessel)) new Func<string>(() => VOID_Tools.GetLongitudeString(Core.vessel))
); );
   
public static readonly VOID_DoubleValue trueAltitude = public static readonly VOID_DoubleValue trueAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (true)", "Altitude (true)",
delegate() delegate()
{ {
double alt_true = core.vessel.orbit.altitude - core.vessel.terrainAltitude; double alt_true = Core.vessel.orbit.altitude - Core.vessel.terrainAltitude;
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
// and water covers the whole surface at 0 m. // and water covers the whole surface at 0 m.
if (core.vessel.terrainAltitude < 0 && core.vessel.mainBody.ocean) if (Core.vessel.terrainAltitude < 0 && Core.vessel.mainBody.ocean)
alt_true = core.vessel.orbit.altitude; alt_true = Core.vessel.orbit.altitude;
return alt_true; return alt_true;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Kinematics #region Kinematics
   
  public static readonly VOID_DoubleValue geeForce =
  new VOID_DoubleValue(
  "G-force",
  new Func<double>(() => Core.vessel.geeForce),
  "gees"
  );
   
  public static readonly VOID_DoubleValue horzVelocity =
  new VOID_DoubleValue(
  "Horizontal speed",
  new Func<double>(() => Core.vessel.horizontalSrfSpeed),
  "m/s"
  );
   
public static readonly VOID_DoubleValue surfVelocity = public static readonly VOID_DoubleValue surfVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Surface velocity", "Surface velocity",
new Func<double>(() => core.vessel.srf_velocity.magnitude), new Func<double>(() => Core.vessel.srf_velocity.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue vertVelocity = public static readonly VOID_DoubleValue vertVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Vertical speed", "Vertical speed",
new Func<double>(() => core.vessel.verticalSpeed), new Func<double>(() => Core.vessel.verticalSpeed),
"m/s" "m/s"
);  
   
public static readonly VOID_DoubleValue horzVelocity =  
new VOID_DoubleValue(  
"Horizontal speed",  
new Func<double>(() => core.vessel.horizontalSrfSpeed),  
"m/s"  
);  
   
public static readonly VOID_DoubleValue geeForce =  
new VOID_DoubleValue(  
"G-force",  
new Func<double>(() => core.vessel.geeForce),  
"gees"  
);  
   
   
public static readonly VOID_DoubleValue vesselAngularVelocity =  
new VOID_DoubleValue(  
"Angular Velocity",  
delegate()  
{  
if (core.vessel != null)  
{  
return core.vessel.angularVelocity.magnitude;  
}  
else  
{  
return double.NaN;  
}  
},  
"rad/s"  
); );
   
public static readonly VOID_DoubleValue vesselAccel = public static readonly VOID_DoubleValue vesselAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Acceleration", "Acceleration",
() => geeForce * KerbinGee, () => geeForce * KerbinGee,
"m/s²" "m/s²"
  );
   
  public static readonly VOID_DoubleValue vesselAngularVelocity =
  new VOID_DoubleValue(
  "Angular Velocity",
  delegate()
  {
  if (Core.vessel != null)
  {
  return Core.vessel.angularVelocity.magnitude;
  }
  else
  {
  return double.NaN;
  }
  },
  "rad/s"
); );
   
#endregion #endregion
   
#region Navigation #region Navigation
   
public static int upcomingManeuverNodes public static int upcomingManeuverNodes
{ {
get get
{ {
if (core.vessel == null || if (Core.vessel == null ||
core.vessel.patchedConicSolver == null || Core.vessel.patchedConicSolver == null ||
core.vessel.patchedConicSolver.maneuverNodes == null) Core.vessel.patchedConicSolver.maneuverNodes == null)
{ {
return 0; return 0;
} }
   
return core.vessel.patchedConicSolver.maneuverNodes.Count; return Core.vessel.patchedConicSolver.maneuverNodes.Count;
} }
} }
   
public static readonly VOID_DoubleValue currManeuverDeltaV =  
new VOID_DoubleValue(  
"Current Maneuver Delta-V",  
delegate()  
{  
if (upcomingManeuverNodes > 0)  
{  
return core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude;  
}  
else  
{  
return double.NaN;  
}  
},  
"m/s"  
);  
   
public static readonly VOID_DoubleValue currManeuverDVRemaining =  
new VOID_DoubleValue(  
"Remaining Maneuver Delta-V",  
delegate()  
{  
if (upcomingManeuverNodes > 0)  
{  
return core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(core.vessel.orbit).magnitude;  
}  
else  
{  
return double.NaN;  
}  
},  
"m/s"  
);  
   
public static readonly VOID_DoubleValue nextManeuverDeltaV =  
new VOID_DoubleValue(  
"Current Maneuver Delta-V",  
delegate()  
{  
if (upcomingManeuverNodes > 1)  
{  
return core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude;  
}  
else  
{  
return double.NaN;  
}  
},  
"m/s"  
);  
   
public static readonly VOID_DoubleValue currentNodeBurnDuration =  
new VOID_DoubleValue(  
"Total Burn Time",  
delegate()  
{  
if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)  
{  
return double.NaN;  
}  
   
double stageThrust = stageNominalThrust;  
   
return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust);  
},  
"s"  
);  
   
public static readonly VOID_DoubleValue currentNodeBurnRemaining =  
new VOID_DoubleValue(  
"Burn Time Remaining",  
delegate()  
{  
if (core.LastStage == null || currManeuverDVRemaining == double.NaN)  
{  
return double.NaN;  
}  
   
double stageThrust = stageNominalThrust;  
   
return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust);  
},  
"s"  
);  
   
public static readonly VOID_DoubleValue currentNodeHalfBurnDuration =  
new VOID_DoubleValue(  
"Half Burn Time",  
delegate()  
{  
if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)  
{  
return double.NaN;  
}  
   
double stageThrust = stageNominalThrust;  
   
return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust);  
},  
"s"  
);  
   
public static readonly VOID_StrValue burnTimeDoneAtNode = public static readonly VOID_StrValue burnTimeDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.ConvertInterval(interval)); return string.Format(format, VOID_Tools.FormatInterval(interval));
} }
); );
   
public static readonly VOID_StrValue burnTimeHalfDoneAtNode = public static readonly VOID_StrValue burnTimeHalfDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.ConvertInterval(interval)); 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 (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
  {
  return double.NaN;
  }
   
  double stageThrust = stageNominalThrust;
   
  return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust);
  },
  "s"
  );
   
  public static readonly VOID_DoubleValue currentNodeBurnRemaining =
  new VOID_DoubleValue(
  "Burn Time Remaining",
  delegate()
  {
  if (Core.LastStage == null || currManeuverDVRemaining == double.NaN)
  {
  return double.NaN;
  }
   
  double stageThrust = stageNominalThrust;
   
  return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust);
  },
  "s"
  );
   
  public static readonly VOID_DoubleValue currentNodeHalfBurnDuration =
  new VOID_DoubleValue(
  "Half Burn Time",
  delegate()
  {
  if (Core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
  {
  return double.NaN;
  }
   
  double stageThrust = stageNominalThrust;
   
  return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust);
  },
  "s"
  );
   
  public static readonly VOID_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 #endregion
   
#region Orbits #region Orbits
   
public static readonly VOID_StrValue primaryName = public static readonly VOID_StrValue primaryName =
new VOID_StrValue( new VOID_StrValue(
VOID_Localization.void_primary, VOID_Localization.void_primary,
delegate() delegate()
{ {
if (core.vessel == null) if (Core.vessel == null)
{ {
return string.Empty; return string.Empty;
} }
return core.vessel.mainBody.name; return Core.vessel.mainBody.name;
} }
); );
   
public static readonly VOID_DoubleValue orbitAltitude = public static readonly VOID_DoubleValue orbitAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (ASL)", "Altitude (ASL)",
new Func<double>(() => core.vessel.orbit.altitude), new Func<double>(() => Core.vessel.orbit.altitude),
"m" "m"
); );
   
public static readonly VOID_DoubleValue orbitVelocity = public static readonly VOID_DoubleValue orbitVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_velocity, VOID_Localization.void_velocity,
new Func<double>(() => core.vessel.orbit.vel.magnitude), new Func<double>(() => Core.vessel.orbit.vel.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue orbitApoAlt = public static readonly VOID_DoubleValue orbitApoAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_apoapsis, VOID_Localization.void_apoapsis,
new Func<double>(() => core.vessel.orbit.ApA), new Func<double>(() => Core.vessel.orbit.ApA),
"m" "m"
); );
   
public static readonly VOID_DoubleValue oribtPeriAlt = public static readonly VOID_DoubleValue oribtPeriAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_periapsis, VOID_Localization.void_periapsis,
new Func<double>(() => core.vessel.orbit.PeA), new Func<double>(() => Core.vessel.orbit.PeA),
"m" "m"
); );
   
public static readonly VOID_StrValue timeToApo = public static readonly VOID_StrValue timeToApo =
new VOID_StrValue( new VOID_StrValue(
"Time to Apoapsis", "Time to Apoapsis",
new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToAp)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToAp))
); );
   
public static readonly VOID_StrValue timeToPeri = public static readonly VOID_StrValue timeToPeri =
new VOID_StrValue( new VOID_StrValue(
"Time to Periapsis", "Time to Periapsis",
new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToPe)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.timeToPe))
); );
   
public static readonly VOID_DoubleValue orbitInclination = public static readonly VOID_DoubleValue orbitInclination =
new VOID_DoubleValue( new VOID_DoubleValue(
"Inclination", "Inclination",
new Func<double>(() => core.vessel.orbit.inclination), new Func<double>(() => Core.vessel.orbit.inclination),
"°" "°"
); );
   
public static readonly VOID_DoubleValue gravityAccel = public static readonly VOID_DoubleValue gravityAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Gravity", "Gravity",
delegate() delegate()
{ {
double orbitRadius = core.vessel.mainBody.Radius + double orbitRadius = Core.vessel.mainBody.Radius +
core.vessel.mainBody.GetAltitude(core.vessel.findWorldCenterOfMass()); Core.vessel.mainBody.GetAltitude(Core.vessel.findWorldCenterOfMass());
return (VOID_Core.Constant_G * core.vessel.mainBody.Mass) / return (VOIDCore.Constant_G * Core.vessel.mainBody.Mass) /
(orbitRadius * orbitRadius); (orbitRadius * orbitRadius);
}, },
"m/s²" "m/s²"
); );
   
public static readonly VOID_StrValue orbitPeriod = public static readonly VOID_StrValue orbitPeriod =
new VOID_StrValue( new VOID_StrValue(
"Period", "Period",
new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.period)) new Func<string>(() => VOID_Tools.FormatInterval(Core.vessel.orbit.period))
); );
   
public static readonly VOID_DoubleValue semiMajorAxis = public static readonly VOID_DoubleValue semiMajorAxis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Semi-Major Axis", "Semi-Major Axis",
new Func<double>(() => core.vessel.orbit.semiMajorAxis), new Func<double>(() => Core.vessel.orbit.semiMajorAxis),
"m" "m"
); );
   
public static readonly VOID_DoubleValue eccentricity = public static readonly VOID_DoubleValue eccentricity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentricity", "Eccentricity",
new Func<double>(() => core.vessel.orbit.eccentricity), new Func<double>(() => Core.vessel.orbit.eccentricity),
"" ""
); );
   
public static readonly VOID_DoubleValue meanAnomaly = public static readonly VOID_DoubleValue meanAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Mean Anomaly", "Mean Anomaly",
new Func<double>(() => core.vessel.orbit.meanAnomaly * 180d / Math.PI), new Func<double>(() => Core.vessel.orbit.meanAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue trueAnomaly = public static readonly VOID_DoubleValue trueAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"True Anomaly", "True Anomaly",
new Func<double>(() => core.vessel.orbit.trueAnomaly), new Func<double>(() => Core.vessel.orbit.trueAnomaly),
"°" "°"
); );
   
public static readonly VOID_DoubleValue eccAnomaly = public static readonly VOID_DoubleValue eccAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentric Anomaly", "Eccentric Anomaly",
new Func<double>(() => core.vessel.orbit.eccentricAnomaly * 180d / Math.PI), new Func<double>(() => Core.vessel.orbit.eccentricAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue longitudeAscNode = public static readonly VOID_DoubleValue longitudeAscNode =
new VOID_DoubleValue( new VOID_DoubleValue(
"Long. Ascending Node", "Long. Ascending Node",
new Func<double>(() => core.vessel.orbit.LAN), new Func<double>(() => Core.vessel.orbit.LAN),
"°" "°"
); );
   
public static readonly VOID_DoubleValue argumentPeriapsis = public static readonly VOID_DoubleValue argumentPeriapsis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Argument of Periapsis", "Argument of Periapsis",
new Func<double>(() => core.vessel.orbit.argumentOfPeriapsis), new Func<double>(() => Core.vessel.orbit.argumentOfPeriapsis),
"°" "°"
); );
   
public static readonly VOID_DoubleValue localSiderealLongitude = public static readonly VOID_DoubleValue localSiderealLongitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Local Sidereal Longitude", "Local Sidereal Longitude",
new Func<double>(() => VOID_Tools.FixDegreeDomain( new Func<double>(() => VOID_Tools.FixDegreeDomain(
core.vessel.longitude + core.vessel.orbit.referenceBody.rotationAngle)), Core.vessel.longitude + Core.vessel.orbit.referenceBody.rotationAngle)),
"°" "°"
); );
   
#endregion #endregion
   
#region Science #region Science
   
public static readonly VOID_StrValue expSituation = public static readonly VOID_StrValue expSituation =
new VOID_StrValue( new VOID_StrValue(
"Situation", "Situation",
new Func<string>(() => core.vessel.GetExperimentSituation().HumanString()) new Func<string>(() => Core.vessel.GetExperimentSituation().HumanString())
); );
   
public static readonly VOID_StrValue currBiome = public static readonly VOID_StrValue currBiome =
new VOID_StrValue( new VOID_StrValue(
"Biome", "Biome",
new Func<string>(() => VOID_Tools.GetBiome(core.vessel).name) new Func<string>(() => VOID_Tools.GetBiome(Core.vessel).name)
); );
   
#endregion #endregion
   
#region Surface #region Surface
   
public static readonly VOID_DoubleValue terrainElevation = public static readonly VOID_DoubleValue terrainElevation =
new VOID_DoubleValue( new VOID_DoubleValue(
"Terrain elevation", "Terrain elevation",
new Func<double>(() => core.vessel.terrainAltitude), new Func<double>(() => Core.vessel.terrainAltitude),
"m" "m"
); );
   
#endregion #endregion
   
private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust)
{ {
Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" +
"\tdeltaV: {0}\n" + "\tdeltaV: {0}\n" +
"\tinitialMass: {1}\n" + "\tinitialMass: {1}\n" +
"\tmassFlow: {2}\n" + "\tmassFlow: {2}\n" +
"\tthrust: {3}\n", "\tthrust: {3}\n",
deltaV, deltaV,
initialMass, initialMass,
massFlow, massFlow,
thrust thrust
); );
return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust)); return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust));
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_DataLogger.cs // VOID_DataLogger.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
  using System.IO;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule
{ {
/* /*
* Fields * Fields
* */ * */
protected bool stopwatch1_running; #region Fields
   
protected bool csv_logging; protected bool _loggingActive;
protected bool first_write; protected bool firstWrite;
   
protected double stopwatch1; [AVOID_SaveValue("logInterval")]
  protected VOID_SaveValue<float> logInterval;
protected string csv_log_interval_str; protected string logIntervalStr;
   
protected float csv_log_interval; protected float csvCollectTimer;
   
protected double csvWriteTimer; protected List<byte> csvBytes;
protected double csvCollectTimer;  
  protected string _fileName;
protected List<string> csvList = new List<string>(); protected FileStream _outputFile;
   
  protected uint outstandingWrites;
   
  protected System.Text.UTF8Encoding _utf8Encoding;
   
  #endregion
   
/* /*
* Properties * 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 * Methods
* */ * */
public VOID_DataLogger() #region Monobehaviour Lifecycle
{  
this._Name = "CSV Data Logger";  
   
this.stopwatch1_running = false;  
   
this.csv_logging = false;  
this.first_write = true;  
   
this.stopwatch1 = 0;  
this.csv_log_interval_str = "0.5";  
   
this.csvWriteTimer = 0;  
this.csvCollectTimer = 0;  
   
this.WindowPos.x = Screen.width - 520;  
this.WindowPos.y = 85;  
}  
   
public override void ModuleWindow(int _)  
{  
GUIStyle txt_white = new GUIStyle(GUI.skin.label);  
txt_white.normal.textColor = txt_white.focused.textColor = Color.white;  
txt_white.alignment = TextAnchor.UpperRight;  
GUIStyle txt_green = new GUIStyle(GUI.skin.label);  
txt_green.normal.textColor = txt_green.focused.textColor = Color.green;  
txt_green.alignment = TextAnchor.UpperRight;  
GUIStyle txt_yellow = new GUIStyle(GUI.skin.label);  
txt_yellow.normal.textColor = txt_yellow.focused.textColor = Color.yellow;  
txt_yellow.alignment = TextAnchor.UpperRight;  
   
GUILayout.BeginVertical();  
   
GUILayout.Label("System time: " + DateTime.Now.ToString("HH:mm:ss"));  
GUILayout.Label(VOID_Tools.ConvertInterval(stopwatch1));  
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
if (GUILayout.Button("Start"))  
{  
if (stopwatch1_running == false) stopwatch1_running = true;  
}  
if (GUILayout.Button("Stop"))  
{  
if (stopwatch1_running == true) stopwatch1_running = false;  
}  
if (GUILayout.Button("Reset"))  
{  
if (stopwatch1_running == true) stopwatch1_running = false;  
stopwatch1 = 0;  
}  
GUILayout.EndHorizontal();  
   
GUIStyle label_style = txt_white;  
string log_label = "Inactive";  
if (csv_logging && vessel.situation.ToString() == "PRELAUNCH")  
{  
log_label = "Awaiting launch";  
label_style = txt_yellow;  
}  
if (csv_logging && vessel.situation.ToString() != "PRELAUNCH")  
{  
log_label = "Active";  
label_style = txt_green;  
}  
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
csv_logging = GUILayout.Toggle(csv_logging, "Data logging: ", GUILayout.ExpandWidth(false));  
GUILayout.Label(log_label, label_style, GUILayout.ExpandWidth(true));  
GUILayout.EndHorizontal();  
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));  
csv_log_interval_str = GUILayout.TextField(csv_log_interval_str, GUILayout.ExpandWidth(true));  
GUILayout.Label("s", GUILayout.ExpandWidth(false));  
GUILayout.EndHorizontal();  
   
float new_log_interval;  
if (float.TryParse(csv_log_interval_str, out new_log_interval))  
{  
csv_log_interval = new_log_interval;  
}  
   
GUILayout.EndVertical();  
GUI.DragWindow();  
}  
   
public void Update() public void Update()
{ {
  if (this.csvBytes != null && this.csvBytes.Count > 0)
  {
  // csvList is not empty, write it
  this.AsyncWriteData();
  }
   
// CSV Logging // CSV Logging
// from ISA MapSat // from ISA MapSat
if (csv_logging) if (loggingActive)
{ {
//data logging is on //data logging is on
//increment timers //increment timers
csvWriteTimer += Time.deltaTime; this.csvCollectTimer += Time.deltaTime;
csvCollectTimer += Time.deltaTime;  
  if (this.csvCollectTimer >= this.logInterval)
if (csvCollectTimer >= csv_log_interval && vessel.situation != Vessel.Situations.PRELAUNCH)  
{ {
//data logging is on, vessel is not prelaunch, and interval has passed //data logging is on, vessel is not prelaunch, and interval has passed
//write a line to the list //write a line to the list
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() {} public void FixedUpdate() {}
   
private void Innsewerants_writeData(string[] csvArray) public void OnDestroy()
{ {
var efile = KSP.IO.File.AppendText<VOID_Core>(vessel.vesselName + "_data.csv", null); Tools.DebugLogger logger = Tools.DebugLogger.New(this);
foreach (string line in csvArray)  
{ logger.Append("Destroying...");
efile.Write(line);  
} this.CloseFileIfOpen();
efile.Close();  
} logger.Append(" Done.");
  logger.Print(false);
private void line_to_csvList() }
{  
  #endregion
   
  #region VOID_Module Overrides
   
  public override void LoadConfig()
  {
  base.LoadConfig();
   
  this.logIntervalStr = this.logInterval.value.ToString("#.0##");
  }
   
  public override void ModuleWindow(int _)
  {
  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;
  }
   
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
  this.loggingActive = GUILayout.Toggle(loggingActive, "Data logging: ", GUILayout.ExpandWidth(false));
  GUILayout.Label(activeLabelText, activeLabelStyle, GUILayout.ExpandWidth(true));
   
  GUILayout.EndHorizontal();
   
  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();
   
  GUI.DragWindow();
  }
   
  #endregion
   
  #region Data Collection
   
  private void CollectLogData()
  {
  if (this.csvBytes == null)
  {
  this.csvBytes = new List<byte>();
  }
   
//called if logging is on and interval has passed //called if logging is on and interval has passed
//writes one line to the csvList //writes one line to the csvList
   
StringBuilder line = new StringBuilder(); StringBuilder line = new StringBuilder();
   
if (first_write && !KSP.IO.File.Exists<VOID_Core>(vessel.vesselName + "_data.csv", null)) if (firstWrite)
{ {
first_write = false; firstWrite = false;
line.Append( line.Append(
"Mission Elapsed Time (s);" + "\"Kerbin Universal Time (s)\"," +
"Altitude ASL (m);" + "\"Mission Elapsed Time (s)\t\"," +
"Altitude above terrain (m);" + "\"Altitude ASL (m)\"," +
"Surface Latitude (°);" + "\"Altitude above terrain (m)\"," +
"Surface Longitude (°);" + "\"Surface Latitude (°)\"," +
"Orbital Velocity (m/s);" + "\"Surface Longitude (°)\"," +
"Surface Velocity (m/s);" + "\"Orbital Velocity (m/s)\"," +
"Vertical Speed (m/s);" + "\"Surface Velocity (m/s)\"," +
"Horizontal Speed (m/s);" + "\"Vertical Speed (m/s)\"," +
"Gee Force (gees);" + "\"Horizontal Speed (m/s)\"," +
"Temperature (°C);" + "\"Gee Force (gees)\"," +
"Gravity (m/s²);" + "\"Temperature (°C)\"," +
"Atmosphere Density (g/m³);" + "\"Gravity (m/s²)\"," +
"Downrange Distance (m);" + "\"Atmosphere Density (g/m³)\"," +
  "\"Downrange Distance (m)\"," +
"\n" "\n"
); );
} }
   
  // Universal time
  line.Append(Planetarium.GetUniversalTime().ToString("F2"));
  line.Append(',');
   
//Mission time //Mission time
line.Append(vessel.missionTime.ToString("F3")); line.Append(vessel.missionTime.ToString("F3"));
line.Append(';'); line.Append(',');
   
//Altitude ASL //Altitude ASL
line.Append(vessel.orbit.altitude.ToString("F3")); line.Append(VOID_Data.orbitAltitude.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//Altitude (true) //Altitude (true)
double alt_true = vessel.orbit.altitude - vessel.terrainAltitude; line.Append(VOID_Data.trueAltitude.Value.ToString("F3"));
if (vessel.terrainAltitude < 0) alt_true = vessel.orbit.altitude; line.Append(',');
line.Append(alt_true.ToString("F3"));  
line.Append(';');  
   
// Surface Latitude // Surface Latitude
  line.Append('"');
line.Append(VOID_Data.surfLatitude.Value); line.Append(VOID_Data.surfLatitude.Value);
line.Append(';'); line.Append('"');
  line.Append(',');
   
// Surface Longitude // Surface Longitude
  line.Append('"');
line.Append(VOID_Data.surfLongitude.Value); line.Append(VOID_Data.surfLongitude.Value);
line.Append(';'); line.Append('"');
  line.Append(',');
   
//Orbital velocity //Orbital velocity
line.Append(vessel.orbit.vel.magnitude.ToString("F3")); line.Append(VOID_Data.orbitVelocity.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//surface velocity //surface velocity
line.Append(vessel.srf_velocity.magnitude.ToString("F3")); line.Append(VOID_Data.surfVelocity.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//vertical speed //vertical speed
line.Append(vessel.verticalSpeed.ToString("F3")); line.Append(VOID_Data.vertVelocity.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//horizontal speed //horizontal speed
line.Append(vessel.horizontalSrfSpeed.ToString("F3")); line.Append(VOID_Data.horzVelocity.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//gee force //gee force
line.Append(vessel.geeForce.ToString("F3")); line.Append(VOID_Data.geeForce.Value.ToString("F3"));
line.Append(';'); line.Append(',');
   
//temperature //temperature
line.Append(vessel.flightIntegrator.getExternalTemperature().ToString("F2")); line.Append(VOID_Data.temperature.Value.ToString("F2"));
line.Append(';'); line.Append(',');
   
//gravity //gravity
double r_vessel = vessel.mainBody.Radius + vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass()); line.Append(VOID_Data.gravityAccel.Value.ToString("F3"));
double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / (r_vessel * r_vessel); line.Append(',');
line.Append(g_vessel.ToString("F3"));  
line.Append(';');  
   
//atm density //atm density
line.Append((vessel.atmDensity * 1000).ToString("F3")); line.Append(VOID_Data.atmDensity.Value.ToString("G3"));
line.Append(';'); line.Append(',');
   
// Downrange Distance // Downrange Distance
line.Append((VOID_Data.downrangeDistance.Value.ToString("G3"))); line.Append((VOID_Data.downrangeDistance.Value.ToString("G3")));
line.Append(';');  
   
line.Append('\n'); line.Append('\n');
   
csvList.Add(line.ToString()); csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
   
csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
   
  #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.logInterval = 0.5f;
  this.csvCollectTimer = 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
} }
} }
   
   
// VOID // VOID
// //
// VOID_DataValue.cs // VOID_DataValue.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using System; using System;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public interface IVOID_DataValue public interface IVOID_DataValue
{ {
  string Label { get; }
  string Units { get; }
  object Value { get; }
   
void Refresh(); void Refresh();
string ValueUnitString(); string ValueUnitString();
void DoGUIHorizontal(); void DoGUIHorizontal();
} }
   
public class VOID_DataValue<T> : IVOID_DataValue public class VOID_DataValue<T> : IVOID_DataValue
{ {
/* /*
* Static Members * Static Members
* */ * */
public static implicit operator T(VOID_DataValue<T> v) public static implicit operator T(VOID_DataValue<T> v)
{ {
return (T)v.Value; return (T)v.Value;
} }
   
/* /*
* Instance Members * Instance Members
* */ * */
/* /*
* Fields * Fields
* */ * */
protected T cache; protected T cache;
protected Func<T> ValueFunc; protected Func<T> ValueFunc;
protected float lastUpdate; protected float lastUpdate;
   
/* /*
* Properties * Properties
* */ * */
public string Label { get; protected set; } public string Label { get; protected set; }
public string Units { get; protected set; } public string Units { get; protected set; }
   
  object IVOID_DataValue.Value
  {
  get
  {
  return (object)this.Value;
  }
  }
   
public T Value public T Value
{ {
get get
{ {
if ( if (
HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsEditor ||
(VOID_Core.Instance.updateTimer - this.lastUpdate > VOID_Core.Instance.updatePeriod) || (VOID_Data.Core.updateTimer - this.lastUpdate > VOID_Data.Core.updatePeriod) ||
(this.lastUpdate > VOID_Core.Instance.updateTimer) (this.lastUpdate > VOID_Data.Core.updateTimer)
) )
{ {
this.Refresh(); this.Refresh();
} }
return (T)this.cache; return (T)this.cache;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_DataValue(string Label, Func<T> ValueFunc, string Units = "") public VOID_DataValue(string Label, Func<T> ValueFunc, string Units = "")
{ {
this.Label = Label; this.Label = Label;
this.Units = Units; this.Units = Units;
this.ValueFunc = ValueFunc; this.ValueFunc = ValueFunc;
this.lastUpdate = 0; this.lastUpdate = 0;
   
  VOID_Data.DataValues[this.GetHashCode()] = this;
} }
   
public void Refresh() public void Refresh()
{ {
this.cache = this.ValueFunc.Invoke (); this.cache = this.ValueFunc.Invoke ();
this.lastUpdate = VOID_Core.Instance.updateTimer; this.lastUpdate = VOID_Data.Core.updateTimer;
} }
   
public T GetFreshValue() public T GetFreshValue()
{ {
this.Refresh (); this.Refresh ();
return (T)this.cache; return (T)this.cache;
} }
   
public virtual string ValueUnitString() { public virtual string ValueUnitString() {
return this.Value.ToString() + this.Units; return this.Value.ToString() + this.Units;
} }
   
public virtual void DoGUIHorizontal() public virtual void DoGUIHorizontal()
{ {
GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
GUILayout.Label (this.Label + ":"); GUILayout.Label (this.Label + ":");
GUILayout.FlexibleSpace (); GUILayout.FlexibleSpace ();
GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false)); GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false));
GUILayout.EndHorizontal (); GUILayout.EndHorizontal ();
  }
   
  public override int GetHashCode()
  {
  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() public override string ToString()
{ {
return string.Format ( return string.Format (
"{0}: {1}{2}", "{0}: {1}{2}",
this.Label, this.Label,
this.Value.ToString (), this.Value.ToString (),
this.Units this.Units
); );
} }
} }
   
public abstract class VOID_NumValue<T> : VOID_DataValue<T> public abstract class VOID_NumValue<T> : VOID_DataValue<T>
where T : IFormattable, IConvertible, IComparable where T : IFormattable, IConvertible, IComparable
{ {
public static implicit operator Double(VOID_NumValue<T> v) public static implicit operator Double(VOID_NumValue<T> v)
{ {
return v.ToDouble(); return v.ToDouble();
} }
   
public static implicit operator Int32(VOID_NumValue<T> v) public static implicit operator Int32(VOID_NumValue<T> v)
{ {
return v.ToInt32(); return v.ToInt32();
} }
   
   
public static implicit operator Single(VOID_NumValue<T> v) public static implicit operator Single(VOID_NumValue<T> v)
{ {
return v.ToSingle(); return v.ToSingle();
} }
   
protected IFormatProvider formatProvider; protected IFormatProvider formatProvider;
   
public VOID_NumValue(string Label, Func<T> ValueFunc, string Units = "") : base(Label, ValueFunc, Units) public VOID_NumValue(string Label, Func<T> ValueFunc, string Units = "") : base(Label, ValueFunc, Units)
{ {
this.formatProvider = System.Globalization.CultureInfo.CurrentUICulture; this.formatProvider = System.Globalization.CultureInfo.CurrentUICulture;
} }
   
public virtual double ToDouble(IFormatProvider provider) public virtual double ToDouble(IFormatProvider provider)
{ {
return this.Value.ToDouble(provider); return this.Value.ToDouble(provider);
} }
   
public virtual double ToDouble() public virtual double ToDouble()
{ {
return this.ToDouble(this.formatProvider); return this.ToDouble(this.formatProvider);
} }
   
public virtual int ToInt32(IFormatProvider provider) public virtual int ToInt32(IFormatProvider provider)
{ {
return this.Value.ToInt32(provider); return this.Value.ToInt32(provider);
} }
   
public virtual int ToInt32() public virtual int ToInt32()
{ {
return this.ToInt32(this.formatProvider); return this.ToInt32(this.formatProvider);
} }
   
public virtual float ToSingle(IFormatProvider provider) public virtual float ToSingle(IFormatProvider provider)
{ {
return this.Value.ToSingle(provider); return this.Value.ToSingle(provider);
} }
   
public virtual float ToSingle() public virtual float ToSingle()
{ {
return this.ToSingle(this.formatProvider); return this.ToSingle(this.formatProvider);
} }
   
public virtual string ToString(string Format) public virtual string ToString(string Format)
{ {
return string.Format ( return string.Format (
"{0}: {1}{2}", "{0}: {1}{2}",
this.Label, this.Label,
this.Value.ToString(Format, this.formatProvider), this.Value.ToString(Format, this.formatProvider),
this.Units this.Units
); );
} }
   
public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue) public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue)
{ {
return string.Format ( return string.Format (
"{0}{1}", "{0}{1}",
Tools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude), Tools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude),
this.Units this.Units
); );
} }
   
public virtual string ValueUnitString(string format) public virtual string ValueUnitString(string format)
{ {
return this.Value.ToString(format, this.formatProvider) + this.Units; return this.Value.ToString(format, this.formatProvider) + this.Units;
} }
public virtual string ValueUnitString(int digits) { public virtual string ValueUnitString(int digits) {
return Tools.MuMech_ToSI(this, digits) + this.Units; return Tools.MuMech_ToSI(this, digits) + this.Units;
} }
   
public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude) public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude)
{ {
return Tools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units; return Tools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units;
} }
   
public virtual void DoGUIHorizontal(string format) public virtual void DoGUIHorizontal(string format)
{ {
GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
GUILayout.Label (this.Label + ":"); GUILayout.Label (this.Label + ":");
GUILayout.FlexibleSpace (); GUILayout.FlexibleSpace ();
GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false)); GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false));
GUILayout.EndHorizontal (); GUILayout.EndHorizontal ();
} }
   
public virtual int DoGUIHorizontal(int digits, bool precisionButton = true) public virtual int DoGUIHorizontal(int digits, bool precisionButton = true)
{ {
if (precisionButton) if (precisionButton)
{ {
return this.DoGUIHorizontalPrec(digits); return this.DoGUIHorizontalPrec(digits);
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true)); GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
return digits; return digits;
} }
   
public virtual int DoGUIHorizontalPrec(int digits) public virtual int DoGUIHorizontalPrec(int digits)
{ {
double magnitude; double magnitude;
double magLimit; double magLimit;
   
magnitude = Math.Log10(Math.Abs((double)this)); magnitude = Math.Log10(Math.Abs((double)this));
   
magLimit = Math.Max(Math.Abs(magnitude), 3d) + 3d; magLimit = Math.Max(Math.Abs(magnitude), 3d) + 3d;
magLimit = Math.Round(Math.Ceiling(magLimit / 3f)) * 3d; magLimit = Math.Round(Math.Ceiling(magLimit / 3f)) * 3d;
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true)); GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
   
if (magnitude >= 0) if (magnitude >= 0)
{ {
GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(3, int.MinValue, (int)magnitude - digits), GUILayout.ExpandWidth(false));
} }
else else
{ {
GUILayout.Label(this.ValueUnitString(3, (int)magnitude + digits, int.MaxValue), GUILayout.ExpandWidth(false)); GUILayout.Label(this.ValueUnitString(3, (int)magnitude + digits, int.MaxValue), GUILayout.ExpandWidth(false));
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (Event.current.type == EventType.mouseUp) if (Event.current.type == EventType.mouseUp)
{ {
Rect lastRect = GUILayoutUtility.GetLastRect(); Rect lastRect = GUILayoutUtility.GetLastRect();
if (lastRect.Contains(Event.current.mousePosition)) if (lastRect.Contains(Event.current.mousePosition))
{ {
Tools.PostDebugMessage(string.Format("{0}: Changing digits from {1} within magLimit {2}.", Tools.PostDebugMessage(string.Format("{0}: Changing digits from {1} within magLimit {2}.",
this.GetType().Name, this.GetType().Name,
digits, digits,
magLimit)); magLimit));
   
if (Event.current.button == 0) if (Event.current.button == 0)
{ {
digits = (digits + 3) % (int)magLimit; digits = (digits + 3) % (int)magLimit;
} }
else if (Event.current.button == 1) else if (Event.current.button == 1)
{ {
digits = (digits - 3) % (int)magLimit; digits = (digits - 3) % (int)magLimit;
} }
   
if (digits < 0) if (digits < 0)
{ {
digits += (int)magLimit; digits += (int)magLimit;
} }
   
Tools.PostDebugMessage(string.Format("{0}: Changed digits to {1}." + Tools.PostDebugMessage(string.Format("{0}: Changed digits to {1}." +
"\n\tNew minMagnitude: {2}, maxMagnitude: {3}" + "\n\tNew minMagnitude: {2}, maxMagnitude: {3}" +
"\n\tMagnitude: {4}", "\n\tMagnitude: {4}",
this.GetType().Name, this.GetType().Name,
digits, digits,
magnitude >= 0 ? int.MinValue : (int)magnitude - 4 + digits, magnitude >= 0 ? int.MinValue : (int)magnitude - 4 + digits,
magnitude >= 0 ? (int)magnitude - digits : int.MaxValue, magnitude >= 0 ? (int)magnitude - digits : int.MaxValue,
magnitude magnitude
)); ));
} }
} }
   
return digits; return digits;
} }
} }
   
public class VOID_DoubleValue : VOID_NumValue<double> public class VOID_DoubleValue : VOID_NumValue<double>
{ {
public VOID_DoubleValue(string Label, Func<double> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_DoubleValue(string Label, Func<double> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_FloatValue : VOID_NumValue<float> public class VOID_FloatValue : VOID_NumValue<float>
{ {
public VOID_FloatValue(string Label, Func<float> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_FloatValue(string Label, Func<float> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_IntValue : VOID_NumValue<int> public class VOID_IntValue : VOID_NumValue<int>
{ {
public VOID_IntValue(string Label, Func<int> ValueFunc, string Units) : base(Label, ValueFunc, Units) {} public VOID_IntValue(string Label, Func<int> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
} }
   
public class VOID_StrValue : VOID_DataValue<string> public class VOID_StrValue : VOID_DataValue<string>
{ {
public VOID_StrValue(string Label, Func<string> ValueFunc) : base(Label, ValueFunc, "") {} public VOID_StrValue(string Label, Func<string> ValueFunc) : base(Label, ValueFunc, "") {}
} }
   
public class VOID_Vector3dValue : VOID_DataValue<Vector3d> public class VOID_Vector3dValue : VOID_DataValue<Vector3d>
{ {
public VOID_Vector3dValue(string Label, Func<Vector3d> ValueFunc, string Units) public VOID_Vector3dValue(string Label, Func<Vector3d> ValueFunc, string Units)
: base(Label, ValueFunc, Units) : base(Label, ValueFunc, Units)
{} {}
   
public string ToString(string format) public string ToString(string format)
{ {
return string.Format("{0}: {1}{2}", return string.Format("{0}: {1}{2}",
this.Label, this.Label,
this.Value.ToString(format), this.Value.ToString(format),
this.Units this.Units
); );
} }
   
public string ValueUnitString(string format) { public string ValueUnitString(string format) {
return this.Value.ToString(format) + this.Units; return this.Value.ToString(format) + this.Units;
} }
} }
} }
   
   
file:a/VOID_EditorCore.cs (deleted)
// VOID  
//  
// VOID_EditorCore.cs  
//  
// Copyright © 2014, toadicus  
// All rights reserved.  
//  
// Redistribution and use in source and binary forms, with or without modification,  
// are permitted provided that the following conditions are met:  
//  
// 1. Redistributions of source code must retain the above copyright notice,  
// this list of conditions and the following disclaimer.  
//  
// 2. Redistributions in binary form must reproduce the above copyright notice,  
// this list of conditions and the following disclaimer in the documentation and/or other  
// materials provided with the distribution.  
//  
// 3. Neither the name of the copyright holder nor the names of its contributors may be used  
// to endorse or promote products derived from this software without specific prior written permission.  
//  
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 
using Engineer.VesselSimulator;  
using KSP;  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using ToadicusTools;  
using UnityEngine;  
 
namespace VOID  
{  
public class VOID_EditorCore : VOID_Core  
{  
/*  
* Static Members  
* */  
protected new static bool _initialized = false;  
public new static bool Initialized  
{  
get  
{  
return _initialized;  
}  
}  
 
protected new static VOID_EditorCore _instance;  
public new static VOID_EditorCore Instance  
{  
get  
{  
if (_instance == null)  
{  
_instance = new VOID_EditorCore();  
_initialized = true;  
}  
return _instance;  
}  
}  
 
public new static void Reset()  
{  
if (_initialized)  
{  
_instance.StopGUI();  
_instance.Dispose();  
_instance = null;  
_initialized = false;  
}  
}  
 
protected override ApplicationLauncher.AppScenes appIconVisibleScenes  
{  
get  
{  
return ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH;  
}  
}  
 
public VOID_EditorCore() : base()  
{  
this._Name = "VOID Editor Core";  
}  
 
public override void OnGUI() {}  
 
public override void DrawGUI()  
{  
if (!this._modulesLoaded)  
{  
this.LoadModulesOfType<IVOID_EditorModule>();  
}  
 
Rect _iconPos = Tools.DockToWindow (this.VOIDIconPos, this.mainWindowPos);  
 
_iconPos = Tools.ClampRectToEditorPad (_iconPos);  
 
if (_iconPos != this.VOIDIconPos)  
{  
this.VOIDIconPos = _iconPos;  
}  
 
base.DrawGUI();  
}  
 
public override void Update()  
{  
this.LoadBeforeUpdate();  
 
foreach (IVOID_EditorModule module in this.Modules)  
{  
if (EditorLogic.startPod == null)  
{  
module.StopGUI();  
continue;  
}  
if (HighLogic.LoadedSceneIsEditor && module.toggleActive && EditorLogic.SortedShipList.Any())  
{  
module.StartGUI();  
}  
if (!HighLogic.LoadedSceneIsEditor || !module.toggleActive || !EditorLogic.SortedShipList.Any())  
{  
module.StopGUI();  
}  
}  
 
if (EditorLogic.startPod == null || !HighLogic.LoadedSceneIsEditor)  
{  
this.StopGUI();  
return;  
}  
else if (!this.guiRunning && HighLogic.LoadedSceneIsEditor)  
{  
this.StartGUI();  
}  
 
if (EditorLogic.SortedShipList.Count > 0 && this.vesselSimActive)  
{  
Tools.PostDebugMessage(this, "Updating SimManager.");  
this.UpdateSimManager();  
}  
 
this.CheckAndSave ();  
}  
 
public override void FixedUpdate() {}  
}  
}  
 
 
// VOID // VOID
// //
// VOID_EditorHUD.cs // VOID_EditorHUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using Engineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_EditorHUD : VOID_Module, IVOID_EditorModule [VOID_Scenes(GameScenes.EDITOR)]
  public class VOID_EditorHUD : VOID_HUDModule
{ {
/* /*
* Fields * Fields
* */ * */
[AVOID_SaveValue("colorIndex")] protected HUDWindow ehudWindow;
protected VOID_SaveValue<int> _colorIndex = 0;  
   
protected List<Color> textColors = new List<Color>();  
   
protected GUIStyle labelStyle;  
   
protected EditorVesselOverlays _vesselOverlays; protected EditorVesselOverlays _vesselOverlays;
   
  [AVOID_SaveValue("snapToLeft")]
  protected VOID_SaveValue<bool> snapToLeft;
   
/* /*
* Properties * 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 protected EditorVesselOverlays vesselOverlays
{ {
get get
{ {
if (this._vesselOverlays == null) if (this._vesselOverlays == null)
{ {
this._vesselOverlays = (EditorVesselOverlays)Resources this._vesselOverlays = (EditorVesselOverlays)Resources
.FindObjectsOfTypeAll(typeof(EditorVesselOverlays)) .FindObjectsOfTypeAll(typeof(EditorVesselOverlays))
.FirstOrDefault(); .FirstOrDefault();
} }
   
return this._vesselOverlays; return this._vesselOverlays;
} }
} }
   
protected EditorMarker_CoM CoMmarker protected EditorMarker_CoM CoMmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoMmarker; return this.vesselOverlays.CoMmarker;
} }
} }
   
protected EditorMarker_CoT CoTmarker protected EditorMarker_CoT CoTmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoTmarker; return this.vesselOverlays.CoTmarker;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_EditorHUD() : base() public VOID_EditorHUD() : base()
{ {
this._Name = "Heads-Up Display"; this._Name = "Heads-Up Display";
   
this.toggleActive = true; this.toggleActive = true;
   
this.textColors.Add(Color.green); this.snapToLeft.value = true;
this.textColors.Add(Color.black);  
this.textColors.Add(Color.white); this.ehudWindow = new HUDWindow(
this.textColors.Add(Color.red); "editorHUD",
this.textColors.Add(Color.blue); this.ehudWindowFunc,
this.textColors.Add(Color.yellow); new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f)
this.textColors.Add(Color.gray); );
this.textColors.Add(Color.cyan); this.Windows.Add(this.ehudWindow);
this.textColors.Add(Color.magenta);  
   
this.labelStyle = new GUIStyle ();  
// this.labelStyle.alignment = TextAnchor.UpperRight;  
this.labelStyle.normal.textColor = this.textColors [this.ColorIndex];  
   
Tools.PostDebugMessage (this.GetType().Name + ": Constructed."); Tools.PostDebugMessage (this.GetType().Name + ": Constructed.");
} }
   
public override void DrawGUI() public void ehudWindowFunc(int id)
{ {
SimManager.RequestSimulation(); StringBuilder hudString = new StringBuilder();
   
if (this.core.LastStage == null) if (this.core.LastStage == null)
{ {
return; return;
} }
   
float hudLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
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;  
}  
   
GUI.skin = this.core.Skin;  
   
Rect hudPos = new Rect (hudLeft, 48, 300, 32);  
   
hudString = new StringBuilder();  
   
// GUI.skin = AssetBase.GetGUISkin("KSP window 2");  
   
labelStyle.normal.textColor = textColors [ColorIndex];  
   
hudString.Append("Total Mass: "); hudString.Append("Total Mass: ");
hudString.Append(this.core.LastStage.totalMass.ToString("F3")); hudString.Append(this.core.LastStage.totalMass.ToString("F3"));
hudString.Append('t'); hudString.Append('t');
   
hudString.Append(' '); hudString.Append(' ');
   
hudString.Append("Part Count: "); hudString.Append("Part Count: ");
hudString.Append(EditorLogic.SortedShipList.Count); hudString.Append(EditorLogic.SortedShipList.Count);
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Total Delta-V: "); hudString.Append("Total Delta-V: ");
hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.totalDeltaV)); hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.totalDeltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage Delta-V"); hudString.Append("Bottom Stage Delta-V");
hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.deltaV)); hudString.Append(Tools.MuMech_ToSI(this.core.LastStage.deltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage T/W Ratio: "); hudString.Append("Bottom Stage T/W Ratio: ");
hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3")); hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3"));
   
  Tools.PostDebugMessage(this,
  "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) 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('\n');
   
hudString.Append("Thrust Offset: "); hudString.Append("Thrust Offset: ");
hudString.Append( hudString.Append(
Vector3.Cross( Vector3.Cross(
this.CoTmarker.dirMarkerObject.transform.forward, this.CoTmarker.dirMarkerObject.transform.forward,
this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position
).ToString("F3")); ).ToString("F3"));
} }
  #if DEBUG
GUI.Label ( else
hudPos, {
  Tools.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped.");
  }
  #endif
   
  GUILayout.Label(
hudString.ToString(), hudString.ToString(),
labelStyle); VOID_Styles.labelHud,
} GUILayout.ExpandWidth(true),
  GUILayout.ExpandHeight(true)
public override void DrawConfigurables() );
{  
if (GUILayout.Button ("Change HUD color", GUILayout.ExpandWidth (false))) if (!this.positionsLocked)
{ {
++this.ColorIndex; GUI.DragWindow();
} }
   
  GUI.BringWindowToBack(id);
  }
   
  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 = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f;
} }
} }
} }
   
// VOID // VOID
// //
// VOID_HUD.cs // VOID_HUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using Engineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_HUD : VOID_Module, IVOID_Module public class VOID_HUD : VOID_HUDModule, IVOID_Module
{ {
/* /*
* Fields * Fields
* */ * */
[AVOID_SaveValue("colorIndex")] protected HUDWindow leftHUD;
protected VOID_SaveValue<int> _colorIndex; protected HUDWindow rightHUD;
   
protected List<Color> textColors;  
   
protected Rect leftHUDdefaultPos;  
protected Rect rightHUDdefaultPos;  
   
[AVOID_SaveValue("leftHUDPos")]  
protected VOID_SaveValue<Rect> leftHUDPos;  
[AVOID_SaveValue("rightHUDPos")]  
protected VOID_SaveValue<Rect> rightHUDPos;  
   
[AVOID_SaveValue("positionsLocked")]  
protected VOID_SaveValue<bool> positionsLocked;  
   
/* /*
* Properties * Properties
* */ * */
public int ColorIndex  
{  
get  
{  
return this._colorIndex;  
}  
set  
{  
if (this._colorIndex >= this.textColors.Count - 1)  
{  
this._colorIndex = 0;  
return;  
}  
   
this._colorIndex = value;  
}  
}  
   
/* /*
* Methods * Methods
* */ * */
public VOID_HUD() : base() public VOID_HUD() : base()
{ {
this._Name = "Heads-Up Display"; this._Name = "Heads-Up Display";
   
this.toggleActive = true; this.toggleActive = 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<Color>(); this.rightHUD = new HUDWindow("rightHUD", this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f));
  this.Windows.Add(this.rightHUD);
this.textColors.Add(Color.green);  
this.textColors.Add(Color.black);  
this.textColors.Add(Color.white);  
this.textColors.Add(Color.red);  
this.textColors.Add(Color.blue);  
this.textColors.Add(Color.yellow);  
this.textColors.Add(Color.gray);  
this.textColors.Add(Color.cyan);  
this.textColors.Add(Color.magenta);  
   
this.leftHUDdefaultPos = new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f);  
this.leftHUDPos = new Rect(this.leftHUDdefaultPos);  
   
this.rightHUDdefaultPos = new Rect(Screen.width * .625f, 0f, 300f, 90f);  
this.rightHUDPos = new Rect(this.rightHUDdefaultPos);  
   
this.positionsLocked = true;  
   
Tools.PostDebugMessage ("VOID_HUD: Constructed."); Tools.PostDebugMessage ("VOID_HUD: Constructed.");
} }
   
protected void leftHUDWindow(int id) protected void leftHUDWindow(int id)
{ {
StringBuilder leftHUD; StringBuilder leftHUD;
   
leftHUD = new StringBuilder(); leftHUD = new StringBuilder();
   
this.core.LabelStyles["hud"].alignment = TextAnchor.UpperRight; VOID_Styles.labelHud.alignment = TextAnchor.UpperRight;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
leftHUD.AppendFormat("Primary: {0} Inc: {1}", leftHUD.AppendFormat("Primary: {0} Inc: {1}",
VOID_Data.primaryName.ValueUnitString(), VOID_Data.primaryName.ValueUnitString(),
VOID_Data.orbitInclination.ValueUnitString("F3") VOID_Data.orbitInclination.ValueUnitString("F3")
); );
leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}", leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}",
VOID_Data.orbitAltitude.ToSIString(), VOID_Data.orbitAltitude.ToSIString(),
VOID_Data.orbitVelocity.ToSIString() VOID_Data.orbitVelocity.ToSIString()
); );
leftHUD.AppendFormat("\nAp: {0} ETA {1}", leftHUD.AppendFormat("\nAp: {0} ETA {1}",
VOID_Data.orbitApoAlt.ToSIString(), VOID_Data.orbitApoAlt.ToSIString(),
VOID_Data.timeToApo.ValueUnitString() VOID_Data.timeToApo.ValueUnitString()
); );
leftHUD.AppendFormat("\nPe: {0} ETA {1}", leftHUD.AppendFormat("\nPe: {0} ETA {1}",
VOID_Data.oribtPeriAlt.ToSIString(), VOID_Data.oribtPeriAlt.ToSIString(),
VOID_Data.timeToPeri.ValueUnitString() VOID_Data.timeToPeri.ValueUnitString()
); );
leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}", leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}",
VOID_Data.totalDeltaV.ToSIString(2), VOID_Data.totalDeltaV.ToSIString(2),
VOID_Data.stageDeltaV.ToSIString(2) VOID_Data.stageDeltaV.ToSIString(2)
); );
} }
else else
{ {
this.core.LabelStyles["hud"].normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
leftHUD.Append(string.Intern("-- POWER LOST --")); leftHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
GUILayout.Label(leftHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); GUILayout.Label(
  leftHUD.ToString(),
  VOID_Styles.labelHud,
  GUILayout.ExpandWidth(true),
  GUILayout.ExpandHeight(true)
  );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
   
protected void rightHUDWindow(int id) protected void rightHUDWindow(int id)
{ {
StringBuilder rightHUD; StringBuilder rightHUD;
   
rightHUD = new StringBuilder(); rightHUD = new StringBuilder();
   
this.core.LabelStyles["hud"].alignment = TextAnchor.UpperLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
rightHUD.AppendFormat("Biome: {0} Sit: {1}", rightHUD.AppendFormat("Biome: {0} Sit: {1}",
VOID_Data.currBiome.ValueUnitString(), VOID_Data.currBiome.ValueUnitString(),
VOID_Data.expSituation.ValueUnitString() VOID_Data.expSituation.ValueUnitString()
); );
rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}", rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}",
VOID_Data.trueAltitude.ToSIString(), VOID_Data.trueAltitude.ToSIString(),
VOID_Data.surfVelocity.ToSIString() VOID_Data.surfVelocity.ToSIString()
); );
rightHUD.AppendFormat("\nVer: {0} Hor: {1}", rightHUD.AppendFormat("\nVer: {0} Hor: {1}",
VOID_Data.vertVelocity.ToSIString(), VOID_Data.vertVelocity.ToSIString(),
VOID_Data.horzVelocity.ToSIString() VOID_Data.horzVelocity.ToSIString()
); );
rightHUD.AppendFormat("\nLat: {0} Lon: {1}", rightHUD.AppendFormat("\nLat: {0} Lon: {1}",
VOID_Data.surfLatitude.ValueUnitString(), VOID_Data.surfLatitude.ValueUnitString(),
VOID_Data.surfLongitude.ValueUnitString() VOID_Data.surfLongitude.ValueUnitString()
); );
rightHUD.AppendFormat("\nHdg: {0} Pit: {1}", rightHUD.AppendFormat("\nHdg: {0} Pit: {1}",
VOID_Data.vesselHeading.ValueUnitString(), VOID_Data.vesselHeading.ValueUnitString(),
VOID_Data.vesselPitch.ToSIString(2) VOID_Data.vesselPitch.ToSIString(2)
); );
   
if ( if (
this.core.vessel.mainBody == this.core.Kerbin && this.core.vessel.mainBody == this.core.HomeBody &&
( (
this.core.vessel.situation == Vessel.Situations.FLYING || this.core.vessel.situation == Vessel.Situations.FLYING ||
this.core.vessel.situation == Vessel.Situations.SUB_ORBITAL || this.core.vessel.situation == Vessel.Situations.SUB_ORBITAL ||
this.core.vessel.situation == Vessel.Situations.LANDED || this.core.vessel.situation == Vessel.Situations.LANDED ||
this.core.vessel.situation == Vessel.Situations.SPLASHED this.core.vessel.situation == Vessel.Situations.SPLASHED
) )
) )
{ {
rightHUD.AppendFormat("\nRange to KSC: {0}", VOID_Data.downrangeDistance.ValueUnitString(2)); rightHUD.AppendFormat("\nRange to KSC: {0}", VOID_Data.downrangeDistance.ValueUnitString(2));
} }
} }
else else
{ {
this.core.LabelStyles["hud"].normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
rightHUD.Append(string.Intern("-- POWER LOST --")); rightHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
   
GUILayout.Label(rightHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true)); GUILayout.Label(
  rightHUD.ToString(),
  VOID_Styles.labelHud,
  GUILayout.ExpandWidth(true),