I’m working on a networking system for Unity which uses Cecil to inject code into the assemblies. Currently I have the following code to do this via an Editor script:
[InitializeOnLoad]
static class AssemblyPostProcessor
{
static AssemblyPostProcessor()
{
// ...
// Inject code into assemblies if needed
// ...
if( anyAssembliesWereChanged )
{
UnityEditorInternal.InternalEditorUtility.RequestScriptReload();
}
}
}
It seemed to be working - if I decompile the assemblies with ILSpy they show the injected code is there. However, when I run the game in the editor, it behaves as if the assembly has not been updated. Not just that the injected code isn’t there, but changes I’ve made to scripts have not been applied either.
If I close the Unity editor and open it again, then the updated code appears to run. Is there any way I can get eliminate this step? It would be nice to have at least a semi Unity-approved way of using Cecil in Unity projects.
JB Evain told me on twitter
simply moving the code to a DLL that you can post process before copying to the Assets folder works
It’s not ideal, but it’s a solution.
UPDATE:
I got it working without the DLL solution! The problem was that my code which processed the assembly had a bug, where I was importing a type or a function into the same module which defined it, so it was causing a cyclic reference. Once I fixed that, it seems to be working fine so far! This is excellent, as it means I get some cool parts of the workflow back such as auto compilation, and more importantly when I double click on a message in the console it makes visual studio bring up the relevant .cs file and go to the correct line.
Hi there. Another way to catch file changed event is using FileSystemWatcher. The benefit of this way is that you will get fileChanged event even if you make player build.
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections.Generic;
[InitializeOnLoad]
static class AssemblyPostProcessor
{
//Keep list of watchers to prevent GC collect
static public List<FileSystemWatcher> watchers = new List<FileSystemWatcher>();
static AssemblyPostProcessor()
{
Debug.Log("Init AssemblyPostProcessor");
RigisterOnFileChanged(Application.dataPath + "/../Library/ScriptAssemblies/Assembly-CSharp.dll", DoInject);
}
static void DoInject(string path)
{
Debug.Log("Inject dll " + path);
//Inject code here...
Debug.Log("Inject dll Done");
}
static public void RigisterOnFileChanged(string path, System.Action<string> action)
{
Debug.Log("Watch: " + Path.GetFullPath(path));
var fileSystemWatcher =
new FileSystemWatcher(Path.GetDirectoryName(path))
{
EnableRaisingEvents = true
};
fileSystemWatcher.Changed +=
(o, e) =>
{
Debug.Log("File changed:" + e.FullPath);
if(Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
{
action(path);
}
};
watchers.Add(fileSystemWatcher);
}
}