载入中...
搜索中...
未找到
Plugins.cpp
浏览该文件的文档.
1#include "plugins/Plugins.h"
2
3#include "common/Exception.h"
4
5#include <simplesquirrel/simplesquirrel.hpp>
6
7#if defined(_WIN32)
8# define WIN32_LEAN_AND_MEAN
9# include <windows.h>
10#else
11# include <dlfcn.h>
12#endif
13
14#include <string_view>
15
16namespace eve::plugins {
17
18namespace {
19
20void rollbackPluginRegistration(std::string_view reason) {
21 auto rollback = ModuleManager::finishPluginRegistration(false);
22 rollback.ignore(reason);
23}
24
25} // namespace
26
27using PluginInitFn = int (*)();
28
30
31Plugins::Plugins() = default;
32
34 // Module factories and Squirrel closures point into plugin code. Keep every
35 // successfully loaded library resident until process teardown.
36 loaded_.clear();
37}
38
39bool Plugins::load(const std::string& path) {
40 if (path.empty())
41 throw Exception("plugins.load: empty path");
42 if (loaded_.count(path))
43 return true;
44 auto registration = ModuleManager::beginPluginRegistration();
45 if (!registration.ok()) throw Exception("plugins.load: nested plugin loading is not supported");
46
47#if defined(_WIN32)
48 HMODULE mod = LoadLibraryA(path.c_str());
49 if (!mod) {
50 const DWORD error = GetLastError();
51 rollbackPluginRegistration("plugin library load failed");
52 throw Exception("plugins.load: LoadLibrary failed for '%s' (err=%lu)", path.c_str(),
53 error);
54 }
55 auto init = reinterpret_cast<PluginInitFn>(GetProcAddress(mod, "eve_plugin_init"));
56 if (!init) {
57 rollbackPluginRegistration("plugin entry point is missing");
58 FreeLibrary(mod);
59 throw Exception("plugins.load: missing eve_plugin_init in '%s'", path.c_str());
60 }
61 int rc = -1;
62 try {
63 rc = init();
64 } catch (...) {
65 rollbackPluginRegistration("plugin initializer threw");
66 FreeLibrary(mod);
67 throw Exception("plugins.load: eve_plugin_init threw for '%s'", path.c_str());
68 }
69 if (rc != 0) {
70 rollbackPluginRegistration("plugin initializer returned failure");
71 FreeLibrary(mod);
72 throw Exception("plugins.load: eve_plugin_init returned %d for '%s'", rc, path.c_str());
73 }
74#else
75 void* mod = dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
76 if (!mod) {
77 rollbackPluginRegistration("plugin library load failed");
78 throw Exception("plugins.load: dlopen failed for '%s': %s", path.c_str(), dlerror());
79 }
80 dlerror();
81 auto init = reinterpret_cast<PluginInitFn>(dlsym(mod, "eve_plugin_init"));
82 const char* err = dlerror();
83 if (err != nullptr || !init) {
84 const std::string error = err ? err : "";
85 rollbackPluginRegistration("plugin entry point is missing");
86 dlclose(mod);
87 throw Exception("plugins.load: missing eve_plugin_init in '%s'%s%s", path.c_str(),
88 error.empty() ? "" : ": ", error.c_str());
89 }
90 int rc = -1;
91 try {
92 rc = init();
93 } catch (...) {
94 rollbackPluginRegistration("plugin initializer threw");
95 dlclose(mod);
96 throw Exception("plugins.load: eve_plugin_init threw for '%s'", path.c_str());
97 }
98 if (rc != 0) {
99 rollbackPluginRegistration("plugin initializer returned failure");
100 dlclose(mod);
101 throw Exception("plugins.load: eve_plugin_init returned %d for '%s'", rc, path.c_str());
102 }
103#endif
104
105 auto registrationResult = ModuleManager::finishPluginRegistration(true);
106 if (!registrationResult.ok()) {
107 const std::string registrationError = registrationResult.status().describe();
108#if defined(_WIN32)
109 FreeLibrary(mod);
110#else
111 dlclose(mod);
112#endif
113 throw Exception("plugins.load: %s in '%s'", registrationError.c_str(), path.c_str());
114 }
115 loaded_[path] = Handle{mod, path};
116
118 throw Exception("plugins.load: expose_pending failed after loading '%s'; plugin retained",
119 path.c_str());
120 return true;
121}
122
123bool Plugins::unload(const std::string& path) {
124 (void) path;
125 return false;
126}
127
128bool Plugins::isLoaded(const std::string& path) const {
129 return loaded_.count(path) > 0;
130}
131
132void Plugins::expose(ssq::Table& table) {
133 auto cls = table.addClass(name, Plugins::create, false);
134 expose(cls);
135}
136
137void Plugins::expose(ssq::Class& cls) {
138 cls.addFunc("getName", &Plugins::getName);
139 cls.addFunc("load", &Plugins::load);
140 cls.addFunc("unload", &Plugins::unload);
141 cls.addFunc("isLoaded", &Plugins::isLoaded);
142}
143
144} // namespace eve::plugins
HSQOBJECT cls
Definition ECS.cpp:21
std::string name
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string error
Definition Package.cpp:60
std::string path
Definition PlayHost.cpp:110
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
static eve::Result< void > beginPluginRegistration()
Begins an atomic native-plugin module registration transaction.
Definition Module.cpp:228
static int expose_pending()
Expose pending.
Definition Module.cpp:303
static eve::Result< void > finishPluginRegistration(bool commit)
Commits or rolls back the active plugin registration transaction.
Definition Module.cpp:239
virtual std::string getName() const =0
Returns the name.
加载导出 eve_plugin_init 的原生动态库(dll / so / dylib)。
Definition Plugins.h:13
bool isLoaded(const std::string &path) const
插件是否已加载。
Definition Plugins.cpp:128
bool load(const std::string &path)
加载插件;路径可为绝对路径或游戏相对路径。
Definition Plugins.cpp:39
~Plugins() override
Definition Plugins.cpp:33
bool unload(const std::string &path)
插件为进程期驻留;该兼容方法始终返回 false。
Definition Plugins.cpp:123
int(*)() PluginInitFn
Definition Plugins.cpp:27