Initial commit. QuantumStruts
Initial commit.

file:b/CoreStrut.cs (new)
--- /dev/null
+++ b/CoreStrut.cs
@@ -1,1 +1,219 @@
-
+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;

+        }

+    }

+}

--- /dev/null
+++ b/Properties/AssemblyInfo.cs
@@ -1,1 +1,37 @@
+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("AutoStrut")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("AutoStrut")]

+[assembly: AssemblyCopyright("Copyright ©  2012")]

+[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("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.0.0.0")]

+[assembly: AssemblyFileVersion("1.0.0.0")]

 

file:b/QuantumStrut.cs (new)
--- /dev/null
+++ b/QuantumStrut.cs
@@ -1,1 +1,332 @@
-
+using System;

+using System.Collections.Generic;

+using System.Linq;

+using System.Text;

+using System.Threading.Tasks;

+using UnityEngine;

+

+namespace QuantumStrut

+{

+    public class QuantumStrut : PartModule

+    {

+        public static Material LaserMaterial;

+

+        Strut strut = null;

+        GameObject lineObj;

+        LineRenderer lr;

+        bool Editor = false;

+        int I = 0;

+

+        #region Fields

+        [KSPField(isPersistant = true)]

+        public bool IsEnabled = true;

+

+        [KSPField(isPersistant = false)]

+        public float PowerConsumption = 0;

+

+

+        [KSPField(isPersistant = false)]

+        public string TransformName = "";

+

+        [KSPField(isPersistant = false)]

+        public Vector3 Start = new Vector3(0,0,0);

+

+        [KSPField(isPersistant = false)]

+        public Vector3 Dir = new Vector3(0, 1, 0);

+

+

+        [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 ToggleStrut(KSPActionParam param)

+        {

+            IsEnabled = !IsEnabled;

+            CheckHit();

+        }

+

+        [KSPAction("Activate")]

+        public void ActivateStrut(KSPActionParam param)

+        {

+            IsEnabled = true;

+            CheckHit();

+        }

+

+        [KSPAction("Deactivate")]

+        public void DeactivateStrut(KSPActionParam param)

+        {

+            IsEnabled = false;

+            CheckHit();

+        }

+        #endregion

+

+        #region Events

+        [KSPEvent(guiActive = true, guiName = "Activate", active = true)]

+        public void ActivateStrut()

+        {

+            IsEnabled = true;

+            CheckHit();

+        }

+

+        [KSPEvent(guiActive = true, guiName = "Deactivate", active = false)]

+        public void DeactivateStrut()

+        {

+            IsEnabled = false;

+            CheckHit();

+        }

+        #endregion

+

+        public Material material = null;

+        public Color startColor = Color.white;

+        public Color endColor = Color.white;

+

+        public Color Vector3toColor(Vector3 vec)

+        {

+            return new Color(vec.x/255, vec.y/255, vec.z/255);

+        }

+

+        Transform getTransform()

+        {

+            if (TransformName == "")

+                return part.transform;

+            else

+                return part.FindModelTransform(TransformName);

+        }

+

+        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);

+        }

+

+        public override void OnLoad(ConfigNode node)

+        {

+            base.OnLoad(node);

+        }

+

+        public override void OnActive()

+        {

+            InitLaser();

+

+            base.OnActive();

+        }

+

+        public override void OnInactive()

+        {

+            DestroyLaser();

+

+            base.OnInactive();

+        }

+

+        public override string GetInfo()

+        {

+            return "Requires:\n- ElectricCharge (" + PowerConsumption + "/s.)\n\n Costs 5 to create strut.";

+            return base.GetInfo();

+        }

+

+        public override void OnStart(PartModule.StartState state)

+        {

+            try

+            {

+                print("Material: {0}", Material);

+                material = new Material(Shader.Find(Material.Trim()));

+            }

+            catch

+            {

+                material = null;

+            }

+

+            startColor = Vector3toColor(StartColor);

+            endColor = Vector3toColor(EndColor);

+

+            if (!Util.isValid(LaserMaterial))

+                LaserMaterial = new Material(Shader.Find("Particles/Additive"));

+

+            if (state == StartState.Docked)

+                CheckHit();

+

+            if (state == StartState.Editor)

+            {

+                Editor = true;

+                RenderingManager.AddToPostDrawQueue(0, DrawBuildOverlay);

+                InitLaser();

+            }

+            else

+            {

+                Editor = false;

+                RenderingManager.RemoveFromPostDrawQueue(0, DrawBuildOverlay);

+                DestroyLaser();

+            }

+

+            base.OnStart(state);

+        }

+

+        public override void OnFixedUpdate()

+        {

+            base.OnFixedUpdate();

+        }

+

+

+        public override void OnUpdate()

+        {

+            Events["ActivateStrut"].active = !IsEnabled;

+            Events["DeactivateStrut"].active = IsEnabled;

+

+            if (IsEnabled)

+            {

+                I = I + 1 % 255;

+

+                if (strut != null && !strut.isDestroyed)

+                {

+                    if (PowerConsumption == 0 || (Util.GetEnergy(part.vessel) > PowerConsumption * TimeWarp.fixedDeltaTime && part.RequestResource("ElectricCharge", PowerConsumption * TimeWarp.fixedDeltaTime) > 0))

+                        strut.Update();

+                    else

+                        strut.Destroy();

+                }

+                else

+                {

+                    if ((I % 10)==0)

+                    {

+                        CheckHit();

+                    }

+                }

+            }

+            else

+            {

+                if (strut != null)

+                {

+                    strut.Destroy();

+                    strut = null;

+                }

+            }

+

+            base.OnUpdate();

+        }

+

+        void CheckHit()

+        {

+            if (!isEnabled)

+            {

+                strut.Destroy();

+                strut = null;

+                return;

+            }

+

+            if (strut == null || strut.isDestroyed)

+            {

+                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)

+                {

+                    Part targetPart = Util.partFromRaycast(info);

+

+                    if (targetPart && vessel.parts.Contains(targetPart) && Util.GetEnergy(part.vessel) > 5 * TimeWarp.fixedDeltaTime)

+                    {

+                        float energy = part.RequestResource("ElectricCharge", 5 * TimeWarp.fixedDeltaTime);

+

+                        strut = new Strut(part, targetPart, targetPart.transform.InverseTransformPoint(info.point), getTransform());

+                        strut.Material = material;

+                        strut.StartColor = startColor;

+                        strut.EndColor = endColor;

+                        strut.StartSize = StartSize;

+                        strut.EndSize = EndSize;

+                    }

+                }

+            }

+        }

+

+        void InitLaser()

+        {

+            if (!Util.isValid(lr))

+            {

+                lineObj = new GameObject();

+

+                lr = lineObj.AddComponent<LineRenderer>();

+                lr.useWorldSpace = true;

+

+                lr.material = material;

+                lr.SetColors(startColor, endColor);

+                lr.SetWidth(StartSize, EndSize);

+

+                lr.SetVertexCount(2);

+                lr.SetPosition(0, Vector3.zero);

+                lr.SetPosition(1, Vector3.zero);

+                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)

+                    {

+                        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);

+            }

+        }

+    }

+}

--- /dev/null
+++ b/QuantumStrutCore.cs
@@ -1,1 +1,474 @@
+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();

+        }

+    }

+}

 

file:b/Strut.cs (new)
--- /dev/null
+++ b/Strut.cs
@@ -1,1 +1,197 @@
-
+using System;

+using System.Collections.Generic;

+using System.Linq;

+using System.Text;

+using System.Threading.Tasks;

+using UnityEngine;

+

+namespace QuantumStrut

+{

+    class Strut

+    {

+        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;

+

+        Transform parentTransform = null;

+        Part parent = null;

+        Part target = null;

+        Vector3 targetOffset = Vector3.zero;

+

+        GameObject LineObj = null;

+        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);

+            }

+        }

+

+        public Strut(Part parent, Part target, Vector3 targetOffset, Transform parentTransform)

+        {

+            this.parent = parent;

+            this.target = target;

+            this.targetOffset = targetOffset;

+            this.parentTransform = parentTransform;

+

+            if (parent.vessel.parts.Contains(target))

+            {

+                joint = parent.parent.gameObject.AddComponent<ConfigurableJoint>();

+                joint.connectedBody = target.rigidbody;

+

+                joint.anchor = new Vector3(0, 0, Vector3.Distance(parentTransform.position, 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;

+

+                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);

+            }

+            else

+            {

+                Destroy();

+            }

+        }

+

+        public void Update()

+        {

+            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:b/Util.cs (new)
--- /dev/null
+++ b/Util.cs
@@ -1,1 +1,132 @@
+using System;

+using System.Collections.Generic;

+using System.ComponentModel;

+using System.Linq;

+using System.Text;

+using System.Threading.Tasks;

+using KSP.IO;

+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 += "    ";

+            }

+

+            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;

+        }

+    }

+}