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; }
|
set { m_filter = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> m_presetPaths = new Dictionary<string, string>();
|
public IReadOnlyDictionary<string, string> m_presetPaths = new Dictionary<string, string>();
|
||||||
public Dictionary<string, string> PresetPaths {
|
public IReadOnlyDictionary<string, string> PresetPaths {
|
||||||
get { return m_presetPaths; }
|
get { return m_presetPaths; }
|
||||||
set { m_presetPaths = value; }
|
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);
|
bool ImportItemFrom(string path);
|
||||||
string[] GetSupportedFormats();
|
string[] GetSupportedFormats();
|
||||||
Dictionary<string, string> GetPresetPaths();
|
IReadOnlyDictionary<string, string> GetPresetPaths();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Logger = Cryville.Common.Logger;
|
using Logger = Cryville.Common.Logger;
|
||||||
|
|
||||||
@@ -19,68 +18,12 @@ namespace Cryville.Crtr.Browsing {
|
|||||||
public string[] CurrentDirectory { get; private set; }
|
public string[] CurrentDirectory { get; private set; }
|
||||||
|
|
||||||
static bool _init;
|
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) {
|
public LegacyResourceManager(string rootPath) {
|
||||||
_rootPath = rootPath;
|
_rootPath = rootPath;
|
||||||
if (!_init) {
|
if (!_init) {
|
||||||
_init = true;
|
_init = true;
|
||||||
LoadExtension(typeof(Extensions.Umg.Extension));
|
ExtensionManager.Init(rootPath);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,8 +115,9 @@ namespace Cryville.Crtr.Browsing {
|
|||||||
|
|
||||||
public bool ImportItemFrom(string path) {
|
public bool ImportItemFrom(string path) {
|
||||||
var file = new FileInfo(path);
|
var file = new FileInfo(path);
|
||||||
if (!converters.ContainsKey(file.Extension)) return false;
|
IEnumerable<ResourceConverter> converters;
|
||||||
foreach (var converter in converters[file.Extension]) {
|
if (!ExtensionManager.TryGetConverters(file.Extension, out converters)) return false;
|
||||||
|
foreach (var converter in converters) {
|
||||||
IEnumerable<Resource> resources = null;
|
IEnumerable<Resource> resources = null;
|
||||||
try {
|
try {
|
||||||
resources = converter.ConvertFrom(file);
|
resources = converter.ConvertFrom(file);
|
||||||
@@ -249,11 +193,11 @@ namespace Cryville.Crtr.Browsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetSupportedFormats() {
|
public string[] GetSupportedFormats() {
|
||||||
return converters.Keys.ToArray();
|
return ExtensionManager.GetSupportedFormats().ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> GetPresetPaths() {
|
public IReadOnlyDictionary<string, string> GetPresetPaths() {
|
||||||
return localRes;
|
return ExtensionManager.GetLocalResourcePaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chart ConvertChartData(ChartData i) {
|
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