Generally compatible with TT refactor.
Generally compatible with TT refactor.

file:a/CoreStrut.cs (deleted)
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using UnityEngine;  
 
namespace QuantumStrut  
{  
class CoreStrut  
{  
public bool isDestroyed = false;  
 
Material _material = null;  
public Material Material  
{  
set  
{  
_material = value;  
if (Material != null)  
lr.material = Material;  
}  
get  
{  
return _material;  
}  
}  
 
Color _startColor = Color.white;  
public Color StartColor  
{  
set  
{  
_startColor = value;  
if (StartColor != null && EndColor != null)  
lr.SetColors(StartColor, EndColor);  
}  
get  
{  
return _startColor;  
}  
}  
 
Color _endColor = Color.white;  
public Color EndColor  
{  
set  
{  
_endColor = value;  
if (StartColor != null && EndColor != null)  
lr.SetColors(StartColor, EndColor);  
}  
get  
{  
return _endColor;  
}  
}  
 
float _startSize = 0;  
public float StartSize  
{  
set  
{  
_startSize = value;  
lr.SetWidth(StartSize, EndSize);  
}  
get  
{  
return _startSize;  
}  
}  
 
float _endSize = 0;  
public float EndSize  
{  
set  
{  
_endSize = value;  
lr.SetWidth(StartSize, EndSize);  
}  
get  
{  
return _endSize;  
}  
}  
 
ConfigurableJoint joint;  
 
public bool Active = true;  
public bool Selected = false;  
public Part parent = null;  
public Vector3 parentOffset = Vector3.zero;  
 
public Part target = null;  
public Vector3 targetOffset = Vector3.zero;  
 
GameObject LineObj;  
LineRenderer lr = null;  
 
public void print(object body, params object[] args)  
{  
string final = body.ToString();  
for (int I = 0; I < args.Length; I++)  
{  
final = final.Replace("{" + I + "}", args[I].ToString());  
}  
MonoBehaviour.print("[AutoStrut] " + final);  
}  
 
void DrawLine(Vector3 origin, Vector3 end)  
{  
if (Util.isValid(lr))  
{  
lr.SetPosition(0, origin);  
lr.SetPosition(1, end);  
}  
}  
 
void createJoint()  
{  
if (!Util.isValid(joint))  
{  
joint = parent.gameObject.AddComponent<ConfigurableJoint>();  
joint.connectedBody = target.rigidbody;  
 
joint.anchor = new Vector3(0, 0, Vector3.Distance(parent.transform.TransformPoint(parentOffset), target.transform.TransformPoint(targetOffset)) / 2);  
joint.axis = new Vector3(0, 0, 1);  
joint.xMotion = ConfigurableJointMotion.Locked;  
joint.yMotion = ConfigurableJointMotion.Locked;  
joint.zMotion = ConfigurableJointMotion.Locked;  
joint.angularXMotion = ConfigurableJointMotion.Locked;  
joint.angularYMotion = ConfigurableJointMotion.Locked;  
joint.angularZMotion = ConfigurableJointMotion.Locked;  
}  
}  
 
void deleteJoint()  
{  
if (Util.isValid(joint))  
GameObject.DestroyImmediate(joint);  
}  
 
public CoreStrut(Part parent, Vector3 parentOffset, Part target, Vector3 targetOffset)  
{  
this.parent = parent;  
this.parentOffset = parentOffset;  
this.target = target;  
this.targetOffset = targetOffset;  
 
createJoint();  
 
LineObj = new GameObject();  
LineObj.name = "quantumstrut";  
 
lr = LineObj.AddComponent<LineRenderer>();  
lr.useWorldSpace = true;  
 
Material = QuantumStrut.LaserMaterial;  
StartColor = Color.white;  
EndColor = Color.white;  
StartSize = 0.03f;  
EndSize = 0.0075f;  
 
lr.SetVertexCount(2);  
lr.SetPosition(0, Vector3.zero);  
lr.SetPosition(1, Vector3.zero);  
}  
 
public void Update()  
{  
if (Util.isValid(parent) && Util.isValid(target) && Util.isValid(parent.vessel) && parent.vessel.parts.Contains(target))  
{  
if (Active)  
{  
createJoint();  
Vector3 start = parent.transform.TransformPoint(parentOffset);  
Vector3 end = target.transform.TransformPoint(targetOffset);  
if (Selected)  
lr.SetColors(Color.blue, Color.blue);  
else  
lr.SetColors(StartColor, EndColor);  
DrawLine(start, end);  
}  
else  
{  
deleteJoint();  
DrawLine(Vector3.zero, Vector3.zero);  
}  
}  
else  
{  
DrawLine(Vector3.zero, Vector3.zero);  
Destroy();  
}  
}  
 
public void Destroy()  
{  
DrawLine(Vector3.zero, Vector3.zero);  
if (Util.isValid(joint))  
GameObject.DestroyImmediate(joint);  
 
if (Util.isValid(lr))  
GameObject.DestroyImmediate(lr);  
 
if (Util.isValid(LineObj))  
GameObject.DestroyImmediate(LineObj);  
 
joint = null;  
LineObj = null;  
lr = null;  
 
parent = null;  
target = null;  
targetOffset = Vector3.zero;  
isDestroyed = true;  
}  
}  
}  
  // QuantumStrutsContinued
  //
  // Continued from QuantumStruts by BoJaN. Used by permission.
  //
  // ModuleManager patches © 2014 K3|Chris. Used by permission.
  //
  // Copyright © 2014, toadicus, K3|Chris
  // 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.
  //
  // 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 ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  @PART[*]:HAS[@MODULE[QuantumStrut]]
  {
  MODULE
  {
  name = KASModuleGrab
  evaPartPos = (0.0, 0.0, -0.15)
  evaPartDir = (0,0,-1)
  storable = true
  storedSize = 2
  attachOnPart = True
  attachOnEva = False
  attachOnStatic = False
  }
  }
  QuantumStrutsContinued
 
  Continued from QuantumStruts by BoJaN. Used by permission.
 
  ModuleManager patches © 2014 K3|Chris. Used by permission.
 
  Copyright © 2014-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.
 
  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 ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/quantumStrut/model.mu differ
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/quantumStrut/model000.mbm differ
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/quantumStrut/model001.mbm differ
  // QuantumStrutsContinued
  //
  // Continued from QuantumStruts by BoJaN. Used by permission.
  //
  // ModuleManager patches © 2014 K3|Chris. Used by permission.
  //
  // 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.
  //
  // 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 ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  PART
  {
  // --- general parameters ---
  name = QuantumStrut
  module = Part
  author = BoJaN
 
  // --- asset parameters ---
  mesh = model.mu
  rescaleFactor = 0.6
 
  // --- node definitions ---
  // definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z
  node_attach = 0.0, 0.0 , 0.0, 0.0, -1.0, 0.0
 
  // --- editor parameters ---
  TechRequired = advScienceTech
  cost = 1500
  category = Utility
  subcategory = 0
  title = Quantum Strut
  manufacturer = Bojantek Corporation
  description = Highly experimental quantum struts harness a form of quantum locking to add support for docked vessels.
 
  // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision
  attachRules = 0,1,0,1,1
 
  // --- standard part parameters ---
  mass = 0.05
  dragModelType = default
  maximum_drag = 0.01
  minimum_drag = 0.01
  angularDrag = 0.1
  crashTolerance = 50
  breakingForce = 50
  breakingTorque = 50
  maxTemp = 3400
 
  MODULE
  {
  name = QuantumStrut
  IsEnabled = true
  PowerConsumption = 0.01
 
  Material = Particles/Additive
  StartColor = 57, 146, 181
  EndColor = 11, 29, 36
  StartSize = 0.03
  EndSize = 0.0025
 
  Start = 0,0,0
  Dir = 0,1,0
  }
 
  }
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/strutGun/model.mu differ
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/strutGun/model000.mbm differ
 Binary files /dev/null and b/GameData/QuantumStrutsContinued/Parts/QuantumStruts/strutGun/model001.mbm differ
  // QuantumStrutsContinued
  //
  // Continued from QuantumStruts by BoJaN. Used by permission.
  //
  // ModuleManager patches © 2014 K3|Chris. Used by permission.
  //
  // 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.
  //
  // 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 ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  PART
  {
  // --- general parameters ---
  name = StrutGun
  module = Part
  author = BoJaN
 
  // --- asset parameters ---
  mesh = model.mu
  rescaleFactor = 0.6
 
  // --- node definitions ---
  // definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z
  node_attach = 0.0, 0.0 , 0.0, 0.0, -1.0, 0.0
 
  // --- editor parameters ---
  TechRequired = advScienceTech
  cost = 500
  category = Utility
  subcategory = 0
  title = Strut Gun
  manufacturer = Bojantek Corporation
  description = A radial strut gun for attaching and detatching struts when needed
 
  // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision
  attachRules = 0,1,0,1,1
 
  // --- standard part parameters ---
  mass = 0.05
  dragModelType = default
  maximum_drag = 0.01
  minimum_drag = 0.01
  angularDrag = 0.1
  crashTolerance = 50
  breakingForce = 50
  breakingTorque = 50
  maxTemp = 3400
 
  MODULE
  {
  name = QuantumStrut
  IsEnabled = true
  PowerConsumption = 0.01
 
  Material = KSP/Sprite
  StartColor = 50, 50, 50
  EndColor = 50, 50, 50
  StartSize = 0.03
  EndSize = 0.03
 
  Start = 0,0,0
  Dir = 0,1,0
  }
  }
