Example #1
0
        /// <summary>
        /// Function to load in the gaming device driver plug ins.
        /// </summary>
        /// <returns>A list of gaming device driver plug ins.</returns>
        private static IReadOnlyList <IGorgonGamingDeviceDriver> GetGamingDeviceDrivers()
        {
            GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.InputPlugInPath);

            // Access our plugin cache.
            _pluginCache = new GorgonMefPlugInCache(GorgonApplication.Log);

            // Get the files from the plugin directory.
            // The plugin directory can be changed in the configuration file
            // to point at wherever you'd like.  If a {0} place holder is
            // in the path, it will be replaced with whatever the build
            // configuration is set to (i.e. DEBUG or RELEASE).
            _pluginCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.*.dll");

            if (_pluginCache.PlugInAssemblies.Count == 0)
            {
                return(Array.Empty <IGorgonGamingDeviceDriver>());
            }

            // Create our plugin service.
            IGorgonPlugInService pluginService = new GorgonMefPlugInService(_pluginCache);

            // Create our input service factory.
            var factory = new GorgonGamingDeviceDriverFactory(pluginService, GorgonApplication.Log);

            // Retrieve the list of driver plug ins from the input service factory.
            return(factory.LoadAllDrivers());
        }
Example #2
0
        /// <summary>
        /// Function to load our useless image codec plug in.
        /// </summary>
        /// <returns><b>true</b> if successful, <b>false</b> if not.</returns>
        private bool LoadCodec()
        {
            const string pluginName = "Gorgon.Graphics.Example.TvImageCodecPlugIn";

            _pluginCache = new GorgonMefPlugInCache(GorgonApplication.Log);

            // Load our plug in.
            _pluginCache.LoadPlugInAssemblies(GorgonApplication.StartupPath.FullName, "TVImageCodec.dll");

            // Activate the plugin service.
            IGorgonPlugInService pluginService = new GorgonMefPlugInService(_pluginCache);

            // Find the plugin.
            GorgonImageCodecPlugIn plugIn = pluginService.GetPlugIn <GorgonImageCodecPlugIn>(pluginName);

            if ((plugIn == null) || (plugIn.Codecs.Count == 0))
            {
                return(false);
            }

            // Normally you would enumerate the plug ins, but in this case we know there's only one.
            _customCodec = plugIn.CreateCodec(plugIn.Codecs[0].Name);

            return(_customCodec != null);
        }
Example #3
0
        /// <summary>
        /// Function to load the Gorgon pack file provider plugin.
        /// </summary>
        /// <returns>The file system provider.</returns>
        private IGorgonFileSystemProvider LoadGorPackProvider()
        {
            // The Gorgon packed file provider plug in dll.
            const string gorPackDll = "Gorgon.FileSystem.GorPack.dll";
            // The name of the Gorgon packed file plugin.
            const string gorPackPlugInName = "Gorgon.IO.GorPack.GorPackProvider";

            // Like the zip file example, we'll just create the plugin infrastructure, grab the provider object
            // and get rid of the plugin stuff since we won't need it again.
            _assemblyCache = new GorgonMefPlugInCache(GorgonApplication.Log);
            _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, gorPackDll);

            var plugIns = new GorgonMefPlugInService(_assemblyCache);

            return(plugIns.GetPlugIn <GorgonFileSystemProvider>(gorPackPlugInName));
        }
Example #4
0
        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Form.Load" /> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            try
            {
                GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.PlugInLocation);

                // Create the assembly cache.
                _assemblies = new GorgonMefPlugInCache(GorgonApplication.Log);
                _assemblies.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.XInput.dll");

                // Create the plug services.
                IGorgonPlugInService pluginService = new GorgonMefPlugInService(_assemblies);

                // Create the gaming device driver factory.
                var factory = new GorgonGamingDeviceDriverFactory(pluginService, GorgonApplication.Log);

                // Create our factory.
                _driver = factory.LoadDriver("Gorgon.Input.XInput.GorgonXInputDriver");

                _stickPosition = new PointF[3];
                _sprayStates   = new SprayCan[3];

                // Get our list of active controllers.
                UpdateActiveControllers();

                // Get the graphics interface for our panel.
                _surface = new DrawingSurface(panelDisplay);

                // Set up our idle loop.
                GorgonApplication.IdleMethod += Idle;

                // Launch a background task to check for connected devices.
                Task.Run(CheckForConnectedDevices);
            }
            catch (Exception ex)
            {
                // We do this here instead of just calling the dialog because this
                // function will send the exception to the Gorgon log file.
                GorgonExample.HandleException(ex);
                GorgonApplication.Quit();
            }
        }
Example #5
0
        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Form.Load"></see> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            try
            {
                GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.PlugInLocation);

                // Load the assembly.
                _assemblyCache = new GorgonMefPlugInCache(GorgonApplication.Log);

                // Create the plugin service.
                IGorgonPlugInService plugInService = new GorgonMefPlugInService(_assemblyCache);

                // Create the factory to retrieve gaming device drivers.
                var factory = new GorgonGamingDeviceDriverFactory(plugInService);

                // Create the raw input interface.
                _input = new GorgonRawInput(this, GorgonApplication.Log);

                // Get available gaming device driver plug ins.
                _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.DirectInput.dll");
                _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.XInput.dll");

                _drivers = factory.LoadAllDrivers();

                _joystickList = new List <IGorgonGamingDevice>();

                // Get all gaming devices from the drivers.
                foreach (IGorgonGamingDeviceDriver driver in _drivers)
                {
                    IReadOnlyList <IGorgonGamingDeviceInfo> infoList = driver.EnumerateGamingDevices(true);

                    foreach (IGorgonGamingDeviceInfo info in infoList)
                    {
                        IGorgonGamingDevice device = driver.CreateGamingDevice(info);

                        // Turn off dead zones for this example.
                        foreach (GorgonGamingDeviceAxis axis in device.Axis)
                        {
                            axis.DeadZone = GorgonRange.Empty;
                        }

                        _joystickList.Add(device);
                    }
                }

                // Create mouse.
                _mouse = new GorgonRawMouse();

                // Create the graphics interface.
                ClientSize = Settings.Default.Resolution;

                IReadOnlyList <IGorgonVideoAdapterInfo> adapters = GorgonGraphics.EnumerateAdapters();
                _graphics = new GorgonGraphics(adapters[0], log: GorgonApplication.Log);
                _screen   = new GorgonSwapChain(_graphics, this, new GorgonSwapChainInfo("INeedYourInput Swapchain")
                {
                    Width  = Settings.Default.Resolution.Width,
                    Height = Settings.Default.Resolution.Height,
                    Format = BufferFormat.R8G8B8A8_UNorm
                });
                _graphics.SetRenderTarget(_screen.RenderTargetView);

                if (!Settings.Default.IsWindowed)
                {
                    _screen.EnterFullScreen();
                }

                // For the backup image. Used to make it as large as the monitor that we're on.
                var currentScreen = Screen.FromHandle(Handle);

                // Relocate the window to the center of the screen.
                Location = new Point(currentScreen.Bounds.Left + (currentScreen.WorkingArea.Width / 2) - (ClientSize.Width / 2),
                                     currentScreen.Bounds.Top + (currentScreen.WorkingArea.Height / 2) - (ClientSize.Height / 2));


                // Create the 2D renderer.
                _2D = new Gorgon2D(_graphics);

                // Create the text font.
                var fontFactory = new GorgonFontFactory(_graphics);
                _font = fontFactory.GetFont(new GorgonFontInfo("Arial", 9.0f, FontHeightMode.Points, "Arial 9pt")
                {
                    FontStyle        = FontStyle.Bold,
                    AntiAliasingMode = FontAntiAliasMode.AntiAlias
                });

                // Create text sprite.
                _messageSprite = new GorgonTextSprite(_font, "Using mouse and keyboard (Windows Forms).")
                {
                    Color = Color.Black
                };

                // Create a back buffer.
                _backBuffer = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, new GorgonTexture2DInfo("Backbuffer storage")
                {
                    Width  = _screen.Width,
                    Height = _screen.Height,
                    Format = _screen.Format
                });
                _backBuffer.Clear(Color.White);
                _backBufferView = _backBuffer.GetShaderResourceView();

                // Clear our backup image to white to match our primary screen.
                using (IGorgonImage image = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, _screen.Format)
                {
                    Width = _screen.Width,
                    Height = _screen.Height,
                    Format = _screen.Format
                }))
                {
                    image.Buffers[0].Fill(0xff);
                    _backupImage = image.ToTexture2D(_graphics,
                                                     new GorgonTexture2DLoadOptions
                    {
                        Binding = TextureBinding.None,
                        Usage   = ResourceUsage.Staging
                    });
                }

                // Set gorgon events.
                _screen.BeforeSwapChainResized += BeforeSwapChainResized;
                _screen.AfterSwapChainResized  += AfterSwapChainResized;

                // Enable the mouse.
                Cursor = Cursors.Cross;
                _mouse.MouseButtonDown += MouseInput;
                _mouse.MouseMove       += MouseInput;
                _mouse.MouseWheelMove  += (sender, args) =>
                {
                    _radius += args.WheelDelta.Sign();

                    if (_radius < 2.0f)
                    {
                        _radius = 2.0f;
                    }
                    if (_radius > 10.0f)
                    {
                        _radius = 10.0f;
                    }
                };

                // Set the mouse position.
                _mouse.Position = new Point(ClientSize.Width / 2, ClientSize.Height / 2);

                _noBlending = _blendBuilder.BlendState(GorgonBlendState.NoBlending)
                              .Build();
                _inverted = _blendBuilder.BlendState(GorgonBlendState.Inverted)
                            .Build();

                // Set up blending states for our pen.
                var blendStateBuilder = new GorgonBlendStateBuilder();
                _currentBlend = _drawModulatedBlend = _blendBuilder.BlendState(blendStateBuilder
                                                                               .ResetTo(GorgonBlendState.Default)
                                                                               .DestinationBlend(alpha: Blend.One)
                                                                               .Build())
                                                      .Build();

                _drawAdditiveBlend = _blendBuilder.BlendState(blendStateBuilder
                                                              .ResetTo(GorgonBlendState.Additive)
                                                              .DestinationBlend(alpha: Blend.One)
                                                              .Build())
                                     .Build();

                _drawNoBlend = _blendBuilder.BlendState(blendStateBuilder
                                                        .ResetTo(GorgonBlendState.NoBlending)
                                                        .DestinationBlend(alpha: Blend.One)
                                                        .Build())
                               .Build();

                GorgonApplication.IdleMethod = Gorgon_Idle;
            }
            catch (ReflectionTypeLoadException refEx)
            {
                string refErr = string.Join("\n", refEx.LoaderExceptions.Select(item => item.Message));
                GorgonDialogs.ErrorBox(this, refErr);
            }
            catch (Exception ex)
            {
                GorgonExample.HandleException(ex);
                GorgonApplication.Quit();
            }
        }
