@ -20,13 +20,6 @@ namespace Aerostats
[KSPField(isPersistant = false, guiActive = false)]
[KSPField(isPersistant = false, guiActive = false)]
public float MaxGasVentRate = 5 0 0 ;
public float MaxGasVentRate = 5 0 0 ;
/// <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 = 1 5 0 0 0 ;
/// <summary>
/// <summary>
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Weight, in kilograms, of 1m^3 of gas at 100kPa and 0°C
/// Helium is 179g/m^3
/// Helium is 179g/m^3
@ -43,24 +36,12 @@ namespace Aerostats
[UI_FloatRange(minValue = 0, maxValue = 20000.0f, stepIncrement = 100.0f)]
[UI_FloatRange(minValue = 0, maxValue = 20000.0f, stepIncrement = 100.0f)]
public float LiftingGasTargetQuantity = 1 0 0.0f ;
public float LiftingGasTargetQuantity = 1 0 0.0f ;
/// <summary>
/// Mass of the empty balloon, in kg
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float BalloonEmptyMass = 5 0.0f ;
/// <summary>
/// <summary>
/// Minimum amount of gas that will be used to inflate the balloon at the beginning. The balloon can not be deflated below this amount.
/// Minimum amount of gas that will be used to inflate the balloon at the beginning. The balloon can not be deflated below this amount.
/// </summary>
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
[KSPField(isPersistant = false, guiActive = false)]
public float MinimumFillQuantity = 1 0.0f ;
public float MinimumFillQuantity = 1 0.0f ;
/// <summary>
/// Drag coefficient of the balloon
/// </summary>
[KSPField(isPersistant = false, guiActive = false)]
public float BalloonDragCoeff = 0.3f ;
/// <summary>
/// <summary>
/// Length of spring that can not be extended (no force applied under this length)
/// Length of spring that can not be extended (no force applied under this length)
/// </summary>
/// </summary>
@ -80,6 +61,8 @@ namespace Aerostats
private bool Destroyed ;
private bool Destroyed ;
private Vector3 EstimatedNextFramePosition ;
/// <summary>
/// <summary>
/// Gas quantity currently inside the balloon
/// Gas quantity currently inside the balloon
/// </summary>
/// </summary>
@ -92,7 +75,17 @@ namespace Aerostats
private ModuleBalloon Balloon ;
private ModuleBalloon Balloon ;
private LineRenderer Spring ;
private LineRenderer Spring ;
private Vector3 EstimatedNextFramePosition ;
public static void RemoveAttachJointBetween ( Part part1 , Part part2 )
{
if ( part1 . attachJoint & & ( ( part1 . attachJoint . Host = = part1 & & part1 . attachJoint . Target = = part2 ) | | ( part1 . attachJoint . Host = = part2 & & part1 . attachJoint . Target = = part1 ) ) )
{
part1 . attachJoint . DestroyJoint ( ) ;
}
if ( part2 . attachJoint & & ( ( part2 . attachJoint . Host = = part2 & & part2 . attachJoint . Target = = part1 ) | | ( part2 . attachJoint . Host = = part1 & & part2 . attachJoint . Target = = part2 ) ) )
{
part2 . attachJoint . DestroyJoint ( ) ;
}
}
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Deploy balloon", unfocusedRange = 5)]
[KSPEvent(guiActive = true, active = true, externalToEVAOnly = false, guiActiveUnfocused = true, guiName = "Deploy balloon", unfocusedRange = 5)]
public void Deploy ( )
public void Deploy ( )
@ -103,15 +96,39 @@ namespace Aerostats
Deployed = true ;
Deployed = true ;
UnityEngine . Debug . Log ( "Aerostats: staged" ) ;
UnityEngine . Debug . Log ( "Aerostats: staged" ) ;
Util . PostScreenMessage ( "staged" ) ;
Util . PostDebug ScreenMessage ( "staged" ) ;
var balloonObject = GameObject . CreatePrimitive ( PrimitiveType . Sphere ) ;
/ * var balloonObject = GameObject . CreatePrimitive ( PrimitiveType . Sphere ) ;
balloonObject . SetActive ( false ) ;
balloonObject . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up ;
balloonObject . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up ;
Balloon = balloonObject . AddComponent < ModuleBalloon > ( ) ;
var balloonPart = balloonObject . AddComponent < Part > ( ) ;
Balloon . part = part ; // TODO: remove this hack and properly instantiate a new vessel?
balloonPart . children = new List < Part > ( ) ;
Balloon . Initialize ( BalloonEmptyMass , part . rigidbody . velocity , MaxBalloonVolume , GasDensity , BalloonDragCoeff ) ;
balloonPart . partTransform = balloonObject . transform ;
balloonPart . name = "heliumBalloon" ;
LiftingGasQuantity = Balloon . InjectGas ( part . RequestResource ( "Helium" , MinimumFillQuantity ) ) ;
new GameObject ( "model" ) . transform . parent = balloonPart . partTransform ;
balloonPart . SetHierarchyRoot ( balloonPart ) ;
balloonPart . vessel = vessel ;
balloonPart . setParent ( part ) ; * /
AvailablePart avPart = PartLoader . Instance . parts . Single ( p = > p . name = = "heliumBalloon" ) ;
var balloonPart = ( Part ) UnityEngine . Object . Instantiate ( avPart . partPrefab ) ;
var balloonObject = balloonPart . gameObject ;
balloonObject . transform . position = part . Rigidbody . position + part . Rigidbody . transform . up * 3.0f ;
//balloonObject.transform.rotation = part.Rigidbody.rotation;
balloonPart . SetHierarchyRoot ( balloonPart ) ;
balloonPart . vessel = vessel ;
balloonPart . setParent ( part ) ;
Balloon = balloonObject . GetComponent < ModuleBalloon > ( ) ;
Balloon . part = balloonPart ;
float initialGasQuantity = Mathf . Min ( 0.1f , part . RequestResource ( "Helium" , MinimumFillQuantity ) ) ;
balloonObject . SetActive ( true ) ;
GameEvents . onVesselWasModified . Fire ( vessel ) ;
Balloon . Initialize ( this , part . rigidbody . velocity , GasDensity , initialGasQuantity ) ;
LiftingGasQuantity = Balloon . LiftingGasQuantity ;
Spring = part . gameObject . AddComponent < LineRenderer > ( ) ;
Spring = part . gameObject . AddComponent < LineRenderer > ( ) ;
Spring . useWorldSpace = true ;
Spring . useWorldSpace = true ;
@ -131,7 +148,13 @@ namespace Aerostats
if ( Destroyed | | ! Deployed )
if ( Destroyed | | ! Deployed )
return ;
return ;
if ( Balloon ! = null )
{
Balloon . OnDetached ( ) ;
Balloon . part . decouple ( ) ; // after that, the balloon becomes an independent vessel
Balloon . part . vessel . vesselName = vessel . vesselName + " balloon" ;
Balloon = null ;
Balloon = null ;
}
Destroy ( Spring ) ;
Destroy ( Spring ) ;
Spring = null ;
Spring = null ;
part . OnJustAboutToBeDestroyed - = OnPartDestroyed ;
part . OnJustAboutToBeDestroyed - = OnPartDestroyed ;
@ -142,7 +165,7 @@ namespace Aerostats
{
{
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
if ( ! HighLogic . LoadedSceneIsEditor & & ! HighLogic . LoadedSceneIsFlight ) { return ; }
Util . PostScreenMessage ( "Aerostat loaded" ) ;
Util . PostDebug ScreenMessage ( "Aerostat loaded" ) ;
part . stagingIcon = "PARACHUTES" ;
part . stagingIcon = "PARACHUTES" ;
}
}
@ -151,6 +174,19 @@ namespace Aerostats
Cut ( ) ;
Cut ( ) ;
}
}
private void CheckKrakensbane ( )
{
// detect Krakensbane teleportation, and fix up the balloon position (otherwise it results in instant ship disintegration due to extreme forces on the spring)
if ( ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude > 1 0 0 0.0f )
{
Util . PostDebugScreenMessage ( "Krakensbane teleportation detected! (dist=" + ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude + ")" ) ;
var offset = part . rigidbody . position - EstimatedNextFramePosition ;
Balloon . rigidbody . position + = offset ;
Balloon . transform . position = Balloon . rigidbody . position ;
}
EstimatedNextFramePosition = part . rigidbody . position + part . rigidbody . velocity * Time . fixedDeltaTime ;
}
private void FixedUpdate ( )
private void FixedUpdate ( )
{
{
if ( Destroyed )
if ( Destroyed )
@ -167,15 +203,10 @@ namespace Aerostats
if ( Deployed )
if ( Deployed )
{
{
// detect Krakensbane teleportation, and fix up the balloon position (otherwise it results in instant ship disintegration due to extreme forces on the spring)
// makes sure the balloon can move freely relatively to the vessel (apparently, KSP creates a joint when attaching a part)
if ( ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude > 1 0 0 0.0f )
RemoveAttachJointBetween ( Balloon . part , part ) ;
{
Util . PostScreenMessage ( "Krakensbane teleportation detected! (dist=" + ( part . Rigidbody . position - EstimatedNextFramePosition ) . magnitude + ")" ) ;
CheckKrakensbane ( ) ;
var offset = part . rigidbody . position - EstimatedNextFramePosition ;
Balloon . rigidbody . position + = offset ;
Balloon . transform . position = Balloon . rigidbody . position ;
}
EstimatedNextFramePosition = part . rigidbody . position + part . rigidbody . velocity * Time . fixedDeltaTime ;
float currentMaxQuantity = Balloon . GetCurrentMaxQuantity ( ) ;
float currentMaxQuantity = Balloon . GetCurrentMaxQuantity ( ) ;
@ -209,7 +240,7 @@ namespace Aerostats
Status = "full (venting)" ;
Status = "full (venting)" ;
}
}
VolumeStatus = Mathf . Round ( Balloon . CurrentVolume ) + " / " + Mathf . Round ( Max BalloonVolume) ;
VolumeStatus = Mathf . Round ( Balloon . CurrentVolume ) + " / " + Mathf . Round ( Balloon . Max Volume) ;
// spring between balloon and base
// spring between balloon and base
float restLength = SpringRestLength + Balloon . Radius ;
float restLength = SpringRestLength + Balloon . Radius ;
@ -225,7 +256,7 @@ namespace Aerostats
part . rigidbody . AddForce ( springForce , ForceMode . Force ) ;
part . rigidbody . AddForce ( springForce , ForceMode . Force ) ;
Balloon . rigidbody . AddForceAtPosition ( - springForce , balloonAttachPoint , ForceMode . Force ) ;
Balloon . rigidbody . AddForceAtPosition ( - springForce , balloonAttachPoint , ForceMode . Force ) ;
}
}
Util . PostSingleScreenMessage ( "spring force" , "Spring force = " + springForceMag + "N" ) ;
Util . PostDebug SingleScreenMessage ( "spring force" , "Spring force = " + springForceMag + "N" ) ;
}
}
else
else
{
{
@ -241,11 +272,23 @@ namespace Aerostats
if ( Deployed )
if ( Deployed )
{
{
CheckKrakensbane ( ) ;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * Balloon . Radius ;
var balloonAttachPoint = Balloon . rigidbody . position - Balloon . transform . up . normalized * Balloon . Radius ;
Spring . SetPosition ( 0 , part . transform . position ) ;
Spring . SetPosition ( 0 , part . transform . position ) ;
Spring . SetPosition ( 1 , balloonAttachPoint ) ;
Spring . SetPosition ( 1 , balloonAttachPoint ) ;
}
}
}
}
private void Update ( )
{
if ( Destroyed )
return ;
if ( Deployed )
{
CheckKrakensbane ( ) ;
}
}
}
}
}
}