using System.Reflection; // QuantumStrutsContinued
using System.Runtime.CompilerServices; //
using System.Runtime.InteropServices; // AssemblyInfo.cs
  //
// General Information about an assembly is controlled through the following // Continued from QuantumStruts by BoJaN. Used by permission.
// set of attributes. Change these attribute values to modify the information //
// associated with an assembly. // ModuleManager patches © 2014 K3|Chris. Used by permission.
[assembly: AssemblyTitle("AutoStrut")] //
[assembly: AssemblyDescription("")] // Copyright © 2014, toadicus
[assembly: AssemblyConfiguration("")] // All rights reserved.
[assembly: AssemblyCompany("")] //
[assembly: AssemblyProduct("AutoStrut")] // Redistribution and use in source and binary forms, with or without modification,
[assembly: AssemblyCopyright("Copyright © 2012")] // are permitted provided that the following conditions are met:
[assembly: AssemblyTrademark("")] //
[assembly: AssemblyCulture("")] // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
// 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 // 2. Redistributions in binary form must reproduce the above copyright notice,
// COM, set the ComVisible attribute to true on that type. // this list of conditions and the following disclaimer in the documentation and/or other
[assembly: ComVisible(false)] // materials provided with the distribution.
  //
// The following GUID is for the ID of the typelib if this project is exposed to COM // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
[assembly: Guid("57e209db-4b94-46b4-be0e-bd6e830d4eb5")] // 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,
// Version information for an assembly consists of the following four values: // 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,
// Major Version // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// Minor Version // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 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")]  
   
  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("QuantumStrutsContinued")]
  [assembly: AssemblyDescription("A KSP part mod that provides magical struts for rigidifying vessels constructed outside the VAB.")]
  [assembly: AssemblyProduct("QuantumStrutsContinued")]
  [assembly: AssemblyCopyright("Copyright © 2014 toadicus")]
   
  // 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("57e209db-4b94-46b4-be0e-bd6e830d4eb5")]
   
  // 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.3.*")]
   
using System; // QuantumStrutsContinued
using System.Collections.Generic; //
using System.Linq; // QuantumStrut.cs
using System.Text; //
using System.Threading.Tasks; // Continued from QuantumStruts by BoJaN. Used by permission.
using UnityEngine; //
  // ModuleManager patches © 2014 K3|Chris. Used by permission.
namespace QuantumStrut //
{ // Copyright © 2014, toadicus
public class QuantumStrut : PartModule // All rights reserved.
{ //
public static Material LaserMaterial; // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
Strut strut = null; //
GameObject lineObj; // 1. Redistributions of source code must retain the above copyright notice,
LineRenderer lr; // this list of conditions and the following disclaimer.
bool Editor = false; //
int I = 0; // 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
#region Fields // materials provided with the distribution.
[KSPField(isPersistant = true)] //
public bool IsEnabled = true; // 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
[KSPField(isPersistant = false)] // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
public float PowerConsumption = 0; // 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
[KSPField(isPersistant = false)] // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
public string TransformName = "";  
  using KSP;
[KSPField(isPersistant = false)] using System;
public Vector3 Start = new Vector3(0,0,0); using ToadicusTools;
  using UnityEngine;
[KSPField(isPersistant = false)]  
public Vector3 Dir = new Vector3(0, 1, 0); namespace QuantumStrut
  {
  public class QuantumStrut : PartModule
[KSPField(isPersistant = false)] {
public string Material = "Particles/Additive"; public static Material LaserMaterial;
  Strut strut = null;
[KSPField(isPersistant = false)] GameObject lineObj;
public Vector3 StartColor = Vector3.zero; LineRenderer lr;
  bool Editor = false;
[KSPField(isPersistant = false)] int I = 0;
public Vector3 EndColor = Vector3.zero;  
  #region Fields
   
[KSPField(isPersistant = false)] [KSPField(isPersistant = true)]
public float StartSize = 0.03f; public bool IsEnabled = true;
  [KSPField(isPersistant = false)]
[KSPField(isPersistant = false)] public float PowerConsumption = 0;
public float EndSize = 0.0075f; [KSPField(isPersistant = false)]
#endregion public string TransformName = "";
  [KSPField(isPersistant = false)]
#region Actions public Vector3 Start = new Vector3(0, 0, 0);
[KSPAction("Toggle")] [KSPField(isPersistant = false)]
public void ToggleStrut(KSPActionParam param) public Vector3 Dir = new Vector3(0, 1, 0);
{ [KSPField(isPersistant = false)]
IsEnabled = !IsEnabled; public string Material = "Particles/Additive";
CheckHit(); [KSPField(isPersistant = false)]
} public Vector3 StartColor = Vector3.zero;
  [KSPField(isPersistant = false)]
[KSPAction("Activate")] public Vector3 EndColor = Vector3.zero;
public void ActivateStrut(KSPActionParam param) [KSPField(isPersistant = false)]
{ public float StartSize = 0.03f;
IsEnabled = true; [KSPField(isPersistant = false)]
CheckHit(); public float EndSize = 0.0075f;
}  
  #endregion
[KSPAction("Deactivate")]  
public void DeactivateStrut(KSPActionParam param) #region Actions
{  
IsEnabled = false; [KSPAction("Toggle")]
CheckHit(); public void ToggleStrut(KSPActionParam param)
} {
#endregion IsEnabled = !IsEnabled;
  CheckHit();
#region Events }
[KSPEvent(guiActive = true, guiName = "Activate", active = true)]  
public void ActivateStrut() [KSPAction("Activate")]
{ public void ActivateStrut(KSPActionParam param)
IsEnabled = true; {
CheckHit(); this.ActivateStrut();
} }
   
[KSPEvent(guiActive = true, guiName = "Deactivate", active = false)] [KSPAction("Deactivate")]
public void DeactivateStrut() public void DeactivateStrut(KSPActionParam param)
{ {
IsEnabled = false; this.DeactivateStrut();
CheckHit(); }
}  
#endregion #endregion
   
public Material material = null; #region Events
public Color startColor = Color.white;  
public Color endColor = Color.white; [KSPEvent(guiActive = true, guiName = "Activate", active = true, guiActiveUnfocused = true, unfocusedRange = 2f)]
  public void ActivateStrut()
public Color Vector3toColor(Vector3 vec) {
{ IsEnabled = true;
return new Color(vec.x/255, vec.y/255, vec.z/255); CheckHit();
} this.Events["ActivateStrut"].guiActiveEditor = false;
  this.Events["DeactivateStrut"].guiActiveEditor = true;
Transform getTransform() }
{  
if (TransformName == "") [KSPEvent(guiActive = true, guiName = "Deactivate", active = false, guiActiveUnfocused = true, unfocusedRange = 2f)]
return part.transform; public void DeactivateStrut()
else {
return part.FindModelTransform(TransformName); IsEnabled = false;
} CheckHit();
  this.Events["ActivateStrut"].guiActiveEditor = true;
public void print(object body, params object[] args) this.Events["DeactivateStrut"].guiActiveEditor = false;
{ }
string final = body.ToString();  
for (int I = 0; I < args.Length; I++) #endregion
{  
final = final.Replace("{" + I + "}", args[I].ToString()); public Material material = null;
} public Color startColor = Color.white;
MonoBehaviour.print("[AutoStrut] " + final); public Color endColor = Color.white;
}  
  public Color Vector3toColor(Vector3 vec)
public override void OnLoad(ConfigNode node) {
{ return new Color(vec.x / 255, vec.y / 255, vec.z / 255);
base.OnLoad(node); }
}  
  Transform getTransform()
public override void OnActive() {
{ if (TransformName == "")
InitLaser(); return part.transform;
  else
base.OnActive(); return part.FindModelTransform(TransformName);
} }
   
public override void OnInactive() public void print(object body, params object[] args)
{ {
DestroyLaser(); string final = body.ToString();
  for (int I = 0; I < args.Length; I++)
base.OnInactive(); {
} final = final.Replace("{" + I + "}", args[I].ToString());
  }
public override string GetInfo() MonoBehaviour.print("[AutoStrut] " + final);
{ }
return "Requires:\n- ElectricCharge (" + PowerConsumption + "/s.)\n\n Costs 5 to create strut.";  
return base.GetInfo(); public override void OnLoad(ConfigNode node)
} {
  base.OnLoad(node);
public override void OnStart(PartModule.StartState state) }
{  
try public override void OnActive()
{ {
print("Material: {0}", Material); InitLaser();
material = new Material(Shader.Find(Material.Trim()));  
} base.OnActive();
catch }
{  
material = null; public override void OnInactive()
} {
  DestroyLaser();
startColor = Vector3toColor(StartColor);  
endColor = Vector3toColor(EndColor); base.OnInactive();
  }
if (!Util.isValid(LaserMaterial))  
LaserMaterial = new Material(Shader.Find("Particles/Additive")); public override string GetInfo()
  {
if (state == StartState.Docked) return "Requires:\n- ElectricCharge (" + PowerConsumption + "/s.)\n\n Costs 5 to create strut.";
CheckHit(); }
   
if (state == StartState.Editor) public override void OnStart(PartModule.StartState state)
{ {
Editor = true; try
RenderingManager.AddToPostDrawQueue(0, DrawBuildOverlay); {
InitLaser(); print("Material: {0}", Material);
} material = new Material(Shader.Find(Material.Trim()));
else }
{ catch
Editor = false; {
RenderingManager.RemoveFromPostDrawQueue(0, DrawBuildOverlay); material = null;
DestroyLaser(); }
}  
  startColor = Vector3toColor(StartColor);
base.OnStart(state); endColor = Vector3toColor(EndColor);
}  
  if (!Util.isValid(LaserMaterial))
public override void OnFixedUpdate() LaserMaterial = new Material(Shader.Find("Particles/Additive"));
{  
base.OnFixedUpdate(); if (state == StartState.Docked)
} CheckHit();
   
  if (state == StartState.Editor)
public override void OnUpdate() {
{ Editor = true;
Events["ActivateStrut"].active = !IsEnabled; RenderingManager.AddToPostDrawQueue(0, DrawBuildOverlay);
Events["DeactivateStrut"].active = IsEnabled; InitLaser();
  }
if (IsEnabled) else
{ {
I = I + 1 % 255; Editor = false;
  RenderingManager.RemoveFromPostDrawQueue(0, DrawBuildOverlay);
if (strut != null && !strut.isDestroyed) DestroyLaser();
{ }
if (PowerConsumption == 0 || (Util.GetEnergy(part.vessel) > PowerConsumption * TimeWarp.fixedDeltaTime && part.RequestResource("ElectricCharge", PowerConsumption * TimeWarp.fixedDeltaTime) > 0))  
strut.Update(); base.OnStart(state);
else }
strut.Destroy();  
} public void Update()
else {
{ Events["ActivateStrut"].guiActiveEditor = Events["ActivateStrut"].active = !IsEnabled;
if ((I % 10)==0) Events["DeactivateStrut"].guiActiveEditor = Events["DeactivateStrut"].active = IsEnabled;
{  
CheckHit(); if (IsEnabled)
} {
} I = I + 1 % 255;
}  
else if (strut != null && !strut.isDestroyed)
{ {
if (strut != null) if (PowerConsumption == 0 || (Util.GetEnergy(part.vessel) > PowerConsumption * TimeWarp.fixedDeltaTime && part.RequestResource(
{ "ElectricCharge",
strut.Destroy(); PowerConsumption * TimeWarp.fixedDeltaTime
strut = null; ) > 0))
} strut.Update();
} else
  strut.Destroy();
base.OnUpdate(); }
} else
  {
void CheckHit() if ((I % 10) == 0)
{ {
if (!isEnabled) CheckHit();
{ }
strut.Destroy(); }
strut = null; }
return; else
} {
  if (strut != null)
if (strut == null || strut.isDestroyed) {
{ strut.Destroy();
Vector3 dir = getTransform().TransformDirection(Dir); strut = null;
Vector3 start = getTransform().TransformPoint(Start); }
  }
UnityEngine.RaycastHit info = new RaycastHit();  
bool hit = Physics.Raycast(new UnityEngine.Ray(start + (dir * 0.05f), dir), out info, 10); base.OnUpdate();
if (hit) }
{  
Part targetPart = Util.partFromRaycast(info); void CheckHit()
  {
if (targetPart && vessel.parts.Contains(targetPart) && Util.GetEnergy(part.vessel) > 5 * TimeWarp.fixedDeltaTime) if (HighLogic.LoadedSceneIsEditor)
{ {
float energy = part.RequestResource("ElectricCharge", 5 * TimeWarp.fixedDeltaTime); Logging.PostDebugMessage(this, "Checking bailing out: in the editor!");
  return;
strut = new Strut(part, targetPart, targetPart.transform.InverseTransformPoint(info.point), getTransform()); }
strut.Material = material;  
strut.StartColor = startColor; if (!isEnabled)
strut.EndColor = endColor; {
strut.StartSize = StartSize; Logging.PostDebugMessage(this, "Destroying strut.");
strut.EndSize = EndSize;  
} strut.Destroy();
} strut = null;
} return;
} }
   
void InitLaser() Logging.PostDebugMessage(this, "Checking for ray hit.");
{  
if (!Util.isValid(lr)) Logging.PostDebugMessage(this, "Enabled, continuing.");
{  
lineObj = new GameObject(); if (strut == null || strut.isDestroyed)
  {
lr = lineObj.AddComponent<LineRenderer>(); Logging.PostDebugMessage(this, "We have no strut, or the strut has been destroyed.");
lr.useWorldSpace = true;  
  Vector3 dir = getTransform().TransformDirection(Dir);
lr.material = material; Vector3 start = getTransform().TransformPoint(Start);
lr.SetColors(startColor, endColor);  
lr.SetWidth(StartSize, EndSize); Logging.PostDebugMessage(this, "Got transforms. Checking for raycast hit.");
   
lr.SetVertexCount(2); UnityEngine.RaycastHit info = new RaycastHit();
lr.SetPosition(0, Vector3.zero); bool hit = Physics.Raycast(new UnityEngine.Ray(start + (dir * 0.05f), dir), out info, 10);
lr.SetPosition(1, Vector3.zero);  
lr.castShadows = false; if (hit)
lr.receiveShadows = true; {
} Logging.PostDebugMessage(this, "Found raycast hit. Fetching target part.");
}  
  Part targetPart = Util.partFromRaycast(info);
void DestroyLaser()  
{ Logging.PostDebugMessage(this, "Found target part.");
if (Util.isValid(lr))  
LineRenderer.DestroyImmediate(lr); if (
  targetPart && vessel.parts.Contains(targetPart) &&
if (Util.isValid(lineObj)) Util.GetEnergy(part.vessel) > 5 * TimeWarp.fixedDeltaTime
GameObject.DestroyImmediate(lineObj); )
} {
  Logging.PostDebugMessage(this, "Target part is in our vessel and we have the energy to continue.");
public void DrawBuildOverlay()  
{ strut = new Strut(
if (Util.isValid(part)) part,
{ targetPart,
if (!Editor) return; targetPart.transform.InverseTransformPoint(info.point),
  getTransform()
if (Util.isValid(lr)) );
{  
Vector3 dir = getTransform().TransformDirection(Dir); Logging.PostDebugMessage(this, "Built a new strut, setting material, colors, and sizes.");
Vector3 start = getTransform().TransformPoint(Start);  
  strut.Material = material;
UnityEngine.RaycastHit info = new RaycastHit(); strut.StartColor = startColor;
bool hit = Physics.Raycast(new UnityEngine.Ray(start + (dir * 0.05f), dir), out info, 10); strut.EndColor = endColor;
if (hit) strut.StartSize = StartSize;
{ strut.EndSize = EndSize;
if (Util.isValid(material))  
lr.material = material; Logging.PostDebugMessage(this, "Strut all done!");
  }
lr.SetColors(startColor, endColor); }
lr.SetWidth(StartSize, EndSize); }
  }
lr.SetPosition(0, start);  
lr.SetPosition(1, info.point); void InitLaser()
} {
else if (!Util.isValid(lr))
{ {
lr.material = LaserMaterial; lineObj = new GameObject();
lr.SetColors(Color.red, Color.red);  
lr.SetWidth(0.01f, 0.01f); lr = lineObj.AddComponent<LineRenderer>();
  lr.useWorldSpace = true;
lr.SetPosition(0, start);  
lr.SetPosition(1, start + (dir * 10)); lr.material = material;
} lr.SetColors(startColor, endColor);
} lr.SetWidth(StartSize, EndSize);
}  
else lr.SetVertexCount(2);
{ lr.SetPosition(0, Vector3.zero);
DestroyLaser(); lr.SetPosition(1, Vector3.zero);
RenderingManager.RemoveFromPostDrawQueue(0, DrawBuildOverlay); lr.castShadows = false;
} lr.receiveShadows = true;
} }
} }
   
  void DestroyLaser()
  {
  if (Util.isValid(lr))
  LineRenderer.DestroyImmediate(lr);
   
  if (Util.isValid(lineObj))
  GameObject.DestroyImmediate(lineObj);
  }
   
  public void DrawBuildOverlay()
  {
  if (Util.isValid(part))
  {
  if (!Editor)
  return;
   
  if (Util.isValid(lr))
  {
  Vector3 dir = getTransform().TransformDirection(Dir);
  Vector3 start = getTransform().TransformPoint(Start);
   
  UnityEngine.RaycastHit info = new RaycastHit();
  bool hit = Physics.Raycast(new UnityEngine.Ray(start + (dir * 0.05f), dir), out info, 10);
  if (hit && IsEnabled)
  {
  if (Util.isValid(material))
  lr.material = material;
   
  lr.SetColors(startColor, endColor);
  lr.SetWidth(StartSize, EndSize);
   
  lr.SetPosition(0, start);
  lr.SetPosition(1, info.point);
  }
  else
  {
  lr.material = LaserMaterial;
  lr.SetColors(Color.red, Color.red);
  lr.SetWidth(0.01f, 0.01f);
   
  lr.SetPosition(0, start);
  lr.SetPosition(1, start + (dir * 10));
  }
  }
  }
  else
  {
  DestroyLaser();
  RenderingManager.RemoveFromPostDrawQueue(0, DrawBuildOverlay);
  }
  }
  }
} }
file:a/QuantumStrutCore.cs (deleted)
using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using UnityEngine;  
using KSP.IO;  
 
 
namespace QuantumStrut  
{  
class QuantumStrutCore : PartModule  
{  
GameObject lineObj = null;  
LineRenderer lr = null;  
ConfigNode nodeToLoad = null;  
 
bool Placing = false;  
bool Deleting = false;  
List<CoreStrut> struts = new List<CoreStrut>();  
 
Part startPart = null;  
Vector3 startOffset = Vector3.zero;  
Part endPart = null;  
Vector3 endOffset = Vector3.zero;  
 
public Material material = null;  
public Color startColor = Color.white;  
public Color endColor = Color.white;  
 
#region Fields  
[KSPField(isPersistant = true)]  
public bool IsEnabled = true;  
 
[KSPField(isPersistant = false)]  
public float PowerConsumption = 0;  
 
[KSPField(isPersistant = false)]  
public int MaxStruts = 8;  
 
[KSPField(isPersistant = false)]  
public string Material = "Particles/Additive";  
 
[KSPField(isPersistant = false)]  
public Vector3 StartColor = Vector3.zero;  
 
[KSPField(isPersistant = false)]  
public Vector3 EndColor = Vector3.zero;  
 
 
[KSPField(isPersistant = false)]  
public float StartSize = 0.03f;  
 
[KSPField(isPersistant = false)]  
public float EndSize = 0.0075f;  
#endregion  
 
#region Actions  
[KSPAction("Toggle")]  
public void ToggleCore(KSPActionParam param)  
{  
IsEnabled = !IsEnabled;  
}  
 
[KSPAction("Activate")]  
public void ActivateCore(KSPActionParam param)  
{  
IsEnabled = true;  
}  
 
[KSPAction("Deactivate")]  
public void DeactivateCore(KSPActionParam param)  
{  
IsEnabled = false;  
}  
#endregion  
 
#region Events  
[KSPEvent(guiActive = true, guiName = "Place Strut", active = false, externalToEVAOnly=true, guiActiveUnfocused=true, unfocusedRange = 5)]  
public void BeginPlace()  
{  
startPart = null;  
startOffset = Vector3.zero;  
endPart = null;  
endOffset = Vector3.zero;  
Placing = true;  
}  
 
[KSPEvent(guiActive = true, guiName = "Remove Strut", active = false, externalToEVAOnly = true, guiActiveUnfocused = true, unfocusedRange = 2500)]  
public void BeginDelete()  
{  
Deleting = true;  
}  
 
[KSPEvent(guiActive = true, guiName = "Activate", active = true)]  
public void ActivateCore()  
{  
IsEnabled = true;  
}  
 
[KSPEvent(guiActive = true, guiName = "Deactivate", active = false)]  
public void DeactivateCore()  
{  
IsEnabled = false;  
}  
#endregion  
 
public Vector3 StringToVector3(string str)  
{  
string[] vals = str.Split(',');  
float x = (float)Convert.ToDecimal(vals[0]);  
float y = (float)Convert.ToDecimal(vals[1]);  
float z = (float)Convert.ToDecimal(vals[2]);  
return new Vector3(x, y, z);  
}  
 
public Color Vector3toColor(Vector3 vec)  
{  
return new Color(vec.x / 255, vec.y / 255, vec.z / 255);  
}  
 
Part partFromGameObject(GameObject ob)  
{  
GameObject o = ob;  
 
while (o)  
{  
Part p = Part.FromGO(o);  
if (p && p != null)  
{  
return p;  
}  
 
if (o.transform.parent)  
o = o.transform.parent.gameObject;  
else  
return null;  
}  
return null;  
}  
 
Part partFromRaycast(RaycastHit hit)  
{  
return partFromGameObject(hit.collider.gameObject);  
}  
 
Part partFromId(long id)  
{  
Console.WriteLine("Vessel Parts: " + part.vessel.Parts.Count);  
foreach (Part p in part.vessel.Parts)  
{  
print(p.uid + " ?= " + id + ": " + (p.uid == id));  
if (p.uid == id)  
return p;  
}  
return null;  
}  
 
bool isValid(UnityEngine.Object obj)  
{  
return (obj && obj != null);  
}  
 
void InitLaser()  
{  
if (!isValid(lr))  
{  
lineObj = new GameObject();  
 
lr = lineObj.AddComponent<LineRenderer>();  
lr.useWorldSpace = true;  
 
lr.material = new Material(Shader.Find("Particles/Additive"));  
lr.SetColors(Color.white, Color.white);  
lr.SetWidth(0.03f, 0.03f);  
 
lr.SetVertexCount(2);  
lr.SetPosition(0, Vector3.zero);  
lr.SetPosition(1, Vector3.zero);  
lr.castShadows = false;  
lr.receiveShadows = true;  
}  
}  
 
void DestroyLaser()  
{  
if (isValid(lr))  
LineRenderer.DestroyImmediate(lr);  
if (isValid(lineObj))  
GameObject.DestroyImmediate(lineObj);  
}  
 
float GetEnergy()  
{  
double energy = 0;  
foreach (Part p in part.vessel.parts)  
{  
foreach (PartResource r in p.Resources)  
{  
if (r.resourceName == "ElectricCharge")  
energy += r.amount;  
}  
}  
return (float)energy;  
}  
 
void AddStrut(Part a, Vector3 aO, Part b, Vector3 bO)  
{  
CoreStrut s = new CoreStrut(a, aO, b, bO);  
s.Material = material;  
s.StartColor = startColor;  
s.EndColor = endColor;  
s.StartSize = StartSize;  
s.EndSize = EndSize;  
struts.Add(s);  
}  
 
public override string GetInfo()  
{  
return "Max Struts: " + MaxStruts + "\nRequires:\n- ElectricCharge (" + PowerConsumption + "/s.)\n\n Energy cost is per-strut.";  
return base.GetInfo();  
}  
 
public override void OnStart(PartModule.StartState state)  
{  
try  
{  
material = new Material(Shader.Find(Material.Trim()));  
}  
catch  
{  
material = null;  
}  
 
startColor = Vector3toColor(StartColor);  
endColor = Vector3toColor(EndColor);  
base.OnStart(state);  
}  
 
public override void OnSave(ConfigNode node)  
{  
foreach (CoreStrut strut in struts)  
{  
if (!strut.isDestroyed)  
{  
ConfigNode n = node.AddNode("QuantumStrut");  
n.AddValue("parent", part.vessel.parts.IndexOf(strut.parent));  
n.AddValue("parentOffset", strut.parentOffset.x + "," + strut.parentOffset.y + "," + strut.parentOffset.z);  
n.AddValue("target", part.vessel.parts.IndexOf(strut.target));  
n.AddValue("targetOffset", strut.targetOffset.x + "," + strut.targetOffset.y + "," + strut.targetOffset.z);  
}  
}  
 
base.OnSave(node);  
}  
 
public override void OnLoad(ConfigNode node)  
{  
if (nodeToLoad == null)  
nodeToLoad = node;  
 
base.OnLoad(node);  
}  
 
void printObj(object obj)  
{  
using (KSP.IO.TextWriter writer = TextWriter.CreateForType<string>("obj.cs"))  
{  
string str = printProperties(obj, TypeDescriptor.GetProperties(obj), 0);  
writer.Write(str);  
print(str);  
}  
}  
 
string printProperties(object obj, PropertyDescriptorCollection collection, int I)  
{  
if (I > 2) return "";  
 
string prefix = "";  
string str = "";  
for (int T = 0; T < I; T++)  
{  
prefix += " ";  
}  
 
str += "\n" + prefix + "#region";  
foreach (PropertyDescriptor d in collection)  
{  
str += "\n" + prefix + d.Name + " = " + d.GetValue(obj);  
str += printProperties(obj, d.GetChildProperties(obj), I+1);  
}  
str += "\n" + prefix + "#endregion";  
return str;  
}  
 
bool kerbalPrinted = false;  
public override void OnUpdate()  
{  
bool eva = isValid(Util.Kerbal);  
Events["ActivateCore"].active = !IsEnabled;  
Events["DeactivateCore"].active = IsEnabled;  
Events["BeginPlace"].active = !Placing && !Deleting && struts.Count < MaxStruts && eva;  
Events["BeginDelete"].active = !Deleting && !Placing && struts.Count > 0 && eva;  
 
if (nodeToLoad != null)  
{  
foreach (ConfigNode strut in nodeToLoad.GetNodes("QuantumStrut"))  
{  
Part parent = part.vessel.parts[Convert.ToInt32(strut.GetValue("parent"))];  
Vector3 parentOffset = StringToVector3(strut.GetValue("parentOffset"));  
Part target = part.vessel.parts[Convert.ToInt32(strut.GetValue("target"))];  
Vector3 targetOffset = StringToVector3(strut.GetValue("targetOffset"));  
 
if (isValid(parent) && isValid(target))  
AddStrut(parent, parentOffset, target, targetOffset);  
}  
nodeToLoad = null;  
}  
 
if (eva)  
{  
InitLaser();  
if (Placing)  
{  
RaycastHit info = new RaycastHit();  
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);  
bool hit = Physics.Raycast(ray, out info, Mathf.Infinity);  
if (isValid(startPart))  
{  
Vector3 pos = startPart.transform.TransformPoint(startOffset);  
ray = new Ray(pos, (info.point - pos).normalized);  
hit = Physics.Raycast(ray, out info, 10);  
}  
 
if (Input.GetMouseButtonUp(0))  
{  
if (hit)  
{  
if (!isValid(startPart))  
{  
startPart = partFromRaycast(info);  
if (isValid(startPart))  
startOffset = startPart.transform.InverseTransformPoint(info.point);  
}  
else if (!isValid(endPart))  
{  
Part p = partFromRaycast(info);  
if (isValid(p))  
{  
if (p != startPart && startPart.vessel.parts.Contains(p))  
{  
endPart = p;  
endOffset = endPart.transform.InverseTransformPoint(info.point);  
 
AddStrut(startPart, startOffset, endPart, endOffset);  
}  
Placing = false;  
}  
}  
}  
}  
 
if(isValid(startPart))  
{  
if (hit)  
{  
Part p = partFromRaycast(info);  
Color c = Color.red;  
 
if (isValid(p))  
{  
if (startPart.vessel.parts.Contains(p) && p != startPart)  
c = Color.green;  
}  
 
lr.SetColors(c, c);  
lr.SetPosition(0, startPart.transform.TransformPoint(startOffset));  
lr.SetPosition(1, info.point);  
}  
else  
{  
lr.SetColors(Color.red, Color.red);  
lr.SetPosition(0, startPart.transform.TransformPoint(startOffset));  
lr.SetPosition(1, ray.GetPoint(10));  
}  
}  
}  
else  
{  
lr.SetPosition(0, Vector3.zero);  
lr.SetPosition(1, Vector3.zero);  
}  
 
if (Deleting)  
{  
RaycastHit info = new RaycastHit();  
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);  
bool hit = Physics.Raycast(ray, out info, Mathf.Infinity);  
 
CoreStrut closest = null;  
float closestDist = Mathf.Infinity;  
foreach (CoreStrut strut in struts)  
{  
strut.Selected = false;  
if (hit)  
{  
Vector3 start = strut.parent.transform.TransformPoint(strut.parentOffset);  
float d = Vector3.Distance(start, info.point);  
 
if (d < 0.05 && d < closestDist)  
{  
closest = strut;  
closestDist = d;  
}  
}  
}  
 
if(closest != null)  
closest.Selected = true;  
 
if (Input.GetMouseButtonUp(0))  
{  
if (closest != null)  
{  
closest.Destroy();  
struts.Remove(closest);  
}  
Deleting = false;  
}  
}  
}  
else  
{  
DestroyLaser();  
}  
 
foreach (CoreStrut s in struts.ToArray())  
{  
if (IsEnabled)  
{  
if (s.Active)  
{  
if (PowerConsumption == 0 || (GetEnergy() > PowerConsumption * TimeWarp.fixedDeltaTime && part.RequestResource("ElectricCharge", PowerConsumption * TimeWarp.fixedDeltaTime) > 0))  
{  
s.Active = true;  
}  
else  
{  
s.Active = false;  
}  
}  
else  
{  
if (GetEnergy() > 5 * TimeWarp.fixedDeltaTime && part.RequestResource("ElectricCharge", 5 * TimeWarp.fixedDeltaTime) > 0)  
{  
s.Active = true;  
}  
}  
}  
else  
{  
s.Active = false;  
}  
 
s.Update();  
if (s.isDestroyed)  
struts.Remove(s);  
}  
base.OnUpdate();  
}  
}  
}  
 
  <?xml version="1.0" encoding="utf-8"?>
  <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration>
  <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  <ProductVersion>8.0.30703</ProductVersion>
  <SchemaVersion>2.0</SchemaVersion>
  <ProjectGuid>{D6EC2150-27A5-4CB2-ACF9-C53FF7754A77}</ProjectGuid>
  <OutputType>Library</OutputType>
  <RootNamespace>QuantumStrutsContinued</RootNamespace>
  <AssemblyName>QuantumStrutsContinued</AssemblyName>
  <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  <UseMSBuildEngine>False</UseMSBuildEngine>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
  <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <OutputPath>bin\Debug</OutputPath>
  <DefineConstants>DEBUG;</DefineConstants>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <PlatformTarget>x86</PlatformTarget>
  <ConsolePause>false</ConsolePause>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\QuantumStrutsContinued\Plugins\" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' ">
  <Optimize>true</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <PlatformTarget>x86</PlatformTarget>
  <ConsolePause>false</ConsolePause>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\QuantumStrutsContinued\Plugins\" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
  <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <OutputPath>bin\Debug</OutputPath>
  <DefineConstants>DEBUG;</DefineConstants>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <PlatformTarget>x86</PlatformTarget>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="cp -af ${TargetFile} ${ProjectDir}/GameData/QuantumStrutsContinued/Plugins/" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' ">
  <Optimize>true</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="cp -af ${TargetFile} ${ProjectDir}/GameData/QuantumStrutsContinued/Plugins/" />
  </CustomCommands>
  </CustomCommands>
  <ConsolePause>false</ConsolePause>
  <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <ItemGroup>
  <Compile Include="QuantumStrut.cs" />
  <Compile Include="Strut.cs" />
  <Compile Include="Util.cs" />
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Compile Include="..\ToadicusTools\Extensions\ComponentExtensions.cs">
  <Link>ToadicusTools\ComponentExtensions.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Text\Extensions.cs">
  <Link>ToadicusTools\Extensions.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Logging.cs">
  <Link>ToadicusTools\Logging.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\MathTools.cs">
  <Link>ToadicusTools\MathTools.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\MuMechTools\MuMech_Tools.cs">
  <Link>ToadicusTools\MuMech_Tools.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Extensions\PartExtensions.cs">
  <Link>ToadicusTools\PartExtensions.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Debug\PooledDebugLogger.cs">
  <Link>ToadicusTools\PooledDebugLogger.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\APIHelpers\PooledObject.cs">
  <Link>ToadicusTools\PooledObject.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Text\PooledStringBuilder.cs">
  <Link>ToadicusTools\PooledStringBuilder.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Text\SIFormatProvider.cs">
  <Link>ToadicusTools\SIFormatProvider.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Text\TextTools.cs">
  <Link>ToadicusTools\TextTools.cs</Link>
  </Compile>
  <Compile Include="..\ToadicusTools\Enums.cs">
  <Link>ToadicusTools\Enums.cs</Link>
  </Compile>
  </ItemGroup>
  <ProjectExtensions>
  <MonoDevelop>
  <Properties>
  <Policies>
  <StandardHeader Text="${ProjectName}&#xD;&#xA;&#xD;&#xA;${FileName}&#xD;&#xA;&#xD;&#xA;Copyright © ${Year}, ${AuthorName}&#xD;&#xA;All rights reserved.&#xD;&#xA;&#xD;&#xA;Redistribution and use in source and binary forms, with or without modification,&#xD;&#xA;are permitted provided that the following conditions are met:&#xD;&#xA;&#xD;&#xA;1. Redistributions of source code must retain the above copyright notice,&#xD;&#xA; this list of conditions and the following disclaimer.&#xD;&#xA;&#xD;&#xA;2. Redistributions in binary form must reproduce the above copyright notice,&#xD;&#xA; this list of conditions and the following disclaimer in the documentation and/or other&#xD;&#xA; materials provided with the distribution.&#xD;&#xA;&#xD;&#xA;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES,&#xD;&#xA;INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE&#xD;&#xA;DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,&#xD;&#xA;SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR&#xD;&#xA;SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,&#xD;&#xA;WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE&#xD;&#xA;OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." IncludeInNewFiles="True" />
  </Policies>
  </Properties>
  </MonoDevelop>
  </ProjectExtensions>
  <ItemGroup>
  <Reference Include="Assembly-CSharp">
  <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
  <Private>False</Private>
  </Reference>
  <Reference Include="System">
  <HintPath>..\_KSPAssemblies\System.dll</HintPath>
  <Private>False</Private>
  </Reference>
  <Reference Include="UnityEngine">
  <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
  <Private>False</Private>
  </Reference>
  </ItemGroup>
  <ItemGroup>
  <None Include="GameData\QuantumStrutsContinued\KASifyQSC.cfg" />
  <None Include="GameData\QuantumStrutsContinued\Parts\QuantumStruts\quantumStrut\part.cfg" />
  <None Include="GameData\QuantumStrutsContinued\Parts\QuantumStruts\strutGun\part.cfg" />
  <None Include="GameData\QuantumStrutsContinued\LICENSE" />
  </ItemGroup>
  <ItemGroup>
  <Folder Include="ToadicusTools\" />
  </ItemGroup>
  </Project>
