Skip to content
This repository was archived by the owner on Jun 29, 2025. It is now read-only.

Commit 32dd0aa

Browse files
authored
Merge pull request #51 from sepluginloader/dev
v1.12.0
2 parents 19b71f3 + d089898 commit 32dd0aa

34 files changed

+1404
-215
lines changed

PluginLoader/AssemblyResolver.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using Mono.Cecil;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
7+
8+
namespace avaness.PluginLoader
9+
{
10+
public class AssemblyResolver
11+
{
12+
private readonly HashSet<string> allowedAssemblyNames = new HashSet<string>();
13+
private readonly HashSet<string> allowedAssemblyFiles = new HashSet<string>();
14+
private readonly List<string> sourceFolders = new List<string>();
15+
private readonly Dictionary<string, string> assemblies = new Dictionary<string, string>();
16+
private bool enabled;
17+
18+
public event Action<string> AssemblyResolved;
19+
20+
public AssemblyResolver()
21+
{
22+
23+
}
24+
25+
/// <summary>
26+
/// Adds an assembly to the list of assemblies that are allowed to request from this resolver.
27+
/// </summary>
28+
public void AddAllowedAssemblyName(string assemblyName)
29+
{
30+
allowedAssemblyNames.Add(assemblyName);
31+
}
32+
33+
/// <summary>
34+
/// Adds an assembly to the list of assemblies that are allowed to request from this resolver.
35+
/// </summary>
36+
public void AddAllowedAssemblyFile(string assemblyFile)
37+
{
38+
allowedAssemblyFiles.Add(Path.GetFullPath(assemblyFile));
39+
}
40+
41+
/// <summary>
42+
/// Adds a folder of assemblies to resolve.
43+
/// </summary>
44+
public void AddSourceFolder(string folder, SearchOption fileSearch = SearchOption.TopDirectoryOnly)
45+
{
46+
if (!Directory.Exists(folder))
47+
return;
48+
49+
sourceFolders.Add(Path.GetFullPath(folder));
50+
foreach (string name in Directory.EnumerateFiles(folder, "*.dll", fileSearch))
51+
{
52+
if (!Path.GetExtension(name).Equals(".dll", StringComparison.OrdinalIgnoreCase))
53+
continue;
54+
string assemblyName = Path.GetFileNameWithoutExtension(name);
55+
if (!assemblies.ContainsKey(assemblyName))
56+
{
57+
assemblies.Add(assemblyName, name);
58+
if(!enabled)
59+
{
60+
AppDomain.CurrentDomain.AssemblyResolve += Resolve;
61+
enabled = true;
62+
}
63+
}
64+
}
65+
}
66+
67+
private Assembly Resolve(object sender, ResolveEventArgs args)
68+
{
69+
if (!IsAllowedRequest(args.RequestingAssembly))
70+
return null;
71+
72+
AssemblyName targetAssembly = new AssemblyName(args.Name);
73+
if (assemblies.TryGetValue(targetAssembly.Name, out string targetPath) && File.Exists(targetPath))
74+
{
75+
Assembly a = Assembly.LoadFile(targetPath);
76+
if (AssemblyResolved != null)
77+
AssemblyResolved.Invoke(targetPath);
78+
LogFile.WriteLine($"Resolved {targetAssembly} as {a.GetName()} for {args.RequestingAssembly.GetName()}");
79+
return a;
80+
}
81+
return null;
82+
}
83+
84+
private bool IsAllowedRequest(Assembly requestingAssembly)
85+
{
86+
if (requestingAssembly == null)
87+
return false;
88+
89+
string name = requestingAssembly.GetName().Name;
90+
91+
if (string.IsNullOrWhiteSpace(requestingAssembly.Location))
92+
return allowedAssemblyNames.Contains(name);
93+
94+
string location = Path.GetFullPath(requestingAssembly.Location);
95+
96+
if (allowedAssemblyFiles.Contains(location))
97+
return true;
98+
99+
if (sourceFolders.Any(x => location.StartsWith(x, StringComparison.OrdinalIgnoreCase)))
100+
return true;
101+
102+
return allowedAssemblyNames.Contains(name);
103+
}
104+
}
105+
}

