Merge branch 'develop' into stable

This commit is contained in:
Jesse Plamondon-Willard 2019-03-01 14:10:46 -05:00
commit 10c7192bb9
No known key found for this signature in database
GPG Key ID: 7D7C8097B62033CE
18 changed files with 340 additions and 247 deletions

View File

@ -1,5 +1,5 @@
using System.Reflection;
[assembly: AssemblyProduct("SMAPI")]
[assembly: AssemblyVersion("2.10.2")]
[assembly: AssemblyFileVersion("2.10.2")]
[assembly: AssemblyVersion("2.11.0")]
[assembly: AssemblyFileVersion("2.11.0")]

View File

@ -1,6 +1,20 @@
# Release notes
## 2.11
Released 01 March 2019 for Stardew Valley 1.3.36.
* For players:
* Updated for Stardew Valley 1.3.36.
* For modders:
* Bumped all deprecation levels to _pending removal_.
* For the web UI:
* The log parser now shows available updates in a section at the top.
* The mod compatibility page now crosses out mod links if they're outdated to avoid confusion.
* Fixed smapi.io linking to an archived download in rare cases.
## 2.10.2
Released 08 January 2019 for Stardew Valley 1.3.3233.
Released 09 January 2019 for Stardew Valley 1.3.3233.
* For players:
* SMAPI now keeps the first save backup created for the day, instead of the last one.

View File

@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
"Version": "2.10.2",
"Version": "2.11.0",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
"MinimumApiVersion": "2.10.2"
"MinimumApiVersion": "2.11.0"
}

View File

@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
"Version": "2.10.2",
"Version": "2.11.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
"MinimumApiVersion": "2.10.2"
"MinimumApiVersion": "2.11.0"
}

View File

@ -141,6 +141,9 @@ namespace StardewModdingAPI.Web.Controllers
foreach (GitAsset asset in release.Assets)
{
if (asset.FileName.StartsWith("Z_OLD"))
continue;
Match match = Regex.Match(asset.FileName, @"SMAPI-(?<version>[\d\.]+(?:-.+)?)-installer(?<forDevs>-for-developers)?.zip");
if (!match.Success || !SemanticVersion.TryParse(match.Groups["version"].Value, out ISemanticVersion version))
continue;

View File

@ -39,6 +39,15 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
/// <summary>A regex pattern matching an entry in SMAPI's content pack list.</summary>
private readonly Regex ContentPackListEntryPattern = new Regex(@"^ (?<name>.+) (?<version>.+) by (?<author>.+) \| for (?<for>.+?)(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching the start of SMAPI's mod update list.</summary>
private readonly Regex ModUpdateListStartPattern = new Regex(@"^You can update \d+ mods?:$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching an entry in SMAPI's mod update list.</summary>
private readonly Regex ModUpdateListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching SMAPI's update line.</summary>
private readonly Regex SMAPIUpdatePattern = new Regex(@"^You can update SMAPI to (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/*********
** Public methods
@ -69,11 +78,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
};
// parse log messages
LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "" };
LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "" };
LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "", Loaded = true };
LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "", Loaded = true };
IDictionary<string, LogModInfo> mods = new Dictionary<string, LogModInfo>();
bool inModList = false;
bool inContentPackList = false;
bool inModUpdateList = false;
foreach (LogMessage message in log.Messages)
{
// collect stats
@ -90,11 +100,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
break;
default:
{
if (mods.ContainsKey(message.Mod))
mods[message.Mod].Errors++;
break;
}
}
}
@ -106,6 +114,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
inModList = false;
if (inContentPackList && !this.ContentPackListEntryPattern.IsMatch(message.Text))
inContentPackList = false;
if (inModUpdateList && !this.ModUpdateListEntryPattern.IsMatch(message.Text))
inModUpdateList = false;
// mod list
if (!inModList && message.Level == LogLevel.Info && this.ModListStartPattern.IsMatch(message.Text))
@ -117,7 +127,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string version = match.Groups["version"].Value;
string author = match.Groups["author"].Value;
string description = match.Groups["description"].Value;
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description };
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true };
}
// content pack list
@ -131,7 +141,36 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string author = match.Groups["author"].Value;
string description = match.Groups["description"].Value;
string forMod = match.Groups["for"].Value;
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod };
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true };
}
// mod update list
else if (!inModUpdateList && message.Level == LogLevel.Alert && this.ModUpdateListStartPattern.IsMatch(message.Text))
inModUpdateList = true;
else if (inModUpdateList)
{
Match match = this.ModUpdateListEntryPattern.Match(message.Text);
string name = match.Groups["name"].Value;
string version = match.Groups["version"].Value;
string link = match.Groups["link"].Value;
if (mods.ContainsKey(name))
{
mods[name].UpdateLink = link;
mods[name].UpdateVersion = version;
}
else
{
mods[name] = new LogModInfo { Name = name, UpdateVersion = version, UpdateLink = link, Loaded = false };
}
}
else if (message.Level == LogLevel.Alert && this.SMAPIUpdatePattern.IsMatch(message.Text))
{
Match match = this.SMAPIUpdatePattern.Match(message.Text);
string version = match.Groups["version"].Value;
string link = match.Groups["link"].Value;
smapiMod.UpdateVersion = version;
smapiMod.UpdateLink = link;
}
// platform info line

