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?

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 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*.name;*

GUI.enabled = (m_currType != typeList*.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*.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 _= GUILayout.Toggle( checkBools,””, 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 =]