summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/wwwroot
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
commita3f21685049cabf2d824c8060dc0b1de47e9449e (patch)
treead9add30e9da2a50e0ea0245f1546b7378f0d282 /src/SMAPI.Web/wwwroot
parent6521df7b131924835eb797251c1e956fae0d6e13 (diff)
parent277bf082675b98b95bf6184fe3c7a45b969c7ac2 (diff)
downloadSMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.gz
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.bz2
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI.Web/wwwroot')
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/json-validator.css111
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/main.css2
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/mods.css57
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/json-validator.js179
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/log-parser.js17
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/mods.js3
-rw-r--r--src/SMAPI.Web/wwwroot/SMAPI.metadata.json (renamed from src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json)237
-rw-r--r--src/SMAPI.Web/wwwroot/schemas/content-patcher.json389
-rw-r--r--src/SMAPI.Web/wwwroot/schemas/manifest.json147
9 files changed, 1008 insertions, 134 deletions
diff --git a/src/SMAPI.Web/wwwroot/Content/css/json-validator.css b/src/SMAPI.Web/wwwroot/Content/css/json-validator.css
new file mode 100644
index 00000000..cd117694
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/Content/css/json-validator.css
@@ -0,0 +1,111 @@
+/*********
+** Main layout
+*********/
+#content {
+ max-width: 100%;
+}
+
+#output {
+ padding: 10px;
+ overflow: auto;
+}
+
+#output table td {
+ font-family: monospace;
+}
+
+#output table tr th,
+#output table tr td {
+ padding: 0 0.75rem;
+ white-space: pre-wrap;
+}
+
+
+/*********
+** Result banner
+*********/
+.banner {
+ border: 2px solid gray;
+ border-radius: 5px;
+ margin-top: 1em;
+ padding: 1em;
+}
+
+.banner.success {
+ border-color: green;
+ background: #CFC;
+}
+
+.banner.error {
+ border-color: red;
+ background: #FCC;
+}
+
+/*********
+** Validation results
+*********/
+.table {
+ border-bottom: 1px dashed #888888;
+ margin-bottom: 5px;
+}
+
+#metadata th, #metadata td {
+ text-align: left;
+ padding-right: 0.7em;
+}
+
+.table {
+ border: 1px solid #000000;
+ background: #ffffff;
+ border-radius: 5px;
+ border-spacing: 1px;
+ overflow: hidden;
+ cursor: default;
+ box-shadow: 1px 1px 1px 1px #dddddd;
+}
+
+.table tr {
+ background: #eee;
+}
+
+.table tr:nth-child(even) {
+ background: #fff;
+}
+
+#output div.sunlight-line-highlight-active {
+ background-color: #eeeacc;
+}
+
+.footer-tip {
+ color: gray;
+ font-size: 0.9em;
+}
+
+.footer-tip a {
+ color: gray;
+}
+
+/*********
+** Upload form
+*********/
+#input {
+ width: 100%;
+ height: 20em;
+ max-height: 70%;
+ margin: auto;
+ box-sizing: border-box;
+ border-radius: 5px;
+ border: 1px solid #000088;
+ outline: none;
+ box-shadow: inset 0px 0px 1px 1px rgba(0, 0, 192, .2);
+}
+
+#submit {
+ font-size: 1.5em;
+ border-radius: 5px;
+ outline: none;
+ box-shadow: inset 0 0 1px 1px rgba(0, 0, 0, .2);
+ cursor: pointer;
+ border: 1px solid #008800;
+ background-color: #cfc;
+}
diff --git a/src/SMAPI.Web/wwwroot/Content/css/main.css b/src/SMAPI.Web/wwwroot/Content/css/main.css
index 57eeee88..dcc7a798 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/main.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/main.css
@@ -73,7 +73,7 @@ a {
}
#sidebar h4 {
- margin: 0 0 0.2em 0;
+ margin: 1.5em 0 0.2em 0;
width: 10em;
border-bottom: 1px solid #CCC;
font-size: 0.8em;
diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css
index fc5fff47..1c2b8056 100644
--- a/src/SMAPI.Web/wwwroot/Content/css/mods.css
+++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css
@@ -15,30 +15,6 @@
border: 3px solid darkgreen;
}
-table.wikitable {
- background-color:#f8f9fa;
- color:#222;
- border:1px solid #a2a9b1;
- border-collapse:collapse
-}
-
-table.wikitable > tr > th,
-table.wikitable > tr > td,
-table.wikitable > * > tr > th,
-table.wikitable > * > tr > td {
- border:1px solid #a2a9b1;
- padding:0.2em 0.4em
-}
-
-table.wikitable > tr > th,
-table.wikitable > * > tr > th {
- background-color:#eaecf0;
-}
-
-table.wikitable > caption {
- font-weight:bold
-}
-
#options {
margin-bottom: 1em;
}
@@ -73,6 +49,39 @@ table.wikitable > caption {
opacity: 0.5;
}
+div.error {
+ padding: 2em 0;
+ color: red;
+ font-weight: bold;
+}
+
+/*********
+** Mod list
+*********/
+table.wikitable {
+ background-color:#f8f9fa;
+ color:#222;
+ border:1px solid #a2a9b1;
+ border-collapse:collapse
+}
+
+table.wikitable > tr > th,
+table.wikitable > tr > td,
+table.wikitable > * > tr > th,
+table.wikitable > * > tr > td {
+ border:1px solid #a2a9b1;
+ padding:0.2em 0.4em
+}
+
+table.wikitable > tr > th,
+table.wikitable > * > tr > th {
+ background-color:#eaecf0;
+}
+
+table.wikitable > caption {
+ font-weight:bold
+}
+
#mod-list {
font-size: 0.9em;
}
diff --git a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js
new file mode 100644
index 00000000..5499cef6
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js
@@ -0,0 +1,179 @@
+/* globals $ */
+
+var smapi = smapi || {};
+
+/**
+ * Manages the logic for line range selections.
+ * @param {int} maxLines The maximum number of lines in the content.
+ */
+smapi.LineNumberRange = function (maxLines) {
+ var self = this;
+
+ /**
+ * @var {int} minLine The first line in the selection, or null if no lines selected.
+ */
+ self.minLine = null;
+
+ /**
+ * @var {int} maxLine The last line in the selection, or null if no lines selected.
+ */
+ self.maxLine = null;
+
+ /**
+ * Parse line numbers from a URL hash.
+ * @param {string} hash the URL hash to parse.
+ */
+ self.parseFromUrlHash = function (hash) {
+ self.minLine = null;
+ self.maxLine = null;
+
+ // parse hash
+ var hashParts = hash.match(/^#L(\d+)(?:-L(\d+))?$/);
+ if (!hashParts || hashParts.length <= 1)
+ return;
+
+ // extract min/max lines
+ self.minLine = parseInt(hashParts[1]);
+ self.maxLine = parseInt(hashParts[2]) || self.minLine;
+ };
+
+ /**
+ * Generate a URL hash for the current line range.
+ * @returns {string} The generated URL hash.
+ */
+ self.buildHash = function() {
+ if (!self.minLine)
+ return "";
+ else if (self.minLine === self.maxLine)
+ return "#L" + self.minLine;
+ else
+ return "#L" + self.minLine + "-L" + self.maxLine;
+ }
+
+ /**
+ * Get a list of all selected lines.
+ * @returns {Array<int>} The selected line numbers.
+ */
+ self.getLinesSelected = function() {
+ // format
+ if (!self.minLine)
+ return [];
+
+ var lines = [];
+ for (var i = self.minLine; i <= self.maxLine; i++)
+ lines.push(i);
+ return lines;
+ };
+
+ return self;
+};
+
+/**
+ * UI logic for the JSON validator page.
+ * @param {any} sectionUrl The base JSON validator page URL.
+ * @param {any} pasteID The Pastebin paste ID for the content being viewed, if any.
+ */
+smapi.jsonValidator = function (sectionUrl, pasteID) {
+ /**
+ * The original content element.
+ */
+ var originalContent = $("#raw-content").clone();
+
+ /**
+ * The currently highlighted lines.
+ */
+ var selection = new smapi.LineNumberRange();
+
+ /**
+ * Rebuild the syntax-highlighted element.
+ */
+ var formatCode = function () {
+ // reset if needed
+ $(".sunlight-container").replaceWith(originalContent.clone());
+
+ // apply default highlighting
+ Sunlight.highlightAll({
+ lineHighlight: selection.getLinesSelected()
+ });
+
+ // fix line links
+ $(".sunlight-line-number-margin a").each(function() {
+ var link = $(this);
+ var lineNumber = parseInt(link.text());
+ link
+ .attr("id", "L" + lineNumber)
+ .attr("href", "#L" + lineNumber)
+ .removeAttr("name")
+ .data("line-number", lineNumber);
+ });
+ };
+
+ /**
+ * Scroll the page so the selected range is visible.
+ */
+ var scrollToRange = function() {
+ if (!selection.minLine)
+ return;
+
+ var targetLine = Math.max(1, selection.minLine - 5);
+ $("#L" + targetLine).get(0).scrollIntoView();
+ };
+
+ /**
+ * Initialize the JSON validator page.
+ */
+ var init = function () {
+ // set initial code formatting
+ selection.parseFromUrlHash(location.hash);
+ formatCode();
+ scrollToRange();
+
+ // update code formatting on hash change
+ $(window).on("hashchange", function() {
+ selection.parseFromUrlHash(location.hash);
+ formatCode();
+ scrollToRange();
+ });
+
+ // change format
+ $("#output #format").on("change", function() {
+ var schemaName = $(this).val();
+ location.href = new URL(schemaName + "/" + pasteID, sectionUrl).toString();
+ });
+
+ // upload form
+ var input = $("#input");
+ if (input.length) {
+ // disable submit if it's empty
+ var toggleSubmit = function () {
+ var hasText = !!input.val().trim();
+ submit.prop("disabled", !hasText);
+ };
+ input.on("input", toggleSubmit);
+ toggleSubmit();
+
+ // drag & drop file
+ input.on({
+ 'dragover dragenter': function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ },
+ 'drop': function (e) {
+ var dataTransfer = e.originalEvent.dataTransfer;
+ if (dataTransfer && dataTransfer.files.length) {
+ e.preventDefault();
+ e.stopPropagation();
+ var file = dataTransfer.files[0];
+ var reader = new FileReader();
+ reader.onload = $.proxy(function (file, $input, event) {
+ $input.val(event.target.result);
+ toggleSubmit();
+ }, this, file, $("#input"));
+ reader.readAsText(file);
+ }
+ }
+ });
+ }
+ };
+ init();
+};
diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js
index e87a1a5c..e6c7591c 100644
--- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js
+++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js
@@ -23,7 +23,7 @@ smapi.logParser = function (data, sectionUrl) {
}
// set local time started
- if(data)
+ if (data)
data.localTimeStarted = ("0" + data.logStarted.getHours()).slice(-2) + ":" + ("0" + data.logStarted.getMinutes()).slice(-2);
// init app
@@ -100,7 +100,7 @@ smapi.logParser = function (data, sectionUrl) {
updateModFilters();
},
- filtersAllow: function(modId, level) {
+ filtersAllow: function (modId, level) {
return this.showMods[modId] !== false && this.showLevels[level] !== false;
},
@@ -121,16 +121,15 @@ smapi.logParser = function (data, sectionUrl) {
var submit = $("#submit");
// instruction OS chooser
- var chooseSystem = function() {
+ var chooseSystem = function () {
systemInstructions.hide();
systemInstructions.filter("[data-os='" + $("input[name='os']:checked").val() + "']").show();
- }
+ };
systemOptions.on("click", chooseSystem);
chooseSystem();
// disable submit if it's empty
- var toggleSubmit = function()
- {
+ var toggleSubmit = function () {
var hasText = !!input.val().trim();
submit.prop("disabled", !hasText);
}
@@ -139,18 +138,18 @@ smapi.logParser = function (data, sectionUrl) {
// drag & drop file
input.on({
- 'dragover dragenter': function(e) {
+ 'dragover dragenter': function (e) {
e.preventDefault();
e.stopPropagation();
},
- 'drop': function(e) {
+ 'drop': function (e) {
var dataTransfer = e.originalEvent.dataTransfer;
if (dataTransfer && dataTransfer.files.length) {
e.preventDefault();
e.stopPropagation();
var file = dataTransfer.files[0];
var reader = new FileReader();
- reader.onload = $.proxy(function(file, $input, event) {
+ reader.onload = $.proxy(function (file, $input, event) {
$input.val(event.target.result);
toggleSubmit();
}, this, file, $("#input"));
diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js
index 130f60be..0394ac4f 100644
--- a/src/SMAPI.Web/wwwroot/Content/js/mods.js
+++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js
@@ -44,6 +44,7 @@ smapi.modList = function (mods, enableBeta) {
download: {
value: {
chucklefish: { value: true, label: "Chucklefish" },
+ curseforge: { value: true, label: "CurseForge" },
moddrop: { value: true, label: "ModDrop" },
nexus: { value: true, label: "Nexus" },
custom: { value: true }
@@ -180,6 +181,8 @@ smapi.modList = function (mods, enableBeta) {
if (!filters.download.value.chucklefish.value)
ignoreSites.push("Chucklefish");
+ if (!filters.download.value.curseforge.value)
+ ignoreSites.push("CurseForge");
if (!filters.download.value.moddrop.value)
ignoreSites.push("ModDrop");
if (!filters.download.value.nexus.value)
diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json
index d0c55552..78918bac 100644
--- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json
+++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json
@@ -14,11 +14,6 @@
* 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.
@@ -59,15 +54,15 @@
"Default | UpdateKey": "Nexus:2270"
},
- "Content Patcher": {
- "ID": "Pathoschild.ContentPatcher",
- "Default | UpdateKey": "Nexus:1915"
- },
+ //"Content Patcher": {
+ // "ID": "Pathoschild.ContentPatcher",
+ // "Default | UpdateKey": "Nexus:1915"
+ //},
- "Custom Farming Redux": {
- "ID": "Platonymous.CustomFarming",
- "Default | UpdateKey": "Nexus:991"
- },
+ //"Custom Farming Redux": {
+ // "ID": "Platonymous.CustomFarming",
+ // "Default | UpdateKey": "Nexus:991"
+ //},
"Custom Shirts": {
"ID": "Platonymous.CustomShirts",
@@ -122,116 +117,175 @@
"Default | UpdateKey": "Nexus:1820"
},
+ /*********
+ ** Obsolete
+ *********/
+ "Animal Mood Fix": {
+ "ID": "GPeters-AnimalMoodFix",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
+ },
+
+ "Bee House Flower Range Fix": {
+ "ID": "kirbylink.beehousefix",
+ "~ | Status": "Obsolete",
+ "~ | StatusReasonPhrase": "the bee house flower range was fixed in Stardew Valley 1.4."
+ },
+
+ "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."
+ },
/*********
- ** Map versions
+ ** Broke in SDV 1.4
*********/
- "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" }
+ "Fix Dice": {
+ "ID": "ashley.fixdice",
+ "~1.1.2 | Status": "AssumeBroken" // crashes game on startup
+ },
+
+ "Fix Dice": {
+ "ID": "ashley.fixdice",
+ "~1.1.2 | Status": "AssumeBroken" // crashes game on startup
+ },
+
+ "Grass Growth": {
+ "ID": "bcmpinc.GrassGrowth",
+ "~1.0 | Status": "AssumeBroken"
+ },
+
+ "Invite Code Mod": {
+ "ID": "KOREJJamJar.InviteCodeMod",
+ "~1.0.1 | Status": "AssumeBroken"
+ },
+
+ "Loved Labels": {
+ "ID": "Advize.LovedLabels",
+ "~2.2.1-unofficial.2-pathoschild | Status": "AssumeBroken"
},
- "Almighty Farming Tool": {
- "ID": "439",
- "MapRemoteVersions": {
- "1.21": "1.2.1",
- "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion"
- }
+ "Neat Additions": {
+ "ID": "ilyaki.neatadditions",
+ "~1.0.3 | Status": "AssumeBroken"
},
- "Basic Sprinkler Improved": {
- "ID": "lrsk_sdvm_bsi.0117171308",
- "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated
+ "Remote Fridge Storage": {
+ "ID": "EternalSoap.RemoteFridgeStorage",
+ "~1.5 | Status": "AssumeBroken"
},
- "Better Shipping Box": {
- "ID": "Kithio:BetterShippingBox",
- "MapLocalVersions": { "1.0.1": "1.0.2" }
+ "Stack Everything": {
+ "ID": "cat.stackeverything",
+ "~2.15 | Status": "AssumeBroken"
},
- "Chefs Closet": {
- "ID": "Duder.ChefsCloset",
- "MapLocalVersions": { "1.3-1": "1.3" }
+ "Yet Another Harvest With Scythe Mod": {
+ "ID": "bcmpinc.HarvestWithScythe",
+ "~1.1 | Status": "AssumeBroken"
},
- "Configurable Machines": {
- "ID": "21da6619-dc03-4660-9794-8e5b498f5b97",
- "MapLocalVersions": { "1.2-beta": "1.2" }
+ /*********
+ ** Broke in SMAPI 3.0 (runtime errors due to lifecycle changes)
+ *********/
+ "Advancing Sprinklers": {
+ "ID": "warix3.advancingsprinklers",
+ "~1.0.0 | Status": "AssumeBroken"
},
- "Crafting Counter": {
- "ID": "lolpcgaming.CraftingCounter",
- "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest
+ "Arcade 2048": {
+ "ID": "Platonymous.2048",
+ "~1.0.6 | Status": "AssumeBroken" // possibly due to PyTK
},
- "Custom Linens": {
- "ID": "Mevima.CustomLinens",
- "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated
+ "Arcade Snake": {
+ "ID": "Platonymous.Snake",
+ "~1.1.0 | Status": "AssumeBroken" // possibly due to PyTK
},
- "Dynamic Horses": {
- "ID": "Bpendragon-DynamicHorses",
- "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated
+ "Better Sprinklers": {
+ "ID": "Speeder.BetterSprinklers",
+ "~2.3.1-unofficial.7-pathoschild | Status": "AssumeBroken"
},
- "Dynamic Machines": {
- "ID": "DynamicMachines",
- "MapLocalVersions": { "1.1": "1.1.1" }
+ "Content Patcher": {
+ "ID": "Pathoschild.ContentPatcher",
+ "Default | UpdateKey": "Nexus:1915",
+ "~1.6.4 | Status": "AssumeBroken"
},
- "Multiple Sprites and Portraits On Rotation (File Loading)": {
- "ID": "FileLoading",
- "MapLocalVersions": { "1.1": "1.12" }
+ "Current Location (Vrakyas)": {
+ "ID": "Vrakyas.CurrentLocation",
+ "~1.5.4 | Status": "AssumeBroken"
},
- "Relationship Status": {
- "ID": "relationshipstatus",
- "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest
+ "Custom Adventure Guild Challenges": {
+ "ID": "DefenTheNation.CustomGuildChallenges",
+ "~1.8 | Status": "AssumeBroken"
},
- "ReRegeneration": {
- "ID": "lrsk_sdvm_rerg.0925160827",
- "MapLocalVersions": { "1.1.2-release": "1.1.2" }
+ "Custom Farming Redux": {
+ "ID": "Platonymous.CustomFarming",
+ "Default | UpdateKey": "Nexus:991",
+ "~2.10.10 | Status": "AssumeBroken" // possibly due to PyTK
},
- "Showcase Mod": {
- "ID": "Igorious.Showcase",
- "MapLocalVersions": { "0.9-500": "0.9" }
+ "Decrafting Mod": {
+ "ID": "MSCFC.DecraftingMod",
+ "~1.0 | Status": "AssumeBroken" // NRE in ModEntry
},
- "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" }
+ "JoJaBan - Arcade Sokoban": {
+ "ID": "Platonymous.JoJaBan",
+ "~0.4.3 | Status": "AssumeBroken" // possibly due to PyTK
},
+ "Level Extender": {
+ "ID": "DevinLematty.LevelExtender",
+ "~3.1 | Status": "AssumeBroken"
+ },
- /*********
- ** Obsolete
- *********/
- "Animal Mood Fix": {
- "ID": "GPeters-AnimalMoodFix",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
+ "Mod Update Menu": {
+ "ID": "cat.modupdatemenu",
+ "~1.4 | Status": "AssumeBroken"
},
- "Colored Chests": {
- "ID": "4befde5c-731c-4853-8e4b-c5cdf946805f",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1."
+ "Quick Start": {
+ "ID": "WuestMan.QuickStart",
+ "~1.5 | Status": "AssumeBroken"
},
- "Modder Serialization Utility": {
- "ID": "SerializerUtils-0-1",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "it's no longer maintained or used."
+ "Seed Bag": {
+ "ID": "Platonymous.SeedBag",
+ "~1.2.7 | Status": "AssumeBroken" // possibly due to PyTK
},
- "No Debug Mode": {
- "ID": "NoDebugMode",
- "~ | Status": "Obsolete",
- "~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0."
+ "Stardew Valley ESP": {
+ "ID": "reimu.sdv-helper",
+ "~1.1 | Status": "AssumeBroken"
+ },
+
+ "Underdark Krobus": {
+ "ID": "melnoelle.underdarkkrobus",
+ "~1.0.0 | Status": "AssumeBroken" // NRE in ModEntry
+ },
+
+ "Underdark Sewer": {
+ "ID": "melnoelle.underdarksewer",
+ "~1.1.0 | Status": "AssumeBroken" // NRE in ModEntry
},
/*********
@@ -349,11 +403,6 @@
"~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
@@ -374,12 +423,6 @@
"~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
@@ -398,7 +441,6 @@
"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)
},
@@ -418,11 +460,6 @@
"~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
*********/
diff --git a/src/SMAPI.Web/wwwroot/schemas/content-patcher.json b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json
new file mode 100644
index 00000000..61a633cb
--- /dev/null
+++ b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json
@@ -0,0 +1,389 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://smapi.io/schemas/content-patcher.json",
+ "title": "Content Patcher content pack",
+ "description": "Content Patcher content file for mods",
+ "@documentationUrl": "https://github.com/Pathoschild/StardewMods/tree/develop/ContentPatcher#readme",
+ "type": "object",
+
+ "properties": {
+ "Format": {
+ "title": "Format version",
+ "description": "The format version. You should always use the latest version to enable the latest features and avoid obsolete behavior.",
+ "type": "string",
+ "const": "1.9",
+ "@errorMessages": {
+ "const": "Incorrect value '@value'. This should be set to the latest format version, currently '1.9'."
+ }
+ },
+ "ConfigSchema": {
+ "title": "Config schema",
+ "description": "Defines the config.json format, to support more complex mods.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "AllowValues": {
+ "title": "Allowed values",
+ "description": "The values the player can provide, as a comma-delimited string. If omitted, any value is allowed.\nTip: for a boolean flag, use \"true, false\".",
+ "type": "string"
+ },
+ "AllowBlank": {
+ "title": "Allow blank",
+ "description": "Whether the field can be left blank. If false or omitted, blank fields will be replaced with the default value.",
+ "type": "boolean"
+ },
+ "AllowMultiple": {
+ "title": "Allow multiple values",
+ "description": "Whether the player can specify multiple comma-delimited values. Default false.",
+ "type": "boolean"
+ },
+ "Default": {
+ "title": "Default value",
+ "description": "The default values when the field is missing. Can contain multiple comma-delimited values if AllowMultiple is true. If omitted, blank fields are left blank.",
+ "type": "string"
+ },
+
+ "additionalProperties": false
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "AllowBlank": { "const": false }
+ },
+ "required": [ "AllowBlank" ]
+ },
+ "then": {
+ "required": [ "Default" ]
+ }
+ }
+ ],
+
+ "@errorMessages": {
+ "allOf": "If 'AllowBlank' is false, the 'Default' field is required."
+ }
+ }
+ },
+ "DynamicTokens": {
+ "title": "Dynamic tokens",
+ "description": "Custom tokens that you can use.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "Name": {
+ "title": "Name",
+ "description": "The name of the token to use for tokens & conditions.",
+ "type": "string"
+ },
+ "Value": {
+ "title": "Token value",
+ "description": "The value(s) to set. This can be a comma-delimited value to give it multiple values. If any block for a token name has multiple values, it will only be usable in conditions. This field supports tokens, including dynamic tokens defined before this entry.",
+ "type": "string"
+ },
+ "When": {
+ "title": "When",
+ "description": "Only set the value if the given conditions match. If not specified, always matches.",
+ "$ref": "#/definitions/Condition"
+ }
+ },
+
+ "required": [ "Name", "Value" ],
+ "additionalProperties": false
+ }
+ },
+ "Changes": {
+ "title": "Changes",
+ "description": "The changes you want to make. Each entry is called a patch, and describes a specific action to perform: replace this file, copy this image into the file, etc. You can list any number of patches.",
+ "type": "array",
+ "items": {
+ "properties": {
+ "Action": {
+ "title": "Action",
+ "description": "The kind of change to make.",
+ "type": "string",
+ "enum": [ "Load", "EditImage", "EditData", "EditMap" ]
+ },
+ "Target": {
+ "title": "Target asset",
+ "description": "The game asset you want to patch (or multiple comma-delimited assets). This is the file path inside your game's Content folder, without the file extension or language (like Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb). This field supports tokens and capitalization doesn't matter. Your changes are applied in all languages unless you specify a language condition.",
+ "type": "string",
+ "not": {
+ "pattern": "^ *[cC][oO][nN][tT][eE][nN][tT]/|\\.[xX][nN][bB] *$|\\.[a-zA-Z][a-zA-Z]-[a-zA-Z][a-zA-Z](?:.xnb)? *$"
+ },
+ "@errorMessages": {
+ "not": "Invalid target; it shouldn't include the 'Content/' folder, '.xnb' extension, or locale code."
+ }
+ },
+ "LogName": {
+ "title": "Patch log name",
+ "description": "A name for this patch shown in log messages. This is very useful for understanding errors; if not specified, will default to a name like 'entry #14 (EditImage Animals/Dinosaurs)'.",
+ "type": "string"
+ },