file:a/Strut.cs -> file:b/Strut.cs
using System; // QuantumStrutsContinued
using System.Collections.Generic; //
using System.Linq; // Strut.cs
using System.Text; //
using System.Threading.Tasks; // Continued from QuantumStruts by BoJaN. Used by permission.
using UnityEngine; //
  // ModuleManager patches © 2014 K3|Chris. Used by permission.
namespace QuantumStrut //
{ // Copyright © 2014, toadicus
class Strut // All rights reserved.
{ //
public bool isDestroyed = false; // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
Material _material = null; //
public Material Material // 1. Redistributions of source code must retain the above copyright notice,
{ // this list of conditions and the following disclaimer.
set //
{ // 2. Redistributions in binary form must reproduce the above copyright notice,
_material = value; // this list of conditions and the following disclaimer in the documentation and/or other
if(Material!=null) // materials provided with the distribution.
lr.material = Material; //
} // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
get // 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,
return _material; // 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.
Color _startColor = Color.white;  
public Color StartColor using KSP;
{ using System;
set using UnityEngine;
{  
_startColor = value; namespace QuantumStrut
if (StartColor != null && EndColor != null) {
lr.SetColors(StartColor, EndColor); class Strut
} {
get public bool isDestroyed = false;
{ Material _material = null;
return _startColor;  
} public Material Material
} {
  set
Color _endColor = Color.white; {
public Color EndColor _material = value;
{ if (Material != null)
set lr.material = Material;
{ }
_endColor = value; get
if (StartColor != null && EndColor != null) {
lr.SetColors(StartColor, EndColor); return _material;
} }
get }
{  
return _endColor; Color _startColor = Color.white;
}  
} public Color StartColor
  {
float _startSize = 0; set
public float StartSize {
{ _startColor = value;
set lr.SetColors(StartColor, EndColor);
{ }
_startSize = value; get
lr.SetWidth(StartSize, EndSize); {
} return _startColor;
get }
{ }
return _startSize;  
} Color _endColor = Color.white;
}  
  public Color EndColor
float _endSize = 0; {
public float EndSize set
{ {
set _endColor = value;
{ lr.SetColors(StartColor, EndColor);
_endSize = value; }
lr.SetWidth(StartSize, EndSize); get
} {
get return _endColor;
{ }
return _endSize; }
}  
} float _startSize = 0;
   
ConfigurableJoint joint; public float StartSize
  {
Transform parentTransform = null; set
Part parent = null; {
Part target = null; _startSize = value;
Vector3 targetOffset = Vector3.zero; lr.SetWidth(StartSize, EndSize);
  }
GameObject LineObj = null; get
LineRenderer lr = null; {
  return _startSize;
public void print(object body, params object[] args) }
{ }
string final = body.ToString();  
for (int I = 0; I < args.Length; I++) float _endSize = 0;
{  
final = final.Replace("{" + I + "}", args[I].ToString()); public float EndSize
} {
MonoBehaviour.print("[AutoStrut] " + final); set
} {
  _endSize = value;
void DrawLine(Vector3 origin, Vector3 end) lr.SetWidth(StartSize, EndSize);
{ }
if (Util.isValid(lr)) get
{ {
lr.SetPosition(0, origin); return _endSize;
lr.SetPosition(1, end); }
} }
}  
  ConfigurableJoint joint;
public Strut(Part parent, Part target, Vector3 targetOffset, Transform parentTransform) Transform parentTransform = null;
{ Part parent = null;
this.parent = parent; Part target = null;
this.target = target; Vector3 targetOffset = Vector3.zero;
this.targetOffset = targetOffset; GameObject LineObj = null;
this.parentTransform = parentTransform; LineRenderer lr = null;
   
if (parent.vessel.parts.Contains(target)) public void print(object body, params object[] args)
{ {
joint = parent.parent.gameObject.AddComponent<ConfigurableJoint>(); string final = body.ToString();
joint.connectedBody = target.rigidbody; for (int I = 0; I < args.Length; I++)
  {
joint.anchor = new Vector3(0, 0, Vector3.Distance(parentTransform.position, target.transform.TransformPoint(targetOffset)) / 2); final = final.Replace("{" + I + "}", args[I].ToString());
joint.axis = new Vector3(0, 0, 1); }
joint.xMotion = ConfigurableJointMotion.Locked; MonoBehaviour.print("[AutoStrut] " + final);
joint.yMotion = ConfigurableJointMotion.Locked; }
joint.zMotion = ConfigurableJointMotion.Locked;  
joint.angularXMotion = ConfigurableJointMotion.Locked; void DrawLine(Vector3 origin, Vector3 end)
joint.angularYMotion = ConfigurableJointMotion.Locked; {
joint.angularZMotion = ConfigurableJointMotion.Locked; if (Util.isValid(lr))
  {
LineObj = new GameObject(); lr.SetPosition(0, origin);
LineObj.name = "quantumstrut"; lr.SetPosition(1, end);
  }
lr = LineObj.AddComponent<LineRenderer>(); }
lr.useWorldSpace = true;  
  public Strut(Part parent, Part target, Vector3 targetOffset, Transform parentTransform)
Material = QuantumStrut.LaserMaterial; {
StartColor = Color.white; this.parent = parent;
EndColor = Color.white; this.target = target;
StartSize = 0.03f; this.targetOffset = targetOffset;
EndSize = 0.0075f; this.parentTransform = parentTransform;
   
lr.SetVertexCount(2); if (parent.vessel.parts.Contains(target))
lr.SetPosition(0, Vector3.zero); {
lr.SetPosition(1, Vector3.zero); joint = parent.parent.gameObject.AddComponent<ConfigurableJoint>();
} joint.connectedBody = target.rigidbody;
else  
{ joint.anchor = new Vector3(
Destroy(); 0,
} 0,
} Vector3.Distance(
  parentTransform.position,
public void Update() target.transform.TransformPoint(targetOffset)
{ ) / 2
if (Util.isValid(parent) && Util.isValid(target) && Util.isValid(parent.vessel) && parent.vessel.parts.Contains(target)) );
{ joint.axis = new Vector3(0, 0, 1);
Vector3 start = parentTransform.position; joint.xMotion = ConfigurableJointMotion.Locked;
Vector3 end = target.transform.TransformPoint(targetOffset); joint.yMotion = ConfigurableJointMotion.Locked;
DrawLine(start, end); joint.zMotion = ConfigurableJointMotion.Locked;
} joint.angularXMotion = ConfigurableJointMotion.Locked;
else joint.angularYMotion = ConfigurableJointMotion.Locked;
{ joint.angularZMotion = ConfigurableJointMotion.Locked;
DrawLine(Vector3.zero, Vector3.zero);  
Destroy(); LineObj = new GameObject();
} LineObj.name = "quantumstrut";
}  
  lr = LineObj.AddComponent<LineRenderer>();
public void Destroy() lr.useWorldSpace = true;
{  
DrawLine(Vector3.zero, Vector3.zero); Material = QuantumStrut.LaserMaterial;
if (Util.isValid(joint)) StartColor = Color.white;
GameObject.DestroyImmediate(joint); EndColor = Color.white;
  StartSize = 0.03f;
if (Util.isValid(lr)) EndSize = 0.0075f;
GameObject.DestroyImmediate(lr);  
  lr.SetVertexCount(2);
if (Util.isValid(LineObj)) lr.SetPosition(0, Vector3.zero);
GameObject.DestroyImmediate(LineObj); lr.SetPosition(1, Vector3.zero);
  }
joint = null; else
LineObj = null; {
lr = null; Destroy();
  }
parentTransform = null; }
parent = null;  
target = null; public void Update()
targetOffset = Vector3.zero; {
isDestroyed = true; if (Util.isValid(parent) && Util.isValid(target) && Util.isValid(parent.vessel) && parent.vessel.parts.Contains(target))
} {
} Vector3 start = parentTransform.position;
  Vector3 end = target.transform.TransformPoint(targetOffset);
  DrawLine(start, end);
  }
  else
  {
  DrawLine(Vector3.zero, Vector3.zero);
  Destroy();
  }
  }
   
  public void Destroy()
  {
  DrawLine(Vector3.zero, Vector3.zero);
  if (Util.isValid(joint))
  GameObject.DestroyImmediate(joint);
   
  if (Util.isValid(lr))
  GameObject.DestroyImmediate(lr);
   
  if (Util.isValid(LineObj))
  GameObject.DestroyImmediate(LineObj);
   
  joint = null;
  LineObj = null;
  lr = null;
   
  parentTransform = null;
  parent = null;
  target = null;
  targetOffset = Vector3.zero;
  isDestroyed = true;
  }
  }
} }
file:a/Util.cs -> file:b/Util.cs
using System; // QuantumStrutsContinued
using System.Collections.Generic; //
using System.ComponentModel; // Util.cs
using System.Linq; //
using System.Text; // Continued from QuantumStruts by BoJaN. Used by permission.
using System.Threading.Tasks; //
using KSP.IO; // ModuleManager patches © 2014 K3|Chris. Used by permission.
using UnityEngine; //
  // Copyright © 2014, toadicus
namespace QuantumStrut // All rights reserved.
{ //
public static class Util // Redistribution and use in source and binary forms, with or without modification,
{ // are permitted provided that the following conditions are met:
static System.Random r = new System.Random(); //
  // 1. Redistributions of source code must retain the above copyright notice,
public static float Random(float min, float max) // this list of conditions and the following disclaimer.
{ //
return (float)((r.NextDouble() * (max - min)) + min); // 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.
public static float Random() //
{ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
return (float)r.NextDouble(); // 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
public static Part getTank(Part parent) // 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
if (parent.Resources.Count != 0) // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return parent;  
   
if (isValid(parent.parent) && parent.fuelCrossFeed)  
return getTank(parent.parent);  
   
return null;  
}  
   
public static Vessel Kerbal  
{  
get  
{  
if (isValid(FlightGlobals.fetch.activeVessel) && FlightGlobals.fetch.activeVessel.isEVA)  
return FlightGlobals.fetch.activeVessel;  
return null;  
}  
}  
   
public static bool isValid(UnityEngine.Object obj)  
{  
return (obj && obj != null);  
}  
   
public static void printObj(object obj)  
{  
using (KSP.IO.TextWriter writer = TextWriter.CreateForType<string>("obj.cs"))  
{  
string str = printProperties(obj, TypeDescriptor.GetProperties(obj), 0);  
writer.Write(str);  
MonoBehaviour.print(str);  
}  
}  
   
static string printProperties(object obj, PropertyDescriptorCollection collection, int I)  
{  
if (I > 2) return "";  
   
string prefix = "";  
string str = "";  
for (int T = 0; T < I; T++)  
{  
prefix += " ";  
}  
   
foreach (PropertyDescriptor d in collection)  
{  
str += "\n" + prefix + d.Name + " = " + d.GetValue(obj);  
}  
return str;  
}  
   
public static Part partFromGameObject(GameObject ob)  
{  
GameObject o = ob;  
   
while (o)  
{  
Part p = Part.FromGO(o);  
if (p && p != null)  
{  
return p;  
}  
   
if (o.transform.parent)  
o = o.transform.parent.gameObject;  
else  
return null;  
}  
return null;  
}  
   
public static Part partFromRaycast(RaycastHit hit)  
{  
return partFromGameObject(hit.collider.gameObject);  
}  
   
public static Part partFromId(Vessel vessel, long id)  
{  
Console.WriteLine("Vessel Parts: " + vessel.Parts.Count);  
foreach (Part p in vessel.Parts)  
{  
MonoBehaviour.print(p.uid + " ?= " + id + ": " + (p.uid == id));  
if (p.uid == id)  
return p;  
}  
return null;  
}  
   
public static float GetEnergy(Vessel vessel)  
{  
double energy = 0;  
foreach (Part p in vessel.parts)  
{  
foreach (PartResource r in p.Resources)  
{  
if (r.resourceName == "ElectricCharge")  
energy += r.amount;  
}  
}  
return (float)energy;  
}  
}  
}  
   