Example #6
0
        /// <summary>
        /// Function to initialize the application.
        /// </summary>
        /// <returns>The main window for the application.</returns>
        private static FormMain Initialize()
        {
            GorgonExample.ResourceBaseDirectory   = new DirectoryInfo(Settings.Default.ResourceLocation);
            GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.PlugInLocation);

            FormMain window = GorgonExample.Initialize(new DX.Size2(Settings.Default.Resolution.Width, Settings.Default.Resolution.Height), "Depth");

            try
            {
                IReadOnlyList <IGorgonVideoAdapterInfo> videoDevices = GorgonGraphics.EnumerateAdapters(log: GorgonApplication.Log);

                if (videoDevices.Count == 0)
                {
                    throw new GorgonException(GorgonResult.CannotCreate,
                                              "Gorgon requires at least a Direct3D 11.4 capable video device.\nThere is no suitable device installed on the system.");
                }

                // Find the best video device.
                _graphics = new GorgonGraphics(videoDevices.OrderByDescending(item => item.FeatureSet).First());

                _screen = new GorgonSwapChain(_graphics,
                                              window,
                                              new GorgonSwapChainInfo("Gorgon2D Depth Buffer Example")
                {
                    Width  = Settings.Default.Resolution.Width,
                    Height = Settings.Default.Resolution.Height,
                    Format = BufferFormat.R8G8B8A8_UNorm
                });

                _depthBuffer = GorgonDepthStencil2DView.CreateDepthStencil(_graphics, new GorgonTexture2DInfo(_screen.RenderTargetView)
                {
                    Binding = TextureBinding.DepthStencil,
                    Format  = BufferFormat.D24_UNorm_S8_UInt
                });

                // Tell the graphics API that we want to render to the "screen" swap chain.
                _graphics.SetRenderTarget(_screen.RenderTargetView, _depthBuffer);

                // Initialize the renderer so that we are able to draw stuff.
                _renderer = new Gorgon2D(_graphics);

                GorgonExample.LoadResources(_graphics);

                // Load our packed file system plug in.
                _assemblyCache = new GorgonMefPlugInCache(GorgonApplication.Log);
                _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.FileSystem.GorPack.dll");
                IGorgonPlugInService plugIns = new GorgonMefPlugInService(_assemblyCache);

                // Load the file system containing our application data (sprites, images, etc...)
                IGorgonFileSystemProviderFactory providerFactory = new GorgonFileSystemProviderFactory(plugIns, GorgonApplication.Log);
                IGorgonFileSystemProvider        provider        = providerFactory.CreateProvider("Gorgon.IO.GorPack.GorPackProvider");
                IGorgonFileSystem fileSystem = new GorgonFileSystem(provider, GorgonApplication.Log);

                // We can load the editor file system directly.
                // This is handy for switching a production environment where your data may be stored
                // as a compressed file, and a development environment where your data consists of loose
                // files.
                // fileSystem.Mount(@"D:\unpak\scratch\DeepAsAPuddle.gorPack\fs\");

                // For now though, we'll load the packed file.
                fileSystem.Mount(Path.Combine(GorgonExample.GetResourcePath(@"FileSystems").FullName, "Depth.gorPack"));

                // Get our sprites.  These make up the frames of animation for our Guy.
                // If and when there's an animation editor, we'll only need to create a single sprite and load the animation.
                IGorgonVirtualFile[] spriteFiles = fileSystem.FindFiles("/Sprites/", "*", true).ToArray();

                // Load our sprite data (any associated textures will be loaded as well).
                Dictionary <string, GorgonSprite> sprites = new Dictionary <string, GorgonSprite>(StringComparer.OrdinalIgnoreCase);

                for (int i = 0; i < spriteFiles.Length; i++)
                {
                    IGorgonVirtualFile file = spriteFiles[i];
                    (GorgonSprite sprite, GorgonTexture2D texture) = fileSystem.LoadSprite(_renderer, file.FullPath);

                    // The LoadSprite extension method will automatically find and load your associated texture if you're using
                    // a Gorgon editor file system. So it's important that you leep track of your textures, disposing of just
                    // the associated GorgonTexture2DView won't cut it here, so you'll need to dispose the actual texture resource
                    // when you're done with it.
                    if (!_textures.Contains(texture))
                    {
                        _textures.Add(texture);
                    }

                    // At super duper resolution, the example graphics would be really hard to see, so we'll scale them up.
                    sprite.Scale       = new DX.Vector2((_screen.Width / (_screen.Height / 2)) * 2.0f);
                    sprites[file.Name] = sprite;
                }

                _snowTile       = sprites["Snow"];
                _snowTile.Depth = 0.5f;

                _icicle       = sprites["Icicle"];
                _icicle.Depth = 0.2f;

                _guySprite       = sprites["Guy_Up_0"];
                _guySprite.Depth = 0.1f;
                _guyPosition     = new DX.Vector2(_screen.Width / 2 + _guySprite.ScaledSize.Width * 1.25f, _screen.Height / 2 + _guySprite.ScaledSize.Height);

                BuildAnimations(sprites);
            }
            finally
            {
                GorgonExample.EndInit();
            }

            return(window);
        }