View File

@ -12,6 +12,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The mod author.</summary>
public string Author { get; set; }
/// <summary>The update version.</summary>
public string UpdateVersion { get; set; }
/// <summary>The update link.</summary>
public string UpdateLink { get; set; }
/// <summary>The mod version.</summary>
public string Version { get; set; }
@ -23,5 +29,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The number of errors logged by this mod.</summary>
public int Errors { get; set; }
/// <summary>Whether the mod was loaded into the game.</summary>
public bool Loaded { get; set; }
/// <summary>Whether the mod has an update available.</summary>
public bool HasUpdate => this.UpdateVersion != null && this.Version != this.UpdateVersion;
}
}

View File

@ -17,10 +17,10 @@
{
<meta name="robots" content="noindex" />
}
<link rel="stylesheet" href="~/Content/css/log-parser.css?r=20180627" />
<link rel="stylesheet" href="~/Content/css/log-parser.css?r=20190221" />
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js" crossorigin="anonymous"></script>
<script src="~/Content/js/log-parser.js?r=20180627"></script>
<script src="~/Content/js/log-parser.js?r=20190221"></script>
<script>
$(function() {
smapi.logParser({
@ -117,9 +117,61 @@ else if (Model.ParsedLog?.IsValid == true)
@* parsed log *@
@if (Model.ParsedLog?.IsValid == true)
{
<h2>Log info</h2>
<div id="output">
<table id="metadata">
@if (Model.ParsedLog.Mods.Any(mod => mod.HasUpdate))
{
<h2>Suggested fixes</h2>
<ul id="fix-list">
<li>
Consider updating these mods to fix problems:
<table id="updates" class="table">
@foreach (LogModInfo mod in Model.ParsedLog.Mods.Where(mod => (mod.HasUpdate && mod.ContentPackFor == null) || (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
{
<tr class="mod-entry">
<td>
<strong class=@(!mod.HasUpdate ? "hidden" : "")>@mod.Name</strong>
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
{
<div class="content-packs">
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
{
<text>+ @contentPack.Name</text><br/>
}
</div>
}
</td>
<td>
@if (mod.HasUpdate)
{
<a href="@mod.UpdateLink" target="_blank">
@(mod.Version == null ? @mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
</a>
}
else
{
<text>&nbsp;</text>
}
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
{
<div>
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
{
<a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br/>
}
</div>
}
</td>
</tr>
}
</table>
</li>
</ul>
}
<h2>Log info</h2>
<table id="metadata" class="table">
<caption>Game info:</caption>
<tr>
<th>Stardew Valley:</th>
@ -139,7 +191,7 @@ else if (Model.ParsedLog?.IsValid == true)
</tr>
</table>
<br />
<table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null)">
<table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null) table">
<caption>
Installed mods:
@if (!Model.ShowRaw)
@ -149,7 +201,7 @@ else if (Model.ParsedLog?.IsValid == true)
<span class="notice btn txt" v-on:click="hideAllMods" v-bind:class="{ invisible: !anyModsShown || !anyModsHidden }">hide all</span>
}
</caption>
@foreach (var mod in Model.ParsedLog.Mods.Where(p => p.ContentPackFor == null))
@foreach (var mod in Model.ParsedLog.Mods.Where(p => p.Loaded && p.ContentPackFor == null))
{
<tr v-on:click="toggleMod('@Model.GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@Model.GetSlug(mod.Name)'] }">
<td><input type="checkbox" v-bind:checked="showMods['@Model.GetSlug(mod.Name)']" v-bind:class="{ invisible: !anyModsHidden }" /></td>

View File

@ -13,6 +13,13 @@ caption {
#output {
padding: 10px;
overflow: auto;
}
#output h2 {
margin: -10px 0 10px -10px;
}
#output table {
font-family: monospace;
}
@ -43,7 +50,7 @@ table caption {
/*********
** Log metadata & filters
*********/
#metadata, #mods, #filters {
.table, #filters {
border-bottom: 1px dashed #888888;
margin-bottom: 5px;
}
@ -53,7 +60,7 @@ table caption {
padding-right: 0.7em;
}
table#metadata, table#mods {
.table {
border: 1px solid #000000;
background: #ffffff;
border-radius: 5px;
@ -63,8 +70,20 @@ table#metadata, table#mods {
box-shadow: 1px 1px 1px 1px #dddddd;
}
.invisible {
visibility: hidden;
.mod-entry {
height: 1.8em;
}
.table > caption {
min-height: 1.3em;
}
#fix-list {
margin-bottom: 2em;
}
#updates {
min-width: 10em;
}
#mods {
@ -87,8 +106,7 @@ table#metadata, table#mods {
cursor: default;
}
#metadata tr,
#mods tr {
.table tr {
background: #eee
}
@ -114,11 +132,11 @@ table#metadata, table#mods {
display: inline-block;
}
#mods .mod-entry.hidden {
.table .hidden {
opacity: 0.5;
}
#mods .content-packs {
.table .content-packs {
margin-left: 1em;
font-size: 0.9em;
font-style: italic;
@ -128,8 +146,7 @@ table#metadata, table#mods {
padding-right: 5px;
}
#metadata tr:nth-child(even),
#mods tr:nth-child(even) {
.table tr:nth-child(even) {
background: #fff
}

View File

@ -128,8 +128,10 @@ table.wikitable > caption {
opacity: 0.7;
}
#mod-list .mod-closed-source {
color: red;
font-size: 0.8em;
opacity: 0.5;
#mod-list tr[data-status="abandoned"] .mod-page-links,
#mod-list tr[data-status="broken"] .mod-page-links,
#mod-list tr[data-status="obsolete"] .mod-page-links,
#mod-list tr[data-status="unofficial"] .mod-page-links,
#mod-list tr[data-status="workaround"] .mod-page-links {
text-decoration: line-through;
}

View File

@ -115,22 +115,9 @@
"Default | UpdateKey": "Nexus:1820"
},
/*********
** Content packs
*********/
"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
},
/*********
** Mods
** Map versions
*********/
"Adjust Artisan Prices": {
"ID": "ThatNorthernMonkey.AdjustArtisanPrices",
@ -146,28 +133,6 @@
}
},
"Always Scroll Map": {
"ID": "bcmpinc.AlwaysScrollMap",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Animal Mood Fix": {
"ID": "GPeters-AnimalMoodFix",
"~ | Status": "Obsolete",
"~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2."
},
"Arcade Pong": {
"ID": "Platonymous.ArcadePong",
"~1.0.2 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
},
"Automated Doors": {
"ID": "azah.automated-doors",
"FormerIDs": "1abcfa07-2cf4-4dc3-a6e9-6068b642112b", // changed in 1.4.1
"Default | UpdateKey": "GitHub:azah/AutomatedDoors" // added in 1.4.2
},
"Basic Sprinklers Improved": {
"ID": "lrsk_sdvm_bsi.0117171308",
"MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated
@ -184,11 +149,6 @@
"MapRemoteVersions": { "1.3.1": "1.3" } // manifest not updated
},
"BJS Night Sounds": {
"ID": "BunnyJumps.BJSNightSounds",
"~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
},
"Casks Anywhere": {
"ID": "CasksAnywhere",
"MapLocalVersions": { "1.1-alpha": "1.1" }
@ -199,43 +159,21 @@
"MapLocalVersions": { "1.3-1": "1.3" }
},
"Chest Pooling": {
"ID": "mralbobo.ChestPooling",
"Default | UpdateKey": "GitHub:mralbobo/stardew-chest-pooling"
},
"Cobalt": {
"ID": "spacechase0.Cobalt",
"MapRemoteVersions": { "1.1.3": "1.1.2" } // not updated in manifest
},
"Colored Chests": {
"ID": "4befde5c-731c-4853-8e4b-c5cdf946805f",
"~ | Status": "Obsolete",
"~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1."
},
"Configurable Machines": {
"ID": "21da6619-dc03-4660-9794-8e5b498f5b97",
"MapLocalVersions": { "1.2-beta": "1.2" }
},
"Craft Counter": {
"ID": "bcmpinc.CraftCounter",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Crafting Counter": {
"ID": "lolpcgaming.CraftingCounter",
"MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest
},
"Custom Farming Automate Bridge": {
"ID": "Platonymous.CFAutomate",
"~1.0.1 | Status": "AssumeBroken", // no longer compatible with Automate
"~1.0.1 | AlternativeUrl": "https://www.nexusmods.com/stardewvalley/mods/991"
},
"Customizable Cart Redux": {
"ID": "KoihimeNakamura.CCR",
"MapLocalVersions": { "1.1-20170917": "1.1" }
@ -256,14 +194,138 @@
"MapLocalVersions": { "1.1": "1.1.1" }
},
"Enemy Health Bars": {
"ID": "Speeder.HealthBars",
"FormerIDs": "SPDHealthBar" // changed in 1.7.1-pathoschild-update
"Hunger Mod (skn)": {
"ID": "skn.HungerMod",
"MapRemoteVersions": { "1.2.1": "1.0" } // manifest not updated
},
"Fall 28 Snow Day": {
"ID": "Omegasis.Fall28SnowDay",
"~1.4.1 | Status": "AssumeBroken" // broke in SMAPI 2.0, and update for SMAPI 2.0 doesn't do anything
"Idle Pause": {
"ID": "Veleek.IdlePause",
"MapRemoteVersions": { "1.2": "1.1" } // manifest not updated
},
"Item Auto Stacker": {
"ID": "cat.autostacker",
"MapRemoteVersions": { "1.0.1": "1.0" } // manifest not updated
},
"Move Faster": {
"ID": "shuaiz.MoveFasterMod",
"~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?)
},
"Multiple Sprites and Portraits On Rotation (File Loading)": {
"ID": "FileLoading",
"MapLocalVersions": { "1.1": "1.12" }
},
"Night Owl": {
"ID": "Omegasis.NightOwl",
"MapLocalVersions": { "2.1": "1.3" } // 1.3 had wrong version in manifest
},
"Point-and-Plant": {
"ID": "jwdred.PointAndPlant",
"MapRemoteVersions": { "1.0.3": "1.0.2" } // manifest not updated
},
"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" }
},
"Shop Expander": {
"ID": "Entoarox.ShopExpander",
"FormerIDs": "EntoaroxShopExpander", // changed in 1.5.2
"MapRemoteVersions": { "1.6.0b": "1.6.0" }
},
"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" }
},
"Solar Eclipse Event": {
"ID": "KoihimeNakamura.SolarEclipseEvent",
"MapLocalVersions": { "1.3.1-20180131": "1.3.1" }
},
"Time Reminder": {
"ID": "KoihimeNakamura.TimeReminder",
"MapLocalVersions": { "1.0-20170314": "1.0.2" }
},
/*********
** 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 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": {
@ -286,131 +348,31 @@
"~0.3 | Status": "AssumeBroken" // broke in 1.3: Exception from HarmonyInstance "bcmpinc.FixScytheExp" [...] Bad label content in ILGenerator.
},
"Gate Opener": {
"ID": "mralbobo.GateOpener",
"Default | UpdateKey": "GitHub:mralbobo/stardew-gate-opener"
},
"Grass Growth": {
"ID": "bcmpinc.GrassGrowth",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Hunger Mod (skn)": {
"ID": "skn.HungerMod",
"MapRemoteVersions": { "1.2.1": "1.0" } // manifest not updated
},
"Idle Pause": {
"ID": "Veleek.IdlePause",
"MapRemoteVersions": { "1.2": "1.1" } // manifest not updated
},
"Item Auto Stacker": {
"ID": "cat.autostacker",
"MapRemoteVersions": { "1.0.1": "1.0" } // manifest not updated
},
"Modder Serialization Utility": {
"ID": "SerializerUtils-0-1",
"~ | Status": "Obsolete",
"~ | StatusReasonPhrase": "it's no longer maintained or used."
},
"More Rain": {
"ID": "Omegasis.MoreRain",
"~1.4 | Status": "AssumeBroken" // broke in SMAPI 2.0
},
"More Silo Storage": {
"ID": "OrneryWalrus.MoreSiloStorage",
"~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3
},
"Move Faster": {
"ID": "shuaiz.MoveFasterMod",
"~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?)
},
"Movement Speed": {
"ID": "bcmpinc.MovementSpeed",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Multiple Sprites and Portraits On Rotation (File Loading)": {
"ID": "FileLoading",
"MapLocalVersions": { "1.1": "1.12" }
},
"Night Owl": {
"ID": "Omegasis.NightOwl",
"MapLocalVersions": { "2.1": "1.3" } // 1.3 had wrong version in manifest
},
"No Added Flying Mine Monsters": {
"ID": "Drynwynn.NoAddedFlyingMineMonsters",
"~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+
},
"No Debug Mode": {
"ID": "NoDebugMode",
"~ | Status": "Obsolete",
"~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0."
},
"OmniFarm": {
"ID": "PhthaloBlue.OmniFarm",
"FormerIDs": "BlueMod_OmniFarm", // changed in 2.0.2-pathoschild-update
"Default | UpdateKey": "GitHub:lambui/StardewValleyMod_OmniFarm"
},
"Point-and-Plant": {
"ID": "jwdred.PointAndPlant",
"MapRemoteVersions": { "1.0.3": "1.0.2" } // manifest not updated
},
"Prairie King Made Easy": {
"ID": "Mucchan.PrairieKingMadeEasy",
"~1.0 | Status": "AssumeBroken" // broke in SDV 1.2
},
"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" }
},
"Save Backup": {
"ID": "Omegasis.SaveBackup",
"~1.2 | Status": "AssumeBroken" // broke in SMAPI 2.0
},
"Server Bookmarker": {
"ID": "Ilyaki.ServerBookmarker",
"~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors)
},
"Shop Expander": {
"ID": "Entoarox.ShopExpander",
"FormerIDs": "EntoaroxShopExpander", // changed in 1.5.2
"MapRemoteVersions": { "1.6.0b": "1.6.0" }
},
"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" }
},
"Skill Prestige: Cooking Adapter": {
"ID": "Alphablackwolf.CookingSkillPrestigeAdapter",
"FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1
@ -423,11 +385,6 @@
"1.3-beta | Status": "AssumeBroken" // doesn't work in multiplayer, no longer maintained
},
"Solar Eclipse Event": {
"ID": "KoihimeNakamura.SolarEclipseEvent",
"MapLocalVersions": { "1.3.1-20180131": "1.3.1" }
},
"Split Screen": {
"ID": "Ilyaki.SplitScreen",
"~3.0.1 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals
@ -438,11 +395,6 @@
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Stardew Notification": {
"ID": "stardewnotification",
"Default | UpdateKey": "GitHub:monopandora/StardewNotification"
},
"Stephan's Lots of Crops": {
"ID": "stephansstardewcrops",
"MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated
@ -460,35 +412,14 @@
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Time Reminder": {
"ID": "KoihimeNakamura.TimeReminder",
"MapLocalVersions": { "1.0-20170314": "1.0.2" }
},
"Tool Charging": {
"ID": "mralbobo.ToolCharging",
"Default | UpdateKey": "GitHub:mralbobo/stardew-tool-charging"
},
"Tree Spread": {
"ID": "bcmpinc.TreeSpread",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Variable Grass": {
"ID": "dantheman999.VariableGrass",
"Default | UpdateKey": "GitHub:dantheman999301/StardewMods"
},
"Yet Another Harvest With Scythe Mod": {
"ID": "bcmpinc.HarvestWithScythe",
"~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request)
},
"Zoom Out Extreme": {
"ID": "RockinMods.ZoomMod",
"FormerIDs": "ZoomMod", // changed circa 1.2.1
"~0.1 | Status": "AssumeBroken" // broke in SDV 1.2
}
}
}

View File

@ -20,13 +20,13 @@ namespace StardewModdingAPI
** Public
****/
/// <summary>SMAPI's current semantic version.</summary>
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.10.2");
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.0");
/// <summary>The minimum supported version of Stardew Valley.</summary>
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.32");
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.36");
/// <summary>The maximum supported version of Stardew Valley.</summary>
public static ISemanticVersion MaximumGameVersion { get; } = new GameVersion("1.3.33");
public static ISemanticVersion MaximumGameVersion { get; } = null;
/// <summary>The target game platform.</summary>
public static GamePlatform TargetPlatform => (GamePlatform)Constants.Platform;

