static CommunityPatchSubModule() { // catch and record exceptions AppDomain.CurrentDomain.FirstChanceException += (sender, args) => { if (RecordFirstChanceExceptions) { RecordedFirstChanceExceptions.AddLast(args.Exception); } }; AppDomain.CurrentDomain.UnhandledException += (sender, args) => { RecordedUnhandledExceptions.AddLast((Exception)args.ExceptionObject); CopyDiagnosticsToClipboard(); }; // TODO: /* * AppDomain.CurrentDomain.TypeResolve += (sender, args) => { * return null; * }; */ // help delay loaded libs refer to mods they depend on AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { MBSubModuleBase reqSm = null; foreach (var sm in Module.CurrentModule.SubModules) { var smAsm = sm.GetType().Assembly; if (smAsm == args.RequestingAssembly) { reqSm = sm; } } if (reqSm == null) { return(null); } var resolvable = new LinkedList <(ModuleInfo Mod, SubModuleInfo SubMod)>(); ModuleInfo reqMi = null; SubModuleInfo reqSmi = null; var modules = ModuleInfo.GetModules(); foreach (var mi in modules) { foreach (var smi in mi.SubModules) { if (smi.Assemblies.Contains(args.Name)) { resolvable.AddLast((mi, smi)); } if (smi.SubModuleClassType != reqSm.GetType().FullName) { continue; } reqMi = mi; reqSmi = smi; } } if (reqSmi == null) { return(null); } foreach (var modId in reqMi.DependedModuleIds) { foreach (var resolution in resolvable) { if (modId != resolution.Mod.Id) { continue; } var modDir = Path.GetDirectoryName(ModuleInfo.GetPath(modId)); if (modDir == null) { continue; } var modPath = Path.Combine(modDir, "bin", Common.ConfigName, args.Name + ".dll"); if (File.Exists(modPath)) { return(Assembly.LoadFile(modPath)); } } } return(null); }; }
private static Assembly OnResolve(object sender, ResolveEventArgs args) { try { var name = new AssemblyName(args.Name); // handle ambiguous resolve requests by checking all mod bin dirs // TODO: recursive scan module dirs if (args.RequestingAssembly == null) { foreach (var modInfo in ModuleInfo.GetModules()) { if (!modInfo.IsSelected) { continue; } var modDir = Path.GetDirectoryName(ModuleInfo.GetPath(modInfo.Id)); if (modDir == null) { continue; } var modPath = Path.Combine(modDir, "bin", Common.ConfigName, name.Name + ".dll"); if (!File.Exists(modPath)) { continue; } var absPath = new Uri(Path.Combine(Environment.CurrentDirectory, modPath)).LocalPath; if (SecurityHelpers.UnblockFile(absPath)) { Console.WriteLine("Unblocked: " + absPath); } Console.WriteLine("Resolved: " + absPath); return(Assembly.LoadFrom(absPath)); } return(null); } MBSubModuleBase reqSm = null; foreach (var sm in Module.CurrentModule.SubModules) { var smAsm = sm.GetType().Assembly; if (smAsm == args.RequestingAssembly) { reqSm = sm; } } if (reqSm == null) { return(null); } var resolvable = new LinkedList <(ModuleInfo Mod, SubModuleInfo SubMod)>(); ModuleInfo reqMi = null; SubModuleInfo reqSmi = null; var modules = ModuleInfo.GetModules(); foreach (var mi in modules) { if (!mi.IsSelected) { continue; } foreach (var smi in mi.SubModules) { if (smi.Assemblies.Contains(args.Name)) { resolvable.AddLast((mi, smi)); } if (smi.SubModuleClassType != reqSm.GetType().FullName) { continue; } reqMi = mi; reqSmi = smi; } } if (reqSmi == null) { return(null); } foreach (var modId in reqMi.DependedModuleIds) { foreach (var resolution in resolvable) { if (modId != resolution.Mod.Id) { continue; } var modDir = Path.GetDirectoryName(ModuleInfo.GetPath(modId)); if (modDir == null) { continue; } var modPath = Path.Combine(modDir, "bin", Common.ConfigName, name.Name + ".dll"); if (!File.Exists(modPath)) { continue; } var absPath = new Uri(Path.Combine(Environment.CurrentDirectory, modPath)).LocalPath; if (SecurityHelpers.UnblockFile(absPath)) { Console.WriteLine("Unblocked: " + absPath); } Console.WriteLine("Resolved: " + absPath); return(Assembly.LoadFrom(absPath)); } } } catch { // TODO: log? } return(null); }
private static void LoadDelayedSubModules() { foreach (var mod in ModuleInfo.GetModules()) { if (!mod.IsSelected) { continue; } var id = mod.Id; var subModsXmlPath = ModuleInfo.GetPath(id); var modDir = Path.GetDirectoryName(subModsXmlPath); if (modDir == null) { continue; } var subModsXml = new XmlDocument(); subModsXml.Load(subModsXmlPath); var delayedSubMods = subModsXml.SelectNodes("/Module/DelayedSubModules/SubModule")?.OfType <XmlElement>(); if (delayedSubMods == null) { continue; } var main = Module.CurrentModule; var typeMain = typeof(Module); foreach (var elem in delayedSubMods) { var delayedSubModInfo = new SubModuleInfo(); delayedSubModInfo.LoadFrom(elem); var dllPath = Path.Combine(modDir, "bin", Common.ConfigName, delayedSubModInfo.DLLName); var subModAsm = AssemblyLoader.LoadFrom(dllPath); var subModType = subModAsm.GetType(delayedSubModInfo.SubModuleClassType); if (!typeof(MBSubModuleBase).IsAssignableFrom(subModType)) { continue; } var delayLoadedSubMod = (MBSubModuleBase)subModType.InvokeMember(".ctor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, new object[0]); typeMain.InvokeMember("AddSubModule", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, main, new object[] { subModAsm, delayedSubModInfo.SubModuleClassType }); var subMods = (ICollection <MBSubModuleBase>)typeMain.InvokeMember("_submodules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, main, new object[0]); subMods.Add(delayLoadedSubMod); subModType.InvokeMember(nameof(OnSubModuleLoad), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, delayLoadedSubMod, new object[0]); } } }
public MCMSubModuleInfo(MCMModuleInfo owner, SubModuleInfo subModuleInfo, Type subModuleType) { Owner = owner; SubModuleInfo = subModuleInfo; SubModuleType = subModuleType; }