139 lines
4.5 KiB
C#
139 lines
4.5 KiB
C#
using Cryville.Common;
|
|
using Cryville.Crtr.Extension;
|
|
using Mono.Cecil;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace Cryville.Crtr.Browsing {
|
|
internal static class ExtensionManager {
|
|
static readonly Dictionary<string, List<ResourceConverter>> _converters
|
|
= new Dictionary<string, List<ResourceConverter>>();
|
|
public static IEnumerable<string> GetSupportedFormats() {
|
|
return _converters.Keys;
|
|
}
|
|
public static bool TryGetConverters(string extension, out IEnumerable<ResourceConverter> converters) {
|
|
List<ResourceConverter> outResult;
|
|
bool result = _converters.TryGetValue(extension, out outResult);
|
|
converters = outResult;
|
|
return result;
|
|
}
|
|
static readonly Dictionary<string, string> _localRes
|
|
= new Dictionary<string, string>();
|
|
public static IReadOnlyDictionary<string, string> GetLocalResourcePaths() {
|
|
return _localRes;
|
|
}
|
|
public static void Init(string rootPath) {
|
|
LoadExtension(typeof(Extensions.Umg.Extension));
|
|
var asms = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToHashSet();
|
|
var modules = new Queue<ModuleItem>();
|
|
var extensionDir = new DirectoryInfo(Path.Combine(rootPath, "extensions"));
|
|
if (extensionDir.Exists) {
|
|
foreach (var extension in extensionDir.EnumerateFiles("*.dll")) {
|
|
try {
|
|
modules.Enqueue(new ModuleItem(extension.OpenRead()));
|
|
}
|
|
catch (Exception ex) {
|
|
Logger.Log("main", 4, "Extension", "Failed to load DLL {0}: {1}", extension, ex);
|
|
}
|
|
}
|
|
}
|
|
int refCounter = 0;
|
|
while (modules.Count > 0 && refCounter < modules.Count) {
|
|
var module = modules.Dequeue();
|
|
bool flag = false;
|
|
foreach (var reference in module.Definition.AssemblyReferences) {
|
|
if (!asms.Contains(reference.Name)) {
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (flag) {
|
|
modules.Enqueue(module);
|
|
refCounter++;
|
|
}
|
|
else {
|
|
try {
|
|
var stream = module.Stream;
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
var buf = new byte[stream.Length];
|
|
stream.Read(buf, 0, buf.Length);
|
|
var asm = Assembly.Load(buf);
|
|
if (asm == null) throw new TypeLoadException("Failed to load the module");
|
|
asms.Add(asm.GetName().Name);
|
|
foreach (var type in asm.GetTypes()) {
|
|
if (typeof(ExtensionInterface).IsAssignableFrom(type)) {
|
|
LoadExtension(type);
|
|
}
|
|
}
|
|
Logger.Log("main", 1, "Extension", "Loaded module {0}", module.Definition.Name);
|
|
}
|
|
catch (Exception ex) {
|
|
Logger.Log("main", 4, "Extension", "An error occured while trying to load module {0}: {1}", module.Definition.Name, ex);
|
|
}
|
|
finally {
|
|
module.Definition.Dispose();
|
|
module.Stream.Dispose();
|
|
refCounter = 0;
|
|
}
|
|
}
|
|
}
|
|
var missingList = new List<string>();
|
|
while (modules.Count > 0) {
|
|
missingList.Clear();
|
|
var module = modules.Dequeue();
|
|
foreach (var reference in module.Definition.AssemblyReferences) {
|
|
if (!asms.Contains(reference.Name)) {
|
|
missingList.Add(reference.Name);
|
|
}
|
|
}
|
|
Logger.Log("main", 4, "Extension", "Could not load the module {0} because the following dependencies were missing: {1}", module.Definition.Name, missingList.Aggregate((current, next) => current + ", " + next));
|
|
module.Definition.Dispose();
|
|
module.Stream.Dispose();
|
|
}
|
|
}
|
|
|
|
struct ModuleItem {
|
|
public ModuleDefinition Definition { get; set; }
|
|
public FileStream Stream { get; set; }
|
|
public ModuleItem(FileStream stream) {
|
|
Stream = stream;
|
|
Definition = ModuleDefinition.ReadModule(stream);
|
|
}
|
|
}
|
|
|
|
static void LoadExtension(Type type) {
|
|
try {
|
|
var extension = (ExtensionInterface)Activator.CreateInstance(type);
|
|
var l1 = extension.GetResourceConverters();
|
|
if (l1 != null) {
|
|
foreach (var c in l1) {
|
|
var fs = c.GetSupportedFormats();
|
|
if (fs == null) continue;
|
|
foreach (var f in fs) {
|
|
if (f == null) continue;
|
|
if (!_converters.ContainsKey(f))
|
|
_converters.Add(f, new List<ResourceConverter> { c });
|
|
else _converters[f].Add(c);
|
|
}
|
|
}
|
|
}
|
|
var l2 = extension.GetResourceFinders();
|
|
if (l2 != null) {
|
|
foreach (var f in l2) {
|
|
var name = f.Name;
|
|
var path = f.GetRootPath();
|
|
if (name != null && path != null) _localRes.Add(name, path);
|
|
}
|
|
}
|
|
Logger.Log("main", 1, "Extension", "Loaded extension {0}", type);
|
|
}
|
|
catch (Exception ex) {
|
|
Logger.Log("main", 4, "Extension", "Failed to load extension {0}: {1}", type, ex);
|
|
}
|
|
}
|
|
}
|
|
}
|