Example #7
0
        /// <summary>
        /// Function to load the file system provider plug ins.
        /// </summary>
        /// <param name="pluginCache">The MEF plug in cache used to load the file system plug ins.</param>
        /// <param name="pluginDir">The plug in directory.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="pluginCache"/>, or the <paramref name="pluginDir"/> parameter is <b>null</b>.</exception>
        public void LoadProviders(GorgonMefPlugInCache pluginCache, DirectoryInfo pluginDir)
        {
            if (pluginCache == null)
            {
                throw new ArgumentNullException(nameof(pluginCache));
            }

            if (pluginDir == null)
            {
                throw new ArgumentNullException(nameof(pluginDir));
            }

            IReadOnlyList <PlugInAssemblyState> assemblies = pluginCache.ValidateAndLoadAssemblies(pluginDir.GetFiles("*.dll"), Program.Log);

            if (assemblies.Count > 0)
            {
                foreach (PlugInAssemblyState record in assemblies.Where(item => !item.IsAssemblyLoaded && item.IsManaged))
                {
                    _disabled[Path.GetFileName(record.Path)] = new DisabledPlugIn(DisabledReasonCode.Error, Path.GetFileName(record.Path), record.LoadFailureReason, record.Path);
                }
            }

            IGorgonPlugInService plugins = new GorgonMefPlugInService(pluginCache);
            IReadOnlyList <GorgonFileSystemProvider> readers = plugins.GetPlugIns <GorgonFileSystemProvider>();
            IReadOnlyList <FileWriterPlugIn>         writers = plugins.GetPlugIns <FileWriterPlugIn>();

            // Get readers.
            foreach (IGorgonFileSystemProvider reader in readers)
            {
                try
                {
                    Program.Log.Print($"Creating file system reader plug in '{reader.Name}'...", LoggingLevel.Simple);
                    _readers[reader.Name] = reader;
                }
                catch (Exception ex)
                {
                    Program.Log.Print($"ERROR: Cannot create file system reader plug in '{reader.Name}'.", LoggingLevel.Simple);
                    Program.Log.LogException(ex);

                    _disabled[reader.Name] = new DisabledPlugIn(DisabledReasonCode.Error, reader.Name, string.Format(Resources.GOREDIT_DISABLE_FILE_PROVIDER_EXCEPTION, ex.Message), reader.ProviderPath);
                }
            }

            // Get writers
            foreach (FileWriterPlugIn writer in writers)
            {
                IReadOnlyList <string> disabled = writer.IsPlugInAvailable();

                try
                {
                    Program.Log.Print($"Creating file system writer plug in '{writer.Name}'...", LoggingLevel.Simple);

                    if (disabled.Count != 0)
                    {
                        Program.Log.Print($"WARNING: The file system writer plug in '{writer.Name}' is disabled:", LoggingLevel.Simple);
                        foreach (string reason in disabled)
                        {
                            Program.Log.Print($"WARNING: {reason}", LoggingLevel.Verbose);
                        }

                        _disabled[writer.Name] = new DisabledPlugIn(DisabledReasonCode.ValidationError, writer.Name, string.Join("\n", disabled), writer.PlugInPath);
                        continue;
                    }

                    writer.AssignCommonServices(_commonServices);
                    _writers[writer.GetType().FullName] = writer;
                }
                catch (Exception ex)
                {
                    Program.Log.Print($"ERROR: Cannot create file system writer plug in '{writer.Name}'.", LoggingLevel.Simple);
                    Program.Log.LogException(ex);

                    _disabled[writer.Name] = new DisabledPlugIn(DisabledReasonCode.Error, writer.Name, string.Format(Resources.GOREDIT_DISABLE_FILE_PROVIDER_EXCEPTION, ex.Message), writer.PlugInPath);
                }
            }
        }
