diff --git a/amxmodx/AMBuilder b/amxmodx/AMBuilder index 5090cee5..23a115eb 100644 --- a/amxmodx/AMBuilder +++ b/amxmodx/AMBuilder @@ -96,6 +96,7 @@ binary.sources = [ 'CLibrarySys.cpp', 'CGameConfigs.cpp', 'gameconfigs.cpp', + 'CoreConfig.cpp', ] if builder.target_platform == 'windows': diff --git a/amxmodx/CoreConfig.cpp b/amxmodx/CoreConfig.cpp new file mode 100644 index 00000000..8ed2fd31 --- /dev/null +++ b/amxmodx/CoreConfig.cpp @@ -0,0 +1,324 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#include "amxmodx.h" +#include "CoreConfig.h" +#include "CLibrarySys.h" +#include + +CoreConfig CoreCfg; + +const char *MainConfigFile = "amxx.cfg"; +const char *AutoConfigDir = "/plugin"; +const char *MapConfigDir = "/maps"; +const char *CommandFormat = "exec %s\n"; + +CoreConfig::CoreConfig() +{ + Clear(); +} + +CoreConfig::~CoreConfig() +{ +} + +void CoreConfig::OnAmxxInitialized() +{ + m_ConfigsBufferedForward = registerForward("OnAutoConfigsBuffered", ET_IGNORE, FP_DONE); + m_ConfigsExecutedForward = registerForward("OnConfigsExecuted", ET_IGNORE, FP_DONE); +} + +void CoreConfig::Clear() +{ + m_ConfigsExecuted = false; + m_PendingForwardPush = false; + m_LegacyMainConfigExecuted = false; + m_LegacyMapConfigsExecuted = false, + m_legacyMapConfigNextTime = 0.0f; +} + +void CoreConfig::ExecuteMainConfig() +{ + if (m_LegacyMainConfigExecuted) + { + return; + } + + char path[PLATFORM_MAX_PATH]; + char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)]; + + UTIL_Format(path, sizeof(path), "%s/%s/%s", g_mod_name.chars(), get_localinfo("amx_configdir", "addons/amxmodx/configs"), MainConfigFile); + UTIL_Format(command, sizeof(command), CommandFormat, path); + + SERVER_COMMAND(command); +} + +void CoreConfig::ExecuteAutoConfigs() +{ + for (size_t i = 0; i < static_cast(g_plugins.getPluginsNum()); ++i) + { + auto plugin = g_plugins.findPlugin(i); + + bool can_create = true; + + for (size_t j = 0; j < plugin->GetConfigCount(); ++j) + { + can_create = ExecuteAutoConfig(plugin, plugin->GetConfig(j), can_create); + } + } + + executeForwards(m_ConfigsBufferedForward); +} + +bool CoreConfig::ExecuteAutoConfig(CPluginMngr::CPlugin *plugin, AutoConfig *config, bool can_create) +{ + bool will_create = false; + + const char *configsDir = get_localinfo("amx_configdir", "addons/amxmodx/configs"); + + if (can_create && config->create) + { + will_create = true; + + const char *folder = config->folder.chars(); + + char path[PLATFORM_MAX_PATH]; + char build[PLATFORM_MAX_PATH]; + + build_pathname_r(path, sizeof(path), "%s%s/%s", configsDir, AutoConfigDir, folder); + + if (!g_LibSys.IsPathDirectory(path)) + { + char *cur_ptr = path; + + g_LibSys.PathFormat(path, sizeof(path), "%s", folder); + build_pathname_r(build, sizeof(build), "%s%s", configsDir, AutoConfigDir); + + size_t length = strlen(build); + + do + { + char *next_ptr = cur_ptr; + + while (*next_ptr != '\0') + { + if (*next_ptr == PLATFORM_SEP_CHAR) + { + *next_ptr = '\0'; + next_ptr++; + break; + } + + next_ptr++; + } + + if (*next_ptr == '\0') + { + next_ptr = nullptr; + } + + length += g_LibSys.PathFormat(&build[length], sizeof(build) - length, "/%s", cur_ptr); + + if (!g_LibSys.CreateFolder(build)) + { + break; + } + + cur_ptr = next_ptr; + + } while (cur_ptr); + } + } + + char file[PLATFORM_MAX_PATH]; + + if (config->folder.length()) + { + UTIL_Format(file, sizeof(file), "%s/%s%s/%s/%s.cfg", g_mod_name.chars(), configsDir, AutoConfigDir, config->folder.chars(), config->autocfg.chars()); + } + else + { + UTIL_Format(file, sizeof(file), "%s/%s%s/%s.cfg", g_mod_name.chars(), configsDir, AutoConfigDir, config->autocfg.chars()); + } + + bool file_exists = g_LibSys.IsPathFile(file); + + if (!file_exists && will_create) + { + auto list = g_CvarManager.GetCvarsList(); + + if (list->empty()) + { + return can_create; + } + + FILE *fp = fopen(file, "wt"); + + if (fp) + { + fprintf(fp, "// This file was auto-generated by AMX Mod X (v%s)\n", AMXX_VERSION); + fprintf(fp, "// Cvars for plugin \"%s\"\n", plugin->getName()); + fprintf(fp, "\n\n"); + + for (auto iter = list->begin(); iter != list->end(); iter++) + { + auto info = (*iter); + + if (info->pluginId == plugin->getId()) + { + char description[255]; + char *ptr = description; + + // Print comments until there is no more + strncopy(description, info->description.chars(), sizeof(description)); + + while (*ptr != '\0') + { + // Find the next line + char *next_ptr = ptr; + + while (*next_ptr != '\0') + { + if (*next_ptr == '\n') + { + *next_ptr = '\0'; + next_ptr++; + break; + } + + next_ptr++; + } + + fprintf(fp, "// %s\n", ptr); + + ptr = next_ptr; + } + + fprintf(fp, "// -\n"); + fprintf(fp, "// Default: \"%s\"\n", info->defaultval.chars()); + + if (info->bound.hasMin) + { + fprintf(fp, "// Minimum: \"%02f\"\n", info->bound.minVal); + } + + if (info->bound.hasMax) + { + fprintf(fp, "// Maximum: \"%02f\"\n", info->bound.maxVal); + } + + fprintf(fp, "%s \"%s\"\n", info->var->name, info->defaultval.chars()); + fprintf(fp, "\n"); + } + } + + fprintf(fp, "\n"); + + file_exists = true; + can_create = false; + + fclose(fp); + } + else + { + AMXXLOG_Error("Failed to auto generate config for %s, make sure the directory has write permission.", plugin->getName()); + return can_create; + } + } + + if (file_exists) + { + char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)]; + UTIL_Format(command, sizeof(command), CommandFormat, file); + + SERVER_COMMAND(command); + } + + return can_create; +} + +void CoreConfig::ExecuteMapConfig() +{ + const char *configsDir = get_localinfo("amx_configdir", "addons/amxmodx/configs"); + + char cfgPath[PLATFORM_MAX_PATH]; + char mapName[PLATFORM_MAX_PATH]; + char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)]; + + strncopy(mapName, STRING(gpGlobals->mapname), sizeof(mapName)); + + char *mapPrefix; + + if (mapPrefix = strtok(mapName, "_")) + { + UTIL_Format(cfgPath, sizeof(cfgPath), "%s/%s%s/prefix_%s.cfg", g_mod_name.chars(), configsDir, MapConfigDir, mapPrefix); + + if (g_LibSys.IsPathFile(cfgPath)) + { + UTIL_Format(command, sizeof(command), CommandFormat, cfgPath); + SERVER_COMMAND(command); + } + } + + strncopy(mapName, STRING(gpGlobals->mapname), sizeof(mapName)); + UTIL_Format(cfgPath, sizeof(cfgPath), "%s/%s%s/%s.cfg", g_mod_name.chars(), configsDir, MapConfigDir, mapName); + + if (g_LibSys.IsPathFile(cfgPath)) + { + UTIL_Format(command, sizeof(command), CommandFormat, cfgPath); + SERVER_COMMAND(command); + } + + // Consider all configs be executed to the next frame. + m_PendingForwardPush = true; +} + + +void CoreConfig::OnMapConfigTimer() +{ + if (m_ConfigsExecuted) + { + return; + } + + if (m_PendingForwardPush) + { + m_PendingForwardPush = false; + m_ConfigsExecuted = true; + + executeForwards(m_ConfigsExecutedForward); + } + else if (!m_LegacyMapConfigsExecuted && m_legacyMapConfigNextTime <= gpGlobals->time) + { + ExecuteMapConfig(); + } +} + +void CoreConfig::CheckLegacyBufferedCommand(char *command) +{ + if (m_ConfigsExecuted) + { + return; + } + + if (!m_LegacyMainConfigExecuted && strstr(command, MainConfigFile)) + { + m_LegacyMainConfigExecuted = true; + } + + if (!m_LegacyMapConfigsExecuted && strstr(command, MapConfigDir)) + { + m_LegacyMapConfigsExecuted = true; + } +} + +void CoreConfig::SetMapConfigTimer(float time) +{ + m_legacyMapConfigNextTime = gpGlobals->time + time; +} diff --git a/amxmodx/CoreConfig.h b/amxmodx/CoreConfig.h new file mode 100644 index 00000000..7cb7465d --- /dev/null +++ b/amxmodx/CoreConfig.h @@ -0,0 +1,51 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#ifndef _CORE_CONFIG_H_ +#define _CORE_CONFIG_H_ + +#include "CPlugin.h" + +class CoreConfig +{ + public: + + CoreConfig(); + ~CoreConfig(); + + public: + + void Clear(); + + void ExecuteMainConfig(); + void ExecuteAutoConfigs(); + bool ExecuteAutoConfig(CPluginMngr::CPlugin *plugin, AutoConfig *config, bool can_create); + void ExecuteMapConfig(); + + void OnAmxxInitialized(); + void OnMapConfigTimer(); + + void CheckLegacyBufferedCommand(char *command); + void SetMapConfigTimer(float time); + + private: + + bool m_ConfigsExecuted; // Whether all configs have been executed + bool m_PendingForwardPush; // Whether OnConfigsExecuted forward should be triggered to the next frame + bool m_LegacyMainConfigExecuted; // Whether the old admin.sma is used and amxx.cfg was executed from there + bool m_LegacyMapConfigsExecuted; // Whether the old admin.sma is used and per-map config was executed from there + float m_legacyMapConfigNextTime; // Sets the next time that per-map configs should be executed + + int m_ConfigsBufferedForward; + int m_ConfigsExecutedForward; +}; + +extern CoreConfig CoreCfg; + +#endif // _CORE_CONFIG_H_ diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj b/amxmodx/msvc12/amxmodx_mm.vcxproj index 8c5866a8..7c5d56be 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj @@ -262,6 +262,7 @@ + @@ -348,6 +349,7 @@ + diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters index a4e18d81..86499225 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters @@ -288,6 +288,9 @@ Source Files + + Source Files + @@ -494,6 +497,9 @@ Header Files + + Header Files +