├── .github ├── README.md └── images │ └── globalSettingInContextMenu.png ├── .gitignore ├── LICENSE.md ├── LICENSE.md.meta ├── Scripts.meta ├── Scripts ├── Editor.meta ├── Editor │ ├── AttachAttributesEditor.cs │ ├── AttachAttributesEditor.cs.meta │ ├── Nrjwolf.Tools.AttachAttributes.asmdef │ └── Nrjwolf.Tools.AttachAttributes.asmdef.meta ├── Runtime.meta └── Runtime │ ├── AttachAttributes.cs │ ├── AttachAttributes.cs.meta │ ├── Nrjwolf.Tools.AttachAttributes.asmdef │ └── Nrjwolf.Tools.AttachAttributes.asmdef.meta ├── package.json └── package.json.meta /.github/README.md: -------------------------------------------------------------------------------- 1 | # Unity auto attach component via attributes 2 | 3 | Forum Thread https://forum.unity.com/threads/auto-attach-components-via-attributes.928098/ 4 | 5 | ### Installation 6 | 7 | Add this as a package to your project by adding the below as an entry to the dependencies in the `/Packages/manifest.json` file: 8 | 9 | ```json 10 | "nrjwolf.games.attachattributes": "https://github.com/Nrjwolf/unity-auto-attach-component-attributes.git" 11 | ``` 12 | For more information on adding git repositories as a package see the [Git support on Package Manager](https://docs.unity3d.com/Manual/upm-git.html) in the Unity Documentation. 13 | 14 | ### Preview video 15 | 16 | [![Play](https://img.youtube.com/vi/LdiJdgHrBl4/0.jpg)](https://www.youtube.com/watch?v=LdiJdgHrBl4) 17 | 18 | ### Example 19 | ``` c# 20 | using Nrjwolf.Tools.AttachAttributes; 21 | 22 | [FindObjectOfType] 23 | [SerializeField] private Camera m_Camera; 24 | 25 | [GetComponent] 26 | [SerializeField] private Image m_Image; 27 | 28 | [GetComponentInChildren(true)] // include inactive 29 | [SerializeField] private Button m_Button; 30 | 31 | [GetComponentInChildren("Buttons/Button1")] // Get the component from the children by path "Buttons/Button1" in hierarchy 32 | [SerializeField] private Button m_Button; 33 | 34 | [AddComponent] // Add component in editor and attach it to field 35 | [SerializeField] private SpringJoint2D m_SpringJoint2D; 36 | 37 | [GetComponentInParent] // Get component from parent 38 | [SerializeField] private Canvas m_Canvas; 39 | ``` 40 | 41 | Now all components will automatically attach when you select your gameobject in hierarchy 42 | 43 | ![](https://github.com/Nrjwolf/unity-auto-attach-component-attributes/blob/master/.github/images/globalSettingInContextMenu.png "Global active/deactive")
44 | You can turn it on/off in component context menu or via ```Tools/Nrjwolf/AttachAttributes``` 45 | 46 | ### About 47 | 48 | This asset help you to auto attach components into your serialized fields in inpector. I started use it to avoid every time assign components in ```Awake/Start``` 49 | function.

