/// <summary> /// Loads a plugin required by another. /// </summary> /// <param name="targetPlugin">The plugin to load</param> /// <param name="dependantPlugin">The plugin requesting the load</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="targetPlugin"/> or <paramref name="dependantPlugin"/> is null.</exception> public virtual void LoadRequiredPlugin(SkyEditorPlugin pluginToLoad, SkyEditorPlugin dependantPlugin) { if (pluginToLoad == null) { throw new ArgumentNullException(nameof(pluginToLoad)); } if (dependantPlugin == null) { throw new ArgumentNullException(nameof(dependantPlugin)); } // - Create the dependant plugin list if it doesn't exist if (!DependantPlugins.ContainsKey(pluginToLoad)) { DependantPlugins.Add(pluginToLoad, new List <SkyEditorPlugin>()); } // - Add the plugin to the dependant plugin list if (!DependantPlugins[pluginToLoad].Contains(dependantPlugin)) { DependantPlugins[pluginToLoad].Add(dependantPlugin); } // Mark this plugin as a dependant, will be loaded by plugin engine later // Because loading takes place in a For Each loop iterating through Plugins, we cannot load plugins here, because that would change the collection. DependantPluginLoadingQueue.Enqueue(pluginToLoad); }
/// <summary> /// Loads the given Core plugin and any other available plugins, if supported by the environment. /// </summary> /// <param name="core">The core plugin that controls the environment.</param> /// <remarks> /// Misc things this function does: /// - Delete files scheduled for deletion /// - Install pending extensions /// </remarks> /// <exception cref="ArgumentNullException">Thrown if <paramref name="core"/> is null.</exception> public virtual async Task LoadCore(CoreSkyEditorPlugin core) { if (core == null) { throw new ArgumentNullException(nameof(core)); } // Load providers CurrentFileSystem = core.GetFileSystem(); CurrentSettingsProvider = core.GetSettingsProvider(this); CurrentConsoleProvider = core.GetConsoleProvider(); // Delete files and directories scheduled for deletion await DeleteScheduledFiles(CurrentSettingsProvider, CurrentFileSystem); // Install pending extensions ExtensionDirectory = core.GetExtensionDirectory(); await ExtensionHelper.InstallPendingExtensions(ExtensionDirectory, this); // Load the provided core CorePluginAssembly = core.GetType().GetTypeInfo().Assembly; Plugins.Add(core); core.Load(this); // Load plugins, if enabled if (core.IsPluginLoadingEnabled()) { // Get the paths of all plugins to be loaded var supportedPlugins = GetPluginPaths(); // Load the plugin assemblies foreach (var item in supportedPlugins) { try { var assemblyActual = core.LoadAssembly(item); if (assemblyActual != null) { PluginAssemblies.Add(assemblyActual); foreach (var plg in assemblyActual.DefinedTypes.Where((x) => ReflectionHelpers.IsOfType(x, typeof(SkyEditorPlugin).GetTypeInfo()) && this.CanCreateInstance(x))) { Plugins.Add(this.CreateInstance(plg) as SkyEditorPlugin); } } } catch (FileLoadException) { // The assembly is a bad assembly. We can continue loading plugins, but not with this FailedPluginLoads.Add(item); } catch (BadImageFormatException) { // The assembly is a bad assembly. We can continue loading plugins, but not with this FailedPluginLoads.Add(item); } catch (NotSupportedException) { // The current environment does not support loading assemblies this way. // Abort dynamic assembly loading break; } } } // Load logical plugins PluginsLoading?.Invoke(this, new EventArgs()); var coreType = core.GetType(); foreach (var item in Plugins.Where(p => p.GetType() != core.GetType())) { item.Load(this); } // Load dependant plugins while (DependantPluginLoadingQueue.Count > 0) { var item = DependantPluginLoadingQueue.Dequeue(); var pluginType = item.GetType(); // Determine if it has already been loaded if (!Plugins.Where((x) => x.GetType() == pluginType).Any()) { // Add the plugin Plugins.Add(item); // Add the assembly if it hasn't been added already var pluginAssembly = pluginType.GetTypeInfo().Assembly; if (!PluginAssemblies.Contains(pluginAssembly)) { PluginAssemblies.Add(pluginAssembly); } // Load the plugin item.Load(this); } } // Use reflection to fill the type registry if (core.IsCorePluginAssemblyDynamicTypeLoadEnabled()) { LoadTypes(CorePluginAssembly); } if (core.IsExtraPluginAssemblyDynamicTypeLoadEnabled()) { foreach (var item in PluginAssemblies) { LoadTypes(item); } } PluginLoadComplete?.Invoke(this, new EventArgs()); }