7#include <Logger/Logger.h>
10#include "../IBaseApi.h"
12#include "../Ark/ApiUtils.h"
27 std::ifstream file{ config_path };
41 namespace fs = std::filesystem;
43 const std::string dir_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins";
45 for (
const auto& dir_name : fs::directory_iterator(dir_path))
47 const auto& path = dir_name.path();
48 if (!is_directory(path))
53 const auto filename = path.filename().stem().generic_string();
55 const std::string dir_file_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins/" +
57 const std::string full_dll_path = dir_file_path +
"/" + filename +
".dll";
58 const std::string new_full_dll_path = dir_file_path +
"/" + filename +
".dll.ArkApi";
63 if (fs::exists(new_full_dll_path))
65 copy_file(new_full_dll_path, full_dll_path, fs::copy_options::overwrite_existing);
66 fs::remove(new_full_dll_path);
69 std::stringstream stream;
71 std::shared_ptr<Plugin>& plugin = LoadPlugin(filename);
73 stream <<
"Loaded plugin " << (plugin->full_name.empty() ? plugin->name : plugin->full_name) <<
" V" <<
74 plugin->version <<
" (" << plugin->description <<
")";
76 Log::GetLog()->info(stream.str());
78 catch (
const std::exception& error)
80 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
96 Log::GetLog()->info(
"Loaded all plugins\n");
101 namespace fs = std::filesystem;
103 const std::string dir_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins/" + plugin_name;
104 const std::string full_dll_path = dir_path +
"/" + plugin_name +
".dll";
106 if (!fs::exists(full_dll_path))
108 throw std::runtime_error(
"Plugin " + plugin_name +
" does not exist");
113 throw std::runtime_error(
"Plugin " + plugin_name +
" was already loaded");
119 const auto required_version =
static_cast<
float>(plugin_info[
"MinApiVersion"]);
120 if (required_version != .0f && game_api->GetVersion() < required_version)
122 throw std::runtime_error(
"Plugin " + plugin_name +
" requires newer API version!");
125 HINSTANCE h_module = LoadLibraryA(full_dll_path.c_str());
126 if (h_module ==
nullptr)
128 throw std::runtime_error(
129 "Failed to load plugin - " + plugin_name +
"\nError code: " +
std::to_string(GetLastError()));
134 using pfnPluginInit =
void(
__fastcall*)();
135 const auto pfn_init =
reinterpret_cast<pfnPluginInit>(GetProcAddress(h_module,
"Plugin_Init"));
136 if (pfn_init !=
nullptr)
142 plugin_info[
"Description"], plugin_info[
"Version"],
143 plugin_info[
"MinApiVersion"],
144 plugin_info[
"Dependencies"]));
149 namespace fs = std::filesystem;
152 if (iter == loaded_plugins_.end())
154 throw std::runtime_error(
"Plugin " + plugin_name +
" is not loaded");
157 const std::string dir_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins/" + plugin_name;
158 const std::string full_dll_path = dir_path +
"/" + plugin_name +
".dll";
160 if (!fs::exists(full_dll_path.c_str()))
162 throw std::runtime_error(
"Plugin " + plugin_name +
" does not exist");
167 using pfnPluginUnload =
void(
__fastcall*)();
168 const auto pfn_unload =
reinterpret_cast<pfnPluginUnload>(GetProcAddress((*iter)->h_module,
"Plugin_Unload"));
169 if (pfn_unload !=
nullptr)
175 dynamic_cast<AsaApi::ApiUtils&>(*API::game_api->GetApiUtils()).RemoveMessagingManagerInternal(FString(full_dll_path).Replace(L"/", L"\\"));
177 const BOOL result = FreeLibrary((*iter)->h_module);
180 throw std::runtime_error(
181 "Failed to unload plugin - " + plugin_name +
"\nError code: " +
std::to_string(GetLastError()));
184 loaded_plugins_.erase(remove(loaded_plugins_.begin(), loaded_plugins_.end(), *iter), loaded_plugins_.end());
189 nlohmann::json plugin_info_result({});
192 const std::string dir_path = Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins/" + plugin_name;
193 const std::string config_path = dir_path +
"/PluginInfo.json";
195 std::ifstream file{ config_path };
204 plugin_info_result[
"FullName"] = plugin_info.value(
"FullName",
"");
205 plugin_info_result[
"Description"] = plugin_info.value(
"Description",
"No description");
206 plugin_info_result[
"Version"] = plugin_info.value(
"Version", 1.00f);
207 plugin_info_result[
"MinApiVersion"] = plugin_info.value(
"MinApiVersion", .0f);
208 plugin_info_result[
"Dependencies"] = plugin_info.value(
"Dependencies", std::vector<std::string>{});
210 catch (
const std::exception& error)
212 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
215 return plugin_info_result;
220 for (
const auto& plugin : loaded_plugins_)
222 if (plugin->dependencies.empty())
227 for (
const std::string& dependency : plugin->dependencies)
229 if (!IsPluginLoaded(dependency))
231 Log::GetLog()->error(
"Plugin {} is missing! {} might not work correctly", dependency,
241 [plugin_name](
const std::shared_ptr<
Plugin>& plugin) ->
bool
243 return plugin->name == plugin_name;
256 auto& pluginManager =
Get();
258 const time_t now = time(
nullptr);
272 namespace fs = std::filesystem;
277 for (
const auto& dir_name : fs::directory_iterator(
278 Tools::GetCurrentDir() +
"/" + game_api->GetApiName() +
"/Plugins"))
280 const auto& path = dir_name.path();
281 if (!is_directory(path))
286 const auto filename = path.filename().stem().generic_string();
288 const std::string plugin_folder = path.generic_string() +
"/";
290 const std::string plugin_file_path = plugin_folder + filename +
".dll";
291 const std::string new_plugin_file_path = plugin_folder + filename +
".dll.ArkApi";
293 if (fs::exists(new_plugin_file_path) && FindPlugin(filename) != loaded_plugins_.end())
299 Log::GetLog()->info(
"Saving world before reloading plugins");
300 AsaApi::GetApiUtils().GetShooterGameMode()->SaveWorld(
true,
true);
301 Log::GetLog()->info(
"World saved.");
308 UnloadPlugin(filename);
310 copy_file(new_plugin_file_path, plugin_file_path, fs::copy_options::overwrite_existing);
311 fs::remove(new_plugin_file_path);
317 LoadPlugin(filename);
319 Log::GetLog()->info(
"Reloaded plugin - {}", filename);
321 catch (
const std::exception& error)
323 Log::GetLog()->warn(
"({}) {}",
__FUNCTION__, error.what());
std::vector< std::shared_ptr< Plugin > > loaded_plugins_
void CheckPluginsDependencies()
std::vector< std::shared_ptr< Plugin > >::const_iterator FindPlugin(const std::string &plugin_name)
Find plugin by it's 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 ARK_API Timer & Get()
ARK_API void UnloadTimersFromModule(const FString &moduleName)
namespace for Niels Lohmann