- Home /
How can I wait for Unity to recompile during the execution of an editor script?
I have an editor script that creates other scripts when it is run. Immediately after creating these new scripts, the editor script needs to access them (e.g., by adding their components to objects, setting references, etc.). Thus, I need a way to make my editor script wait for Unity to recompile before it tries to access these newly-created scripts.
Answer by Adam-Mechtley · Apr 14, 2010 at 07:06 PM
I think I found a workaround solution for this problem:
- Immediately after I create my script using StreamWriter, I call AssetDatabase.ImportAsset using ImportAssetOptions.ForceSynchronousImport.
- I then try to add the component that my procedurally-generated script has created.
- If the result of the AddComponent call is null, then I call AssetDatabase.ImportAsset on the asset I am postprocessing. The second time it imports, the class exists.
To clarify, the process basically works like this:
If the script already exists and its contents are identical, then just proceed to link references.
If the script already exists and its contents are different, but its fields are identical to the inco$$anonymous$$g replacement script, then call ImportAsset forcing synchronous and then proceed to link references.
If the script does not already exist, or if it exists but the fields have changed, then call ImportAsset forcing synchronous and immediately reimport the current asset. The next time it runs, it will do path 1.
If I use reflection on the class after the initial import of the new script, the assembly claims it exists though I cannot add the component, so the second importation may be giving the assemblies time to rebuild?
Interesting. I wish I could get this to work. Don't suppose you've any code examples you could show?
I'm also very confused about this. Can you give me any example code about that?
Answer by qJake · Apr 03, 2010 at 08:29 PM
I don't think that's possible. There is no "OnCompiled" event or anything of that nature.
I think your best bet would be to tell your script to wait for a few seconds (enough time to where you would be sure the scripts have compiled) and then try to access them. You can use a coroutine (and yield return WaitForSeconds(x)), or you can start a new thread and use Thread.Sleep(<milliseconds>).
Unfortunately you can't use Untiy's coroutines in the editor, but you can use threads or implement your own coroutine handler.
http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
Answer by Lucas Meijer 1 · Apr 03, 2010 at 09:13 PM
I think you can achieve this by leveraging the fact that when Unity reloads scripts, it completely serializes all editor windows (including yours), shuts down mono, starts mono, and deserializes all editor windows.
If you can detect that this process has happened, you're probably good to go.
I think you can recognize this by stuffing a value into a field that is not serialized, and then keep monitoring that value in OnGUI() (or something else that happens frequently). As soon as your variable is gone, that means your scripts have reloaded.
make sure not to do the check in a tight loop, but instead let unity "breathe", and check from a OnGUI() method or similar.
Hi Lucas
$$anonymous$$y editor script actually extends AssetPostProcessor, not ScriptableObject, so I don't have an OnGUI() function. I am guessing there is therefore also no way for me to start a coroutine to do a similar thing?
I did exactly as Lucas described to monitor the re-creation of the editor window and it worked perfectly. Thank you.
Answer by Molix · Apr 12, 2010 at 04:09 PM
Maybe you can yield on EditorApplication.isCompiling?
That sounds like it would work, but unfortunately I cannot yield inside an AssetPostprocessor script
Answer by Tommynator · Oct 27, 2011 at 07:47 AM
Another solution to have a sort of OnPostBuildEvent in Unity is hidden in the AssetPostProcessor class. Save this little snippet in your editor folder and you will get an automatic call whenever compilation finished.
class MyAllPostprocessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(
string[] importedAssets,
string[] deletedAssets,
string[] movedAssets,
string[] movedFromAssetPaths)
{
Debug.Log("Hello OnPostBuildEvent");
}
}