Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Radial UI layout in Unity, Code included

Discussion in 'Unity UI & TextMesh Pro' started by DGoodayle, Sep 17, 2015.

  1. DGoodayle

    DGoodayle

    Joined:
    Dec 5, 2011
    Posts:
    23
  2. solkar

    solkar

    Joined:
    Aug 15, 2012
    Posts:
    38
    I'm sure this will come in handy
     
  3. rahuxx

    rahuxx

    Joined:
    May 8, 2009
    Posts:
    525
    nice work m8.
     
  4. HolyShovel

    HolyShovel

    Joined:
    Jun 19, 2013
    Posts:
    156
    Intresting.
     
  5. Hakazaba

    Hakazaba

    Joined:
    Jul 1, 2015
    Posts:
    107
    I'm getting an error when trying to build.

    Assets/Scripts/JustAPixel/uGui/RadialLayout.cs(44,29): error CS0115: `RadialLayout.OnValidate()' is marked as an override but no suitable method found to override
     
  6. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    325
    Hi, this is fixed if you redownload the code. I bumped into the same issue :)

    Bye,

    Jean
     
  7. AndreiKubyshkin

    AndreiKubyshkin

    Joined:
    Nov 14, 2013
    Posts:
    198
    Hey guys,

    I've noticed, that this script layout elements even if they're not active, i.e. it works a little different from other layout scripts.

    I've changed main function of the script a little so it won't take inactive elements into account.

    Hope someone will find it usefull.

    Code (CSharp):
    1. void CalculateRadial()
    2.         {
    3.             int activeChildCount = 0;
    4.             for(int i =0;i<transform.childCount;i++)
    5.             {
    6.                 var child = transform.GetChild(i);
    7.                 if(child && child.gameObject.activeSelf)
    8.                 {
    9.                     activeChildCount++;
    10.                 }
    11.             }
    12.            
    13.  
    14.             m_Tracker.Clear();
    15.             if (activeChildCount == 0)
    16.                 return;
    17.             float fOffsetAngle = ((MaxAngle - MinAngle)) / (activeChildCount - 1);
    18.  
    19.  
    20.             float fAngle = StartAngle;
    21.             for (int i = 0; i < transform.childCount; i++)
    22.             {
    23.                 RectTransform child = (RectTransform)transform.GetChild(i);
    24.                 if (child != null && child.gameObject.activeSelf)
    25.                 {
    26.                     //Adding the elements to the tracker stops the user from modifiying their positions via the editor.
    27.                     m_Tracker.Add(this, child,
    28.                     DrivenTransformProperties.Anchors |
    29.                     DrivenTransformProperties.AnchoredPosition |
    30.                     DrivenTransformProperties.Pivot);
    31.                     Vector3 vPos = new Vector3(Mathf.Cos(fAngle * Mathf.Deg2Rad), Mathf.Sin(fAngle * Mathf.Deg2Rad), 0);
    32.                     child.localPosition = vPos * fDistance;
    33.                     //Force objects to be center aligned, this can be changed however I'd suggest you keep all of the objects with the same anchor points.
    34.                     child.anchorMin = child.anchorMax = child.pivot = new Vector2(0.5f, 0.5f);
    35.                     fAngle += fOffsetAngle;
    36.                 }
    37.  
    38.             }
    39.  
    40.         }
     
  8. Bezzy

    Bezzy

    Joined:
    Apr 1, 2009
    Posts:
    75
    I think it may also need to check "LayoutElement" 's "ignore layout" boolean (and this is a bit more expensive because of GetComponent calls - can't think of a great way to cache them off at runtime if you're dealing with dynamically changing number of radial elements - however, this would go against how Radials work, ergonomically, since they rely heavily on muscle memory).
     
    Last edited: Apr 15, 2016
  9. JtheSpaceC

    JtheSpaceC

    Joined:
    Oct 5, 2014
    Posts:
    14
    Nice one!
     
  10. Kabendji

    Kabendji

    Joined:
    Feb 9, 2013
    Posts:
    24
    Hi,

    Is there a way to change value the value of "StartAngle" Trough another Script ?

    Example
    Code (CSharp):
    1. public class _myScripts_load_data : MonoBehaviour {
    2.  
    3. RadialLayout radial_layout;
    4.  
    5. void Start()
    6. {
    7. radial_layout = GameObject.Find("Hello").GetComponent<RadialLayout>();
    8.  
    9. radial_layout.StartAngle = 150f;
    10. }
    11. }
    Thanks for Your help
     
  11. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    The code above should work and change the value of StartAngle. Is it not working?
     
  12. Kabendji

    Kabendji

    Joined:
    Feb 9, 2013
    Posts:
    24
    Nop, as "RadialLayout" is not a Monobehaviour but a LayerGroup :/
     
  13. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    It worked fine for me. Try this in a new project.
    1. Copy the RadialLayout from the link about and Save as a C# Script
    2. Create a Panel name it RadialPanel. Drag the RadialLayout Script onto it.
    3. Set the Radial Layout Start Angle to 180 in the Editor
    4. Create a new Script and save the script I have below into it. Make sure to call the script RadialTest
    5. Create a new Panel and drag my Script onto it.
    6. Set the Other Panel variable on this script to the RadialPanel (drag it down)
    7. Hit Play. Notice my script changes startAngle to 44
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.EventSystems;
    4. using System.Collections;
    5.  
    6.  
    7. public class RadialTest : MonoBehaviour {
    8.  
    9.     public GameObject OtherPanel;
    10.     private RadialLayout myRL;
    11.     void Start()
    12.     {
    13.         myRL = OtherPanel.GetComponent<RadialLayout>();
    14.         myRL.StartAngle = 44;
    15.     }
    16. }
     
  14. Kabendji

    Kabendji

    Joined:
    Feb 9, 2013
    Posts:
    24
    Error : 'RadialLayout' is not a known identifier - (11, 22)

    Maybe RadialLayout and myScript have to be on the same Folder Project ?
     
  15. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    I don't know. I'm fairly new to Unity. When I tried the above it was in a brand new project and both Scripts were in a Folder called Scripts. Did you try this in a brand new project to see if it wasn't something else that was the problem?
     
  16. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    4,403
    @Kabendji Do you have the using UnityEngine.UI at the top of your script?

    If RadialLayout is giving you an error. In visual studios you can right click on it and click the lightbulb. It will offer you solutions to fix it. Monodevelop has a feature like this as well, but I can't remember what they call it.
     
  17. Kabendji

    Kabendji

    Joined:
    Feb 9, 2013
    Posts:
    24
    I'm using Sublime to develop (with OmniSharp) I'll try to open with VisualStudio to take a look, thanks you :)
     
  18. Kabendji

    Kabendji

    Joined:
    Feb 9, 2013
    Posts:
    24
    Fix the issue, forgot to Call the namespace UI.Extentions ..

    Thanks guys to point me out.

    Another Question :

    Is there a way to not use the "first child" for MinAngle and MaxAngle, but another one?

    I'm Making a animation, using MinAngle to Collapse child, then F Distance to 0 to center them and make it disapear.

    But I want to change the child where it's collapse depending on a value.

    I'm seeing no where what push the first child to be the "default value".
     
  19. HunterAugust

    HunterAugust

    Joined:
    Jan 18, 2015
    Posts:
    2
    This is a really great asset, so thank you very much for sharing it!

    I did run into an issue where it would not ignore the LayoutElement.IgnoreLayout bool. So I resolved that with this (In case anyone else runs into this issue).

    Thanks again! @DGoodayle :)

    Code (CSharp):
    1. void CalculateRadial()
    2.     {
    3.         m_Tracker.Clear();
    4.         if(transform.childCount == 0)
    5.             return;
    6.  
    7.         int childCount = 0;
    8.  
    9.         //Checks if any child has a layoutelement, if not adds to childCount.
    10.         for(int i = 0; i < transform.childCount; i++)
    11.         {
    12.             RectTransform child = (RectTransform)transform.GetChild(i);
    13.             LayoutElement childLayout = child.GetComponent<LayoutElement>();
    14.             if(childLayout != null)
    15.             {
    16.                 if(!childLayout.ignoreLayout) // if it has the layout element but Ignore Layout is false add to childCount.
    17.                 {
    18.                     childCount++;
    19.                 }
    20.             }
    21.             else
    22.             {
    23.                 childCount++;
    24.             }
    25.         }
    26.  
    27.  
    28.         float fOffsetAngle = ((MaxAngle - MinAngle)) / (childCount - 1);
    29.  
    30.         float fAngle = StartAngle;
    31.         for(int i = 0; i < childCount; i++)
    32.         {
    33.             RectTransform child = (RectTransform)transform.GetChild(i);
    34.    
    35.             if(child != null)
    36.             {
    37.                 //Adding the elements to the tracker stops the user from modifiying their positions via the editor.
    38.                 m_Tracker.Add(this, child,
    39.                 DrivenTransformProperties.Anchors |
    40.                 DrivenTransformProperties.AnchoredPosition |
    41.                 DrivenTransformProperties.Pivot);
    42.                 Vector3 vPos = new Vector3(Mathf.Cos(fAngle * Mathf.Deg2Rad), Mathf.Sin(fAngle * Mathf.Deg2Rad), 0);
    43.                 child.localPosition = vPos * Distance;
    44.                 //Force objects to be center aligned, this can be changed however I'd suggest you keep all of the objects with the same anchor points.
    45.                 child.anchorMin = child.anchorMax = child.pivot = new Vector2(0.5f, 0.5f);
    46.                 fAngle += fOffsetAngle;
    47.             }
    48.         }
    49.     }
     
  20. ScareCrow95

    ScareCrow95

    Joined:
    Apr 5, 2016
    Posts:
    4
    I can't thank you enough for this great asset, it really helped me out!

    I modified it a bit on top of Andrie's changes, now you it will auto calculate the max angle, so all the circles will be evenly spaced as you create them, you can still change minimum angle to offset them manually.


    Code (CSharp):
    1. void CalculateRadial()
    2.     {
    3.         int activeChildCount = 0;
    4.         for(int i =0;i<transform.childCount;i++)
    5.         {
    6.             var child = transform.GetChild(i);
    7.             if(child && child.gameObject.activeSelf)
    8.             {
    9.                 activeChildCount++;
    10.             }
    11.         }
    12.  
    13.  
    14.         m_Tracker.Clear();
    15.         if (activeChildCount == 0)
    16.             return;
    17.  
    18.         float sAngle = 360/activeChildCount*(activeChildCount-1);
    19.  
    20.         if (MinAngle > sAngle)
    21.             MinAngle = sAngle;
    22.  
    23.         float fOffsetAngle = ((sAngle - MinAngle)) / (activeChildCount - 1);
    24.  
    25.        
    26.  
    27.         float fAngle = StartAngle;
    28.         for (int i = 0; i < transform.childCount; i++)
    29.         {
    30.             RectTransform child = (RectTransform)transform.GetChild(i);
    31.             if (child != null && child.gameObject.activeSelf)
    32.             {
    33.                 //Adding the elements to the tracker stops the user from modifiying their positions via the editor.
    34.                 m_Tracker.Add(this, child,
    35.                     DrivenTransformProperties.Anchors |
    36.                     DrivenTransformProperties.AnchoredPosition |
    37.                     DrivenTransformProperties.Pivot);
    38.                 Vector3 vPos = new Vector3(Mathf.Cos(fAngle * Mathf.Deg2Rad), Mathf.Sin(fAngle * Mathf.Deg2Rad), 0);
    39.                 child.localPosition = vPos * fDistance;
    40.                 //Force objects to be center aligned, this can be changed however I'd suggest you keep all of the objects with the same anchor points.
    41.                 child.anchorMin = child.anchorMax = child.pivot = new Vector2(0.5f, 0.5f);
    42.                 fAngle += fOffsetAngle;
    43.             }
    44.  
    45.         }
    46.  
    47.     }
     
  21. xlabrom

    xlabrom

    Joined:
    Apr 21, 2013
    Posts:
    4
    I added rotation, expansion, expansion limit, clockwise, can someone come in handy



    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. namespace Gamenasia.Unity.GameGUI {
    7.  
    8.     public class UIRadialLayout : LayoutGroup {
    9.  
    10.         [SerializeField]
    11.         protected float radius;
    12.         [SerializeField]
    13.         protected bool clockwise;
    14.         [Range (0f, 360f)]
    15.         [SerializeField]
    16.         protected float minAngle;
    17.         [Range (0f, 360f)]
    18.         [SerializeField]
    19.         protected float maxAngle = 360f;
    20.         [Range (0f, 360f)]
    21.         [SerializeField]
    22.         protected float startAngle;
    23.         [SerializeField]
    24.         protected bool customRebuild;
    25.  
    26.         [Header ("Child rotation")]
    27.         [Range (0f, 360f)]
    28.         [SerializeField]
    29.         protected float startElementAngle;
    30.         [SerializeField]
    31.         protected bool rotateElements;
    32.  
    33.         [Header("Child width")]
    34.         [SerializeField]
    35.         protected bool expandChildWidth;
    36.         [SerializeField]
    37.         protected float childWidthFactor = 1f;
    38.         [Range (0f, 360f)]
    39.         [SerializeField]
    40.         protected float maxWidthFactor = 360f;
    41.         [SerializeField]
    42.         protected bool childWidthFromRadius;
    43.         [SerializeField]
    44.         protected float childWidthRadiusFactor = 0.01f;
    45.  
    46.         [Header ("Child height")]
    47.         [SerializeField]
    48.         protected bool expandChildHeight;
    49.         [SerializeField]
    50.         protected float childHeight = 100f;
    51.         [SerializeField]
    52.         protected bool childHeightFromRadius;
    53.         [SerializeField]
    54.         protected float childHeightRadiusFactor = 0.0025f;
    55.  
    56.         #region Properties
    57.  
    58.         public float Radius {
    59.             get {
    60.                 return radius;
    61.             }
    62.             set {
    63.                 if (radius != value) {
    64.                     radius = value;
    65.                     OnValueChanged ();
    66.                 }
    67.             }
    68.         }
    69.  
    70.         public bool Clockwise {
    71.             get {
    72.                 return clockwise;
    73.             }
    74.             set {
    75.                 if (clockwise != value) {
    76.                     clockwise = value;
    77.                     OnValueChanged ();
    78.                 }
    79.             }
    80.         }
    81.  
    82.         public float MinAngle {
    83.             get {
    84.                 return minAngle;
    85.             }
    86.             set {
    87.                 if (minAngle != value) {
    88.                     minAngle = value;
    89.                     OnValueChanged ();
    90.                 }
    91.             }
    92.         }
    93.  
    94.         public float MaxAngle {
    95.             get {
    96.                 return maxAngle;
    97.             }
    98.             set {
    99.                 if (maxAngle != value) {
    100.                     maxAngle = value;
    101.                     OnValueChanged ();
    102.                 }
    103.             }
    104.         }
    105.  
    106.         public float StartAngle {
    107.             get {
    108.                 return startAngle;
    109.             }
    110.             set {
    111.                 if (startAngle != value) {
    112.                     startAngle = value;
    113.                     OnValueChanged ();
    114.                 }
    115.             }
    116.         }
    117.  
    118.         public bool CustomRebuild {
    119.             get {
    120.                 return customRebuild;
    121.             }
    122.             set {
    123.                 if (customRebuild != value) {
    124.                     customRebuild = value;
    125.                     OnValueChanged ();
    126.                 }
    127.             }
    128.         }
    129.  
    130.         public bool ExpandChildWidth {
    131.             get {
    132.                 return expandChildWidth;
    133.             }
    134.             set {
    135.                 if (expandChildWidth != value) {
    136.                     expandChildWidth = value;
    137.                     OnValueChanged ();
    138.                 }
    139.             }
    140.         }
    141.  
    142.         public float ChildWidthFactor {
    143.             get {
    144.                 return childWidthFactor;
    145.             }
    146.             set {
    147.                 if (childWidthFactor != value) {
    148.                     childWidthFactor = value;
    149.                     OnValueChanged ();
    150.                 }
    151.             }
    152.         }
    153.  
    154.         public bool ChildWidthFromRadius {
    155.             get {
    156.                 return childWidthFromRadius;
    157.             }
    158.             set {
    159.                 if (childWidthFromRadius != value) {
    160.                     childWidthFromRadius = value;
    161.                     OnValueChanged ();
    162.                 }
    163.             }
    164.         }
    165.  
    166.         public float ChildWidthRadiusFactor {
    167.             get {
    168.                 return childWidthRadiusFactor;
    169.             }
    170.             set {
    171.                 if (childWidthRadiusFactor != value) {
    172.                     childWidthRadiusFactor = value;
    173.                     OnValueChanged ();
    174.                 }
    175.             }
    176.         }
    177.  
    178.         public bool ExpandChildHeight {
    179.             get {
    180.                 return expandChildHeight;
    181.             }
    182.             set {
    183.                 if (expandChildHeight != value) {
    184.                     expandChildHeight = value;
    185.                     OnValueChanged ();
    186.                 }
    187.             }
    188.         }
    189.  
    190.         public float ChildHeight {
    191.             get {
    192.                 return childHeight;
    193.             }
    194.             set {
    195.                 if (childHeight != value) {
    196.                     childHeight = value;
    197.                     OnValueChanged ();
    198.                 }
    199.             }
    200.         }
    201.  
    202.         public bool ChildHeightFromRadius {
    203.             get {
    204.                 return childHeightFromRadius;
    205.             }
    206.             set {
    207.                 if (childHeightFromRadius != value) {
    208.                     childHeightFromRadius = value;
    209.                     OnValueChanged ();
    210.                 }
    211.             }
    212.         }
    213.  
    214.         public float ChildHeightRadiusFactor {
    215.             get {
    216.                 return childHeightRadiusFactor;
    217.             }
    218.             set {
    219.                 if (childHeightRadiusFactor != value) {
    220.                     childHeightRadiusFactor = value;
    221.                     OnValueChanged ();
    222.                 }
    223.             }
    224.         }
    225.  
    226.         public RectTransform SelfTransform {
    227.             get {
    228.                 return rectTransform;
    229.             }
    230.         }
    231.  
    232.         public void OnValueChanged () {
    233.             if (customRebuild) {
    234.                 CalculateRadial ();
    235.             }
    236.         }
    237.  
    238.         #endregion
    239.  
    240.         protected override void OnEnable () {
    241.             base.OnEnable ();
    242.             CalculateRadial ();
    243.         }
    244.  
    245.         public override void SetLayoutHorizontal () {
    246.  
    247.         }
    248.  
    249.         public override void SetLayoutVertical () {
    250.  
    251.         }
    252.  
    253.         public override void CalculateLayoutInputVertical () {
    254.             CalculateRadial ();
    255.         }
    256.  
    257.         public override void CalculateLayoutInputHorizontal () {
    258.             CalculateRadial ();
    259.         }
    260.  
    261. #if UNITY_EDITOR
    262.         protected override void OnValidate () {
    263.             base.OnValidate ();
    264.             CalculateRadial ();
    265.         }
    266. #endif
    267.  
    268.         public void CalculateRadial () {
    269.             int activeChildCount = 0;
    270.             List<RectTransform> childList = new List<RectTransform> ();
    271.             for (int i = 0; i < transform.childCount; i++) {
    272.                 RectTransform child = transform.GetChild (i) as RectTransform;
    273.                 LayoutElement childLayout = child.GetComponent<LayoutElement> ();
    274.                 if (child == null || !child.gameObject.activeSelf || (childLayout != null && childLayout.ignoreLayout)) {
    275.                     continue;
    276.                 }
    277.                 childList.Add (child);
    278.                 activeChildCount++;
    279.             }
    280.  
    281.             m_Tracker.Clear ();
    282.             if (activeChildCount == 0) {
    283.                 return;
    284.             }
    285.  
    286.             rectTransform.sizeDelta = new Vector2 (radius, radius) * 2f;
    287.             float sAngle = ((360f) / activeChildCount) * (activeChildCount - 1f);
    288.  
    289.             float anglOffset = minAngle;
    290.             if (anglOffset > sAngle) {
    291.                 anglOffset = sAngle;
    292.             }
    293.  
    294.             float buff = sAngle - anglOffset;
    295.  
    296.             float maxAngl = 360f - maxAngle;
    297.             if (maxAngl > sAngle) {
    298.                 maxAngl = sAngle;
    299.             }
    300.  
    301.             if (anglOffset > sAngle) {
    302.                 anglOffset = sAngle;
    303.             }
    304.  
    305.             buff = sAngle - anglOffset;
    306.  
    307.             float fOffsetAngle = ((buff - maxAngl)) / (activeChildCount - 1f);
    308.             float fAngle = startAngle + anglOffset;
    309.             float countWidthFactor = fOffsetAngle < maxWidthFactor ? fOffsetAngle : maxWidthFactor;
    310.  
    311.             bool expandChilds = expandChildWidth | expandChildHeight;
    312.             DrivenTransformProperties drivenTransformProperties = DrivenTransformProperties.Anchors | DrivenTransformProperties.AnchoredPosition | DrivenTransformProperties.Pivot;
    313.             if (expandChildWidth) {
    314.                 drivenTransformProperties |= DrivenTransformProperties.SizeDeltaX;
    315.             }
    316.             if (expandChildHeight) {
    317.                 drivenTransformProperties |= DrivenTransformProperties.SizeDeltaY;
    318.             }
    319.             if (rotateElements) {
    320.                 drivenTransformProperties |= DrivenTransformProperties.Rotation;
    321.             }
    322.  
    323.             if (clockwise) {
    324.                 fOffsetAngle *= -1f;
    325.             }
    326.  
    327.             for (int i = 0; i < childList.Count; i++) {
    328.                 RectTransform child = childList[i];
    329.                 if (child != null && child.gameObject.activeSelf) {
    330.                     //Adding the elements to the tracker stops the user from modifiying their positions via the editor.
    331.                     m_Tracker.Add (this, child, drivenTransformProperties);
    332.                     Vector3 vPos = new Vector3 (Mathf.Cos (fAngle * Mathf.Deg2Rad), Mathf.Sin (fAngle * Mathf.Deg2Rad), 0);
    333.                     child.localPosition = vPos * radius;
    334.                     //Force objects to be center aligned, this can be changed however I'd suggest you keep all of the objects with the same anchor points.
    335.                     child.anchorMin = child.anchorMax = child.pivot = new Vector2 (0.5f, 0.5f);
    336.  
    337.                     float elementAngle = startElementAngle;
    338.                     if (rotateElements) {
    339.                         elementAngle += fAngle;
    340.                         child.localEulerAngles = new Vector3 (0f, 0f, elementAngle);
    341.                     } else {
    342.                         child.localEulerAngles = new Vector3 (0f, 0f, elementAngle);
    343.                     }
    344.  
    345.                     if (expandChilds) {
    346.                         Vector2 expandSize = child.sizeDelta;
    347.                         if (expandChildWidth) {
    348.                             expandSize.x = childWidthFromRadius ? (radius * childWidthRadiusFactor) * countWidthFactor * childWidthFactor : countWidthFactor * childWidthFactor;
    349.                         }
    350.                         if (expandChildHeight) {
    351.                             expandSize.y = childHeightFromRadius ? (radius * childHeightRadiusFactor) * childHeight : childHeight;
    352.                         }
    353.                         child.sizeDelta = expandSize;
    354.                     }
    355.  
    356.                     fAngle += fOffsetAngle;
    357.                 }
    358.  
    359.             }
    360.  
    361.         }
    362.  
    363.     }
    364.  
    365. }
    366.  
     
    Last edited: Sep 28, 2017
    Tbaumer2, Rahd, temresen and 5 others like this.
  22. bbproger

    bbproger

    Joined:
    Aug 30, 2014
    Posts:
    2
    Hi guys,

    @xlabrom , can you explain me how i can add dragging input from device? like scrolling
     
    JamesArndt likes this.
  23. PopeZandy

    PopeZandy

    Joined:
    May 10, 2018
    Posts:
    1
    Hey man, I was looking for something like this for a while! I tweaked it to have each item in the list look at the center point, and I have the panel rotate around the center, so now I've got an awesome rotating radial menu for item selection, which is exactly what I wanted. Thanks so much my friend.
     
  24. Tbaumer2

    Tbaumer2

    Joined:
    Mar 29, 2016
    Posts:
    17
    This might be the most helpful script I've ever found. THANK YOU (though it is a bit late :))