Example #8
0
        private static void Main(string[] args)
        {
            _log = new GorgonLog("Example 004", "Tape_Worm", typeof(Program).Assembly.GetName().Version);

            // Set up the assembly cache.
            // We'll need the assemblies loaded into this object in order to load our plugin types.
            var pluginCache = new GorgonMefPlugInCache(_log);

            // Create our plugin service.
            // This takes the cache of assemblies we just created.
            IGorgonPlugInService pluginService = new GorgonMefPlugInService(pluginCache);

            try
            {
                Console.Title           = "Gorgon Example #4 - PlugIns.";
                Console.ForegroundColor = ConsoleColor.White;

                Console.WriteLine("This is an example to show how to create and use custom plugins.");
                Console.WriteLine("The plugin interface in Gorgon is quite flexible and gives the developer");
                Console.WriteLine("the ability to allow extensions to their own applications.\n");

                Console.ResetColor();

                pluginCache.LoadPlugInAssemblies(Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]).FormatDirectory(Path.DirectorySeparatorChar), "Example004.*PlugIn.dll");
                Console.WriteLine("{0} plugin assemblies found.", pluginCache.PlugInAssemblies.Count);

                if (pluginCache.PlugInAssemblies.Count == 0)
                {
                    return;
                }

                // Our text writer plugin interfaces.
                IList <TextColorWriter> writers = new List <TextColorWriter>();

                // Create our plugin instances, we'll limit to 9 entries just for giggles.
                TextColorPlugIn[] plugins = (from pluginName in pluginService.GetPlugInNames()
                                             let plugin = pluginService.GetPlugIn <TextColorPlugIn>(pluginName)
                                                          where plugin != null
                                                          select plugin).ToArray();

                // Display a list of the available plugins.
                Console.WriteLine("\n{0} Plug-ins loaded:\n", plugins.Length);
                for (int i = 0; i < plugins.Length; i++)
                {
                    // Here's where we make use of our description.
                    Console.WriteLine("{0}. {1} ({2})", i + 1, plugins[i].Description, plugins[i].GetType().FullName);

                    // Create the text writer interface and add it to the list.
                    writers.Add(plugins[i].CreateWriter());
                }

                Console.Write("0. Quit\n\nSelect a plugin:  ");

                // Loop until we quit.
                while (true)
                {
                    if (!Console.KeyAvailable)
                    {
                        continue;
                    }

                    Console.ResetColor();

                    // Remember our cursor coordinates.
                    int cursorX = Console.CursorLeft; // Cursor position.
                    int cursorY = Console.CursorTop;

                    ConsoleKeyInfo keyValue = Console.ReadKey(false);

                    if (char.IsNumber(keyValue.KeyChar))
                    {
                        if (keyValue.KeyChar == '0')
                        {
                            break;
                        }

                        // Move to the next line and clear the previous line of text.
                        Console.WriteLine();
                        Console.Write(new string(' ', Console.BufferWidth - 1));
                        Console.CursorLeft = 0;

                        // Call our text color writer to print the text in the plugin color.
                        int writerIndex = keyValue.KeyChar - '0';
                        writers[writerIndex - 1].WriteString($"You pressed #{writerIndex}.");
                    }

                    Console.CursorTop  = cursorY;
                    Console.CursorLeft = cursorX;
                }
            }
            catch (Exception ex)
            {
                ex.Catch(_ =>
                {
                    Console.Clear();
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Exception:\n{0}\n\nStack Trace:{1}", ex.Message, ex.StackTrace);
                },
                         _log);
                Console.ResetColor();
#if DEBUG
                Console.ReadKey(true);
#endif
            }
            finally
            {
                // Always call dispose so we can unload our temporary application domain.
                //pluginAssemblies.Dispose();
                pluginCache.Dispose();

                _log.LogEnd();
            }
        }