-
This page shows all known SMAPI mods and (incompatible) content packs, whether they work with the latest versions of Stardew Valley and SMAPI, and how to fix them if not. If a mod doesn't work after following the instructions below, check the troubleshooting guide or ask for help.
-
-
The list is updated every few days (you can help update it!). It doesn't include XNB mods (see using XNB mods on the wiki instead) or compatible content packs.
-
- @if (Model.BetaVersion != null)
- {
-
Note: "SDV beta only" means Stardew Valley @Model.BetaVersion-beta; if you didn't opt in to the beta, you have the stable version and can ignore that line. If a mod doesn't have a "SDV beta only" line, the compatibility applies to both versions of the game.
- }
-
-
+
+
This page shows all known SMAPI mods and (incompatible) content packs, whether they work with the latest versions of Stardew Valley and SMAPI, and how to fix them if not. If a mod doesn't work after following the instructions below, check the troubleshooting guide or ask for help.
+
+
The list is updated every few days (you can help update it!). It doesn't include XNB mods (see using XNB mods on the wiki instead) or compatible content packs.
+
+ @if (Model.BetaVersion != null)
+ {
+
Note: "SDV @Model.BetaVersion only" lines are for an unreleased version of the game, not the stable version most players have. If a mod doesn't have that line, the info applies to both versions of the game.
+ }
+
+
@@ -47,8 +47,7 @@
- {{visibleStats.total}} mods shown ({{Math.round((visibleStats.compatible + visibleStats.workaround) / visibleStats.total * 100)}}% compatible or have a workaround, {{Math.round((visibleStats.soon + visibleStats.broken) / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.abandoned / visibleStats.total * 100)}}% obsolete).
- SMAPI 3.0 (upcoming): {{Math.round(visibleStats.smapi3_ok / visibleStats.total * 100)}}% ready, {{Math.round(visibleStats.smapi3_soon / visibleStats.total * 100)}}% soon, {{Math.round(visibleStats.smapi3_broken / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.smapi3_unknown / visibleStats.total * 100)}}% unknown.
+ {{visibleStats.total}} mods shown ({{Math.round((visibleStats.compatible + visibleStats.workaround) / visibleStats.total * 100)}}% compatible or have a workaround, {{Math.round((visibleStats.soon + visibleStats.broken) / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.abandoned / visibleStats.total * 100)}}% obsolete).
No matching mods found.
@@ -61,12 +60,11 @@
compatibility |
broke in |
code |
-
3.0 ready |
|
-
+
{{mod.Name}}
(aka {{mod.AlternateNames}})
@@ -82,8 +80,8 @@
|
-
- SDV beta only:
+
+ SDV @Model.BetaVersion only:
⚠ {{warning}}
@@ -93,12 +91,6 @@
source
no source
|
-
-
- {{mod.Smapi3DisplayText}}
- {{mod.Smapi3DisplayText}}
-
- |
#
|
diff --git a/src/SMAPI.Web/appsettings.Development.json b/src/SMAPI.Web/appsettings.Development.json
index db90a3de..49234a3b 100644
--- a/src/SMAPI.Web/appsettings.Development.json
+++ b/src/SMAPI.Web/appsettings.Development.json
@@ -8,28 +8,28 @@
*/
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Debug",
- "System": "Information",
- "Microsoft": "Information"
+ "Logging": {
+ "IncludeScopes": false,
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+
+ "Site": {
+ "RootUrl": "http://localhost:59482/",
+ "ModListUrl": "http://localhost:59482/mods/",
+ "LogParserUrl": "http://localhost:59482/log/",
+ "BetaEnabled": false,
+ "BetaBlurb": null
+ },
+
+ "ApiClients": {
+ "GitHubUsername": null,
+ "GitHubPassword": null,
+
+ "PastebinUserKey": null,
+ "PastebinDevKey": null
}
- },
-
- "Site": {
- "RootUrl": "http://localhost:59482/",
- "ModListUrl": "http://localhost:59482/mods/",
- "LogParserUrl": "http://localhost:59482/log/",
- "BetaEnabled": false,
- "BetaBlurb": null
- },
-
- "ApiClients": {
- "GitHubUsername": null,
- "GitHubPassword": null,
-
- "PastebinUserKey": null,
- "PastebinDevKey": null
- }
}
diff --git a/src/SMAPI.Web/appsettings.json b/src/SMAPI.Web/appsettings.json
index e97b2339..9e15aa97 100644
--- a/src/SMAPI.Web/appsettings.json
+++ b/src/SMAPI.Web/appsettings.json
@@ -7,54 +7,54 @@
*/
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
+ "Logging": {
+ "IncludeScopes": false,
+ "LogLevel": {
+ "Default": "Warning"
+ }
+ },
+
+ "Site": {
+ "RootUrl": null, // see top note
+ "ModListUrl": null, // see top note
+ "LogParserUrl": null, // see top note
+ "BetaEnabled": null, // see top note
+ "BetaBlurb": null // see top note
+ },
+
+ "ApiClients": {
+ "UserAgent": "SMAPI/{0} (+https://smapi.io)",
+
+ "ChucklefishBaseUrl": "https://community.playstarbound.com",
+ "ChucklefishModPageUrlFormat": "resources/{0}",
+
+ "GitHubBaseUrl": "https://api.github.com",
+ "GitHubStableReleaseUrlFormat": "repos/{0}/releases/latest",
+ "GitHubAnyReleaseUrlFormat": "repos/{0}/releases?per_page=2", // allow for draft release (only visible if GitHub repo is owned by same account as the update check credentials)
+ "GitHubAcceptHeader": "application/vnd.github.v3+json",
+ "GitHubUsername": null, // see top note
+ "GitHubPassword": null, // see top note
+
+ "ModDropApiUrl": "https://www.moddrop.com/api/mods/data",
+ "ModDropModPageUrl": "https://www.moddrop.com/sdv/mod/{0}",
+
+ "NexusBaseUrl": "https://www.nexusmods.com/stardewvalley/",
+ "NexusModUrlFormat": "mods/{0}",
+ "NexusModScrapeUrlFormat": "mods/{0}?tab=files",
+
+ "PastebinBaseUrl": "https://pastebin.com/",
+ "PastebinUserKey": null, // see top note
+ "PastebinDevKey": null // see top note
+ },
+
+ "ModCompatibilityList": {
+ "CacheMinutes": 10
+ },
+
+ "ModUpdateCheck": {
+ "SuccessCacheMinutes": 60,
+ "ErrorCacheMinutes": 5,
+ "SemanticVersionRegex": "^(?>(?0|[1-9]\\d*))\\.(?>(?0|[1-9]\\d*))(?>(?:\\.(?0|[1-9]\\d*))?)(?:-(?(?>[a-z0-9]+[\\-\\.]?)+))?$",
+ "CompatibilityPageUrl": "https://mods.smapi.io"
}
- },
-
- "Site": {
- "RootUrl": null, // see top note
- "ModListUrl": null, // see top note
- "LogParserUrl": null, // see top note
- "BetaEnabled": null, // see top note
- "BetaBlurb": null // see top note
- },
-
- "ApiClients": {
- "UserAgent": "SMAPI/{0} (+https://smapi.io)",
-
- "ChucklefishBaseUrl": "https://community.playstarbound.com",
- "ChucklefishModPageUrlFormat": "resources/{0}",
-
- "GitHubBaseUrl": "https://api.github.com",
- "GitHubStableReleaseUrlFormat": "repos/{0}/releases/latest",
- "GitHubAnyReleaseUrlFormat": "repos/{0}/releases?per_page=2", // allow for draft release (only visible if GitHub repo is owned by same account as the update check credentials)
- "GitHubAcceptHeader": "application/vnd.github.v3+json",
- "GitHubUsername": null, // see top note
- "GitHubPassword": null, // see top note
-
- "ModDropApiUrl": "https://www.moddrop.com/api/mods/data",
- "ModDropModPageUrl": "https://www.moddrop.com/sdv/mod/{0}",
-
- "NexusBaseUrl": "https://www.nexusmods.com/stardewvalley/",
- "NexusModUrlFormat": "mods/{0}",
- "NexusModScrapeUrlFormat": "mods/{0}?tab=files",
-
- "PastebinBaseUrl": "https://pastebin.com/",
- "PastebinUserKey": null, // see top note
- "PastebinDevKey": null // see top note
- },
-
- "ModCompatibilityList": {
- "WikiCacheMinutes": 10
- },
-
- "ModUpdateCheck": {
- "SuccessCacheMinutes": 60,
- "ErrorCacheMinutes": 5,
- "SemanticVersionRegex": "^(?>(?0|[1-9]\\d*))\\.(?>(?0|[1-9]\\d*))(?>(?:\\.(?0|[1-9]\\d*))?)(?:-(?(?>[a-z0-9]+[\\-\\.]?)+))?$",
- "CompatibilityPageUrl": "https://mods.smapi.io"
- }
}
diff --git a/src/SMAPI.Web/wwwroot/Content/css/index.css b/src/SMAPI.Web/wwwroot/Content/css/index.css
index 979af4af..93a85bed 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/index.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/index.css
@@ -106,7 +106,25 @@ h1 {
padding-left: 1em;
}
-#support-links li small {
- display: block;
- width: 50em;
+#donate-links li {
+ list-style: none;
+ margin-bottom: 5px;
+}
+
+#donate-links .donate-button {
+ display: inline-block;
+ min-width: 10em;
+ background: #2A413B;
+ padding: 6px 12px;
+ font-family: Quicksand, Helvetica, Century Gothic, sans-serif;
+ text-decoration: none;
+ font-weight: 700;
+ color: #FFF;
+ border-radius: 8px;
+}
+
+#donate-links .donate-button img {
+ vertical-align: middle;
+ max-height: 15px;
+ max-width: 15px;
}
diff --git a/src/SMAPI.Web/wwwroot/Content/images/ko-fi.png b/src/SMAPI.Web/wwwroot/Content/images/ko-fi.png
new file mode 100644
index 00000000..a483f452
Binary files /dev/null and b/src/SMAPI.Web/wwwroot/Content/images/ko-fi.png differ
diff --git a/src/SMAPI.Web/wwwroot/Content/images/patreon.png b/src/SMAPI.Web/wwwroot/Content/images/patreon.png
new file mode 100644
index 00000000..d589fedc
Binary files /dev/null and b/src/SMAPI.Web/wwwroot/Content/images/patreon.png differ
diff --git a/src/SMAPI.Web/wwwroot/Content/images/paypal.png b/src/SMAPI.Web/wwwroot/Content/images/paypal.png
new file mode 100644
index 00000000..225c9d7b
Binary files /dev/null and b/src/SMAPI.Web/wwwroot/Content/images/paypal.png differ
diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js
index 874fbf25..130f60be 100644
--- a/src/SMAPI.Web/wwwroot/Content/js/mods.js
+++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js
@@ -11,11 +11,7 @@ smapi.modList = function (mods, enableBeta) {
soon: 0,
broken: 0,
abandoned: 0,
- invalid: 0,
- smapi3_unknown: 0,
- smapi3_ok: 0,
- smapi3_broken: 0,
- smapi3_soon: 0
+ invalid: 0
};
var data = {
mods: mods,
@@ -52,16 +48,6 @@ smapi.modList = function (mods, enableBeta) {
nexus: { value: true, label: "Nexus" },
custom: { value: true }
}
- },
- smapi3: {
- label: "SMAPI 3.0",
- value: {
- // note: keys must match status returned by the API
- ok: { value: true, label: "ready" },
- soon: { value: true },
- broken: { value: true },
- unknown: { value: true }
- }
}
},
search: ""
@@ -87,8 +73,6 @@ smapi.modList = function (mods, enableBeta) {
else
delete data.filters.betaStatus;
- window.boop = data.filters;
-
// init mods
for (var i = 0; i < data.mods.length; i++) {
var mod = mods[i];
@@ -99,24 +83,6 @@ smapi.modList = function (mods, enableBeta) {
// set overall compatibility
mod.LatestCompatibility = mod.BetaCompatibility || mod.Compatibility;
- // set SMAPI 3.0 display text
- switch (mod.Smapi3Status) {
- case "ok":
- mod.Smapi3DisplayText = "✓ yes";
- mod.Smapi3Tooltip = "The latest version of this mod is compatible with SMAPI 3.0.";
- break;
-
- case "broken":
- mod.Smapi3DisplayText = "✖ no";
- mod.Smapi3Tooltip = "This mod will break in SMAPI 3.0; consider notifying the author.";
- break;
-
- default:
- mod.Smapi3DisplayText = "↻ " + mod.Smapi3Status;
- mod.Smapi3Tooltip = "This mod has a pending update for SMAPI 3.0 which hasn't been released yet.";
- break;
- }
-
// concatenate searchable text
mod.SearchableText = [mod.Name, mod.AlternateNames, mod.Author, mod.AlternateAuthors, mod.Compatibility.Summary, mod.BrokeIn];
if (mod.Compatibility.UnofficialVersion)
@@ -173,7 +139,6 @@ smapi.modList = function (mods, enableBeta) {
if (mod.Visible) {
stats.total++;
stats[this.getCompatibilityGroup(mod)]++;
- stats["smapi3_" + mod.Smapi3Status]++;
}
}
},
@@ -188,6 +153,10 @@ smapi.modList = function (mods, enableBeta) {
matchesFilters: function(mod, searchWords) {
var filters = data.filters;
+ // check hash
+ if (location.hash === "#" + mod.Slug)
+ return true;
+
// check source
if (!filters.source.value.open.value && mod.SourceUrl)
return false;
@@ -206,10 +175,6 @@ smapi.modList = function (mods, enableBeta) {
return false;
}
- // check SMAPI 3.0 compatibility
- if (filters.smapi3.value[mod.Smapi3Status] && !filters.smapi3.value[mod.Smapi3Status].value)
- return false;
-
// check download sites
var ignoreSites = [];
@@ -281,4 +246,7 @@ smapi.modList = function (mods, enableBeta) {
}
});
app.applyFilters();
+ window.addEventListener("hashchange", function () {
+ app.applyFilters();
+ });
};
diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json
index 9de692fe..d0c55552 100644
--- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json
+++ b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json
@@ -1,434 +1,434 @@
{
- /**
- * Metadata about some SMAPI mods used in compatibility, update, and dependency checks. This
- * field shouldn't be edited by players in most cases.
- *
- * Standard fields
- * ===============
- * The predefined fields are documented below (only 'ID' is required). Each entry's key is the
- * default display name for the mod if one isn't available (e.g. in dependency checks).
- *
- * - ID: the mod's latest unique ID (if any).
- *
- * - FormerIDs: uniquely identifies the mod across multiple versions, and supports matching
- * other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple
- * variants can be separated with '|'.
- *
- * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions
- * during update checks. For example, if the API returns version '1.1-1078' where '1078' is
- * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the
- * mod's current version. This is only meant to support legacy mods with injected update keys.
- *
- * Versioned metadata
- * ==================
- * Each record can also specify extra metadata using the field keys below.
- *
- * Each key consists of a field name prefixed with any combination of version range and 'Default',
- * separated by pipes (whitespace trimmed). For example, 'UpdateKey' will always override,
- * 'Default | UpdateKey' will only override if the mod has no update keys, and
- * '~1.1 | Default | Name' will do the same up to version 1.1.
- *
- * The version format is 'min~max' (where either side can be blank for unbounded), or a single
- * version number.
- *
- * These are the valid field names:
- *
- * - UpdateKey: the update key to set in the mod's manifest. This is used to enable update
- * checks for older mods that haven't been updated to use it yet.
- *
- * - Status: overrides compatibility checks. The possible values are Obsolete (SMAPI won't load
- * it because the mod should no longer be used), AssumeBroken (SMAPI won't load it because
- * the specified version isn't compatible), or AssumeCompatible (SMAPI will try to load it
- * even if it detects incompatible code).
- *
- * Note that this shouldn't be set to 'AssumeBroken' if SMAPI can detect the incompatibility
- * automatically, since that hides the details from trace logs.
- *
- * - StatusReasonPhrase: a message to show to the player explaining why the mod can't be loaded
- * (if applicable). If blank, will default to a generic not-compatible message.
- *
- * - AlternativeUrl: a URL where the player can find an unofficial update or alternative if the
- * mod is no longer compatible.
- */
- "ModData": {
- /*********
- ** Common dependencies for friendly errors
- *********/
- "Advanced Location Loader": {
- "ID": "Entoarox.AdvancedLocationLoader",
- "Default | UpdateKey": "Nexus:2270"
- },
-
- "Content Patcher": {
- "ID": "Pathoschild.ContentPatcher",
- "Default | UpdateKey": "Nexus:1915"
- },
-
- "Custom Farming Redux": {
- "ID": "Platonymous.CustomFarming",
- "Default | UpdateKey": "Nexus:991"
- },
-
- "Custom Shirts": {
- "ID": "Platonymous.CustomShirts",
- "Default | UpdateKey": "Nexus:2416"
- },
-
- "Entoarox Framework": {
- "ID": "Entoarox.EntoaroxFramework",
- "Default | UpdateKey": "Nexus:2269"
- },
-
- "JSON Assets": {
- "ID": "spacechase0.JsonAssets",
- "Default | UpdateKey": "Nexus:1720",
- "1.3.1 | Status": "AssumeBroken" // causes runtime crashes
- },
-
- "Mail Framework": {
- "ID": "DIGUS.MailFrameworkMod",
- "Default | UpdateKey": "Nexus:1536"
- },
-
- "MTN": {
- "ID": "SgtPickles.MTN",
- "Default | UpdateKey": "Nexus:2256",
- "~1.2.6 | Status": "AssumeBroken" // replaces Game1.multiplayer, which breaks SMAPI's multiplayer API.
- },
-
- "PyTK": {
- "ID": "Platonymous.Toolkit",
- "Default | UpdateKey": "Nexus:1726"
- },
-
- "Rubydew": {
- "ID": "bwdy.rubydew",
- "SuppressWarnings": "UsesDynamic", // mod explicitly loads DLLs for Linux/Mac compatibility
- "Default | UpdateKey": "Nexus:3656"
- },
-
- "SpaceCore": {
- "ID": "spacechase0.SpaceCore",
- "Default | UpdateKey": "Nexus:1348"
- },
-
- "Stardust Core": {
- "ID": "Omegasis.StardustCore",
- "Default | UpdateKey": "Nexus:2341"
- },
-
- "TMX Loader": {
- "ID": "Platonymous.TMXLoader",
- "Default | UpdateKey": "Nexus:1820"
- },
-
-
- /*********
- ** Map versions
- *********/
- "Adjust Artisan Prices": {
- "ID": "ThatNorthernMonkey.AdjustArtisanPrices",
- "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update
- "MapRemoteVersions": { "0.01": "0.0.1" }
- },
-
- "Almighty Farming Tool": {
- "ID": "439",
- "MapRemoteVersions": {
- "1.21": "1.2.1",
- "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion"
- }
- },
-
- "Basic Sprinkler Improved": {
- "ID": "lrsk_sdvm_bsi.0117171308",
- "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated
- },
-
- "Better Shipping Box": {
- "ID": "Kithio:BetterShippingBox",
- "MapLocalVersions": { "1.0.1": "1.0.2" }
- },
-
- "Chefs Closet": {
- "ID": "Duder.ChefsCloset",
- "MapLocalVersions": { "1.3-1": "1.3" }
- },
-
- "Configurable Machines": {
- "ID": "21da6619-dc03-4660-9794-8e5b498f5b97",
- "MapLocalVersions": { "1.2-beta": "1.2" }
- },
-
- "Crafting Counter": {
- "ID": "lolpcgaming.CraftingCounter",
- "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest
- },
-
- "Custom Linens": {
- "ID": "Mevima.CustomLinens",
- "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated
- },
-
- "Dynamic Horses": {
- "ID": "Bpendragon-DynamicHorses",
- "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated
- },
-
- "Dynamic Machines": {
- "ID": "DynamicMachines",
- "MapLocalVersions": { "1.1": "1.1.1" }
- },
-
- "Multiple Sprites and Portraits On Rotation (File Loading)": {
- "ID": "FileLoading",
- "MapLocalVersions": { "1.1": "1.12" }
- },
-
- "Relationship Status": {
- "ID": "relationshipstatus",
- "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest
- },
-
- "ReRegeneration": {
- "ID": "lrsk_sdvm_rerg.0925160827",
- "MapLocalVersions": { "1.1.2-release": "1.1.2" }
- },
-
- "Showcase Mod": {
- "ID": "Igorious.Showcase",
- "MapLocalVersions": { "0.9-500": "0.9" }
- },
-
- "Siv's Marriage Mod": {
- "ID": "6266959802", // official version
- "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions
- "MapLocalVersions": { "0.0": "1.4" }
- },
-
-
- /*********
- ** Obsolete
- *********/
- "Animal Mood Fix": {
- "ID": "GPeters-AnimalMoodFix",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
- },
-
- "Colored Chests": {
- "ID": "4befde5c-731c-4853-8e4b-c5cdf946805f",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1."
- },
-
- "Modder Serialization Utility": {
- "ID": "SerializerUtils-0-1",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "it's no longer maintained or used."
- },
-
- "No Debug Mode": {
- "ID": "NoDebugMode",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0."
- },
-
- /*********
- ** Broke in SDV 1.3.36
- *********/
- "2cute FarmCave": {
- "ID": "taintedwheat.2CuteFarmCave",
- "Default | UpdateKey": "Nexus:843",
- "~2.0 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Ace's Expanded Caves - Default Cave": {
- "ID": "Acerbicon.AECdefault",
- "Default | UpdateKey": "Nexus:2131",
- "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Ace's Expanded Caves - Desert Cave": {
- "ID": "Acerbicon.AECdesert",
- "Default | UpdateKey": "Nexus:2131",
- "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Ace's Expanded Caves - Ice Cave": {
- "ID": "Acerbicon.AECice",
- "Default | UpdateKey": "Nexus:2131",
- "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Ace's Expanded Caves - Lava Cave": {
- "ID": "Acerbicon.AEClava",
- "Default | UpdateKey": "Nexus:2131",
- "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Ace's Expanded Caves - Slime Cave": {
- "ID": "Acerbicon.AECslime",
- "Default | UpdateKey": "Nexus:2131",
- "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Green Pastures Farm": {
- "ID": "bugbuddy.GreenPasturesFarm",
- "Default | UpdateKey": "Nexus:2326",
- "~1.0 | Status": "AssumeBroken" // references deleted Content/weapons.xnb
- },
-
- "Immersive Farm 2": {
- "ID": "zander.immersivefarm2",
- "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- "Karmylla's Immersive Map Edits": {
- "ID": "Karmylla.ImmersiveMapEdits",
- "Default | UpdateKey": "Nexus:1149",
- "~2.4 | Status": "AssumeBroken" // references deleted Content/weapons.xnb
- },
-
- "Secret Gardens Greenhouse": {
- "ID": "jessebot.secretgardens",
- "Default | UpdateKey": "Nexus:3067",
- "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
- },
-
- /*********
- ** Broke circa SDV 1.3
- *********/
- "Canon-Friendly Dialogue Expansion": {
- "ID": "gizzymo.canonfriendlyexpansion",
- "~1.1.1 | Status": "AssumeBroken" // causes a save crash on certain dates
- },
-
- "Everytime Submarine": {
- "ID": "MustafaDemirel.EverytimeSubmarine",
- "~1.0.0 | Status": "AssumeBroken" // breaks player saves if their beach bridge is fixed
- },
-
- "Always Scroll Map": {
- "ID": "bcmpinc.AlwaysScrollMap",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Arcade Pong": {
- "ID": "Platonymous.ArcadePong",
- "~1.0.2 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
- },
-
- "BJS Night Sounds": {
- "ID": "BunnyJumps.BJSNightSounds",
- "~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
- },
-
- "Craft Counter": {
- "ID": "bcmpinc.CraftCounter",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Fishing Adjust": {
- "ID": "shuaiz.FishingAdjustMod",
- "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)'
- },
-
- "Fishing Automaton": {
- "ID": "Drynwynn.FishingAutomaton",
- "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
- },
-
- "Fix Animal Tools": {
- "ID": "bcmpinc.FixAnimalTools",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Fix Scythe Exp": {
- "ID": "bcmpinc.FixScytheExp",
- "~0.3 | Status": "AssumeBroken" // broke in 1.3: Exception from HarmonyInstance "bcmpinc.FixScytheExp" [...] Bad label content in ILGenerator.
- },
-
- "Grass Growth": {
- "ID": "bcmpinc.GrassGrowth",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "More Silo Storage": {
- "ID": "OrneryWalrus.MoreSiloStorage",
- "~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3
- },
-
- "Movement Speed": {
- "ID": "bcmpinc.MovementSpeed",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "No Added Flying Mine Monsters": {
- "ID": "Drynwynn.NoAddedFlyingMineMonsters",
- "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
- },
-
- "Server Bookmarker": {
- "ID": "Ilyaki.ServerBookmarker",
- "~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors)
- },
-
- "Skill Prestige: Cooking Adapter": {
- "ID": "Alphablackwolf.CookingSkillPrestigeAdapter",
- "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1
- "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated
- },
-
- "Skull Cave Saver": {
- "ID": "cantorsdust.SkullCaveSaver",
- "FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2
- "1.3-beta | Status": "AssumeBroken" // doesn't work in multiplayer, no longer maintained
- },
-
- "Split Screen": {
- "ID": "Ilyaki.SplitScreen",
- "~3.0.1 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
- },
-
- "Stardew Hack": {
- "ID": "bcmpinc.StardewHack",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Stephan's Lots of Crops": {
- "ID": "stephansstardewcrops",
- "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated
- "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items)
- },
-
- "Summit Reborn": {
- "ID": "KoihimeNakamura.summitreborn",
- "FormerIDs": "emissaryofinfinity.summitreborn", // changed in 1.0.2
- "~1.0.2 | Status": "AssumeBroken" // broke in SDV 1.3 (runtime errors)
- },
-
- "Tilled Soil Decay": {
- "ID": "bcmpinc.TilledSoilDecay",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Tree Spread": {
- "ID": "bcmpinc.TreeSpread",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- "Yet Another Harvest With Scythe Mod": {
- "ID": "bcmpinc.HarvestWithScythe",
- "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
- },
-
- /*********
- ** Broke circa SDV 1.2
- *********/
- "Move Faster": {
- "ID": "shuaiz.MoveFasterMod",
- "~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?)
+ /**
+ * Metadata about some SMAPI mods used in compatibility, update, and dependency checks. This
+ * field shouldn't be edited by players in most cases.
+ *
+ * Standard fields
+ * ===============
+ * The predefined fields are documented below (only 'ID' is required). Each entry's key is the
+ * default display name for the mod if one isn't available (e.g. in dependency checks).
+ *
+ * - ID: the mod's latest unique ID (if any).
+ *
+ * - FormerIDs: uniquely identifies the mod across multiple versions, and supports matching
+ * other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple
+ * variants can be separated with '|'.
+ *
+ * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions
+ * during update checks. For example, if the API returns version '1.1-1078' where '1078' is
+ * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the
+ * mod's current version. This is only meant to support legacy mods with injected update keys.
+ *
+ * Versioned metadata
+ * ==================
+ * Each record can also specify extra metadata using the field keys below.
+ *
+ * Each key consists of a field name prefixed with any combination of version range and 'Default',
+ * separated by pipes (whitespace trimmed). For example, 'UpdateKey' will always override,
+ * 'Default | UpdateKey' will only override if the mod has no update keys, and
+ * '~1.1 | Default | Name' will do the same up to version 1.1.
+ *
+ * The version format is 'min~max' (where either side can be blank for unbounded), or a single
+ * version number.
+ *
+ * These are the valid field names:
+ *
+ * - UpdateKey: the update key to set in the mod's manifest. This is used to enable update
+ * checks for older mods that haven't been updated to use it yet.
+ *
+ * - Status: overrides compatibility checks. The possible values are Obsolete (SMAPI won't load
+ * it because the mod should no longer be used), AssumeBroken (SMAPI won't load it because
+ * the specified version isn't compatible), or AssumeCompatible (SMAPI will try to load it
+ * even if it detects incompatible code).
+ *
+ * Note that this shouldn't be set to 'AssumeBroken' if SMAPI can detect the incompatibility
+ * automatically, since that hides the details from trace logs.
+ *
+ * - StatusReasonPhrase: a message to show to the player explaining why the mod can't be loaded
+ * (if applicable). If blank, will default to a generic not-compatible message.
+ *
+ * - AlternativeUrl: a URL where the player can find an unofficial update or alternative if the
+ * mod is no longer compatible.
+ */
+ "ModData": {
+ /*********
+ ** Common dependencies for friendly errors
+ *********/
+ "Advanced Location Loader": {
+ "ID": "Entoarox.AdvancedLocationLoader",
+ "Default | UpdateKey": "Nexus:2270"
+ },
+
+ "Content Patcher": {
+ "ID": "Pathoschild.ContentPatcher",
+ "Default | UpdateKey": "Nexus:1915"
+ },
+
+ "Custom Farming Redux": {
+ "ID": "Platonymous.CustomFarming",
+ "Default | UpdateKey": "Nexus:991"
+ },
+
+ "Custom Shirts": {
+ "ID": "Platonymous.CustomShirts",
+ "Default | UpdateKey": "Nexus:2416"
+ },
+
+ "Entoarox Framework": {
+ "ID": "Entoarox.EntoaroxFramework",
+ "Default | UpdateKey": "Nexus:2269"
+ },
+
+ "JSON Assets": {
+ "ID": "spacechase0.JsonAssets",
+ "Default | UpdateKey": "Nexus:1720",
+ "1.3.1 | Status": "AssumeBroken" // causes runtime crashes
+ },
+
+ "Mail Framework": {
+ "ID": "DIGUS.MailFrameworkMod",
+ "Default | UpdateKey": "Nexus:1536"
+ },
+
+ "MTN": {
+ "ID": "SgtPickles.MTN",
+ "Default | UpdateKey": "Nexus:2256",
+ "~1.2.6 | Status": "AssumeBroken" // replaces Game1.multiplayer, which breaks SMAPI's multiplayer API.
+ },
+
+ "PyTK": {
+ "ID": "Platonymous.Toolkit",
+ "Default | UpdateKey": "Nexus:1726"
+ },
+
+ "Rubydew": {
+ "ID": "bwdy.rubydew",
+ "SuppressWarnings": "UsesDynamic", // mod explicitly loads DLLs for Linux/Mac compatibility
+ "Default | UpdateKey": "Nexus:3656"
+ },
+
+ "SpaceCore": {
+ "ID": "spacechase0.SpaceCore",
+ "Default | UpdateKey": "Nexus:1348"
+ },
+
+ "Stardust Core": {
+ "ID": "Omegasis.StardustCore",
+ "Default | UpdateKey": "Nexus:2341"
+ },
+
+ "TMX Loader": {
+ "ID": "Platonymous.TMXLoader",
+ "Default | UpdateKey": "Nexus:1820"
+ },
+
+
+ /*********
+ ** Map versions
+ *********/
+ "Adjust Artisan Prices": {
+ "ID": "ThatNorthernMonkey.AdjustArtisanPrices",
+ "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update
+ "MapRemoteVersions": { "0.01": "0.0.1" }
+ },
+
+ "Almighty Farming Tool": {
+ "ID": "439",
+ "MapRemoteVersions": {
+ "1.21": "1.2.1",
+ "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion"
+ }
+ },
+
+ "Basic Sprinkler Improved": {
+ "ID": "lrsk_sdvm_bsi.0117171308",
+ "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated
+ },
+
+ "Better Shipping Box": {
+ "ID": "Kithio:BetterShippingBox",
+ "MapLocalVersions": { "1.0.1": "1.0.2" }
+ },
+
+ "Chefs Closet": {
+ "ID": "Duder.ChefsCloset",
+ "MapLocalVersions": { "1.3-1": "1.3" }
+ },
+
+ "Configurable Machines": {
+ "ID": "21da6619-dc03-4660-9794-8e5b498f5b97",
+ "MapLocalVersions": { "1.2-beta": "1.2" }
+ },
+
+ "Crafting Counter": {
+ "ID": "lolpcgaming.CraftingCounter",
+ "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest
+ },
+
+ "Custom Linens": {
+ "ID": "Mevima.CustomLinens",
+ "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated
+ },
+
+ "Dynamic Horses": {
+ "ID": "Bpendragon-DynamicHorses",
+ "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated
+ },
+
+ "Dynamic Machines": {
+ "ID": "DynamicMachines",
+ "MapLocalVersions": { "1.1": "1.1.1" }
+ },
+
+ "Multiple Sprites and Portraits On Rotation (File Loading)": {
+ "ID": "FileLoading",
+ "MapLocalVersions": { "1.1": "1.12" }
+ },
+
+ "Relationship Status": {
+ "ID": "relationshipstatus",
+ "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest
+ },
+
+ "ReRegeneration": {
+ "ID": "lrsk_sdvm_rerg.0925160827",
+ "MapLocalVersions": { "1.1.2-release": "1.1.2" }
+ },
+
+ "Showcase Mod": {
+ "ID": "Igorious.Showcase",
+ "MapLocalVersions": { "0.9-500": "0.9" }
+ },
+
+ "Siv's Marriage Mod": {
+ "ID": "6266959802", // official version
+ "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions
+ "MapLocalVersions": { "0.0": "1.4" }
+ },
+
+
+ /*********
+ ** Obsolete
+ *********/
+ "Animal Mood Fix": {
+ "ID": "GPeters-AnimalMoodFix",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
+ },
+
+ "Colored Chests": {
+ "ID": "4befde5c-731c-4853-8e4b-c5cdf946805f",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1."
+ },
+
+ "Modder Serialization Utility": {
+ "ID": "SerializerUtils-0-1",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "it's no longer maintained or used."
+ },
+
+ "No Debug Mode": {
+ "ID": "NoDebugMode",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0."
+ },
+
+ /*********
+ ** Broke in SDV 1.3.36
+ *********/
+ "2cute FarmCave": {
+ "ID": "taintedwheat.2CuteFarmCave",
+ "Default | UpdateKey": "Nexus:843",
+ "~2.0 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Ace's Expanded Caves - Default Cave": {
+ "ID": "Acerbicon.AECdefault",
+ "Default | UpdateKey": "Nexus:2131",
+ "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Ace's Expanded Caves - Desert Cave": {
+ "ID": "Acerbicon.AECdesert",
+ "Default | UpdateKey": "Nexus:2131",
+ "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Ace's Expanded Caves - Ice Cave": {
+ "ID": "Acerbicon.AECice",
+ "Default | UpdateKey": "Nexus:2131",
+ "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Ace's Expanded Caves - Lava Cave": {
+ "ID": "Acerbicon.AEClava",
+ "Default | UpdateKey": "Nexus:2131",
+ "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Ace's Expanded Caves - Slime Cave": {
+ "ID": "Acerbicon.AECslime",
+ "Default | UpdateKey": "Nexus:2131",
+ "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Green Pastures Farm": {
+ "ID": "bugbuddy.GreenPasturesFarm",
+ "Default | UpdateKey": "Nexus:2326",
+ "~1.0 | Status": "AssumeBroken" // references deleted Content/weapons.xnb
+ },
+
+ "Immersive Farm 2": {
+ "ID": "zander.immersivefarm2",
+ "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ "Karmylla's Immersive Map Edits": {
+ "ID": "Karmylla.ImmersiveMapEdits",
+ "Default | UpdateKey": "Nexus:1149",
+ "~2.4 | Status": "AssumeBroken" // references deleted Content/weapons.xnb
+ },
+
+ "Secret Gardens Greenhouse": {
+ "ID": "jessebot.secretgardens",
+ "Default | UpdateKey": "Nexus:3067",
+ "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb
+ },
+
+ /*********
+ ** Broke circa SDV 1.3
+ *********/
+ "Canon-Friendly Dialogue Expansion": {
+ "ID": "gizzymo.canonfriendlyexpansion",
+ "~1.1.1 | Status": "AssumeBroken" // causes a save crash on certain dates
+ },
+
+ "Everytime Submarine": {
+ "ID": "MustafaDemirel.EverytimeSubmarine",
+ "~1.0.0 | Status": "AssumeBroken" // breaks player saves if their beach bridge is fixed
+ },
+
+ "Always Scroll Map": {
+ "ID": "bcmpinc.AlwaysScrollMap",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Arcade Pong": {
+ "ID": "Platonymous.ArcadePong",
+ "~1.0.2 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
+ },
+
+ "BJS Night Sounds": {
+ "ID": "BunnyJumps.BJSNightSounds",
+ "~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
+ },
+
+ "Craft Counter": {
+ "ID": "bcmpinc.CraftCounter",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Fishing Adjust": {
+ "ID": "shuaiz.FishingAdjustMod",
+ "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)'
+ },
+
+ "Fishing Automaton": {
+ "ID": "Drynwynn.FishingAutomaton",
+ "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
+ },
+
+ "Fix Animal Tools": {
+ "ID": "bcmpinc.FixAnimalTools",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Fix Scythe Exp": {
+ "ID": "bcmpinc.FixScytheExp",
+ "~0.3 | Status": "AssumeBroken" // broke in 1.3: Exception from HarmonyInstance "bcmpinc.FixScytheExp" [...] Bad label content in ILGenerator.
+ },
+
+ "Grass Growth": {
+ "ID": "bcmpinc.GrassGrowth",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "More Silo Storage": {
+ "ID": "OrneryWalrus.MoreSiloStorage",
+ "~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3
+ },
+
+ "Movement Speed": {
+ "ID": "bcmpinc.MovementSpeed",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "No Added Flying Mine Monsters": {
+ "ID": "Drynwynn.NoAddedFlyingMineMonsters",
+ "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
+ },
+
+ "Server Bookmarker": {
+ "ID": "Ilyaki.ServerBookmarker",
+ "~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors)
+ },
+
+ "Skill Prestige: Cooking Adapter": {
+ "ID": "Alphablackwolf.CookingSkillPrestigeAdapter",
+ "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1
+ "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated
+ },
+
+ "Skull Cave Saver": {
+ "ID": "cantorsdust.SkullCaveSaver",
+ "FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2
+ "1.3-beta | Status": "AssumeBroken" // doesn't work in multiplayer, no longer maintained
+ },
+
+ "Split Screen": {
+ "ID": "Ilyaki.SplitScreen",
+ "~3.0.1 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
+ },
+
+ "Stardew Hack": {
+ "ID": "bcmpinc.StardewHack",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Stephan's Lots of Crops": {
+ "ID": "stephansstardewcrops",
+ "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated
+ "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items)
+ },
+
+ "Summit Reborn": {
+ "ID": "KoihimeNakamura.summitreborn",
+ "FormerIDs": "emissaryofinfinity.summitreborn", // changed in 1.0.2
+ "~1.0.2 | Status": "AssumeBroken" // broke in SDV 1.3 (runtime errors)
+ },
+
+ "Tilled Soil Decay": {
+ "ID": "bcmpinc.TilledSoilDecay",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Tree Spread": {
+ "ID": "bcmpinc.TreeSpread",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ "Yet Another Harvest With Scythe Mod": {
+ "ID": "bcmpinc.HarvestWithScythe",
+ "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
+ },
+
+ /*********
+ ** Broke circa SDV 1.2
+ *********/
+ "Move Faster": {
+ "ID": "shuaiz.MoveFasterMod",
+ "~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?)
+ }
}
- }
}
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 7351596f..6c00a973 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -20,7 +20,7 @@ namespace StardewModdingAPI
** Public
****/
/// SMAPI's current semantic version.
- public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.2");
+ public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.3");
/// Android SMAPI's current semantic version.
public static ISemanticVersion AndroidApiVersion { get; } = new Toolkit.SemanticVersion("0.9.0");
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 9875c424..7d7d77ed 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -139,7 +139,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
throw GetContentError($"can't read unpacked map file directly from the underlying content manager. It must be loaded through the mod's {typeof(IModHelper)}.{nameof(IModHelper.Content)} helper.");
default:
- throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.png', '.tbin', or '.xnb'.");
+ throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.json', '.png', '.tbin', or '.xnb'.");
}
}
catch (Exception ex) when (!(ex is SContentLoadException))
diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs
index 3153bbb4..984bb487 100644
--- a/src/SMAPI/Framework/DeprecationManager.cs
+++ b/src/SMAPI/Framework/DeprecationManager.cs
@@ -132,7 +132,7 @@ namespace StardewModdingAPI.Framework
else
{
this.Monitor.Log(message, level);
- this.Monitor.Log(warning.StackTrace);
+ this.Monitor.Log(warning.StackTrace, LogLevel.Debug);
}
}
}
diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs
index cd5ecb39..a740db65 100644
--- a/src/SMAPI/Framework/Monitor.cs
+++ b/src/SMAPI/Framework/Monitor.cs
@@ -78,7 +78,7 @@ namespace StardewModdingAPI.Framework
/// Log a message for the player or developer.
/// The message to log.
/// The log severity level.
- public void Log(string message, LogLevel level = LogLevel.Debug)
+ public void Log(string message, LogLevel level = LogLevel.Trace)
{
this.LogImpl(this.Source, message, (ConsoleLogLevel)level);
}
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 2941964d..543899ef 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -778,8 +778,8 @@ namespace StardewModdingAPI.Framework
if (this.Monitor.IsVerbose)
{
- string addedText = this.Watchers.LocationsWatcher.Added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
- string removedText = this.Watchers.LocationsWatcher.Removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
+ string addedText = added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
+ string removedText = removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace);
}
diff --git a/src/SMAPI/IMonitor.cs b/src/SMAPI/IMonitor.cs
index 0f153e10..943c1c59 100644
--- a/src/SMAPI/IMonitor.cs
+++ b/src/SMAPI/IMonitor.cs
@@ -19,7 +19,7 @@ namespace StardewModdingAPI
/// Log a message for the player or developer.
/// The message to log.
/// The log severity level.
- void Log(string message, LogLevel level = LogLevel.Debug);
+ void Log(string message, LogLevel level = LogLevel.Trace);
/// Log a message that only appears when is enabled.
/// The message to log.
diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs
index d8905fd1..f1c25c05 100644
--- a/src/SMAPI/Patches/DialogueErrorPatch.cs
+++ b/src/SMAPI/Patches/DialogueErrorPatch.cs
@@ -13,7 +13,7 @@ namespace StardewModdingAPI.Patches
internal class DialogueErrorPatch : IHarmonyPatch
{
/*********
- ** Private methods
+ ** Fields
*********/
/// Writes messages to the console and log file on behalf of the game.
private static IMonitor MonitorForGame;
@@ -21,6 +21,9 @@ namespace StardewModdingAPI.Patches
/// Simplifies access to private code.
private static Reflector Reflection;
+ /// Whether the getter is currently being intercepted.
+ private static bool IsInterceptingCurrentDialogue;
+
/*********
** Accessors
@@ -46,10 +49,14 @@ namespace StardewModdingAPI.Patches
/// The Harmony instance.
public void Apply(HarmonyInstance harmony)
{
- ConstructorInfo constructor = AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) });
- MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(DialogueErrorPatch.Prefix));
-
- harmony.Patch(constructor, new HarmonyMethod(prefix), null);
+ harmony.Patch(
+ original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }),
+ prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Before_Dialogue_Constructor))
+ );
+ harmony.Patch(
+ original: AccessTools.Property(typeof(NPC), nameof(NPC.CurrentDialogue)).GetMethod,
+ prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Before_NPC_CurrentDialogue))
+ );
}
@@ -63,7 +70,7 @@ namespace StardewModdingAPI.Patches
/// Returns whether to execute the original method.
/// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
- private static bool Prefix(Dialogue __instance, string masterDialogue, NPC speaker)
+ private static bool Before_Dialogue_Constructor(Dialogue __instance, string masterDialogue, NPC speaker)
{
// get private members
bool nameArraysTranslated = DialogueErrorPatch.Reflection.GetField(typeof(Dialogue), "nameArraysTranslated").GetValue();
@@ -96,5 +103,35 @@ namespace StardewModdingAPI.Patches
return false;
}
+
+ /// The method to call instead of .
+ /// The instance being patched.
+ /// The return value of the original method.
+ /// The method being wrapped.
+ /// Returns whether to execute the original method.
+ /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
+ [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
+ private static bool Before_NPC_CurrentDialogue(NPC __instance, ref Stack __result, MethodInfo __originalMethod)
+ {
+ if (DialogueErrorPatch.IsInterceptingCurrentDialogue)
+ return true;
+
+ try
+ {
+ DialogueErrorPatch.IsInterceptingCurrentDialogue = true;
+ __result = (Stack)__originalMethod.Invoke(__instance, new object[0]);
+ return false;
+ }
+ catch (TargetInvocationException ex)
+ {
+ DialogueErrorPatch.MonitorForGame.Log($"Failed loading current dialogue for NPC {__instance.Name}:\n{ex.InnerException ?? ex}", LogLevel.Error);
+ __result = new Stack();
+ return false;
+ }
+ finally
+ {
+ DialogueErrorPatch.IsInterceptingCurrentDialogue = false;
+ }
+ }
}
}
diff --git a/src/SMAPI/Patches/EventErrorPatch.cs b/src/SMAPI/Patches/EventErrorPatch.cs
new file mode 100644
index 00000000..cd530616
--- /dev/null
+++ b/src/SMAPI/Patches/EventErrorPatch.cs
@@ -0,0 +1,84 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using Harmony;
+using StardewModdingAPI.Framework.Patching;
+using StardewValley;
+
+namespace StardewModdingAPI.Patches
+{
+ /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing.
+ internal class EventErrorPatch : IHarmonyPatch
+ {
+ /*********
+ ** Fields
+ *********/
+ /// Writes messages to the console and log file on behalf of the game.
+ private static IMonitor MonitorForGame;
+
+ /// Whether the method is currently being intercepted.
+ private static bool IsIntercepted;
+
+
+ /*********
+ ** Accessors
+ *********/
+ /// A unique name for this patch.
+ public string Name => $"{nameof(EventErrorPatch)}";
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// Writes messages to the console and log file on behalf of the game.
+ public EventErrorPatch(IMonitor monitorForGame)
+ {
+ EventErrorPatch.MonitorForGame = monitorForGame;
+ }
+
+ /// Apply the Harmony patch.
+ /// The Harmony instance.
+ public void Apply(HarmonyInstance harmony)
+ {
+ harmony.Patch(
+ original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"),
+ prefix: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Before_GameLocation_CheckEventPrecondition))
+ );
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// The method to call instead of the GameLocation.CheckEventPrecondition.
+ /// The instance being patched.
+ /// The return value of the original method.
+ /// The precondition to be parsed.
+ /// The method being wrapped.
+ /// Returns whether to execute the original method.
+ /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
+ [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
+ private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod)
+ {
+ if (EventErrorPatch.IsIntercepted)
+ return true;
+
+ try
+ {
+ EventErrorPatch.IsIntercepted = true;
+ __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition });
+ return false;
+ }
+ catch (TargetInvocationException ex)
+ {
+ __result = -1;
+ EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error);
+ return false;
+ }
+ finally
+ {
+ EventErrorPatch.IsIntercepted = false;
+ }
+ }
+ }
+}
diff --git a/src/SMAPI/Patches/LoadForNewGamePatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs
similarity index 67%
rename from src/SMAPI/Patches/LoadForNewGamePatch.cs
rename to src/SMAPI/Patches/LoadContextPatch.cs
index 9e788e84..3f86c9a9 100644
--- a/src/SMAPI/Patches/LoadForNewGamePatch.cs
+++ b/src/SMAPI/Patches/LoadContextPatch.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
-using System.Reflection;
using Harmony;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Framework.Patching;
@@ -13,10 +12,10 @@ namespace StardewModdingAPI.Patches
{
/// A Harmony patch for which notifies SMAPI for save creation load stages.
/// This patch hooks into , checks if TitleMenu.transitioningCharacterCreationMenu is true (which means the player is creating a new save file), then raises after the location list is cleared twice (the second clear happens right before locations are created), and when the method ends.
- internal class LoadForNewGamePatch : IHarmonyPatch
+ internal class LoadContextPatch : IHarmonyPatch
{
/*********
- ** Accessors
+ ** Fields
*********/
/// Simplifies access to private code.
private static Reflector Reflection;
@@ -28,14 +27,14 @@ namespace StardewModdingAPI.Patches
private static bool IsCreating;
/// The number of times that has been cleared since started.
- private static int TimesLocationsCleared = 0;
+ private static int TimesLocationsCleared;
/*********
** Accessors
*********/
/// A unique name for this patch.
- public string Name => $"{nameof(LoadForNewGamePatch)}";
+ public string Name => $"{nameof(LoadContextPatch)}";
/*********
@@ -44,21 +43,21 @@ namespace StardewModdingAPI.Patches
/// Construct an instance.
/// Simplifies access to private code.
/// A callback to invoke when the load stage changes.
- public LoadForNewGamePatch(Reflector reflection, Action onStageChanged)
+ public LoadContextPatch(Reflector reflection, Action onStageChanged)
{
- LoadForNewGamePatch.Reflection = reflection;
- LoadForNewGamePatch.OnStageChanged = onStageChanged;
+ LoadContextPatch.Reflection = reflection;
+ LoadContextPatch.OnStageChanged = onStageChanged;
}
/// Apply the Harmony patch.
/// The Harmony instance.
public void Apply(HarmonyInstance harmony)
{
- MethodInfo method = AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame));
- MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(LoadForNewGamePatch.Prefix));
- MethodInfo postfix = AccessTools.Method(this.GetType(), nameof(LoadForNewGamePatch.Postfix));
-
- harmony.Patch(method, new HarmonyMethod(prefix), new HarmonyMethod(postfix));
+ harmony.Patch(
+ original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)),
+ prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_LoadForNewGame)),
+ postfix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.After_Game1_LoadForNewGame))
+ );
}
@@ -68,15 +67,15 @@ namespace StardewModdingAPI.Patches
/// The method to call instead of .
/// Returns whether to execute the original method.
/// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
- private static bool Prefix()
+ private static bool Before_Game1_LoadForNewGame()
{
- LoadForNewGamePatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadForNewGamePatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue();
- LoadForNewGamePatch.TimesLocationsCleared = 0;
- if (LoadForNewGamePatch.IsCreating)
+ LoadContextPatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue();
+ LoadContextPatch.TimesLocationsCleared = 0;
+ if (LoadContextPatch.IsCreating)
{
// raise CreatedBasicInfo after locations are cleared twice
ObservableCollection locations = (ObservableCollection)Game1.locations;
- locations.CollectionChanged += LoadForNewGamePatch.OnLocationListChanged;
+ locations.CollectionChanged += LoadContextPatch.OnLocationListChanged;
}
return true;
@@ -84,16 +83,16 @@ namespace StardewModdingAPI.Patches
/// The method to call instead after .
/// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
- private static void Postfix()
+ private static void After_Game1_LoadForNewGame()
{
- if (LoadForNewGamePatch.IsCreating)
+ if (LoadContextPatch.IsCreating)
{
// clean up
- ObservableCollection locations = (ObservableCollection) Game1.locations;
- locations.CollectionChanged -= LoadForNewGamePatch.OnLocationListChanged;
+ ObservableCollection locations = (ObservableCollection)Game1.locations;
+ locations.CollectionChanged -= LoadContextPatch.OnLocationListChanged;
// raise stage changed
- LoadForNewGamePatch.OnStageChanged(LoadStage.CreatedLocations);
+ LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations);
}
}
@@ -102,8 +101,8 @@ namespace StardewModdingAPI.Patches
/// The event arguments.
private static void OnLocationListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- if (++LoadForNewGamePatch.TimesLocationsCleared == 2)
- LoadForNewGamePatch.OnStageChanged(LoadStage.CreatedBasicInfo);
+ if (++LoadContextPatch.TimesLocationsCleared == 2)
+ LoadContextPatch.OnStageChanged(LoadStage.CreatedBasicInfo);
}
}
}
diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs
index 0481259d..5b918d39 100644
--- a/src/SMAPI/Patches/ObjectErrorPatch.cs
+++ b/src/SMAPI/Patches/ObjectErrorPatch.cs
@@ -1,8 +1,8 @@
using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
using Harmony;
using StardewModdingAPI.Framework.Patching;
using StardewValley;
+using StardewValley.Menus;
using SObject = StardewValley.Object;
namespace StardewModdingAPI.Patches
@@ -24,10 +24,17 @@ namespace StardewModdingAPI.Patches
/// The Harmony instance.
public void Apply(HarmonyInstance harmony)
{
- MethodInfo method = AccessTools.Method(typeof(SObject), nameof(SObject.getDescription));
- MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Prefix));
+ // object.getDescription
+ harmony.Patch(
+ original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)),
+ prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_Object_GetDescription))
+ );
- harmony.Patch(method, new HarmonyMethod(prefix), null);
+ // IClickableMenu.drawToolTip
+ harmony.Patch(
+ original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)),
+ prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_IClickableMenu_DrawTooltip))
+ );
}
@@ -40,7 +47,7 @@ namespace StardewModdingAPI.Patches
/// Returns whether to execute the original method.
/// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
- private static bool Prefix(SObject __instance, ref string __result)
+ private static bool Before_Object_GetDescription(SObject __instance, ref string __result)
{
// invalid bigcraftables crash instead of showing '???' like invalid non-bigcraftables
if (!__instance.IsRecipe && __instance.bigCraftable.Value && !Game1.bigCraftablesInformation.ContainsKey(__instance.ParentSheetIndex))
@@ -51,5 +58,20 @@ namespace StardewModdingAPI.Patches
return true;
}
+
+ /// The method to call instead of .
+ /// The instance being patched.
+ /// The item for which to draw a tooltip.
+ /// Returns whether to execute the original method.
+ /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.
+ [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
+ private static bool Before_IClickableMenu_DrawTooltip(IClickableMenu __instance, Item hoveredItem)
+ {
+ // invalid edible item cause crash when drawing tooltips
+ if (hoveredItem is SObject obj && obj.Edibility != -300 && !Game1.objectInformation.ContainsKey(obj.ParentSheetIndex))
+ return false;
+
+ return true;
+ }
}
}
diff --git a/src/SMAPI/StardewModdingAPI.config.json b/src/SMAPI/StardewModdingAPI.config.json
new file mode 100644
index 00000000..c04cceee
--- /dev/null
+++ b/src/SMAPI/StardewModdingAPI.config.json
@@ -0,0 +1,77 @@
+/*
+
+
+
+This file contains advanced configuration for SMAPI. You generally shouldn't change this file.
+
+
+
+*/
+{
+ /**
+ * The console color theme to use. The possible values are:
+ * - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color automatically on Linux or Windows.
+ * - LightBackground: use darker text colors that look better on a white or light background.
+ * - DarkBackground: use lighter text colors that look better on a black or dark background.
+ */
+ "ColorScheme": "AutoDetect",
+
+ /**
+ * Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new
+ * versions are available, an alert will be shown in the console. This doesn't affect the load
+ * time even if your connection is offline or slow, because it happens in the background.
+ */
+ "CheckForUpdates": true,
+
+ /**
+ * Whether to enable features intended for mod developers. Currently this only makes TRACE-level
+ * messages appear in the console.
+ */
+ "DeveloperMode": true,
+
+ /**
+ * Whether to add a section to the 'mod issues' list for mods which directly use potentially
+ * sensitive .NET APIs like file or shell access. Note that many mods do this legitimately as
+ * part of their normal functionality, so these warnings are meaningless without further
+ * investigation. When this is commented out, it'll be true for local debug builds and false
+ * otherwise.
+ */
+ //"ParanoidWarnings": true,
+
+ /**
+ * Whether SMAPI should show newer beta versions as an available update. When this is commented
+ * out, it'll be true if the current SMAPI version is beta, and false otherwise.
+ */
+ //"UseBetaChannel": true,
+
+ /**
+ * SMAPI's GitHub project name, used to perform update checks.
+ */
+ "GitHubProjectName": "Pathoschild/SMAPI",
+
+ /**
+ * The base URL for SMAPI's web API, used to perform update checks.
+ * Note: the protocol will be changed to http:// on Linux/Mac due to OpenSSL issues with the
+ * game's bundled Mono.
+ */
+ "WebApiBaseUrl": "https://api.smapi.io",
+
+ /**
+ * Whether SMAPI should log more information about the game context.
+ */
+ "VerboseLogging": false,
+
+ /**
+ * Whether to generate a 'SMAPI-latest.metadata-dump.json' file in the logs folder with the full mod
+ * metadata for detected mods. This is only needed when troubleshooting some cases.
+ */
+ "DumpMetadata": false,
+
+ /**
+ * The mod IDs SMAPI should ignore when performing update checks or validating update keys.
+ */
+ "SuppressUpdateChecks": [
+ "SMAPI.ConsoleCommands",
+ "SMAPI.SaveBackup"
+ ]
+}
diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj
index 55b02c98..eda53025 100644
--- a/src/SMAPI/StardewModdingAPI.csproj
+++ b/src/SMAPI/StardewModdingAPI.csproj
@@ -1,425 +1,60 @@
-
-
+
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {9ef11e43-1701-4396-8835-8392d57abb70}
- Library
- Properties
StardewModdingAPI
StardewModdingAPI
- 512
- Resources\Resource.designer.cs
- Off
- false
- v9.0
-
-
- true
- portable
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
+ net45
+ false
+ latest
+ x86
+ Exe
+ $(SolutionDir)\..\bin\$(Configuration)\SMAPI
+ $(SolutionDir)\..\bin\$(Configuration)\SMAPI\StardewModdingAPI.xml
+ false
+ true
+ icon.ico
+
-
- ..\..\..\..\..\..\..\SteamLibrary\steamapps\common\Stardew Valley\smapi-internal\0Harmony.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\BmFont.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Google.Android.Vending.Expansion.Downloader.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Google.Android.Vending.Expansion.ZipFile.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Google.Android.Vending.Licensing.dll
-
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.Analytics.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.Analytics.Android.Bindings.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.Android.Bindings.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.Crashes.dll
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\Microsoft.AppCenter.Crashes.Android.Bindings.dll
-
-
-
-
- ..\..\..\..\..\..\..\SteamLibrary\steamapps\common\Stardew Valley\smapi-internal\Mono.Cecil.dll
-
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\MonoGame.Framework.dll
-
-
- ..\..\..\..\..\Downloads\MonoMod.RuntimeDetour.dll
-
-
- ..\..\..\..\..\Downloads\MonoMod.Utils.dll
-
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\StardewValley.dll
-
-
-
+
+
+
+
+
+
+
+
True
-
-
-
- ..\..\..\..\..\Downloads\com.chucklefish.stardewvalley_1.322\assemblies\xTile.dll
+
+ True
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
-
-
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {d5cfd923-37f1-4bc3-9be8-e506e202ac28}
- StardewModdingAPI.Toolkit.CoreInterfaces
-
-
- {ea5cfd2e-9453-4d29-b80f-8e0ea23f4ac6}
- StardewModdingAPI.Toolkit
-
+
+ PreserveNewest
+
+
+ StardewModdingAPI.metadata.json
+ PreserveNewest
+
+
+ PreserveNewest
+
+
-
-
-
\ No newline at end of file
+
+
+
diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs
deleted file mode 100644
index 879cfd8a..00000000
--- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
-{
- /// Whether a mod is ready for the upcoming SMAPI 3.0.
- public enum WikiSmapi3Status
- {
- /// The mod's compatibility status is unknown.
- Unknown = 0,
-
- /// The mod is compatible with the upcoming SMAPI 3.0.
- Ok = 1,
-
- /// The mod will break in SMAPI 3.0.
- Broken = 2,
-
- /// The mod has a pull request submitted for SMAPI 3.0 compatibility.
- Soon = 3
- }
-}