  using KSP.IO;
  using System;
  using System.ComponentModel;
  using UnityEngine;
   
  namespace QuantumStrut
  {
  public static class Util
  {
  static System.Random r = new System.Random();
   
  public static float Random(float min, float max)
  {
  return (float)((r.NextDouble() * (max - min)) + min);
  }
   
  public static float Random()
  {
  return (float)r.NextDouble();
  }
   
  public static Part getTank(Part parent)
  {
  if (parent.Resources.Count != 0)
  return parent;
   
  if (isValid(parent.parent) && parent.fuelCrossFeed)
  return getTank(parent.parent);
   
  return null;
  }
   
  public static Vessel Kerbal
  {
  get
  {
  if (isValid(FlightGlobals.fetch.activeVessel) && FlightGlobals.fetch.activeVessel.isEVA)
  return FlightGlobals.fetch.activeVessel;
  return null;
  }
  }
   
  public static bool isValid(UnityEngine.Object obj)
  {
  return (obj && obj != null);
  }
   
  public static void printObj(object obj)
  {
  using (KSP.IO.TextWriter writer = TextWriter.CreateForType<string>("obj.cs"))
  {
  string str = printProperties(obj, TypeDescriptor.GetProperties(obj), 0);
  writer.Write(str);
  MonoBehaviour.print(str);
  }
  }
   
