├── .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 | [](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 | 
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 |
--------------------------------------------------------------------------------