- Home /
Editor assembly
I am working on a editor class that needs access to another of my classes that is in another namespace. However, this throws an error that the referenced class does not exist. In addition, when I used reflection to look through the assembly, I found none of the other classes I have made.
Do the editor classes get assembled in a different place than the rest of the scripts?
Um, you shouldn't be using namespaces. Do you mean System.Reflection
?
Well, this is an ancient problem that I don't need fixed. The reason I use namespaces for most of my more complicated stuff is I do a lot of work with the $$anonymous$$S CLR. It's fine as long as you don't see them from within Unity, just scripts.
The editor scripts are compiled into a different assembly than the runtime scripts, which answers my question.
Interesting. I am working to find a list of $$anonymous$$onoBehavior's subclasses in an EditorWindow. This code seems to grab the Editor assembly (not surprising) rather than the player's assembly. In your code travels, did you ever come across a way to reference the assembly containing all the $$anonymous$$onoBehaviors? Here's my code in an EditorWindow that grabs from the wrong assembly right now.
public class TypePickerEditorWindow : EditorWindow
{
List<string> typeNames = new List<string>();
List<Type> typeTypes = new List<Type>();
void Awake()
{
// List all C# class Types that are subclasses of $$anonymous$$onoBehavior
Assembly asm = Assembly.GetExecutingAssembly(); // Wrong assembly!!
foreach( Type type in asm.GetTypes() )
{
if ( type.IsSubclassOf( typeof($$anonymous$$onoBehaviour) ) )
{
typeNames.Add( ""+ type );
typeTypes.Add( type );
}
}
}
}
Any thoughts, guesses, advice?
The easiest way to get around this is to do Assembly.GetAssembly(SomeClassInRuntime.class);
Answer by Bunny83 · Apr 13, 2012 at 12:18 PM
Unity compiles your scripts into several Assemblies. One first-pass, one "second pass" (normal) and one editor assembly for each language! That means in the worst case you have 9 assemblies (when you use all 3 languages, each one has scripts in the Asset folder, Standard Assets folder and editor folder).
This little script gives you all loaded assemblies:
// C#
System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var A in assemblies)
{
Debug.Log(A.FullName);
}
In my test project it returns those:
System.Runtime.Serialization
System.Xml
Boo.Lang
UnityScript.Lang
I18N.West
I18N
StrumpyShaderEditor
PluginBase
Ionic.Zip
ClassLibrary1
ICSharpCode.SharpZipLib
99aa27bda4361f14daa122d8422328a8 // those are my script assemblies
6dac0c9e57c785f48af23cab4b6a9065 //
e5fb0309aa8d3f343b2426d5b5cbb406 // I have used C# and UnityScript
89151c5adb8fb004db23eed2920f5f0b // so there are 6 assemblies ;)
0ffeb8055303a1e42bd4fe4f136bb35d //
1998a47c8bf283646903c1fefb57955f //
System.Core
Mono.Cecil
System
UnityEditor
UnityEngine
mscorlib
Unity have to do this so other languages can use an assembly from another language. However to use an assembly it has to be compiled first. That's why we have a first pass and a second pass assembly. The first-pass assemblies can't use each other. They are compiled at the same time so they can't reference each other.
The second-pass assemblies are compiled next so they can use all first-pass assemblies, but not other second-pass assemblies. That's why you have to put scripts that should be accessible from another language in a first-pass folder (Standard Assets, plugins).
Editor assemblies, which are only build and used in the editor, are compiled last so they can use all previous assemblies.
To get a complete list of certain classes you have to crawl through all assemblies.
Here's a helper function that returns all types derived from a certain baseclass:
public static System.Type[] GetAllSubTypes(System.Type aBaseClass)
{
var result = new System.Collections.Generic.List<System.Type>();
System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var A in AS)
{
System.Type[] types = A.GetTypes();
foreach (var T in types)
{
if (T.IsSubclassOf(aBaseClass))
result.Add(T);
}
}
return result.ToArray();
}
void Start ()
{
foreach (var T in GetAllSubTypes(typeof(MonoBehaviour)))
{
Debug.Log(T.Name);
}
}
Final note: You can put your classes into namespaces without any problems. However Unity "extracts" classes that are derived from MonoBehaviour into the global namespace. That's why namespaces for MonoBehaviours become irrelevant. You can't have two MonoBehaviours (or Editor, EditorWindows, ...) with the same name, even when they are in different namespaces.
Thanks, I found this out when I was trying to answer the question originally.
On another note, Unity said that they are going to support namespaces in the future. Do you know if that was still happening? It would make life a lot easier.
Yes i've heard about that too, but yet we don't have namespace support for scripts. I guess it's not that easy. Think about AddComponent and namespaces. All $$anonymous$$onoBehaviours get registrated in the AssetDatabase and they need a unique name. There's a lot that has to be modified and don't forget that they always want to keep the player compatible with old projects.
There's nothing worse than a software that can't open it's own files ;) (I just remember the old $$anonymous$$S Paint... you could open pcx file and save as pcx, but it can't open it's own created pcx file xD )
Of course namespaces would be nice since it's a very basic feature of the language itself, but i guess it will take some time...
Answer by kenlane22 · Apr 20, 2012 at 03:54 AM
Thanks for the excellent and prompt responses. Below is the Editor class I created. It lets you pick from a list of all available Component classes and then lists the GameObjects that have the component you picked on them (with buttons to select and show 'F'-style in Scene).
[Updated 9/10/12 to base from Component (thnx, Bunny83 and mviuk for the guidance. I also alphabetized the list and nixed the checkboxes until I get around to making them cause selection.]
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Reflection;
using System;
using GSES;
public class TypePickerEditorWindow : EditorWindow
{
Vector2 scrollPos, scrollPos2;
List<bool> checkBools = new List<bool>();
string filter = "";
class NameAndType
{
public NameAndType( string n, Type t ) { name = n; type = t; }
public string name;
public Type type;
}
List<NameAndType> typeList = new List<NameAndType>();
Type m_currType = null;
void Awake()
{
// List all C# class Types that are subclasses of Component
typeList.Clear();
foreach( Type type in GetAllSubTypes( typeof(Component) ) )
{
typeList.Add( new NameAndType( type.Name, type ) );
}
typeList.Sort( delegate(NameAndType a, NameAndType b) { return a.name.CompareTo(b.name); });
}
public static System.Type[] GetAllSubTypes(System.Type aBaseClass)
{
var result = new System.Collections.Generic.List<System.Type>();
System.Reflection.Assembly[] AS = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var A in AS)
{
System.Type[] types = A.GetTypes();
foreach (var T in types)
{
if (T.IsSubclassOf(aBaseClass))
result.Add(T);
}
}
return result.ToArray();
}
void OnGUI()
{
GUILayout.Label( "Pick a Component type, then click buttons to select GameObjects." );
GUILayout.BeginHorizontal();
{
GUILayout.BeginVertical();
{
GUILayout.BeginHorizontal();
{
GUILayout.Label( "Filter:", GUILayout.Width(45) );
filter = GUILayout.TextField( filter );
}
GUILayout.EndHorizontal();
scrollPos2 = GUILayout.BeginScrollView( scrollPos2, GUILayout.Width(230) );
{
int n = typeList.Count;
for( int i = 0; i < n; i++ )
{
string nm = typeList[i].name;
GUI.enabled = (m_currType != typeList[i].type); // disable selected one
if (
( nm.ToUpper().Contains( filter.ToUpper() ) ) // filtered list wont bother drawning the filtered
&&
( GUILayout.Button( nm ) ) // button pushed!
)
{
m_currType = typeList[i].type;
// And set up checkboxes to all false
UnityEngine.Object[] ueoList = FindSceneObjectsOfType( m_currType );
checkBools.Clear();
for (int j = 0; j< ueoList.Length; j++)
checkBools.Add( false );
}
}
}
GUILayout.EndScrollView();
}
GUILayout.EndVertical();
GUILayout.BeginVertical();
{
if ( m_currType == null)
{
GUILayout.Label( "Pick a type in the left column." );
}
else
{
GUILayout.Label( "All GameObjects with the class: "+ m_currType.Name );
scrollPos = GUILayout.BeginScrollView( scrollPos );
{
int i = 0;
UnityEngine.Object[] ueoList = FindSceneObjectsOfType( m_currType );
foreach( UnityEngine.Object o in ueoList )
{
GUILayout.BeginHorizontal();
{
Component com = o as Component;
if ( (com != null) && (com.gameObject != null) )
{
//checkBools[i] = GUILayout.Toggle( checkBools[i],"", GUILayout.Width(20) );
if ( GUILayout.Button( NameWithParent( com.gameObject ) ) )
{
Selection.activeGameObject = com.gameObject;
}
if ( GUILayout.Button( "Show", GUILayout.Width(50) ) )
{
GameObject g = Selection.activeGameObject;
Selection.activeGameObject = com.gameObject;
if (SceneView.lastActiveSceneView != null) SceneView.lastActiveSceneView.FrameSelected();
Selection.activeGameObject = g;
}
}
i++;
}
GUILayout.EndHorizontal();
}
}
GUILayout.EndScrollView();
}
}
GUILayout.EndVertical();
}
GUILayout.EndHorizontal();
}
string NameWithParent( GameObject g )
{
return g.name;
//string s;
//if (g.transform.parent != null) return "~/"+ g.transform.parent.name +"/"+ g.name;
//else return g.name;
}
[MenuItem ("Window/TypePickerEditorWindow")]
[MenuItem ("GSE/TypePickerEditorWindow")]
static public void Init()
{
TypePickerEditorWindow editorWindow = GetWindow(typeof(TypePickerEditorWindow)) as TypePickerEditorWindow;
editorWindow.autoRepaintOnSceneChange = true;
editorWindow.Show();
}
}
Hope it comes in handy for someone.
-Ken =]
Nice one. You might want to post it one the unifycommunity wiki as well
Great script, you may want to do your sub stype checking on Behaviour ins$$anonymous$$d of $$anonymous$$onoBehaviour, that way you don't need to do camera manually and you get other behaviours too like Animation.
Well, you can simply search for all "Components" ins$$anonymous$$d of $$anonymous$$onoBehaviour. This will include all components that can be attached to a gameobject including Transform, Colliders, Rigidbodiy, Renderers, ... which are not Behaviours.
Thanks for the tips, Bunny83 & mviuk. I updated the script to base from Component and went ahead and alphabetized the list. Getting closer to truly useful. Next up, add checkboxes that multi-select in hierarchy and Select All/None buttons on the right column. Then off to the unify wiki with it. -$$anonymous$$en =]
How can you find classes that do not use mono-behaviour?