Files
se-launcher/PluginLoader/Compiler/RoslynReferences.cs

135 lines
4.2 KiB
C#

using System.Reflection;
using System.Text;
using HarmonyLib;
using Microsoft.CodeAnalysis;
namespace PluginLoader.Compiler;
public static class RoslynReferences
{
private static readonly Dictionary<string, MetadataReference> allReferences = new();
private static readonly HashSet<string> referenceBlacklist = new(new[] { "System.ValueTuple" });
public static void GenerateAssemblyList()
{
if (allReferences.Count > 0)
return;
var harmonyInfo = typeof(Harmony).Assembly.GetName();
var loadedAssemblies = new Stack<Assembly>(AppDomain.CurrentDomain.GetAssemblies().Where(IsValidReference));
var sb = new StringBuilder();
sb.AppendLine();
var line = "===================================";
sb.AppendLine(line);
sb.AppendLine("Assembly References");
sb.AppendLine(line);
try
{
foreach (var a in loadedAssemblies)
{
// Prevent other Harmony versions from being loaded
var name = a.GetName();
if (name.Name == harmonyInfo.Name && name.Version != harmonyInfo.Version)
{
LogFile.WriteLine(
$"WARNING: Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
continue;
}
AddAssemblyReference(a);
sb.AppendLine(a.FullName);
}
sb.AppendLine(line);
while (loadedAssemblies.Count > 0)
{
var a = loadedAssemblies.Pop();
foreach (var name in a.GetReferencedAssemblies())
{
// Prevent other Harmony versions from being loaded
if (name.Name == harmonyInfo.Name && name.Version != harmonyInfo.Version)
{
LogFile.WriteLine(
$"WARNING: Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
continue;
}
if (!ContainsReference(name) && TryLoadAssembly(name, out var aRef) && IsValidReference(aRef))
{
AddAssemblyReference(aRef);
sb.AppendLine(name.FullName);
loadedAssemblies.Push(aRef);
}
}
}
sb.AppendLine(line);
}
catch (Exception e)
{
sb.Append("Error: ").Append(e).AppendLine();
}
LogFile.WriteLine(sb.ToString(), false);
}
private static bool ContainsReference(AssemblyName name)
{
return allReferences.ContainsKey(name.Name);
}
private static bool TryLoadAssembly(AssemblyName name, out Assembly aRef)
{
try
{
aRef = Assembly.Load(name);
return true;
}
catch (IOException)
{
aRef = null;
return false;
}
}
private static void AddAssemblyReference(Assembly a)
{
var name = a.GetName().Name;
if (!allReferences.ContainsKey(name))
allReferences.Add(name, MetadataReference.CreateFromFile(a.Location));
}
public static IEnumerable<MetadataReference> EnumerateAllReferences()
{
return allReferences.Values;
}
private static bool IsValidReference(Assembly a)
{
return !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location) && !referenceBlacklist.Contains(a.GetName().Name);
}
public static void LoadReference(string name)
{
try
{
var aName = new AssemblyName(name);
if (!allReferences.ContainsKey(aName.Name))
{
var a = Assembly.Load(aName);
LogFile.WriteLine("Reference added at runtime: " + a.FullName);
MetadataReference aRef = MetadataReference.CreateFromFile(a.Location);
allReferences[a.GetName().Name] = aRef;
}
}
catch (IOException)
{
LogFile.WriteLine("WARNING: Unable to find the assembly '" + name + "'!");
}
}
}