From a0d081adb9ca8128ce78edb3802646c0065d144d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 13:55:33 +0200 Subject: [PATCH 01/11] Replace StringUtils::format in components/detournavigator --- components/detournavigator/asyncnavmeshupdater.cpp | 9 ++++----- components/detournavigator/navmeshdb.cpp | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index fe8cadd703..4a4137170a 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -20,6 +19,7 @@ #include #include +#include #include #include #include @@ -78,7 +78,7 @@ namespace DetourNavigator std::string makeRevision(const Version& version) { - return Misc::StringUtils::format(".%zu.%zu", version.mGeneration, version.mRevision); + return std::format(".{}.{}", version.mGeneration, version.mRevision); } void writeDebugRecastMesh( @@ -90,9 +90,8 @@ namespace DetourNavigator if (settings.mEnableRecastMeshFileNameRevision) revision = makeRevision(recastMesh.getVersion()); writeToFile(recastMesh, - Misc::StringUtils::format( - "%s%d.%d.", settings.mRecastMeshPathPrefix, tilePosition.x(), tilePosition.y()), - revision, settings.mRecast); + std::format("{}{}.{}.", settings.mRecastMeshPathPrefix, tilePosition.x(), tilePosition.y()), revision, + settings.mRecast); } void writeDebugNavMesh( diff --git a/components/detournavigator/navmeshdb.cpp b/components/detournavigator/navmeshdb.cpp index 76f0811f16..bfc6dd5ecb 100644 --- a/components/detournavigator/navmeshdb.cpp +++ b/components/detournavigator/navmeshdb.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -11,6 +10,7 @@ #include #include +#include #include #include @@ -148,7 +148,7 @@ namespace DetourNavigator void setMaxPageCount(sqlite3& db, std::uint64_t value) { - const auto query = Misc::StringUtils::format("pragma max_page_count = %lu;", value); + const auto query = std::format("pragma max_page_count = {};", value); if (const int ec = sqlite3_exec(&db, query.c_str(), nullptr, nullptr, nullptr); ec != SQLITE_OK) throw std::runtime_error("Failed set max page count: " + std::string(sqlite3_errmsg(&db))); } From 58a232d6c75a3628e9f30276553510cdd1b0c40b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 14:07:41 +0200 Subject: [PATCH 02/11] Replace StringUtils::format in components/interpreter --- components/interpreter/interpreter.cpp | 46 ++++++++++++++++---------- components/interpreter/interpreter.hpp | 9 ++--- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 6a51a2cddf..be6d7d1adf 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -1,6 +1,7 @@ #include "interpreter.hpp" #include +#include #include #include @@ -9,27 +10,36 @@ namespace Interpreter { - [[noreturn]] static void abortUnknownCode(int segment, int opcode) + namespace { - const std::string error = "unknown opcode " + std::to_string(opcode) + " in segment " + std::to_string(segment); - throw std::runtime_error(error); - } - - [[noreturn]] static void abortUnknownSegment(Type_Code code) - { - const std::string error = "opcode outside of the allocated segment range: " + std::to_string(code); - throw std::runtime_error(error); - } - - template - auto& getDispatcher(const T& segment, unsigned int seg, int opcode) - { - auto it = segment.find(opcode); - if (it == segment.end()) + [[noreturn]] void abortUnknownCode(int segment, int opcode) { - abortUnknownCode(seg, opcode); + const std::string error = std::format("unknown opcode {} in segment {}", opcode, segment); + throw std::runtime_error(error); } - return it->second; + + [[noreturn]] void abortUnknownSegment(Type_Code code) + { + const std::string error = std::format("opcode outside of the allocated segment range: {}", code); + throw std::runtime_error(error); + } + + template + auto& getDispatcher(const T& segment, unsigned int seg, int opcode) + { + auto it = segment.find(opcode); + if (it == segment.end()) + { + abortUnknownCode(seg, opcode); + } + return it->second; + } + } + + [[noreturn]] void Interpreter::abortDuplicateInstruction(std::string_view name, int code) + { + throw std::invalid_argument( + std::format("Duplicated interpreter instruction code in segment {}: {:#x}", name, code)); } void Interpreter::execute(Type_Code code) diff --git a/components/interpreter/interpreter.hpp b/components/interpreter/interpreter.hpp index 381cb5dd6b..6ad7a9dc96 100644 --- a/components/interpreter/interpreter.hpp +++ b/components/interpreter/interpreter.hpp @@ -4,13 +4,9 @@ #include #include #include -#include #include -#include - #include "opcodes.hpp" -#include "program.hpp" #include "runtime.hpp" #include "types.hpp" @@ -34,12 +30,13 @@ namespace Interpreter void end(); + [[noreturn]] void abortDuplicateInstruction(std::string_view name, int code); + template void installSegment(auto& segment, std::string_view name, int code, Args&&... args) { if (segment.find(code) != segment.end()) - throw std::invalid_argument(Misc::StringUtils::format( - "Duplicated interpreter instruction code in segment %s: 0x%x", name, code)); + abortDuplicateInstruction(name, code); segment.emplace(code, std::make_unique(std::forward(args)...)); } From 26e562490ff1c4a2d61cd0d22f086518caa032a1 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 14:28:17 +0200 Subject: [PATCH 03/11] Replace StringUtils::format in components/lua --- components/lua/configuration.cpp | 13 ++++++------- components/lua/inputactions.cpp | 25 ++++++++++++------------- components/lua/utf8.cpp | 18 ++++++++---------- components/lua/yamlloader.cpp | 12 ++++++------ 4 files changed, 32 insertions(+), 36 deletions(-) diff --git a/components/lua/configuration.cpp b/components/lua/configuration.cpp index 858137ab73..3ca350e39b 100644 --- a/components/lua/configuration.cpp +++ b/components/lua/configuration.cpp @@ -3,10 +3,10 @@ #include #include #include +#include #include #include -#include #include namespace LuaUtil @@ -187,13 +187,13 @@ namespace LuaUtil line = line.substr(0, line.size() - 1); if (!Misc::StringUtils::ciEndsWith(line, ".lua")) - throw std::runtime_error(Misc::StringUtils::format( - "Lua script should have suffix '.lua', got: %s", std::string(line.substr(0, 300)))); + throw std::runtime_error( + std::format("Lua script should have suffix '.lua', got: {}", line.substr(0, 300))); // Split tags and script path size_t semicolonPos = line.find(':'); - if (semicolonPos == std::string::npos) - throw std::runtime_error(Misc::StringUtils::format("No flags found in: %s", std::string(line))); + if (semicolonPos == std::string_view::npos) + throw std::runtime_error(std::format("No flags found in: {}", line)); std::string_view tagsStr = line.substr(0, semicolonPos); std::string_view scriptPath = line.substr(semicolonPos + 1); while (isSpace(scriptPath[0])) @@ -222,8 +222,7 @@ namespace LuaUtil else if (typesIt != typeTagsByName.end()) script.mTypes.push_back(typesIt->second); else - throw std::runtime_error( - Misc::StringUtils::format("Unknown tag '%s' in: %s", std::string(tagName), std::string(line))); + throw std::runtime_error(std::format("Unknown tag '{}' in: {}", tagName, line)); } } } diff --git a/components/lua/inputactions.cpp b/components/lua/inputactions.cpp index b0c7fe2e9f..5570824394 100644 --- a/components/lua/inputactions.cpp +++ b/components/lua/inputactions.cpp @@ -116,14 +116,14 @@ namespace LuaUtil void Registry::insert(const Info& info) { if (mIds.find(info.mKey) != mIds.end()) - throw std::domain_error(Misc::StringUtils::format("Action key \"%s\" is already in use", info.mKey)); + throw std::domain_error(std::format("Action key \"{}\" is already in use", info.mKey)); if (info.mKey.empty()) throw std::domain_error("Action key can't be an empty string"); if (info.mL10n.empty()) throw std::domain_error("Localization context can't be empty"); if (!validateActionValue(info.mDefaultValue, info.mType)) - throw std::logic_error(Misc::StringUtils::format( - "Invalid value: \"%s\" for action \"%s\"", LuaUtil::toString(info.mDefaultValue), info.mKey)); + throw std::logic_error(std::format( + "Invalid value: \"{}\" for action \"{}\"", LuaUtil::toString(info.mDefaultValue), info.mKey)); Id id = mBindingTree.insert(); mKeys.push_back(info.mKey); mIds[std::string(info.mKey)] = id; @@ -156,7 +156,7 @@ namespace LuaUtil { auto iter = mIds.find(key); if (iter == mIds.end()) - throw std::logic_error(Misc::StringUtils::format("Unknown action key: \"%s\"", key)); + throw std::logic_error(std::format("Unknown action key: \"{}\"", key)); return iter->second; } @@ -183,7 +183,7 @@ namespace LuaUtil Info info = mInfo[id]; if (info.mType != type) throw std::logic_error( - Misc::StringUtils::format("Attempt to get value of type \"%s\" from action \"%s\" with type \"%s\"", + std::format("Attempt to get value of type \"{}\" from action \"{}\" with type \"{}\"", typeName(type), key, typeName(info.mType))); return mValues[id]; } @@ -210,10 +210,9 @@ namespace LuaUtil catch (std::exception& e) { if (!validateActionValue(newValue, mInfo[node].mType)) - Log(Debug::Error) << Misc::StringUtils::format( - "Error due to invalid value of action \"%s\"(\"%s\"): ", mKeys[node], - LuaUtil::toString(newValue)) - << e.what(); + Log(Debug::Error) + << "Error due to invalid value of action \"" << mKeys[node] + << "\"(\"" << LuaUtil::toString(newValue) << "\"): " << e.what(); else Log(Debug::Error) << "Error in callback: " << e.what(); } @@ -222,8 +221,8 @@ namespace LuaUtil bindings.end()); if (!validateActionValue(newValue, mInfo[node].mType)) - Log(Debug::Error) << Misc::StringUtils::format( - "Invalid value of action \"%s\": %s", mKeys[node], LuaUtil::toString(newValue)); + Log(Debug::Error) << "Invalid value of action \"" << mKeys[node] + << "\": " << LuaUtil::toString(newValue); if (mValues[node] != newValue) { mValues[node] = sol::object(newValue); @@ -270,14 +269,14 @@ namespace LuaUtil { auto it = mIds.find(key); if (it == mIds.end()) - throw std::domain_error(Misc::StringUtils::format("Unknown trigger key \"%s\"", key)); + throw std::domain_error(std::format("Unknown trigger key \"{}\"", key)); return it->second; } void Registry::insert(const Info& info) { if (mIds.find(info.mKey) != mIds.end()) - throw std::domain_error(Misc::StringUtils::format("Trigger key \"%s\" is already in use", info.mKey)); + throw std::domain_error(std::format("Trigger key \"{}\" is already in use", info.mKey)); if (info.mKey.empty()) throw std::domain_error("Trigger key can't be an empty string"); if (info.mL10n.empty()) diff --git a/components/lua/utf8.cpp b/components/lua/utf8.cpp index d8aa7cf295..4c52c75255 100644 --- a/components/lua/utf8.cpp +++ b/components/lua/utf8.cpp @@ -1,7 +1,7 @@ -#include - #include "utf8.hpp" +#include + namespace { constexpr std::string_view UTF8PATT = "[%z\x01-\x7F\xC2-\xF4][\x80-\xBF]*"; // %z is deprecated in Lua5.2 @@ -17,12 +17,12 @@ namespace { double integer; if (!arg.is()) - throw std::runtime_error(Misc::StringUtils::format("bad argument #%i to '%s' (number expected, got %s)", n, - name, sol::type_name(arg.lua_state(), arg.get_type()))); + throw std::runtime_error(std::format("bad argument #{} to '{}' (number expected, got {})", n, name, + sol::type_name(arg.lua_state(), arg.get_type()))); if (std::modf(arg, &integer) != 0) throw std::runtime_error( - Misc::StringUtils::format("bad argument #%i to '%s' (number has no integer representation)", n, name)); + std::format("bad argument #{} to '{}' (number has no integer representation)", n, name)); return static_cast(integer); } @@ -127,8 +127,7 @@ namespace LuaUtf8 { int64_t codepoint = getInteger(args[i], (i + 1), "char"); if (codepoint < 0 || codepoint > MAXUNICODE) - throw std::runtime_error( - "bad argument #" + std::to_string(i + 1) + " to 'char' (value out of range)"); + throw std::runtime_error(std::format("bad argument #{} to 'char' (value out of range)", i + 1)); codepointToUTF8(static_cast(codepoint), result); } @@ -142,8 +141,7 @@ namespace LuaUtf8 { const auto pair = decodeNextUTF8Character(s, posByte); if (pair.second == -1) - throw std::runtime_error( - "Invalid UTF-8 code at position " + std::to_string(posByte.size())); + throw std::runtime_error(std::format("Invalid UTF-8 code at position {}", posByte.size())); return pair; } @@ -202,7 +200,7 @@ namespace LuaUtf8 { codepoints.push_back(decodeNextUTF8Character(s, posByte).second); if (codepoints.back() == -1) - throw std::runtime_error("Invalid UTF-8 code at position " + std::to_string(posByte.size())); + throw std::runtime_error(std::format("Invalid UTF-8 code at position {}", posByte.size())); } return sol::as_returns(std::move(codepoints)); diff --git a/components/lua/yamlloader.cpp b/components/lua/yamlloader.cpp index df83af6253..e271f7c428 100644 --- a/components/lua/yamlloader.cpp +++ b/components/lua/yamlloader.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -13,8 +14,7 @@ #include -#include -#include +#include namespace LuaUtil { @@ -213,10 +213,10 @@ namespace LuaUtil } case ScalarType::Boolean: { - if (Misc::StringUtils::lowerCase(value) == "true") + if (Misc::StringUtils::ciEqual(value, "true")) return sol::make_object(lua, true); - if (Misc::StringUtils::lowerCase(value) == "false") + if (Misc::StringUtils::ciEqual(value, "false")) return sol::make_object(lua, false); nodeError(node, "Can not read a boolean value '" + value + "'"); @@ -272,8 +272,8 @@ namespace LuaUtil [[noreturn]] void nodeError(const YAML::Node& node, const std::string& message) { const auto& mark = node.Mark(); - std::string error = Misc::StringUtils::format( - " at line=%d column=%d position=%d", mark.line + 1, mark.column + 1, mark.pos + 1); + std::string error + = std::format(" at line={} column={} position={}", mark.line + 1, mark.column + 1, mark.pos + 1); throw std::runtime_error(message + error); } } From 924d59115830b85a1577050ce35363f67dfda5f7 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 14:35:44 +0200 Subject: [PATCH 04/11] Replace StringUtils::format in components/sceneutil --- components/sceneutil/animblendrules.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/animblendrules.cpp b/components/sceneutil/animblendrules.cpp index c285988f40..2702584e63 100644 --- a/components/sceneutil/animblendrules.cpp +++ b/components/sceneutil/animblendrules.cpp @@ -1,10 +1,10 @@ #include "animblendrules.hpp" +#include #include #include #include -#include #include #include @@ -68,8 +68,7 @@ namespace SceneUtil if (!root.IsDefined() || root.IsNull() || root.IsScalar()) { - Log(Debug::Error) << Misc::StringUtils::format( - "Can't parse file '%s'. Check that it's a valid YAML/JSON file.", configPath); + Log(Debug::Error) << "Can't parse file '" << configPath << "'. Check that it's a valid YAML/JSON file."; return nullptr; } @@ -104,12 +103,11 @@ namespace SceneUtil } else { - throw std::domain_error( - Misc::StringUtils::format("'blending_rules' object not found in '%s' file!", configPath)); + throw std::domain_error(std::format("'blending_rules' object not found in '{}' file!", configPath.value())); } // If no rules then dont allocate any instance - if (rules.size() == 0) + if (rules.empty()) return nullptr; return new AnimBlendRules(rules); From ecbc3a7b9e27da7b3825d87cc5488b2f824bf4ff Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 15:40:55 +0200 Subject: [PATCH 05/11] Reduce string usage in ShaderManager --- components/shader/shadermanager.cpp | 126 ++++++++++++---------------- components/shader/shadermanager.hpp | 5 +- 2 files changed, 55 insertions(+), 76 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index c22055c82c..a958637516 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -3,44 +3,47 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include #include #include #include #include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + namespace { osg::Shader::Type getShaderType(const std::string& templateName) { - auto ext = std::filesystem::path(templateName).extension(); + std::string_view ext = Misc::getFileExtension(templateName); - if (ext == ".vert") + if (ext == "vert") return osg::Shader::VERTEX; - if (ext == ".frag") + if (ext == "frag") return osg::Shader::FRAGMENT; - if (ext == ".geom") + if (ext == "geom") return osg::Shader::GEOMETRY; - if (ext == ".comp") + if (ext == "comp") return osg::Shader::COMPUTE; - if (ext == ".tese") + if (ext == "tese") return osg::Shader::TESSEVALUATION; - if (ext == ".tesc") + if (ext == "tesc") return osg::Shader::TESSCONTROL; throw std::runtime_error("unrecognized shader template name: " + templateName); } - std::string getRootPrefix(const std::string& path) + std::string_view getRootPrefix(std::string_view path) { if (path.starts_with("lib")) return "lib"; @@ -48,8 +51,26 @@ namespace return "compatibility"; else if (path.starts_with("core")) return "core"; + return {}; + } + + int getLineNumber(std::string_view source, std::size_t foundPos, int lineNumber, int offset) + { + constexpr std::string_view tag = "#line"; + std::size_t lineDirectivePosition = source.rfind(tag, foundPos); + if (lineDirectivePosition != std::string_view::npos) + { + std::size_t lineNumberStart = lineDirectivePosition + tag.size() + 1; + std::size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string_view lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = Misc::StringUtils::toNumeric(lineNumberString, 2) + offset; + } else - return ""; + { + lineDirectivePosition = 0; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); + return lineNumber; } } @@ -85,21 +106,7 @@ namespace Shader if (foundPos == std::string::npos) break; - size_t lineDirectivePosition = source.rfind("#line", foundPos); - int lineNumber; - if (lineDirectivePosition != std::string::npos) - { - size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); - size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); - std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); - lineNumber = Misc::StringUtils::toNumeric(lineNumberString, 2) - 1; - } - else - { - lineDirectivePosition = 0; - lineNumber = 1; - } - lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); + int lineNumber = getLineNumber(source, foundPos, 1, -1); source.replace(foundPos, 0, "#line " + std::to_string(lineNumber) + "\n"); @@ -154,21 +161,7 @@ namespace Shader std::filesystem::path includePath = shaderPath / includeFilename; // Determine the line number that will be used for the #line directive following the included source - size_t lineDirectivePosition = source.rfind("#line", foundPos); - int lineNumber; - if (lineDirectivePosition != std::string::npos) - { - size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); - size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); - std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); - lineNumber = Misc::StringUtils::toNumeric(lineNumberString, 2) - 1; - } - else - { - lineDirectivePosition = 0; - lineNumber = 0; - } - lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); + int lineNumber = getLineNumber(source, foundPos, 0, -1); // Include the file recursively std::ifstream includeFstream; @@ -202,7 +195,8 @@ namespace Shader bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos) { - size_t iterNameStart = foundPos + strlen("$foreach") + 1; + constexpr std::string_view directiveStart = "$foreach"; + size_t iterNameStart = foundPos + directiveStart.size() + 1; size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); if (iterNameEnd == std::string::npos) { @@ -218,46 +212,32 @@ namespace Shader Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; return false; } - std::string list = source.substr(listStart, listEnd - listStart); + std::string_view list = std::string_view(source).substr(listStart, listEnd - listStart); std::vector listElements; - if (list != "") + if (!list.empty()) Misc::StringUtils::split(list, listElements, ","); size_t contentStart = source.find_first_not_of("\n\r", listEnd); - size_t contentEnd = source.find("$endforeach", contentStart); + constexpr std::string_view directiveEnd = "$endforeach"; + size_t contentEnd = source.find(directiveEnd, contentStart); if (contentEnd == std::string::npos) { Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; return false; } - std::string content = source.substr(contentStart, contentEnd - contentStart); + std::string_view content = std::string_view(source).substr(contentStart, contentEnd - contentStart); - size_t overallEnd = contentEnd + std::string("$endforeach").length(); + size_t overallEnd = contentEnd + directiveEnd.size(); - size_t lineDirectivePosition = source.rfind("#line", overallEnd); - int lineNumber; - if (lineDirectivePosition != std::string::npos) - { - size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); - size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); - std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); - lineNumber = Misc::StringUtils::toNumeric(lineNumberString, 2); - } - else - { - lineDirectivePosition = 0; - lineNumber = 2; - } - lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n'); + int lineNumber = getLineNumber(source, overallEnd, 2, 0); std::string replacement; - for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); - element++) + for (const std::string& element : listElements) { - std::string contentInstance = content; + std::string contentInstance(content); size_t foundIterator; while ((foundIterator = contentInstance.find(iteratorName)) != std::string::npos) - contentInstance.replace(foundIterator, iteratorName.length(), *element); + contentInstance.replace(foundIterator, iteratorName.length(), element); replacement += contentInstance; } replacement += "\n#line " + std::to_string(lineNumber); @@ -327,7 +307,7 @@ namespace Shader Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; return false; } - std::string directive = source.substr(foundPos + 1, endPos - (foundPos + 1)); + std::string_view directive = std::string_view(source).substr(foundPos + 1, endPos - (foundPos + 1)); if (directive == "foreach") { if (!parseForeachDirective(source, templateName, foundPos)) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 827fef7e88..bdcd8622dd 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_SHADERMANAGER_H #include +#include #include #include #include @@ -9,11 +10,9 @@ #include #include -#include - -#include #include #include +#include namespace osgViewer { From 9cce6bad68ba4688df20281e227b88f64e938651 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 15:43:11 +0200 Subject: [PATCH 06/11] Replace StringUtils::format in components/shader --- components/shader/shadermanager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a958637516..b51901df97 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include namespace @@ -108,7 +108,7 @@ namespace Shader int lineNumber = getLineNumber(source, foundPos, 1, -1); - source.replace(foundPos, 0, "#line " + std::to_string(lineNumber) + "\n"); + source.replace(foundPos, 0, std::format("#line {}\n", lineNumber)); position = foundPos; } @@ -554,7 +554,7 @@ namespace Shader // Assign a unique prefix to allow the SharedStateManager to compare shaders efficiently. // Append shader source filename for debugging. static unsigned int counter = 0; - shader->setName(Misc::StringUtils::format("%u %s", counter++, templateName)); + shader->setName(std::format("{} {}", counter++, templateName)); mHotReloadManager->addShaderFiles(templateName, defines); From 23210868768a38de5dad16dc640c6d0e81e08554 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 16:01:17 +0200 Subject: [PATCH 07/11] Replace StringUtils::format in components/misc --- apps/launcher/graphicspage.cpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 60 ++++++++++++---------------- components/misc/display.cpp | 7 ++-- components/misc/display.hpp | 2 +- 4 files changed, 30 insertions(+), 41 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 38b0446efc..b25d6e3dae 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -201,7 +201,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) return result; } - auto str = Misc::getResolutionText(mode.w, mode.h, "%i × %i (%i:%i)"); + auto str = Misc::getResolutionText(mode.w, mode.h); result.append(QString(str.c_str())); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 70a067899a..1d638f56e9 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -85,17 +85,6 @@ namespace return MyGUI::LanguageManager::getInstance().replaceTags(result); } - void parseResolution(int& x, int& y, const std::string& str) - { - std::vector split; - Misc::StringUtils::split(str, split, "@(x"); - assert(split.size() >= 2); - Misc::StringUtils::trim(split[0]); - Misc::StringUtils::trim(split[1]); - x = MyGUI::utility::parseInt(split[0]); - y = MyGUI::utility::parseInt(split[1]); - } - bool sortResolutions(std::pair left, std::pair right) { if (left.first == right.first) @@ -368,10 +357,10 @@ namespace MWGui std::sort(resolutions.begin(), resolutions.end(), sortResolutions); for (std::pair& resolution : resolutions) { - std::string str = Misc::getResolutionText(resolution.first, resolution.second, "%i x %i (%i:%i)"); + std::string str = Misc::getResolutionText(resolution.first, resolution.second); if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) - mResolutionList->addItem(str); + mResolutionList->addItem(str, resolution); } highlightCurrentResolution(); @@ -493,14 +482,14 @@ namespace MWGui void SettingsWindow::onResolutionAccept() { - const std::string& resStr = mResolutionList->getItemNameAt(mResolutionList->getIndexSelected()); - int resX, resY; - parseResolution(resX, resY, resStr); + auto resultion = mResolutionList->getItemDataAt>(mResolutionList->getIndexSelected()); + if (resultion) + { + Settings::video().mResolutionX.set(resultion->first); + Settings::video().mResolutionY.set(resultion->second); - Settings::video().mResolutionX.set(resX); - Settings::video().mResolutionY.set(resY); - - apply(); + apply(); + } } void SettingsWindow::onResolutionCancel() @@ -517,10 +506,8 @@ namespace MWGui for (size_t i = 0; i < mResolutionList->getItemCount(); ++i) { - int resX, resY; - parseResolution(resX, resY, mResolutionList->getItemNameAt(i)); - - if (resX == currentX && resY == currentY) + auto resultion = mResolutionList->getItemDataAt>(i); + if (resultion && resultion->first == currentX && resultion->second == currentY) { mResolutionList->setIndexSelected(i); break; @@ -886,28 +873,31 @@ namespace MWGui // check if this resolution is supported in fullscreen if (mResolutionList->getIndexSelected() != MyGUI::ITEM_NONE) { - const std::string& resStr = mResolutionList->getItemNameAt(mResolutionList->getIndexSelected()); - int resX, resY; - parseResolution(resX, resY, resStr); - Settings::video().mResolutionX.set(resX); - Settings::video().mResolutionY.set(resY); + auto resultion + = mResolutionList->getItemDataAt>(mResolutionList->getIndexSelected()); + if (resultion) + { + Settings::video().mResolutionX.set(resultion->first); + Settings::video().mResolutionY.set(resultion->second); + } } bool supported = false; int fallbackX = 0, fallbackY = 0; for (size_t i = 0; i < mResolutionList->getItemCount(); ++i) { - const std::string& resStr = mResolutionList->getItemNameAt(i); - int resX, resY; - parseResolution(resX, resY, resStr); + auto resultion = mResolutionList->getItemDataAt>(i); + if (!resultion) + continue; if (i == 0) { - fallbackX = resX; - fallbackY = resY; + fallbackX = resultion->first; + fallbackY = resultion->second; } - if (resX == Settings::video().mResolutionX && resY == Settings::video().mResolutionY) + if (resultion->first == Settings::video().mResolutionX + && resultion->second == Settings::video().mResolutionY) supported = true; } diff --git a/components/misc/display.cpp b/components/misc/display.cpp index ee78b2a0c9..2a7c5a4688 100644 --- a/components/misc/display.cpp +++ b/components/misc/display.cpp @@ -1,13 +1,12 @@ #include "display.hpp" +#include #include #include -#include - namespace Misc { - std::string getResolutionText(int x, int y, const std::string& format) + std::string getResolutionText(int x, int y) { int gcd = std::gcd(x, y); if (gcd == 0) @@ -77,6 +76,6 @@ namespace Misc if (flipped) std::swap(xaspect, yaspect); - return Misc::StringUtils::format(format, x, y, xaspect, yaspect); + return std::format("{} × {} ({}:{})", x, y, xaspect, yaspect); } } diff --git a/components/misc/display.hpp b/components/misc/display.hpp index 82037661c8..6f60a48cda 100644 --- a/components/misc/display.hpp +++ b/components/misc/display.hpp @@ -5,7 +5,7 @@ namespace Misc { - std::string getResolutionText(int x, int y, const std::string& format); + std::string getResolutionText(int x, int y); } #endif From 44fe7038277fb334366b8c42bcd490f9a60eab7f Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 16:05:41 +0200 Subject: [PATCH 08/11] Use correct string types in SettingsWindow --- apps/openmw/mwgui/settingswindow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 1d638f56e9..749b68a874 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -46,7 +46,7 @@ namespace { - std::string textureFilteringToStr(const std::string& mipFilter, const std::string& magFilter) + std::string_view textureFilteringToStr(const std::string& mipFilter, const std::string& magFilter) { if (mipFilter == "none") return "#{OMWEngine:TextureFilteringDisabled}"; @@ -65,9 +65,9 @@ namespace return "#{OMWEngine:TextureFilteringOther}"; } - std::string lightingMethodToStr(SceneUtil::LightingMethod method) + MyGUI::UString lightingMethodToStr(SceneUtil::LightingMethod method) { - std::string result; + std::string_view result; switch (method) { case SceneUtil::LightingMethod::FFP: @@ -82,7 +82,7 @@ namespace break; } - return MyGUI::LanguageManager::getInstance().replaceTags(result); + return MyGUI::LanguageManager::getInstance().replaceTags(MyGUI::UString(result)); } bool sortResolutions(std::pair left, std::pair right) @@ -840,7 +840,7 @@ namespace MWGui void SettingsWindow::updateLightSettings() { auto lightingMethod = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getLightingMethod(); - std::string lightingMethodStr = lightingMethodToStr(lightingMethod); + MyGUI::UString lightingMethodStr = lightingMethodToStr(lightingMethod); mLightingMethodButton->removeAllItems(); From e97542a487688784ea88e4c5e798ac05759235b5 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 24 Aug 2025 16:11:34 +0200 Subject: [PATCH 09/11] Fix include --- components/lua/inputactions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lua/inputactions.cpp b/components/lua/inputactions.cpp index 5570824394..71e2263bd4 100644 --- a/components/lua/inputactions.cpp +++ b/components/lua/inputactions.cpp @@ -1,10 +1,10 @@ #include "inputactions.hpp" +#include #include #include #include -#include #include "luastate.hpp" From 79a1f1c3d2379ac0ca0d07e4e0fc2fec12db673a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 25 Aug 2025 16:46:04 +0200 Subject: [PATCH 10/11] Address feedback --- apps/openmw/mwgui/settingswindow.cpp | 32 ++++++++++++------------- components/lua/inputactions.cpp | 26 ++++++++++++-------- components/sceneutil/animblendrules.cpp | 4 ++-- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 749b68a874..8a609f6bb7 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -482,11 +482,11 @@ namespace MWGui void SettingsWindow::onResolutionAccept() { - auto resultion = mResolutionList->getItemDataAt>(mResolutionList->getIndexSelected()); - if (resultion) + auto resolution = mResolutionList->getItemDataAt>(mResolutionList->getIndexSelected()); + if (resolution) { - Settings::video().mResolutionX.set(resultion->first); - Settings::video().mResolutionY.set(resultion->second); + Settings::video().mResolutionX.set(resolution->first); + Settings::video().mResolutionY.set(resolution->second); apply(); } @@ -506,8 +506,8 @@ namespace MWGui for (size_t i = 0; i < mResolutionList->getItemCount(); ++i) { - auto resultion = mResolutionList->getItemDataAt>(i); - if (resultion && resultion->first == currentX && resultion->second == currentY) + auto resolution = mResolutionList->getItemDataAt>(i); + if (resolution && resolution->first == currentX && resolution->second == currentY) { mResolutionList->setIndexSelected(i); break; @@ -873,12 +873,12 @@ namespace MWGui // check if this resolution is supported in fullscreen if (mResolutionList->getIndexSelected() != MyGUI::ITEM_NONE) { - auto resultion + auto resolution = mResolutionList->getItemDataAt>(mResolutionList->getIndexSelected()); - if (resultion) + if (resolution) { - Settings::video().mResolutionX.set(resultion->first); - Settings::video().mResolutionY.set(resultion->second); + Settings::video().mResolutionX.set(resolution->first); + Settings::video().mResolutionY.set(resolution->second); } } @@ -886,18 +886,18 @@ namespace MWGui int fallbackX = 0, fallbackY = 0; for (size_t i = 0; i < mResolutionList->getItemCount(); ++i) { - auto resultion = mResolutionList->getItemDataAt>(i); - if (!resultion) + auto resolution = mResolutionList->getItemDataAt>(i); + if (!resolution) continue; if (i == 0) { - fallbackX = resultion->first; - fallbackY = resultion->second; + fallbackX = resolution->first; + fallbackY = resolution->second; } - if (resultion->first == Settings::video().mResolutionX - && resultion->second == Settings::video().mResolutionY) + if (resolution->first == Settings::video().mResolutionX + && resolution->second == Settings::video().mResolutionY) supported = true; } diff --git a/components/lua/inputactions.cpp b/components/lua/inputactions.cpp index 71e2263bd4..c220bdf331 100644 --- a/components/lua/inputactions.cpp +++ b/components/lua/inputactions.cpp @@ -1,6 +1,5 @@ #include "inputactions.hpp" -#include #include #include @@ -116,14 +115,14 @@ namespace LuaUtil void Registry::insert(const Info& info) { if (mIds.find(info.mKey) != mIds.end()) - throw std::domain_error(std::format("Action key \"{}\" is already in use", info.mKey)); + throw std::domain_error("Action key \"" + info.mKey + "\" is already in use"); if (info.mKey.empty()) throw std::domain_error("Action key can't be an empty string"); if (info.mL10n.empty()) throw std::domain_error("Localization context can't be empty"); if (!validateActionValue(info.mDefaultValue, info.mType)) - throw std::logic_error(std::format( - "Invalid value: \"{}\" for action \"{}\"", LuaUtil::toString(info.mDefaultValue), info.mKey)); + throw std::logic_error("Invalid value: \"" + LuaUtil::toString(info.mDefaultValue) + "\" for action \"" + + info.mKey + "\""); Id id = mBindingTree.insert(); mKeys.push_back(info.mKey); mIds[std::string(info.mKey)] = id; @@ -156,7 +155,7 @@ namespace LuaUtil { auto iter = mIds.find(key); if (iter == mIds.end()) - throw std::logic_error(std::format("Unknown action key: \"{}\"", key)); + throw std::logic_error("Unknown action key: \"" + std::string(key) + "\""); return iter->second; } @@ -182,9 +181,16 @@ namespace LuaUtil Id id = safeIdByKey(key); Info info = mInfo[id]; if (info.mType != type) - throw std::logic_error( - std::format("Attempt to get value of type \"{}\" from action \"{}\" with type \"{}\"", - typeName(type), key, typeName(info.mType))); + { + std::string message("Attempt to get value of type \""); + message += typeName(type); + message += "\" from action \""; + message += key; + message += "\" with type \""; + message += typeName(info.mType); + message += "\""; + throw std::logic_error(message); + } return mValues[id]; } @@ -269,14 +275,14 @@ namespace LuaUtil { auto it = mIds.find(key); if (it == mIds.end()) - throw std::domain_error(std::format("Unknown trigger key \"{}\"", key)); + throw std::domain_error("Unknown trigger key \"" + std::string(key) + "\""); return it->second; } void Registry::insert(const Info& info) { if (mIds.find(info.mKey) != mIds.end()) - throw std::domain_error(std::format("Trigger key \"{}\" is already in use", info.mKey)); + throw std::domain_error("Trigger key \"" + info.mKey + "\" is already in use"); if (info.mKey.empty()) throw std::domain_error("Trigger key can't be an empty string"); if (info.mL10n.empty()) diff --git a/components/sceneutil/animblendrules.cpp b/components/sceneutil/animblendrules.cpp index 2702584e63..a67de075b2 100644 --- a/components/sceneutil/animblendrules.cpp +++ b/components/sceneutil/animblendrules.cpp @@ -1,6 +1,5 @@ #include "animblendrules.hpp" -#include #include #include @@ -103,7 +102,8 @@ namespace SceneUtil } else { - throw std::domain_error(std::format("'blending_rules' object not found in '{}' file!", configPath.value())); + throw std::domain_error( + "'blending_rules' object not found in '" + std::string(configPath.value()) + "' file!"); } // If no rules then dont allocate any instance From e88e60f475e3c0b1c90df559b5c2aef3e1cd356a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 26 Aug 2025 18:08:38 +0200 Subject: [PATCH 11/11] Check length before dereferencing --- components/lua/configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lua/configuration.cpp b/components/lua/configuration.cpp index 3ca350e39b..cbec2e4abc 100644 --- a/components/lua/configuration.cpp +++ b/components/lua/configuration.cpp @@ -196,7 +196,7 @@ namespace LuaUtil throw std::runtime_error(std::format("No flags found in: {}", line)); std::string_view tagsStr = line.substr(0, semicolonPos); std::string_view scriptPath = line.substr(semicolonPos + 1); - while (isSpace(scriptPath[0])) + while (!scriptPath.empty() && isSpace(scriptPath[0])) scriptPath = scriptPath.substr(1); ESM::LuaScriptCfg& script = cfg.mScripts.emplace_back();