View File

@ -26,7 +26,7 @@ namespace StardewModdingAPI.Framework.Content
[Obsolete("Access " + nameof(AssetData<IDictionary<TKey, TValue>>.Data) + "field directly.")]
public void Set(TKey key, TValue value)
{
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.Info);
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval);
this.Data[key] = value;
}
@ -36,7 +36,7 @@ namespace StardewModdingAPI.Framework.Content
[Obsolete("Access " + nameof(AssetData<IDictionary<TKey, TValue>>.Data) + "field directly.")]
public void Set(TKey key, Func<TValue, TValue> value)
{
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.Info);
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval);
this.Data[key] = value(this.Data[key]);
}
@ -45,7 +45,7 @@ namespace StardewModdingAPI.Framework.Content
[Obsolete("Access " + nameof(AssetData<IDictionary<TKey, TValue>>.Data) + "field directly.")]
public void Set(Func<TKey, TValue, TValue> replacer)
{
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.Info);
SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval);
foreach (var pair in this.Data.ToArray())
this.Data[pair.Key] = replacer(pair.Key, pair.Value);
}

View File

@ -14,7 +14,11 @@ namespace StardewModdingAPI.Framework
private readonly HashSet<string> LoggedDeprecations = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
/// <summary>Encapsulates monitoring and logging for a given module.</summary>
#if !SMAPI_3_0_STRICT
private readonly Monitor Monitor;
#else
private readonly IMonitor Monitor;
#endif
/// <summary>Tracks the installed mods.</summary>
private readonly ModRegistry ModRegistry;
@ -22,6 +26,11 @@ namespace StardewModdingAPI.Framework
/// <summary>The queued deprecation warnings to display.</summary>
private readonly IList<DeprecationWarning> QueuedWarnings = new List<DeprecationWarning>();
#if !SMAPI_3_0_STRICT
/// <summary>Whether the one-time deprecation message has been shown.</summary>
private bool DeprecationHeaderShown = false;
#endif
/*********
** Public methods
@ -29,7 +38,11 @@ namespace StardewModdingAPI.Framework
/// <summary>Construct an instance.</summary>
/// <param name="monitor">Encapsulates monitoring and logging for a given module.</param>
/// <param name="modRegistry">Tracks the installed mods.</param>
#if !SMAPI_3_0_STRICT
public DeprecationManager(Monitor monitor, ModRegistry modRegistry)
#else
public DeprecationManager(IMonitor monitor, ModRegistry modRegistry)
#endif
{
this.Monitor = monitor;
this.ModRegistry = modRegistry;
@ -38,7 +51,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Log a deprecation warning for the old-style events.</summary>
public void WarnForOldEvents()
{
this.Warn("legacy events", "2.9", DeprecationLevel.Info);
this.Warn("legacy events", "2.9", DeprecationLevel.PendingRemoval);
}
/// <summary>Log a deprecation warning.</summary>
@ -68,15 +81,25 @@ namespace StardewModdingAPI.Framework
/// <summary>Print any queued messages.</summary>
public void PrintQueued()
{
#if !SMAPI_3_0_STRICT
if (!this.DeprecationHeaderShown && this.QueuedWarnings.Any())
{
this.Monitor.Newline();
this.Monitor.Log("Some of your mods will break in the upcoming SMAPI 3.0. Please update your mods now, or notify the author if no update is available. See https://mods.smapi.io for links to the latest versions.", LogLevel.Warn);
this.Monitor.Newline();
this.DeprecationHeaderShown = true;
}
#endif
foreach (DeprecationWarning warning in this.QueuedWarnings.OrderBy(p => p.ModName).ThenBy(p => p.NounPhrase))
{
// build message
#if SMAPI_3_0_STRICT
string message = $"{warning.ModName ?? "An unknown mod"} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version}).";
string message = $"{warning.ModName} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version}).";
#else
string message = warning.NounPhrase == "legacy events"
? $"{warning.ModName ?? "An unknown mod"} uses deprecated code (legacy events are deprecated since SMAPI {warning.Version})."
: $"{warning.ModName ?? "An unknown mod"} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version}).";
? $"{warning.ModName ?? "An unknown mod"} will break in the upcoming SMAPI 3.0 (legacy events are deprecated since SMAPI {warning.Version})."
: $"{warning.ModName ?? "An unknown mod"} will break in the upcoming SMAPI 3.0 ({warning.NounPhrase} is deprecated since SMAPI {warning.Version}).";
#endif
// get log level

View File

@ -166,7 +166,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
[Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.CreateTemporary) + " instead")]
public IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version)
{
SCore.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Info);
SCore.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.PendingRemoval);
return this.ContentPacks.CreateTemporary(directoryPath, id, name, description, author, version);
}

View File

@ -151,7 +151,7 @@ namespace StardewModdingAPI.Framework.ModLoading
mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalisation '{actualFilename}'. The capitalisation must match for crossplatform compatibility.");
continue;
#else
SCore.DeprecationManager.Warn(mod.DisplayName, $"{nameof(IManifest.EntryDll)} value with case-insensitive capitalisation", "2.11", DeprecationLevel.Info);
SCore.DeprecationManager.Warn(mod.DisplayName, $"{nameof(IManifest.EntryDll)} value with case-insensitive capitalisation", "2.11", DeprecationLevel.PendingRemoval);
#endif
}
}

View File

@ -929,7 +929,7 @@ namespace StardewModdingAPI.Framework
// add deprecation warning for old version format
{
if (mod.Manifest?.Version is Toolkit.SemanticVersion version && version.IsLegacyFormat)
SCore.DeprecationManager.Warn(mod.DisplayName, "non-string manifest version", "2.8", DeprecationLevel.Info);
SCore.DeprecationManager.Warn(mod.DisplayName, "non-string manifest version", "2.8", DeprecationLevel.PendingRemoval);
}
#endif

View File

@ -33,7 +33,7 @@ namespace StardewModdingAPI
{
get
{
SCore.DeprecationManager?.Warn($"{nameof(ISemanticVersion)}.{nameof(ISemanticVersion.Build)}", "2.8", DeprecationLevel.Info);
SCore.DeprecationManager?.Warn($"{nameof(ISemanticVersion)}.{nameof(ISemanticVersion.Build)}", "2.8", DeprecationLevel.PendingRemoval);
return this.Version.PrereleaseTag;
}
}