- Home /
Force Unity to recompile scripts
Hi all,
I would like to know if it's possible to tell Unity (in the editor) to recompile scripts (just like when you tab in/out of Unity and it checks for changes and recompiles).
The reason I am asking is because I have made an editor script which (through a menu item) makes some changes to script files. The problem is that these changes do not show up until you tab out/in of Unity to make it recompile. If I could make Unity recompile automatically that would be awesome.
Thanks for any input!
/Simon
Answer by Bunny83 · Mar 14, 2013 at 01:06 PM
AssetDatabase.Refresh should do what you want.
AssetDatabase.ImportAsset will allow you to update only a specific asset.
Thank you very much, that's exactly what I was looking for :)
I've tested this adding a custom script text file and, unfortunately, it doesn't return a valid class from the monoscript that is created.
I don't have the feeling your comment is even partly related to the question or my answer. If you have a problem, ask a seperate question and be more specific about your problem.
$$anonymous$$onoScript is just a TextAsset which provides a way to get the System.Type for the $$anonymous$$onoBehaviour or ScriptableObject in that script file. I think you may have misunderstood what $$anonymous$$onoScript is good for. Again, if you have a question, Ask a Question.
@Bunny83 I'm sorry if I offended you. That wasn't my intent. I was merely adding a comment to anyone who stumbled upon this as I did and found that, although marked as correct, it didn't provide a synchronous update to the project. Again, sorry if I offended you.
Lee
Answer by rfadeev · Jun 01, 2020 at 08:44 AM
Unity 2019.3 introduced public editor API to force scripts recompilation: it's UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation
method. Tested it with hooking to assembly compilation started/finished events and this method indeed recompiles all scripts in the project.
For Unity versions from Unity 2017.1 to Unity 2019.2 can call UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface.DirtyAllScripts
via reflection. DirtyAllScripts
is the method Unity 2019.3 calls internally from RequestScriptCompilation
method (see reference). Sadly for Unity versions older than 2017.1 I'm not sure DirtyAllScripts
is present since Unity C# reference has no source code for that Unity versions.
Simple editor window to force scripts recompilation on button click (tested with Unity 2019.3.0f6 and Unity 2017.1.1f1):
using UnityEditor;
#if UNITY_2019_3_OR_NEWER
using UnityEditor.Compilation;
#elif UNITY_2017_1_OR_NEWER
using System.Reflection;
#endif
using UnityEngine;
namespace PumpEditor
{
public class CompilationWindow : EditorWindow
{
[MenuItem("Window/Pump Editor/Compilation")]
private static void ShowWindow()
{
var window = EditorWindow.GetWindow<CompilationWindow>();
window.titleContent = new GUIContent("Compilation");
window.Show();
}
private void OnGUI()
{
if (GUILayout.Button("Request Script Compilation"))
{
#if UNITY_2019_3_OR_NEWER
CompilationPipeline.RequestScriptCompilation();
#elif UNITY_2017_1_OR_NEWER
var editorAssembly = Assembly.GetAssembly(typeof(Editor));
var editorCompilationInterfaceType = editorAssembly.GetType("UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface");
var dirtyAllScriptsMethod = editorCompilationInterfaceType.GetMethod("DirtyAllScripts", BindingFlags.Static | BindingFlags.Public);
dirtyAllScriptsMethod.Invoke(editorCompilationInterfaceType, null);
#endif
}
}
}
}
THIS is exactly what I was looking for! Thank you! :D
Answer by darbotron · Jun 30, 2016 at 09:07 PM
I know this question is years out of date, but I've just run into a situation where AssetDatabase.Refresh() and AssetDatabase.ImportAsset() don't seem to cause a recompile.
I'm using some editor scripts to keep multiple copies of several of the .asset files in the ProjectSettingsFolder - this allows me to have multiple build configurations set up with different scripting defines, different scenes, etc.
Each build configuration has its own copies of the .asset files stored in a folder and I copy them over the ones in the main ProjectSettings folder to change build configuration.
Normally if you edit the scripting defines in the player settings inspector this triggers a recompile, but this doesn't seem to happen if you copy a new ProjectSettings.asset file over the main one from script.
AssetDatabase.Refresh() and ImportAsset() also didn't seem to help.
Whilst messing about with some other editor code recently I noticed that when a script execution order is changed this forces a recompile of all scripts, so I'm using this snippet of code to force a recompile of all scripts after I change the settings file and it seems to work reliably (N.B. this will only work in editor code)
MonoScript cMonoScript = MonoImporter.GetAllRuntimeMonoScripts()[ 0 ];
MonoImporter.SetExecutionOrder( cMonoScript, MonoImporter.GetExecutionOrder( cMonoScript ) );
As you can see it makes a change that doesn't change anything, but this seems to trigger a complete recompile of all scripts :)
Hope this helps someone :)
Update (November 2016):
Apparently MonoImporter is now undocumented so this technique may stop working soon.
Another way to force a recompile manually is to change the scripting define symbols (in the player settings window) to a new value.
It is possible to set this from script using PlayerSettings.SetScriptingDefineSymbolsForGroup() and one of the plugins I bought off the asset store seems to use this method to force a recompile but I've yet to need to try it so I can't offer sourcecode.
The one thing to mention to anyone thinking of trying this is that I would assume the editor only triggers a recompile if the symbols you pass are different to the ones already set...
Update (June 2018): The MonoImporter method no longer seems to work.
I'm now using PlayerSettings.SetScriptingDefineSymbolsForGroup() as mentioned above.
The code I have adds a dummy symbol to the end of the symbols which has a number in it - e.g. "_dummy_0".
Each time I need to force it again I parse the symbol string to find the number on the end, remove the existing symbol and add a new one with a number one higher (which wraps back to 0 eventually).
FWIW you could just use 2 different unique symbols and swap which you use each time which would be simpler but I've written the code now ;)
Very handy! I was having the same problem. AssetDatabase.Refresh() seems somewhat unreliable. It seemed to work when I had Unity opened normally, but in batch mode, it was giving me trouble. This method seems to work in both cases!
Works like a charm! Thank you very much! There's one caveat though: $$anonymous$$onoImporter is now undocumented (at least since version 5.4, AFAI$$anonymous$$).
Modifying the defines works very well for force-recompiling scripts. However, still, Unity Package Manager does not update and resolve until we hit "Ctrl+r" (We modify the hash value of git packages in Packages/packages-lock.json
in order to update git packages from the script.). Any ideas? (Using Unity 2019.4.33f1)
Answer by Landern · Mar 14, 2013 at 12:57 PM
Have you tried Clicking Assets->Refresh Assets(or ctrl+r in windows cmd+r on mac)?
The script(s)/class(es) should reload automagically as long as you actually saved them in your editor of choice, at least that has been my experience.
Answer by ShawnFeatherly · Jan 16, 2019 at 09:46 PM
This is an implementation of @darbotron answer. @darbotron did the findings and idea in his update from June 2018. Tested working in Unity 2018.2.0
public static void ForceRebuild()
{
string[] rebuildSymbols = { "RebuildToggle1", "RebuildToggle2" };
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup);
if (definesString.Contains(rebuildSymbols[0]))
{
definesString = definesString.Replace(rebuildSymbols[0], rebuildSymbols[1]);
}
else if (definesString.Contains(rebuildSymbols[1]))
{
definesString = definesString.Replace(rebuildSymbols[1], rebuildSymbols[0]);
}
else
{
definesString += ";" + rebuildSymbols[0];
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup,
definesString);
}
There an even more elegant way that only alters the Symbols for a moment so they don't get polluted permanently:
public static void ForceRebuild()
{
string[] rebuildSymbols = { "RebuildToggle1", "RebuildToggle2" };
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup);
var definesStringTemp = definesString;
if (definesStringTemp.Contains(rebuildSymbols[0]))
{
definesStringTemp = definesStringTemp.Replace(rebuildSymbols[0], rebuildSymbols[1]);
}
else if (definesStringTemp.Contains(rebuildSymbols[1]))
{
definesStringTemp = definesStringTemp.Replace(rebuildSymbols[1], rebuildSymbols[0]);
}
else
{
definesStringTemp += ";" + rebuildSymbols[0];
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup,
definesStringTemp);
PlayerSettings.SetScriptingDefineSymbolsForGroup(
EditorUserBuildSettings.selectedBuildTargetGroup,
definesString);
}
A simple way:
public static void RecompileUnityEditor()
{
BuildTargetGroup target = Utility.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
string rawSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(target);
PlayerSettings.SetScriptingDefineSymbolsForGroup(target, rawSymbols + "a");
PlayerSettings.SetScriptingDefineSymbolsForGroup(target, rawSymbols);
}
Your answer
Follow this Question
Related Questions
Pressing 'Play' always triggers a recompile (and so breaks game) 0 Answers
ScriptChangesWhilePlaying option "Stop Playing and Recompile" not working as expected 1 Answer
Custom Editor for Map/Dictionary in Unity 0 Answers
How to build an editor window with a treeview widget? 4 Answers
How can I fix my blurry editor? 0 Answers