  static string printProperties(object obj, PropertyDescriptorCollection collection, int I)
  {
  if (I > 2)
  return "";
   
  string prefix = "";
  string str = "";
  for (int T = 0; T < I; T++)
  {
  prefix += " ";
  }
   
  PropertyDescriptor d;
  for (int i = 0; i < collection.Count; i++)
  {
  d = collection[i];
   
  str += "\n" + prefix + d.Name + " = " + d.GetValue(obj);
  }
  return str;
  }
   
  public static Part partFromGameObject(GameObject ob)
  {
  GameObject o = ob;
   
  while (o)
  {
  Part p = Part.FromGO(o);
  if (p && p != null)
  {
  return p;
  }
   
  if (o.transform.parent)
  o = o.transform.parent.gameObject;
  else
  return null;
  }
  return null;
  }
   
  public static Part partFromRaycast(RaycastHit hit)
  {
  return partFromGameObject(hit.collider.gameObject);
  }
   
  public static float GetEnergy(Vessel vessel)
  {
  double energy = 0;
  Part p;
  for (int pIdx = 0; pIdx < vessel.parts.Count; pIdx++)
  {
  p = vessel.parts[pIdx];
   
  PartResource r;
  for (int rIdx = 0; rIdx < p.Resources.Count; rIdx++)
  {
  r = p.Resources[rIdx];
   
  if (r.resourceName == "ElectricCharge")
  energy += r.amount;
  }
  }
  return (float)energy;
  }
  }
  }