7#include <Logger/Logger.h>
10#include "../Helpers.h"
11#include "../IBaseApi.h"
23 namespace fs = std::filesystem;
29 for (
const auto& dir_name : fs::directory_iterator(dir_path))
31 const auto& path = dir_name.path();
32 const auto filename = path.filename().stem().generic_string();
36 const auto plugin_pdb_config = ReadPluginPDBConfig(filename);
37 MergePdbConfig(result, plugin_pdb_config);
39 catch (
const std::exception& error)
41 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
50 namespace fs = std::filesystem;
52 auto plugin_pdb_config =
nlohmann::json({});
55 const std::string config_path = dir_path +
"/PdbConfig.json";
57 if (!fs::exists(config_path))
59 return plugin_pdb_config;
62 std::ifstream file{config_path};
65 file >> plugin_pdb_config;
69 return plugin_pdb_config;
77 std::ifstream file{config_path};
91 namespace fs = std::filesystem;
95 for (
const auto& dir_name : fs::directory_iterator(dir_path))
97 const auto& path = dir_name.path();
98 if (!is_directory(path))
103 const auto filename = path.filename().stem().generic_string();
105 const std::string dir_file_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins/" +
107 const std::string full_dll_path = dir_file_path +
"/" + filename +
".dll";
108 const std::string new_full_dll_path = dir_file_path +
"/" + filename +
".dll.ArkApi";
113 if (fs::exists(new_full_dll_path))
115 copy_file(new_full_dll_path, full_dll_path, fs::copy_options::overwrite_existing);
116 fs::remove(new_full_dll_path);
119 std::stringstream stream;
121 std::shared_ptr<Plugin>& plugin = LoadPlugin(filename);
123 stream <<
"Loaded plugin " << (plugin->full_name.empty() ? plugin->name : plugin->full_name) <<
" V" <<
124 plugin->version <<
" (" << plugin->description <<
")";
126 Log::GetLog()->info(stream.str());
128 catch (
const std::exception& error)
130 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
151 namespace fs = std::filesystem;
154 const std::string full_dll_path = dir_path +
"/" + plugin_name +
".dll";
156 if (!fs::exists(full_dll_path))
158 throw std::runtime_error(
"Plugin " + plugin_name +
" does not exist");
163 throw std::runtime_error(
"Plugin " + plugin_name +
" was already loaded");
169 const auto required_version =
static_cast<
float>(plugin_info[
"MinApiVersion"]);
172 throw std::runtime_error(
"Plugin " + plugin_name +
" requires newer API version!");
175 HINSTANCE h_module = LoadLibraryA(full_dll_path.c_str());
176 if (h_module ==
nullptr)
178 throw std::runtime_error(
179 "Failed to load plugin - " + plugin_name +
"\nError code: " +
std::to_string(GetLastError()));
184 using pfnPluginInit =
void(
__fastcall*)();
185 const auto pfn_init =
reinterpret_cast<pfnPluginInit>(GetProcAddress(h_module,
"Plugin_Init"));
186 if (pfn_init !=
nullptr)
191 return loaded_plugins_.emplace_back(std::make_shared<Plugin>(h_module, plugin_name, plugin_info[
"FullName"],
192 plugin_info[
"Description"], plugin_info[
"Version"],
193 plugin_info[
"MinApiVersion"],
194 plugin_info[
"Dependencies"]));
199 namespace fs = std::filesystem;
204 throw std::runtime_error(
"Plugin " + plugin_name +
" is not loaded");
208 const std::string full_dll_path = dir_path +
"/" + plugin_name +
".dll";
210 if (!fs::exists(full_dll_path.c_str()))
212 throw std::runtime_error(
"Plugin " + plugin_name +
" does not exist");
217 using pfnPluginUnload =
void(
__fastcall*)();
218 const auto pfn_unload =
reinterpret_cast<pfnPluginUnload>(GetProcAddress((*iter)->
h_module,
"Plugin_Unload"));
219 if (pfn_unload !=
nullptr)
224 const BOOL result = FreeLibrary((*iter)->
h_module);
227 throw std::runtime_error(
228 "Failed to unload plugin - " + plugin_name +
"\nError code: " +
std::to_string(GetLastError()));
236 nlohmann::json plugin_info_result({});
240 const std::string config_path = dir_path +
"/PluginInfo.json";
242 std::ifstream file{config_path};
251 plugin_info_result[
"FullName"] = plugin_info.value(
"FullName",
"");
252 plugin_info_result[
"Description"] = plugin_info.value(
"Description",
"No description");
253 plugin_info_result[
"Version"] = plugin_info.value(
"Version", 1.00f);
254 plugin_info_result[
"MinApiVersion"] = plugin_info.value(
"MinApiVersion", .0f);
255 plugin_info_result[
"Dependencies"] = plugin_info.value(
"Dependencies",
std::vector<
std::string>{});
257 catch (
const std::exception& error)
262 return plugin_info_result;
288 [plugin_name](
const std::shared_ptr<
Plugin>& plugin) ->
bool
290 return plugin->
name == plugin_name;
303 auto& pluginManager =
Get();
305 const time_t now = time(
nullptr);
319 namespace fs = std::filesystem;
324 for (
const auto& dir_name : fs::directory_iterator(
325 Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins"))
327 const auto& path = dir_name.path();
328 if (!is_directory(path))
333 const auto filename = path.filename().stem().generic_string();
335 const std::string plugin_folder = path.generic_string() +
"/";
337 const std::string plugin_file_path = plugin_folder + filename +
".dll";
338 const std::string new_plugin_file_path = plugin_folder + filename +
".dll.ArkApi";
340 if (fs::exists(new_plugin_file_path) && FindPlugin(filename) != loaded_plugins_.end())
346 Log::GetLog()->info(
"Saving world before reloading plugins ...");
347 ArkApi::GetApiUtils().GetShooterGameMode()->SaveWorld(
true);
348 Log::GetLog()->info(
"World saved.");
355 UnloadPlugin(filename);
357 copy_file(new_plugin_file_path, plugin_file_path, fs::copy_options::overwrite_existing);
358 fs::remove(new_plugin_file_path);
364 LoadPlugin(filename);
366 Log::GetLog()->info(
"Reloaded plugin - {}", filename);
368 catch (
const std::exception& error)
370 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
virtual float GetVersion()=0
virtual std::string GetApiName()=0
std::vector< std::shared_ptr< Plugin > > loaded_plugins_
static nlohmann::json GetAllPDBConfigs()
Get all plugin pdb configs.
void CheckPluginsDependencies()
std::vector< std::shared_ptr< Plugin > >::const_iterator FindPlugin(const std::string &plugin_name)
Find plugin by it's name.
static nlohmann::json ReadPluginPDBConfig(const std::string &plugin_name)
bool save_world_before_reload_
void DetectPluginChanges()
time_t next_reload_check_
void LoadAllPlugins()
Find and load all plugins.
static PluginManager & Get()
static nlohmann::json ReadPluginInfo(const std::string &plugin_name)
bool enable_plugin_reload_
bool IsPluginLoaded(const std::string &plugin_name)
Returns true if plugin was loaded, false otherwise.
std::shared_ptr< Plugin > & LoadPlugin(const std::string &plugin_name) noexcept(false)
Load plugin by it's name.
static void DetectPluginChangesTimerCallback()
Checks for auto plugin reloads.
int reload_sleep_seconds_
void UnloadPlugin(const std::string &plugin_name) noexcept(false)
Unload plugin by it's name. Plugin must free all used resources.
static nlohmann::json ReadSettingsConfig()
static std::shared_ptr< spdlog::logger > & GetLog()
void warn(const char *fmt, const Arg1 &, const Args &... args)
void error(const char *fmt, const Arg1 &, const Args &... args)
std::unique_ptr< IBaseApi > game_api
namespace for Niels Lohmann
std::vector< std::string > dependencies