PluginLoader/Compiler/RoslynCompiler.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.CodeAnalysis;
1+
using avaness.PluginLoader.Network;
2+
using Microsoft.CodeAnalysis;
23
using Microsoft.CodeAnalysis.CSharp;
34
using Microsoft.CodeAnalysis.Emit;
45
using Microsoft.CodeAnalysis.Text;
@@ -14,6 +15,7 @@ namespace avaness.PluginLoader.Compiler
1415
public class RoslynCompiler
1516
{
1617
private readonly List<Source> source = new List<Source>();
18+
private readonly List<MetadataReference> customReferences = new List<MetadataReference>();
1719
private bool debugBuild;
1820

1921
public RoslynCompiler(bool debugBuild = false)
@@ -38,7 +40,7 @@ public byte[] Compile(string assemblyName, out byte[] symbols)
3840
CSharpCompilation compilation = CSharpCompilation.Create(
3941
assemblyName,
4042
syntaxTrees: source.Select(x => x.Tree),
41-
references: RoslynReferences.EnumerateAllReferences(),
43+
references: RoslynReferences.EnumerateAllReferences().Concat(customReferences),
4244
options: new CSharpCompilationOptions(
4345
OutputKind.DynamicallyLinkedLibrary,
4446
optimizationLevel: debugBuild ? OptimizationLevel.Debug : OptimizationLevel.Release,
@@ -72,7 +74,7 @@ public byte[] Compile(string assemblyName, out byte[] symbols)
7274
Location location = diagnostic.Location;
7375
Source source = this.source.FirstOrDefault(x => x.Tree == location.SourceTree);
7476
LinePosition pos = location.GetLineSpan().StartLinePosition;
75-
LogFile.WriteLine($"{diagnostic.Id}: {diagnostic.GetMessage()} in file:\n{source?.Name ?? "null"} ({pos.Line + 1},{pos.Character + 1})");
77+
LogFile.Error($"{diagnostic.Id}: {diagnostic.GetMessage()} in file:\n{source?.Name ?? "null"} ({pos.Line + 1},{pos.Character + 1})");
7678
}
7779
throw new Exception("Compilation failed!");
7880
}
@@ -91,6 +93,26 @@ public byte[] Compile(string assemblyName, out byte[] symbols)
9193

9294
}
9395

96+
public void TryAddDependency(string dll)
97+
{
98+
if(Path.HasExtension(dll)
99+
&& Path.GetExtension(dll).Equals(".dll", StringComparison.OrdinalIgnoreCase)
100+
&& File.Exists(dll))
101+
{
102+
try
103+
{
104+
MetadataReference reference = MetadataReference.CreateFromFile(dll);
105+
if (reference != null)
106+
{
107+
LogFile.WriteLine("Custom compiler reference: " + (reference.Display ?? dll));
108+
customReferences.Add(reference);
109+
}
110+
}
111+
catch
112+
{ }
113+
}
114+
}
115+
94116
private class Source
95117
{
96118
public string Name { get; }

PluginLoader/Compiler/RoslynReferences.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.CodeAnalysis;
2+
using NLog;
23
using System;
34
using System.Collections.Generic;
45
using System.IO;
@@ -30,6 +31,7 @@ public static void GenerateAssemblyList()
3031
sb.AppendLine("Assembly References");
3132
sb.AppendLine(line);
3233

34+
LogLevel level = LogLevel.Info;
3335
try
3436
{
3537
foreach (Assembly a in loadedAssemblies)
@@ -38,7 +40,7 @@ public static void GenerateAssemblyList()
3840
AssemblyName name = a.GetName();
3941
if (name.Name == harmonyInfo.Name && name.Version != harmonyInfo.Version)
4042
{
41-
LogFile.WriteLine($"WARNING: Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
43+
LogFile.Warn($"Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
4244
continue;
4345
}
4446

@@ -60,7 +62,7 @@ public static void GenerateAssemblyList()
6062
// Prevent other Harmony versions from being loaded
6163
if (name.Name == harmonyInfo.Name && name.Version != harmonyInfo.Version)
6264
{
63-
LogFile.WriteLine($"WARNING: Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
65+
LogFile.Warn($"Multiple Harmony assemblies are loaded. Plugin Loader is using {harmonyInfo} but found {name}");
6466
continue;
6567
}
6668

@@ -77,9 +79,10 @@ public static void GenerateAssemblyList()
7779
catch (Exception e)
7880
{
7981
sb.Append("Error: ").Append(e).AppendLine();
82+
level = LogLevel.Error;
8083
}
8184

82-
LogFile.WriteLine(sb.ToString(), false);
85+
LogFile.WriteLine(sb.ToString(), level, gameLog: false);
8386
}
8487

8588
/// <summary>
@@ -141,7 +144,7 @@ public static void LoadReference(string name)
141144
}
142145
catch (IOException)
143146
{
144-
LogFile.WriteLine("WARNING: Unable to find the assembly '" + name + "'!");
147+
LogFile.Warn("Unable to find the assembly '" + name + "'!");
145148
}
146149
}
147150
}

PluginLoader/Config/PluginConfig.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,14 @@ public void Init(PluginList plugins)
145145

146146
foreach (KeyValuePair<string, PluginData> kv in enabledPlugins.Where(x => x.Value == null).ToArray())
147147
{
148-
LogFile.WriteLine($"{kv.Key} was in the config but is no longer available");
148+
LogFile.Warn($"{kv.Key} was in the config but is no longer available");
149149
enabledPlugins.Remove(kv.Key);
150150
save = true;
151151
}
152152

153153
foreach (string id in pluginSettings.Keys.Where(x => !plugins.Contains(x)).ToArray())
154154
{
155-
LogFile.WriteLine($"{id} had settings in the config but is no longer available");
155+
LogFile.Warn($"{id} had settings in the config but is no longer available");
156156
pluginSettings.Remove(id);
157157
save = true;
158158
}
@@ -202,7 +202,7 @@ public void Save()
202202
}
203203
catch (Exception e)
204204
{
205-
LogFile.WriteLine($"An error occurred while saving plugin config: " + e);
205+
LogFile.Error($"An error occurred while saving plugin config: " + e);
206206
}
207207
}
208208

