Notification when AssetDatabase.Refresh is ready
c#, unity-game-engine
Solution
Notifications
Way 1
It is funny, but you have already listed this option:
- static constructors are called immediately after refreshing is ready if their class has the InitializeOnLoadAttribute set
So, if static constructor of some class with `[InitializeOnLoadAttribute]` is invoked: it is a good sign that Unity has just rebuilt the solution.
Way 2. Black magic :)
It is undocumented, but if you add `[DidReloadScripts]` attribute to a static method in any editor class, this method will be called after Unity re-compiles scripts. See example:
public class SomeEditorClass
{
[DidReloadScripts]
public static void OnCompileScripts()
{
Debug.Log("Bla-bla-bla");
}
}
Surviving between rebuilds with editor windows
But in order to use all this to solve your problem you still need a way of storing some data between solution rebuilds. If you are doing your "operation" from editor window, here is a trick that you can use: Unity stores EditorWindow object state. So, you can do something like this:
[InitializeOnLoadAttribute]
public class YourWindow : EditorWindow
{
const string path = @"Assets/Bla-bla-bla.cs";
private static bool justRecompiled;
static YourWindow()
{
justRecompiled = true;
}
[MenuItem("Test/YourWindow")]
public static void Generate()
{
GetWindow(typeof(YourWindow));
}
private bool waitingForRecompiling;
private GameObject gameObject;
public void OnRecompile()
{
MonoScript monoScript = AssetDatabase.LoadAssetAtPath(path, typeof(MonoScript)) as MonoScript;
Type monoScriptClass = monoScript.GetClass();
if (gameObject.GetComponent(monoScriptClass) == null)
gameObject.AddComponent(monoScriptClass);
}
public void OnGUI()
{
if (GUILayout.Button("Execute"))
if (Selection.activeGameObject != null)
{
// Do your script file generation here
waitingForRecompiling = true;
gameObject = Selection.activeGameObject;
AssetDatabase.ImportAsset(path);
}
}
public void Update()
{
if (justRecompiled && waitingForRecompiling)
{
waitingForRecompiling = false;
OnRecompile();
}
justRecompiled = false;
}
}
It's a bit ugly, but still an option.
Problem
I have a Unity3D editor class that creates a new asset on the fly. Then I call AssetDatabase.Refresh using the default option (which is strongly recommended). Due to the fact that refreshing is an asynchronous way I need a way to get informed when refreshing is ready. Background: I wrote a code generator that creates a C# script. It is meant to create a helper component for the active game object in the scene. Everything works fine so far, the file is created by methods from System.File.IO. Now I want to add the newly created MonoBehaviour to the active game object automatically. Current status / limiting factors: - As expected all active objects are destroyed during the refresh process. This makes it impossible to work with any standard polling approach like invoke or coroutines as they terminate when the game object is destroyed. - Polling is in general no good solution, but would be alright in this case. On the other hand I don't want to use threads as this is not recommended in Unity. - static constructors are called immediately after refreshing is ready if their class has the InitializeOnLoadAttribute set or if the component is referred in the active scene. Possible (cumbersome) way that might work: - Define a class `ActionAfterRefresh` that contains meta information and code to perform after a refresh e.g. class name to load and code to perform an `AddComponent` for it in constructor. - Serialise this class as JSON file in a special cache directory - Define a class `Loader` having a static constructor that: - Looks if there is a matching JSON file in the cache directory. If so, create an instance and execute the code - Delete JSON file I think this could work and I guess you know why I wrote cumbersome. Is there any smarter, better, faster way to achieve this? Did I overlook the live saving OnRefreshDatabaseReady event? Thanks for your help