aha
This commit is contained in:
@ -0,0 +1,31 @@
|
||||
// tests use WeaveAssembler, which uses AssemblyBuilder to Build().
|
||||
// afterwards ILPostProcessor weaves the build.
|
||||
// this works on windows, but build() does not run ILPP on mac atm.
|
||||
// we need to manually invoke ILPP with an assembly from file.
|
||||
//
|
||||
// this is in Weaver folder becuase CompilationPipeline can only be accessed
|
||||
// from assemblies with the name "Unity.*.CodeGen"
|
||||
using System.IO;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
public class CompiledAssemblyFromFile : ICompiledAssembly
|
||||
{
|
||||
readonly string assemblyPath;
|
||||
|
||||
public string Name => Path.GetFileNameWithoutExtension(assemblyPath);
|
||||
public string[] References { get; set; }
|
||||
public string[] Defines { get; set; }
|
||||
public InMemoryAssembly InMemoryAssembly { get; }
|
||||
|
||||
public CompiledAssemblyFromFile(string assemblyPath)
|
||||
{
|
||||
this.assemblyPath = assemblyPath;
|
||||
byte[] peData = File.ReadAllBytes(assemblyPath);
|
||||
string pdbFileName = Path.GetFileNameWithoutExtension(assemblyPath) + ".pdb";
|
||||
byte[] pdbData = File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(assemblyPath), pdbFileName));
|
||||
InMemoryAssembly = new InMemoryAssembly(peData, pdbData);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9009d1db4ed44f6694a92bf8ad7738e9
|
||||
timeCreated: 1630129423
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,205 @@
|
||||
// based on paul's resolver from
|
||||
// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split
|
||||
//
|
||||
// an assembly resolver's job is to open an assembly in case we want to resolve
|
||||
// a type from it.
|
||||
//
|
||||
// for example, while weaving MyGame.dll: if we want to resolve ArraySegment<T>,
|
||||
// then we need to open and resolve from another assembly (CoreLib).
|
||||
//
|
||||
// using DefaultAssemblyResolver with ILPostProcessor throws Exceptions in
|
||||
// WeaverTypes.cs when resolving anything, for example:
|
||||
// ArraySegment<T> in Mirror.Tests.Dll.
|
||||
//
|
||||
// we need a custom resolver for ILPostProcessor.
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Mono.CecilX;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
class ILPostProcessorAssemblyResolver : IAssemblyResolver
|
||||
{
|
||||
readonly string[] assemblyReferences;
|
||||
|
||||
// originally we used Dictionary + lock.
|
||||
// Resolve() is called thousands of times for large projects.
|
||||
// ILPostProcessor is multithreaded, so best to use ConcurrentDictionary without the lock here.
|
||||
readonly ConcurrentDictionary<string, AssemblyDefinition> assemblyCache =
|
||||
new ConcurrentDictionary<string, AssemblyDefinition>();
|
||||
|
||||
// Resolve() calls FindFile() every time.
|
||||
// thousands of times for String => mscorlib alone in large projects.
|
||||
// cache the results! ILPostProcessor is multithreaded, so use a ConcurrentDictionary here.
|
||||
readonly ConcurrentDictionary<string, string> fileNameCache =
|
||||
new ConcurrentDictionary<string, string>();
|
||||
|
||||
readonly ICompiledAssembly compiledAssembly;
|
||||
AssemblyDefinition selfAssembly;
|
||||
|
||||
readonly Logger Log;
|
||||
|
||||
public ILPostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly, Logger Log)
|
||||
{
|
||||
this.compiledAssembly = compiledAssembly;
|
||||
assemblyReferences = compiledAssembly.References;
|
||||
this.Log = Log;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Cleanup
|
||||
}
|
||||
|
||||
public AssemblyDefinition Resolve(AssemblyNameReference name) =>
|
||||
Resolve(name, new ReaderParameters(ReadingMode.Deferred));
|
||||
|
||||
// here is an example on when this is called:
|
||||
// Player : NetworkBehaviour has a [SyncVar] of type String.
|
||||
// Weaver's SyncObjectInitializer checks if ImplementsSyncObject()
|
||||
// which needs to resolve the type 'String' from mscorlib.
|
||||
// Resolve() lives in CecilX.MetadataResolver.Resolve()
|
||||
// which calls assembly_resolver.Resolve().
|
||||
// which uses our ILPostProcessorAssemblyResolver here.
|
||||
//
|
||||
// for large projects, this is called thousands of times for mscorlib alone.
|
||||
// initially ILPostProcessorAssemblyResolver took 30x longer than with CompilationFinishedHook.
|
||||
// we need to cache and speed up everything we can here!
|
||||
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
|
||||
{
|
||||
if (name.Name == compiledAssembly.Name)
|
||||
return selfAssembly;
|
||||
|
||||
// cache FindFile.
|
||||
// in large projects, this is called thousands(!) of times for String=>mscorlib alone.
|
||||
// reduces a single String=>mscorlib resolve from 0.771ms to 0.015ms.
|
||||
// => 50x improvement in TypeReference.Resolve() speed!
|
||||
// => 22x improvement in Weaver speed!
|
||||
if (!fileNameCache.TryGetValue(name.Name, out string fileName))
|
||||
{
|
||||
fileName = FindFile(name.Name);
|
||||
fileNameCache.TryAdd(name.Name, fileName);
|
||||
}
|
||||
|
||||
if (fileName == null)
|
||||
{
|
||||
// returning null will throw exceptions in our weaver where.
|
||||
// let's make it obvious why we returned null for easier debugging.
|
||||
// NOTE: if this fails for "System.Private.CoreLib":
|
||||
// ILPostProcessorReflectionImporter fixes it!
|
||||
|
||||
// the fix for #2503 started showing this warning for Bee.BeeDriver on mac,
|
||||
// which is for compilation. we can ignore that one.
|
||||
if (!name.Name.StartsWith("Bee.BeeDriver"))
|
||||
{
|
||||
Log.Warning($"ILPostProcessorAssemblyResolver.Resolve: Failed to find file for {name}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// try to get cached assembly by filename + writetime
|
||||
DateTime lastWriteTime = File.GetLastWriteTime(fileName);
|
||||
string cacheKey = fileName + lastWriteTime;
|
||||
if (assemblyCache.TryGetValue(cacheKey, out AssemblyDefinition result))
|
||||
return result;
|
||||
|
||||
// otherwise resolve and cache a new assembly
|
||||
parameters.AssemblyResolver = this;
|
||||
MemoryStream ms = MemoryStreamFor(fileName);
|
||||
|
||||
string pdb = fileName + ".pdb";
|
||||
if (File.Exists(pdb))
|
||||
parameters.SymbolStream = MemoryStreamFor(pdb);
|
||||
|
||||
AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters);
|
||||
assemblyCache.TryAdd(cacheKey, assemblyDefinition);
|
||||
return assemblyDefinition;
|
||||
}
|
||||
|
||||
// find assemblyname in assembly's references
|
||||
string FindFile(string name)
|
||||
{
|
||||
// perhaps the type comes from a .dll or .exe
|
||||
// check both in one call without Linq instead of iterating twice like originally
|
||||
foreach (string r in assemblyReferences)
|
||||
{
|
||||
if (Path.GetFileNameWithoutExtension(r) == name)
|
||||
return r;
|
||||
}
|
||||
|
||||
// this is called thousands(!) of times.
|
||||
// constructing strings only once saves ~0.1ms per call for mscorlib.
|
||||
string dllName = name + ".dll";
|
||||
|
||||
// Unfortunately the current ICompiledAssembly API only provides direct references.
|
||||
// It is very much possible that a postprocessor ends up investigating a type in a directly
|
||||
// referenced assembly, that contains a field that is not in a directly referenced assembly.
|
||||
// if we don't do anything special for that situation, it will fail to resolve. We should fix this
|
||||
// in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references
|
||||
// are always located next to direct references, so we search in all directories of direct references we
|
||||
// got passed, and if we find the file in there, we resolve to it.
|
||||
foreach (string parentDir in assemblyReferences.Select(Path.GetDirectoryName).Distinct())
|
||||
{
|
||||
string candidate = Path.Combine(parentDir, dllName);
|
||||
if (File.Exists(candidate))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// open file as MemoryStream.
|
||||
// ILPostProcessor is multithreaded.
|
||||
// retry a few times in case another thread is still accessing the file.
|
||||
static MemoryStream MemoryStreamFor(string fileName)
|
||||
{
|
||||
return Retry(10, TimeSpan.FromSeconds(1), () =>
|
||||
{
|
||||
byte[] byteArray;
|
||||
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
byteArray = new byte[fs.Length];
|
||||
int readLength = fs.Read(byteArray, 0, (int)fs.Length);
|
||||
if (readLength != fs.Length)
|
||||
throw new InvalidOperationException("File read length is not full length of file.");
|
||||
}
|
||||
|
||||
return new MemoryStream(byteArray);
|
||||
});
|
||||
}
|
||||
|
||||
static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func<MemoryStream> func)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
if (retryCount == 0)
|
||||
throw;
|
||||
Console.WriteLine($"Caught IO Exception, trying {retryCount} more times");
|
||||
Thread.Sleep(waitTime);
|
||||
return Retry(retryCount - 1, waitTime, func);
|
||||
}
|
||||
}
|
||||
|
||||
// if the CompiledAssembly's AssemblyDefinition is known, we can add it
|
||||
public void SetAssemblyDefinitionForCompiledAssembly(AssemblyDefinition assemblyDefinition)
|
||||
{
|
||||
selfAssembly = assemblyDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b3e94696e22440ead0b3a42411bbe14
|
||||
timeCreated: 1629693784
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,53 @@
|
||||
// helper function to use ILPostProcessor for an assembly from file.
|
||||
// we keep this in Weaver folder because we can access CompilationPipleine here.
|
||||
// in tests folder we can't, unless we rename to "Unity.*.CodeGen",
|
||||
// but then tests wouldn't be weaved anymore.
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
using System;
|
||||
using System.IO;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
public static class ILPostProcessorFromFile
|
||||
{
|
||||
// read, weave, write file via ILPostProcessor
|
||||
public static void ILPostProcessFile(string assemblyPath, string[] references, Action<string> OnWarning, Action<string> OnError)
|
||||
{
|
||||
// we COULD Weave() with a test logger manually.
|
||||
// but for test result consistency on all platforms,
|
||||
// let's invoke the ILPostProcessor here too.
|
||||
CompiledAssemblyFromFile assembly = new CompiledAssemblyFromFile(assemblyPath);
|
||||
assembly.References = references;
|
||||
|
||||
// create ILPP and check WillProcess like Unity would.
|
||||
ILPostProcessorHook ilpp = new ILPostProcessorHook();
|
||||
if (ilpp.WillProcess(assembly))
|
||||
{
|
||||
//Debug.Log($"Will Process: {assembly.Name}");
|
||||
|
||||
// process it like Unity would
|
||||
ILPostProcessResult result = ilpp.Process(assembly);
|
||||
|
||||
// handle the error messages like Unity would
|
||||
foreach (DiagnosticMessage message in result.Diagnostics)
|
||||
{
|
||||
if (message.DiagnosticType == DiagnosticType.Warning)
|
||||
{
|
||||
OnWarning(message.MessageData);
|
||||
}
|
||||
else if (message.DiagnosticType == DiagnosticType.Error)
|
||||
{
|
||||
OnError(message.MessageData);
|
||||
}
|
||||
}
|
||||
|
||||
// save the weaved assembly to file.
|
||||
// some tests open it and check for certain IL code.
|
||||
File.WriteAllBytes(assemblyPath, result.InMemoryAssembly.PeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a4b115486b74d27a9540f3c39ae2d46
|
||||
timeCreated: 1630152191
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,143 @@
|
||||
// hook via ILPostProcessor from Unity 2020.3+
|
||||
// (2020.1 has errors https://github.com/vis2k/Mirror/issues/2912)
|
||||
#if UNITY_2020_3_OR_NEWER
|
||||
// Unity.CompilationPipeline reference is only resolved if assembly name is
|
||||
// Unity.*.CodeGen:
|
||||
// https://forum.unity.com/threads/how-does-unity-do-codegen-and-why-cant-i-do-it-myself.853867/#post-5646937
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
// to use Mono.CecilX here, we need to 'override references' in the
|
||||
// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.
|
||||
// otherwise we get a reflection exception with 'file not found: CecilX'.
|
||||
using Mono.CecilX;
|
||||
using Mono.CecilX.Cil;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
// IMPORTANT: 'using UnityEngine' does not work in here.
|
||||
// Unity gives "(0,0): error System.Security.SecurityException: ECall methods must be packaged into a system module."
|
||||
//using UnityEngine;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
public class ILPostProcessorHook : ILPostProcessor
|
||||
{
|
||||
// from CompilationFinishedHook
|
||||
const string MirrorRuntimeAssemblyName = "Mirror";
|
||||
|
||||
// ILPostProcessor is invoked by Unity.
|
||||
// we can not tell it to ignore certain assemblies before processing.
|
||||
// add a 'ignore' define for convenience.
|
||||
// => WeaverTests/WeaverAssembler need it to avoid Unity running it
|
||||
public const string IgnoreDefine = "ILPP_IGNORE";
|
||||
|
||||
// we can't use Debug.Log in ILPP, so we need a custom logger
|
||||
ILPostProcessorLogger Log = new ILPostProcessorLogger();
|
||||
|
||||
// ???
|
||||
public override ILPostProcessor GetInstance() => this;
|
||||
|
||||
// check if assembly has the 'ignore' define
|
||||
static bool HasDefine(ICompiledAssembly assembly, string define) =>
|
||||
assembly.Defines != null &&
|
||||
assembly.Defines.Contains(define);
|
||||
|
||||
// process Mirror, or anything that references Mirror
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
// compiledAssembly.References are file paths:
|
||||
// Library/Bee/artifacts/200b0aE.dag/Mirror.CompilerSymbols.dll
|
||||
// Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll
|
||||
// /Applications/Unity/Hub/Editor/2021.2.0b6_apple_silicon/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll
|
||||
//
|
||||
// log them to see:
|
||||
// foreach (string reference in compiledAssembly.References)
|
||||
// LogDiagnostics($"{compiledAssembly.Name} references {reference}");
|
||||
bool relevant = compiledAssembly.Name == MirrorRuntimeAssemblyName ||
|
||||
compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == MirrorRuntimeAssemblyName);
|
||||
bool ignore = HasDefine(compiledAssembly, IgnoreDefine);
|
||||
return relevant && !ignore;
|
||||
}
|
||||
|
||||
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
//Log.Warning($"Processing {compiledAssembly.Name}");
|
||||
|
||||
// load the InMemoryAssembly peData into a MemoryStream
|
||||
byte[] peData = compiledAssembly.InMemoryAssembly.PeData;
|
||||
//LogDiagnostics($" peData.Length={peData.Length} bytes");
|
||||
using (MemoryStream stream = new MemoryStream(peData))
|
||||
using (ILPostProcessorAssemblyResolver asmResolver = new ILPostProcessorAssemblyResolver(compiledAssembly, Log))
|
||||
{
|
||||
// we need to load symbols. otherwise we get:
|
||||
// "(0,0): error Mono.CecilX.Cil.SymbolsNotFoundException: No symbol found for file: "
|
||||
using (MemoryStream symbols = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData))
|
||||
{
|
||||
ReaderParameters readerParameters = new ReaderParameters{
|
||||
SymbolStream = symbols,
|
||||
ReadWrite = true,
|
||||
ReadSymbols = true,
|
||||
AssemblyResolver = asmResolver,
|
||||
// custom reflection importer to fix System.Private.CoreLib
|
||||
// not being found in custom assembly resolver above.
|
||||
ReflectionImporterProvider = new ILPostProcessorReflectionImporterProvider()
|
||||
};
|
||||
using (AssemblyDefinition asmDef = AssemblyDefinition.ReadAssembly(stream, readerParameters))
|
||||
{
|
||||
// resolving a Mirror.dll type like NetworkServer while
|
||||
// weaving Mirror.dll does not work. it throws a
|
||||
// NullReferenceException in WeaverTypes.ctor
|
||||
// when Resolve() is called on the first Mirror type.
|
||||
// need to add the AssemblyDefinition itself to use.
|
||||
asmResolver.SetAssemblyDefinitionForCompiledAssembly(asmDef);
|
||||
|
||||
// weave this assembly.
|
||||
Weaver weaver = new Weaver(Log);
|
||||
if (weaver.Weave(asmDef, asmResolver, out bool modified))
|
||||
{
|
||||
//Log.Warning($"Weaving succeeded for: {compiledAssembly.Name}");
|
||||
|
||||
// write if modified
|
||||
if (modified)
|
||||
{
|
||||
// when weaving Mirror.dll with ILPostProcessor,
|
||||
// Weave() -> WeaverTypes -> resolving the first
|
||||
// type in Mirror.dll adds a reference to
|
||||
// Mirror.dll even though we are in Mirror.dll.
|
||||
// -> this would throw an exception:
|
||||
// "Mirror references itself" and not compile
|
||||
// -> need to detect and fix manually here
|
||||
if (asmDef.MainModule.AssemblyReferences.Any(r => r.Name == asmDef.Name.Name))
|
||||
{
|
||||
asmDef.MainModule.AssemblyReferences.Remove(asmDef.MainModule.AssemblyReferences.First(r => r.Name == asmDef.Name.Name));
|
||||
//Log.Warning($"fixed self referencing Assembly: {asmDef.Name.Name}");
|
||||
}
|
||||
|
||||
MemoryStream peOut = new MemoryStream();
|
||||
MemoryStream pdbOut = new MemoryStream();
|
||||
WriterParameters writerParameters = new WriterParameters
|
||||
{
|
||||
SymbolWriterProvider = new PortablePdbWriterProvider(),
|
||||
SymbolStream = pdbOut,
|
||||
WriteSymbols = true
|
||||
};
|
||||
|
||||
asmDef.Write(peOut, writerParameters);
|
||||
|
||||
InMemoryAssembly inMemory = new InMemoryAssembly(peOut.ToArray(), pdbOut.ToArray());
|
||||
return new ILPostProcessResult(inMemory, Log.Logs);
|
||||
}
|
||||
}
|
||||
// if anything during Weave() fails, we log an error.
|
||||
// don't need to indicate 'weaving failed' again.
|
||||
// in fact, this would break tests only expecting certain errors.
|
||||
//else Log.Error($"Weaving failed for: {compiledAssembly.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// always return an ILPostProcessResult with Logs.
|
||||
// otherwise we won't see Logs if weaving failed.
|
||||
return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, Log.Logs);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f113eb695b348b5b28cd85358c8959a
|
||||
timeCreated: 1628859074
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using Mono.CecilX;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
public class ILPostProcessorLogger : Logger
|
||||
{
|
||||
// can't Debug.Log in ILPostProcessor. need to add to this list.
|
||||
internal List<DiagnosticMessage> Logs = new List<DiagnosticMessage>();
|
||||
|
||||
void Add(string message, DiagnosticType logType)
|
||||
{
|
||||
Logs.Add(new DiagnosticMessage
|
||||
{
|
||||
// TODO add file etc. for double click opening later?
|
||||
DiagnosticType = logType, // doesn't have .Log
|
||||
File = null,
|
||||
Line = 0,
|
||||
Column = 0,
|
||||
MessageData = message
|
||||
});
|
||||
}
|
||||
|
||||
public void LogDiagnostics(string message, DiagnosticType logType = DiagnosticType.Warning)
|
||||
{
|
||||
// TODO IN-44868 FIX IS IN 2021.3.32f1, 2022.3.11f1, 2023.2.0b13 and 2023.3.0a8
|
||||
// DiagnosticMessage can't display \n for some reason.
|
||||
// it just cuts it off and we don't see any stack trace.
|
||||
// so let's replace all line breaks so we get the stack trace.
|
||||
// (Unity 2021.2.0b6 apple silicon)
|
||||
//message = message.Replace("\n", "/");
|
||||
|
||||
// lets break it into several messages instead so it's easier readable
|
||||
string[] lines = message.Split('\n');
|
||||
|
||||
// if it's just one line, simply log it
|
||||
if (lines.Length == 1)
|
||||
{
|
||||
// tests assume exact message log.
|
||||
// don't include 'Weaver: ...' or similar.
|
||||
Add($"{message}", logType);
|
||||
}
|
||||
// for multiple lines, log each line separately with start/end indicators
|
||||
else
|
||||
{
|
||||
// first line with Weaver: ... first
|
||||
Add("----------------------------------------------", logType);
|
||||
foreach (string line in lines) Add(line, logType);
|
||||
Add("----------------------------------------------", logType);
|
||||
}
|
||||
}
|
||||
|
||||
public void Warning(string message) => Warning(message, null);
|
||||
public void Warning(string message, MemberReference mr)
|
||||
{
|
||||
if (mr != null) message = $"{message} (at {mr})";
|
||||
LogDiagnostics(message, DiagnosticType.Warning);
|
||||
}
|
||||
|
||||
public void Error(string message) => Error(message, null);
|
||||
public void Error(string message, MemberReference mr)
|
||||
{
|
||||
if (mr != null) message = $"{message} (at {mr})";
|
||||
LogDiagnostics(message, DiagnosticType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7b56e7826664e34a415e4b70d958f2a
|
||||
timeCreated: 1629533154
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,36 @@
|
||||
// based on paul's resolver from
|
||||
// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split
|
||||
//
|
||||
// ILPostProcessorAssemblyRESOLVER does not find the .dll file for:
|
||||
// "System.Private.CoreLib"
|
||||
// we need this custom reflection importer to fix that.
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Mono.CecilX;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
internal class ILPostProcessorReflectionImporter : DefaultReflectionImporter
|
||||
{
|
||||
const string SystemPrivateCoreLib = "System.Private.CoreLib";
|
||||
readonly AssemblyNameReference fixedCoreLib;
|
||||
|
||||
public ILPostProcessorReflectionImporter(ModuleDefinition module) : base(module)
|
||||
{
|
||||
// find the correct library for "System.Private.CoreLib".
|
||||
// either mscorlib or netstandard.
|
||||
// defaults to System.Private.CoreLib if not found.
|
||||
fixedCoreLib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == SystemPrivateCoreLib);
|
||||
}
|
||||
|
||||
public override AssemblyNameReference ImportReference(AssemblyName name)
|
||||
{
|
||||
// System.Private.CoreLib?
|
||||
if (name.Name == SystemPrivateCoreLib && fixedCoreLib != null)
|
||||
return fixedCoreLib;
|
||||
|
||||
// otherwise import as usual
|
||||
return base.ImportReference(name);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6403a7e3b3ae4e009ae282f111d266e0
|
||||
timeCreated: 1629709256
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs
|
||||
uploadId: 736421
|
@ -0,0 +1,16 @@
|
||||
// based on paul's resolver from
|
||||
// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split
|
||||
//
|
||||
// ILPostProcessorAssemblyRESOLVER does not find the .dll file for:
|
||||
// "System.Private.CoreLib"
|
||||
// we need this custom reflection importer to fix that.
|
||||
using Mono.CecilX;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
internal class ILPostProcessorReflectionImporterProvider : IReflectionImporterProvider
|
||||
{
|
||||
public IReflectionImporter GetReflectionImporter(ModuleDefinition module) =>
|
||||
new ILPostProcessorReflectionImporter(module);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1003b568bad4e69b961c4c81d5afd96
|
||||
timeCreated: 1629709223
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129321
|
||||
packageName: Mirror
|
||||
packageVersion: 96.0.1
|
||||
assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs
|
||||
uploadId: 736421
|
Reference in New Issue
Block a user