2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2025-02-19 01:58:56 +03:00
metamod-r/metamod/src/mlist.cpp

683 lines
17 KiB
C++
Raw Normal View History

2016-07-26 07:22:47 +07:00
#include "precompiled.h"
2016-07-04 12:07:29 +06:00
// Constructor
2017-06-26 18:10:34 +03:00
MPluginList::MPluginList(const char* ifile) : m_last_index(0), m_plugins()
2016-07-04 12:07:29 +06:00
{
// store filename of ini file
Q_strncpy(m_inifile, ifile, sizeof m_inifile - 1);
m_inifile[sizeof m_inifile - 1] = '\0';
}
2017-06-26 18:10:34 +03:00
plugins_t* MPluginList::getPlugins()
{
2017-06-26 18:10:34 +03:00
return &m_plugins;
2016-07-04 12:07:29 +06:00
}
// Find a plugin based on the plugin handle.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find(module_handle_t handle)
2016-07-26 07:22:47 +07:00
{
if (!handle)
return nullptr;
2016-07-26 07:22:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2017-06-26 18:10:34 +03:00
if (handle == p->m_sys_module.gethandle())
return p;
2016-07-04 12:07:29 +06:00
}
2016-07-26 07:22:47 +07:00
return nullptr;
2016-07-04 12:07:29 +06:00
}
// Find a plugin based on the plugin index #.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find(int pindex)
2016-07-26 07:22:47 +07:00
{
if (pindex <= 0)
return nullptr;
2016-07-26 07:22:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_index == pindex && p->m_status >= PL_VALID)
return p;
}
2017-05-09 19:31:09 +03:00
2017-06-26 18:10:34 +03:00
return nullptr;
2016-07-04 12:07:29 +06:00
}
// Find a plugin with the given plid.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find(plid_t id)
2016-07-26 07:22:47 +07:00
{
if (!id)
return nullptr;
2016-07-26 07:22:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2017-06-26 18:10:34 +03:00
if (p->m_info == id)
return p;
2016-07-04 12:07:29 +06:00
}
2016-07-26 07:22:47 +07:00
return nullptr;
2016-07-04 12:07:29 +06:00
}
// Find a plugin with the given pathname.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find(const char* findpath)
2016-07-26 07:22:47 +07:00
{
if (!findpath)
return nullptr;
2016-07-26 07:22:47 +07:00
2017-05-08 23:44:19 +03:00
META_DEBUG(8, "Looking for loaded plugin with path: %s", findpath);
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
META_DEBUG(9, "Looking at: plugin %s loadedpath: %s", p->m_file, p->m_pathname);
2017-06-26 18:10:34 +03:00
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (!Q_strcmp(p->m_pathname, findpath)) {
META_DEBUG(8, "Found loaded plugin %s", p->m_file);
return p;
2016-07-04 12:07:29 +06:00
}
}
2016-07-26 07:22:47 +07:00
2017-01-09 02:44:49 +03:00
META_DEBUG(8, "No loaded plugin found with path: %s", findpath);
return nullptr;
2016-07-04 12:07:29 +06:00
}
// Find a plugin that uses the given memory location.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find_memloc(void* memptr)
2016-07-26 07:22:47 +07:00
{
2017-11-15 22:13:36 +07:00
module_handle_t ptr = CSysModule::find(memptr);
if (ptr != CSysModule::INVALID_HANDLE) {
return find(ptr);
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
2017-01-07 01:24:40 +03:00
return nullptr;
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
// Find a plugin with non-ambiguous prefix string matching desc, file,
2016-07-04 12:07:29 +06:00
// name, or logtag.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find_match(const char* prefix, bool& unique)
2016-07-26 07:22:47 +07:00
{
if (!prefix) {
return nullptr;
2016-07-26 23:31:47 +07:00
}
MPlugin* pfound = nullptr;
size_t len = Q_strlen(prefix);
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (p->info() && !Q_strnicmp(p->info()->name, prefix, len)
|| !Q_strnicmp(p->m_desc, prefix, len)
|| !Q_strnicmp(p->m_file, prefix, len)
|| p->info() && !Q_strnicmp(p->info()->logtag, prefix, len)) {
if (pfound) {
unique = false;
break;
}
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
pfound = p;
unique = true;
2016-07-04 12:07:29 +06:00
}
}
2016-07-26 23:31:47 +07:00
return pfound;
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
// Find a plugin with same file, logtag, desc or significant
2016-07-04 12:07:29 +06:00
// prefix of file. Uses the platform_match() method of MPlugin.
2017-05-09 19:31:09 +03:00
MPlugin* MPluginList::find_match(MPlugin* pmatch)
2016-07-26 07:22:47 +07:00
{
if (!pmatch) {
return nullptr;
2016-07-26 23:31:47 +07:00
}
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
auto plug = p;
if (plug->platform_match(pmatch)) {
return plug;
2016-07-04 12:07:29 +06:00
}
}
return nullptr;
2016-07-04 12:07:29 +06:00
}
MPlugin* MPluginList::plugin_addload(plid_t plid, const char* fname, PLUG_LOADTIME now)
{
auto pl_loader = find(plid);
if (!pl_loader) {
2017-01-09 02:44:49 +03:00
META_DEBUG(1, "Couldn't find plugin that gave this loading request!");
return nullptr;
}
MPlugin pl_temp = {};
if (!pl_temp.plugin_parseline(fname, pl_loader->m_index)) {
return nullptr;
}
2017-05-09 18:34:55 +03:00
if (!pl_temp.resolve()) {
META_DEBUG(1, "Couldn't resolve given path into a file: %s", pl_temp.m_file);
return nullptr;
}
auto pl_found = find(pl_temp.m_pathname);
2017-05-09 19:31:09 +03:00
if (pl_found) {
META_DEBUG(1, "Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.m_file, pl_found->m_file, pl_found->m_desc);
2017-01-17 00:30:02 +03:00
return pl_found;
}
auto pl_added = add(&pl_temp);
2017-05-09 19:31:09 +03:00
if (!pl_added) {
META_DEBUG(1, "Couldn't add plugin '%s' to list; see log", pl_temp.m_desc);
return nullptr;
}
pl_added->m_action = PA_LOAD;
bool delayed;
if (!pl_added->load(now, delayed)) {
2017-05-09 19:31:09 +03:00
if (pl_added->m_status == PL_OPENED) {
META_DEBUG(1, "Opened plugin '%s', but failed to attach; see log", pl_added->m_desc);
}
2017-05-09 19:31:09 +03:00
else {
META_DEBUG(1, "Couldn't load plugin '%s'; see log", pl_added->m_desc);
}
return nullptr;
}
META_DEBUG(1, "Loaded plugin '%s' successfully", pl_added->m_desc);
return pl_added;
}
2016-07-04 12:07:29 +06:00
// Add a plugin to the list.
MPlugin* MPluginList::add(MPlugin* padd)
2016-07-26 07:22:47 +07:00
{
2017-06-26 18:10:34 +03:00
auto plug = new MPlugin();
memset(plug, 0, sizeof(MPlugin));
2016-07-04 12:07:29 +06:00
2017-06-26 18:10:34 +03:00
plug->m_index = ++m_last_index;
2016-07-04 12:07:29 +06:00
// copy filename into this free slot
2017-06-26 18:10:34 +03:00
Q_strncpy(plug->m_filename, padd->m_filename, sizeof plug->m_filename - 1);
plug->m_filename[sizeof plug->m_filename - 1] = '\0';
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
// Copy file offset ptr.
// Can't just copy ptr, as it points to offset in padd, which will go
// away; need to point to corresponding offset in iplug.
2017-06-26 18:10:34 +03:00
plug->m_file = plug->m_filename + (padd->m_file - padd->m_filename);
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
// copy description
2017-06-26 18:10:34 +03:00
Q_strncpy(plug->m_desc, padd->m_desc, sizeof plug->m_desc - 1);
plug->m_desc[sizeof plug->m_desc - 1] = '\0';
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
// copy pathname
2017-06-26 18:10:34 +03:00
Q_strncpy(plug->m_pathname, padd->m_pathname, sizeof plug->m_pathname - 1);
plug->m_pathname[sizeof plug->m_pathname - 1] = '\0';
normalize_path(plug->m_pathname);
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
plug->m_source = padd->m_source;
plug->m_status = padd->m_status;
plug->m_source_plugin_index = padd->m_source_plugin_index;
2016-07-04 12:07:29 +06:00
2017-06-26 18:10:34 +03:00
m_plugins.push_back(plug);
return plug;
2016-07-26 07:22:47 +07:00
}
2016-07-04 12:07:29 +06:00
2017-06-26 18:10:34 +03:00
// Read plugins.ini at server startup->
2016-07-30 02:03:01 +03:00
bool MPluginList::ini_startup()
2016-07-26 07:22:47 +07:00
{
2016-07-04 12:07:29 +06:00
char line[MAX_STRBUF_LEN];
int n, ln;
2017-05-09 19:31:09 +03:00
if (!is_file_exists_in_gamedir(m_inifile)) {
META_ERROR("ini: Metamod plugins file empty or missing: %s", m_inifile);
2017-01-07 21:03:16 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
full_gamedir_path(m_inifile, m_inifile);
2017-05-09 00:35:21 +03:00
FILE* fp = fopen(m_inifile, "r");
2017-05-09 19:31:09 +03:00
if (!fp) {
META_ERROR("ini: Unable to open plugins file '%s': %s", m_inifile, strerror(errno));
2017-01-07 21:03:16 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
META_LOG("ini: Begin reading plugins list: %s", m_inifile);
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof line, fp); ln++)
{
2016-07-04 12:07:29 +06:00
// Remove line terminations.
char* cp;
2016-07-26 23:31:47 +07:00
if ((cp = Q_strrchr(line, '\r')))
2016-07-26 07:22:47 +07:00
*cp = '\0';
2016-07-26 23:31:47 +07:00
if ((cp = Q_strrchr(line, '\n')))
2016-07-26 07:22:47 +07:00
*cp = '\0';
2016-07-26 23:31:47 +07:00
trimbuf(line);
// skip empty lines
if (line[0] == '\0') {
continue;
}
// skip comments
if (line[0] == '#' || line[0] == ';' || !Q_strncmp(line, "//", 2)) {
continue;
}
auto plug = new MPlugin();
2016-07-04 12:07:29 +06:00
// Parse directly into next entry in array
2017-06-26 18:10:34 +03:00
if (!plug->ini_parseline(line)) {
delete plug;
2016-07-04 12:07:29 +06:00
continue;
2017-06-26 18:10:34 +03:00
}
2017-05-09 19:31:09 +03:00
2016-07-04 12:07:29 +06:00
// Check for a duplicate - an existing entry with this pathname.
2017-06-26 18:10:34 +03:00
if (find(plug->m_pathname)) {
2016-07-04 12:07:29 +06:00
// Should we check platform specific level here?
2017-06-26 18:10:34 +03:00
META_INFO("ini: Skipping duplicate plugin, line %d of %s: %s", ln, m_inifile, plug->m_pathname);
delete plug;
2016-07-04 12:07:29 +06:00
continue;
}
2016-07-26 23:31:47 +07:00
// Check for a matching platform with different platform specifics level.
2017-06-26 18:10:34 +03:00
auto pmatch = find_match(plug); // TODO: check it
2017-05-09 19:31:09 +03:00
if (pmatch) {
2017-05-09 18:34:55 +03:00
META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin", ln);
int index = pmatch->m_index;
2016-07-26 23:31:47 +07:00
Q_memset(pmatch, 0, sizeof(MPlugin));
2017-05-09 18:34:55 +03:00
pmatch->m_index = index;
2016-07-04 12:07:29 +06:00
}
2017-06-26 18:10:34 +03:00
plug->m_index = ++m_last_index;
plug->m_action = PA_LOAD;
m_plugins.push_back(plug);
META_LOG("ini: Read plugin config for: %s", plug->m_desc);
2016-07-04 12:07:29 +06:00
n++;
}
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", m_inifile, n);
2016-07-04 12:07:29 +06:00
fclose(fp);
2017-05-09 18:34:55 +03:00
2016-07-26 23:31:47 +07:00
if (!n)
2017-05-09 18:34:55 +03:00
META_LOG("ini: Warning; no plugins found to load?");
2016-07-26 23:31:47 +07:00
2016-07-30 02:03:01 +03:00
return true;
2016-07-04 12:07:29 +06:00
}
// Re-read plugins.ini looking for added/deleted/changed plugins.
2016-07-30 02:03:01 +03:00
bool MPluginList::ini_refresh()
2016-07-26 07:22:47 +07:00
{
2016-07-04 12:07:29 +06:00
char line[MAX_STRBUF_LEN];
int n, ln;
2017-05-09 00:35:21 +03:00
FILE* fp = fopen(m_inifile, "r");
2017-05-09 19:31:09 +03:00
if (!fp) {
META_ERROR("ini: Unable to open plugins file '%s': %s", m_inifile, strerror(errno));
2017-01-07 21:03:16 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
META_LOG("ini: Begin re-reading plugins list: %s", m_inifile);
2017-06-26 18:10:34 +03:00
for (n = 0 , ln = 1; !feof(fp) && fgets(line, sizeof line, fp); ln++) {
2016-07-04 12:07:29 +06:00
// Remove line terminations.
2017-05-09 19:31:09 +03:00
char* cp;
2016-07-26 23:31:47 +07:00
if ((cp = Q_strrchr(line, '\r')))
2016-07-26 07:22:47 +07:00
*cp = '\0';
2016-07-26 23:31:47 +07:00
if ((cp = Q_strrchr(line, '\n')))
2016-07-26 07:22:47 +07:00
*cp = '\0';
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
// Parse into a temp plugin
2017-05-09 18:34:55 +03:00
MPlugin pl_temp = {};
2017-05-09 19:31:09 +03:00
if (!pl_temp.ini_parseline(line)) {
META_ERROR("ini: Skipping malformed line %d of %s", ln, m_inifile);
2016-07-04 12:07:29 +06:00
continue;
}
// Try to find plugin with this pathname in the current list of
// plugins.
2017-05-09 18:34:55 +03:00
auto pl_found = find(pl_temp.m_pathname);
2017-05-09 19:31:09 +03:00
if (!pl_found) {
2016-07-04 12:07:29 +06:00
// Check for a matching platform with higher platform specifics
// level.
2017-05-09 18:34:55 +03:00
pl_found = find_match(&pl_temp);
2017-05-09 19:31:09 +03:00
if (pl_found) {
if (pl_found->m_action == PA_LOAD) {
2017-05-09 18:34:55 +03:00
META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin", ln);
int _index = pl_found->m_index;
2016-07-26 23:31:47 +07:00
Q_memset(pl_found, 0, sizeof(MPlugin));
pl_found->m_index = _index;
2016-07-04 12:07:29 +06:00
}
2017-05-09 19:31:09 +03:00
else {
2017-05-09 18:34:55 +03:00
META_DEBUG(1, "ini: Plugin in line %d should override existing plugin. Unable to comply.", ln);
2016-07-04 12:07:29 +06:00
continue;
}
}
// new plugin; add to list
2017-05-09 18:34:55 +03:00
auto pl_added = add(&pl_temp);
2017-05-09 19:31:09 +03:00
if (pl_added) {
2016-07-04 12:07:29 +06:00
// try to load this plugin at the next opportunity
pl_added->m_action = PA_LOAD;
2016-07-04 12:07:29 +06:00
}
else
// error details logged in add()
2016-07-04 12:07:29 +06:00
continue;
}
2017-05-09 19:31:09 +03:00
else {
2016-07-04 12:07:29 +06:00
// This plugin is already in the current list of plugins.
// Pathname already matches. Recopy desc, if specified in
// plugins.ini.
2017-05-09 19:31:09 +03:00
if (pl_temp.m_desc[0] != '<') {
Q_strncpy(pl_found->m_desc, pl_temp.m_desc, sizeof pl_found->m_desc - 1);
pl_found->m_desc[sizeof pl_found->m_desc - 1] = '\0';
2016-07-26 07:22:47 +07:00
}
2016-07-04 12:07:29 +06:00
// Check the file to see if it looks like it's been modified
// since we last loaded it.
2017-05-09 19:31:09 +03:00
if (!pl_found->newer_file()) {
pl_found->m_action = PA_KEEP;
2016-07-04 12:07:29 +06:00
}
// Newer file on disk.
2017-05-09 19:31:09 +03:00
else if (pl_found->m_status >= PL_OPENED) {
META_DEBUG(2, "ini: Plugin '%s' has newer file on disk", pl_found->m_desc);
pl_found->m_action = PA_RELOAD;
2016-07-04 12:07:29 +06:00
}
else
META_ERROR("ini: Plugin '%s' has newer file, but unexpected status (%s)", pl_found->m_desc, pl_found->str_status());
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
if (pl_found)
META_LOG("ini: Read plugin config for: %s", pl_found->m_desc);
2016-07-26 23:31:47 +07:00
else
META_LOG("ini: Read plugin config for: %s", pl_temp.m_desc);
2017-05-09 18:34:55 +03:00
2016-07-04 12:07:29 +06:00
n++;
}
META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", m_inifile, n);
2016-07-04 12:07:29 +06:00
fclose(fp);
2017-05-09 18:34:55 +03:00
2016-07-26 23:31:47 +07:00
if (!n)
META_ERROR("ini: Warning; no plugins found to load?");
2016-07-26 23:31:47 +07:00
2016-07-30 02:03:01 +03:00
return true;
2016-07-04 12:07:29 +06:00
}
// Load a plugin from a console command.
2016-07-30 02:03:01 +03:00
bool MPluginList::cmd_addload(const char* args)
2016-07-26 07:22:47 +07:00
{
2016-07-30 02:03:01 +03:00
MPlugin pl_temp = {};
2017-05-09 19:31:09 +03:00
if (!pl_temp.cmd_parseline(args)) {
2016-07-04 12:07:29 +06:00
META_CONS("Couldn't parse 'meta load' arguments: %s", args);
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
// resolve given path into a file; accepts various "shortcut"
// pathnames.
2017-05-09 19:31:09 +03:00
if (!pl_temp.resolve()) {
2016-07-04 12:07:29 +06:00
// Couldn't find a matching file on disk
META_CONS("Couldn't resolve given path into a file: %s", pl_temp.m_file);
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
// Try to find plugin with this pathname in the current list of
// plugins.
2017-05-09 18:34:55 +03:00
auto pl_found = find(pl_temp.m_pathname);
2017-05-09 19:31:09 +03:00
if (pl_found) {
2016-07-04 12:07:29 +06:00
// Already in list
META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.m_file, pl_found->m_file, pl_found->m_desc);
2017-01-07 21:03:16 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
// new plugin; add to list
2017-05-09 18:34:55 +03:00
auto pl_added = add(&pl_temp);
2017-05-09 19:31:09 +03:00
if (!pl_added) {
META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.m_desc);
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
// try to load new plugin
pl_added->m_action = PA_LOAD;
bool delayed;
if (!pl_added->load(PT_ANYTIME, delayed)) {
2016-07-04 12:07:29 +06:00
// load failed
if (pl_added->m_status == PL_OPENED)
META_CONS("Opened plugin '%s', but failed to attach; see log", pl_added->m_desc);
2016-07-04 12:07:29 +06:00
else
META_CONS("Couldn't load plugin '%s'; see log", pl_added->m_desc);
2016-07-26 23:31:47 +07:00
2017-05-09 18:34:55 +03:00
show();
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
META_CONS("Loaded plugin '%s' successfully", pl_added->m_desc);
2017-05-09 18:34:55 +03:00
show();
2016-07-30 02:03:01 +03:00
meta_rebuild_callbacks();
return true;
2016-07-04 12:07:29 +06:00
}
2017-06-26 18:10:34 +03:00
// Load plugins at startup->
2016-07-30 02:03:01 +03:00
bool MPluginList::load()
2016-07-26 07:22:47 +07:00
{
2016-07-26 23:31:47 +07:00
int n = 0;
2017-05-09 19:31:09 +03:00
if (!ini_startup()) {
META_ERROR("Problem loading plugins.ini: %s", m_inifile);
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
META_LOG("dll: Loading plugins...");
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
bool delayed;
2017-06-26 18:10:34 +03:00
if (p->load(PT_STARTUP, delayed))
2016-07-04 12:07:29 +06:00
n++;
else
// all plugins should be loadable at startup->..
2017-06-26 18:10:34 +03:00
META_ERROR("dll: Failed to load plugin '%s'", p->m_file);
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
META_LOG("dll: Finished loading %d plugins", n);
2017-05-09 18:34:55 +03:00
meta_rebuild_callbacks();
2016-07-30 02:03:01 +03:00
return true;
2016-07-04 12:07:29 +06:00
}
// Update list of loaded plugins from ini file, and load any new/changed plugins.
2016-07-30 02:03:01 +03:00
bool MPluginList::refresh(PLUG_LOADTIME now)
2016-07-26 07:22:47 +07:00
{
2017-05-09 00:35:21 +03:00
int ndone = 0, nkept = 0, nloaded = 0, nunloaded = 0, nreloaded = 0, ndelayed = 0;
2016-07-04 12:07:29 +06:00
2017-05-09 19:31:09 +03:00
if (!ini_refresh()) {
META_ERROR("dll: Problem reloading plugins.ini: %s", m_inifile);
2016-07-30 02:03:01 +03:00
return false;
2016-07-04 12:07:29 +06:00
}
META_LOG("dll: Updating plugins...");
bool delayed;
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
switch (p->m_action) {
2016-07-26 07:22:47 +07:00
case PA_KEEP:
2017-06-26 18:10:34 +03:00
META_DEBUG(1, "Keeping plugin '%s'", p->m_desc);
p->m_action = PA_NONE;
2016-07-26 07:22:47 +07:00
nkept++;
break;
case PA_LOAD:
2017-06-26 18:10:34 +03:00
META_DEBUG(1, "Loading plugin '%s'", p->m_desc);
if (p->load(now, delayed))
2016-07-26 07:22:47 +07:00
nloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
2016-07-26 07:22:47 +07:00
break;
case PA_RELOAD:
2017-06-26 18:10:34 +03:00
META_DEBUG(1, "Reloading plugin '%s'", p->m_desc);
if (p->reload(now, PNL_FILE_NEWER, delayed))
2016-07-26 07:22:47 +07:00
nreloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
2016-07-26 07:22:47 +07:00
break;
case PA_NONE:
// If previously loaded from ini, but apparently removed from new ini.
2017-06-26 18:10:34 +03:00
if (p->m_source == PS_INI && p->m_status >= PL_RUNNING) {
META_DEBUG(1, "Unloading plugin '%s'", p->m_desc);
p->m_action = PA_UNLOAD;
if (p->unload(now, PNL_INI_DELETED, delayed))
2016-07-04 12:07:29 +06:00
nunloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
2016-07-26 07:22:47 +07:00
}
break;
case PA_ATTACH:
// Previously requested attach, but was delayed?
2017-06-26 18:10:34 +03:00
META_DEBUG(1, "Retrying attach plugin '%s'", p->m_desc);
if (p->retry(now, PNL_DELAYED))
2016-07-26 07:22:47 +07:00
nloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
2016-07-26 07:22:47 +07:00
break;
case PA_UNLOAD:
// Previously requested unload, but was delayed?
2017-06-26 18:10:34 +03:00
META_DEBUG(1, "Retrying unload plugin '%s'", p->m_desc);
if (p->retry(now, PNL_DELAYED))
2016-07-26 07:22:47 +07:00
nunloaded++;
/*else if (meta_errno == ME_DELAYED) TODO
ndelayed++;*/
2016-07-26 07:22:47 +07:00
break;
case PA_NULL:
2017-06-26 18:10:34 +03:00
META_ERROR("dll: Unexpected action for plugin '%s': '%s'", p->m_desc, p->str_action());
2016-07-26 07:22:47 +07:00
break;
default:
2017-06-26 18:10:34 +03:00
META_ERROR("dll: Unrecognized action for plugin '%s': '%s'", p->m_desc, p->str_action());
2016-07-26 07:22:47 +07:00
break;
2016-07-04 12:07:29 +06:00
}
ndone++;
}
2016-07-26 23:31:47 +07:00
META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed);
2017-05-09 18:34:55 +03:00
meta_rebuild_callbacks();
2016-07-30 02:03:01 +03:00
return true;
2016-07-04 12:07:29 +06:00
}
// Re-enable any plugins currently paused.
2017-05-08 23:52:22 +03:00
void MPluginList::unpause_all()
2016-07-26 07:22:47 +07:00
{
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status == PL_PAUSED)
p->unpause();
2016-07-04 12:07:29 +06:00
}
}
// Retry any pending actions on plugins, for instance load/unload delayed
// until changelevel.
2016-07-26 07:22:47 +07:00
void MPluginList::retry_all(PLUG_LOADTIME now)
{
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_action != PA_NONE)
p->retry(now, PNL_DELAYED);
2016-07-04 12:07:29 +06:00
}
}
// List plugins and information about them in a formatted table.
2016-07-26 07:22:47 +07:00
void MPluginList::show(int source_index)
{
2016-07-26 23:31:47 +07:00
int n = 0, r = 0;
2017-05-09 19:31:09 +03:00
char desc[15 + 1], file[16 + 1], vers[7 + 1]; // plus 1 for term null
2016-07-26 07:22:47 +07:00
if (source_index <= 0)
2016-07-04 12:07:29 +06:00
META_CONS("Currently loaded plugins:");
else
META_CONS("Child plugins:");
2016-07-26 07:22:47 +07:00
2017-01-17 00:30:02 +03:00
META_CONS(" %*s %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, "", sizeof desc - 1, "description", "stat", "pend",
2017-05-09 19:31:09 +03:00
sizeof file - 1, "file", sizeof vers - 1, "ers", 2 + WIDTH_MAX_PLUGINS, "src", "load ", "unlod");
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (source_index > 0 && p->m_source_plugin_index != source_index)
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
Q_strncpy(desc, p->m_desc, sizeof desc - 1);
2017-01-17 00:30:02 +03:00
desc[sizeof desc - 1] = '\0';
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
Q_strncpy(file, p->m_file, sizeof file - 1);
2017-01-17 00:30:02 +03:00
file[sizeof file - 1] = '\0';
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (p->info() && p->info()->version) {
Q_strncpy(vers, p->info()->version, sizeof vers - 1);
2017-01-17 00:30:02 +03:00
vers[sizeof vers - 1] = '\0';
2016-07-26 07:22:47 +07:00
}
2017-05-09 19:31:09 +03:00
else {
2017-01-17 00:30:02 +03:00
Q_strncpy(vers, " -", sizeof vers - 1);
vers[sizeof vers - 1] = '\0';
2016-07-26 07:22:47 +07:00
}
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
META_CONS(" [%*d] %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, p->m_index,
sizeof desc - 1, desc, p->str_status(ST_SHOW), p->str_action(SA_SHOW), sizeof file - 1, file, sizeof vers - 1, vers,
2 + WIDTH_MAX_PLUGINS, p->str_source(SO_SHOW), p->str_loadable(SL_SHOW), p->str_unloadable(SL_SHOW));
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (p->m_status == PL_RUNNING)
2016-07-04 12:07:29 +06:00
r++;
n++;
}
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
META_CONS("%d plugins, %d running", n, r);
}
// List plugins and information to Player/client entity. Differs from the
// "meta list" console command in that:
// - Shows only "running" plugins, skipping any failed or paused plugins.
2016-07-26 23:31:47 +07:00
// - Limited info about each plugin, mostly the "public" info (name, author,
2016-07-04 12:07:29 +06:00
// etc).
2017-05-09 19:31:09 +03:00
void MPluginList::show_client(edict_t* pEntity)
2016-07-26 07:22:47 +07:00
{
2016-07-26 23:31:47 +07:00
int n = 0;
2016-07-04 12:07:29 +06:00
META_CLIENT(pEntity, "Currently running plugins:");
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status != PL_RUNNING || !p->info())
2016-07-04 12:07:29 +06:00
continue;
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
n++;
2016-07-26 23:31:47 +07:00
META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n,
2017-06-26 18:10:34 +03:00
p->info()->name ? p->info()->name : "<unknown>",
p->info()->version ? p->info()->version : "<?>",
p->info()->date ? p->info()->date : "<../../..>",
p->info()->author ? p->info()->author : "<unknown>",
p->info()->url ? p->info()->url : "<unknown>");
2016-07-04 12:07:29 +06:00
}
2016-07-26 23:31:47 +07:00
2016-07-04 12:07:29 +06:00
META_CLIENT(pEntity, "%d plugins", n);
}
2016-07-30 02:03:01 +03:00
bool MPluginList::found_child_plugins(int source_index) const
{
if (source_index <= 0)
2016-07-30 02:03:01 +03:00
return false;
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (p->m_source_plugin_index == source_index)
2016-07-30 02:03:01 +03:00
return true;
}
2016-07-30 02:03:01 +03:00
return false;
}
void MPluginList::clear_source_plugin_index(int source_index)
{
if (source_index <= 0)
return;
2017-06-26 18:10:34 +03:00
for (auto p : m_plugins) {
if (p->m_status < PL_VALID)
continue;
2016-07-26 23:31:47 +07:00
2017-06-26 18:10:34 +03:00
if (p->m_source_plugin_index == source_index)
p->m_source_plugin_index = -1;
}
}