diff options
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor')
14 files changed, 908 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs new file mode 100644 index 0000000..b7f2cb1 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs @@ -0,0 +1,66 @@ +// Disable the warning: "Field 'DependencyCheck.Dependency.name' is never assigned to, and will always have its default value null" +#pragma warning disable 649 +using UnityEditor; +using System.Linq; +using UnityEngine; + +namespace Pathfinding.Util { + [InitializeOnLoad] + static class DependencyCheck { + struct Dependency { + public string name; + public string version; + } + + static DependencyCheck() { + var missingDependencies = new Dependency[] { +#if !MODULE_BURST + new Dependency { + name = "com.unity.burst", + version = "1.8.3", + }, +#endif +#if !MODULE_MATHEMATICS + new Dependency { + name = "com.unity.mathematics", + version = "1.2.6", + }, +#endif +#if !MODULE_COLLECTIONS + new Dependency { + name = "com.unity.collections", + version = "1.5.1", + }, +#endif + // #if !MODULE_ENTITIES + // new Dependency { + // name = "com.unity.entities", + // version = "1.0.0-pre.47", + // }, + // #endif + }; + + if (missingDependencies.Length > 0) { + string missing = string.Join(", ", missingDependencies.Select(p => p.name + " (" + p.version + ")")); + bool res = EditorUtility.DisplayDialog("Missing dependencies", "The packages " + missing + " are required by the A* Pathfinding Project but they are not installed, or the installed versions are too old. Do you want to install the latest versions of the packages?", "Ok", "Cancel"); + if (res) { + foreach (var dep in missingDependencies) { + UnityEditor.PackageManager.Client.Add(dep.name); + } + } + } + + // E.g. 2023.3.0b8 + var v = Application.unityVersion.Split('.'); + UnityEngine.Assertions.Assert.IsTrue(v.Length >= 3, "Unity version string is not in the expected format"); + var major = int.Parse(v[0]); + var minor = int.Parse(v[1]); + // Filter out non-digits from v[2] + v[2] = new string(v[2].TakeWhile(char.IsDigit).ToArray()); + var patch = int.Parse(v[2]); + if (major == 2022 && minor == 3 && patch < 21) { + Debug.LogError("This version of Unity has a bug which causes components in the A* Pathfinding Project to randomly stop working. Please update to unity 2022.3.21 or later."); + } + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs.meta new file mode 100644 index 0000000..4aa5da4 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/DependencyCheck.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13cd4e1cd3bf242b3a58eb62092ce599 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs new file mode 100644 index 0000000..19efef1 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs @@ -0,0 +1,300 @@ +using UnityEditor; +using UnityEngine; +using System.Collections.Generic; +using System.Linq; + +namespace Pathfinding { + /// <summary>Helper for creating editors</summary> + [CustomEditor(typeof(VersionedMonoBehaviour), true)] + [CanEditMultipleObjects] + public class EditorBase : Editor { + static System.Collections.Generic.Dictionary<string, string> cachedTooltips; + static System.Collections.Generic.Dictionary<string, string> cachedURLs; + Dictionary<string, SerializedProperty> props = new Dictionary<string, SerializedProperty>(); + + static GUIContent content = new GUIContent(); + static GUIContent showInDocContent = new GUIContent("Show in online documentation", ""); + static GUILayoutOption[] noOptions = new GUILayoutOption[0]; + public static System.Func<string> getDocumentationURL; + + protected HashSet<string> remainingUnhandledProperties; + + + static void LoadMeta () { + if (cachedTooltips == null) { + var filePath = EditorResourceHelper.editorAssets + "/tooltips.tsv"; + + try { + var lines = System.IO.File.ReadAllLines(filePath).Select(l => l.Split('\t', 3)).Where(l => l.Length == 3).ToArray(); + cachedURLs = lines.ToDictionary(l => l[0], l => l[1]); + cachedTooltips = lines.ToDictionary(l => l[0], l => l[2].Replace("\\n", "\n")); + } catch (System.Exception e) { + Debug.LogWarning("Could not load tooltips from " + filePath + "\n" + e); + cachedURLs = new System.Collections.Generic.Dictionary<string, string>(); + cachedTooltips = new System.Collections.Generic.Dictionary<string, string>(); + } + } + } + + + static string LookupPath (System.Type type, string path, Dictionary<string, string> lookupData) { + // Find the correct type if the path was not an immediate member of #type + while (true) { + var index = path.IndexOf('.'); + if (index == -1) break; + var fieldName = path.Substring(0, index); + var remaining = path.Substring(index + 1); + var field = type.GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); + if (field != null) { + type = field.FieldType; + path = remaining; + } else { + // Could not find the correct field + return null; + } + } + + // Find a documentation entry for the field, fall back to parent classes if necessary + while (type != null) { + if (lookupData.TryGetValue(type.FullName + "." + path, out var value)) { + return value; + } + type = type.BaseType; + } + return null; + } + + string FindTooltip (string path) { + LoadMeta(); + return LookupPath(target.GetType(), path, cachedTooltips); + } + + protected virtual void OnEnable () { + foreach (var target in targets) if (target != null) (target as IVersionedMonoBehaviourInternal).UpgradeFromUnityThread(); + EditorApplication.contextualPropertyMenu += OnContextMenu; + } + + protected virtual void OnDisable () { + EditorApplication.contextualPropertyMenu -= OnContextMenu; + } + + void OnContextMenu (GenericMenu menu, SerializedProperty property) { + if (property.serializedObject != this.serializedObject) return; + + LoadMeta(); + var url = LookupPath(target.GetType(), property.propertyPath, cachedURLs); + + if (url != null && getDocumentationURL != null) { + menu.AddItem(showInDocContent, false, () => Application.OpenURL(getDocumentationURL() + url)); + } + } + + public sealed override void OnInspectorGUI () { + EditorGUI.indentLevel = 0; + serializedObject.Update(); + try { + Inspector(); + InspectorForRemainingAttributes(false, true); + } catch (System.Exception e) { + // This exception type should never be caught. See https://docs.unity3d.com/ScriptReference/ExitGUIException.html + if (e is ExitGUIException) throw e; + Debug.LogException(e, target); + } + serializedObject.ApplyModifiedProperties(); + if (targets.Length == 1 && (target as MonoBehaviour).enabled) { + var attr = target.GetType().GetCustomAttributes(typeof(UniqueComponentAttribute), true); + for (int i = 0; i < attr.Length; i++) { + string tag = (attr[i] as UniqueComponentAttribute).tag; + foreach (var other in (target as MonoBehaviour).GetComponents<MonoBehaviour>()) { + // Note: other can be null if some scripts are missing references + if (other == null || !other.enabled || other == target) continue; + if (other.GetType().GetCustomAttributes(typeof(UniqueComponentAttribute), true).Where(c => (c as UniqueComponentAttribute).tag == tag).Any()) { + EditorGUILayout.HelpBox("This component and " + other.GetType().Name + " cannot be used at the same time", MessageType.Warning); + } + } + } + } + } + + + protected virtual void Inspector () { + InspectorForRemainingAttributes(true, false); + } + + /// <summary>Draws an inspector for all fields that are likely not handled by the editor script itself</summary> + protected virtual void InspectorForRemainingAttributes (bool showHandled, bool showUnhandled) { + if (remainingUnhandledProperties == null) { + remainingUnhandledProperties = new HashSet<string>(); + + var tp = serializedObject.targetObject.GetType(); + var handledAssemblies = new List<System.Reflection.Assembly>(); + + // Find all types for which we have a [CustomEditor(type)] attribute. + // Unity hides this field, so we have to use reflection to get it. + var customEditorAttrs = this.GetType().GetCustomAttributes(typeof(CustomEditor), true).Cast<CustomEditor>().ToArray(); + foreach (var attr in customEditorAttrs) { + var inspectedTypeField = attr.GetType().GetField("m_InspectedType", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var inspectedType = inspectedTypeField.GetValue(attr) as System.Type; + if (!handledAssemblies.Contains(inspectedType.Assembly)) { + handledAssemblies.Add(inspectedType.Assembly); + } + } + bool enterChildren = true; + for (var prop = serializedObject.GetIterator(); prop.NextVisible(enterChildren); enterChildren = false) { + var name = prop.propertyPath; + var field = tp.GetField(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (field == null) { + // Can happen for some built-in Unity fields. They are not important + continue; + } else { + var declaringType = field.DeclaringType; + var foundOtherAssembly = false; + var foundThisAssembly = false; + while (declaringType != null) { + if (handledAssemblies.Contains(declaringType.Assembly)) { + foundThisAssembly = true; + break; + } else { + foundOtherAssembly = true; + } + declaringType = declaringType.BaseType; + } + if (foundOtherAssembly && foundThisAssembly) { + // This is a field in a class in a different assembly, which inherits from a class in one of the handled assemblies. + // That probably means the editor script doesn't explicitly know about that field and we should show it anyway. + remainingUnhandledProperties.Add(prop.propertyPath); + } + } + } + } + + // Basically the same as DrawDefaultInspector, but with tooltips + bool enterChildren2 = true; + + for (var prop = serializedObject.GetIterator(); prop.NextVisible(enterChildren2); enterChildren2 = false) { + var handled = !remainingUnhandledProperties.Contains(prop.propertyPath); + if ((showHandled && handled) || (showUnhandled && !handled)) { + PropertyField(prop.propertyPath); + } + } + } + + protected SerializedProperty FindProperty (string name) { + if (!props.TryGetValue(name, out SerializedProperty res)) res = props[name] = serializedObject.FindProperty(name); + if (res == null) throw new System.ArgumentException(name); + return res; + } + + protected void Section (string label) { + EditorGUILayout.Separator(); + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + } + + protected bool SectionEnableable (string label, string enabledProperty) { + EditorGUILayout.Separator(); + var v = EditorGUILayout.ToggleLeft(label, FindProperty(enabledProperty).boolValue, EditorStyles.boldLabel); + FindProperty(enabledProperty).boolValue = v; + return v; + } + + /// <summary>Bounds field using center/size instead of center/extent</summary> + protected void BoundsField (string propertyPath) { + PropertyField(propertyPath + ".m_Center", "Center"); + var extentsProp = FindProperty(propertyPath + ".m_Extent"); + var r = EditorGUILayout.GetControlRect(); + var label = EditorGUI.BeginProperty(r, new GUIContent("Size"), extentsProp); + extentsProp.vector3Value = 0.5f * EditorGUI.Vector3Field(r, label, extentsProp.vector3Value * 2.0f); + EditorGUI.EndProperty(); + } + + protected void FloatField (string propertyPath, string label = null, string tooltip = null, float min = float.NegativeInfinity, float max = float.PositiveInfinity) { + PropertyField(propertyPath, label, tooltip); + Clamp(propertyPath, min, max); + } + + protected void FloatField (SerializedProperty prop, string label = null, string tooltip = null, float min = float.NegativeInfinity, float max = float.PositiveInfinity) { + PropertyField(prop, label, tooltip); + Clamp(prop, min, max); + } + + protected bool PropertyField (string propertyPath, string label = null, string tooltip = null) { + return PropertyField(FindProperty(propertyPath), label, tooltip, propertyPath); + } + + protected bool PropertyField (SerializedProperty prop, string label = null, string tooltip = null) { + return PropertyField(prop, label, tooltip, prop.propertyPath); + } + + bool PropertyField (SerializedProperty prop, string label, string tooltip, string propertyPath) { + content.text = label ?? prop.displayName; + content.tooltip = tooltip ?? FindTooltip(propertyPath); + EditorGUILayout.PropertyField(prop, content, true, noOptions); + return prop.propertyType == SerializedPropertyType.Boolean ? !prop.hasMultipleDifferentValues && prop.boolValue : true; + } + + protected void Popup (string propertyPath, GUIContent[] options, string label = null) { + var prop = FindProperty(propertyPath); + + content.text = label ?? prop.displayName; + content.tooltip = FindTooltip(propertyPath); + EditorGUI.BeginChangeCheck(); + var r = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, EditorStyles.popup); + r = EditorGUI.PrefixLabel(r, EditorGUI.BeginProperty(r, content, prop)); + var tmpIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + int newVal = EditorGUI.Popup(r, prop.propertyType == SerializedPropertyType.Enum ? prop.enumValueIndex : prop.intValue, options); + EditorGUI.indentLevel = tmpIndent; + if (EditorGUI.EndChangeCheck()) { + if (prop.propertyType == SerializedPropertyType.Enum) prop.enumValueIndex = newVal; + else prop.intValue = newVal; + } + EditorGUI.EndProperty(); + } + + protected void IntSlider (string propertyPath, int left, int right) { + var prop = FindProperty(propertyPath); + + content.text = prop.displayName; + content.tooltip = FindTooltip(propertyPath); + EditorGUILayout.IntSlider(prop, left, right, content, noOptions); + } + + protected void Slider (string propertyPath, float left, float right) { + var prop = FindProperty(propertyPath); + + content.text = prop.displayName; + content.tooltip = FindTooltip(propertyPath); + EditorGUILayout.Slider(prop, left, right, content, noOptions); + } + + protected bool ByteAsToggle (string propertyPath, string label) { + var prop = FindProperty(propertyPath); + + content.text = label; + content.tooltip = FindTooltip(propertyPath); + EditorGUI.BeginChangeCheck(); + var r = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, EditorStyles.popup); + r = EditorGUI.PrefixLabel(r, EditorGUI.BeginProperty(r, content, prop)); + var tmpIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + prop.intValue = EditorGUI.Toggle(r, prop.intValue != 0) ? 1 : 0; + EditorGUI.indentLevel = tmpIndent; + EditorGUI.EndProperty(); + return prop.intValue != 0; + } + + protected void Clamp (SerializedProperty prop, float min, float max = float.PositiveInfinity) { + if (!prop.hasMultipleDifferentValues) prop.floatValue = Mathf.Clamp(prop.floatValue, min, max); + } + + protected void Clamp (string name, float min, float max = float.PositiveInfinity) { + Clamp(FindProperty(name), min, max); + } + + protected void ClampInt (string name, int min, int max = int.MaxValue) { + var prop = FindProperty(name); + + if (!prop.hasMultipleDifferentValues) prop.intValue = Mathf.Clamp(prop.intValue, min, max); + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs.meta new file mode 100644 index 0000000..fe26580 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 58753931a68ae48b3973d0ce32d1a760 +timeCreated: 1495461526 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs new file mode 100644 index 0000000..3a0a3f0 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs @@ -0,0 +1,198 @@ +using UnityEngine; +using System.Collections.Generic; +using UnityEditor; + +namespace Pathfinding { + /// <summary>Simple GUI utility functions</summary> + public static class GUIUtilityx { + static Stack<Color> colors = new Stack<Color>(); + + public static void PushTint (Color tint) { + colors.Push(GUI.color); + GUI.color *= tint; + } + + public static void PopTint () { + GUI.color = colors.Pop(); + } + + public static Rect SliceRow (ref Rect rect, float height) { + var r = new Rect(rect.x, rect.y, rect.width, height); + rect.yMin += height + EditorGUIUtility.standardVerticalSpacing; + return r; + } + + public static Rect SliceColumn (ref Rect rect, float width, float spacing = 0) { + var r = new Rect(rect.x, rect.y, width, rect.height); + rect.xMin += width + spacing; + return r; + } + } + + /// <summary> + /// Editor helper for hiding and showing a group of GUI elements. + /// Call order in OnInspectorGUI should be: + /// - Begin + /// - Header/HeaderLabel (optional) + /// - BeginFade + /// - [your gui elements] (if BeginFade returns true) + /// - End + /// </summary> + public class FadeArea { + Rect lastRect; + float value; + float lastUpdate; + GUIStyle labelStyle; + GUIStyle areaStyle; + bool visible; + Editor editor; + + /// <summary> + /// Is this area open. + /// This is not the same as if any contents are visible, use <see cref="BeginFade"/> for that. + /// </summary> + public bool open; + + /// <summary>Animate dropdowns when they open and close</summary> + public static bool fancyEffects; + const float animationSpeed = 100f; + + public FadeArea (bool open, Editor editor, GUIStyle areaStyle, GUIStyle labelStyle = null) { + this.areaStyle = areaStyle; + this.labelStyle = labelStyle; + this.editor = editor; + visible = this.open = open; + value = open ? 1 : 0; + } + + void Tick () { + if (Event.current.type == EventType.Repaint) { + float deltaTime = Time.realtimeSinceStartup-lastUpdate; + + // Right at the start of a transition the deltaTime will + // not be reliable, so use a very small value instead + // until the next repaint + if (value == 0f || value == 1f) deltaTime = 0.001f; + deltaTime = Mathf.Clamp(deltaTime, 0.00001F, 0.1F); + + // Larger regions fade slightly slower + deltaTime /= Mathf.Sqrt(Mathf.Max(lastRect.height, 100)); + + lastUpdate = Time.realtimeSinceStartup; + + + float targetValue = open ? 1F : 0F; + if (!Mathf.Approximately(targetValue, value)) { + value += deltaTime*animationSpeed*Mathf.Sign(targetValue-value); + value = Mathf.Clamp01(value); + editor.Repaint(); + + if (!fancyEffects) { + value = targetValue; + } + } else { + value = targetValue; + } + } + } + + public void Begin () { + if (areaStyle != null) { + lastRect = EditorGUILayout.BeginVertical(areaStyle); + } else { + lastRect = EditorGUILayout.BeginVertical(); + } + } + + public void HeaderLabel (string label) { + GUILayout.Label(label, labelStyle); + } + + public void Header (string label) { + Header(label, ref open); + } + + public void Header (string label, ref bool open) { + if (GUILayout.Button(label, labelStyle)) { + open = !open; + editor.Repaint(); + } + this.open = open; + } + + /// <summary>Hermite spline interpolation</summary> + static float Hermite (float start, float end, float value) { + return Mathf.Lerp(start, end, value * value * (3.0f - 2.0f * value)); + } + + public bool BeginFade () { + var hermite = Hermite(0, 1, value); + + visible = EditorGUILayout.BeginFadeGroup(hermite); + GUIUtilityx.PushTint(new Color(1, 1, 1, hermite)); + Tick(); + + // Another vertical group is necessary to work around + // a kink of the BeginFadeGroup implementation which + // causes the padding to change when value!=0 && value!=1 + EditorGUILayout.BeginVertical(); + + return visible; + } + + public void End () { + EditorGUILayout.EndVertical(); + + if (visible) { + // Some space that cannot be placed in the GUIStyle unfortunately + GUILayout.Space(4); + } + + EditorGUILayout.EndFadeGroup(); + EditorGUILayout.EndVertical(); + GUIUtilityx.PopTint(); + } + } + /// <summary>Handles fading effects and also some custom GUI functions such as LayerMaskField</summary> + public static class EditorGUILayoutx { + static Dictionary<int, string[]> layerNames = new Dictionary<int, string[]>(); + static long lastUpdateTick; + static List<string> dummyList = new List<string>(); + + /// <summary>Displays a LayerMask field.</summary> + /// <param name="label">Label to display</param> + /// <param name="selected">Current LayerMask</param> + public static LayerMask LayerMaskField (string label, LayerMask selected) { + if (Event.current.type == EventType.Layout && System.DateTime.UtcNow.Ticks - lastUpdateTick > 10000000L) { + layerNames.Clear(); + lastUpdateTick = System.DateTime.UtcNow.Ticks; + } + + string[] currentLayerNames; + if (!layerNames.TryGetValue(selected.value, out currentLayerNames)) { + var layers = dummyList; + layers.Clear(); + + int emptyLayers = 0; + for (int i = 0; i < 32; i++) { + string layerName = LayerMask.LayerToName(i); + + if (layerName != "") { + for (; emptyLayers > 0; emptyLayers--) layers.Add("Layer "+(i-emptyLayers)); + layers.Add(layerName); + } else { + emptyLayers++; + if (((selected.value >> i) & 1) != 0 && selected.value != -1) { + for (; emptyLayers > 0; emptyLayers--) layers.Add("Layer "+(i+1-emptyLayers)); + } + } + } + + currentLayerNames = layerNames[selected.value] = layers.ToArray(); + } + + selected.value = EditorGUILayout.MaskField(label, selected.value, currentLayerNames); + return selected; + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs.meta new file mode 100644 index 0000000..c27c695 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EditorGUIx.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2b6b4977544da4af3a4fe9e895fb6888 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs new file mode 100644 index 0000000..8e14970 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs @@ -0,0 +1,39 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace Pathfinding { + [CustomPropertyDrawer(typeof(EnumFlagAttribute))] + public class EnumFlagDrawer : PropertyDrawer { + public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) { + Enum targetEnum = GetBaseProperty<Enum>(property); + + EditorGUI.BeginProperty(position, label, property); + EditorGUI.BeginChangeCheck(); +#if UNITY_2017_3_OR_NEWER + Enum enumNew = EditorGUI.EnumFlagsField(position, label, targetEnum); +#else + Enum enumNew = EditorGUI.EnumMaskField(position, label, targetEnum); +#endif + if (EditorGUI.EndChangeCheck() || !property.hasMultipleDifferentValues) { + property.intValue = (int)Convert.ChangeType(enumNew, targetEnum.GetType()); + } + EditorGUI.EndProperty(); + } + + static T GetBaseProperty<T>(SerializedProperty prop) { + // Separate the steps it takes to get to this property + string[] separatedPaths = prop.propertyPath.Split('.'); + + // Go down to the root of this serialized property + System.Object reflectionTarget = prop.serializedObject.targetObject as object; + // Walk down the path to get the target object + foreach (var path in separatedPaths) { + FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + reflectionTarget = fieldInfo.GetValue(reflectionTarget); + } + return (T)reflectionTarget; + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs.meta new file mode 100644 index 0000000..1d12a74 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/EnumFlagDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 616267fcc419f44ea929599afa5c6aa2 +timeCreated: 1500392257 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs new file mode 100644 index 0000000..45d2dab --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs @@ -0,0 +1,29 @@ +using UnityEngine; +using UnityEditor; +using System.Linq; + +namespace Pathfinding.Legacy { + public static class LegacyEditorHelper { + public static void UpgradeDialog (Object[] targets, System.Type upgradeType) { + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + var gui = EditorGUIUtility.IconContent("console.warnicon"); + gui.text = "You are using the compatibility version of this component. It is recommended that you upgrade to the newer version. This may change the component's behavior."; + EditorGUILayout.LabelField(GUIContent.none, gui, EditorStyles.wordWrappedMiniLabel); + if (GUILayout.Button("Upgrade")) { + Undo.RecordObjects(targets.Select(s => (s as Component).gameObject).ToArray(), "Upgrade from Legacy Component"); + foreach (var tg in targets) { + var comp = tg as Component; + var components = comp.gameObject.GetComponents<Component>(); + int index = System.Array.IndexOf(components, comp); + var newRVO = Undo.AddComponent(comp.gameObject, upgradeType); + foreach (var field in newRVO.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)) { + field.SetValue(newRVO, field.GetValue(comp)); + } + Undo.DestroyObjectImmediate(comp); + for (int i = components.Length - 1; i > index; i--) UnityEditorInternal.ComponentUtility.MoveComponentUp(newRVO); + } + } + EditorGUILayout.EndVertical(); + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs.meta new file mode 100644 index 0000000..99b9e67 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/LegacyEditorHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a97cec2d4f06c4d0eb0068c24cb47ca1 +timeCreated: 1490879139 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs new file mode 100644 index 0000000..e3f1666 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs @@ -0,0 +1,164 @@ +using UnityEngine; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; + +namespace Pathfinding { + /// <summary> + /// Helper for enabling or disabling compiler directives. + /// Used only in the editor. + /// </summary> + public static class OptimizationHandler { + public class DefineDefinition { + public string name; + public string description; + public bool enabled; + public bool consistent; + } + + /// <summary> + /// Various build targets that Unity have deprecated. + /// There is apparently no way to figure out which these are without hard coding them. + /// </summary> + static readonly BuildTargetGroup[] deprecatedBuildTargets = new BuildTargetGroup[] { + BuildTargetGroup.Unknown, +#if UNITY_5_4_OR_NEWER + (BuildTargetGroup)16, /* BlackBerry */ +#endif +#if UNITY_5_5_OR_NEWER + (BuildTargetGroup)5, /* PS3 */ + (BuildTargetGroup)6, /* XBox360 */ + (BuildTargetGroup)15, /* WP8 */ +#endif +#if UNITY_2017_4_OR_NEWER + (BuildTargetGroup)2, /* WebPlayer */ + (BuildTargetGroup)20, /* PSM */ +#endif +#if UNITY_2018_1_OR_NEWER + (BuildTargetGroup)22, /* SamsungTV */ + (BuildTargetGroup)24, /* WiiU */ +#endif +#if UNITY_2018_2_OR_NEWER + (BuildTargetGroup)17, /* Tizen */ +#endif +#if UNITY_2018_3_OR_NEWER + (BuildTargetGroup)18, /* PSP2 */ + (BuildTargetGroup)23, /* Nintendo3DS */ +#endif + }; + + static string GetPackageRootDirectory () { + var rootDir = EditorResourceHelper.editorAssets + "/../../"; + + return rootDir; + } + + static Dictionary<BuildTargetGroup, List<string> > GetDefineSymbols () { + var result = new Dictionary<BuildTargetGroup, List<string> >(); + + var nonDeprecatedBuildTypes = typeof(BuildTargetGroup) + .GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static) + .Where(fieldInfo => fieldInfo.GetCustomAttributes(typeof(System.ObsoleteAttribute), false).Length == 0) + .Select(fieldInfo => (BuildTargetGroup)fieldInfo.GetValue(null)).ToArray(); + + for (int i = 0; i < nonDeprecatedBuildTypes.Length; i++) { + // Kept for compatibility with older versions of Unity which did not always accurately add Obsolete attributes + // (in particular Unity 2017.4 seems to miss marking the PSM build target as obsolete, the other ones seem accurate) + if (deprecatedBuildTargets.Contains(nonDeprecatedBuildTypes[i])) continue; + +#if UNITY_2021_3_OR_NEWER + PlayerSettings.GetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(nonDeprecatedBuildTypes[i]), out var defines); +#else + string defineString = PlayerSettings.GetScriptingDefineSymbolsForGroup(nonDeprecatedBuildTypes[i]); + if (defineString == null) continue; + + var defines = defineString.Split(';').Select(s => s.Trim()); +#endif + result[nonDeprecatedBuildTypes[i]] = defines.ToList(); + } + return result; + } + + static void SetDefineSymbols (Dictionary<BuildTargetGroup, List<string> > symbols) { + foreach (var pair in symbols) { +#if UNITY_2021_3_OR_NEWER + string[] symbolsArr = pair.Value.Distinct().ToArray(); + PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(pair.Key), symbolsArr); +#else + var defineString = string.Join(";", pair.Value.Distinct().ToArray()); + PlayerSettings.SetScriptingDefineSymbolsForGroup(pair.Key, defineString); +#endif + } + } + + public static void EnableDefine (string name) { + name = name.Trim(); + var newSymbols = GetDefineSymbols().ToDictionary(pair => pair.Key, pair => { + pair.Value.Add(name); + return pair.Value; + }); + SetDefineSymbols(newSymbols); + } + + public static void DisableDefine (string name) { + name = name.Trim(); + var newSymbols = GetDefineSymbols().ToDictionary(pair => pair.Key, pair => { + pair.Value.Remove(name); + return pair.Value; + }); + SetDefineSymbols(newSymbols); + } + + public static void IsDefineEnabled (string name, out bool enabled, out bool consistent) { + name = name.Trim(); + int foundEnabled = 0; + int foundDisabled = 0; + + foreach (var pair in GetDefineSymbols()) { + if (pair.Value.Contains(name)) { + foundEnabled++; + } else { + foundDisabled++; + } + } + + enabled = foundEnabled > foundDisabled; + consistent = (foundEnabled > 0) != (foundDisabled > 0); + } + + public static List<DefineDefinition> FindDefines () { + var path = GetPackageRootDirectory()+"/defines.csv"; + + if (File.Exists(path)) { + // Read a file consisting of lines with the format + // NAME;Description + // Ignore empty lines and lines which do not contain exactly 1 ';' + var definePairs = File.ReadAllLines(path) + .Select(line => line.Trim()) + .Where(line => line.Length > 0) + .Select(line => line.Split(';')) + .Where(opts => opts.Length == 2); + + return definePairs.Select(opts => { + var def = new DefineDefinition { name = opts[0].Trim(), description = opts[1].Trim() }; + IsDefineEnabled(def.name, out def.enabled, out def.consistent); + return def; + }).ToList(); + } + + Debug.LogError("Could not find file '"+path+"'"); + return new List<DefineDefinition>(); + } + + public static void ApplyDefines (List<DefineDefinition> defines) { + foreach (var define in defines) { + if (define.enabled) { + EnableDefine(define.name); + } else { + DisableDefine(define.name); + } + } + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs.meta new file mode 100644 index 0000000..6ece61e --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/OptimizationHandler.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ec7eea22fd1c74193aa7d047949503e7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef new file mode 100644 index 0000000..ded42ec --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef @@ -0,0 +1,44 @@ +{ + "name": "AstarPackageToolsEditor", + "rootNamespace": "", + "references": [ + "GUID:f4059aaf6c60a4a58a177a2609feb769" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.burst", + "expression": "1.8.3", + "define": "MODULE_BURST" + }, + { + "name": "com.unity.mathematics", + "expression": "1.2.6", + "define": "MODULE_MATHEMATICS" + }, + { + "name": "com.unity.collections", + "expression": "1.5.1", + "define": "MODULE_COLLECTIONS" + }, + { + "name": "com.unity.collections", + "expression": "0.11-preview", + "define": "MODULE_COLLECTIONS_0_11_OR_NEWER" + }, + { + "name": "com.unity.entities", + "expression": "1.0.0-pre.47", + "define": "MODULE_ENTITIES" + } + ], + "noEngineReferences": false +}
\ No newline at end of file diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef.meta new file mode 100644 index 0000000..6f9de39 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/PackageTools/Editor/PackageToolsEditor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 774e21169c4ac4ec8a01db9cdb98d33b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: |