26 for (std::string_view
event :
leaks.Subscriptions)
28 Log::Warn(
"{} left a {} subscription behind; the host dropped it.", name,
event);
32 Log::Warn(
"{} left the service '{}' published; the host withdrew it.", name,
service);
36 Log::Warn(
"{} left workshop addon {} required; the host released it.", name,
addonId);
40static std::filesystem::path
LibraryPath(std::string_view name)
60 LoadGroup(
installed, [](std::string_view) {
return true; });
61 Log::Info(
"{} of {} installed plugin(s) loaded.", _loaded.size(),
68 while (!_loaded.empty())
70 UnloadOne(_loaded.back().Manifest.Name, UnloadTime::Shutdown);
76 _pending.push_back({.Kind =
kind, .Name = std::string(name)});
88 const std::vector<PendingAction>
actions = std::move(_pending);
122 for (
const std::string& name :
list.ToLoad)
124 if (!
wanted(name) || FindLoaded(name) !=
nullptr)
132 Refuse(name,
loaded.error().Detail);
137void PluginLoader::Refuse(std::string_view name, std::string
reason)
140 _refused.insert_or_assign(std::string(name), std::move(
reason));
145 const std::string& name =
manifest.Name;
150 return std::unexpected(
code.error());
156 return std::unexpected(
entry.error());
159 using EntryPoint =
const PluginDescriptor* (*)();
169 return std::unexpected(
Error::Failed(
"the host already holds a view under that name"));
184 view->ReplayMissedEvents();
187 _refused.erase(name);
193void PluginLoader::UnloadOne(std::string_view name, UnloadTime
when)
196 const std::string
plugin(name);
199 std::ranges::find_if(_loaded, [&](
const LoadedPlugin&
loaded) {
return loaded.Manifest.Name ==
plugin; });
200 if (
found == _loaded.end())
205 if (
when == UnloadTime::MidMap)
209 found->Descriptor->Unload();
214 _loaded.erase(
found);
218LoadedPlugin* PluginLoader::FindLoaded(std::string_view name)
221 std::ranges::find_if(_loaded, [name](
const LoadedPlugin&
plugin) {
return plugin.Manifest.Name == name; });
222 return found != _loaded.end() ? &*
found :
nullptr;
235std::vector<PluginManifest> PluginLoader::LoadedManifests()
const
246void PluginLoader::RunLoad(std::string_view name)
248 if (FindLoaded(name) !=
nullptr)
250 Log::Warn(
"'{}' is already loaded.", name);
258 Refuse(name,
broken->Reason.Detail);
265 Log::Warn(
"'{}' is not installed.", name);
273 Refuse(name, std::format(
"it requires '{}', which is not loaded.",
dependency));
280 Refuse(name,
loaded.error().Detail);
284void PluginLoader::RunUnload(std::string_view name)
298 UnloadOne(name, UnloadTime::MidMap);
301void PluginLoader::RunReload(std::string_view name)
310 group.emplace_back(name);
312 std::vector<std::string>
going;
323 UnloadOne(
plugin, UnloadTime::MidMap);
Enumerator names without a hand-written switch.
LoadedPlugin * RequireLoaded(std::string_view name)
PluginLoader(PluginRegistry ®istry, ServerAssets &assets)
void Defer(ActionKind kind, std::string_view name)
The loaded plugins and the engine events raised on them, one per process.
PluginContext * FindPlugin(std::string_view name)
LeakReport RemovePlugin(std::string_view name)
PluginContext * AddPlugin(std::string_view name, std::string_view logTag={}, std::string_view version={})
void Mount(std::string_view plugin)
void Unmount(std::string_view plugin)
static Result< SharedLibrary > Open(const std::filesystem::path &path)
static std::string Join(const std::vector< std::string > &parts, std::string_view delimiter)
static std::string ToLower(std::string_view str)
InstalledScan Discover(const std::filesystem::path &plugins)
void Error(std::format_string< Args... > fmt, Args &&... args)
void Info(std::format_string< Args... > fmt, Args &&... args)
void Warn(std::format_string< Args... > fmt, Args &&... args)
LoadList Resolve(std::span< const PluginManifest > installed)
Decide which of installed the host loads.
std::vector< std::string > RequiredDependents(std::string_view plugin, std::span< const PluginManifest > loaded)
std::filesystem::path ResolvePath(std::string_view relativePath)
a relative path against the base directory. If the path is already absolute, returns it as-is.
static constexpr std::string_view LibrarySuffix
static std::string ReadFile(const std::filesystem::path &path)
static std::filesystem::path LibraryPath(std::string_view name)
Status ValidateDescriptor(const PluginDescriptor *descriptor, std::string_view hostVersion)
std::string PluginFile(std::string_view plugin, std::string_view relative)
"addons/voltmod/plugins/<plugin>/<relative>".
std::expected< void, Error > Status
constexpr const char * PluginEntryName
static void WarnLeaks(std::string_view name, const LeakReport &leaks)
static InstalledScan Installed()
static Error Failed(std::string detail)