├── .editorconfig
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── assets
├── Editor.meta
├── Editor
│ ├── ClassTypeReferencePropertyDrawer.cs
│ ├── ClassTypeReferencePropertyDrawer.cs.meta
│ ├── _assembly.asmdef
│ └── _assembly.asmdef.meta
├── Source.meta
└── Source
│ ├── ClassExtendsAttribute.cs
│ ├── ClassExtendsAttribute.cs.meta
│ ├── ClassGrouping.cs
│ ├── ClassGrouping.cs.meta
│ ├── ClassImplementsAttribute.cs
│ ├── ClassImplementsAttribute.cs.meta
│ ├── ClassTypeConstraintAttribute.cs
│ ├── ClassTypeConstraintAttribute.cs.meta
│ ├── ClassTypeReference.cs
│ ├── ClassTypeReference.cs.meta
│ ├── _assembly.asmdef
│ └── _assembly.asmdef.meta
├── index.js
├── package.json
└── screenshot.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; Grab the EditorConfig extension for Visual Studio:
2 | ; https://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328
3 |
4 | ; Top-most EditorConfig file
5 | root = true
6 |
7 | ; Unix-style newlines with a newline ending every file
8 | [*]
9 | end_of_line = LF
10 | insert_final_newline = true
11 | indent_style = space
12 | indent_size = 4
13 | trim_trailing_whitespace = true
14 |
15 | [*.{md,yaml}]
16 | trim_trailing_whitespace = false
17 |
18 | [*.{js,json,yaml,html,css,styl}]
19 | indent_size = 2
20 |
21 | [Makefile]
22 | indent_style = tab
23 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Apply native OS line-endings on checkout of these files...
2 | *.boo text
3 | *.c text
4 | *.cginc text
5 | *.config text
6 | *.contentproj text
7 | *.cpp text
8 | *.cs text
9 | *.css text
10 | *.dae text
11 | *.DAE text
12 | *.dtd text
13 | *.fx text
14 | *.glsl text
15 | *.h text
16 | *.htm text
17 | *.html text
18 | *.inc text
19 | *.ini text
20 | *.js text
21 | *.JSFL text
22 | *.jsfl text
23 | *.json text
24 | *.log text
25 | *.md text
26 | *.mel text
27 | *.php text
28 | *.po text
29 | *.shader text
30 | *.txt text
31 | *.TXT text
32 | *.xaml text
33 | *.xml text
34 | *.xsd text
35 | .gitattributes text
36 | .gitignore text
37 | COPYING text
38 | INSTALL* text
39 | KEYS* text
40 | LICENSE* text
41 | NEWS* text
42 | NOTICE* text
43 | README* text
44 | TODO* text
45 | WHATSNEW* text
46 |
47 | # Apply Unix-style LF line-endings on checkout for these files since Unity
48 | # project has been configured to force text output for them...
49 | *.anim text eol=lf
50 | *.asset text eol=lf
51 | *.controller text eol=lf
52 | *.cubemap text eol=lf
53 | *.guiskin text eol=lf
54 | *.mat text eol=lf
55 | *.prefab text eol=lf
56 | *.physicMaterial text eol=lf
57 | *.physicmaterial text eol=lf
58 | *.unity text eol=lf
59 |
60 | # Apply Unix-style LF line-endings on checkout of these files...
61 | *.meta text eol=lf
62 | *.sh text eol=lf
63 | *.vspscc text eol=lf
64 | .htaccess text eol=lf
65 |
66 | # Apply Windows/DOS-style CR-LF line-endings on checkout of these files...
67 | *.bat text eol=crlf
68 | *.cmd text eol=crlf
69 | *.csproj text eol=crlf
70 | *.sln text eol=crlf
71 | *.user text eol=crlf
72 | *.vcproj text eol=crlf
73 |
74 | # No end-of-line conversions are applied (i.e., "-text -diff") to these files...
75 | *.7z binary
76 | *.ai binary
77 | *.apk binary
78 | *.bin binary
79 | *.bmp binary
80 | *.BMP binary
81 | *.com binary
82 | *.COM binary
83 | *.dex binary
84 | *.dll binary
85 | *.DLL binary
86 | *.dylib binary
87 | *.eps binary
88 | *.exe binary
89 | *.EXE binary
90 | *.exr binary
91 | *.fbx binary
92 | *.FBX binary
93 | *.fla binary
94 | *.flare binary
95 | *.flv binary
96 | *.gif binary
97 | *.gz binary
98 | *.ht binary
99 | *.ico binary
100 | *.jpeg binary
101 | *.jpg binary
102 | *.keystore binary
103 | *.mask binary
104 | *.mb binary
105 | *.mo binary
106 | *.mp3 binary
107 | *.mp4 binary
108 | *.mpg binary
109 | *.ogg binary
110 | *.PCX binary
111 | *.pcx binary
112 | *.pdb binary
113 | *.pdf binary
114 | *.png binary
115 | *.ps binary
116 | *.psd binary
117 | *.qt binary
118 | *.so binary
119 | *.swf binary
120 | *.tga binary
121 | *.tif binary
122 | *.tiff binary
123 | *.ttf binary
124 | *.TTF binary
125 | *.unitypackage binary
126 | *.unityPackage binary
127 | *.wav binary
128 | *.wmv binary
129 | *.zip binary
130 | *.ZIP binary
131 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Derived From:
2 | # http://kleber-swf.com/the-definitive-gitignore-for-unity-projects/
3 |
4 | # ============= #
5 | # Working Files #
6 | # ============= #
7 | node_modules/
8 | npm-debug.log
9 |
10 | # ===================== #
11 | # Working Files - Unity #
12 | # ===================== #
13 | /Temp/
14 | /Library/
15 | /Packages/
16 | /ProjectSettings/
17 | /assets/Plugins/
18 | /assets/Plugins.meta
19 | /*.csproj
20 | /*.sln
21 |
22 | # ===================================== #
23 | # Visual Studio / MonoDevelop generated #
24 | # ===================================== #
25 | /.vs/
26 | bin
27 | obj
28 | ExportedObj/
29 | *.svd
30 | *.userprefs
31 | *.pidb
32 | *.suo
33 | *.user
34 | *.unityproj
35 | *.booproj
36 | *.pdb
37 | *.pdb.meta
38 |
39 | # ============ #
40 | # OS generated #
41 | # ============ #
42 | .DS_Store
43 | .DS_Store?
44 | *~
45 | ._*
46 | .Spotlight-V100
47 | .Trashes
48 | Icon?
49 | ehthumbs.db
50 | Thumbs.db
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2017 Rotorz Limited
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # unity3d-class-type-reference
2 |
3 | An example npm package that contains some example assets to demonstrate how to create a
4 | package for use in games made using the Unity game engine.
5 |
6 |
7 | ```sh
8 | $ yarn add rotorz/unity3d-class-type-reference
9 | ```
10 |
11 | This package is compatible with the [unity3d-package-syncer][tool] tool. Refer to the
12 | tools' [README][tool] for information on syncing packages into a Unity project.
13 |
14 | [tool]: https://github.com/rotorz/unity3d-package-syncer
15 |
16 | 
17 |
18 |
19 | ## Warning
20 |
21 | Whilst we have not encountered any platform specific issues yet, the source code in this
22 | repository *might* not necessarily work for all of Unity's platforms or build
23 | configurations. It would be greatly appreciated if people would report issues using the
24 | issue tracker.
25 |
26 |
27 | ## Usage Examples
28 |
29 | Type references can be made using the inspector simply by using `ClassTypeReference`:
30 |
31 | ```csharp
32 | using Rotorz.Games.Reflection;
33 | using UnityEngine;
34 |
35 | public class ExampleBehaviour : MonoBehaviour
36 | {
37 | public ClassTypeReference greetingLoggerType;
38 | }
39 | ```
40 |
41 | A default value can be specified in the normal way:
42 |
43 | ```csharp
44 | public ClassTypeReference greetingLoggerType = typeof(DefaultGreetingLogger);
45 | ```
46 |
47 | You can apply one of two attributes to drastically reduce the number of types presented
48 | when using the drop-down field.
49 |
50 | ```csharp
51 | using Rotorz.Games.Reflection;
52 | using UnityEngine;
53 |
54 | public class ExampleBehaviour : MonoBehaviour
55 | {
56 | // Allow selection of classes that implement an interface.
57 | [ClassImplements(typeof(IGreetingLogger))]
58 | public ClassTypeReference greetingLoggerType;
59 |
60 | // Allow selection of classes that extend a specific class.
61 | [ClassExtends(typeof(MonoBehaviour))]
62 | public ClassTypeReference someBehaviourType;
63 | }
64 | ```
65 |
66 | To create an instance at runtime you can use the `System.Activator` class from the .NET /
67 | Mono library:
68 |
69 | ```csharp
70 | using Rotorz.Games.Reflection;
71 | using System;
72 | using UnityEngine;
73 |
74 | public class ExampleBehaviour : MonoBehaviour
75 | {
76 | [ClassImplements(typeof(IGreetingLogger))]
77 | public ClassTypeReference greetingLoggerType = typeof(DefaultGreetingLogger);
78 |
79 |
80 | private void Start()
81 | {
82 | if (this.greetingLoggerType.Type == null) {
83 | Debug.LogWarning("No type of greeting logger was specified.");
84 | }
85 | else {
86 | var greetingLogger = Activator.CreateInstance(this.greetingLoggerType) as IGreetingLogger;
87 | greetingLogger.LogGreeting();
88 | }
89 | }
90 | }
91 | ```
92 |
93 | Presentation of drop-down list can be customized by supplying a `ClassGrouping` value to
94 | either of the attributes `ClassImplements` or `ClassExtends`.
95 |
96 | - **ClassGrouping.None** - No grouping, just show type names in a list; for instance,
97 | "Some.Nested.Namespace.SpecialClass".
98 |
99 | - **ClassGrouping.ByNamespace** - Group classes by namespace and show foldout menus for
100 | nested namespaces; for instance, "Some > Nested > Namespace > SpecialClass".
101 |
102 | - **ClassGrouping.ByNamespaceFlat** (default) - Group classes by namespace; for instance,
103 | "Some.Nested.Namespace > SpecialClass".
104 |
105 | - **ClassGrouping.ByAddComponentMenu** - Group classes in the same way as Unity does for
106 | its component menu. This grouping method must only be used for `MonoBehaviour` types.
107 |
108 | For instance,
109 |
110 | ```csharp
111 | using Rotorz.Games.Reflection;
112 | using UnityEngine;
113 |
114 | public class ExampleBehaviour : MonoBehaviour
115 | {
116 | [ClassImplements(typeof(IGreetingLogger), Grouping = ClassGrouping.ByAddComponentMenu)]
117 | public ClassTypeReference greetingLoggerType;
118 | }
119 | ```
120 |
121 |
122 | ## Contribution Agreement
123 |
124 | This project is licensed under the MIT license (see LICENSE). To be in the best
125 | position to enforce these licenses the copyright status of this project needs to
126 | be as simple as possible. To achieve this the following terms and conditions
127 | must be met:
128 |
129 | - All contributed content (including but not limited to source code, text,
130 | image, videos, bug reports, suggestions, ideas, etc.) must be the
131 | contributors own work.
132 |
133 | - The contributor disclaims all copyright and accepts that their contributed
134 | content will be released to the public domain.
135 |
136 | - The act of submitting a contribution indicates that the contributor agrees
137 | with this agreement. This includes (but is not limited to) pull requests, issues,
138 | tickets, e-mails, newsgroups, blogs, forums, etc.
139 |
--------------------------------------------------------------------------------
/assets/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1cf7ccd7278ddd342a9eb5e5e4a492fa
3 | folderAsset: yes
4 | timeCreated: 1494476847
5 | licenseType: Pro
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/assets/Editor/ClassTypeReferencePropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Reflection;
7 | using UnityEditor;
8 | using UnityEngine;
9 |
10 | namespace Rotorz.Games.Reflection
11 | {
12 | ///
13 | /// Custom property drawer for properties.
14 | ///
15 | [CustomPropertyDrawer(typeof(ClassTypeReference))]
16 | [CustomPropertyDrawer(typeof(ClassTypeConstraintAttribute), true)]
17 | public sealed class ClassTypeReferencePropertyDrawer : PropertyDrawer
18 | {
19 | #region Type Filtering
20 |
21 | ///
22 | /// Gets or sets a function that returns a collection of types that are
23 | /// to be excluded from drop-down. A value of null specifies that
24 | /// no types are to be excluded.
25 | ///
26 | ///
27 | /// This property must be set immediately before presenting a class
28 | /// type reference property field using
29 | /// or since the value of this
30 | /// property is reset to null each time the control is drawn.
31 | /// Since filtering makes extensive use of
32 | /// it is recommended to use a collection that is optimized for fast
33 | /// lookups such as for better performance.
34 | ///
35 | ///
36 | /// Exclude a specific type from being selected:
37 | /// GetExcludedTypeCollection() {
50 | /// var set = new HashSet();
51 | /// set.Add(typeof(SpecialClassToHideInDropdown));
52 | /// return set;
53 | /// }
54 | /// ]]>
55 | ///
56 | public static Func> ExcludedTypeCollectionGetter { get; set; }
57 |
58 | private static List GetFilteredTypes(ClassTypeConstraintAttribute filter)
59 | {
60 | var types = new List();
61 |
62 | var excludedTypes = (ExcludedTypeCollectionGetter != null ? ExcludedTypeCollectionGetter() : null);
63 |
64 | foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
65 | FilterTypes(assembly, filter, excludedTypes, types);
66 | }
67 |
68 | types.Sort((a, b) => a.FullName.CompareTo(b.FullName));
69 |
70 | return types;
71 | }
72 |
73 | private static void FilterTypes(Assembly assembly, ClassTypeConstraintAttribute filter, ICollection excludedTypes, List output)
74 | {
75 | foreach (var type in assembly.GetTypes()) {
76 | if (!type.IsPublic || !type.IsClass) {
77 | continue;
78 | }
79 |
80 | if (filter != null && !filter.IsConstraintSatisfied(type)) {
81 | continue;
82 | }
83 |
84 | if (excludedTypes != null && excludedTypes.Contains(type)) {
85 | continue;
86 | }
87 |
88 | output.Add(type);
89 | }
90 | }
91 |
92 | #endregion
93 |
94 |
95 | #region Type Utility
96 |
97 | private static Dictionary s_TypeMap = new Dictionary();
98 |
99 | private static Type ResolveType(string classRef)
100 | {
101 | Type type;
102 | if (!s_TypeMap.TryGetValue(classRef, out type)) {
103 | type = !string.IsNullOrEmpty(classRef) ? Type.GetType(classRef) : null;
104 | s_TypeMap[classRef] = type;
105 | }
106 | return type;
107 | }
108 |
109 | #endregion
110 |
111 |
112 | #region Control Drawing / Event Handling
113 |
114 | private static readonly int s_ControlHint = typeof(ClassTypeReferencePropertyDrawer).GetHashCode();
115 | private static GUIContent s_TempContent = new GUIContent();
116 |
117 | private static string DrawTypeSelectionControl(Rect position, GUIContent label, string classRef, ClassTypeConstraintAttribute filter)
118 | {
119 | if (label != null && label != GUIContent.none) {
120 | position = EditorGUI.PrefixLabel(position, label);
121 | }
122 |
123 | int controlID = GUIUtility.GetControlID(s_ControlHint, FocusType.Keyboard, position);
124 |
125 | bool triggerDropDown = false;
126 |
127 | switch (Event.current.GetTypeForControl(controlID)) {
128 | case EventType.ExecuteCommand:
129 | if (Event.current.commandName == "TypeReferenceUpdated") {
130 | if (s_SelectionControlID == controlID) {
131 | if (classRef != s_SelectedClassRef) {
132 | classRef = s_SelectedClassRef;
133 | GUI.changed = true;
134 | }
135 |
136 | s_SelectionControlID = 0;
137 | s_SelectedClassRef = null;
138 | }
139 | }
140 | break;
141 |
142 | case EventType.MouseDown:
143 | if (GUI.enabled && position.Contains(Event.current.mousePosition)) {
144 | GUIUtility.keyboardControl = controlID;
145 | triggerDropDown = true;
146 | Event.current.Use();
147 | }
148 | break;
149 |
150 | case EventType.KeyDown:
151 | if (GUI.enabled && GUIUtility.keyboardControl == controlID) {
152 | if (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.Space) {
153 | triggerDropDown = true;
154 | Event.current.Use();
155 | }
156 | }
157 | break;
158 |
159 | case EventType.Repaint:
160 | // Remove assembly name from content of popup control.
161 | var classRefParts = classRef.Split(',');
162 |
163 | s_TempContent.text = classRefParts[0].Trim();
164 | if (s_TempContent.text == "") {
165 | s_TempContent.text = "(None)";
166 | }
167 | else if (ResolveType(classRef) == null) {
168 | s_TempContent.text += " {Missing}";
169 | }
170 |
171 | EditorStyles.popup.Draw(position, s_TempContent, controlID);
172 | break;
173 | }
174 |
175 | if (triggerDropDown) {
176 | s_SelectionControlID = controlID;
177 | s_SelectedClassRef = classRef;
178 |
179 | var filteredTypes = GetFilteredTypes(filter);
180 | DisplayDropDown(position, filteredTypes, ResolveType(classRef), filter.Grouping);
181 | }
182 |
183 | return classRef;
184 | }
185 |
186 | private static void DrawTypeSelectionControl(Rect position, SerializedProperty property, GUIContent label, ClassTypeConstraintAttribute filter)
187 | {
188 | try {
189 | bool restoreShowMixedValue = EditorGUI.showMixedValue;
190 | EditorGUI.showMixedValue = property.hasMultipleDifferentValues;
191 |
192 | property.stringValue = DrawTypeSelectionControl(position, label, property.stringValue, filter);
193 |
194 | EditorGUI.showMixedValue = restoreShowMixedValue;
195 | }
196 | finally {
197 | ExcludedTypeCollectionGetter = null;
198 | }
199 | }
200 |
201 | private static void DisplayDropDown(Rect position, List types, Type selectedType, ClassGrouping grouping)
202 | {
203 | var menu = new GenericMenu();
204 |
205 | menu.AddItem(new GUIContent("(None)"), selectedType == null, s_OnSelectedTypeName, null);
206 | menu.AddSeparator("");
207 |
208 | for (int i = 0; i < types.Count; ++i) {
209 | var type = types[i];
210 |
211 | string menuLabel = FormatGroupedTypeName(type, grouping);
212 | if (string.IsNullOrEmpty(menuLabel)) {
213 | continue;
214 | }
215 |
216 | var content = new GUIContent(menuLabel);
217 | menu.AddItem(content, type == selectedType, s_OnSelectedTypeName, type);
218 | }
219 |
220 | menu.DropDown(position);
221 | }
222 |
223 | private static string FormatGroupedTypeName(Type type, ClassGrouping grouping)
224 | {
225 | string name = type.FullName;
226 |
227 | switch (grouping) {
228 | default:
229 | case ClassGrouping.None:
230 | return name;
231 |
232 | case ClassGrouping.ByNamespace:
233 | return name.Replace('.', '/');
234 |
235 | case ClassGrouping.ByNamespaceFlat:
236 | int lastPeriodIndex = name.LastIndexOf('.');
237 | if (lastPeriodIndex != -1) {
238 | name = name.Substring(0, lastPeriodIndex) + "/" + name.Substring(lastPeriodIndex + 1);
239 | }
240 |
241 | return name;
242 |
243 | case ClassGrouping.ByAddComponentMenu:
244 | var addComponentMenuAttributes = type.GetCustomAttributes(typeof(AddComponentMenu), false);
245 | if (addComponentMenuAttributes.Length == 1) {
246 | return ((AddComponentMenu)addComponentMenuAttributes[0]).componentMenu;
247 | }
248 |
249 | return "Scripts/" + type.FullName.Replace('.', '/');
250 | }
251 | }
252 |
253 | private static int s_SelectionControlID;
254 | private static string s_SelectedClassRef;
255 |
256 | private static readonly GenericMenu.MenuFunction2 s_OnSelectedTypeName = OnSelectedTypeName;
257 |
258 | private static void OnSelectedTypeName(object userData)
259 | {
260 | var selectedType = userData as Type;
261 |
262 | s_SelectedClassRef = ClassTypeReference.GetClassRef(selectedType);
263 |
264 | var typeReferenceUpdatedEvent = EditorGUIUtility.CommandEvent("TypeReferenceUpdated");
265 | EditorWindow.focusedWindow.SendEvent(typeReferenceUpdatedEvent);
266 | }
267 |
268 | #endregion
269 |
270 |
271 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
272 | {
273 | return EditorStyles.popup.CalcHeight(GUIContent.none, 0);
274 | }
275 |
276 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
277 | {
278 | DrawTypeSelectionControl(position, property.FindPropertyRelative("classRef"), label, attribute as ClassTypeConstraintAttribute);
279 | }
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/assets/Editor/ClassTypeReferencePropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e590d83066b6dc84c905affd1bdfce81
3 | timeCreated: 1494476848
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Editor/_assembly.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rotorz.unity3d-class-type-reference.editor",
3 | "references": [
4 | "rotorz.unity3d-class-type-reference"
5 | ],
6 | "optionalUnityReferences": [],
7 | "includePlatforms": [
8 | "Editor"
9 | ],
10 | "excludePlatforms": [],
11 | "allowUnsafeCode": false
12 | }
13 |
--------------------------------------------------------------------------------
/assets/Editor/_assembly.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fd123adc3f5794c45b50ae6897c5d79a
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/assets/Source.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5fdc96b7460483e4ba75f70abf119379
3 | folderAsset: yes
4 | timeCreated: 1494534088
5 | licenseType: Pro
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/assets/Source/ClassExtendsAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | using System;
5 |
6 | namespace Rotorz.Games.Reflection
7 | {
8 | ///
9 | /// Constraint that allows selection of classes that extend a specific class when
10 | /// selecting a with the Unity inspector.
11 | ///
12 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
13 | public sealed class ClassExtendsAttribute : ClassTypeConstraintAttribute
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ClassExtendsAttribute()
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// Type of class that selectable classes must derive from.
26 | public ClassExtendsAttribute(Type baseType)
27 | {
28 | this.BaseType = baseType;
29 | }
30 |
31 |
32 | ///
33 | /// Gets the type of class that selectable classes must derive from.
34 | ///
35 | public Type BaseType { get; private set; }
36 |
37 |
38 | ///
39 | public override bool IsConstraintSatisfied(Type type)
40 | {
41 | return base.IsConstraintSatisfied(type)
42 | && this.BaseType.IsAssignableFrom(type) && type != this.BaseType;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/assets/Source/ClassExtendsAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4b26348d5ced6e649a94efdcb219e04f
3 | timeCreated: 1494477112
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Source/ClassGrouping.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | namespace Rotorz.Games.Reflection
5 | {
6 | ///
7 | /// Indicates how selectable classes should be collated in drop-down menu.
8 | ///
9 | public enum ClassGrouping
10 | {
11 | ///
12 | /// No grouping, just show type names in a list; for instance, "Some.Nested.Namespace.SpecialClass".
13 | ///
14 | None,
15 | ///
16 | /// Group classes by namespace and show foldout menus for nested namespaces; for
17 | /// instance, "Some > Nested > Namespace > SpecialClass".
18 | ///
19 | ByNamespace,
20 | ///
21 | /// Group classes by namespace; for instance, "Some.Nested.Namespace > SpecialClass".
22 | ///
23 | ByNamespaceFlat,
24 | ///
25 | /// Group classes in the same way as Unity does for its component menu. This
26 | /// grouping method must only be used for types.
27 | ///
28 | ByAddComponentMenu,
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/assets/Source/ClassGrouping.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 15f8f58fca38df441bd86ba4862b1081
3 | timeCreated: 1494477112
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Source/ClassImplementsAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | using System;
5 |
6 | namespace Rotorz.Games.Reflection
7 | {
8 | ///
9 | /// Constraint that allows selection of classes that implement a specific interface
10 | /// when selecting a with the Unity inspector.
11 | ///
12 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
13 | public sealed class ClassImplementsAttribute : ClassTypeConstraintAttribute
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ClassImplementsAttribute()
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// Type of interface that selectable classes must implement.
26 | public ClassImplementsAttribute(Type interfaceType)
27 | {
28 | this.InterfaceType = interfaceType;
29 | }
30 |
31 |
32 | ///
33 | /// Gets the type of interface that selectable classes must implement.
34 | ///
35 | public Type InterfaceType { get; private set; }
36 |
37 |
38 | ///
39 | public override bool IsConstraintSatisfied(Type type)
40 | {
41 | if (base.IsConstraintSatisfied(type)) {
42 | foreach (var interfaceType in type.GetInterfaces()) {
43 | if (interfaceType == this.InterfaceType) {
44 | return true;
45 | }
46 | }
47 | }
48 | return false;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/assets/Source/ClassImplementsAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c5072d81a2f7efc4485abb4971f589d3
3 | timeCreated: 1494477112
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Source/ClassTypeConstraintAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | using System;
5 | using UnityEngine;
6 |
7 | namespace Rotorz.Games.Reflection
8 | {
9 | ///
10 | /// Base class for class selection constraints that can be applied when selecting
11 | /// a with the Unity inspector.
12 | ///
13 | public abstract class ClassTypeConstraintAttribute : PropertyAttribute
14 | {
15 | private ClassGrouping grouping = ClassGrouping.ByNamespaceFlat;
16 | private bool allowAbstract = false;
17 |
18 |
19 | ///
20 | /// Gets or sets grouping of selectable classes. Defaults to
21 | /// unless explicitly specified.
22 | ///
23 | public ClassGrouping Grouping {
24 | get { return this.grouping; }
25 | set { this.grouping = value; }
26 | }
27 |
28 | ///
29 | /// Gets or sets whether abstract classes can be selected from drop-down.
30 | /// Defaults to a value of false unless explicitly specified.
31 | ///
32 | public bool AllowAbstract {
33 | get { return this.allowAbstract; }
34 | set { this.allowAbstract = value; }
35 | }
36 |
37 |
38 | ///
39 | /// Determines whether the specified satisfies filter constraint.
40 | ///
41 | /// Type to test.
42 | ///
43 | /// A value indicating if the type specified by
44 | /// satisfies this constraint and should thus be selectable.
45 | ///
46 | public virtual bool IsConstraintSatisfied(Type type)
47 | {
48 | return this.AllowAbstract || !type.IsAbstract;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/assets/Source/ClassTypeConstraintAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 970f27dc1c40938449349f883d0abd5d
3 | timeCreated: 1494476848
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Source/ClassTypeReference.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | using System;
5 | using UnityEngine;
6 | using UnityEngine.Serialization;
7 |
8 | namespace Rotorz.Games.Reflection
9 | {
10 | ///
11 | /// Reference to a class with support for Unity serialization.
12 | ///
13 | [Serializable]
14 | public sealed class ClassTypeReference : ISerializationCallbackReceiver
15 | {
16 | public static string GetClassRef(Type type)
17 | {
18 | return type != null
19 | ? type.FullName + ", " + type.Assembly.GetName().Name
20 | : "";
21 | }
22 |
23 |
24 | [SerializeField, FormerlySerializedAs("_classRef")]
25 | private string classRef;
26 |
27 |
28 | private Type type;
29 |
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | ///
34 | public ClassTypeReference()
35 | {
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | /// Assembly qualified class name.
42 | public ClassTypeReference(string assemblyQualifiedClassName)
43 | {
44 | this.Type = !string.IsNullOrEmpty(assemblyQualifiedClassName)
45 | ? Type.GetType(assemblyQualifiedClassName)
46 | : null;
47 | }
48 |
49 | ///
50 | /// Initializes a new instance of the class.
51 | ///
52 | /// Class type.
53 | ///
54 | /// If is not a class type.
55 | ///
56 | public ClassTypeReference(Type type)
57 | {
58 | this.Type = type;
59 | }
60 |
61 |
62 | ///
63 | /// Gets or sets type of class reference.
64 | ///
65 | ///
66 | /// If is not a class type.
67 | ///
68 | public Type Type {
69 | get { return this.type; }
70 | set {
71 | if (value != null && !value.IsClass) {
72 | throw new ArgumentException(string.Format("'{0}' is not a class type.", value.FullName), "value");
73 | }
74 |
75 | this.type = value;
76 | this.classRef = GetClassRef(value);
77 | }
78 | }
79 |
80 |
81 | void ISerializationCallbackReceiver.OnAfterDeserialize()
82 | {
83 | if (!string.IsNullOrEmpty(this.classRef)) {
84 | this.type = System.Type.GetType(this.classRef);
85 |
86 | if (this.type == null) {
87 | Debug.LogWarning(string.Format("'{0}' was referenced but class type was not found.", this.classRef));
88 | }
89 | }
90 | else {
91 | this.type = null;
92 | }
93 | }
94 |
95 | void ISerializationCallbackReceiver.OnBeforeSerialize()
96 | {
97 | }
98 |
99 |
100 | public static implicit operator string(ClassTypeReference typeReference)
101 | {
102 | return typeReference.classRef;
103 | }
104 |
105 | public static implicit operator Type(ClassTypeReference typeReference)
106 | {
107 | return typeReference.Type;
108 | }
109 |
110 | public static implicit operator ClassTypeReference(Type type)
111 | {
112 | return new ClassTypeReference(type);
113 | }
114 |
115 | public override string ToString()
116 | {
117 | return this.Type != null ? this.Type.FullName : "(None)";
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/assets/Source/ClassTypeReference.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bd58c46d158910445bc6dd4947b5650c
3 | timeCreated: 1494476848
4 | licenseType: Pro
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/assets/Source/_assembly.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rotorz.unity3d-class-type-reference"
3 | }
4 |
--------------------------------------------------------------------------------
/assets/Source/_assembly.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: defade650d4200943bb41a087ec43f59
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | throw new Error("This package is not supposed to be used directly.");
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rotorz/unity3d-class-type-reference",
3 | "version": "1.0.4",
4 | "description": "A class which provides serializable references to `System.Type` of classes with an accompanying custom property drawer which allows class selection from drop-down.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/rotorz/unity3d-class-type-reference"
12 | },
13 | "author": "Rotorz Limited",
14 | "license": "MIT",
15 | "keywords": [
16 | "unity3d",
17 | "unity3d-package"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rotorz/unity3d-class-type-reference/de57a9c7d86af306031a6e735aefb6ef728cd314/screenshot.png
--------------------------------------------------------------------------------