/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef CONFIGVALUECACHE_H #define CONFIGVALUECACHE_H #include "Common.h" #include "Config.h" #include "Errors.h" #include "Log.h" #include template class ConfigValueCache { static_assert(std::is_enum_v); public: enum class Reloadable : bool { No = false, Yes = true }; ConfigValueCache(ConfigEnum const configCount) { _configs.resize(static_cast(configCount)); _reloading = false; } void Initialize(bool reload) { _reloading = reload; BuildConfigCache(); _reloading = false; VerifyAllConfigsLoaded(); } template void SetConfigValue(ConfigEnum const config, std::string const& configName, T const& defaultValue, Reloadable reloadable = Reloadable::Yes, std::function&& checker = {}, std::string const& validationErrorText = "") { uint32 const configIndex = static_cast(config); ASSERT(configIndex < _configs.size(), "Config index out of bounds"); T const& configValue = sConfigMgr->GetOption(configName, defaultValue); bool configValueChanged = false; if (_reloading) { if (std::get(_configs[configIndex]) != configValue) configValueChanged = true; if (reloadable == Reloadable::No) { if (configValueChanged) LOG_ERROR("server.loading", "Server Config (Name: {}) cannot be changed by reload. A server restart is required to update this config value.", configName); return; } } else ASSERT(_configs[configIndex].index() == 0, "Config overwriting an existing value"); if (checker && !checker(configValue)) { LOG_ERROR("server.loading", "Server Config (Name: {}) failed validation check '{}'. Default value '{}' will be used instead.", configName, validationErrorText, defaultValue); _configs[configIndex] = defaultValue; } else _configs[configIndex] = configValue; } template void OverwriteConfigValue(ConfigEnum const config, T const& value) { uint32 const configIndex = static_cast(config); ASSERT(configIndex < _configs.size(), "Config index out of bounds"); size_t const oldValueTypeIndex = _configs[configIndex].index(); ASSERT(oldValueTypeIndex != 0, "Config value must already be set"); _configs[configIndex] = value; ASSERT(oldValueTypeIndex == _configs[configIndex].index(), "Config value type changed"); } template T GetConfigValue(ConfigEnum const config) const { uint32 const configIndex = static_cast(config); ASSERT(configIndex < _configs.size(), "Config index out of bounds"); ASSERT(_configs[configIndex].index() != 0, "Config value must already be set"); T const* value = std::get_if(&_configs[configIndex]); ASSERT(value, "Wrong config variant type"); return *value; } // Custom handling for string configs to convert from std::string to std::string_view std::string_view GetConfigValue(ConfigEnum const config) const { uint32 const configIndex = static_cast(config); ASSERT(configIndex < _configs.size(), "Config index out of bounds"); ASSERT(_configs[configIndex].index() != 0, "Config value must already be set"); std::string const* stringValue = std::get_if(&_configs[configIndex]); ASSERT(stringValue, "Wrong config variant type"); return std::string_view(*stringValue); } protected: virtual void BuildConfigCache() = 0; private: void VerifyAllConfigsLoaded() { uint32 configIndex = 0; for (auto const& variant : _configs) { if (variant.index() == 0) { LOG_ERROR("server.loading", "Server Config (Index: {}) is defined but not loaded, unable to continue.", configIndex); ASSERT(false); } ++configIndex; } } std::vector> _configs; bool _reloading; }; #endif