public void PreloadPlugins() { Stopwatch benchmark = Stopwatch.StartNew(); Debugger.Module("Pre loading modules"); string[] modules = Directory.GetDirectories(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules")); foreach (string module in modules) { // Skip modules without Module.json if (!File.Exists(Path.Combine(module, "module.json"))) { continue; } try { string serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); PluginInformation modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); PluginSettings modSettings = GetPluginSettings(module); if (File.Exists(Path.Combine(module, modInformation.EntryPoint))) { Debugger.Module($"Compiling plugin: {modInformation.Name}"); if (CompilePlugin(module, modInformation)) { Debugger.Module($"{modInformation.Name} compiled successfully."); } else { continue; } } Stopwatch s = Stopwatch.StartNew(); foreach (string required in modInformation.Dependencies) { AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, required))); } Assembly plugin = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, $"{modInformation.Name}.dll"))); IEnumerable <Type> entries = plugin.ExportedTypes.Where(exp => exp.GetMethod("Initialize") != null); if (entries.Count() > 0) { dynamic mod = plugin.CreateInstance(entries.First().ToString()); packages.Add(new PluginPackage { plugin = mod, information = modInformation, settings = modSettings, path = module }); } } catch (Exception err) { Debugger.Error(err); continue; } } IsReady = true; benchmark.Stop(); Debugger.Module($"Pre loaded {packages.Count} module(s) in {benchmark.ElapsedMilliseconds}ms"); if (QueueLoad) { LoadPlugins(); } }
public bool CompilePlugin(string pluginPath, PluginInformation information) { var compiler = CSharpCompilation.Create($"{nameof(HunterPie)}{information.Name}", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOptimizationLevel(OptimizationLevel.Release)); var types = new[] { typeof(Hunterpie), // HunterPie typeof(JObject), // Newtonsoft.Json.dll typeof(Object), // mscorlib.dll typeof(UIElement), // PresentationCore.dll typeof(Window), // PresentationFramework.dll typeof(Uri), // System.dll typeof(Enumerable), // System.Core.dll typeof(DataSet), // System.Data.dll typeof(DataTableExtensions), // System.Data.DataSetExtensions.dll typeof(Bitmap), // System.Drawing.dll typeof(HttpClient), // System.Net.Http.dll typeof(BigInteger), // System.Numerics.dll typeof(Form), // System.Windows.Forms.dll typeof(XamlType), // System.Xaml.dll typeof(XmlNode), // System.Xml.dll typeof(XNode), // System.Xml.Linq.dll typeof(Rect), // WindowsBase.dll }; // Load all basic dependencies List <MetadataReference> references = types.Select(type => MetadataReference.CreateFromFile(type.Assembly.Location)).ToList <MetadataReference>(); if (information.Dependencies != null) { foreach (string extDependency in information.Dependencies) { references.Add(MetadataReference.CreateFromFile(Path.Combine(pluginPath, extDependency))); } } compiler = compiler.AddReferences(references); var code = File.ReadAllText(Path.Combine(pluginPath, information.EntryPoint)); var options = CSharpParseOptions.Default.WithLanguageVersion( LanguageVersion.CSharp7_3); var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(code, Encoding.UTF8), options, Path.Combine(pluginPath, information.EntryPoint)); compiler = compiler.AddSyntaxTrees(syntaxTree); var result = compiler.Emit(Path.Combine(pluginPath, information.Name) + ".dll"); if (result.Success) { return(true); } else { Debugger.Error($"Failed to compile plugin: {information.Name}"); foreach (var exception in result.Diagnostics) { Debugger.Error(exception); } return(false); } }
public void LoadPlugins(Game ctx) { Stopwatch benchmark = Stopwatch.StartNew(); if (plugins.Count > 0) { // Quick load foreach (IPlugin plugin in plugins) { plugin.Initialize(ctx); } } else { string[] modules = Directory.GetDirectories(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules")); foreach (string module in modules) { try { string serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); PluginInformation modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); if (File.Exists(Path.Combine(module, modInformation.EntryPoint))) { Debugger.Module($"Compiling plugin: {modInformation.Name}"); if (CompilePlugin(module, modInformation)) { Debugger.Module($"{modInformation.Name} compiled successfully."); } else { continue; } } foreach (string required in modInformation.Dependencies) { AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, required))); } var plugin = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, $"{modInformation.Name}.dll"))); IEnumerable <Type> entries = plugin.ExportedTypes.Where(exp => exp.GetMethod("Initialize") != null); if (entries.Count() > 0) { dynamic mod = plugin.CreateInstance(entries.First().ToString()); mod.Initialize(ctx); plugins.Add(mod); } } catch (Exception err) { Debugger.Error(err); continue; } } } benchmark.Stop(); Debugger.Module($"Loaded {plugins.Count} module(s) in {benchmark.ElapsedMilliseconds}ms"); }
public async Task <string> GetModuleUpdateUrl(PluginInformation pInformation) { if (await ShouldUseProxy()) { return(BuildUrl(ConfigManager.Settings.HunterPie.PluginRegistryUrl, "plugin", Uri.EscapeUriString(pInformation.Name), "module")); } return(pInformation.Update.UpdateUrl); }
public static async Task <bool> UpdateAllFiles(PluginInformation pInformation, string modPath) { string onlineSerializedInformation = await ReadOnlineModuleJson(pInformation.Update.UpdateUrl); if (onlineSerializedInformation is null) { //Debugger.Error($"Failed to update plugin: {pInformation.Name}!"); return(false); } PluginInformation onlineInformation = JsonConvert.DeserializeObject <PluginInformation>(onlineSerializedInformation); if (!(Hunterpie.ParseVersion(Hunterpie.HUNTERPIE_VERSION) >= Hunterpie.ParseVersion(onlineInformation.Update.MinimumVersion))) { return(false); } foreach (string filePath in onlineInformation.Update.FileHashes.Keys) { string onlineHash = onlineInformation.Update.FileHashes[filePath]; if (onlineHash.ToLower() == "installonly" && File.Exists(Path.Combine(modPath, filePath))) { continue; } if (pInformation.Update.FileHashes.ContainsKey(filePath)) { string localHash = pInformation.Update.FileHashes[filePath]; if (onlineHash.ToLower() != localHash.ToLower() || !File.Exists(Path.Combine(modPath, filePath))) { string updateurl = $"{pInformation.Update.UpdateUrl}/{filePath}"; string outputPath = Path.Combine(modPath, filePath); if (!(await DownloadFileAsync(updateurl, outputPath, filePath))) { return(false); } } } else { string updateurl = $"{pInformation.Update.UpdateUrl}/{filePath}"; string outputPath = Path.Combine(modPath, filePath); if (!(await DownloadFileAsync(updateurl, outputPath, filePath))) { return(false); } } } return(await DownloadFileAsync($"{pInformation.Update.UpdateUrl}/module.json", Path.Combine(modPath, "module.json"), "module.json")); }
public async Task <bool> PreloadPlugins() { Stopwatch benchmark = Stopwatch.StartNew(); Debugger.Module("Pre loading modules"); foreach (string module in IterateModules()) { try { string serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); PluginInformation modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); try { await PreloadPlugin(module, modInformation); failedPlugins.Remove(modInformation.Name); } catch { failedPlugins.Add(modInformation.Name); throw; } } catch (Exception err) { Debugger.Error(err); } } benchmark.Stop(); Debugger.Module($"Pre loaded {packages.Count} module(s) in {benchmark.ElapsedMilliseconds}ms"); if (!tsc.Task.IsCompleted) { tsc.SetResult(null); } return(true); }
private async Task PreloadPlugin(string module, PluginInformation modInformation) { if (File.Exists(Path.Combine(module, ".remove"))) { Directory.Delete(module, true); Debugger.Module($"Plugin {modInformation.Name} removed."); return; } if (modInformation.Update.MinimumVersion is null) { Debugger.Error($"{modInformation.Name.ToUpper()} MIGHT BE OUTDATED! CONSIDER UPDATING IT."); } if (PluginUpdate.PluginSupportsUpdate(modInformation)) { switch (await PluginUpdate.UpdateAllFiles(modInformation, module)) { case UpdateResult.Updated: var serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); Debugger.Module($"Updated plugin: {modInformation.Name} (ver {modInformation.Version})"); break; case UpdateResult.Skipped: break; case UpdateResult.Failed: Debugger.Error($"Failed to update plugin: {modInformation.Name}"); break; case UpdateResult.UpToDate: Debugger.Module($"Plugin {modInformation.Name} is up-to-date (ver {modInformation.Version})"); break; } } PluginSettings modSettings = GetPluginSettings(module); if (!string.IsNullOrEmpty(modInformation.EntryPoint) && File.Exists(Path.Combine(module, modInformation.EntryPoint))) { Debugger.Module($"Compiling plugin: {modInformation.Name}"); if (CompilePlugin(module, modInformation)) { Debugger.Module($"{modInformation.Name} compiled successfully."); } else { return; } } foreach (string required in modInformation.Dependencies) { AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, required))); } Assembly plugin = AppDomain.CurrentDomain.Load( AssemblyName.GetAssemblyName(Path.Combine(module, $"{modInformation.Name}.dll"))); IEnumerable <Type> entries = plugin.ExportedTypes.Where(exp => exp.GetMethod("Initialize") != null); if (entries.Any()) { dynamic mod = plugin.CreateInstance(entries.First().ToString()); packages.Add(new PluginPackage { plugin = mod, information = modInformation, settings = modSettings, path = module }); } }
private async Task PreloadPlugin(string module, PluginInformation modInformation) { if (File.Exists(Path.Combine(module, ".remove"))) { Directory.Delete(module, true); Debugger.Module($"Plugin {modInformation.Name} removed."); return; } if (modInformation.Update.MinimumVersion is null) { Debugger.Error($"{modInformation.Name.ToUpper()} MIGHT BE OUTDATED! CONSIDER UPDATING IT."); } if (PluginUpdate.PluginSupportsUpdate(modInformation)) { switch (await PluginUpdate.UpdateAllFiles(modInformation, module)) { case UpdateResult.Updated: var serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); Debugger.Module($"Updated plugin: {modInformation.Name} (ver {modInformation.Version})"); break; case UpdateResult.Skipped: break; case UpdateResult.Failed: Debugger.Error($"Failed to update plugin: {modInformation.Name}"); break; case UpdateResult.UpToDate: Debugger.Module($"Plugin {modInformation.Name} is up-to-date (ver {modInformation.Version})"); break; } } PluginSettings modSettings = GetPluginSettings(module); if (!string.IsNullOrEmpty(modInformation.EntryPoint) && File.Exists(Path.Combine(module, modInformation.EntryPoint))) { Debugger.Module($"Compiling plugin: {modInformation.Name}"); if (CompilePlugin(module, modInformation)) { Debugger.Module($"{modInformation.Name} compiled successfully."); } else { return; } } foreach (string required in modInformation.Dependencies) { AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, required))); } var moduleAssembly = AppDomain.CurrentDomain.Load( AssemblyName.GetAssemblyName(Path.Combine(module, $"{modInformation.Name}.dll")) ); var pluginType = moduleAssembly.ExportedTypes.FirstOrDefault(exp => exp.GetMethod("Initialize") != null); if (pluginType != null) { var plugin = (IPlugin)moduleAssembly.CreateInstance(pluginType.FullName); // making sure that name is matching modInformation, e.g. if plugin dev forgot to populate this value plugin.Name = modInformation.Name; var package = new PluginPackage { plugin = plugin, information = modInformation, settings = modSettings, path = module }; packages.Add(package); // if plugin is enabled, adding it's settings if (modSettings.IsEnabled) { AddPackageSettings(package); } } }
public static async Task <UpdateResult> UpdateAllFiles(PluginInformation pInformation, string modPath) { var updateUrl = await PluginRegistryService.Instance.GetModuleUpdateUrl(pInformation); string onlineSerializedInformation = await ReadOnlineModuleJson(updateUrl); if (onlineSerializedInformation is null) { //Debugger.Error($"Failed to update plugin: {pInformation.Name}!"); return(UpdateResult.Failed); } PluginInformation onlineInformation = JsonConvert.DeserializeObject <PluginInformation>(onlineSerializedInformation); if (!IsVersionOk(onlineInformation.Update.MinimumVersion)) { Debugger.Warn($"Newest version of {pInformation.Name} requires HunterPie v{onlineInformation.Update.MinimumVersion}!"); return(UpdateResult.Skipped); } UpdateResult result = UpdateResult.UpToDate; foreach (string filePath in onlineInformation.Update.FileHashes.Keys) { string onlineHash = onlineInformation.Update.FileHashes[filePath]; if (onlineHash.ToLower() == "installonly" && File.Exists(Path.Combine(modPath, filePath))) { continue; } if (pInformation.Update.FileHashes.ContainsKey(filePath)) { string localHash = pInformation.Update.FileHashes[filePath]; if (onlineHash.ToLower() != localHash.ToLower() || !File.Exists(Path.Combine(modPath, filePath))) { string outputPath = Path.Combine(modPath, filePath); if (!(await DownloadFileAsync($"{updateUrl}/{filePath}", outputPath, filePath))) { return(UpdateResult.Failed); } result = UpdateResult.Updated; } } else { string outputPath = Path.Combine(modPath, filePath); if (!(await DownloadFileAsync($"{updateUrl}/{filePath}", outputPath, filePath))) { return(UpdateResult.Failed); } result = UpdateResult.Updated; } } return(await DownloadFileAsync($"{updateUrl}/module.json", Path.Combine(modPath, "module.json"), "module.json") ? result : UpdateResult.Failed); }
public static bool PluginSupportsUpdate(PluginInformation pluginInformation) { return(!string.IsNullOrEmpty(pluginInformation.Update.UpdateUrl)); }
public async Task <bool> PreloadPlugins() { Stopwatch benchmark = Stopwatch.StartNew(); Debugger.Module("Pre loading modules"); string[] modules = Directory.GetDirectories(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules")); foreach (string module in modules) { // Skip modules without Module.json if (!File.Exists(Path.Combine(module, "module.json"))) { continue; } try { string serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); PluginInformation modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); if (modInformation.Update.MinimumVersion is null) { Debugger.Error($"{modInformation.Name.ToUpper()} MIGHT BE OUTDATED! CONSIDER UPDATING IT."); } if (PluginUpdate.PluginSupportsUpdate(modInformation)) { switch (await PluginUpdate.UpdateAllFiles(modInformation, module)) { case UpdateResult.Updated: serializedModule = File.ReadAllText(Path.Combine(module, "module.json")); modInformation = JsonConvert.DeserializeObject <PluginInformation>(serializedModule); Debugger.Module($"Updated plugin: {modInformation.Name} (ver {modInformation.Version})"); break; case UpdateResult.Skipped: break; case UpdateResult.Failed: Debugger.Error($"Failed to update plugin: {modInformation.Name}"); continue; case UpdateResult.UpToDate: Debugger.Module($"Plugin {modInformation.Name} is up-to-date (ver {modInformation.Version})"); break; } } PluginSettings modSettings = GetPluginSettings(module); if (!string.IsNullOrEmpty(modInformation.EntryPoint) && File.Exists(Path.Combine(module, modInformation.EntryPoint))) { Debugger.Module($"Compiling plugin: {modInformation.Name}"); if (CompilePlugin(module, modInformation)) { Debugger.Module($"{modInformation.Name} compiled successfully."); } else { continue; } } Stopwatch s = Stopwatch.StartNew(); foreach (string required in modInformation.Dependencies) { AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, required))); } Assembly plugin = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(Path.Combine(module, $"{modInformation.Name}.dll"))); IEnumerable <Type> entries = plugin.ExportedTypes.Where(exp => exp.GetMethod("Initialize") != null); if (entries.Count() > 0) { dynamic mod = plugin.CreateInstance(entries.First().ToString()); packages.Add(new PluginPackage { plugin = mod, information = modInformation, settings = modSettings, path = module }); } } catch (Exception err) { Debugger.Error(err); continue; } } IsReady = true; benchmark.Stop(); Debugger.Module($"Pre loaded {packages.Count} module(s) in {benchmark.ElapsedMilliseconds}ms"); if (QueueLoad) { LoadPlugins(); } return(true); }