From 3a366cc1e460b1a25105b6a9a4279cba329bacc8 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Thu, 18 Aug 2022 23:23:00 +0200 Subject: [PATCH] Core: Rewrite plugin system --- examples/Showcase/main.cpp | 10 +- include/Nazara/Core.hpp | 4 +- include/Nazara/Core/Enums.hpp | 10 - include/Nazara/Core/Plugin.hpp | 55 ++++ include/Nazara/Core/Plugin.inl | 82 +++++ include/Nazara/Core/PluginInterface.hpp | 38 +++ include/Nazara/Core/PluginInterface.inl | 12 + include/Nazara/Core/PluginLoader.hpp | 48 +++ include/Nazara/Core/PluginLoader.inl | 19 ++ include/Nazara/Core/PluginManager.hpp | 58 ---- .../Nazara/Utility/Plugins/AssimpPlugin.hpp | 37 +++ .../Nazara/Utility/Plugins/AssimpPlugin.inl | 12 + .../Nazara/Utility/Plugins/FFmpegPlugin.hpp | 39 +++ .../Nazara/Utility/Plugins/FFmpegPlugin.inl | 12 + plugins/Assimp/Plugin.cpp | 106 ++++--- plugins/FFmpeg/Plugin.cpp | 84 +++-- src/Nazara/Core/Core.cpp | 3 +- src/Nazara/Core/PluginInterface.cpp | 11 + src/Nazara/Core/PluginLoader.cpp | 75 +++++ src/Nazara/Core/PluginManager.cpp | 295 ------------------ src/Nazara/Utility/Plugin/AssimpPlugin.cpp | 10 + src/Nazara/Utility/Plugin/FFmpegPlugin.cpp | 10 + 22 files changed, 596 insertions(+), 434 deletions(-) create mode 100644 include/Nazara/Core/Plugin.hpp create mode 100644 include/Nazara/Core/Plugin.inl create mode 100644 include/Nazara/Core/PluginInterface.hpp create mode 100644 include/Nazara/Core/PluginInterface.inl create mode 100644 include/Nazara/Core/PluginLoader.hpp create mode 100644 include/Nazara/Core/PluginLoader.inl delete mode 100644 include/Nazara/Core/PluginManager.hpp create mode 100644 include/Nazara/Utility/Plugins/AssimpPlugin.hpp create mode 100644 include/Nazara/Utility/Plugins/AssimpPlugin.inl create mode 100644 include/Nazara/Utility/Plugins/FFmpegPlugin.hpp create mode 100644 include/Nazara/Utility/Plugins/FFmpegPlugin.inl create mode 100644 src/Nazara/Core/PluginInterface.cpp create mode 100644 src/Nazara/Core/PluginLoader.cpp delete mode 100644 src/Nazara/Core/PluginManager.cpp create mode 100644 src/Nazara/Utility/Plugin/AssimpPlugin.cpp create mode 100644 src/Nazara/Utility/Plugin/FFmpegPlugin.cpp diff --git a/examples/Showcase/main.cpp b/examples/Showcase/main.cpp index 92a0846dc..5183b269e 100644 --- a/examples/Showcase/main.cpp +++ b/examples/Showcase/main.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -31,12 +32,9 @@ int main() rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; Nz::Modules nazara(rendererConfig); - - Nz::PluginManager::Mount(Nz::Plugin::Assimp); - Nz::CallOnExit unmountAssimp([] - { - Nz::PluginManager::Unmount(Nz::Plugin::Assimp); - }); + + Nz::PluginLoader loader; + Nz::Plugin assimp = loader.Load(); std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index 1cc50c19f..68cc69662 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -61,7 +61,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index fd8459561..f0e06d94f 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -132,16 +132,6 @@ namespace Nz Max = Userdata }; - enum class Plugin - { - Assimp, - FFmpeg, - - Max = Assimp - }; - - constexpr std::size_t PluginCount = static_cast(Plugin::Max) + 1; - enum class PrimitiveType { Box, diff --git a/include/Nazara/Core/Plugin.hpp b/include/Nazara/Core/Plugin.hpp new file mode 100644 index 000000000..5b4a2a89a --- /dev/null +++ b/include/Nazara/Core/Plugin.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CORE_PLUGIN_HPP +#define NAZARA_CORE_PLUGIN_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + template + class Plugin + { + static_assert(std::is_base_of_v); + + public: + Plugin(DynLib dynLib, std::unique_ptr pluginInterface, bool isActive = false); + Plugin(const Plugin&) = delete; + Plugin(Plugin&&) = delete; + ~Plugin(); + + bool Activate(); + + template Plugin Cast() &&; + + void Deactivate(); + + const DynLib& GetDynamicLibrary() const; + + T* operator->(); + const T* operator->() const; + + Plugin& operator=(const Plugin&) = delete; + Plugin& operator=(Plugin&&) = delete; + + private: + std::unique_ptr m_interface; + DynLib m_lib; + bool m_isActive; + }; + + using GenericPlugin = Plugin; +} + +#include + +#endif // NAZARA_CORE_PLUGIN_HPP diff --git a/include/Nazara/Core/Plugin.inl b/include/Nazara/Core/Plugin.inl new file mode 100644 index 000000000..a2f627c68 --- /dev/null +++ b/include/Nazara/Core/Plugin.inl @@ -0,0 +1,82 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + template + Plugin::Plugin(DynLib dynLib, std::unique_ptr pluginInterface, bool isActive) : + m_interface(std::move(pluginInterface)), + m_lib(std::move(dynLib)), + m_isActive(isActive) + { + } + + template + Plugin::~Plugin() + { + if (m_interface) + { + Deactivate(); + + // Destroys interface before freeing the library + m_interface.reset(); + } + + m_lib.Unload(); + } + + template + bool Plugin::Activate() + { + if (m_isActive) + return true; + + if (!m_interface->Activate()) + return false; + + m_isActive = true; + return true; + } + + template + template + Plugin Plugin::Cast() && + { + return Plugin(std::move(m_lib), std::unique_ptr(static_cast(m_interface.release())), m_isActive); + } + + template + void Plugin::Deactivate() + { + if (m_isActive) + { + m_interface->Deactivate(); + m_isActive = false; + } + } + + template + const DynLib& Plugin::GetDynamicLibrary() const + { + return m_lib; + } + + template + T* Plugin::operator->() + { + return m_interface; + } + + template + const T* Plugin::operator->() const + { + return m_interface; + } +} + +#include diff --git a/include/Nazara/Core/PluginInterface.hpp b/include/Nazara/Core/PluginInterface.hpp new file mode 100644 index 000000000..e6cbaf923 --- /dev/null +++ b/include/Nazara/Core/PluginInterface.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CORE_PLUGININTERFACE_HPP +#define NAZARA_CORE_PLUGININTERFACE_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_CORE_API PluginInterface + { + public: + PluginInterface() = default; + PluginInterface(const PluginInterface&) = delete; + PluginInterface(PluginInterface&&) = delete; + virtual ~PluginInterface(); + + virtual bool Activate() = 0; + virtual void Deactivate() = 0; + + virtual std::string_view GetDescription() const = 0; + virtual std::string_view GetName() const = 0; + virtual UInt32 GetVersion() const = 0; + + PluginInterface& operator=(const PluginInterface&) = delete; + PluginInterface& operator=(PluginInterface&&) = delete; + }; +} + +#include + +#endif // NAZARA_CORE_PLUGININTERFACE_HPP diff --git a/include/Nazara/Core/PluginInterface.inl b/include/Nazara/Core/PluginInterface.inl new file mode 100644 index 000000000..c1bcf7941 --- /dev/null +++ b/include/Nazara/Core/PluginInterface.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Core/PluginLoader.hpp b/include/Nazara/Core/PluginLoader.hpp new file mode 100644 index 000000000..fd6f6fba5 --- /dev/null +++ b/include/Nazara/Core/PluginLoader.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CORE_PLUGINLOADER_HPP +#define NAZARA_CORE_PLUGINLOADER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class PluginInterface; + + class NAZARA_CORE_API PluginLoader + { + public: + PluginLoader(); + PluginLoader(const PluginLoader&) = delete; + PluginLoader(PluginLoader&&) = delete; + ~PluginLoader() = default; + + void AddSearchDirectory(const std::filesystem::path& directoryPath); + + template Plugin Load(bool activate = true); + GenericPlugin Load(const std::filesystem::path& pluginPath, bool activate = true); + + void RemoveSearchDirectory(const std::filesystem::path& directoryPath); + + PluginLoader& operator=(const PluginLoader&) = delete; + PluginLoader& operator=(PluginLoader&&) = delete; + + private: + using PluginLoadCallback = PluginInterface* (*)(); + + std::vector m_directories; + }; +} + +#include + +#endif // NAZARA_CORE_PLUGINLOADER_HPP diff --git a/include/Nazara/Core/PluginLoader.inl b/include/Nazara/Core/PluginLoader.inl new file mode 100644 index 000000000..0d691bf03 --- /dev/null +++ b/include/Nazara/Core/PluginLoader.inl @@ -0,0 +1,19 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + template + Plugin PluginLoader::Load(bool activate) + { + GenericPlugin plugin = Load(Utf8Path(T::Filename), activate); + return std::move(plugin).Cast(); + } +} + +#include diff --git a/include/Nazara/Core/PluginManager.hpp b/include/Nazara/Core/PluginManager.hpp deleted file mode 100644 index 1964259c9..000000000 --- a/include/Nazara/Core/PluginManager.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Core module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_CORE_PLUGINMANAGER_HPP -#define NAZARA_CORE_PLUGINMANAGER_HPP - -#include -#include -#include -#include -#include -#include - -///TODO: Revision -namespace Nz -{ - class DynLib; - - class NAZARA_CORE_API PluginManager - { - public: - PluginManager() = delete; - ~PluginManager() = delete; - - static void AddDirectory(const std::filesystem::path& directoryPath); - - static bool Initialize(); - - static bool Mount(Plugin plugin); - static bool Mount(const std::filesystem::path& pluginPath, bool appendExtension = true); - - static void RemoveDirectory(const std::filesystem::path& directoryPath); - - static void Unmount(Plugin plugin); - static void Unmount(const std::filesystem::path& pluginPath); - - static void Uninitialize(); - - private: - // https://stackoverflow.com/questions/51065244/is-there-no-standard-hash-for-stdfilesystempath - struct PathHash - { - std::size_t operator()(const std::filesystem::path& p) const - { - return hash_value(p); - } - }; - - static std::set s_directories; - static std::unordered_map, PathHash> s_plugins; - static bool s_initialized; - }; -} - -#endif // NAZARA_CORE_PLUGINMANAGER_HPP diff --git a/include/Nazara/Utility/Plugins/AssimpPlugin.hpp b/include/Nazara/Utility/Plugins/AssimpPlugin.hpp new file mode 100644 index 000000000..382db075b --- /dev/null +++ b/include/Nazara/Utility/Plugins/AssimpPlugin.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_UTILITY_PLUGIN_ASSIMPPLUGIN_HPP +#define NAZARA_UTILITY_PLUGIN_ASSIMPPLUGIN_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_UTILITY_API AssimpPlugin : public PluginInterface + { + public: +#ifdef NAZARA_DEBUG + static constexpr std::string_view Filename = "PluginAssimp-d"; +#else + static constexpr std::string_view Filename = "PluginAssimp"; +#endif + + AssimpPlugin() = default; + AssimpPlugin(const AssimpPlugin&) = delete; + AssimpPlugin(AssimpPlugin&&) = delete; + ~AssimpPlugin() = default; + + AssimpPlugin& operator=(const AssimpPlugin&) = delete; + AssimpPlugin& operator=(AssimpPlugin&&) = delete; + }; +} + +#include + +#endif // NAZARA_UTILITY_PLUGIN_ASSIMPPLUGIN_HPP diff --git a/include/Nazara/Utility/Plugins/AssimpPlugin.inl b/include/Nazara/Utility/Plugins/AssimpPlugin.inl new file mode 100644 index 000000000..040546a90 --- /dev/null +++ b/include/Nazara/Utility/Plugins/AssimpPlugin.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Utility/Plugins/FFmpegPlugin.hpp b/include/Nazara/Utility/Plugins/FFmpegPlugin.hpp new file mode 100644 index 000000000..62ca057c0 --- /dev/null +++ b/include/Nazara/Utility/Plugins/FFmpegPlugin.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_UTILITY_PLUGIN_FFMPEGPLUGIN_HPP +#define NAZARA_UTILITY_PLUGIN_FFMPEGPLUGIN_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_UTILITY_API FFmpegPlugin : public PluginInterface + { + public: +#ifdef NAZARA_DEBUG + static constexpr std::string_view Filename = "PluginFFmpeg-d"; +#else + static constexpr std::string_view Filename = "PluginFFmpeg"; +#endif + + FFmpegPlugin() = default; + FFmpegPlugin(const FFmpegPlugin&) = delete; + FFmpegPlugin(FFmpegPlugin&&) = delete; + ~FFmpegPlugin() = default; + + FFmpegPlugin& operator=(const FFmpegPlugin&) = delete; + FFmpegPlugin& operator=(FFmpegPlugin&&) = delete; + + private: + }; +} + +#include + +#endif // NAZARA_UTILITY_PLUGIN_FFMPEGPLUGIN_HPP diff --git a/include/Nazara/Utility/Plugins/FFmpegPlugin.inl b/include/Nazara/Utility/Plugins/FFmpegPlugin.inl new file mode 100644 index 000000000..aa5136a06 --- /dev/null +++ b/include/Nazara/Utility/Plugins/FFmpegPlugin.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 96bde1b88..93b31bf1a 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -40,6 +40,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -888,49 +889,80 @@ std::shared_ptr LoadMesh(Nz::Stream& stream, const Nz::MeshParams& par namespace { - const Nz::AnimationLoader::Entry* animationLoaderEntry = nullptr; - const Nz::MeshLoader::Entry* meshLoaderEntry = nullptr; + class AssimpPluginImpl final : public Nz::AssimpPlugin + { + public: + bool Activate() override + { + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); + m_animationLoaderEntry = animationLoader.RegisterLoader({ + IsSupported, + nullptr, + nullptr, + CheckAnimation, + LoadAnimation + }); + + Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); + m_meshLoaderEntry = meshLoader.RegisterLoader({ + IsSupported, + nullptr, + nullptr, + CheckMesh, + LoadMesh + }); + + return true; + } + + void Deactivate() override + { + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); + animationLoader.UnregisterLoader(m_animationLoaderEntry); + + Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); + meshLoader.UnregisterLoader(m_meshLoaderEntry); + } + + std::string_view GetDescription() const + { + return "Adds supports to load meshes and animations using Assimp"; + } + + std::string_view GetName() const override + { + return "Assimp loader"; + } + + Nz::UInt32 GetVersion() const override + { + return 100; + } + + private: + const Nz::AnimationLoader::Entry* m_animationLoaderEntry = nullptr; + const Nz::MeshLoader::Entry* m_meshLoaderEntry = nullptr; + }; } extern "C" { - NAZARA_EXPORT int PluginLoad() + NAZARA_EXPORT Nz::PluginInterface* PluginLoad() { Nz::Utility* utility = Nz::Utility::Instance(); - NazaraAssert(utility, "utility module is not instancied"); + if (!utility) + { + NazaraError("Utility module must be initialized"); + return nullptr; + } - Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); - animationLoaderEntry = animationLoader.RegisterLoader({ - IsSupported, - nullptr, - nullptr, - CheckAnimation, - LoadAnimation - }); - - Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); - meshLoaderEntry = meshLoader.RegisterLoader({ - IsSupported, - nullptr, - nullptr, - CheckMesh, - LoadMesh - }); - - return 1; - } - - NAZARA_EXPORT void PluginUnload() - { - Nz::Utility* utility = Nz::Utility::Instance(); - NazaraAssert(utility, "utility module is not instancied"); - - Nz::AnimationLoader& animationLoader = utility->GetAnimationLoader(); - animationLoader.UnregisterLoader(animationLoaderEntry); - animationLoaderEntry = nullptr; - - Nz::MeshLoader& meshLoader = utility->GetMeshLoader(); - meshLoader.UnregisterLoader(meshLoaderEntry); - meshLoaderEntry = nullptr; + std::unique_ptr plugin = std::make_unique(); + return plugin.release(); } } diff --git a/plugins/FFmpeg/Plugin.cpp b/plugins/FFmpeg/Plugin.cpp index e250de233..ba4b28fcd 100644 --- a/plugins/FFmpeg/Plugin.cpp +++ b/plugins/FFmpeg/Plugin.cpp @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with thi #include #include #include +#include extern "C" { @@ -28,8 +29,6 @@ extern "C" namespace { - const Nz::ImageStreamLoader::Entry* ffmpegLoaderEntry = nullptr; - class FFmpegStream : public Nz::ImageStream { public: @@ -448,35 +447,70 @@ namespace return ffmpegStream; } + + class FFmpegPluginImpl final : public Nz::FFmpegPlugin + { + public: + bool Activate() override + { + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::ImageStreamLoader::Entry loaderEntry; + loaderEntry.extensionSupport = CheckVideoExtension; + loaderEntry.streamChecker = CheckVideo; + loaderEntry.fileLoader = LoadFile; + loaderEntry.memoryLoader = LoadMemory; + loaderEntry.streamLoader = LoadStream; + + Nz::ImageStreamLoader& imageStreamLoader = utility->GetImageStreamLoader(); + m_ffmpegLoaderEntry = imageStreamLoader.RegisterLoader(loaderEntry); + + return true; + } + + void Deactivate() override + { + Nz::Utility* utility = Nz::Utility::Instance(); + NazaraAssert(utility, "utility module is not instancied"); + + Nz::ImageStreamLoader& imageStreamLoader = utility->GetImageStreamLoader(); + imageStreamLoader.UnregisterLoader(m_ffmpegLoaderEntry); + m_ffmpegLoaderEntry = nullptr; + } + + std::string_view GetDescription() const + { + return "Adds supports to load and decode videos streams"; + } + + std::string_view GetName() const override + { + return "FFMpeg loader"; + } + + Nz::UInt32 GetVersion() const override + { + return 100; + } + + private: + const Nz::ImageStreamLoader::Entry* m_ffmpegLoaderEntry = nullptr; + }; } extern "C" { - NAZARA_EXPORT int PluginLoad() + NAZARA_EXPORT Nz::PluginInterface* PluginLoad() { Nz::Utility* utility = Nz::Utility::Instance(); - NazaraAssert(utility, "utility module is not instancied"); + if (!utility) + { + NazaraError("Utility module must be initialized"); + return nullptr; + } - Nz::ImageStreamLoader::Entry loaderEntry; - loaderEntry.extensionSupport = CheckVideoExtension; - loaderEntry.streamChecker = CheckVideo; - loaderEntry.fileLoader = LoadFile; - loaderEntry.memoryLoader = LoadMemory; - loaderEntry.streamLoader = LoadStream; - - Nz::ImageStreamLoader& imageStreamLoader = utility->GetImageStreamLoader(); - ffmpegLoaderEntry = imageStreamLoader.RegisterLoader(loaderEntry); - - return 1; - } - - NAZARA_EXPORT void PluginUnload() - { - Nz::Utility* utility = Nz::Utility::Instance(); - NazaraAssert(utility, "utility module is not instancied"); - - Nz::ImageStreamLoader& imageStreamLoader = utility->GetImageStreamLoader(); - imageStreamLoader.UnregisterLoader(ffmpegLoaderEntry); - ffmpegLoaderEntry = nullptr; + std::unique_ptr plugin = std::make_unique(); + return plugin.release(); } } diff --git a/src/Nazara/Core/Core.cpp b/src/Nazara/Core/Core.cpp index 8b555c21b..6c713d08d 100644 --- a/src/Nazara/Core/Core.cpp +++ b/src/Nazara/Core/Core.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -30,7 +30,6 @@ namespace Nz Core::~Core() { HardwareInfo::Uninitialize(); - PluginManager::Uninitialize(); TaskScheduler::Uninitialize(); LogUninit(); Log::Uninitialize(); diff --git a/src/Nazara/Core/PluginInterface.cpp b/src/Nazara/Core/PluginInterface.cpp new file mode 100644 index 000000000..1d49cf7b3 --- /dev/null +++ b/src/Nazara/Core/PluginInterface.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + PluginInterface::~PluginInterface() = default; +} diff --git a/src/Nazara/Core/PluginLoader.cpp b/src/Nazara/Core/PluginLoader.cpp new file mode 100644 index 000000000..b44f19638 --- /dev/null +++ b/src/Nazara/Core/PluginLoader.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + PluginLoader::PluginLoader() + { + AddSearchDirectory("."); + AddSearchDirectory("plugins"); + } + + void PluginLoader::AddSearchDirectory(const std::filesystem::path& directoryPath) + { + m_directories.push_back(std::filesystem::absolute(directoryPath)); + } + + GenericPlugin PluginLoader::Load(const std::filesystem::path& pluginPath, bool activate) + { + std::filesystem::path path = pluginPath; + if (path.extension() != NAZARA_DYNLIB_EXTENSION) + path += NAZARA_DYNLIB_EXTENSION; + + bool exists = false; + if (!path.is_absolute()) + { + for (const std::filesystem::path& dir : m_directories) + { + std::filesystem::path testPath = dir / path; + if (std::filesystem::exists(testPath)) + { + path = testPath; + exists = true; + break; + } + } + } + else if (std::filesystem::exists(path)) + exists = true; + + if (!exists) + throw std::runtime_error("failed to find plugin file"); + + DynLib library; + if (!library.Load(path)) + throw std::runtime_error("failed to load plugin"); + + PluginLoadCallback loadFunc = reinterpret_cast(library.GetSymbol("PluginLoad")); + if (!loadFunc) + throw std::runtime_error("failed to load plugin: PluginLoad symbol not found"); + + std::unique_ptr pluginInterface = std::unique_ptr(loadFunc()); + if (!pluginInterface) + throw std::runtime_error("plugin failed to load"); + + if (activate && !pluginInterface->Activate()) + throw std::runtime_error("failed to activate plugin"); + + return GenericPlugin(std::move(library), std::move(pluginInterface), activate); + } + + void PluginLoader::RemoveSearchDirectory(const std::filesystem::path& directoryPath) + { + auto it = std::find(m_directories.begin(), m_directories.end(), std::filesystem::absolute(directoryPath)); + if (it != m_directories.end()) + m_directories.erase(it); + } + +} diff --git a/src/Nazara/Core/PluginManager.cpp b/src/Nazara/Core/PluginManager.cpp deleted file mode 100644 index 13092e9fd..000000000 --- a/src/Nazara/Core/PluginManager.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Core module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include - -#ifdef NAZARA_PLATFORM_WINDOWS -#define NAZARA_DYNLIB_PREFIX "" -#else -#define NAZARA_DYNLIB_PREFIX "lib" -#endif - -namespace Nz -{ - namespace NAZARA_ANONYMOUS_NAMESPACE - { - using PluginLoad = int (*)(); - using PluginUnload = void (*)(); - - const char* s_pluginFiles[] = - { - NAZARA_DYNLIB_PREFIX "PluginAssimp", // Plugin::Assimp - NAZARA_DYNLIB_PREFIX "PluginFFmpeg", // Plugin::FFmpeg - }; - } - - /*! - * \ingroup core - * \class Nz::PluginManager - * \brief Core class that represents a manager for plugin - */ - - /*! - * \brief Adds a directory - * - * \param directoryPath Path to the directory - * - * \remark Produces a NazaraError if not initialized - */ - - void PluginManager::AddDirectory(const std::filesystem::path& directoryPath) - { - if (!Initialize()) - { - NazaraError("Failed to initialize PluginManager"); - return; - } - - s_directories.insert(std::filesystem::absolute(directoryPath)); - } - - /*! - * \brief Initializes the plugin manager - * \return true if everything is ok - */ - - bool PluginManager::Initialize() - { - if (s_initialized) - return true; - - s_initialized = true; - - AddDirectory("."); - AddDirectory("plugins"); - - return true; - } - - /*! - * \brief Mounts the plugin - * \return true if mounting was a success - * - * \remark Produces a NazaraError if not initialized - * \remark Produces a NazaraError if plugin is not found - * \remark Produces a NazaraError if fail to load plugin - * \remark Produces a NazaraError if fail to get symbol PluginLoad - * \remark Produces a NazaraError if fail to initialize the plugin with PluginLoad - */ - - bool PluginManager::Mount(Plugin plugin) - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - std::filesystem::path pluginName = s_pluginFiles[UnderlyingCast(plugin)]; - - #ifdef NAZARA_DEBUG - std::filesystem::path debugPath = pluginName; - debugPath += "-d"; - - if (Mount(debugPath, true)) - return true; - #endif - - return Mount(pluginName, true); - } - - /*! - * \brief Mounts the plugin with a path - * \return true if mounting was a success - * - * \param pluginPath Path to the plugin - * \param appendExtension Adds the extension to the path or not - * - * \remark Produces a NazaraError if not initialized - * \remark Produces a NazaraError if plugin is not found - * \remark Produces a NazaraError if fail to load plugin - * \remark Produces a NazaraError if fail to get symbol PluginLoad - * \remark Produces a NazaraError if fail to initialize the plugin with PluginLoad - */ - - bool PluginManager::Mount(const std::filesystem::path& pluginPath, bool appendExtension) - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - if (!Initialize()) - { - NazaraError("Failed to initialize PluginManager"); - return false; - } - - std::filesystem::path path = pluginPath; - if (appendExtension && path.extension() != NAZARA_DYNLIB_EXTENSION) - path += NAZARA_DYNLIB_EXTENSION; - - bool exists = false; - if (!path.is_absolute()) - { - for (const std::filesystem::path& dir : s_directories) - { - std::filesystem::path testPath = dir / path; - if (std::filesystem::exists(testPath)) - { - path = testPath; - exists = true; - break; - } - } - } - else if (std::filesystem::exists(path)) - exists = true; - - if (!exists) - { - NazaraError("Failed to find plugin file"); - return false; - } - - std::unique_ptr library = std::make_unique(); - if (!library->Load(path)) - { - NazaraError("Failed to load plugin"); - return false; - } - - PluginLoad func = reinterpret_cast(library->GetSymbol("PluginLoad")); - if (!func) - { - NazaraError("Failed to get symbol PluginLoad"); - return false; - } - - if (!func()) - { - NazaraError("Plugin failed to load"); - return false; - } - - std::filesystem::path canonicalPath = std::filesystem::canonical(path); - s_plugins[canonicalPath] = std::move(library); - - return true; - } - - /*! - * \brief Removes a directory - * - * \param directoryPath Path to the directory - * - * \remark Produces a NazaraError if not initialized - */ - - void PluginManager::RemoveDirectory(const std::filesystem::path& directoryPath) - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - if (!Initialize()) - { - NazaraError("Failed to initialize PluginManager"); - return; - } - - s_directories.erase(std::filesystem::canonical(directoryPath)); - } - - /*! - * \brief Unmounts the plugin with a path - * - * \param plugin Path to the plugin - * - * \remark Produces a NazaraError if not initialized - * \remark Produces a NazaraError if plugin is not loaded - */ - - void PluginManager::Unmount(Plugin plugin) - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - std::filesystem::path pluginName = s_pluginFiles[UnderlyingCast(plugin)]; - -#ifdef NAZARA_DEBUG - std::filesystem::path debugPath = pluginName; - debugPath += "-d"; - - Unmount(debugPath); -#endif - - Unmount(pluginName); - } - - /*! - * \brief Unmounts the plugin with a path - * - * \param pluginPath Path to the plugin - * - * \remark Produces a NazaraError if not initialized - * \remark Produces a NazaraError if plugin is not loaded - */ - - void PluginManager::Unmount(const std::filesystem::path& pluginPath) - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - if (!Initialize()) - { - NazaraError("Failed to initialize PluginManager"); - return; - } - - std::filesystem::path path = pluginPath; - if (path.extension() != NAZARA_DYNLIB_EXTENSION) - path += NAZARA_DYNLIB_EXTENSION; - - if (!std::filesystem::exists(path)) - return; - - std::filesystem::path canonicalPath = std::filesystem::canonical(path); - auto it = s_plugins.find(canonicalPath); - if (it == s_plugins.end()) - { - NazaraError("Plugin not loaded"); - return; - } - - PluginUnload func = reinterpret_cast(it->second->GetSymbol("PluginUnload")); - if (func) - func(); - - s_plugins.erase(it); - } - - /*! - * \brief Uninitializes the plugin manager - */ - - void PluginManager::Uninitialize() - { - NAZARA_USE_ANONYMOUS_NAMESPACE - - if (!s_initialized) - return; - - s_initialized = false; - - s_directories.clear(); - - for (auto& pair : s_plugins) - { - PluginUnload func = reinterpret_cast(pair.second->GetSymbol("PluginUnload")); - if (func) - func(); - } - - s_plugins.clear(); - } - - std::set PluginManager::s_directories; - std::unordered_map, PluginManager::PathHash> PluginManager::s_plugins; - bool PluginManager::s_initialized = false; -} diff --git a/src/Nazara/Utility/Plugin/AssimpPlugin.cpp b/src/Nazara/Utility/Plugin/AssimpPlugin.cpp new file mode 100644 index 000000000..0d21a5df2 --- /dev/null +++ b/src/Nazara/Utility/Plugin/AssimpPlugin.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} diff --git a/src/Nazara/Utility/Plugin/FFmpegPlugin.cpp b/src/Nazara/Utility/Plugin/FFmpegPlugin.cpp new file mode 100644 index 000000000..34ed50738 --- /dev/null +++ b/src/Nazara/Utility/Plugin/FFmpegPlugin.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +}