summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-01-14 00:04:31 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-01-15 18:21:28 -0500
commitde789fb3e8f344a09032c23f56e800717ea801a0 (patch)
tree703082118fe8ae9f198e00e4d74908cbcc312150
parentd31370b1d702511fd2d08c66a1f58aac5d454edd (diff)
downloadSMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.tar.gz
SMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.tar.bz2
SMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.zip
fix semantic version comparison returning wrong value in rare cases
-rw-r--r--docs/release-notes.md2
-rw-r--r--src/SMAPI.Toolkit/SemanticVersion.cs80
2 files changed, 51 insertions, 31 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index f4f65653..0d8fc0ac 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -11,6 +11,8 @@
* For players:
* Fixed issue where title screen music didn't stop after loading a save.
+* For modders:
+ * Fixed `SemanticVersion` comparisons returning wrong value in rare cases.
## 3.8.3
Released 08 January 2021 for Stardew Valley 1.5.2 or later.
diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs
index 0f341665..d58dce0c 100644
--- a/src/SMAPI.Toolkit/SemanticVersion.cs
+++ b/src/SMAPI.Toolkit/SemanticVersion.cs
@@ -230,38 +230,49 @@ namespace StardewModdingAPI.Toolkit
const int curNewer = 1;
const int curOlder = -1;
- // compare stable versions
- if (this.MajorVersion != otherMajor)
- return this.MajorVersion.CompareTo(otherMajor);
- if (this.MinorVersion != otherMinor)
- return this.MinorVersion.CompareTo(otherMinor);
- if (this.PatchVersion != otherPatch)
- return this.PatchVersion.CompareTo(otherPatch);
- if (this.PlatformRelease != otherPlatformRelease)
- return this.PlatformRelease.CompareTo(otherPlatformRelease);
- if (this.PrereleaseTag == otherTag)
- return same;
-
- // stable supersedes prerelease
- bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag);
- bool otherIsStable = string.IsNullOrWhiteSpace(otherTag);
- if (curIsStable)
- return curNewer;
- if (otherIsStable)
- return curOlder;
-
- // compare two prerelease tag values
- string[] curParts = this.PrereleaseTag.Split('.', '-');
- string[] otherParts = otherTag.Split('.', '-');
- for (int i = 0; i < curParts.Length; i++)
+ int CompareToRaw()
{
- // longer prerelease tag supersedes if otherwise equal
- if (otherParts.Length <= i)
+ // compare stable versions
+ if (this.MajorVersion != otherMajor)
+ return this.MajorVersion.CompareTo(otherMajor);
+ if (this.MinorVersion != otherMinor)
+ return this.MinorVersion.CompareTo(otherMinor);
+ if (this.PatchVersion != otherPatch)
+ return this.PatchVersion.CompareTo(otherPatch);
+ if (this.PlatformRelease != otherPlatformRelease)
+ return this.PlatformRelease.CompareTo(otherPlatformRelease);
+ if (this.PrereleaseTag == otherTag)
+ return same;
+
+ // stable supersedes prerelease
+ bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag);
+ bool otherIsStable = string.IsNullOrWhiteSpace(otherTag);
+ if (curIsStable)
return curNewer;
-
- // compare if different
- if (curParts[i] != otherParts[i])
+ if (otherIsStable)
+ return curOlder;
+
+ // compare two prerelease tag values
+ string[] curParts = this.PrereleaseTag.Split('.', '-');
+ string[] otherParts = otherTag.Split('.', '-');
+ int length = Math.Max(curParts.Length, otherParts.Length);
+ for (int i = 0; i < length; i++)
{
+ // longer prerelease tag supersedes if otherwise equal
+ if (curParts.Length <= i)
+ return curOlder;
+ if (otherParts.Length <= i)
+ return curNewer;
+
+ // skip if same value, unless we've reached the end
+ if (curParts[i] == otherParts[i])
+ {
+ if (i == length - 1)
+ return same;
+
+ continue;
+ }
+
// unofficial is always lower-precedence
if (otherParts[i].Equals("unofficial", StringComparison.OrdinalIgnoreCase))
return curNewer;
@@ -277,10 +288,17 @@ namespace StardewModdingAPI.Toolkit
// else compare lexically
return string.Compare(curParts[i], otherParts[i], StringComparison.OrdinalIgnoreCase);
}
+
+ // fallback (this should never happen)
+ return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase);
}
- // fallback (this should never happen)
- return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase);
+ return CompareToRaw() switch
+ {
+ (< 0) => curOlder,
+ (> 0) => curNewer,
+ _ => same
+ };
}
/// <summary>Assert that the current version is valid.</summary>