diff --git a/distribution/changelog.txt b/distribution/changelog.txt index dda93f4697..958368cfda 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -3,6 +3,7 @@ - Feature: [#22704] Rides can be made invisible more easily. - Improved: [#25941] The command line sprite build command is now faster. - Fix: [#25237] Wrong colours on the Knight costume. +- Fix: [#25910] Folders starting with numbers are sorted incorrectly (e.g. 1, 10, 2 instead of 1, 2, 10). 0.4.31 (2026-02-01) ------------------------------------------------------------------------ diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index a7983d83cd..8136cd6988 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -721,13 +721,8 @@ namespace OpenRCT2::String return escaped.str(); } - /* Case insensitive logical compare, produces the same output as Notepad++ lexicographical sort */ - // Example: - // - Guest 10 - // - Guest 99 - // - Guest 100 - // - John v2.0 - // - John v2.1 + // Case insensitive natural sort (numbers compared numerically). + // Strings starting with digits sort before alphabetic strings. int32_t logicalCmp(const char* s1, const char* s2) { const auto isDigit = [](char c) { return std::isdigit(static_cast(c)); }; @@ -737,30 +732,9 @@ namespace OpenRCT2::String bool s1StartsDigit = isDigit(*s1); bool s2StartsDigit = isDigit(*s2); if (s1StartsDigit && !s2StartsDigit) - { - return -1; // s1 (starts with digit) comes before s2 - } + return -1; if (!s1StartsDigit && s2StartsDigit) - { - return 1; // s2 (starts with digit) comes before s1 - } - - // If both start with digits, compare lexicographically - if (s1StartsDigit && s2StartsDigit) - { - while (*s1 != '\0' && *s2 != '\0') - { - char c1 = toUpper(*s1); - char c2 = toUpper(*s2); - if (c1 != c2) - { - return c1 - c2; - } - s1++; - s2++; - } - return *s1 == '\0' ? (*s2 == '\0' ? 0 : -1) : 1; - } + return 1; while (*s1 != '\0' && *s2 != '\0') { diff --git a/test/tests/StringTest.cpp b/test/tests/StringTest.cpp index 7a30610fd9..e97f86020c 100644 --- a/test/tests/StringTest.cpp +++ b/test/tests/StringTest.cpp @@ -255,10 +255,12 @@ TEST_F(CodepointViewTest, CodepointView_iterate) TEST_F(StringTest, LogicalCompare) { + // Strings starting with digits come first, sorted numerically + // Then alphabetic strings sorted case-insensitively std::vector expected = { - "1001 Troubles", "3D Cinema 1", "Aerial Cycles", "Batflyer", "bpb", - "bpb.sv6", "Drive-by", "foo", "foobar", "Guest 10", - "Guest 99", "Guest 100", "John v2.0", "John v2.1", "River of the Damned", + "3D Cinema 1", "1001 Troubles", "Aerial Cycles", "Batflyer", "bpb", + "bpb.sv6", "Drive-by", "foo", "foobar", "Guest 10", + "Guest 99", "Guest 100", "John v2.0", "John v2.1", "River of the Damned", "Terror-dactyl", };