50 | So, you can ask why I need it? Well, maybe you use code like this and do not know, that this is bad for perfomance 51 | ``` c# 52 | private Transform m_CachedTransform 53 | public Transform transform 54 | { 55 | get 56 | { 57 | if (m_CachedTransform == null) 58 | m_CachedTransform = InternalGetTransform(); 59 | return m_CachedTransform; 60 | } 61 | } 62 | ``` 63 | You can read about here: https://blogs.unity3d.com/ru/2014/05/16/custom-operator-should-we-keep-it/ 64 | 65 | --- 66 | 67 | >Telegram : https://t.me/nrjwolf_games
68 | >Discord : https://discord.gg/jwPVsat
69 | >Reddit : https://www.reddit.com/r/Nrjwolf/
70 | >Twitter : https://twitter.com/nrjwolf
71 | -------------------------------------------------------------------------------- /.github/images/globalSettingInContextMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nrjwolf/unity-auto-attach-component-attributes/719b0afa8a1abd8765d71d6ce1cce7b97718bc59/.github/images/globalSettingInContextMenu.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nrjwolf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 887821fc0b22a6e43965f9a3c51a984c 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3f21cf050985f245bc5f883659f2acf 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 043622a1c21f8a9408b81b044cab6060 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Editor/AttachAttributesEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | using Nrjwolf.Tools.AttachAttributes; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Nrjwolf.Tools.Editor.AttachAttributes 9 | { 10 | public static class AttachAttributesUtils 11 | { 12 | private const string k_ContextMenuItemLabel = "CONTEXT/Component/AttachAttributes"; 13 | private const string k_ToolsMenuItemLabel = "Tools/Nrjwolf/AttachAttributes"; 14 | 15 | private const string k_EditorPrefsAttachAttributesGlobal = "IsAttachAttributesActive"; 16 | 17 | public static bool IsEnabled 18 | { 19 | get => EditorPrefs.GetBool(k_EditorPrefsAttachAttributesGlobal, true); 20 | set 21 | { 22 | if (value) EditorPrefs.DeleteKey(k_EditorPrefsAttachAttributesGlobal); 23 | else EditorPrefs.SetBool(k_EditorPrefsAttachAttributesGlobal, value); // clear value if it's equals defaultValue 24 | } 25 | } 26 | 27 | [MenuItem(k_ContextMenuItemLabel)] 28 | [MenuItem(k_ToolsMenuItemLabel)] 29 | private static void ToggleAction() 30 | { 31 | IsEnabled = !IsEnabled; 32 | } 33 | 34 | [MenuItem(k_ContextMenuItemLabel, true)] 35 | [MenuItem(k_ToolsMenuItemLabel, true)] 36 | private static bool ToggleActionValidate() 37 | { 38 | Menu.SetChecked(k_ContextMenuItemLabel, IsEnabled); 39 | Menu.SetChecked(k_ToolsMenuItemLabel, IsEnabled); 40 | return true; 41 | } 42 | 43 | public static string GetPropertyType(this SerializedProperty property) 44 | { 45 | var type = property.type; 46 | var match = Regex.Match(type, @"PPtr<\$(.*?)>"); 47 | if (match.Success) 48 | type = match.Groups[1].Value; 49 | return type; 50 | } 51 | 52 | public static Type StringToType(this string aClassName) => System.AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).First(x => x.IsSubclassOf(typeof(Component)) && x.Name == aClassName); 53 | } 54 | 55 | /// Base class for Attach Attribute 56 | public class AttachAttributePropertyDrawer : PropertyDrawer 57 | { 58 | private Color m_GUIColorDefault = new Color(.6f, .6f, .6f, 1); 59 | private Color m_GUIColorNull = new Color(1f, .5f, .5f, 1); 60 | 61 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 62 | { 63 | // turn off attribute if not active or in Play Mode (imitate as build will works) 64 | if (!AttachAttributesUtils.IsEnabled || Application.isPlaying) 65 | { 66 | property.serializedObject.Update(); 67 | EditorGUI.PropertyField(position, property, label, true); 68 | property.serializedObject.ApplyModifiedProperties(); 69 | return; 70 | } 71 | 72 | bool isPropertyValueNull = property.objectReferenceValue == null; 73 | 74 | // Change GUI color 75 | var prevColor = GUI.color; 76 | GUI.color = isPropertyValueNull ? m_GUIColorNull : m_GUIColorDefault; 77 | 78 | // Default draw 79 | EditorGUI.PropertyField(position, property, label, true); 80 | 81 | // Get property type and GameObject 82 | property.serializedObject.Update(); 83 | if (isPropertyValueNull) 84 | { 85 | var type = property.GetPropertyType().StringToType(); 86 | var go = ((MonoBehaviour)(property.serializedObject.targetObject)).gameObject; 87 | UpdateProperty(property, go, type); 88 | } 89 | 90 | property.serializedObject.ApplyModifiedProperties(); 91 | GUI.color = prevColor; 92 | } 93 | 94 | /// Customize it for each attribute 95 | public virtual void UpdateProperty(SerializedProperty property, GameObject go, Type type) 96 | { 97 | // Do whatever 98 | // For example to get component 99 | // property.objectReferenceValue = go.GetComponent(type); 100 | } 101 | } 102 | 103 | #region Attribute Editors 104 | 105 | /// GetComponent 106 | [CustomPropertyDrawer(typeof(GetComponentAttribute))] 107 | public class GetComponentAttributeEditor : AttachAttributePropertyDrawer 108 | { 109 | public override void UpdateProperty(SerializedProperty property, GameObject go, Type type) 110 | { 111 | property.objectReferenceValue = go.GetComponent(type); 112 | } 113 | } 114 | 115 | /// GetComponentInChildren 116 | [CustomPropertyDrawer(typeof(GetComponentInChildrenAttribute))] 117 | public class GetComponentInChildrenAttributeEditor : AttachAttributePropertyDrawer 118 | { 119 | public override void UpdateProperty(SerializedProperty property, GameObject go, Type type) 120 | { 121 | GetComponentInChildrenAttribute labelAttribute = (GetComponentInChildrenAttribute)attribute; 122 | if (labelAttribute.ChildName == null) 123 | { 124 | property.objectReferenceValue = go.GetComponentInChildren(type, labelAttribute.IncludeInactive); 125 | } 126 | else 127 | { 128 | var child = go.transform.Find(labelAttribute.ChildName); 129 | if (child != null) 130 | { 131 | property.objectReferenceValue = child.GetComponent(type); 132 | } 133 | } 134 | } 135 | } 136 | 137 | /// AddComponent 138 | [CustomPropertyDrawer(typeof(AddComponentAttribute))] 139 | public class AddComponentAttributeEditor : AttachAttributePropertyDrawer 140 | { 141 | public override void UpdateProperty(SerializedProperty property, GameObject go, Type type) 142 | { 143 | property.objectReferenceValue = go.AddComponent(type); 144 | } 145 | } 146 | 147 | /// FindObjectOfType 148 | [CustomPropertyDrawer(typeof(FindObjectOfTypeAttribute))] 149 | public class FindObjectOfTypeAttributeEditor : AttachAttributePropertyDrawer 150 | { 151 | public override void UpdateProperty(SerializedProperty property, GameObject go, Type type) 152 | { 153 | property.objectReferenceValue = FindObjectsOfTypeByName(property.GetPropertyType()); 154 | } 155 | 156 | public UnityEngine.Object FindObjectsOfTypeByName(string aClassName) 157 | { 158 | var assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); 159 | for (int i = 0; i < assemblies.Length; i++) 160 | { 161 | var types = assemblies[i].GetTypes(); 162 | for (int n = 0; n < types.Length; n++) 163 | { 164 | if (typeof(UnityEngine.Object).IsAssignableFrom(types[n]) && aClassName == types[n].Name) 165 | return UnityEngine.Object.FindObjectOfType(types[n]); 166 | } 167 | } 168 | return new UnityEngine.Object(); 169 | } 170 | } 171 | 172 | /// GetComponentInParent 173 | [CustomPropertyDrawer(typeof(GetComponentInParent))] 174 | public class GetComponentInParentAttributeEditor : AttachAttributePropertyDrawer 175 | { 176 | public override void UpdateProperty(SerializedProperty property, GameObject go, Type type) 177 | { 178 | if (go.transform.parent != null) 179 | property.objectReferenceValue = go.transform.parent.gameObject.GetComponent(type); 180 | } 181 | } 182 | #endregion 183 | } 184 | -------------------------------------------------------------------------------- /Scripts/Editor/AttachAttributesEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a6e78c00e20078645ae24557eaa95e31 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Editor/Nrjwolf.Tools.AttachAttributes.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nrjwolf.Tools.Editor.AttachAttributes", 3 | "references": [ 4 | "Nrjwolf.Tools.AttachAttributes" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [] 16 | } -------------------------------------------------------------------------------- /Scripts/Editor/Nrjwolf.Tools.AttachAttributes.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8222b8826718456f977156f0da3a697 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8bb5da8004b0ea49901dec38fde0c4b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Runtime/AttachAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Nrjwolf.Tools.AttachAttributes 5 | { 6 | [AttributeUsage(System.AttributeTargets.Field)] public class GetComponentAttribute : AttachPropertyAttribute { } 7 | 8 | [AttributeUsage(System.AttributeTargets.Field)] 9 | public class GetComponentInChildrenAttribute : AttachPropertyAttribute 10 | { 11 | public bool IncludeInactive { get; private set; } 12 | public string ChildName; 13 | 14 | public GetComponentInChildrenAttribute(bool includeInactive = false) 15 | { 16 | IncludeInactive = includeInactive; 17 | } 18 | 19 | public GetComponentInChildrenAttribute(string childName) 20 | { 21 | ChildName = childName; 22 | } 23 | } 24 | 25 | [AttributeUsage(System.AttributeTargets.Field)] public class AddComponentAttribute : AttachPropertyAttribute { } 26 | [AttributeUsage(System.AttributeTargets.Field)] public class FindObjectOfTypeAttribute : AttachPropertyAttribute { } 27 | [AttributeUsage(System.AttributeTargets.Field)] public class GetComponentInParent : AttachPropertyAttribute { } 28 | 29 | public class AttachPropertyAttribute : PropertyAttribute { } 30 | } 31 | -------------------------------------------------------------------------------- /Scripts/Runtime/AttachAttributes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b46ce8ce45ac7d743b075a7fcf098d23 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Runtime/Nrjwolf.Tools.AttachAttributes.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nrjwolf.Tools.AttachAttributes", 3 | "references": [], 4 | "includePlatforms": [], 5 | "excludePlatforms": [], 6 | "allowUnsafeCode": false, 7 | "overrideReferences": false, 8 | "precompiledReferences": [], 9 | "autoReferenced": true, 10 | "defineConstraints": [], 11 | "versionDefines": [] 12 | } -------------------------------------------------------------------------------- /Scripts/Runtime/Nrjwolf.Tools.AttachAttributes.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b4794e38edc74eb8986ad993a5ad5c8 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nrjwolf.games.attachattributes", 3 | "version": "1.0.0", 4 | "displayName": "Attach Attributes", 5 | "description": "Use attach attributes to auto attach components.\n\nFor example \n\n[GetComponent] \n[SerializeField] private Image m_Image;\n\nNow all components will automatically attach when you select your gameobject in hierarchy", 6 | "unity": "2018.2" 7 | } 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8e12ab761fc947d5817c3e65b96e32b 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------