Browse Source

first version

master
Youen Toupin 9 years ago
parent
commit
41bc63965a
  1. 1
      .gitignore
  2. 22
      Aerostats.sln
  3. 36
      Parts/Balloon/balloon.cfg
  4. BIN
      Parts/Balloon/model.mu
  5. BIN
      Parts/Balloon/model000.dds
  6. BIN
      Parts/Balloon/model001.dds
  7. 62
      Plugin/Aerostats.csproj
  8. 185
      Plugin/ModuleAerostat.cs
  9. 36
      Plugin/Properties/AssemblyInfo.cs
  10. 19
      Plugin/Util.cs

1
.gitignore vendored

@ -0,0 +1 @@
/*.suo

22
Aerostats.sln

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aerostats", "Plugin/Aerostats.csproj", "{086EA143-7591-4B21-9666-5204900A0C7D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{086EA143-7591-4B21-9666-5204900A0C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{086EA143-7591-4B21-9666-5204900A0C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{086EA143-7591-4B21-9666-5204900A0C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{086EA143-7591-4B21-9666-5204900A0C7D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

36
Parts/Balloon/balloon.cfg

@ -0,0 +1,36 @@
PART
{
name = balloon
module = Part
author = Youen
mesh = model.mu
scale = 0.1
rescaleFactor = 1
node_stack_bottom = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0, 1
node_attach = 0.0, -0.020649, 0.0, 0.0, -1.0, 0.0
sound_parachute_open = activate
TechRequired = advLanding
entryCost = 3500
cost = 400
category = Utility
subcategory = 0
title = Balloon
description = A test balloon.
attachRules = 1,0,0,1,0
mass = 0.2
dragModelType = default
angularDrag = 3
crashTolerance = 12
maxTemp = 2000 // = 3100
breakingForce = 100
breakingTorque = 50
bodyLiftMultiplier = 0
stageOffset = -1
bulkheadProfiles = size1, srf
MODULE
{
name = ModuleAerostat
DeployAnimation = semiDeployLarge
InflateAnimation = fullyDeployLarge
}
}

BIN
Parts/Balloon/model.mu

Binary file not shown.

BIN
Parts/Balloon/model000.dds

Binary file not shown.

BIN
Parts/Balloon/model001.dds

Binary file not shown.

62
Plugin/Aerostats.csproj

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{086EA143-7591-4B21-9666-5204900A0C7D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Aerostats</RootNamespace>
<AssemblyName>Aerostats</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\1.0_dev\GameData\Aerostats\Plugin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Assembly-CSharp">
<HintPath>..\..\1.0_dev\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="UnityEngine">
<HintPath>..\..\1.0_dev\KSP_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ModuleAerostat.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Util.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

185
Plugin/ModuleAerostat.cs

@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Aerostats
{
public class ModuleAerostat : PartModule
{
[KSPField(isPersistant = false, guiActive = false)]
public string DeployAnimation = "semiDeploy";
[KSPField(isPersistant = false, guiActive = false)]
public string InflateAnimation = "fullyDeploy";
// In this class, amount of gas Q is specified in m^3 at stp (standard pressure of 100kPa and temperature of 0°C = 273K). Ideal gas equation P.V = n.R.T gives us the equivalent number of moles: n = P.V/R/T = 100000.Q/8.314/273 = 44.Q mol
private static readonly float R = 8.314f;
private static readonly float StpVolumeToMoles = 100000.0f / R / 273.15f;
/// <summary>
/// Maximum rate at which gas can be injected in the balloon to fill it, in m^3/s at stp
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float MaxGasFillRate = 100;
/// <summary>
/// Maximum rate at which gas can be removed from the balloon to deflate it, in m^3/s at stp
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float MaxGasVentRate = 500;
/// <summary>
/// Volume at which the balloon is full. Trying to add more gas, or simply having already stored gas expand due to lower exterior pressure or increased temperature, will cause gas to be vented through the security valve.
/// Air density at sea level is about 1.2kg/m^3, which means a 1000m^3 balloon will be able to lift about 1 ton at sea level (after substracting the balloon gas weight)
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float MaxBalloonVolume = 10000;
/// <summary>
/// Maximum initial reserve of compressed gas, in m^3 at stp
/// For helium, the volume needed to store this reserve is about 0.0014m^3 of compressed storage (liquid) for 1m^3 of gas at stp
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float CompressedGasStorage = 15000;
[KSPField(isPersistant = true, guiActive = true)]
public float RemainingCompressedGas = 15000;
/// <summary>
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Helium is 179g/m^3
/// Hydrogen is 90g/m^3
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float GasDensity = 0.179f;
/// <summary>
/// Quantity of gas that the system is trying to get inside the balloon, in m^3 at 100kPa and 0°C. If the balloon contains more gas, some will be vented, otherwise, gas will be injected.
/// If the balloon can not store the target amount of gas (because the maximum volume has been reached), the system won't try to inject more gas, to avoid venting through the security valve of the balloon.
/// </summary>
[KSPField(isPersistant = true, guiActive = true)]
[UI_FloatRange(minValue = 0.0f, maxValue = 20000.0f, stepIncrement = 1.0f)]
public float LiftingGasTargetQuantity;
private bool Staged;
/// <summary>
/// Gas quantity currently inside the balloon
/// </summary>
[KSPField(isPersistant = true, guiActive = true)]
public float LiftingGasQuantity;
/// <summary>
/// Inflation ratio of the balloon (0=empty, 1=maximum)
/// </summary>
private float Inflation = 0;
private void PlayAnimation(string animationName, float animationSpeed)
{
foreach (Animation animation in part.FindModelAnimators(animationName))
{
AnimationState state = animation[animationName];
state.normalizedTime = 0;
state.normalizedSpeed = animationSpeed;
state.enabled = true;
animation.Play(animationName);
}
}
private bool IsAnimationPlaying(string animationName)
{
return part.FindModelAnimators(animationName).Any(a => a[animationName].enabled);
}
private void SetInflation(float ratio)
{
foreach (Animation animation in part.FindModelAnimators(InflateAnimation))
{
AnimationState state = animation[InflateAnimation];
state.normalizedTime = ratio;
state.normalizedSpeed = 0;
state.enabled = true;
animation.Play(InflateAnimation);
}
}
public override void OnStart(PartModule.StartState state)
{
if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { return; }
ScreenMessages.PostScreenMessage("Aerostat loaded");
part.stagingIcon = "PARACHUTES";
}
private void OnStaged()
{
UnityEngine.Debug.Log("Aerostats: staged");
ScreenMessages.PostScreenMessage("staged");
PlayAnimation(DeployAnimation, 1.0f);
}
private void FixedUpdate()
{
if (!Staged && part.inverseStage >= Staging.CurrentStage)
{
Staged = true;
OnStaged();
}
if (Staged)
{
if (!IsAnimationPlaying(DeployAnimation))
{
float externalTemperature = (float)FlightGlobals.getExternalTemperature();
float balloonInternalTemperature = externalTemperature;
float externalPressure = Math.Max((float)FlightGlobals.getStaticPressure() * 1000, 0.00001f);
Util.PostSingleScreenMessage("external atmo", "Temperature = " + externalTemperature + "K, Pressure=" + externalPressure + "Pa");
float currentMaxQuantity = MaxBalloonVolume / R / balloonInternalTemperature * externalPressure / StpVolumeToMoles;
if(LiftingGasTargetQuantity > LiftingGasQuantity)
{
float stepFinalQuantity = Math.Min(LiftingGasQuantity + MaxGasFillRate * Time.fixedDeltaTime, Math.Min(LiftingGasTargetQuantity, currentMaxQuantity));
float step = Math.Max(stepFinalQuantity - LiftingGasQuantity, 0.0f);
LiftingGasQuantity += step;
RemainingCompressedGas -= step;
if(RemainingCompressedGas < 0)
{
Util.PostSingleScreenMessage("out of gas", "Lifting gas reserve exhausted");
LiftingGasQuantity += RemainingCompressedGas;
RemainingCompressedGas = 0;
}
}
else
{
LiftingGasQuantity = Math.Max(LiftingGasQuantity - MaxGasVentRate * Time.fixedDeltaTime, LiftingGasTargetQuantity);
}
// balloon security valve
if (LiftingGasQuantity > currentMaxQuantity)
{
Util.PostSingleScreenMessage("security valve", "Some gas has been vented by the balloon security valve");
LiftingGasQuantity = currentMaxQuantity;
}
float currentGasMoles = StpVolumeToMoles * LiftingGasQuantity;
float currentGasVolume = currentGasMoles * R * balloonInternalTemperature / externalPressure;
Inflation = currentGasVolume / MaxBalloonVolume;
Util.PostSingleScreenMessage("inflation", "Inflation = " + (Inflation * 100.0f).ToString("0.00") + "%");
SetInflation(Inflation);
float airDensity = (float)FlightGlobals.getAtmDensity(externalPressure / 1000.0f, externalTemperature, vessel.mainBody);
float balloonLift = currentGasVolume * (airDensity - GasDensity);
Util.PostSingleScreenMessage("lift", "Air density = " + airDensity + "kg/m^3, Lift = " + balloonLift + "kg");
var gravityAccel = FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D());
//Util.PostSingleScreenMessage("gravity", "Gravity accel = (" + gravityAccel.x + ", " + gravityAccel.y + ", " + gravityAccel.z + ")");
part.Rigidbody.AddForce(-gravityAccel * balloonLift / 1000.0f, ForceMode.Force);
}
}
}
}
}

36
Plugin/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Aerostats")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Aerostats")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2f05e8bf-ff36-4fe3-b4ed-479eeadb2f9d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

19
Plugin/Util.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Aerostats
{
static class Util
{
private static Dictionary<string, ScreenMessage> messages = new Dictionary<string, ScreenMessage>();
public static void PostSingleScreenMessage(string id, string message)
{
if (messages.ContainsKey(id))
ScreenMessages.RemoveMessage(messages[id]);
messages[id] = ScreenMessages.PostScreenMessage(message);
}
}
}
Loading…
Cancel
Save