summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/StardewModdingAPI.Tests/Core/ModResolverTests.cs6
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs49
-rw-r--r--src/StardewModdingAPI/Framework/Models/ModCompatibility.cs55
-rw-r--r--src/StardewModdingAPI/Framework/Models/ModDataRecord.cs30
-rw-r--r--src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs22
-rw-r--r--src/StardewModdingAPI/Program.cs2
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.config.json688
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
8 files changed, 526 insertions, 327 deletions
diff --git a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
index 4dbd1438..2d65eee9 100644
--- a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
+++ b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
@@ -141,7 +141,11 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
Mock<IModMetadata> mock = this.GetMetadata("Mod A", new string[0], allowStatusChange: true);
- this.SetupMetadataForValidation(mock, new ModDataRecord { Status = ModStatus.AssumeBroken, UpperVersion = new SemanticVersion("1.0"), UpdateUrls = new[] { "http://example.org" } });
+ this.SetupMetadataForValidation(mock, new ModDataRecord
+ {
+ Compatibility = new[] { new ModCompatibility("~1.0", ModStatus.AssumeBroken, null) },
+ UpdateUrls = new[] { "http://example.org" }
+ });
// act
new ModResolver().ValidateManifests(new[] { mock.Object }, apiVersion: new SemanticVersion("1.0"));
diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
index 3674faec..31ba5bc5 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
@@ -61,14 +61,7 @@ namespace StardewModdingAPI.Framework.ModLoading
string key = !string.IsNullOrWhiteSpace(manifest.UniqueID) ? manifest.UniqueID : manifest.EntryDll;
// get data record
- dataRecord = (
- from mod in dataRecords
- where
- mod.ID.Matches(key, manifest)
- && (mod.LowerVersion == null || !manifest.Version.IsOlderThan(mod.LowerVersion))
- && (mod.UpperVersion == null || !manifest.Version.IsNewerThan(mod.UpperVersion))
- select mod
- ).FirstOrDefault();
+ dataRecord = dataRecords.FirstOrDefault(record => record.ID.Matches(key, manifest));
}
// build metadata
@@ -98,28 +91,26 @@ namespace StardewModdingAPI.Framework.ModLoading
continue;
// validate compatibility
+ ModCompatibility compatibility = mod.DataRecord?.GetCompatibility(mod.Manifest.Version);
+ switch (compatibility?.Status)
{
- ModDataRecord dataRecord = mod.DataRecord;
- switch (dataRecord?.Status)
- {
- case ModStatus.Obsolete:
- mod.SetStatus(ModMetadataStatus.Failed, $"it's obsolete: {dataRecord.ReasonPhrase}");
- continue;
-
- case ModStatus.AssumeBroken:
- {
- string reasonPhrase = dataRecord.ReasonPhrase ?? "it's no longer compatible";
- string error = $"{reasonPhrase}. Please check for a ";
- if (mod.Manifest.Version.Equals(dataRecord.UpperVersion) && dataRecord.UpperVersionLabel == null)
- error += "newer version";
- else
- error += $"version newer than {dataRecord.UpperVersionLabel ?? dataRecord.UpperVersion.ToString()}";
- error += " at " + string.Join(" or ", dataRecord.UpdateUrls);
-
- mod.SetStatus(ModMetadataStatus.Failed, error);
- continue;
- }
- }
+ case ModStatus.Obsolete:
+ mod.SetStatus(ModMetadataStatus.Failed, $"it's obsolete: {compatibility.ReasonPhrase}");
+ continue;
+
+ case ModStatus.AssumeBroken:
+ {
+ string reasonPhrase = compatibility.ReasonPhrase ?? "it's no longer compatible";
+ string error = $"{reasonPhrase}. Please check for a ";
+ if (mod.Manifest.Version.Equals(compatibility.UpperVersion))
+ error += "newer version";
+ else
+ error += $"version newer than {compatibility.UpperVersion}";
+ error += " at " + string.Join(" or ", mod.DataRecord.UpdateUrls);
+
+ mod.SetStatus(ModMetadataStatus.Failed, error);
+ }
+ continue;
}
// validate SMAPI version
diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs
new file mode 100644
index 00000000..54737e6c
--- /dev/null
+++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace StardewModdingAPI.Framework.Models
+{
+ /// <summary>Specifies the compatibility of a given mod version range.</summary>
+ internal class ModCompatibility
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The lowest version in the range, or <c>null</c> for all past versions.</summary>
+ public ISemanticVersion LowerVersion { get; }
+
+ /// <summary>The highest version in the range, or <c>null</c> for all future versions.</summary>
+ public ISemanticVersion UpperVersion { get; }
+
+ /// <summary>The mod compatibility.</summary>
+ public ModStatus Status { get; }
+
+ /// <summary>The reason phrase to show in log output, or <c>null</c> to use the default value.</summary>
+ /// <example>For example, "this version is incompatible with the latest version of the game".</example>
+ public string ReasonPhrase { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="versionRange">A version range, which consists of two version strings separated by a '~' character. Either side can be left blank for an unbounded range.</param>
+ /// <param name="status">The mod compatibility.</param>
+ /// <param name="reasonPhrase">The reason phrase to show in log output, or <c>null</c> to use the default value.</param>
+ public ModCompatibility(string versionRange, ModStatus status, string reasonPhrase)
+ {
+ // extract version strings
+ string[] versions = versionRange.Split('~');
+ if (versions.Length != 2)
+ throw new FormatException($"Could not parse '{versionRange}' as a version range. It must have two version strings separated by a '~' character (either side can be left blank for an unbounded range).");
+
+ // initialise
+ this.LowerVersion = !string.IsNullOrWhiteSpace(versions[0]) ? new SemanticVersion(versions[0]) : null;
+ this.UpperVersion = !string.IsNullOrWhiteSpace(versions[1]) ? new SemanticVersion(versions[1]) : null;
+ this.Status = status;
+ this.ReasonPhrase = reasonPhrase;
+ }
+
+ /// <summary>Get whether a given version is contained within this compatibility range.</summary>
+ /// <param name="version">The version to check.</param>
+ public bool MatchesVersion(ISemanticVersion version)
+ {
+ return
+ (this.LowerVersion == null || !version.IsOlderThan(this.LowerVersion))
+ && (this.UpperVersion == null || !version.IsNewerThan(this.UpperVersion));
+ }
+ }
+}
diff --git a/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs b/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs
index 8126022d..de219076 100644
--- a/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs
+++ b/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs
@@ -1,3 +1,4 @@
+using System.Linq;
using Newtonsoft.Json;
using StardewModdingAPI.Framework.Serialisation;
@@ -16,25 +17,22 @@ namespace StardewModdingAPI.Framework.Models
/// <summary>The mod name.</summary>
public string Name { get; set; }
- /// <summary>The oldest incompatible mod version, or <c>null</c> for all past versions.</summary>
- [JsonConverter(typeof(SFieldConverter))]
- public ISemanticVersion LowerVersion { get; set; }
-
- /// <summary>The most recent incompatible mod version.</summary>
- [JsonConverter(typeof(SFieldConverter))]
- public ISemanticVersion UpperVersion { get; set; }
-
- /// <summary>A label to show to the user instead of <see cref="UpperVersion"/>, when the manifest version differs from the user-facing version.</summary>
- public string UpperVersionLabel { get; set; }
-
/// <summary>The URLs the user can check for a newer version.</summary>
public string[] UpdateUrls { get; set; }
- /// <summary>The reason phrase to show in the warning, or <c>null</c> to use the default value.</summary>
- /// <example>"this version is incompatible with the latest version of the game"</example>
- public string ReasonPhrase { get; set; }
+ /// <summary>The compatibility of given mod versions (if any).</summary>
+ [JsonConverter(typeof(SFieldConverter))]
+ public ModCompatibility[] Compatibility { get; set; } = new ModCompatibility[0];
+
- /// <summary>Indicates how SMAPI should treat the mod.</summary>
- public ModStatus Status { get; set; } = ModStatus.AssumeBroken;
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Get the compatibility record for a given version, if any.</summary>
+ /// <param name="version">The mod version to check.</param>
+ public ModCompatibility GetCompatibility(ISemanticVersion version)
+ {
+ return this.Compatibility.FirstOrDefault(p => p.MatchesVersion(version));
+ }
}
}
diff --git a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs
index d71e138b..ffece081 100644
--- a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs
+++ b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs
@@ -27,7 +27,8 @@ namespace StardewModdingAPI.Framework.Serialisation
return
objectType == typeof(ISemanticVersion)
|| objectType == typeof(IManifestDependency[])
- || objectType == typeof(ModDataID);
+ || objectType == typeof(ModDataID)
+ || objectType == typeof(ModCompatibility[]);
}
/// <summary>Reads the JSON representation of the object.</summary>
@@ -68,7 +69,7 @@ namespace StardewModdingAPI.Framework.Serialisation
}
}
- // manifest dependency
+ // manifest dependencies
if (objectType == typeof(IManifestDependency[]))
{
List<IManifestDependency> result = new List<IManifestDependency>();
@@ -82,13 +83,28 @@ namespace StardewModdingAPI.Framework.Serialisation
return result.ToArray();
}
- // mod compatibility ID
+ // mod data ID
if (objectType == typeof(ModDataID))
{
JToken token = JToken.Load(reader);
return new ModDataID(token.Value<string>());
}
+ // mod compatibility records
+ if (objectType == typeof(ModCompatibility[]))
+ {
+ List<ModCompatibility> result = new List<ModCompatibility>();
+ foreach (JProperty property in JObject.Load(reader).Properties())
+ {
+ string range = property.Name;
+ ModStatus status = property.Value.Value<ModStatus>(nameof(ModCompatibility.Status));
+ string reasonPhrase = property.Value.Value<string>(nameof(ModCompatibility.ReasonPhrase));
+
+ result.Add(new ModCompatibility(range, status, reasonPhrase));
+ }
+ return result.ToArray();
+ }
+
// unknown
throw new NotSupportedException($"Unknown type '{objectType?.FullName}'.");
}
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index 63176dd1..4860968c 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -640,7 +640,7 @@ namespace StardewModdingAPI
Assembly modAssembly;
try
{
- modAssembly = modAssemblyLoader.Load(metadata, assemblyPath, assumeCompatible: metadata.DataRecord?.Status == ModStatus.AssumeCompatible);
+ modAssembly = modAssemblyLoader.Load(metadata, assemblyPath, assumeCompatible: metadata.DataRecord.GetCompatibility(metadata.Manifest.Version)?.Status == ModStatus.AssumeCompatible);
}
catch (IncompatibleInstructionException ex)
{
diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json
index c93ba130..3844b8b0 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.config.json
+++ b/src/StardewModdingAPI/StardewModdingAPI.config.json
@@ -48,958 +48,1092 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha
{
"Name": "AccessChestAnywhere",
"ID": "AccessChestAnywhere",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/257", "http://www.nexusmods.com/stardewvalley/mods/518" ],
- "Notes": "Broke in SDV 1.1."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SDV 1.1
+ }
},
{
"Name": "AdjustArtisanPrices",
"ID": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc",
- "UpperVersion": "0.0",
- "UpperVersionLabel": "0.01",
"UpdateUrls": [ "http://community.playstarbound.com/resources/3532", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 1.9."
+ "Compatibility": {
+ "~0.01": { "Status": "AssumeBroken" } // broke in SMAPI 1.9
+ }
},
{
"Name": "Advanced Location Loader",
"ID": "Entoarox.AdvancedLocationLoader",
- "UpperVersion": "1.2.10",
"UpdateUrls": [ "http://community.playstarbound.com/resources/3619" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.2.10": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "AgingMod",
"ID": "skn.AgingMod",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1129", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Almighty Tool",
"ID": "AlmightyTool.dll",
- "UpperVersion": "1.1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/439" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.1.1": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Animal Mood Fix",
"ID": "GPeters-AnimalMoodFix",
- "Status": "Obsolete",
- "ReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
+ "Compatibility": {
+ "~": { "Status": "Obsolete", "ReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2." }
+ }
},
{
"Name": "Animal Sitter",
"ID": "AnimalSitter.dll",
- "UpperVersion": "1.0.8",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/581", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.8": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "A Tapper's Dream",
"ID": "ddde5195-8f85-4061-90cc-0d4fd5459358",
- "UpperVersion": "1.4",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/260", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.4": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Better Sprinklers",
"ID": "SPDSprinklersMod | Speeder.BetterSprinklers", // changed in 2.3
- "UpperVersion": "2.3.1-pathoschild-update",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/41", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~2.3.1-pathoschild-update": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Birthday Mail",
"ID": "005e02dc-d900-425c-9c68-1ff55c5a295d",
- "UpperVersion": "1.2.2",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/276", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.2.2": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Build Endurance",
"ID": "{ID:'4be88c18-b6f3-49b0-ba96-f94b1a5be890', Name:'BuildEndurance'}", // disambiguate from other Alpha_Omegasis mods
- "UpperVersion": "1.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/445", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Build Health",
"ID": "{ID:'4be88c18-b6f3-49b0-ba96-f94b1a5be890', Name:'BuildHealth'}", // disambiguate from other Alpha_Omegasis mods
- "UpperVersion": "1.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/446", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Buy Cooking Recipes",
"ID": "Denifia.BuyRecipes",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1126", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Buy Back Collectables",
"ID": "BuyBackCollectables",
- "UpperVersion": "1.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/507", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Chest Label System",
"ID": "SPDChestLabel",
- "UpperVersion": "1.6",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/242", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.1."
+ "Compatibility": {
+ "~1.6": { "Status": "AssumeBroken" } // broke in SDV 1.1
+ }
},
{
"Name": "Chest Pooling",
"ID": "ChestPooling.dll",
- "UpperVersion": "1.2",
"UpdateUrls": [ "http://community.playstarbound.com/threads/111988" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.2": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Chests Anywhere",
"ID": "ChestsAnywhere | Pathoschild.ChestsAnywhere", // changed in 1.9
- "UpperVersion": "1.9-beta",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/518" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.9-beta": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Choose Baby Gender",
"ID": "ChooseBabyGender.dll",
- "UpperVersion": "1.0.2",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/590", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.2": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "CJB Automation",
"ID": "CJBAutomation",
- "UpperVersion": "1.4",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/211", "http://www.nexusmods.com/stardewvalley/mods/1063" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.4": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "CJB Cheats Menu",
"ID": "CJBCheatsMenu",
- "UpperVersion": "1.12",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/4" ],
- "Notes": "Broke in SDV 1.1."
+ "Compatibility": {
+ "~1.12": { "Status": "AssumeBroken" } // broke in SDV 1.1
+ }
},
{
"Name": "CJB Item Spawner",
"ID": "CJBItemSpawner",
- "UpperVersion": "1.5",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/93" ],
- "Notes": "Broke in SDV 1.1."
+ "Compatibility": {
+ "~1.5": { "Status": "AssumeBroken" } // broke in SDV 1.1
+ }
},
{
"Name": "CJB Show Item Sell Price",
"ID": "CJBShowItemSellPrice",
- "UpperVersion": "1.6",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/93" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.6": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Climates of Ferngill",
"ID": "KoihimeNakamura.ClimatesOfFerngill",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/604", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Cold Weather Haley",
"ID": "LordXamon.ColdWeatherHaleyPRO",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1169", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Colored Chests",
"ID": "4befde5c-731c-4853-8e4b-c5cdf946805f",
- "Status": "Obsolete",
- "ReasonPhrase": "colored chests were added in Stardew Valley 1.1."
+ "Compatibility": {
+ "~": { "Status": "Obsolete", "ReasonPhrase": "colored chests were added in Stardew Valley 1.1." }
+ }
},
{
"Name": "Combat with Farm Implements",
"ID": "SPDFarmingImplementsInCombat",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/313", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Configurable Shipping Dates",
"ID": "ConfigurableShippingDates",
- "UpperVersion": "1.1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/675", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Cooking Skill",
"ID": "CookingSkill | spacechase0.CookingSkill", // changed in 1.0.4–6
- "UpperVersion": "1.0.6",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/522" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.6": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "CrabNet",
"ID": "CrabNet.dll",
- "UpperVersion": "1.0.4",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/584", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.4": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Customize Exterior",
"ID": "CustomizeExterior",
- "UpperVersion": "1.0.2",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1099" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.2": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Customizable Traveling Cart Days",
"ID": "TravelingCartYyeahdude",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/567", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Daily News",
"ID": "bashNinja.DailyNews",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1141", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Dynamic Checklist",
"ID": "gunnargolf.DynamicChecklist",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1145", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Dynamic Machines",
"ID": "DynamicMachines",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/374", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Empty Hands",
"ID": "QuicksilverFox.EmptyHands",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1176", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Enemy Health Bars",
"ID": "SPDHealthBar",
- "UpperVersion": "1.7",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/193", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.7": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Entoarox Framework",
"ID": "eacdb74b-4080-4452-b16b-93773cda5cf9 | Entoarox.EntoaroxFramework", // changed in ???
- "UpperVersion": "1.7.9",
"UpdateUrls": [ "http://community.playstarbound.com/resources/4228" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.7.9": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Extended Fridge",
"ID": "Mystra007ExtendedFridge",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/485", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Extended Greenhouse",
"ID": "ExtendedGreenhouse",
- "UpperVersion": "1.0.2",
"UpdateUrls": [ "http://community.playstarbound.com/resources/4303", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.0.2": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Fall 28 Snow Day",
"ID": "{ID:'7ad4f6f7-c3de-4729-a40f-7a11d2b2a358', Name:'Fall28 Snow Day'}", // disambiguate from other mods by Alpha_Omegasis
- "UpperVersion": "1.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/486", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Farm Automation: Barn Door Automation",
"ID": "FarmAutomation.BarnDoorAutomation.dll",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://community.playstarbound.com/threads/111931", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Farm Automation: Item Collector",
"ID": "FarmAutomation.ItemCollector.dll",
- "UpperVersion": "1.0",
"UpdateUrls": [ "http://community.playstarbound.com/threads/111931", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.0": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Farm Automation Unofficial: Item Collector",
"ID": "Maddy99.FarmAutomation.ItemCollector",
- "UpperVersion": "0.5",
"UpdateUrls": [ "http://community.playstarbound.com/threads/125172", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~0.5": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Farm Expansion",
"ID": "3888bdfd-73f6-4776-8bb7-8ad45aea1915 | AdvizeFarmExpansionMod-2-0 | AdvizeFarmExpansionMod-2-0-5", // changed in 2.0 and 2.0.5
- "UpperVersion": "2.0.5",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/130", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~2.0.5": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Farm Resource Generator",
"ID": "FarmResourceGenerator.dll",
- "UpperVersion": "1.0.4",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/647", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.4": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Faster Run",
"ID": "FasterRun.dll",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/733", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "FlorenceMod",
"ID": "FlorenceMod.dll",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/591", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Forage at the Farm",
"ID": "ForageAtTheFarm",
- "UpperVersion": "1.5.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/673", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.5.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Instant Geode",
"ID": "InstantGeode",
- "UpperVersion": "1.12",
"UpdateUrls": [ "http://community.playstarbound.com/threads/109038", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.12": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Gate Opener",
"ID": "GateOpener.dll | mralbobo.GateOpener", // changed in 1.1
- "UpperVersion": "1.0.1",
"UpdateUrls": [ "http://community.playstarbound.com/threads/111988" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~1.0.1": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "GenericShopExtender",
"ID": "GenericShopExtender",
- "UpperVersion": "0.1.2",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/814", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~0.1.2": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Get Dressed",
"ID": "GetDressed.dll | Advize.GetDressed", // changed in 3.3
- "UpperVersion": "3.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/331" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~3.3": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Gift Taste Helper",
"ID": "8008db57-fa67-4730-978e-34b37ef191d6",
- "UpperVersion": "2.3.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/229" ],
- "Notes": "Broke in SDV 1.2."
+ "Compatibility": {
+ "~2.3.1": { "Status": "AssumeBroken" } // broke in SDV 1.2
+ }
},
{
"Name": "Happy Animals",
"ID": "HappyAnimals",
- "UpperVersion": "1.0.3",
"UpdateUrls": [ "https://community.playstarbound.com/threads/126655", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Happy Birthday",
"ID": "{ID:'HappyBirthday', Author:'Alpha_Omegasis'}", // disambiguate from Oxyligen's fork
- "UpperVersion": "1.3",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/520", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.3": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Harvest With Scythe",
"ID": "965169fd-e1ed-47d0-9f12-b104535fb4bc",
- "UpperVersion": "1.0.6",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/236", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.0.6": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Hunger for Food",
"ID": "HungerForFoodByTigerle",
- "UpperVersion": "0.1.2",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/810", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~0.1.2": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Improved Quality of Life",
"ID": "Demiacle.ImprovedQualityOfLife",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/1025", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Less Strict Over-Exertion (AntiExhaustion)",
"ID": "BALANCEMOD_AntiExhaustion",
- "UpperVersion": "1.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/637", "http://stardewvalleywiki.com/Modding:SMAPI_2.0" ],
- "Notes": "Broke in SMAPI 2.0."
+ "Compatibility": {
+ "~1.1": { "Status": "AssumeBroken" } // broke in SMAPI 2.0
+ }
},
{
"Name": "Lookup Anything",
"ID": "LookupAnything | Pathoschild.LookupAnything", // changed in 1.10.1
- "UpperVersion": "1.10.1",
"UpdateUrls": [ "http://www.nexusmods.com/stardewvalley/mods/541" ],
-