diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7a40d23baf..1584798238 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -93,8 +93,7 @@ namespace Launcher int getMaxNavMeshDbFileSizeMiB() { - return static_cast( - Settings::Manager::getInt64("max navmeshdb file size", "Navigator") / (1024 * 1024)); + return Settings::Manager::getUInt64("max navmeshdb file size", "Navigator") / (1024 * 1024); } } } @@ -318,8 +317,8 @@ QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, void Launcher::DataFilesPage::saveSettings(const QString& profile) { if (const int value = ui.navMeshMaxSizeSpinBox->value(); value != getMaxNavMeshDbFileSizeMiB()) - Settings::Manager::setInt64( - "max navmeshdb file size", "Navigator", static_cast(value) * 1024 * 1024); + Settings::Manager::setUInt64( + "max navmeshdb file size", "Navigator", static_cast(std::max(0, value)) * 1024 * 1024); QString profileName = profile; diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index cf7a3d6a4a..75c383d5de 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -196,8 +196,7 @@ namespace NavMeshTool const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); const DetourNavigator::AgentBounds agentBounds{ agentCollisionShape, agentHalfExtents }; - const std::uint64_t maxDbFileSize - = static_cast(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); + const std::uint64_t maxDbFileSize = Settings::Manager::getUInt64("max navmeshdb file size", "Navigator"); const auto dbPath = Files::pathToUnicodeString(config.getUserDataPath() / "navmesh.db"); DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize); diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index e02e3032f4..24d161f6bd 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -123,7 +123,7 @@ namespace MWGui void DebugWindow::startLogRecording() { - sLogCircularBuffer.resize(std::max(0, Settings::Manager::getInt64("log buffer size", "General"))); + sLogCircularBuffer.resize(Settings::Manager::getSize("log buffer size", "General")); Debug::setLogListener([](Debug::Level level, std::string_view prefix, std::string_view msg) { if (sLogCircularBuffer.empty()) return; // Log viewer is disabled. diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index 7467feb55f..c39275d468 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -43,10 +43,8 @@ namespace DetourNavigator = std::clamp(::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"), 1, 65535); result.mMaxPolys = std::clamp(::Settings::Manager::getInt("max polygons per tile", "Navigator"), 1, (1 << 22) - 1); - result.mMaxPolygonPathSize - = static_cast(std::max(0, ::Settings::Manager::getInt("max polygon path size", "Navigator"))); - result.mMaxSmoothPathSize - = static_cast(std::max(0, ::Settings::Manager::getInt("max smooth path size", "Navigator"))); + result.mMaxPolygonPathSize = ::Settings::Manager::getSize("max polygon path size", "Navigator"); + result.mMaxSmoothPathSize = ::Settings::Manager::getSize("max smooth path size", "Navigator"); return result; } @@ -60,10 +58,9 @@ namespace DetourNavigator result.mMaxTilesNumber = std::max(0, ::Settings::Manager::getInt("max tiles number", "Navigator")); result.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator"); - result.mAsyncNavMeshUpdaterThreads = static_cast( - std::max(0, ::Settings::Manager::getInt("async nav mesh updater threads", "Navigator"))); - result.mMaxNavMeshTilesCacheSize = static_cast( - std::max(std::int64_t{ 0 }, ::Settings::Manager::getInt64("max nav mesh tiles cache size", "Navigator"))); + result.mAsyncNavMeshUpdaterThreads + = ::Settings::Manager::getSize("async nav mesh updater threads", "Navigator"); + result.mMaxNavMeshTilesCacheSize = ::Settings::Manager::getSize("max nav mesh tiles cache size", "Navigator"); result.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator"); result.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator"); @@ -77,8 +74,7 @@ namespace DetourNavigator = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator")); result.mEnableNavMeshDiskCache = ::Settings::Manager::getBool("enable nav mesh disk cache", "Navigator"); result.mWriteToNavMeshDb = ::Settings::Manager::getBool("write to navmeshdb", "Navigator"); - result.mMaxDbFileSize - = static_cast(::Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); + result.mMaxDbFileSize = ::Settings::Manager::getUInt64("max navmeshdb file size", "Navigator"); return result; } diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 5dfadd9d50..c5dd9a7837 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,14 +1,44 @@ #include "settings.hpp" #include "parser.hpp" +#include +#include #include #include +#include #include #include namespace Settings { + namespace + { + template + auto parseIntegralNumber(const std::string& value, std::string_view setting, std::string_view category) + { + T number{}; + const auto result = std::from_chars(value.data(), value.data() + value.size(), number); + if (result.ec != std::errc()) + throw std::system_error(std::make_error_code(result.ec), + "Failed to parse number from setting [" + std::string(category) + "] " + std::string(setting) + + " value \"" + value + "\""); + return number; + } + + template + auto parseFloatingPointNumber(const std::string& value, std::string_view setting, std::string_view category) + { + std::stringstream stream(value); + T number{}; + stream >> number; + if (stream.bad()) + throw std::system_error(errno, std::generic_category(), + "Failed to parse number from setting [" + std::string(category) + "] " + std::string(setting) + + " value \"" + value + "\""); + return number; + } + } CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); @@ -109,38 +139,27 @@ namespace Settings float Manager::getFloat(std::string_view setting, std::string_view category) { - const std::string& value = getString(setting, category); - std::stringstream stream(value); - float number = 0.f; - stream >> number; - return number; + return parseFloatingPointNumber(getString(setting, category), setting, category); } double Manager::getDouble(std::string_view setting, std::string_view category) { - const std::string& value = getString(setting, category); - std::stringstream stream(value); - double number = 0.0; - stream >> number; - return number; + return parseFloatingPointNumber(getString(setting, category), setting, category); } int Manager::getInt(std::string_view setting, std::string_view category) { - const std::string& value = getString(setting, category); - std::stringstream stream(value); - int number = 0; - stream >> number; - return number; + return parseIntegralNumber(getString(setting, category), setting, category); } - std::int64_t Manager::getInt64(std::string_view setting, std::string_view category) + std::uint64_t Manager::getUInt64(std::string_view setting, std::string_view category) { - const std::string& value = getString(setting, category); - std::stringstream stream(value); - std::int64_t number = 0; - stream >> number; - return number; + return parseIntegralNumber(getString(setting, category), setting, category); + } + + std::size_t Manager::getSize(std::string_view setting, std::string_view category) + { + return parseIntegralNumber(getString(setting, category), setting, category); } bool Manager::getBool(std::string_view setting, std::string_view category) @@ -213,7 +232,7 @@ namespace Settings setString(setting, category, stream.str()); } - void Manager::setInt64(std::string_view setting, std::string_view category, const std::int64_t value) + void Manager::setUInt64(std::string_view setting, std::string_view category, const std::uint64_t value) { std::ostringstream stream; stream << value; diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 6efd494e9c..3184c470c3 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -61,7 +61,8 @@ namespace Settings ///< returns the list of changed settings intersecting with the filter static int getInt(std::string_view setting, std::string_view category); - static std::int64_t getInt64(std::string_view setting, std::string_view category); + static std::uint64_t getUInt64(std::string_view setting, std::string_view category); + static std::size_t getSize(std::string_view setting, std::string_view category); static float getFloat(std::string_view setting, std::string_view category); static double getDouble(std::string_view setting, std::string_view category); static const std::string& getString(std::string_view setting, std::string_view category); @@ -71,7 +72,7 @@ namespace Settings static osg::Vec3f getVector3(std::string_view setting, std::string_view category); static void setInt(std::string_view setting, std::string_view category, int value); - static void setInt64(std::string_view setting, std::string_view category, std::int64_t value); + static void setUInt64(std::string_view setting, std::string_view category, std::uint64_t value); static void setFloat(std::string_view setting, std::string_view category, float value); static void setDouble(std::string_view setting, std::string_view category, double value); static void setString(std::string_view setting, std::string_view category, const std::string& value); diff --git a/docs/source/reference/modding/settings/general.rst b/docs/source/reference/modding/settings/general.rst index a7a64e04b8..84c4a19f44 100644 --- a/docs/source/reference/modding/settings/general.rst +++ b/docs/source/reference/modding/settings/general.rst @@ -90,7 +90,7 @@ Two highest priority locales may be assigned via the Localization tab of the in- log buffer size --------------- -:Type: integer +:Type: platform dependant unsigned integer :Range: >= 0 :Default: 65536 diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 5220d500fc..63e9363fc6 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -77,7 +77,7 @@ If true generated navmesh tiles will be stored into disk cache while game is run max navmeshdb file size ----------------------- -:Type: integer +:Type: unsigned 64-bit integer :Range: > 0 :Default: 2147483648 @@ -91,7 +91,7 @@ This section is for advanced PC uses who understands concepts of OS thread and m async nav mesh updater threads ------------------------------ -:Type: integer +:Type: platform dependant unsigned integer :Range: >= 1 :Default: 1 @@ -103,7 +103,7 @@ Don't expect twice better latency by doubling this value. max nav mesh tiles cache size ----------------------------- -:Type: integer +:Type: platform dependant unsigned integer :Range: >= 0 :Default: 268435456 @@ -279,7 +279,7 @@ Pay attention to slopes and roofs when change it. Increasing this value will red max polygon path size --------------------- -:Type: integer +:Type: platform dependant unsigned integer :Range: > 0 :Default: 1024 @@ -288,7 +288,7 @@ Maximum size of path over polygons. max smooth path size -------------------- -:Type: integer +:Type: platform dependant unsigned integer :Range: > 0 :Default: 1024