Botcraft 1.21.4
Loading...
Searching...
No Matches
PluginLoader.cpp
Go to the documentation of this file.
3
4#include <filesystem>
5#include <functional>
6#include <unordered_map>
7#include <string_view>
8
9#ifdef _WIN32
10#define NOMINMAX
11#define WIN32_LEAN_AND_MEAN
12#include <Windows.h>
13#else
14#include <dlfcn.h>
15#endif
16
17namespace ProtocolCraft
18{
19 namespace Internal
20 {
21 /// @brief Folder in which the protocolCraft plugins will be searched for
22 constexpr std::string_view plugins_folder = "protocolcraft_plugins";
23
24 // These are the expected signatures to load from the plugins.
25 // We assume they are exposed with these names and signatures.
26 PluginObject* (*GetPluginObject)(const char* identifier) = 0;
27 void (*DestroyPluginObject)(PluginObject* object) = 0;
28
29 template<typename F>
30#ifdef _WIN32
31 F GetKnownProcAddressImpl(HMODULE hmod, const char* module_name, const char* name, F)
32#else
33 F GetKnownProcAddressImpl(void* hmod, const char* module_name, const char* name, F)
34#endif
35 {
36#ifdef _WIN32
37 auto proc = GetProcAddress(hmod, name);
38#else
39 auto proc = dlsym(hmod, name);
40#endif
41 if (proc == NULL)
42 {
43 throw std::runtime_error(std::string("Couldn't load function ") + name + " from " + module_name);
44 }
45 return reinterpret_cast<F>(proc);
46 }
47#define GetKnownProcAddress(plugins_map, plugin_name, func) GetKnownProcAddressImpl(plugins_map[plugin_name], plugin_name.c_str(), #func, func);
48
50 {
51 public:
53 {
54 if (std::filesystem::exists(plugins_folder))
55 {
56 for (const auto& f : std::filesystem::directory_iterator(plugins_folder))
57 {
58 const std::string path_str = f.path().string();
59#ifdef _WIN32
60 plugins[path_str] = LoadLibraryA(path_str.c_str());
61#else
62 plugins[path_str] = dlopen(path_str.c_str(), RTLD_NOW);
63#endif
64 if (plugins[path_str] == NULL)
65 {
66 throw std::runtime_error("Couldn't load plugin at " + path_str);
67 }
68
71 }
72 }
73 }
74
76 {
80
81 for (auto& [k, v] : plugins)
82 {
83#ifdef _WIN32
84 FreeLibrary(v);
85#else
86 dlclose(v);
87#endif
88 }
89 }
90
91 std::shared_ptr<PluginObject> CreatePluginObject(const char* identifier)
92 {
93 const auto it = cached_identifier_to_plugin.find(identifier);
94 // First time we encounter this identifier
95 if (it == cached_identifier_to_plugin.end())
96 {
97 for (const auto& [k, v] : GetPluginObject_funcs)
98 {
99 PluginObject* ptr = v(identifier);
100 if (ptr != nullptr)
101 {
102 cached_identifier_to_plugin[identifier] = k;
103 return std::shared_ptr<PluginObject>(ptr, DestroyPluginObject_funcs[k]);
104 }
105 }
106 // No plugin for this identifier
107 cached_identifier_to_plugin[identifier] = "";
108 }
109 // We know this identifier exists in a known plugin
110 else if (!it->second.empty())
111 {
112 PluginObject* raw_ptr = GetPluginObject_funcs[it->second](identifier);
113 if (raw_ptr != nullptr)
114 {
115 return std::shared_ptr<PluginObject>(raw_ptr, DestroyPluginObject_funcs[it->second]);
116 }
117 }
118 // If we reach this, we know there is no plugin with this identifier
119 return nullptr;
120 }
121
122 private:
123#if _WIN32
124 std::unordered_map<std::string, HMODULE> plugins;
125#else
126 std::unordered_map<std::string, void*> plugins;
127#endif
128 std::unordered_map<std::string, std::function<PluginObject* (const char*)>> GetPluginObject_funcs;
129 std::unordered_map<std::string, std::function<void(PluginObject*)>> DestroyPluginObject_funcs;
130
131 std::unordered_map<std::string, std::string> cached_identifier_to_plugin;
132 };
133 }
134
135 std::shared_ptr<PluginObject> CreateObjectFromPlugin(const char* identifier)
136 {
137 static Internal::PluginLoader loader;
138 return loader.CreatePluginObject(identifier);
139 }
140}
#define GetKnownProcAddress(plugins_map, plugin_name, func)
std::shared_ptr< PluginObject > CreatePluginObject(const char *identifier)
std::unordered_map< std::string, std::string > cached_identifier_to_plugin
std::unordered_map< std::string, std::function< void(PluginObject *)> > DestroyPluginObject_funcs
std::unordered_map< std::string, void * > plugins
std::unordered_map< std::string, std::function< PluginObject *(const char *)> > GetPluginObject_funcs
void(* DestroyPluginObject)(PluginObject *object)=0
F GetKnownProcAddressImpl(void *hmod, const char *module_name, const char *name, F)
PluginObject *(* GetPluginObject)(const char *identifier)=0
constexpr std::string_view plugins_folder
Folder in which the protocolCraft plugins will be searched for.
std::shared_ptr< PluginObject > CreateObjectFromPlugin(const char *identifier)
Create an abstract PluginObject using a runtime loaded plugin (dll/so)