<repo_name>masaywar/MP_ARCT<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_GateEnd.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_LG_GateEnd : UIC_LG_Gate
{
    protected override void Awake()
    {
        base.Awake();
        _image = GetComponent<Image>();
        _text = transform.GetChild(0).GetComponentInChildren<Text>();
    }

    void Update()
    {
        if (outValue == 1)
        {
            Color outColor = Color.green;
            ColorUtility.TryParseHtmlString("#6AFF6A", out outColor);
            _image.color = outColor;
            _text.text = "on";
        }
        else if (outValue == 0)
        {
            Color outColor = Color.green;
            ColorUtility.TryParseHtmlString("#636363", out outColor);
            _image.color = outColor;
            _text.text = "off";
        }
        else
        {
            _image.color = new Color(1, 1, 1);
            _text.text = "--";
        }
    }

    Image _image;
    Text _text;

    public override void Solve()
    {
        GetInputs();

        if (inputs.Count > 0)
        {
            outValue = inputs[0];
        }
        else
        {
            outValue = -1;
            return;
        }
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Pointer.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

//[ExecuteInEditMode]
public class UIC_Pointer : MonoBehaviour
{
    UIC_Manager _uicManager;
    public KeyCode clickKey;
    public KeyCode secondaryKey;

    Image _image;
    Canvas _pointerCanvas;

    GraphicRaycaster m_Raycaster;
    PointerEventData m_PointerEventData;
    EventSystem m_EventSystem;

    public Sprite iconDefault;
    public Sprite iconHold;

    Vector3 _initialMousePos;

    List<I_UIC_Object> _orderedObjectsList = new List<I_UIC_Object>();

    // v1.3 - corrected pointer position for canvas render mode overlay and camera
    public Vector3 PointerPosition
    {
        get
        {
            return Input.mousePosition;
        }
    }

    public UnityEvent e_OnPointerDownFirst;
    public UnityEvent e_OnPointerDownLast;

    public UnityEvent e_OnDragFirst;
    public UnityEvent e_OnDragLast;

    public UnityEvent e_OnPointerUpFirst;
    public UnityEvent e_OnPointerUpLast;
    // OBS.: event First and Last means that it is called prior or after all the actions on the event

    void OnDrawGizmos()
    {
#if UNITY_EDITOR
        if (!Application.isPlaying)
        {
            UnityEditor.EditorApplication.QueuePlayerLoopUpdate();
            UnityEditor.SceneView.RepaintAll();
        }
#endif
    }

    void OnValidate()
    {
        Init();

        Awake();
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
    }

    void Start()
    {
        e_OnPointerDownFirst = e_OnPointerDownFirst ?? new UnityEvent();
        e_OnPointerDownLast = e_OnPointerDownLast ?? new UnityEvent();
        e_OnDragFirst = e_OnDragFirst ?? new UnityEvent();
        e_OnDragLast = e_OnDragLast ?? new UnityEvent();
        e_OnPointerUpFirst = e_OnPointerUpFirst ?? new UnityEvent();
        e_OnPointerUpLast = e_OnPointerUpLast ?? new UnityEvent();

        Cursor.visible = false;
        FollowMouse();
        Init();

        m_Raycaster = FindObjectOfType<GraphicRaycaster>();
        m_EventSystem = FindObjectOfType<EventSystem>();
    }

    public void Init()
    {
        _image = _image ? _image : GetComponent<Image>() ? GetComponent<Image>() : gameObject.AddComponent<Image>();
        _image.raycastTarget = false;
        _pointerCanvas = _pointerCanvas ? _pointerCanvas : GetComponent<Canvas>() ? GetComponent<Canvas>() : gameObject.AddComponent<Canvas>();
        _pointerCanvas.overrideSorting = true;
        _pointerCanvas.sortingOrder = 999; // pointer on top of everything makes dragged entity being also on top of everithing
    }

    void Update()
    {
        FollowMouse();

        if (Input.GetKeyDown(clickKey))
        {
            OnPointerDown();
        }

        if (Input.GetKey(clickKey))
        {
            if (_initialMousePos != transform.position)
                OnDrag();
        }

        if (Input.GetKeyUp(clickKey))
        {
            OnPointerUp();
        }

    }

    private void OnDisable()
    {
        e_OnPointerDownFirst.RemoveAllListeners();
        e_OnPointerDownLast.RemoveAllListeners();
        e_OnDragFirst.RemoveAllListeners();
        e_OnDragLast.RemoveAllListeners();
        e_OnPointerUpFirst.RemoveAllListeners();
        e_OnPointerUpLast.RemoveAllListeners();
    }

    void FollowMouse()
    {
        Camera mainCamera = _uicManager.mainCamera;
        if (_uicManager.CanvasRenderMode == RenderMode.ScreenSpaceOverlay)
        {
            transform.position = PointerPosition;
        }
        else if (_uicManager.CanvasRenderMode == RenderMode.ScreenSpaceCamera)
        {
            var screenPoint = PointerPosition;
            screenPoint.z = _uicManager.transform.position.z - mainCamera.transform.position.z; //distance of the plane from the camera
            transform.position = mainCamera.ScreenToWorldPoint(screenPoint);
        }
        // v1.5 - set pointer on the world space canvas
        else if (_uicManager.CanvasRenderMode == RenderMode.WorldSpace)
        {
            var screenPoint = PointerPosition;
            screenPoint.z = _uicManager.transform.position.z - mainCamera.transform.position.z; //distance of the plane from the camera
            transform.position = mainCamera.ScreenToWorldPoint(screenPoint);
        }
    }

    public void OnPointerDown()
    {
        e_OnPointerDownFirst.Invoke();

        _image.sprite = iconHold;

        SelectCloserUIObject();
        UIC_ContextMenu.UpdateContextMenu();
        _initialMousePos = transform.position;

        e_OnPointerDownLast.Invoke();
    }

    public void OnDrag()
    {
        e_OnDragFirst.Invoke();

        if (_uicManager.clickedUIObject is I_UIC_Draggable)
            (_uicManager.clickedUIObject as I_UIC_Draggable).OnDrag();

        if (_uicManager.clickedUIObject is UIC_Entity)
        {
            foreach (I_UIC_Selectable obj in _uicManager.selectedUIObjectsList)
            {
                if (obj is UIC_Entity)
                {
                    (obj as I_UIC_Draggable).OnDrag();
                }
            }
        }

        e_OnDragLast.Invoke();
    }

    public void OnPointerUp()
    {
        e_OnPointerUpFirst.Invoke();

        _image.sprite = iconDefault;

        if (_uicManager.clickedUIObject is I_UIC_Clickable)
            (_uicManager.clickedUIObject as I_UIC_Clickable).OnPointerUp();

        foreach (I_UIC_Object uiObject in _uicManager.selectedUIObjectsList)
        {
            if (uiObject is I_UIC_Clickable)
                (uiObject as I_UIC_Clickable).OnPointerUp();
        }

        e_OnPointerUpLast.Invoke();
    }

    public void UnselectAllUIObjects()
    {
        if (!Input.GetKey(secondaryKey))
        {
            for (int i = _uicManager.selectedUIObjectsList.Count - 1; i >= 0; i--)
            {
                _uicManager.selectedUIObjectsList[i].Unselect();
            }
        }

    }

    [System.Obsolete]
    public List<RaycastResult> RaycastUI()
    {
        // v2.0 - by using more than one canvases, raycast system needs to know search the objects in every graphicRaycaster
        List<RaycastResult> results = new List<RaycastResult>();
        m_PointerEventData = new PointerEventData(m_EventSystem);
        m_PointerEventData.position = PointerPosition;
        List<RaycastResult> resultsLocal = new List<RaycastResult>();

        // you can cache this array for performance
        GraphicRaycaster[] m_RaycasterArray = FindObjectsOfType<GraphicRaycaster>();
        foreach (GraphicRaycaster gr in m_RaycasterArray)
        {
            gr.Raycast(m_PointerEventData, resultsLocal);
            results.AddRange(resultsLocal);
        }

        return results;
    }

    // v2.0 - fix: wrong raycaster found when using more than one canvas
    public List<RaycastResult> RaycastUIAll()
    {
        List<RaycastResult> results = new List<RaycastResult>();
        m_PointerEventData = new PointerEventData(m_EventSystem);
        m_PointerEventData.position = PointerPosition;
        List<RaycastResult> resultsLocal = new List<RaycastResult>();

        // if the GraphicRaycasters are fixed, its possible to cache this array for performance 
        GraphicRaycaster[] m_RaycasterArray = FindObjectsOfType<GraphicRaycaster>();
        foreach (GraphicRaycaster gr in m_RaycasterArray)
        {
            gr.Raycast(m_PointerEventData, resultsLocal);
            results.AddRange(resultsLocal);
        }

        return results;
    }

    private static int SortByPriority(I_UIC_Object o1, I_UIC_Object o2)
    {
        return o2.Priority.CompareTo(o1.Priority);
    }

    public List<I_UIC_Object> ReorderFoundObjectsToPriority(List<I_UIC_Object> objectsList)
    {
        objectsList.Sort(SortByPriority);
        return objectsList;
    }

    public List<I_UIC_Object> OrderedObjectsUnderPointer()
    {
        List<I_UIC_Object> orderedObjects = new List<I_UIC_Object>();

        List<RaycastResult> results = RaycastUIAll();

        I_UIC_Object uiObject = null;

        foreach (RaycastResult result in results)
        {
            uiObject = result.gameObject.GetComponent<I_UIC_Object>();

            if (uiObject != null)
            {
                if (!(uiObject is I_UIC_Clickable) || !(uiObject as I_UIC_Clickable).DisableClick)
                    orderedObjects.Add(uiObject);
            }
        }

        // v1.5 - find closest connection based on the world space
        if (_uicManager.CanvasRenderMode != RenderMode.WorldSpace)
        {
            uiObject = _uicManager.FindClosestConnectionToPosition(PointerPosition, 15);
        }
        else
        {
            uiObject = _uicManager.FindClosestConnectionToPosition(UIC_Utility.WorldToScreenPointInCanvas(transform.position, _uicManager), 15);
        }
        if (uiObject != null)
            if (!(uiObject as I_UIC_Clickable).DisableClick)
                orderedObjects.Add(uiObject);

        orderedObjects.Sort(SortByPriority);

        return orderedObjects;
    }

    public I_UIC_Object FindObjectCloserToPointer()
    {
        _orderedObjectsList = OrderedObjectsUnderPointer();

        if (_orderedObjectsList.Count > 0)
        {
            if (!(_orderedObjectsList[0] is I_UIC_ContextItem))
                UnselectAllUIObjects();

            return _orderedObjectsList[0];
        }
        else
        {
            UnselectAllUIObjects();
            return null;
        }
    }

    public void SelectCloserUIObject()
    {
        _uicManager.clickedUIObject = FindObjectCloserToPointer();
        if (_uicManager.clickedUIObject is I_UIC_Clickable)
        {
            (_uicManager.clickedUIObject as I_UIC_Clickable).OnPointerDown();
        }
    }

    // v2.0 - method to find closest node by distance made obsolete
    [System.Obsolete("Obsolete, use RaycastClosestNodeOfOppositPolarity instead.")]
    public static UIC_Node FindClosestNodeOfOppositPolarity(Vector2 position, float maxDistance, UIC_Node draggedNode, UIC_Manager uicManager)
    {
        float minDist = Mathf.Infinity;
        UIC_Node closestNode = null;
        foreach (UIC_Entity entity in uicManager.EntityList)
        {
            if ((entity == draggedNode.entity && entity.enableSelfConnection) || entity != draggedNode.entity)
            {
                foreach (UIC_Node node in entity.nodeList)
                {
                    if (draggedNode != node && node.haveSpots && draggedNode.haveSpots)
                    {
                        if (node.polarityType != draggedNode.polarityType || node.polarityType == UIC_Node.PolarityTypeEnum._all)
                        {
                            float distance = Vector2.Distance(position, node.transform.position);
                            if (distance < minDist && distance <= maxDistance / uicManager.uiLineRenderer.rectTransform.localScale.x)
                            {
                                closestNode = node;
                                minDist = distance;
                            }
                        }
                    }
                }
            }
        }
        
        return closestNode;
    }

    // v2.0 - new method to find node using raycast from pointer
    public UIC_Node RaycastClosestNodeOfOppositPolarity(UIC_Node draggedNode)
    {
        UIC_Node closestNode = null;

        List<RaycastResult> results = _uicManager.pointer.RaycastUIAll();
        I_UIC_Object uiObject = null;
        foreach (RaycastResult result in results)
        {
            uiObject = result.gameObject.GetComponent<I_UIC_Object>();

            if (uiObject != null)
            {
                if (!(uiObject is I_UIC_Clickable) || !(uiObject as I_UIC_Clickable).DisableClick)
                    if (uiObject is UIC_Node)
                    {
                        UIC_Node node = (uiObject as UIC_Node);
                        if (draggedNode != node && node.haveSpots && draggedNode.haveSpots)
                            if ((node.entity == draggedNode.entity && node.entity.enableSelfConnection) || node.entity != draggedNode.entity)
                                if (node.polarityType != draggedNode.polarityType || node.polarityType == UIC_Node.PolarityTypeEnum._all)
                                {
                                    return node;
                                }
                    }
            }
        }
        return closestNode;
    }

}
<file_sep>/MP_ARCT/Assets/Scripts/BlockCompiler.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlockCompiler : MonoBehaviour 
{
    public void CompileBlocks(Block[] blocks)
    {
        foreach(var block in blocks)
        {
#if UNITY_EDITOR
            block.TestAction();
#endif
        }
    }

    public void CompileBlock(Block block)
    {
#if UNITY_EDITOR
        block.TestAction();
#endif
        block.BlockAction();
    }
}

<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_GatesManager.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// v1.4 - Logic Gates scene added
// this scene uses a really simple solve method just as inspiration on using the asset. It is possible to use a more complex solver and expand the project.

// gates manager class responsible for calling the solve method of each gate and manage connections 
public class UIC_LG_GatesManager : MonoBehaviour
{
    public UIC_Manager uicManager;

    void Start()
    {
        // add listener for pointer event
        uicManager.pointer.e_OnPointerUpFirst.AddListener(
            delegate
            {
                CheckAndUpdateNodeConnections();
            });
    }

    void Update()
    {
        foreach (UIC_Entity entity in uicManager.EntityList)
        {
            UIC_LG_Gate gate = entity.GetComponent<UIC_LG_Gate>();
            gate.Solve();
            gate.UpdateConnections();
        }
    }

    void CheckAndUpdateNodeConnections()
    {
        UIC_Node clickedNode = uicManager.GetClickedObjectOfType<UIC_Node>();

        if (clickedNode)
        {
            UIC_Node foundNode = clickedNode.lastFoundNode;

            if (foundNode)
            {
                UIC_Connection outConn = clickedNode.connectionsList.Count > 0 ? clickedNode.connectionsList[0] : null;
                UIC_Connection inConn = foundNode.connectionsList.Count > 0 ? foundNode.connectionsList[0] : null;

                if (outConn != null)
                {
                    outConn.Remove();
                }

                if (inConn != null)
                {
                    inConn.Remove();
                }
            }
        }
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Base/ExtensionMethods.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public static class ExtensionMethods
{
    public static void ForEach<T>(this IEnumerable<T> source, System.Action<T> action)
    {
        foreach (var e in source)
            action(e);
    }

    public static List<T> ToList<T>(this IEnumerable<T> source)
    {
        return source.ToList();
    }

    public static IEnumerable<T> ToArray<T>(this IEnumerable<T> source)
    {
        return source.ToArray();
    }

    public static IEnumerable<T> SubArray<T>(this IEnumerable<T> source, int start, int count)
    {
        return source.Skip(start).Take(count);
    }

    public static T GetTop<T>(this T[] array)
    {
        return array[array.Length - 1];
    }

    public static T Top<T>(this List<T> list)
    {
        return list[list.Count - 1];
    }

    public static IEnumerator DoWaitForSeconds(float time, System.Action action)
    {
        yield return new WaitForSeconds(time);
        action();
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Utility.cs
﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class UIC_Utility
{
    // adapted from http://csharphelper.com/blog/2016/09/find-the-shortest-distance-between-a-point-and-a-line-segment-in-c/
    public static float FindDistanceToSegment(Vector2 pt, Vector2 p1, Vector2 p2)
    {
        Vector2 closest;
        float dx = p2.x - p1.x;
        float dy = p2.y - p1.y;
        if ((dx == 0) && (dy == 0))
        {
            // It's a point not a line segment.
            closest = p1;
            dx = pt.x - p1.x;
            dy = pt.y - p1.y;
            return Mathf.Sqrt(dx * dx + dy * dy);
        }

        // Calculate the t that minimizes the distance.
        float t = ((pt.x - p1.x) * dx + (pt.y - p1.y) * dy) /
            (dx * dx + dy * dy);

        // See if this represents one of the segment's
        // end points or a point in the middle.
        if (t < 0)
        {
            closest = new Vector2(p1.x, p1.y);
            dx = pt.x - p1.x;
            dy = pt.y - p1.y;
        }
        else if (t > 1)
        {
            closest = new Vector2(p2.x, p2.y);
            dx = pt.x - p2.x;
            dy = pt.y - p2.y;
        }
        else
        {
            closest = new Vector2(p1.x + t * dx, p1.y + t * dy);
            dx = pt.x - closest.x;
            dy = pt.y - closest.y;
        }

        return Mathf.Sqrt(dx * dx + dy * dy);
    }

    // v1.2 - method DistanceToSpline made obsolete due to missing detection in some cases, changed to DistanceToConnection
    [Obsolete("Method obsolete, use DistanceToConnection instead")]
    public static float DistanceToSpline(UISpline spline, Vector3 point, int steps)
    {
        float minDist = Mathf.Infinity;

        for (int i = 0; i <= steps; i++)
        {
            Vector3 curvePoint = spline.GetPoint(spline.controlPoints[0], spline.controlPoints[1], spline.controlPoints[2],
                        spline.controlPoints[3], (float)i / (float)steps);

            float distance = Vector3.Distance(point, curvePoint);
            if (distance < minDist)
                minDist = distance;
        }

        return minDist;
    }

    // v1.2 - new precise method used to find distance from pointer to connection
    public static float DistanceToConnectino(UIC_Connection conn, Vector3 point, float maxDistance)
    {

        List<Vector2> connPoints = conn.line.points;
        int connectionPointsCount = connPoints.Count;
        float minDist = Mathf.Infinity;

        for (int i = 1; i < connectionPointsCount; i++)
        {
            float distance = UIC_Utility.FindDistanceToSegment(point, connPoints[i - 1], connPoints[i]);
            if (distance < minDist && distance <= maxDistance)
            {
                minDist = distance;
            }
        }

        return minDist;
    }

    // adapted from https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
    //---
    // Given three colinear points p, q, r, the function checks if 
    // point q lies on line segment 'pr' 
    static bool PointIsOnSegment(Vector2 p, Vector2 q, Vector2 r)
    {
        if (q.x <= Mathf.Max(p.x, r.x) && q.x >= Mathf.Min(p.x, r.x) &&
            q.y <= Mathf.Max(p.y, r.y) && q.y >= Mathf.Min(p.y, r.y))
            return true;

        return false;
    }

    // To find orientation of ordered triplet (p, q, r). 
    // The function returns following values 
    // 0 --> p, q and r are colinear 
    // 1 --> Clockwise 
    // 2 --> Counterclockwise 
    static int LineOrientation(Vector2 p, Vector2 q, Vector2 r)
    {
        // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ 
        // for details of below formula. 
        float val = (q.y - p.y) * (r.x - q.x) -
                  (q.x - p.x) * (r.y - q.y);

        if (val == 0) return 0;  // colinear 

        return (val > 0) ? 1 : 2; // clock or counterclock wise 
    }

    // The main function that returns true if line segment 'p1q1' 
    // and 'p2q2' intersect. 
    public static bool LinesDoIntersect(Vector2 p1, Vector2 q1, Vector2 p2, Vector2 q2)
    {
        // Find the four orientations needed for general and 
        // special cases 
        int o1 = LineOrientation(p1, q1, p2);
        int o2 = LineOrientation(p1, q1, q2);
        int o3 = LineOrientation(p2, q2, p1);
        int o4 = LineOrientation(p2, q2, q1);

        // General case 
        if (o1 != o2 && o3 != o4)
            return true;

        // Special Cases 
        // p1, q1 and p2 are colinear and p2 lies on segment p1q1 
        if (o1 == 0 && PointIsOnSegment(p1, p2, q1)) return true;

        // p1, q1 and q2 are colinear and q2 lies on segment p1q1 
        if (o2 == 0 && PointIsOnSegment(p1, q2, q1)) return true;

        // p2, q2 and p1 are colinear and p1 lies on segment p2q2 
        if (o3 == 0 && PointIsOnSegment(p2, p1, q2)) return true;

        // p2, q2 and q1 are colinear and q1 lies on segment p2q2 
        if (o4 == 0 && PointIsOnSegment(p2, q1, q2)) return true;

        return false; // Doesn't fall in any of the above cases 
    }
    //--- 

    public static bool ConnectionsIntersect(UIC_Connection conn1, UIC_Connection conn2)
    {
        bool intersect = false;

        if (conn1 != conn2)
        {
            List<Vector2> conn1Points = conn1.line.points;
            List<Vector2> conn2Points = conn2.line.points;
            int conn1PointsCount = conn1Points.Count;
            int conn2PointsCount = conn2Points.Count;
            for (int i = 1; i < conn1PointsCount; i++)
            {
                for (int j = 1; j < conn2PointsCount; j++)
                {
                    Vector2 p1 = conn1Points[i - 1];
                    Vector2 q1 = conn1Points[i];
                    Vector2 p2 = conn2Points[j - 1];
                    Vector2 q2 = conn2Points[j];
                    intersect = UIC_Utility.LinesDoIntersect(p1, q1, p2, q2);
                    if (intersect)
                        break;
                }
                if (intersect)
                    break;
            }
        }
        return intersect;
    }

    public static bool ConnectionIntersectRect(UIC_Connection conn1, RectTransform rt)
    {
        int intersectCount = 0;

        List<Vector2> conn1Points = conn1.line.points;
        int conn1PointsCount = conn1Points.Count;
        for (int i = 1; i < conn1PointsCount; i++)
        {
            Vector2 p1 = conn1Points[i - 1];
            Vector2 q1 = conn1Points[i];

            Vector3[] v = new Vector3[4];
            rt.GetWorldCorners(v);

            intersectCount = 0;

            for (int j = 1; j <= 4; j++)
            {
                bool intersect = false;

                int k = j;
                Vector2 p2 = v[k - 1];
                if (j == 4)
                {
                    k = 0;
                }
                Vector2 q2 = v[k];

                intersect = UIC_Utility.LinesDoIntersect(p1, q1, p2, q2);

                if (intersect)
                    intersectCount++;

                if (intersectCount >= 2)
                    break;
            }

            if (intersectCount >= 2)
                break;

        }
        return intersectCount >= 2 ? true : false;
    }

    // v2.0 - added local manager to parameters
    // v1.5 - transformation to world space
    public static Vector3 WorldToScreenPointInCanvas(Vector3 point, UIC_Manager uicManager)
    {
        Camera mainCamera = uicManager.mainCamera;
        RectTransform canvasRect = uicManager.canvasRectTransform;

        // v2.1 - Corrected lines position when LineRenderer is offset for Canvas World Space
        Vector3 uicManagerOffset = mainCamera.WorldToScreenPoint(uicManager.transform.position);
        Vector3 uicLineRendererOffset = mainCamera.WorldToScreenPoint(uicManager.uiLineRenderer.transform.position);

        Vector3 screenPos = mainCamera.WorldToScreenPoint(point) - uicLineRendererOffset + uicManagerOffset;
        Vector2 screenPos2D = new Vector2(screenPos.x, screenPos.y);
        Vector2 anchoredPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPos2D, mainCamera, out anchoredPos);
        return anchoredPos;// + new Vector2(canvasRect.sizeDelta.x / 2, canvasRect.sizeDelta.y / 2);
    }

    // v2.1 - Method added to corrected lines position when LineRenderer is offset for Canvas Screen Space Camera
    public static Vector3 WorldToScreenPoint(Vector3 point, UIC_Manager uicManager)
    {
        Camera mainCamera = uicManager.mainCamera;

        // v2.1 - Corrected lines position when LineRenderer is offset for Canvas Screen Space Camera
        Vector3 uicLineRendererOffset = mainCamera.WorldToScreenPoint(uicManager.uiLineRenderer.transform.position);

        return mainCamera.WorldToScreenPoint(point) - uicLineRendererOffset;
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Loader/ResourceLoader.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class ResourceLoader : ScriptableObject
{
    public abstract void Initialize();
  
    public abstract void LoadResources();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/ScrollView Graphs/Scripts/UIC_SV_Zoom.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

// this is only a simple example code to show the zoomming is possible with the correct hierarchy, please, use a more reliable code in your project 
public class UIC_SV_Zoom : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    bool _mouseIsOver;
    public RectTransform contentRectTransform;

    void Update()
    {
        if (_mouseIsOver)
        {
            if (Input.mouseScrollDelta.y != 0)
            {
                contentRectTransform.localScale += Vector3.one * Input.mouseScrollDelta.y * 0.2f;
            }
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        _mouseIsOver = true;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        _mouseIsOver = false;
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Connection Puzzle/Scripts/ConnectionPuzzle_GameManager.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ConnectionPuzzle_GameManager : MonoBehaviour
{
    public UIC_Manager uicManager;

    void Start()
    {
        // set the global line type
        uicManager.globalLineType = UIC_Connection.LineTypeEnum.Line;
        // disable click on connections
        uicManager.disableConnectionClick = true;

        // add listeners for pointer events
        uicManager.pointer.e_OnDragLast.AddListener(
            delegate
            {
                PerformVirtualClickOnFoundNode();
            });

        uicManager.pointer.e_OnPointerDownLast.AddListener(
            delegate
            {
                CheckAndUpdateCrossedConnections();
            });
    }

    List<UIC_Connection> alreadyCheckedConnection = new List<UIC_Connection>();
    private void CheckAndUpdateCrossedConnections()
    {
        UIC_Node clickedNode = uicManager.GetClickedObjectOfType<UIC_Node>();

        if (clickedNode)
        {
            alreadyCheckedConnection.Clear();

            // check every connection for a crossing, excluding the ones that were checked previously
            foreach (UIC_Connection conn in clickedNode.connectionsList)
            {
                if (!alreadyCheckedConnection.Contains(conn))
                {
                    alreadyCheckedConnection.Add(conn);
                    bool red = false;

                    // get connections that are crossed by conn and set their color red if exist
                    List<UIC_Connection> cross = conn.GetCrossedConnections();
                    if (cross.Count > 0)
                    {
                        alreadyCheckedConnection.AddRange(cross);
                        foreach (UIC_Connection c in cross)
                        {
                            c.line.color = Color.red;
                        }
                        red = true;
                    }

                    // alse check if the conn crosses any entity 
                    foreach (UIC_Entity entity in uicManager.EntityList)
                    {
                        if ((entity != conn.node0.entity && entity != conn.node1.entity) && UIC_Utility.ConnectionIntersectRect(conn, entity.GetComponent<RectTransform>()))
                        {
                            red = true;
                            break;
                        }
                    }

                    if (red)
                    {
                        conn.line.color = Color.red;
                    }
                    else
                    {
                        conn.line.color = conn.line.defaultColor;
                    }
                }
            }
        }
    }

    void PerformVirtualClickOnFoundNode()
    {
        UIC_Node clickedNode = uicManager.GetClickedObjectOfType<UIC_Node>();

        // check if clicked object is a node to perform virtual click
        if (clickedNode)
        {
            // get last node detected under the pointer
            UIC_Node foundNode = clickedNode.lastFoundNode;

            if (foundNode != null)
            {
                // if first clicked node is != than detected one, perform new simulated click
                if (foundNode != clickedNode)
                {
                    uicManager.pointer.OnPointerUp();
                    uicManager.pointer.OnPointerDown();
                }
            }
        }
        else
        {
            // call pointer down to mantain the click action
            uicManager.pointer.OnPointerDown();
        }
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_Gate.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// defines a logic gate, it is inherited by each specific gate and has the methods for get the input values and calculate output
// each gate overrides the solve method with its own logic
public class UIC_LG_Gate : MonoBehaviour
{
    public UIC_Entity entity;
    [HideInInspector]
    public int outValue; // 0(low), 1(high), -1(undefined)

    protected virtual void Awake()
    {
        entity = GetComponent<UIC_Entity>();
    }

    // update connection with the correspondent animation
    public virtual void UpdateConnections()
    {
        if (entity.nodeList.Count - 1 == entity.GetEntitiesConnectedToPolarity(UIC_Node.PolarityTypeEnum._in).Count && !inputs.Contains(-1))
        {
            if (outValue == 1)
            {
                foreach (UIC_Node node in entity.nodeList)
                {
                    if (node.polarityType == UIC_Node.PolarityTypeEnum._out)
                    {
                        foreach (UIC_Connection conn in node.connectionsList)
                        {
                            conn.line.animation.color = Color.red;
                            conn.line.animation.DrawType = UIC_Line.CapTypeEnum.Triangle;
                            conn.line.animation.isActive = true;
                        }
                    }
                }
            }
            else
            {
                foreach (UIC_Node node in entity.nodeList)
                {
                    if (node.polarityType == UIC_Node.PolarityTypeEnum._out)
                    {
                        foreach (UIC_Connection conn in node.connectionsList)
                        {
                            conn.line.animation.color = Color.white;
                            conn.line.animation.DrawType = UIC_Line.CapTypeEnum.Circle;
                            conn.line.animation.isActive = true;
                        }
                    }
                }
            }
        }
        else
        {
            foreach (UIC_Node node in entity.nodeList)
            {
                if (node.polarityType == UIC_Node.PolarityTypeEnum._out)
                {
                    foreach (UIC_Connection conn in node.connectionsList)
                    {
                        conn.line.animation.isActive = false;
                    }
                }
            }
        }
    }

    public List<int> inputs;
    
    public virtual void GetInputs()
    {
        inputs = new List<int>();

        foreach (UIC_Entity inEntity in entity.GetEntitiesConnectedToPolarity(UIC_Node.PolarityTypeEnum._in))
        {
            UIC_LG_Gate inGate = inEntity.GetComponent<UIC_LG_Gate>();

            inputs.Add(inGate.outValue);
        }
    }

    // ex AND
    public virtual void Solve()
    {
        GetInputs();

        int result;
        if (inputs.Count > 0)
            result = inputs[0];
        else
        {
            outValue = -1;
            return;
        }

        for (int i = 1; i < inputs.Count; i++)
        {
            if (inputs[i] == -1)
            {
                outValue = -1;
                return;
            }
            else
            {
                bool boolInput = inputs[i] == 1;
                bool boolResult = result == 1;
                boolResult = boolResult & boolInput;
                outValue = boolResult == true ? 1 : 0;
            }
        }
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_GateValue.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIC_LG_GateValue : UIC_LG_Gate
{
    protected override void Awake()
    {
        base.Awake();
    }

    public bool value;

    public override void Solve()
    {
        outValue = value == true ? 1 : 0;
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_LocalLineAnimationPointCount.cs
﻿using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;

// v1.4 - context menu line animation point count slider added
public class UIC_LocalLineAnimationPointCount : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;

    public string ID => "input";
    public Color objectColor { get; set; }
    public int Priority => -10;

    Slider _slider;

    public void Action()
    {

    }

    List<UIC_Connection> _connList = new List<UIC_Connection>();

    public void OnChangeSelection()
    {
        _connList.Clear();
        bool _show = false;
        foreach (I_UIC_Selectable item in _uicManager.selectedUIObjectsList)
        {
            if (item is UIC_Connection)
            {
                _connList.Add(item as UIC_Connection);
                _show = true;
            }
        }

        gameObject.SetActive(_show);

        if (_connList.Count == 1)
            _slider.value = _connList[0].line.animation.pointCount;
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _slider = GetComponentInChildren<Slider>();
    }

    private void SetPointCount(float arg0)
    {
        foreach (UIC_Connection conn in _connList)
        {
            conn.line.animation.pointCount = (int)_slider.value;
        }
    }

    void OnEnable()
    {
        _slider.onValueChanged.AddListener(SetPointCount);
    }

    void OnDisable()
    {
        _slider.onValueChanged.RemoveAllListeners();
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_SimpleColorPicker.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_SimpleColorPicker : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;

    Transform _colorsPanel;
    Button[] _colorButtons;

    public string ID => "color picker";
    public Color objectColor { get; set; }

    public int Priority => -10;

    public void Action()
    {

    }

    public void OnChangeSelection()
    {
        gameObject.SetActive(_uicManager.selectedUIObjectsList.Count > 0);
    }

    void SetColor(Button _button)
    {
        foreach (I_UIC_Object obj in _uicManager.selectedUIObjectsList)
        {
            obj.objectColor = _button.image.color;
        }
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();

        _colorsPanel = transform.GetChild(1);
        _colorButtons = new Button[_colorsPanel.childCount];

        for (int i = 0; i < _colorButtons.Length; i++)
        {
            _colorButtons[i] = _colorsPanel.GetChild(i).GetComponent<Button>();
        }
    }

    void OnEnable()
    {
        foreach (Button button in _colorButtons)
        {
            button.onClick.AddListener(delegate { SetColor(button); });
        }
    }

    void OnDisable()
    {
        foreach (Button button in _colorButtons)
        {
            button.onClick.RemoveAllListeners();
        }
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Editor/ResouceLoaderInspector.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(ResourceLoader), true)]
public class DatabaseLoaderInspector : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        ResourceLoader dbLoader = (ResourceLoader)target;
        if (GUILayout.Button("Load Resources"))
            dbLoader.LoadResources();
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Entity.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[ExecuteInEditMode]
public class UIC_Entity : MonoBehaviour, I_UIC_Object, I_UIC_Selectable, I_UIC_Draggable, I_UIC_Clickable
{
    // v2.0 - local UIC manager
    public UIC_Manager uicManager;

    [Header("Logic")]
    [SerializeField]
    bool _enableDrag;
    public bool EnableDrag { get => _enableDrag; set => _enableDrag = value; }
    public bool enableSelfConnection;

    RectTransform _rectTransform;

    [Header("Elements")]
    public List<UIC_Node> nodeList;

    Outline _outline;

    public string ID => name;

    public Vector3[] Handles { get; set; }
    public Color objectColor { get => _image.color; set => _image.color = value; }

    public int Priority => 0;

    public bool DisableClick { get; set; }

    Image _image;

    void Awake()
    {
        uicManager = GetComponentInParent<UIC_Manager>();

        DisableClick = false;
        _image = GetComponent<Image>();

        // v2.0 - maintain the last parent
        parent = transform.parent;
    }

    void OnValidate()
    {
        Init();

        Awake();
    }

    void Start()
    {
        Init();
    }

    public void Init()
    {
        _outline = _outline ? _outline : gameObject.GetComponent<Outline>() ? gameObject.GetComponent<Outline>() : gameObject.AddComponent<Outline>();
        if (_outline)
        {
            _outline.effectColor = new Color32(0x7f, 0x5a, 0xf0, 0xFF);
            _outline.effectDistance = new Vector2(3, -3);
            _outline.enabled = false;
        }

        _rectTransform = _rectTransform ? _rectTransform : GetComponent<RectTransform>();

        nodeList = new List<UIC_Node>();
        nodeList.AddRange(transform.GetComponentsInChildren<UIC_Node>());
    }

    public void UpdateConnections()
    {
        foreach (UIC_Node node in nodeList)
        {
            foreach (UIC_Connection conn in node.connectionsList)
            {
                conn.UpdateLine();
            }
        }
    }

    public void Select()
    {
        _outline.enabled = true;
        if (!uicManager.selectedUIObjectsList.Contains(this))
        {
            uicManager.selectedUIObjectsList.Add(this);
        }
    }

    public void Unselect()
    {
        _outline.enabled = false;
        if (uicManager.selectedUIObjectsList.Contains(this))
        {
            uicManager.selectedUIObjectsList.Remove(this);
        }
    }

    // v2.0 - using not static UIC Manager method
    public void Remove()
    {
        Unselect();

        foreach (UIC_Node node in nodeList)
        {
            node.RemoveAllConnections();
        }

        if (uicManager.EntityList.Contains(this))
        {
            uicManager.EntityList.Remove(this);
        }

        Destroy(gameObject);
    }

    public Transform parent;

    public void OnPointerDown()
    {
        if (!uicManager.selectedUIObjectsList.Contains(this))
        {
            Select();

            // v2.0 - maintain the last parent
            parent = transform.parent;
        }
        else
        {
            Unselect();
        }
    }

    public void OnPointerUp()
    {
        // v1.2 - using static Manager instance to set parent of dropped entity
        transform.SetParent(uicManager.transform);

        // v2.0 - maintain the last parent
        transform.SetParent(parent);
        
        UpdateConnections();
    }

    public void OnDrag()
    {
        if (EnableDrag)
        {
            Select();
            transform.SetParent(uicManager.pointer.transform.GetChild(0));

            UpdateConnections();
        }
    }

    public List<UIC_Entity> GetConnectedEntities()
    {
        List<UIC_Entity> connectedEntities = new List<UIC_Entity>();
        foreach (UIC_Node node in nodeList)
        {
            foreach (UIC_Connection conn in node.connectionsList)
            {
                UIC_Entity connEntitiy = conn.node0 != node ? conn.node0.entity : conn.node1.entity;
                connectedEntities.Add(connEntitiy);
            }
        }
        return connectedEntities;
    }

    // v1.4 - method to get entities connected to an specific node polarity
    public List<UIC_Entity> GetEntitiesConnectedToPolarity(UIC_Node.PolarityTypeEnum polarity)
    {
        List<UIC_Entity> connectedEntities = new List<UIC_Entity>();
        foreach (UIC_Node node in nodeList)
        {
            if (node.polarityType == polarity)
            {
                foreach (UIC_Connection conn in node.connectionsList)
                {
                    UIC_Entity connEntitiy = conn.node0 != node ? conn.node0.entity : conn.node1.entity;
                    connectedEntities.Add(connEntitiy);
                }
            }
        }
        return connectedEntities;
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_ObjectName.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_ObjectName : MonoBehaviour, I_UIC_ContextItem
{
    UIC_Manager _uicManager;
    Text _text;

    public void Action()
    {

    }

    public void OnChangeSelection()
    {
        if (_uicManager.selectedUIObjectsList.Count <= 0)
        {
            _text.text = "--";
        }
        else if (_uicManager.selectedUIObjectsList.Count == 1)
        {
            _text.text = (_uicManager.selectedUIObjectsList[0] as I_UIC_Object).ID;
        }
        else
        {
            _text.text = string.Format("Multiple Objects ({0})", _uicManager.selectedUIObjectsList.Count);
        }

    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _text = transform.GetComponentInChildren<Text>();
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/BlockFactory.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;

public class BlockFactory : MonoBehaviour
{
    [SerializeField] private List<Block> blockList = new List<Block>(); 

    public T InstantiateBlock<T>(int input, int output) where T : Block
    {   
        T block = Instantiate<T>((T)blockList[input*3 + (output-1)]);
        return block;
    }

    public void SetBlockAttribute<T>() where T : Block
    {

    }
}
<file_sep>/MP_ARCT/Assets/Scripts/LogicManager.cs
using System.Net.WebSockets;
using System.Net;
using System;
using System.Net.NetworkInformation;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class LogicManager : MonoBehaviour
{
    [SerializeField] private bool isLive;

    [SerializeField] private ARSession _arSession;
    [SerializeField] private GameObject _prefab;
    [SerializeField] private GameObject _spawnedPrefab;
    [SerializeField] private ARRaycastManager _arRaycastManager;
    [SerializeField] private ARPlaneManager _arPlaneManager;


    private List<ARRaycastHit> hits = new List<ARRaycastHit>();

    private void Awake()
    {

        if (TryInitialize())
        {
            print("Error in initialize LogicManager");
        }
    }


    private void Update()
    {
        if (isLive)
        {
            if (Input.touchCount > 0)
            {
                OnScreenTouch();
            }
        }

    }

    private bool TryInitialize()
    {
        _arSession = GetComponent<ARSession>();
        return _arSession.Equals(null) || _arPlaneManager.Equals(null) || _arPlaneManager.Equals(null);
    }

    public void SetPlaneDetection(bool set)
    {
        _arPlaneManager.enabled = set;
    }

    private void OnScreenTouch()
    {
        Touch touch = Input.GetTouch(0);
        Vector3 touchPos = Camera.main.ScreenToWorldPoint(touch.position);
        Ray ray = Camera.main.ScreenPointToRay(touchPos);

        if (touch.phase == TouchPhase.Began)
        {
            if (_spawnedPrefab.Equals(null))
            {
                if (_arRaycastManager.Raycast(ray, hits, TrackableType.PlaneWithinPolygon))
                {
                    Pose hitPose = hits[0].pose;
                    Spawn(hitPose.position);
                }
            }
            else
            {
                // if (Physics.Raycast(ray, out var hit))
                // {
                //     if (hit.collider.gameObject.CompareTag("Selectable"))                    
                //     OnTouchObject(hit.collider.gameObject);
                // }
            }
        }
    }

    private void Spawn(Vector3 pos)
    {
        _spawnedPrefab = Instantiate(_prefab);
        _spawnedPrefab.SetActive(true);
        _spawnedPrefab.transform.SetPositionAndRotation(pos, Quaternion.identity);
    }

    private void OnTouchObject(GameObject selected)
    {
        
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_ButtonDuplicateBlock.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_ButtonDuplicateBlock : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;

    Button _button;
    public string ID => "button";
    public Color objectColor { get; set; }
    public int Priority => -10;

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _button = GetComponent<Button>();
    }

    public void Action()
    {
        for (int i = _uicManager.selectedUIObjectsList.Count - 1; i >= 0; i--)
        {
            UIC_Entity entityToDuplicate = _uicManager.selectedUIObjectsList[i] as UIC_Entity;
            if (entityToDuplicate)
            {
                _uicManager.InstantiateEntityAtPosition(entityToDuplicate, entityToDuplicate.transform.position + new Vector3(15, -15));
            }
        }
        UIC_ContextMenu.UpdateContextMenu();
    }

    // v1.5 - fix: incorrect enabling of button "duplicate"
    public void OnChangeSelection()
    {
        int entityCount = 0;
        for (int i = _uicManager.selectedUIObjectsList.Count - 1; i >= 0; i--)
        {
            UIC_Entity entity = _uicManager.selectedUIObjectsList[i] as UIC_Entity;
            if (entity)
            {
                entityCount++;
            }
        }
        gameObject.SetActive(entityCount > 0);
    }

    void OnEnable()
    {
        _button.onClick.AddListener(Action);
    }

    void OnDisable()
    {
        _button.onClick.RemoveAllListeners();
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_LocalLineAnimationActive.cs
﻿using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;

// v1.4 - context menu line animation active toggle added
public class UIC_LocalLineAnimationActive : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;
    public string ID => "input";
    public Color objectColor { get; set; }
    public int Priority => -10;

    Toggle _toggle;

    public void Action()
    {

    }

    List<UIC_Connection> _connList = new List<UIC_Connection>();

    public void OnChangeSelection()
    {
        _connList.Clear();
        bool _show = false;
        foreach (I_UIC_Selectable item in _uicManager.selectedUIObjectsList)
        {
            if (item is UIC_Connection)
            {
                _connList.Add(item as UIC_Connection);
                _show = true;
            }
        }

        gameObject.SetActive(_show);

        if (_connList.Count == 1)
            _toggle.isOn = _connList[0].line.animation.isActive;
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _toggle = GetComponentInChildren<Toggle>();
    }

    private void SetIsOn(bool arg0)
    {
        foreach (UIC_Connection conn in _connList)
        {
            conn.line.animation.isActive = _toggle.isOn;
        }
    }

    void OnEnable()
    {
        _toggle.onValueChanged.AddListener(SetIsOn);
    }

    void OnDisable()
    {
        _toggle.onValueChanged.RemoveAllListeners();
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Line Renderer/UIC_Line.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class UIC_Line
{
    public CapTypeEnum capStartType;
    public float capStartSize;
    public Color capStartColor;
    public float capStartAngleOffset;
    public CapTypeEnum capEndType;
    public float capEndSize;
    public Color capEndColor;
    public float capEndAngleOffset;

    public string ID;
    public float width;

    public Color color;
    public List<Vector2> points;

    public Color selectedColor = new Color32(0x7f, 0x5a, 0xf0, 0xff);
    public Color hoverColor = new Color32(0x2c, 0xb6, 0x7d, 0xff);
    public Color defaultColor = new Color32(0xff, 0xff, 0xfe, 0xff);

    public UIC_Line()
    {
        color = defaultColor;
        width = 2;
        points = new List<Vector2>();
    }

    /// <summary>
    /// Clear all points and add new points to the line
    /// </summary>
    /// <param name="newPoints"></param>
    public void SetPoints(Vector2[] newPoints)
    {
        if (newPoints != null)
        {
            points.Clear();
            points.AddRange(newPoints);
        }

        length = GetLength();
    }

    public enum CapTypeEnum { none, Square, Circle, Triangle };
    public enum CapIDEnum { Start, End };
    public void SetCap(CapIDEnum capID, CapTypeEnum capType, float capSize = 5, Color? capColor = null, float angleOffset = 0)
    {
        if (capID == CapIDEnum.Start)
        {
            this.capStartSize = capSize;
            this.capStartType = capType;
            this.capStartColor = capColor ?? Color.white;
            this.capStartAngleOffset = angleOffset;
        }
        else
        {
            this.capEndSize = capSize;
            this.capEndType = capType;
            this.capEndColor = capColor ?? Color.white;
            this.capEndAngleOffset = angleOffset;
        }
    }

    // v1.4 - new methods and variables for enabling lerp line
    [Range(0, 1)]
    public float linePosition01;
    public float length;
    public UIC_LineAnimation animation = new UIC_LineAnimation();
    float _deg2Rad90 = Mathf.Deg2Rad * 90f;
    public float GetLength()
    {
        float l = 0;
        for (int i = 1; i < points.Count; i++)
        {
            l += Vector2.Distance(points[i - 1], points[i]);
        }
        return l;
    }
    System.Tuple<int, float> GetPreviousPointELength(float pos01)
    {
        System.Tuple<int, float> t = new System.Tuple<int, float>(0, 0);
        float l = 0;
        float prevL = 0;
        for (int i = 1; i < points.Count; i++)
        {
            l += Vector2.Distance(points[i - 1], points[i]);
            if (l >= pos01 * length)
            {
                t = new System.Tuple<int, float>(i - 1, prevL);
                break;
            }
            prevL = l;
        }
        return t;
    }

    // v1.4 - LerpLine method that returns point in the line, used to draw animations points
    public System.Tuple<Vector2, float> LerpLine(float pos01)
    {
        System.Tuple<int, float> t = GetPreviousPointELength(pos01);
        Vector2 p0 = points[t.Item1];
        Vector2 p1 = points[t.Item1 + 1];
        float ppDistance = Vector2.Distance(p0, p1);

        Vector2 position = Vector2.Lerp(p0, p1, ((pos01 * length) - t.Item2) / ppDistance);
        float angle = Mathf.Atan2(p0.y - p1.y, p0.x - p1.x) + _deg2Rad90;

        return new System.Tuple<Vector2, float>(position, angle);
    }
}

// v1.4 - added line animation class for uic_lines 
[System.Serializable]
public class UIC_LineAnimation
{
    public enum AnimationTypeEnum {lerp, constantSpeed}
    public AnimationTypeEnum Type = AnimationTypeEnum.lerp;
    public bool isActive = false;
    [Range(1, 10)]
    public int pointCount = 1;
    public float size = 10;
    public Color color = Color.white;
    public UIC_Line.CapTypeEnum DrawType = UIC_Line.CapTypeEnum.Triangle;
    public float speed = 0.5f;
    [HideInInspector]
    public float time = 0;
}
<file_sep>/MP_ARCT/Assets/Scripts/BlockOutput.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlockOutput : UIC_Node
{
}
<file_sep>/MP_ARCT/Assets/Scripts/Base/BaseObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class BaseObject : MonoBehaviour
{
    private ObjectManager m_ObjectManager;

    [SerializeField] private string mId;

    public string ID
    { 
        get => mId;
        set => mId = value;
    }

    protected virtual void Awake()
    {
        TryInitialize();
    }

    protected virtual bool TryInitialize()
    {
        m_ObjectManager = ObjectManager.Instance;

        return true;
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Node.cs
﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[ExecuteInEditMode]
public class UIC_Node : MonoBehaviour, I_UIC_Object, I_UIC_Draggable, I_UIC_Clickable
{
    public Type type;
    public enum PolarityTypeEnum { _in, _out, _all };
    [Header("Logic")]
    public PolarityTypeEnum polarityType;
    [HideInInspector]
    public UIC_Entity entity;

    public int maxConnections = 0; // 0 - no limit

    [Header("Visuals")]
    public Sprite iconUnconnected;
    public Sprite iconConnected;

    public Color iconColorDefault;
    public Color iconColorHover;
    public Color iconColorSelected;
    public Color iconColorConnected;

    Text text;
    Image imageCurrentIcon;

    [Header("Elements")]
    public Transform spLineControlPointTranform;

    public bool haveSpots
    {
        get
        {
            return maxConnections == 0 || connectionsList.Count < maxConnections;
        }
    }

    public string ID => string.Format("{0}'s Node ({1})", entity.name, name);

    public Color objectColor { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

    public int Priority => 2;

    public bool EnableDrag { get; set; }

    public bool DisableClick => false;

    UIC_Line connectionUILine;
    UISpline connectionUISpline;

    public UIC_LineRenderer uILineRenderer;

    [HideInInspector]
    public UIC_Node lastFoundNode;
    UIC_Node closestFoundNode;

    public List<UIC_Connection> connectionsList;

    void OnValidate()
    {
        Init();

        Awake();
    }

    void Awake()
    {

    }

    void Start()
    {
        Init();

        imageCurrentIcon.color = iconColorDefault;
        connectionsList = new List<UIC_Connection>();

        connectionUILine = new UIC_Line();
        connectionUILine.animation.isActive = false;
    }

    public void Init()
    {
        text = transform.GetChild(0).GetComponent<Text>();
        imageCurrentIcon = transform.GetChild(1).GetComponent<Image>();
        spLineControlPointTranform = transform.GetChild(2);
        spLineControlPointTranform.name = "SPLineControlPoint";

        if (polarityType == PolarityTypeEnum._in)
        {
            name = "In Node";
        }
        else if (polarityType == PolarityTypeEnum._out)
        {
            name = "Out Node";
        }
        else if (polarityType == PolarityTypeEnum._all)
        {
            name = "In-Out Node";
        }

        imageCurrentIcon.sprite = iconUnconnected;

        entity = GetParentEntity(transform);
        if (entity != null && !entity.nodeList.Contains(this))
            entity.nodeList.Add(this);

        connectionUISpline = new UISpline();

        uILineRenderer = FindObjectOfType<UIC_LineRenderer>();
    }

    UIC_Entity GetParentEntity(Transform child)
    {
        if (child && child.gameObject.activeSelf)
        {
            UIC_Entity parentEntity = GetComponentInParent<UIC_Entity>();
            if (parentEntity != null)
                return parentEntity;
            else
                return GetParentEntity(child.parent);
        }
        else return null;
    }

    public void SetIcon()
    {
        if (connectionsList.Count > 0)
        {
            imageCurrentIcon.sprite = iconConnected;
            imageCurrentIcon.color = iconColorConnected;
        }
        else
        {
            imageCurrentIcon.sprite = iconUnconnected;
            imageCurrentIcon.color = iconColorDefault;
        }
    }

    // v1.2.1 - UIC_Node.ConnectTo return UIC_Connection
    public UIC_Connection ConnectTo(UIC_Node otherNode)
    {
        UIC_Connection _connection = null;

        if (otherNode.haveSpots && this.haveSpots)
        {
            _connection = entity.uicManager.AddConnection(this, otherNode, entity.uicManager.globalLineType);
            otherNode.SetIcon();
        }
        SetIcon();

        return _connection;
    }

    public void Remove()
    {
        RemoveAllConnections();
        entity.nodeList.Remove(this);
        Destroy(gameObject);
    }

    public void RemoveAllConnections()
    {
        for (int i = connectionsList.Count - 1; i >= 0; i--)
        {
            connectionsList[i].Remove();
        }

        SetIcon();
    }

    public void OnPointerDown()
    {
        UIC_Manager uicManager = entity.uicManager;
        imageCurrentIcon.color = iconColorSelected;
        entity.uicManager.AddLine(connectionUILine);

        connectionUILine.width = uicManager.globalLineWidth;
        connectionUILine.defaultColor = uicManager.globalLineDefaultColor;
        connectionUILine.color = uicManager.globalLineDefaultColor;

        connectionUILine.SetCap(UIC_Line.CapIDEnum.Start, uicManager.globalCapStartType, uicManager.globalCapStartSize,
                            uicManager.globalCapStartColor, uicManager.globalCapStartAngleOffset);
        connectionUILine.SetCap(UIC_Line.CapIDEnum.End, uicManager.globalCapEndType, uicManager.globalCapEndSize,
                            uicManager.globalCapEndColor, uicManager.globalCapEndAngleOffset);
    }

    public void OnPointerUp()
    {
        imageCurrentIcon.color = iconColorDefault;
        connectionUILine.points.Clear();
        entity.uicManager.RemoveLine(connectionUILine);
        UIC_Manager uicManager = entity.uicManager;

        closestFoundNode = uicManager.pointer.RaycastClosestNodeOfOppositPolarity(this);
        if (closestFoundNode)
        {
            closestFoundNode.imageCurrentIcon.color = closestFoundNode.iconColorDefault;

            if (polarityType == PolarityTypeEnum._in || closestFoundNode.polarityType == PolarityTypeEnum._out)
                closestFoundNode.ConnectTo(this);
            else
                ConnectTo(closestFoundNode);
        }

        SetIcon();

        lastFoundNode = null;
    }

    // v1.3 - line poinst adjusted to canvas render mode overlay and camera
    Vector3[] LinePoints
    {
        get
        {
            UIC_Manager uicManager = entity.uicManager;
            Vector3 pointerPosition = uicManager.pointer.PointerPosition;
            if (uicManager.CanvasRenderMode == RenderMode.ScreenSpaceOverlay)
            {
                return new Vector3[] {
                    transform.position,
                    spLineControlPointTranform.position,
                    closestFoundNode ? closestFoundNode.spLineControlPointTranform.position : pointerPosition,
                    closestFoundNode ? closestFoundNode.transform.position : pointerPosition };
            }
            else if (uicManager.CanvasRenderMode == RenderMode.ScreenSpaceCamera)
            {
                return new Vector3[] {
                    UIC_Utility.WorldToScreenPoint(transform.position, uicManager),
                    UIC_Utility.WorldToScreenPoint(spLineControlPointTranform.position, uicManager),
                    closestFoundNode ? UIC_Utility.WorldToScreenPoint(closestFoundNode.spLineControlPointTranform.position, uicManager) : pointerPosition,
                    closestFoundNode ? UIC_Utility.WorldToScreenPoint(closestFoundNode.transform.position, uicManager) : pointerPosition };
            }
            // v1.5 - set the line points on the world space canvas
            else if (uicManager.CanvasRenderMode == RenderMode.WorldSpace)
            {
                return new Vector3[] {
                    UIC_Utility.WorldToScreenPointInCanvas(transform.position, uicManager),
                    UIC_Utility.WorldToScreenPointInCanvas(spLineControlPointTranform.position, uicManager),
                    closestFoundNode ? UIC_Utility.WorldToScreenPointInCanvas(closestFoundNode.spLineControlPointTranform.position, uicManager) : UIC_Utility.WorldToScreenPointInCanvas(uicManager.pointer.transform.position, uicManager),
                    closestFoundNode ? UIC_Utility.WorldToScreenPointInCanvas(closestFoundNode.transform.position, uicManager) : UIC_Utility.WorldToScreenPointInCanvas(uicManager.pointer.transform.position, uicManager) };
            }

            return new Vector3[] {
                transform.position,
                spLineControlPointTranform.position,
                closestFoundNode ? closestFoundNode.spLineControlPointTranform.position : pointerPosition,
                closestFoundNode ? closestFoundNode.transform.position : pointerPosition };
        }
    }

    public void OnDrag()
    {
        UIC_Manager uicManager = entity.uicManager;
        if (lastFoundNode)
            lastFoundNode.SetIcon();

        closestFoundNode = uicManager.pointer.RaycastClosestNodeOfOppositPolarity(this);

        if (closestFoundNode)
        {
            closestFoundNode.imageCurrentIcon.color = closestFoundNode.iconColorSelected;
            lastFoundNode = closestFoundNode;
        }

        if (uicManager.globalLineType == UIC_Connection.LineTypeEnum.Spline)
        {
            connectionUISpline.SetControlPoints(
                LinePoints[0],
                LinePoints[1],
                LinePoints[2],
                LinePoints[3]);
            connectionUILine.SetPoints(connectionUISpline.points);
        }
        else if (uicManager.globalLineType == UIC_Connection.LineTypeEnum.Z_Shape)
        {
            connectionUILine.SetPoints(new Vector2[] {
                LinePoints[0],
                (LinePoints[1] + LinePoints[0])/2,
                (LinePoints[2] + LinePoints[3])/2,
                LinePoints[3] });
        }
        else if (uicManager.globalLineType == UIC_Connection.LineTypeEnum.Line)
        {
            connectionUILine.SetPoints(new Vector2[] {
                LinePoints[0],
                LinePoints[3] });
        }
    }

    public List<UIC_Entity> GetConnectedEntities()
    {
        List<UIC_Entity> connectedEntities = new List<UIC_Entity>();
        foreach (UIC_Connection conn in connectionsList)
        {
            UIC_Entity connEntitiy = conn.node0 != this ? conn.node0.entity : conn.node1.entity;
            connectedEntities.Add(connEntitiy);
        }
        return connectedEntities;
    }

    public List<UIC_Connection> GetOutConnections()
    {
        List<UIC_Connection> outConnections = new List<UIC_Connection>();
        foreach (UIC_Connection conn in connectionsList)
        {
            if (conn.node0 == this)
                outConnections.Add(conn);
        }
        return outConnections;
    }

    public List<UIC_Connection> GetInConnections()
    {
        List<UIC_Connection> outConnections = new List<UIC_Connection>();
        foreach (UIC_Connection conn in connectionsList)
        {
            if (conn.node0 != this)
                outConnections.Add(conn);
        }
        return outConnections;
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_GateNOT.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIC_LG_GateNOT : UIC_LG_Gate
{
    protected override void Awake()
    {
        base.Awake();
    }

    public override void Solve()
    {
        GetInputs();

        if (inputs.Count > 0)
        {
            outValue = inputs[0] == 0 ? 1 : 0;
        }
        else
        {
            outValue = -1;
            return;
        }
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Loader/PrefabLoader.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[CreateAssetMenu(menuName = "LoadResouces/LoadPrefabs")]
public class PrefabLoader : ResourceLoader
{
    [SerializeField] private string[] paths;
    public List<List<BaseObject>> mLoadedPrefabs;

    private WaitForSeconds waits = new WaitForSeconds(0.01f);

    public override void Initialize()
    {
        mLoadedPrefabs = new List<List<BaseObject>>();
    }

    public override void LoadResources()
    {
        foreach (var path in paths)
        {
            Resources.LoadAll<BaseObject>(path);
        }
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/SetupInitialConnections/Editor/SetupInitialConnectionsEditor.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(SetupInitialConnections))]
public class SetupInitialConnectionsEditor : Editor
{
    SetupInitialConnections _setup;

    SerializedProperty _fromNodes;
    SerializedProperty _toNodes;

    void OnEnable()
    {
        _setup = (SetupInitialConnections)target;
        _fromNodes = serializedObject.FindProperty("fromNodes");
        _toNodes = serializedObject.FindProperty("toNodes");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        string _message = 
                    "Define the number of connections that will be created on start.\n" + 
                    "Set the start nodes to the left column and the end nodes to the right column.";
        EditorGUILayout.HelpBox(_message, MessageType.Info);

        int size = _setup.size;
        _setup.size = EditorGUILayout.IntSlider("# of Connections", size, 0, 20);

        int fromCount = _setup.fromNodes.Count;
        int toCount = _setup.toNodes.Count;

        EditorGUILayout.LabelField("Connections to be created On Start:");
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.BeginVertical();
        if (_setup.fromNodes != null)
        {
            for (int i = 0; i < fromCount; i++)
            {
                EditorGUILayout.PropertyField(_fromNodes.GetArrayElementAtIndex(i), GUIContent.none);
            }
        }
        EditorGUILayout.EndVertical();
        EditorGUILayout.BeginVertical();
        if (_setup.fromNodes != null)
        {
            for (int i = 0; i < fromCount; i++)
            {
                EditorGUILayout.LabelField("——(" + i + ")——>", GUILayout.MaxWidth(80));
            }
        }
        EditorGUILayout.EndVertical();
        EditorGUILayout.BeginVertical();
        if (_setup.toNodes != null)
        {
            for (int i = 0; i < toCount; i++)
            {
                EditorGUILayout.PropertyField(_toNodes.GetArrayElementAtIndex(i), GUIContent.none);
            }
        }
        EditorGUILayout.EndVertical();
        EditorGUILayout.EndHorizontal();

        if (fromCount < size)
        {
            for (int i = fromCount - 1; i < size; i++)
            {
                _setup.fromNodes.Add(null);
            }
        }
        else if (fromCount > size)
        {
            for (int i = fromCount - 1; i >= size; i--)
            {
                _setup.fromNodes.RemoveAt(i);
            }
        }
        if (toCount < size)
        {
            for (int i = toCount - 1; i < size; i++)
            {
                _setup.toNodes.Add(null);
            }
        }
        else if (toCount > size)
        {
            for (int i = toCount - 1; i >= size; i--)
            {
                _setup.toNodes.RemoveAt(i);
            }
        }

        serializedObject.ApplyModifiedProperties();
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Multiple Charts/Scripts/UIC_MultipleChartsManager.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_MultipleChartsManager : MonoBehaviour
{
    public List<GameObject> chartsList;

    public void OpenChart(GameObject chart)
    {
        foreach (GameObject c in chartsList)
        {
            c.SetActive(false);
        }
        chart.SetActive(true);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Manager.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[ExecuteInEditMode]
public class UIC_Manager : MonoBehaviour
{
    // v2.0 - entity list not static to localize UIC to children
    // list of entities in the scene, used to improve performance of detections 
    List<UIC_Entity> _entityList;
    public List<UIC_Entity> EntityList { get => _entityList; }

    // v2.0 - made not static to localize UIC to children
    // list of connections in the scene, used to improve performance of detections
    List<UIC_Connection> _connectionsList;
    public List<UIC_Connection> ConnectionsList { get => _connectionsList; }

    // v2.0 - made not static to localize UIC to children
    public UIC_LineRenderer uiLineRenderer;
    public List<UIC_Line> UILinesList { get => uiLineRenderer.UILines; }

    // v2.0 - made not static to localize UIC to children
    public Canvas canvas;
    public RectTransform canvasRectTransform;

    // v2.0 - made not static to localize UIC to children
    // v1.3 - reference to rendermode
    public RenderMode CanvasRenderMode
    {
        get
        {
            if (!canvas)
                canvas = GetComponent<Canvas>();

            return canvas.renderMode;
        }
    }
    public Camera mainCamera;

    // list of selected uic objects, used for single or multi selection
    public List<I_UIC_Selectable> selectedUIObjectsList = new List<I_UIC_Selectable>();
    public I_UIC_Object clickedUIObject;

    public T GetClickedObjectOfType<T>()
    {
        if (clickedUIObject is T)
            return (T)clickedUIObject;
        else
            return default(T);
    }

    // v2.0 - made public and not static
    public UIC_Pointer pointer;

    [Header("Logic")]
    public bool replaceConnectionByReverse;
    // v2.0 - using detect nodes from raycast instead of distance to pointer
    //float _maxPointerDetectionDistance = 30;
    //public float MaxPointerDetectionDistance
    //{
    //    get
    //    {
    //        return _maxPointerDetectionDistance * canvasRectTransform.localScale.x;
    //    }
    //    set
    //    {
    //        _maxPointerDetectionDistance = value;
    //    }
    //}

    [Header("Connection Settings (for new liens)")]
    public bool disableConnectionClick = false;
    public int globalLineWidth = 2;
    public Color globalLineDefaultColor = Color.white;
    public UIC_Connection.LineTypeEnum globalLineType;
    [Header("- line caps")]
    public UIC_Line.CapTypeEnum globalCapStartType;
    public float globalCapStartSize;
    public Color globalCapStartColor;
    public float globalCapStartAngleOffset;
    public UIC_Line.CapTypeEnum globalCapEndType;
    public float globalCapEndSize;
    public Color globalCapEndColor;
    public float globalCapEndAngleOffset;

    [Header("- line animation")]
    public UIC_LineAnimation globalLineAnimation = new UIC_LineAnimation();

    private void OnEnable()
    {
        InitUILineRenderer();
    }

    void OnValidate()
    {
        Awake();
    }

    void Awake()
    {
        canvas = GetComponent<Canvas>();
        canvasRectTransform = canvas.GetComponent<RectTransform>();
        pointer = GetComponentInChildren<UIC_Pointer>();
    }

    void Start()
    {
        _entityList = new List<UIC_Entity>();
        UpdateEntityList();
        _connectionsList = new List<UIC_Connection>();

        InitUILineRenderer();
    }

    void InitUILineRenderer()
    {
        uiLineRenderer = GetComponentInChildren<UIC_LineRenderer>();
        if (!uiLineRenderer)
        {
            uiLineRenderer = GetComponentInChildren<UIC_LineRenderer>();

            if (!uiLineRenderer)
            {
                uiLineRenderer = Instantiate(Resources.Load("UIC_LineRenderer") as UIC_LineRenderer, transform.position, Quaternion.identity, transform);
                uiLineRenderer.name = "UIC_LineRenderer";
            }
        }
    }

    public void AddLine(UIC_Line line)
    {
        if (!uiLineRenderer.UILines.Contains(line))
            uiLineRenderer.UILines.Add(line);
    }

    public void RemoveLine(UIC_Line line)
    {
        if (uiLineRenderer.UILines.Contains(line))
            uiLineRenderer.UILines.Remove(line);
    }

    // v2.0 - made not static
    // v1.3 - new method instantiate Entity at position
    public void InstantiateEntityAtPosition(UIC_Entity entityToInstantiate, Vector3 position)
    {
        GameObject go = Instantiate(entityToInstantiate.gameObject, new Vector3(200, 100), Quaternion.identity, canvas.transform);
        AddEntity(go.GetComponent<UIC_Entity>());

        // v1.5 - instantiate entity at a convenient world space position 
        if (CanvasRenderMode == RenderMode.ScreenSpaceOverlay)
        {
            go.transform.position = position + new Vector3(15, 15, 0);
        }
        else if (CanvasRenderMode == RenderMode.ScreenSpaceCamera)
        {
            position.z = 0;
            go.transform.localPosition = position + new Vector3(1, 1, 0);
        }
        else if (CanvasRenderMode == RenderMode.WorldSpace)
        {
            position.z = 0;
            go.transform.localPosition = position + new Vector3(1, 1, 0);
            go.transform.localRotation = Quaternion.identity;
        }
    }

    // v2.0 - made not static
    public void AddEntity(UIC_Entity entityToAdd)
    {
        if (!EntityList.Contains(entityToAdd))
        {
            EntityList.Add(entityToAdd);
        }
    }

    // v2.0 - made not static and get entities in children
    public void UpdateEntityList()
    {
        _entityList = new List<UIC_Entity>();
        _entityList.AddRange(GetComponentsInChildren<UIC_Entity>());
    }

    // v1.3 - UIC_Manager.AddConnection return UIC_Connection
    public UIC_Connection AddConnection(UIC_Node node0, UIC_Node node1, UIC_Connection.LineTypeEnum lineType = UIC_Connection.LineTypeEnum.Spline)
    {
        UIC_Connection previousConnectionWithSameNode = NodesAreConnected(node0, node1);
        if (previousConnectionWithSameNode != null)
        {
            if (replaceConnectionByReverse)
            {
                previousConnectionWithSameNode.Remove();
                return previousConnectionWithSameNode;
            }
            else
            {
                return previousConnectionWithSameNode;
            }
        }

        UIC_Connection _connection = CreateConnection(node0, node1, lineType);
        ConnectionsList.Add(_connection);

        node0.connectionsList.Add(_connection);
        node1.connectionsList.Add(_connection);

        AddLine(_connection.line);

        _connection.line.width = globalLineWidth;
        _connection.line.defaultColor = globalLineDefaultColor;
        _connection.line.color = globalLineDefaultColor;

        _connection.line.SetCap(UIC_Line.CapIDEnum.Start, globalCapStartType, globalCapStartSize, globalCapStartColor, globalCapStartAngleOffset);
        _connection.line.SetCap(UIC_Line.CapIDEnum.End, globalCapEndType, globalCapEndSize, globalCapEndColor, globalCapEndAngleOffset);

        CopyAnimation(globalLineAnimation, _connection.line.animation);

        _connection.UpdateLine();

        return _connection;
    }

    public static void CopyAnimation(UIC_LineAnimation from, UIC_LineAnimation to)
    {
        to.Type = from.Type;
        to.isActive = from.isActive;
        to.pointCount = from.pointCount;
        to.size = from.size;
        to.color = from.color;
        to.DrawType = from.DrawType;
        to.speed = from.speed;
        to.time = from.time;
    }

    // v1.4 - NodesAreConnected verification method made public 
    public UIC_Connection NodesAreConnected(UIC_Node node0, UIC_Node node1)
    {
        foreach (UIC_Connection connection in ConnectionsList)
        {
            if ((node0 == connection.node0 && node1 == connection.node1) ||
                    (node0 == connection.node1 && node1 == connection.node0))
                return connection;
        }
        return null;
    }

    UIC_Connection CreateConnection(UIC_Node node0, UIC_Node node1, UIC_Connection.LineTypeEnum lineType)
    {
        UIC_Connection _connection = new UIC_Connection(node0, node1, lineType);
        _connection.line = new UIC_Line();
        _connection.line.width = 2;

        return _connection;
    }

    public void RemoveUIObject()
    {
        for (int i = selectedUIObjectsList.Count - 1; i >= 0; i--)
        {
            selectedUIObjectsList[i].Remove();
        }
    }

    public UIC_Connection FindClosestConnectionToPosition(Vector3 position, float maxDistance)
    {
        float minDist = Mathf.Infinity;
        UIC_Connection closestConnection = null;
        foreach (UIC_Connection connection in ConnectionsList)
        {
            int connectionPointsCount = connection.line.points.Count;
            if (connectionPointsCount > 0)
            {
                // v1.2 - changed from DistanceToSpline(obsolete) to DistanceToConnection, a general and more precise way to find distance to connections independent of the lineType
                for (int i = 1; i < connectionPointsCount; i++)
                {
                    float distance = UIC_Utility.DistanceToConnectino(connection, position, maxDistance);
                    if (distance < minDist)
                    {
                        closestConnection = connection;
                        minDist = distance;
                    }
                }
            }
        }

        return closestConnection;
    }

}

<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/SetupInitialConnections/SetupInitialConnections.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// v1.3 - connect defined nodes on start of the project
public class SetupInitialConnections : MonoBehaviour
{
    public UIC_Manager uicManager;

    [SerializeField] public List<UIC_Node> fromNodes = new List<UIC_Node>();
    [SerializeField] public List<UIC_Node> toNodes = new List<UIC_Node>();
    public int size = 1;

    void Awake()
    {
        uicManager = GetComponentInParent<UIC_Manager>();
    }

    bool lateStart = true;
    void LateStart()
    {
        for (int i = 0; i < fromNodes.Count; i++)
        {
            if (fromNodes[i] && toNodes[i])
            {
                fromNodes[i].ConnectTo(toNodes[i]);
            }
        }

        lateStart = false;
        //Destroy(gameObject);
    }

    void Update()
    {
        if (lateStart)
        {
            LateStart();
        }

        foreach (UIC_Connection conn in uicManager.ConnectionsList)
        {
            conn.UpdateLine();
        }
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Logic Gates/Scripts/UIC_LG_GateOR.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIC_LG_GateOR : UIC_LG_Gate
{
    protected override void Awake()
    {
        base.Awake();
    }

    public override void Solve()
    {
        GetInputs();

        int result;
        if (inputs.Count > 0)
            result = inputs[0];
        else
        {
            outValue = -1;
            return;
        }

        for (int i = 1; i < inputs.Count; i++)
        {
            if (inputs[i] == -1)
            {
                outValue = -1;
                return;
            }
            else
            {
                bool boolInput = inputs[i] == 1;
                bool boolResult = result == 1;
                boolResult = boolResult | boolInput;
                outValue = boolResult == true ? 1 : 0;
            }
        }
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/ObjectManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectManager : Singleton<ObjectManager>
{
    [SerializeField]private PrefabLoader mPrefabLoader;

    private Dictionary<string, Dictionary<int, BaseObject>> mActiveObjectDict;
    private Dictionary<string, Dictionary<int, BaseObject>> mDeactiveObjectDict;

    public Dictionary<string, Dictionary<int, BaseObject>> ActiveObjectDict { get => mActiveObjectDict;}
    public Dictionary<string, Dictionary<int, BaseObject>> DeactiveObjectDict { get => mDeactiveObjectDict;}

    private bool TryInitialize()
    {
        mActiveObjectDict = new Dictionary<string, Dictionary<int, BaseObject>>();
        mDeactiveObjectDict = new Dictionary<string, Dictionary<int, BaseObject>>();

        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="instance"></param>
    /// <param name="position"></param>
    /// <param name="rotation"></param>
    /// <param name="parent"></param>
    public void Spawn<T>(T instance, Vector3 position, Quaternion rotation, Transform parent) where T : BaseObject
    { 
        
    }

    public void Spawn<T>(T instance, Vector3 position, Quaternion rotation) where T : BaseObject
    {
        Spawn<T>(instance, position, rotation, null);
    }

    public void Spawn<T>(T instance, Vector3 position, Transform parent) where T : BaseObject
    {
        Spawn<T>(instance, position, Quaternion.identity, parent);
    }

    public void Spawn<T>(T instance, Quaternion rotation, Transform parent) where T : BaseObject
    {
        Spawn<T>(instance, Vector3.zero, rotation, parent);
    }

    public void Spawn<T>(T instance, Vector3 position) where T : BaseObject
    {
        Spawn<T>(instance, position, Quaternion.identity, null);
    }

    public void Spawn<T>(T instance, Quaternion rotation) where T : BaseObject
    {
        Spawn<T>(instance, Vector3.zero, rotation, null);
    }

    public void Spawn<T>(T instance, Transform parent) where T : BaseObject
    {
        Spawn<T>(instance, Vector3.zero, Quaternion.identity, parent);
    }

    public void Spawn<T>(T instance) where T : BaseObject
    {
        Spawn<T>(instance, Vector3.zero, Quaternion.identity, null);
    }

    public void Despawn<T>(T instance) where T : BaseObject
    { 
    
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/BlockManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlockManager : Singleton<BlockManager>
{
    [SerializeField] private BlockCompiler m_blockCompiler;

    public Tree<Block> blocks = new Tree<Block>();

    public void Compile()
    {
        var levelTree = blocks.LevelTraversal();

        levelTree.ForEach(leaf => m_blockCompiler.CompileBlock(leaf.info));
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Line Renderer/UIC_LineRenderer.cs
﻿/// <NAME>
/// Procedural UI Rounded Corners - https://danielcmcg.github.io/
/// 
/// Based on CiaccoDavide's Unity-UI-Polygon
/// Sourced from - https://github.com/CiaccoDavide/Unity-UI-Polygon

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

// v2.1 - changed from Graphic to MaskableGraphic
// v1.2 - UIC_LineRenderer code optimization and refactoring
[ExecuteInEditMode]
public class UIC_LineRenderer : MaskableGraphic
{
    UIC_Manager _uicManager;

    public Sprite s1;

    [SerializeField] Texture m_Texture;

    RectTransform _rectTransform;
    float _rectScaleX;
    float _deg2Rad90 = Mathf.Deg2Rad * 90f;

    Canvas _canvas;

    //[HideInInspector]
    public List<UIC_Line> uIlines;
    // v1.0.1 - added property for UIC_LineRenderer.UILines with null check
    public List<UIC_Line> UILines
    {
        get
        {
            // v2.0 - fix: uILines list reset on enable
            //if (uIlines == null)
            //    uIlines = new List<UIC_Line>();
            return uIlines;
        }
    }

    [HideInInspector]
    public override Texture mainTexture
    {
        get => m_Texture == null ? s_WhiteTexture : m_Texture;
    }
    [HideInInspector]
    public Texture texture
    {
        get => m_Texture;
        set
        {
            if (m_Texture == value) return;
            m_Texture = value;
            SetVerticesDirty();
            SetMaterialDirty();
        }
    }

    protected override void OnEnable()
    {
        // v2.0 - fix: uILines list reset on enable
        //uIlines = uIlines == null ? uIlines : new List<UIC_Line>();
        _rectTransform = GetComponent<RectTransform>();
        _rectScaleX = _rectTransform.localScale.x;

        _canvas = GetComponentInParent<Canvas>();

        Awake();
    }

    void Awake()
    {
        // v2.0 - fix: uILines list reset on enable
        //uIlines = uIlines == null ? uIlines : new List<UIC_Line>();
        _uicManager = GetComponentInParent<UIC_Manager>();
    }

    void Update()
    {
        // v1.5 - scale the line renderer for world space
        if (_uicManager.CanvasRenderMode != RenderMode.WorldSpace)
        {
            _rectTransform.localScale = Vector3.one / _canvas.scaleFactor;
        }
        else
        {
            _rectTransform.localScale = Vector3.one;

            // v2.1 - fix: changes on the UIC_Manager pivot, cause offset on the LineRenderer, compensated by setting the LineRenderer pivot
            _rectTransform.pivot = new Vector2(_uicManager.canvasRectTransform.pivot.x - 0.5f, _uicManager.canvasRectTransform.pivot.y - 0.5f);
        }

        SetVerticesDirty();
        SetMaterialDirty();
    }

    // v1.2.1 - added uiline count limit
    [HideInInspector]
    public int vertCount = 0;
    public bool IsVertLimitReached { get => (vertCount >= 64000); }

    protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs, Color _color)
    {
        UIVertex[] vbo = new UIVertex[4];
        for (int i = 0; i < vertices.Length; i++)
        {
            var vert = UIVertex.simpleVert;
            vert.color = _color;

            vert.position = vertices[i];
            vert.uv0 = uvs[i];
            vbo[i] = vert;
        }

        return vbo;
    }

    Vector2 lastPos2;
    Vector2 lastPos3;

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();

        _vh = _vh ?? vh;

        if (uIlines != null)
        {
            foreach (UIC_Line line in uIlines)
            {
                if (line.points != null && line.points.Count > 0)
                {
                    if (!IsVertLimitReached)
                    {
                        // v1.2 - fix: excessive frame drop on spline drawing
                        DrawLine(line);
                    }
                    else
                    {
                        Debug.Log("<!> Vert limit reached. Some lines may not be drawn");
                    }

                    vertCount = _vh.currentVertCount;
                }
            }
        }

    }

    float animT = 0;
    Vector2 animPositionStart;
    Vector2 animPositionEnd;


    VertexHelper _vh;

    Vector2 uv0 = new Vector2(0, 0);
    Vector2 uv1 = new Vector2(0, 1);
    Vector2 uv2 = new Vector2(1, 1);
    Vector2 uv3 = new Vector2(1, 0);

    Vector2 pos0;
    Vector2 pos1;
    Vector2 pos2;
    Vector2 pos3;

    void DrawLine(UIC_Line line)
    {
        // v2.1 - Corrected lines position when LineRenderer is offset for Canvas Overlay
        Vector2 uicLineRendererOffset = Vector2.zero;
        if (_uicManager.CanvasRenderMode == RenderMode.ScreenSpaceOverlay)
        {
            uicLineRendererOffset = transform.position;
        }

        int linePointsCount = line.points.Count;
        for (int i = 1; i < linePointsCount; i++)
        {
            Vector2 p0 = line.points[i - 1];
            Vector2 p1 = line.points[i];

            float angle = Mathf.Atan2(p0.y - p1.y, p0.x - p1.x) + (_deg2Rad90);

            float cos = Mathf.Cos(angle);   // calc cos
            float sin = Mathf.Sin(angle);   // calc sin

            float _halfLineWidth = ((line.width / _rectScaleX) / 2);
            float _wCos = (_halfLineWidth * cos);
            float _wSin = (_halfLineWidth * sin);

            // v2.1 - Corrected lines position when LineRenderer is offset
            pos0 = new Vector2((p0.x) + _wCos, (p0.y) + _wSin) - uicLineRendererOffset;
            pos1 = new Vector2((p0.x) - _wCos, (p0.y) - _wSin) - uicLineRendererOffset;
            pos2 = new Vector2((p1.x) - _wCos, (p1.y) - _wSin) - uicLineRendererOffset;
            pos3 = new Vector2((p1.x) + _wCos, (p1.y) + _wSin) - uicLineRendererOffset;

            _vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }, line.color));

            if (i > 1)
            {
                _vh.AddUIVertexQuad(SetVbo(new[] { lastPos3, lastPos2, pos1, pos0 }, new[] { uv0, uv1, uv2, uv3 }, line.color));
            }

            if (i == 1)
                DrawCap(line.points[i - 1] - uicLineRendererOffset, angle + (line.capStartAngleOffset * Mathf.Deg2Rad), line.capStartSize, line.capStartType, line.capStartColor);
            if (i == linePointsCount - 1)
                DrawCap(line.points[i] - uicLineRendererOffset, angle + (line.capEndAngleOffset * Mathf.Deg2Rad), line.capEndSize, line.capEndType, line.capEndColor);

            lastPos2 = pos2;
            lastPos3 = pos3;
        }

        DrawLineAnimation(line, -uicLineRendererOffset);
    }

    public void DrawCap(Vector2 position, float angle, float size, UIC_Line.CapTypeEnum type, Color color)
    {
        if (type != UIC_Line.CapTypeEnum.none)
        {
            float cos = Mathf.Cos(angle);   // calc cos
            float sin = Mathf.Sin(angle);   // calc sin
            size /= _rectScaleX;

            float _sSin = (size * sin);
            float _sCos = (size * cos);

            if (type == UIC_Line.CapTypeEnum.Square)
            {
                Vector2 po0 = new Vector2((position.x - _sSin) + _sCos, (position.y + _sCos) + _sSin);
                Vector2 po1 = new Vector2((position.x - _sSin) - _sCos, (position.y + _sCos) - _sSin);
                Vector2 po2 = new Vector2((position.x + _sSin) - _sCos, (position.y - _sCos) - _sSin);
                Vector2 po3 = new Vector2((position.x + _sSin) + _sCos, (position.y - _sCos) + _sSin);

                _vh.AddUIVertexQuad(SetVbo(new[] { po0, po1, po2, po3 }, new[] { uv0, uv1, uv2, uv3 }, color));
            }
            else if (type == UIC_Line.CapTypeEnum.Triangle)
            {
                Vector2 po0 = new Vector2((position.x - _sSin), (position.y + _sCos));
                Vector2 po1 = new Vector2((position.x - _sSin), (position.y + _sCos));
                Vector2 po2 = new Vector2((position.x + _sSin) - _sCos, (position.y - _sCos) - _sSin);
                Vector2 po3 = new Vector2((position.x + _sSin) + _sCos, (position.y - _sCos) + _sSin);

                _vh.AddUIVertexQuad(SetVbo(new[] { po0, po1, po2, po3 }, new[] { uv0, uv1, uv2, uv3 }, color));
            }
            else if (type == UIC_Line.CapTypeEnum.Circle)
            {
                DrawCircle(position, size, color);
            }
        }
    }

    void DrawCircle(Vector2 position, float radius, Color color)
    {
        Vector2 p0 = position;

        Vector2 prevX = p0;
        float _circleSlice = (360 / 10);
        for (int j = 0; j <= 10; j++)
        {
            float angle = _circleSlice * j;
            angle = Mathf.Deg2Rad * angle;

            float cos = Mathf.Cos(angle);   // calc cos
            float sin = Mathf.Sin(angle);   // calc sin

            pos2 = p0;
            pos3 = p0;
            pos0 = prevX;
            pos1 = new Vector2((p0.x) + (radius * cos), (p0.y) + (radius * sin));

            prevX = pos1;

            // v1.4 - fix: circle cap with uv wrongly positioned
            _vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv3, uv0, uv1, uv2 }, color));
        }
    }

    // v1.4 - method to draw line animations
    public void DrawLineAnimation(UIC_Line line, Vector2 offset)
    {
        UIC_LineAnimation animation = line.animation;
        if (animation.isActive)
        {
            for (int i = 0; i < animation.pointCount; i++)
            {
                System.Tuple<Vector2, float> pointInLine;
                if (animation.Type == UIC_LineAnimation.AnimationTypeEnum.lerp)
                {
                    // triangle wave
                    animation.time = Mathf.Abs(((Time.time * animation.speed + ((float)i / (float)animation.pointCount)) % 1));

                    if (animation.speed < 0)
                        animation.time = 1 - animation.time;

                    pointInLine = line.LerpLine(animation.time);
                }
                else
                {
                    float timePerPoint = 0;
                    animation.time += Mathf.Abs(((Time.deltaTime * animation.speed * 100)) / line.length);
                    if (animation.time > 1)
                        animation.time = 0;

                    timePerPoint = animation.time + ((float)i / (float)animation.pointCount);
                    if (timePerPoint > 1)
                        timePerPoint = timePerPoint - 1;

                    if (animation.speed < 0)
                        timePerPoint = 1 - timePerPoint;

                    pointInLine = line.LerpLine(timePerPoint);
                }
                DrawCap(pointInLine.Item1 + offset, pointInLine.Item2, animation.size, animation.DrawType, animation.color);
            }
        }
    }
}

[System.Serializable]
public class UISpline
{
    public Vector2[] controlPoints = new Vector2[4];
    public Vector2[] points = new Vector2[1];
    public int steps;
    public static int minPoints = 5;
    public static int maxPoints = 15;

    public void SetControlPoints(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
    {
        // v1.2 - sets the number of points in the line based on its curvature
        steps = CalculateNumberOfPointsInLine(p0, p1, p2, p3);

        controlPoints = new Vector2[] { p0, p1, p2, p3 };
        points = GetCurve(steps);
    }

    // v1.2 - added method that sets the number of points in the line based on its curvature
    // - adjust the values  minPoints and maxPoints to achieve the desired efficiency or smoothness of the lines
    public int CalculateNumberOfPointsInLine(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
    {
        float a0 = Mathf.Abs(Mathf.Sin(Vector2.Angle(p0 - p1, p3 - p1) * Mathf.Deg2Rad));
        float a1 = Mathf.Abs(Mathf.Sin(Vector2.Angle(p3 - p2, p0 - p2) * Mathf.Deg2Rad));
        float r0 = a0 > a1 ? a0 : a1;

        return (int)((r0 * (maxPoints - minPoints)) + minPoints);
    }

    Vector2[] GetCurve(int steps)
    {
        points = new Vector2[steps + 1];
        for (int i = 0; i < steps; i++)
        {
            points[i] = GetPoint(controlPoints[0], controlPoints[1], controlPoints[2], controlPoints[3], (float)i / (float)steps);
        }
        points[steps] = controlPoints[3];

        return points;
    }

    public Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
    {
        t = Mathf.Clamp01(t);
        float oneMinusT = 1f - t;
        return
            oneMinusT * oneMinusT * oneMinusT * p0 +
            3f * oneMinusT * oneMinusT * t * p1 +
            3f * oneMinusT * t * t * p2 +
            t * t * t * p3;
    }

}<file_sep>/MP_ARCT/Assets/Scripts/BlockInput.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BlockInput : UIC_Node
{
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Editor/UIC_NodeEditor.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(UIC_Node))]
public class UIC_NodeEditor : Editor
{
    UIC_Node uicNode;

    public override void OnInspectorGUI()
    {
        if (uicNode == null)
            uicNode = (UIC_Node)target;
        nodePosition = uicNode.transform.position;
        spLineControlPosition = uicNode.spLineControlPointTranform.position;
        DrawDefaultInspector();
    }

    Vector3 nodePosition;
    Vector3 spLineControlPosition;
    void OnSceneGUI()
    {
        Handles.DrawLine(nodePosition, spLineControlPosition);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/Connect The Life Cycles/Scripts/LifeCycles_GameManager.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LifeCycles_GameManager : MonoBehaviour
{
    public UIC_Manager uicManager;

    int lastConnCount;

    void Start()
    {
        foreach (UIC_Entity entity in uicManager.EntityList)
        {
            entity.DisableClick = true;
        }

        lastConnCount = uicManager.ConnectionsList != null ? uicManager.ConnectionsList.Count : 0;

        // set pointer detection range for nodes
        //uicManager.MaxPointerDetectionDistance = 130;
        // set the line type
        uicManager.globalLineType = UIC_Connection.LineTypeEnum.Line;

        // add listener for pointer event
        uicManager.pointer.e_OnPointerUpFirst.AddListener(
            delegate
            {
                CheckAndUpdateNodeConnections();
            });
    }

    private void CheckAndUpdateNodeConnections()
    {
        UIC_Node clickedNode = uicManager.GetClickedObjectOfType<UIC_Node>();

        if (clickedNode)
        {
            UIC_Node foundNode = clickedNode.lastFoundNode;

            if (foundNode)
            {
                UIC_Connection outConn = clickedNode.GetOutConnections().Count > 0 ? clickedNode.GetOutConnections()[0] : null;
                UIC_Connection inConn = foundNode.GetInConnections().Count > 0 ? foundNode.GetInConnections()[0] : null;

                if (outConn != null)
                {
                    outConn.Remove();
                }

                if (inConn != null)
                {
                    inConn.Remove();
                }
            }
        }
    }

    void Update()
    {
        if (lastConnCount != uicManager.ConnectionsList.Count)
        {
            lastConnCount = uicManager.ConnectionsList.Count;
        }
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/DataStructure/Node.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Node<T>
{
    public int level;
    public Node<T> parent;
    public List<Node<T>> branches = new List<Node<T>>();
    public Tree<T> rootTree;
    public T info;
    
    public int branchCount
    {
        get=>branches.Count;
    }

    public bool isRoot
    {
        get => parent == null;
    }

    public bool isExternal
    {
        get => branchCount == 0;
    }

    public bool isInternal
    {
        get => !isExternal;
    }

    public Node(Tree<T> tree, T info, Node<T> parent=null)
    {
        this.rootTree = tree;
        this.info = info;

        if (parent != null)
        {
            level = parent.level + 1;
        }
        
        tree.height = Math.Max(tree.height, level);
    }
}

   
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_EmptyContextItem.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIC_EmptyContextItem : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    public string ID => "empty";
    public Color objectColor { get; set; }
    public int priority;
    public int Priority => priority;

    public void Action()
    {

    }

    public void OnChangeSelection()
    {

    }

    public void Remove()
    {

    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_Connection.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[System.Serializable]
public class UIC_Connection : I_UIC_Object, I_UIC_Selectable, I_UIC_Clickable
{
    // connection nodes, node0 start & node1 end 
    public UIC_Node node0;
    public UIC_Node node1;

    public enum LineTypeEnum { Spline, Z_Shape, Line }
    public LineTypeEnum lineType;
    public UIC_Line line;

    public Vector3[] handles = new Vector3[2];

    public UIC_Connection(UIC_Node node0, UIC_Node node1, LineTypeEnum lineType)
    {
        this.node0 = node0;
        this.node1 = node1;
        this.lineType = lineType;
    }

    public string ID => string.Format("Connection ({0} - {1})", node0.entity ? node0.entity.name : "null", node1.entity ? node1.entity.name : "null");

    public Vector3[] Handles
    {
        get
        {
            handles[0] = node0.spLineControlPointTranform.position;
            handles[1] = node1.spLineControlPointTranform.position;
            return handles;
        }
        set => handles = value;
    }
    public Color objectColor
    {
        get => line.defaultColor;
        set
        {
            line.color = value;
            line.defaultColor = value;
        }
    }

    public int Priority => 1;

    public bool DisableClick => node0.entity.uicManager.disableConnectionClick;

    public void OnPointerDown()
    {
        if (!node0.entity.uicManager.selectedUIObjectsList.Contains(this))
        {
            Select();
        }
        else
        {
            Unselect();
        }
    }

    public void OnPointerUp()
    {

    }

    public void Remove()
    {
        Unselect();

        node0.connectionsList.Remove(this);
        node1.connectionsList.Remove(this);

        node0.SetIcon();
        node1.SetIcon();

        node0.entity.uicManager.RemoveLine(this.line);
        node0.entity.uicManager.ConnectionsList.Remove(this);
    }

    public void Select()
    {
        line.color = line.selectedColor;
        if (!node0.entity.uicManager.selectedUIObjectsList.Contains(this))
        {
            node0.entity.uicManager.selectedUIObjectsList.Add(this);
        }
    }

    public void Unselect()
    {
        line.color = line.defaultColor;
        if (node0.entity.uicManager.selectedUIObjectsList.Contains(this))
        {
            node0.entity.uicManager.selectedUIObjectsList.Remove(this);
        }
    }

    public UISpline connectionUISpline;

    // v1.3 - line poinst adjusted to canvas render mode overlay and camera
    Vector3[] LinePoints
    {
        get
        {
            UIC_Manager uicManager = node0.entity.uicManager;
            Camera mainCamera = uicManager.mainCamera;
            if (uicManager.CanvasRenderMode == RenderMode.ScreenSpaceOverlay)
            {
                return new Vector3[] {
                    node0.transform.position,
                    Handles[0],
                    Handles[1],
                    node1.transform.position };
            }
            else if (uicManager.CanvasRenderMode == RenderMode.ScreenSpaceCamera)
            {
                return new Vector3[] {
                    UIC_Utility.WorldToScreenPoint(node0.transform.position, uicManager),
                    UIC_Utility.WorldToScreenPoint(Handles[0], uicManager),
                    UIC_Utility.WorldToScreenPoint(Handles[1], uicManager),
                    UIC_Utility.WorldToScreenPoint(node1.transform.position, uicManager) };
            }
            // v1.5 - set the line points on the world space canvas
            else if (uicManager.CanvasRenderMode == RenderMode.WorldSpace)
            {
                return new Vector3[] {
                    UIC_Utility.WorldToScreenPointInCanvas(node0.transform.position, uicManager),
                    UIC_Utility.WorldToScreenPointInCanvas(Handles[0], uicManager),
                    UIC_Utility.WorldToScreenPointInCanvas(Handles[1], uicManager),
                    UIC_Utility.WorldToScreenPointInCanvas(node1.transform.position, uicManager) };
            }

            return new Vector3[] {
                node0.transform.position,
                Handles[0],
                Handles[1],
                node1.transform.position };
        }
    }

    public void UpdateLine()
    {
        if (lineType == LineTypeEnum.Spline)
        {
            connectionUISpline = new UISpline();
            connectionUISpline.SetControlPoints(
                LinePoints[0],
                LinePoints[1],
                LinePoints[2],
                LinePoints[3]);
            line.SetPoints(connectionUISpline.points);
        }
        if (lineType == LineTypeEnum.Z_Shape)
        {
            line.SetPoints(new Vector2[] {
                LinePoints[0],
                (LinePoints[1] + LinePoints[0])/2,
                (LinePoints[2] + LinePoints[3])/2,
                LinePoints[3] });
        }
        if (lineType == LineTypeEnum.Line)
        {
            line.SetPoints(new Vector2[] {
                LinePoints[0],
                LinePoints[3] });
        }
    }

    public List<UIC_Connection> GetCrossedConnections()
    {
        List<UIC_Connection> crossedConnections = new List<UIC_Connection>();

        foreach (UIC_Connection conn in node0.entity.uicManager.ConnectionsList)
        {
            if (UIC_Utility.ConnectionsIntersect(conn, this))
                if (!(conn.node0 == node0 || conn.node1 == node1 || conn.node0 == node1 || conn.node1 == node0))
                    crossedConnections.Add(conn);
        }

        return crossedConnections;
    }

    public UIC_Node GetOppositeNode(UIC_Node node)
    {
        return node0 == node ? node1 : node0;
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Block.cs
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Block : UIC_Entity
{
    [SerializeField] int _numOfInput;
    [SerializeField] int _numOfOutput;

    private BlockManager m_BlockManager;

    public int InputCount
    {
        get => _numOfInput;
        set => _numOfInput = value;
    }

    public int OutputCount
    {
        get => _numOfOutput;
        set => _numOfOutput = value;
    }

    private void Awake()
    {
        m_BlockManager = BlockManager.Instance;
    }

    public virtual BlockOutput[] BlockAction()
    {
        return null;
    }

    public void OnAttached(Block block)
    {
        
    }

    public void OnDetached()
    {

    }

    public void TestAction()
    {
        string inputs = "";
        string outputs = "";

        foreach(var node in nodeList)
        {
            if (node.polarityType == UIC_Node.PolarityTypeEnum._in)
            {
                inputs += " " + node.name;
            }

            else if (node.polarityType == UIC_Node.PolarityTypeEnum._out)
            {
                outputs += " " + node.name;
            }
        }

        print(string.Format("In Node : {0}, Out Node : {1}", inputs, outputs));
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Interfaces/I_UIC_ContextItem.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface I_UIC_ContextItem
{
    void Action();
    void OnChangeSelection();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Interfaces/I_UIC_Selectable.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface I_UIC_Selectable
{
    Vector3[] Handles { get; set; }
    void Select();
    void Unselect();
    void Remove();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_LocalInputLineWidth.cs
﻿using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;

public class UIC_LocalInputLineWidth : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;
    public string ID => "input";
    public Color objectColor { get; set; }
    public int Priority => -10;

    InputField _inputField;

    public void Action()
    {

    }

    List<UIC_Connection> _connList = new List<UIC_Connection>();

    public void OnChangeSelection()
    {
        _connList.Clear();
        bool _show = false;
        foreach (I_UIC_Selectable item in _uicManager.selectedUIObjectsList)
        {
            if (item is UIC_Connection)
            {
                _connList.Add(item as UIC_Connection);
                _show = true;
            }
        }

        gameObject.SetActive(_show);

        if (_connList.Count != 1)
            _inputField.text = "-";
        else
            _inputField.text = _connList[0].line.width.ToString();
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _inputField = GetComponentInChildren<InputField>();
    }

    private void SetWidth(string arg0)
    {
        if (_inputField.text != "-")
        {
            foreach (UIC_Connection conn in _connList)
            {
                float w = conn.line.width;
                if (float.TryParse(_inputField.text, NumberStyles.Float, CultureInfo.InvariantCulture, out w))
                    conn.line.width = w;
            }
        }
    }

    void OnEnable()
    {
        _inputField.onValueChanged.AddListener(SetWidth);
    }

    void OnDisable()
    {
        _inputField.onValueChanged.RemoveAllListeners();
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Interfaces/I_UIC_Object.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface I_UIC_Object
{
    string ID { get; }
    Color objectColor { get; set; }
    int Priority { get; }
    void Remove();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Interfaces/I_UIC_Clickable.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface I_UIC_Clickable
{
    bool DisableClick { get; }
    void OnPointerDown();
    void OnPointerUp();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/Interfaces/I_UIC_Draggable.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface I_UIC_Draggable
{
    bool EnableDrag { get; set; }
    void OnDrag();
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_DropdownGlobalLineType.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_DropdownGlobalLineType : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;

    Dropdown _dropdown;

    public string ID => "dropdown";
    public Color objectColor { get; set; }

    public int Priority => -9;

    public void Action()
    {

    }

    public void OnChangeSelection()
    {

    }

    private void SetLineType(int arg0)
    {
        UIC_Connection.LineTypeEnum parsed_enum = (UIC_Connection.LineTypeEnum)System.Enum.Parse(typeof(UIC_Connection.LineTypeEnum), _dropdown.options[_dropdown.value].text);
        _uicManager.globalLineType = parsed_enum;
    }

    void SetDropdown()
    {
        _dropdown.value = _dropdown.options.FindIndex(option => option.text == _uicManager.globalLineType.ToString());
    }

    void OnEnable()
    {
        SetDropdown();
        _dropdown.onValueChanged.AddListener(SetLineType);
    }

    void OnDisable()
    {
        _dropdown.onValueChanged.RemoveAllListeners();
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _dropdown = GetComponent<Dropdown>();
    }

    void Start()
    {
        string[] _names = System.Enum.GetNames(typeof(UIC_Connection.LineTypeEnum));
        List<string> _options = new List<string>();
        _options.AddRange(_names);

        _dropdown.options.Clear();
        _dropdown.AddOptions(_options);
    }

    public void Remove()
    {
        Destroy(gameObject);
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/DataStructure/Tree.cs
using System.Collections;
using System.Collections.Generic;

public class Tree<T>
{
    public Node<T> root;
    public int height = 0;

    public Tree(Node<T> root)
    {
        this.root = root; 
    }

    public Tree()
    {

    }

    public Node<T> GetNode()
    {
        return null;
    }

    public void AddBranch(Node<T> target, Node<T> added)
    {
        target.branches.Add(added);
    }

    public void RemoveBranch(Node<T> target, Node<T> deleted)
    {
        if (target.branchCount > 0)
        {
            target.branches.Remove(deleted);
        }
    }

    public Node<T>[] LevelTraversal()
    {
        Queue<Node<T>> queue = new Queue<Node<T>>();
        List<Node<T>> returnList = new List<Node<T>>();

        queue.Enqueue(root);

        while(queue.Count > 0)
        {
            var temp = queue.Dequeue();
            foreach(var branch in temp.branches)
            {
                queue.Enqueue(branch);
            }

            returnList.Add(temp);
        }

        return returnList.ToArray();
    }
}
<file_sep>/MP_ARCT/Assets/Scripts/Base/Singleton.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static bool _ShuttingDown = false;
    private static object _Lock = new object();
    private static T _Instance;
    public static T Instance
    {
        get
        {
            if (_ShuttingDown)
            {
                Debug.Log("[Singleton] Instance '" + typeof(T) + "' already destroyed. Returning null.");
                return null;
            }
            lock (_Lock) //Thread Safe
            {
                if (_Instance == null)
                {
                    _Instance = (T)FindObjectOfType(typeof(T));
                    if (_Instance == null)
                    {
                        var singletonObject = new GameObject();
                        _Instance = singletonObject.AddComponent<T>();
                        singletonObject.name = typeof(T).ToString();
                    }
                }
                return _Instance;
            }
        }
    }

    private void OnApplicationQuit()
    {
        _ShuttingDown = true;
    }
    private void OnDestroy()
    {
        _ShuttingDown = true;
    }
}


//출처: https://skuld2000.tistory.com/26 [아마군의 Dev로그]<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scenes/ScrollView Graphs/Scripts/CustomScrollRect.cs
﻿using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine;

public class CustomScrollRect : ScrollRect 
{
    int maximumTouchCount = 2;

    public Vector2 MultiTouchPosition
    {
        get
        {
            Vector2 position = Vector2.zero;
            for (int i = 0; i < Input.touchCount && i < maximumTouchCount; i++)
            {
                position += Input.touches[i].position;
            }
            position /= ((Input.touchCount <= maximumTouchCount) ? Input.touchCount : maximumTouchCount);

            return position;
        }
    }

    public override void OnBeginDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Middle)
        {
            eventData.button = PointerEventData.InputButton.Left;
            base.OnBeginDrag(eventData);
        }
        if (Input.touchCount >= maximumTouchCount)
        {
            eventData.position = MultiTouchPosition;
            base.OnBeginDrag(eventData);
        }
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Middle)
        {
            eventData.button = PointerEventData.InputButton.Left;
            base.OnEndDrag(eventData);
        }
        if (Input.touchCount >= maximumTouchCount)
        {
            eventData.position = MultiTouchPosition;
            base.OnEndDrag(eventData);
        }
    }

    public override void OnDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Middle)
        {
            eventData.button = PointerEventData.InputButton.Left;
            base.OnDrag(eventData);
        }
        if (Input.touchCount >= maximumTouchCount)
        {
            eventData.position = MultiTouchPosition;
            base.OnDrag(eventData);
        }
    }

}<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/ContextItems/UIC_GlobalInputLineWidth.cs
﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIC_GlobalInputLineWidth : MonoBehaviour, I_UIC_ContextItem, I_UIC_Object
{
    UIC_Manager _uicManager;

    InputField _inputField;

    public string ID => throw new NotImplementedException();

    public Color objectColor { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

    public int Priority => -10;

    public void Action()
    {

    }

    public void OnChangeSelection()
    {
        _inputField.text = _uicManager.globalLineWidth.ToString();
    }

    void Awake()
    {
        _uicManager = GetComponentInParent<UIC_Manager>();
        _inputField = GetComponentInChildren<InputField>();
    }

    private void SetWidth(string arg0)
    {
        _uicManager.globalLineWidth = int.Parse(_inputField.text);
    }

    void OnEnable()
    {
        _inputField.onValueChanged.AddListener(SetWidth);
    }

    void OnDisable()
    {
        _inputField.onValueChanged.RemoveAllListeners();
    }

    public void Remove()
    {
        throw new NotImplementedException();
    }
}
<file_sep>/MP_ARCT/Assets/UI Connect Asset/Scripts/UIC_ContextMenu.cs
﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIC_ContextMenu : MonoBehaviour
{
    static List<I_UIC_ContextItem> contextItemList;

    void Awake()
    {
        contextItemList = new List<I_UIC_ContextItem>();
        foreach (Transform t in transform)
        {
            I_UIC_ContextItem item = t.GetComponent<I_UIC_ContextItem>();
            if (item != null)
                contextItemList.Add(item);
        }
    }

    void Start()
    {
        UpdateContextMenu();
    }

    public static void UpdateContextMenu()
    {
        if (contextItemList != null)
        {
            foreach (I_UIC_ContextItem item in contextItemList)
            {
                item.OnChangeSelection();
            }
        }
    }
}
