Detects assembly references and determines loading order automatically.
This commit is contained in:
@@ -28,8 +28,8 @@ namespace Cryville.Common.Unity {
|
||||
set { m_filter = value; }
|
||||
}
|
||||
|
||||
public Dictionary<string, string> m_presetPaths = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> PresetPaths {
|
||||
public IReadOnlyDictionary<string, string> m_presetPaths = new Dictionary<string, string>();
|
||||
public IReadOnlyDictionary<string, string> PresetPaths {
|
||||
get { return m_presetPaths; }
|
||||
set { m_presetPaths = value; }
|
||||
}
|
||||
|
138
Assets/Cryville/Crtr/Browsing/ExtensionManager.cs
Normal file
138
Assets/Cryville/Crtr/Browsing/ExtensionManager.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Browsing/ExtensionManager.cs.meta
Normal file
11
Assets/Cryville/Crtr/Browsing/ExtensionManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9ea11165e6269b488f916982507a2af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -12,6 +12,6 @@ namespace Cryville.Crtr.Browsing {
|
||||
|
||||
bool ImportItemFrom(string path);
|
||||
string[] GetSupportedFormats();
|
||||
Dictionary<string, string> GetPresetPaths();
|
||||
IReadOnlyDictionary<string, string> GetPresetPaths();
|
||||
}
|
||||
}
|
@@ -7,7 +7,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Logger = Cryville.Common.Logger;
|
||||
|
||||
@@ -19,68 +18,12 @@ namespace Cryville.Crtr.Browsing {
|
||||
public string[] CurrentDirectory { get; private set; }
|
||||
|
||||
static bool _init;
|
||||
static readonly Dictionary<string, List<ResourceConverter>> converters
|
||||
= new Dictionary<string, List<ResourceConverter>>();
|
||||
static readonly Dictionary<string, string> localRes
|
||||
= new Dictionary<string, string>();
|
||||
|
||||
public LegacyResourceManager(string rootPath) {
|
||||
_rootPath = rootPath;
|
||||
if (!_init) {
|
||||
_init = true;
|
||||
LoadExtension(typeof(Extensions.Umg.Extension));
|
||||
var extensionDir = new DirectoryInfo(Path.Combine(rootPath, "extensions"));
|
||||
if (extensionDir.Exists) {
|
||||
foreach (var extension in extensionDir.EnumerateFiles("*.dll")) {
|
||||
try {
|
||||
using (Stream stream = extension.OpenRead()) {
|
||||
var buf = new byte[stream.Length];
|
||||
stream.Read(buf, 0, buf.Length);
|
||||
var asm = Assembly.Load(buf);
|
||||
foreach (var type in asm.GetTypes()) {
|
||||
if (typeof(ExtensionInterface).IsAssignableFrom(type)) {
|
||||
LoadExtension(type);
|
||||
}
|
||||
}
|
||||
Logger.Log("main", 1, "Extension", "Loaded extension DLL {0}", extension.Name);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Log("main", 4, "Extension", "An error occured while trying to load extension DLL {0}: {1}", extension.Name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ExtensionManager.Init(rootPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +115,9 @@ namespace Cryville.Crtr.Browsing {
|
||||
|
||||
public bool ImportItemFrom(string path) {
|
||||
var file = new FileInfo(path);
|
||||
if (!converters.ContainsKey(file.Extension)) return false;
|
||||
foreach (var converter in converters[file.Extension]) {
|
||||
IEnumerable<ResourceConverter> converters;
|
||||
if (!ExtensionManager.TryGetConverters(file.Extension, out converters)) return false;
|
||||
foreach (var converter in converters) {
|
||||
IEnumerable<Resource> resources = null;
|
||||
try {
|
||||
resources = converter.ConvertFrom(file);
|
||||
@@ -249,11 +193,11 @@ namespace Cryville.Crtr.Browsing {
|
||||
}
|
||||
|
||||
public string[] GetSupportedFormats() {
|
||||
return converters.Keys.ToArray();
|
||||
return ExtensionManager.GetSupportedFormats().ToArray();
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetPresetPaths() {
|
||||
return localRes;
|
||||
public IReadOnlyDictionary<string, string> GetPresetPaths() {
|
||||
return ExtensionManager.GetLocalResourcePaths();
|
||||
}
|
||||
|
||||
static Chart ConvertChartData(ChartData i) {
|
||||
|
BIN
Assets/Plugins/Mono.Cecil.dll
Normal file
BIN
Assets/Plugins/Mono.Cecil.dll
Normal file
Binary file not shown.
33
Assets/Plugins/Mono.Cecil.dll.meta
Normal file
33
Assets/Plugins/Mono.Cecil.dll.meta
Normal file
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47f861a77858b7b42b0e57f60f5ccace
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user