@@ -222,7 +222,7 @@ public static PluginConfig Load(string mainDirectory)
222222
}
223223
catch (Exception e)
224224
{
225-
LogFile.WriteLine($"An error occurred while loading plugin config: " + e);
225+
LogFile.Error($"An error occurred while loading plugin config: " + e);
226226
}
227227
}
228228

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System.IO;
2+
using System.Xml.Serialization;
3+
4+
namespace avaness.PluginLoader.Data
5+
{
6+
public partial class GitHubPlugin
7+
{
8+
public class AssetFile
9+
{
10+
public enum AssetType { Asset, Lib, LibContent }
11+
12+
public string Name { get; set; }
13+
public string Hash { get; set; }
14+
public long Length { get; set; }
15+
public AssetType Type { get; set; }
16+
[XmlIgnore]
17+
public string BaseDir { get; set; }
18+
19+
public string NormalizedFileName => Name.Replace('\\', '/').TrimStart('/');
20+
21+
public string FullPath => Path.GetFullPath(Path.Combine(BaseDir, Name));
22+
23+
public AssetFile()
24+
{
25+
26+
}
27+
28+
public AssetFile(string file, AssetType type)
29+
{
30+
Name = file;
31+
Type = type;
32+
}
33+
34+
public void GetFileInfo()
35+
{
36+
string file = FullPath;
37+
if (!File.Exists(file))
38+
return;
39+
40+
FileInfo info = new FileInfo(file);
41+
Length = info.Length;
42+
Hash = LoaderTools.GetHash256(file);
43+
}
44+
45+
public bool IsValid()
46+
{
47+
string file = FullPath;
48+
if (!File.Exists(file))
49+
return false;
50+
51+
FileInfo info = new FileInfo(file);
52+
if (info.Length != Length)
53+
return false;
54+
55+
string newHash = LoaderTools.GetHash256(file);
56+
if (newHash != Hash)
57+
return false;
58+
59+
return true;
60+
}
61+
62+
public void Save(Stream stream)
63+
{
64+
string newFile = FullPath;
65+
Directory.CreateDirectory(Path.GetDirectoryName(newFile));
66+
using (FileStream file = File.Create(newFile))
67+
{
68+
stream.CopyTo(file);
69+
}
70+
71+
GetFileInfo();
72+
}
73+
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)