Created
June 12, 2021 11:23
-
-
Save OneManMonkeySquad/959c26b7364fa67e971488940bfddcbe to your computer and use it in GitHub Desktop.
Unity ILPostProcessor Cecil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Name the asmdef of your patcher Unity.SOMETHING.Codegen | |
Then edit the asmdef to include | |
"references": [ "Unity.CompilationPipeline.Common.dll" ], | |
I had to use my own Mono.Cecil dlls in the patcher directory, somehow it should be possible to reference the Unity.Cecil.dll etc. | |
Then use some code like this (Note at RpcPostProcessor.Process does the actual work here): | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using Mono.Cecil; | |
using Unity.CompilationPipeline.Common.ILPostProcessing; | |
public class Patch : ILPostProcessor { | |
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] | |
public static extern void OutputDebugString(string message); | |
public override ILPostProcessor GetInstance() { | |
return new Patch(); | |
} | |
public override bool WillProcess(ICompiledAssembly compiledAssembly) { | |
string name = compiledAssembly.Name; | |
if (name.StartsWith("Unity.") || name.StartsWith("UnityEngine.") || name.StartsWith("UnityEditor.")) | |
return false; | |
if (!compiledAssembly.References.Any(r => r.EndsWith("Cube.Replication.dll"))) | |
return false; // No reference to Replication | |
OutputDebugString($"{compiledAssembly.Name}: WillProcess"); | |
return true; | |
} | |
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) { | |
OutputDebugString($"{compiledAssembly.Name}: Start patching..."); | |
var msgs = new System.Collections.Generic.List<Unity.CompilationPipeline.Common.Diagnostics.DiagnosticMessage>(); | |
try { | |
using (var stream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData)) { | |
var resolver = new DefaultAssemblyResolver(); | |
foreach (var path in compiledAssembly.References) { | |
var dir = Path.GetDirectoryName(path); | |
if (resolver.GetSearchDirectories().Contains(dir)) | |
continue; | |
OutputDebugString($"{compiledAssembly.Name}: Search in {dir}"); | |
resolver.AddSearchDirectory(dir); | |
} | |
var readerParameters = new ReaderParameters() { | |
AssemblyResolver = resolver, | |
}; | |
using (var assembly = AssemblyDefinition.ReadAssembly(stream, readerParameters)) { | |
var rpcProcessor = new RpcPostProcessor(assembly.MainModule); | |
var anythingChanged = rpcProcessor.Process(assembly.MainModule); | |
if (!anythingChanged) { | |
OutputDebugString($"{compiledAssembly.Name}: NOTHING CHANGED"); | |
return new ILPostProcessResult(compiledAssembly.InMemoryAssembly); | |
} | |
using (var outStream = new MemoryStream()) { | |
assembly.Write(outStream); | |
OutputDebugString($"{compiledAssembly.Name}: SUCCESS"); | |
return new ILPostProcessResult(new InMemoryAssembly(outStream.ToArray(), compiledAssembly.InMemoryAssembly.PdbData), msgs); | |
} | |
} | |
} | |
} catch (System.Exception e) { | |
var msg = new Unity.CompilationPipeline.Common.Diagnostics.DiagnosticMessage(); | |
msg.DiagnosticType = Unity.CompilationPipeline.Common.Diagnostics.DiagnosticType.Error; | |
msg.MessageData = e.Message; | |
msgs.Add(msg); | |
OutputDebugString($"{compiledAssembly.Name}: FAILED {e.Message}"); | |
return new ILPostProcessResult(null, msgs); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment