You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			426 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			426 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine;
 | 
						|
using UnityEditor;
 | 
						|
using System.IO;
 | 
						|
using System.Threading;
 | 
						|
using Autohand;
 | 
						|
 | 
						|
namespace AutoHand {
 | 
						|
    [InitializeOnLoad]
 | 
						|
    public class AutoHandSetupWizard : EditorWindow {
 | 
						|
        public Texture autohandlogo;
 | 
						|
 | 
						|
        static AutoHandSetupWizard window;
 | 
						|
        static string[] requiredLayerNames = { "Grabbing", "Grabbable", "Hand", "HandPlayer" };
 | 
						|
        static string assetPath;
 | 
						|
 | 
						|
 | 
						|
        public static float quality = 2;
 | 
						|
 | 
						|
        static AutoHandSettings _handSettings = null;
 | 
						|
        static AutoHandSettings handSettings {
 | 
						|
            get {
 | 
						|
                if(_handSettings == null)
 | 
						|
                    _handSettings = Resources.Load<AutoHandSettings>("AutoHandSettings");
 | 
						|
                return _handSettings;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        static AutoHandSetupWizard() {
 | 
						|
            EditorApplication.update += Start;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        static void Start() {
 | 
						|
            SetRequiredSettings();
 | 
						|
 | 
						|
            if(ShowSetupWindow()) {
 | 
						|
                OpenWindow();
 | 
						|
                Application.OpenURL("https://earnest-robot.gitbook.io/auto-hand-docs/");
 | 
						|
                assetPath = Application.dataPath;
 | 
						|
            }
 | 
						|
 | 
						|
            EditorApplication.update -= Start;
 | 
						|
        }
 | 
						|
 | 
						|
        [MenuItem("Window/Autohand/Setup Window")]
 | 
						|
        public static void OpenWindow() {
 | 
						|
            window = GetWindow<AutoHandSetupWizard>(true);
 | 
						|
            window.minSize = new Vector2(320, 440);
 | 
						|
            window.maxSize = new Vector2(360, 500);
 | 
						|
            window.titleContent = new GUIContent("Auto Hand Setup");
 | 
						|
            SetRequiredSettings();
 | 
						|
        }
 | 
						|
 | 
						|
        void OnDestroy() {
 | 
						|
            SetRequiredSettings();
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        public void OnGUI() {
 | 
						|
 | 
						|
            if(autohandlogo == null) {
 | 
						|
                var assets = AssetDatabase.FindAssets("AutohandLogo");
 | 
						|
                if(assets.Length > 0)
 | 
						|
                    autohandlogo = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath(assets[0]));
 | 
						|
            }
 | 
						|
 | 
						|
            var rect = EditorGUILayout.GetControlRect();
 | 
						|
            rect.height *= 5;
 | 
						|
            GUI.Label(rect, autohandlogo, AutoHandExtensions.LabelStyle(TextAnchor.MiddleCenter, FontStyle.Normal, 25));
 | 
						|
            rect = EditorGUILayout.GetControlRect();
 | 
						|
            rect = EditorGUILayout.GetControlRect();
 | 
						|
            rect = EditorGUILayout.GetControlRect();
 | 
						|
 | 
						|
            GUILayout.Space(12f);
 | 
						|
            GUI.Label(qualityLabelRect, "AUTO HAND SETUP", AutoHandExtensions.LabelStyle(TextAnchor.MiddleCenter, FontStyle.Normal, 25));
 | 
						|
            GUILayout.Space(12f);
 | 
						|
 | 
						|
            GUI.Label(qualityLabelRect, "RECOMMENDED PHYSICS SETTINGS", AutoHandExtensions.LabelStyle(TextAnchor.MiddleCenter, FontStyle.Normal, 19));
 | 
						|
            GUILayout.Space(24f);
 | 
						|
 | 
						|
            GUI.Label(qualityLabelRect, "Physics Quality", AutoHandExtensions.LabelStyle(TextAnchor.MiddleCenter, FontStyle.Normal, 16));
 | 
						|
            GUILayout.Space(5f);
 | 
						|
 | 
						|
            quality = GUI.HorizontalSlider(qualitySliderRect, quality, -1, 3);
 | 
						|
            quality = Mathf.Round(quality);
 | 
						|
 | 
						|
            GUI.Label(qualityLabelRect, QualityGUIContent(quality), AutoHandExtensions.LabelStyle(QualityColor(quality), TextAnchor.MiddleCenter));
 | 
						|
 | 
						|
 | 
						|
            ShowQualitySettings(quality);
 | 
						|
 | 
						|
 | 
						|
            GUILayout.Space(30f);
 | 
						|
            if(GUI.Button(qualitySliderRect, "Apply")) {
 | 
						|
                handSettings.quality = quality;
 | 
						|
                SetPhysicsSettings(handSettings.quality);
 | 
						|
                EditorUtility.SetDirty(handSettings); 
 | 
						|
                var physicsManager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/DynamicsManager.asset")[0];
 | 
						|
                if(physicsManager != null) {
 | 
						|
                    EditorUtility.SetDirty(physicsManager);
 | 
						|
                }
 | 
						|
                this.Close();
 | 
						|
            }
 | 
						|
 | 
						|
            ShowDoNotShowButton();
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        public void ShowQualitySettings(float quality) {
 | 
						|
 | 
						|
            GUILayout.Space(15);
 | 
						|
            var labelStyle = AutoHandExtensions.LabelStyle(new Color(0.7f, 0.7f, 0.7f, 1f));
 | 
						|
            var labelStyleB = AutoHandExtensions.LabelStyleB(new Color(0.7f, 0.7f, 0.7f, 1f));
 | 
						|
 | 
						|
            handSettings.useAutomaticControllerOffset = GUI.Toggle(qualitySliderRect, handSettings.useAutomaticControllerOffset, "Automatic Controller Offset", labelStyleB);
 | 
						|
            handSettings.usingDynamicTimestep = GUI.Toggle(qualitySliderRect, handSettings.usingDynamicTimestep, "Dynamic Timestep", labelStyleB);
 | 
						|
 | 
						|
            if(quality <= -1) {
 | 
						|
                GUI.Label(qualitySliderRect, "Ignore Recommended Settings", labelStyle);
 | 
						|
            }
 | 
						|
            else if(quality <= 0) {
 | 
						|
                if(!handSettings.usingDynamicTimestep)
 | 
						|
                    GUI.Label(qualitySliderRect, "Fixed Timestep: 1/50", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Contact Offset: 0.01", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Iterations: 10", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Velocity Iterations: 5", labelStyle);
 | 
						|
            }
 | 
						|
            else if(quality <= 1) {
 | 
						|
                if(!handSettings.usingDynamicTimestep)
 | 
						|
                    GUI.Label(qualitySliderRect, "Fixed Timestep: 1/60", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Contact Offset: 0.01", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Iterations: 10", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Velocity Iterations: 5", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Enable Adaptive Force: true", labelStyle);
 | 
						|
            }
 | 
						|
            else if(quality <= 2) {
 | 
						|
                if(!handSettings.usingDynamicTimestep)
 | 
						|
                    GUI.Label(qualitySliderRect, "Fixed Timestep: 1/72", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Contact Offset: 0.005", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Iterations: 20", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Velocity Iterations: 10", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Enable Adaptive Force: true", labelStyle);
 | 
						|
            }
 | 
						|
            else if(quality <= 3) {
 | 
						|
                if(!handSettings.usingDynamicTimestep)
 | 
						|
                    GUI.Label(qualitySliderRect, "Fixed Timestep: 1/90", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Contact Offset: 0.0035", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Iterations: 50", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Solver Velocity Iterations: 50", labelStyle);
 | 
						|
                GUI.Label(qualitySliderRect, "Enable Adaptive Force: true", labelStyle);
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        public static void SetPhysicsSettings(float quality) {
 | 
						|
 | 
						|
            if(quality <= 0) {
 | 
						|
                Time.fixedDeltaTime = 1 / 50f;
 | 
						|
                Physics.defaultContactOffset = 0.01f;
 | 
						|
                Physics.defaultSolverIterations = 10;
 | 
						|
                Physics.defaultSolverVelocityIterations = 5;
 | 
						|
                Physics.defaultMaxAngularSpeed = 35f;
 | 
						|
 | 
						|
            }
 | 
						|
            else if(quality <= 1) {
 | 
						|
                EnableAdaptiveForce();
 | 
						|
                Time.fixedDeltaTime = 1 / 60f;
 | 
						|
                Physics.defaultContactOffset = 0.0075f;
 | 
						|
                Physics.defaultSolverIterations = 10;
 | 
						|
                Physics.defaultSolverVelocityIterations = 5;
 | 
						|
                Physics.defaultMaxAngularSpeed = 35f;
 | 
						|
            }
 | 
						|
            else if(quality <= 2) {
 | 
						|
                EnableAdaptiveForce();
 | 
						|
                Time.fixedDeltaTime = 1 / 72f;
 | 
						|
                Physics.defaultContactOffset = 0.005f;
 | 
						|
                Physics.defaultSolverIterations = 20;
 | 
						|
                Physics.defaultSolverVelocityIterations = 10;
 | 
						|
                Physics.defaultMaxAngularSpeed = 35f;
 | 
						|
            }
 | 
						|
            else if(quality <= 3) {
 | 
						|
                EnableAdaptiveForce();
 | 
						|
                Time.fixedDeltaTime = 1 / 90f;
 | 
						|
                Physics.defaultContactOffset = 0.0035f;
 | 
						|
                Physics.defaultSolverIterations = 30;
 | 
						|
                Physics.defaultSolverVelocityIterations = 20;
 | 
						|
                Physics.defaultMaxAngularSpeed = 35f;
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public static void SetRequiredSettings() {
 | 
						|
            if(!LayersExist()) {
 | 
						|
                GenerateAutoHandLayers();
 | 
						|
                UpdateRequiredCollisionLayers();
 | 
						|
            }
 | 
						|
            if(!IsIgnoreCollisionSet()) {
 | 
						|
                UpdateRequiredCollisionLayers();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void ShowDoNotShowButton() {
 | 
						|
            var GUIColor = GUI.backgroundColor;
 | 
						|
            GUI.backgroundColor = new Color(0.7f, 0.4f, 0.4f);
 | 
						|
            GUILayout.Space(30f);
 | 
						|
            var buttonRect = new Rect(qualitySliderRect);
 | 
						|
            buttonRect.width /= 1.5f;
 | 
						|
            buttonRect.height /= 1f;
 | 
						|
            buttonRect.x += buttonRect.width / 4f;
 | 
						|
            if(GUI.Button(buttonRect, "Dont Show Again")) {
 | 
						|
                EditorUtility.SetDirty(handSettings);
 | 
						|
                handSettings.ignoreSetup = true;
 | 
						|
                this.Close();
 | 
						|
            }
 | 
						|
            GUI.backgroundColor = GUIColor;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        public Rect qualitySliderRect {
 | 
						|
            get {
 | 
						|
                var _qualitySlider = EditorGUILayout.GetControlRect();
 | 
						|
                _qualitySlider.x += _qualitySlider.width / 6f;
 | 
						|
                _qualitySlider.width *= 2 / 3f;
 | 
						|
                return _qualitySlider;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public Rect qualityLabelRect {
 | 
						|
            get {
 | 
						|
                var _qualitySlider = EditorGUILayout.GetControlRect();
 | 
						|
                _qualitySlider.height *= 1.5f;
 | 
						|
                return _qualitySlider;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public Color QualityColor(float quality) {
 | 
						|
            if(quality <= 0) {
 | 
						|
                return Color.red;
 | 
						|
            }
 | 
						|
            else if(quality <= 1) {
 | 
						|
                return Color.yellow;
 | 
						|
            }
 | 
						|
            else if(quality <= 2) {
 | 
						|
                return Color.green;
 | 
						|
            }
 | 
						|
            else if(quality <= 3) {
 | 
						|
                return Color.magenta;
 | 
						|
            }
 | 
						|
 | 
						|
            return Color.white;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        public GUIContent QualityGUIContent(float quality) {
 | 
						|
            var content = new GUIContent();
 | 
						|
            if(quality <= -1)
 | 
						|
                content.text += "IGNORE RECOMMENDED SETTINGS";
 | 
						|
            else if(quality <= 0)
 | 
						|
                content.text += "LOW (Not Recommended)";
 | 
						|
            else if(quality <= 1)
 | 
						|
                content.text += "MEDIUM";
 | 
						|
            else if(quality <= 2)
 | 
						|
                content.text += "HIGH (Quest Recommended)";
 | 
						|
            else if(quality <= 3)
 | 
						|
                content.text += "VERY HIGH";
 | 
						|
 | 
						|
            return content;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        static bool ShowSetupWindow() {
 | 
						|
            return handSettings.quality == -1 && !handSettings.ignoreSetup || !AutoHandSetupWizard.LayersExist();
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        static void GenerateAutoHandLayers() {
 | 
						|
            CreateLayers();
 | 
						|
            AssetDatabase.Refresh();
 | 
						|
#if UNITY_2020
 | 
						|
#if !UNITY_2020_1
 | 
						|
        AssetDatabase.RefreshSettings();
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        public static void CreateLayers() {
 | 
						|
            foreach(var layer in requiredLayerNames) {
 | 
						|
                CreateLayer(layer);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public static bool LayersExist() {
 | 
						|
            bool success = true;
 | 
						|
            Dictionary<string, int> existingLayers = GetAllLayers();
 | 
						|
            foreach(var layer in requiredLayerNames) {
 | 
						|
                if(!existingLayers.ContainsKey(layer)) {
 | 
						|
                    success = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return success;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        static void CreateLayer(string name) {
 | 
						|
            bool success = false;
 | 
						|
            Dictionary<string, int> existingLayers = GetAllLayers();
 | 
						|
 | 
						|
            if(!existingLayers.ContainsKey(name)) {
 | 
						|
                SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
 | 
						|
                SerializedProperty layers = tagManager.FindProperty("layers");
 | 
						|
 | 
						|
                for(int i = 0; i < 31; i++) {
 | 
						|
                    SerializedProperty element = layers.GetArrayElementAtIndex(i);
 | 
						|
                    if(string.IsNullOrEmpty(element.stringValue) && i >= 6) {
 | 
						|
                        element.stringValue = name;
 | 
						|
 | 
						|
                        tagManager.ApplyModifiedProperties();
 | 
						|
                        success = true;
 | 
						|
                        Debug.Log(i.ToString() + " layer created: " + name);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if(!success) {
 | 
						|
                    Debug.Log("Could not create required layer, you likely do not have enough empty layers. Please delete some unused physics layers and reload the Auto Hand Setup Wizard in Window/AutoHand/Setup");
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public static Dictionary<string, int> GetAllLayers() {
 | 
						|
            Dictionary<string, int> layerDictionary = new Dictionary<string, int>();
 | 
						|
            SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
 | 
						|
            SerializedProperty layers = tagManager.FindProperty("layers");
 | 
						|
            int layerSize = layers.arraySize;
 | 
						|
 | 
						|
            for(int i = 0; i < layerSize; i++) {
 | 
						|
                SerializedProperty element = layers.GetArrayElementAtIndex(i);
 | 
						|
                string layerName = element.stringValue;
 | 
						|
 | 
						|
                if(!string.IsNullOrEmpty(layerName)) {
 | 
						|
                    layerDictionary.Add(layerName, i);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return layerDictionary;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        static void EnableAdaptiveForce() {
 | 
						|
            assetPath = Application.dataPath;
 | 
						|
            var path = assetPath.Substring(0, assetPath.Length - 6);
 | 
						|
            path += "ProjectSettings/DynamicsManager.asset";
 | 
						|
 | 
						|
            List<string> layerNames = new List<string>();
 | 
						|
            for(int i = 0; i < requiredLayerNames.Length; i++) {
 | 
						|
                layerNames.Add(requiredLayerNames[i]);
 | 
						|
            }
 | 
						|
 | 
						|
            StreamReader reader = new StreamReader(path);
 | 
						|
            string line = reader.ReadLine();
 | 
						|
            string[] lines = File.ReadAllLines(path);
 | 
						|
 | 
						|
            int lineIndex = 0;
 | 
						|
            List<int> lineTargetList = new List<int>();
 | 
						|
 | 
						|
            while((line = reader.ReadLine()) != null) {
 | 
						|
                if(line.Contains("m_EnableAdaptiveForce"))
 | 
						|
                    lineTargetList.Add(lineIndex);
 | 
						|
                lineIndex++;
 | 
						|
            }
 | 
						|
            reader.Close();
 | 
						|
 | 
						|
 | 
						|
            StreamWriter writer = new StreamWriter(path);
 | 
						|
            lineIndex = 0;
 | 
						|
            for(lineIndex = 0; lineIndex < lines.Length; lineIndex++) {
 | 
						|
                bool found = false;
 | 
						|
                if(lineIndex == lineTargetList[0] + 1) {
 | 
						|
                    writer.WriteLine("  m_EnableAdaptiveForce: 1");
 | 
						|
                    found = true;
 | 
						|
                }
 | 
						|
                if(!found)
 | 
						|
                    writer.WriteLine(lines[lineIndex]);
 | 
						|
 | 
						|
            }
 | 
						|
            writer.Close();
 | 
						|
            AssetDatabase.Refresh();
 | 
						|
#if UNITY_2020
 | 
						|
#if !UNITY_2020_1
 | 
						|
        AssetDatabase.RefreshSettings();
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
        }
 | 
						|
 | 
						|
        static void UpdateRequiredCollisionLayers() {
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Hand"), LayerMask.NameToLayer("Hand"), true);
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Hand"), LayerMask.NameToLayer("Grabbing"), true);
 | 
						|
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Grabbable"), true);
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Grabbing"), true);
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Hand"), true);
 | 
						|
            Physics.IgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("HandPlayer"), true);
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        public static bool IsIgnoreCollisionSet() {
 | 
						|
            return LayersExist() &&
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("Hand"), LayerMask.NameToLayer("Hand")) &&
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("Hand"), LayerMask.NameToLayer("Grabbing")) &&
 | 
						|
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Grabbable")) &&
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Grabbing")) &&
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("Hand")) &&
 | 
						|
            Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("HandPlayer"), LayerMask.NameToLayer("HandPlayer"));
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
} |