Skip to content

Commit

Permalink
Merge branch 'develop' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Pathoschild committed Feb 22, 2020
2 parents c8d627c + 585b237 commit 66079f2
Show file tree
Hide file tree
Showing 40 changed files with 599 additions and 285 deletions.
2 changes: 1 addition & 1 deletion build/common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<!--set properties -->
<PropertyGroup>
<Version>3.2.0</Version>
<Version>3.3.0</Version>
<Product>SMAPI</Product>

<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
Expand Down
36 changes: 35 additions & 1 deletion docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
&larr; [README](README.md)

# Release notes
## 3.3
Released 22 February 2020 for Stardew Valley 1.4.1 or later.

* For players:
* Improved performance for mods which load many images.
* Reduced network traffic for mod broadcasts to players who can't process them.
* Fixed update-check errors for recent versions of SMAPI on Android.
* Updated draw logic to match recent game updates.
* Updated compatibility list.
* Updated SMAPI/game version map.
* Updated translations. Thanks to xCarloC (added Italian)!

* For the Save Backup mod:
* Fixed warning on MacOS when you have no saves yet.
* Reduced log messages.

* For modders:
* Added support for [message sending](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Integrations#Message_sending) to mods on the current computer (in addition to remote computers).
* Added `ExtendImage` method to content API when editing files to resize textures.
* Added `helper.Input.GetState` to get the low-level state of a button.
* **[Breaking change]** Map tilesheets are no loaded from `Content` if they can't be found in `Content/Maps`. This reflects an upcoming change in the game to delete duplicate map tilesheets under `Content`. Most mods should be unaffected.
* Improved map tilesheet errors so they provide more info.
* When mods load an asset using a more general type like `content.Load<object>`, SMAPI now calls `IAssetEditor` instances with the actual asset type instead of the specified one.
* Updated dependencies (including Mono.Cecil 0.11.1 → 0.11.2).
* Fixed dialogue propagation clearing marriage dialogue.

* For the web UI:
* Updated the JSON validator and Content Patcher schema for `.tmx` support.
* The mod compatibility page now has a sticky table header.

* For SMAPI/tool developers:
* Improved support for four-part versions to support SMAPI on Android.
* The SMAPI log now prefixes the OS name with `Android` on Android.

## 3.2
Released 01 February 2020 for Stardew Valley 1.4.1 or later.

Expand All @@ -23,7 +57,7 @@ Released 01 February 2020 for Stardew Valley 1.4.1 or later.
* Fixed Android issue where game files were backed up.

* For modders:
* Added support for `.tmx` map files.
* Added support for `.tmx` map files. (Thanks to [Platonymous for the underlying library](https://github.com/Platonymous/TMXTile)!)
* Added special handling for `Vector2` values in `.json` files, so they work consistently crossplatform.
* Reworked the order that asset editors/loaders are called between multiple mods to support some framework mods like Content Patcher and Json Assets. Note that the order is undefined and should not be depended on.
* Fixed incorrect warning about mods adding invalid schedules in some cases. The validation was unreliable, and has been removed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
<PrivateAssets>all</PrivateAssets>
Expand Down
4 changes: 2 additions & 2 deletions src/SMAPI.Mods.ConsoleCommands/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
"Version": "3.2.0",
"Version": "3.3.0",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
"MinimumApiVersion": "3.2.0"
"MinimumApiVersion": "3.3.0"
}
46 changes: 29 additions & 17 deletions src/SMAPI.Mods.SaveBackup/ModEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,37 @@ private void CreateBackup(DirectoryInfo backupFolder)
FileInfo targetFile = new FileInfo(Path.Combine(backupFolder.FullName, this.FileName));
DirectoryInfo fallbackDir = new DirectoryInfo(Path.Combine(backupFolder.FullName, this.BackupLabel));
if (targetFile.Exists || fallbackDir.Exists)
{
this.Monitor.Log("Already backed up today.");
return;
}

// copy saves to fallback directory (ignore non-save files/folders)
this.Monitor.Log($"Backing up saves to {fallbackDir.FullName}...", LogLevel.Trace);
DirectoryInfo savesDir = new DirectoryInfo(Constants.SavesPath);
this.RecursiveCopy(savesDir, fallbackDir, entry => this.MatchSaveFolders(savesDir, entry), copyRoot: false);
if (!this.RecursiveCopy(savesDir, fallbackDir, entry => this.MatchSaveFolders(savesDir, entry), copyRoot: false))
{
this.Monitor.Log("No saves found.");
return;
}

// compress backup if possible
this.Monitor.Log("Compressing backup if possible...", LogLevel.Trace);
if (!this.TryCompress(fallbackDir.FullName, targetFile, out Exception compressError))
{
if (Constants.TargetPlatform != GamePlatform.Android) // expected to fail on Android
this.Monitor.Log($"Couldn't compress backup, leaving it uncompressed.\n{compressError}", LogLevel.Trace);
this.Monitor.Log(Constants.TargetPlatform != GamePlatform.Android
? $"Backed up to {fallbackDir.FullName}." // expected to fail on Android
: $"Backed up to {fallbackDir.FullName}. Couldn't compress backup:\n{compressError}"
);
}
else
{
this.Monitor.Log($"Backed up to {targetFile.FullName}.");
fallbackDir.Delete(recursive: true);

this.Monitor.Log("Backup done!", LogLevel.Trace);
}
}
catch (Exception ex)
{
this.Monitor.Log("Couldn't back up save files (see log file for details).", LogLevel.Warn);
this.Monitor.Log(ex.ToString(), LogLevel.Trace);
this.Monitor.Log("Couldn't back up saves (see log file for details).", LogLevel.Warn);
this.Monitor.Log(ex.ToString());
}
}

Expand All @@ -108,7 +116,7 @@ private void PruneBackups(DirectoryInfo backupFolder, int backupsToKeep)
{
try
{
this.Monitor.Log($"Deleting {entry.Name}...", LogLevel.Trace);
this.Monitor.Log($"Deleting {entry.Name}...");
if (entry is DirectoryInfo folder)
folder.Delete(recursive: true);
else
Expand All @@ -123,7 +131,7 @@ private void PruneBackups(DirectoryInfo backupFolder, int backupsToKeep)
catch (Exception ex)
{
this.Monitor.Log("Couldn't remove old backups (see log file for details).", LogLevel.Warn);
this.Monitor.Log(ex.ToString(), LogLevel.Trace);
this.Monitor.Log(ex.ToString());
}
}

Expand Down Expand Up @@ -199,29 +207,33 @@ private void CompressUsingMacProcess(string sourcePath, FileInfo destination)
/// <param name="copyRoot">Whether to copy the root folder itself, or <c>false</c> to only copy its contents.</param>
/// <param name="filter">A filter which matches the files or directories to copy, or <c>null</c> to copy everything.</param>
/// <remarks>Derived from the SMAPI installer code.</remarks>
private void RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, Func<FileSystemInfo, bool> filter, bool copyRoot = true)
/// <returns>Returns whether any files were copied.</returns>
private bool RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, Func<FileSystemInfo, bool> filter, bool copyRoot = true)
{
if (!targetFolder.Exists)
targetFolder.Create();
if (!source.Exists || filter?.Invoke(source) == false)
return false;

if (filter?.Invoke(source) == false)
return;
bool anyCopied = false;

switch (source)
{
case FileInfo sourceFile:
targetFolder.Create();
sourceFile.CopyTo(Path.Combine(targetFolder.FullName, sourceFile.Name));
anyCopied = true;
break;

case DirectoryInfo sourceDir:
DirectoryInfo targetSubfolder = copyRoot ? new DirectoryInfo(Path.Combine(targetFolder.FullName, sourceDir.Name)) : targetFolder;
foreach (var entry in sourceDir.EnumerateFileSystemInfos())
this.RecursiveCopy(entry, targetSubfolder, filter);
anyCopied = this.RecursiveCopy(entry, targetSubfolder, filter) || anyCopied;
break;

default:
throw new NotSupportedException($"Unknown filesystem info type '{source.GetType().FullName}'.");
}

return anyCopied;
}

/// <summary>A copy filter which matches save folders.</summary>
Expand Down
4 changes: 2 additions & 2 deletions src/SMAPI.Mods.SaveBackup/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
"Version": "3.2.0",
"Version": "3.3.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
"MinimumApiVersion": "3.2.0"
"MinimumApiVersion": "3.3.0"
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Serialization.Converters;

namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
/// <summary>Metadata about a version.</summary>
Expand All @@ -7,6 +10,7 @@ public class ModEntryVersionModel
** Accessors
*********/
/// <summary>The version number.</summary>
[JsonConverter(typeof(NonStandardSemanticVersionConverter))]
public ISemanticVersion Version { get; set; }

/// <summary>The mod page URL.</summary>
Expand Down
2 changes: 1 addition & 1 deletion src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.18" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.20" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.3.1" />
<PackageReference Include="System.Management" Version="4.5.0" Condition="'$(OS)' == 'Windows_NT'" />
Expand Down
9 changes: 5 additions & 4 deletions src/SMAPI.Toolkit/SemanticVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,19 @@ public bool IsNonStandard()
/// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParse(string version, out ISemanticVersion parsed)
{
return SemanticVersion.TryParseNonStandard(version, out parsed) && !parsed.IsNonStandard();
return SemanticVersion.TryParse(version, allowNonStandard: false, out parsed);
}

/// <summary>Parse a version string without throwing an exception if it fails, including support for non-standard extensions like <see cref="IPlatformSpecificVersion"/>.</summary>
/// <summary>Parse a version string without throwing an exception if it fails.</summary>
/// <param name="version">The version string.</param>
/// <param name="allowNonStandard">Whether to allow non-standard extensions to semantic versioning.</param>
/// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParseNonStandard(string version, out ISemanticVersion parsed)
public static bool TryParse(string version, bool allowNonStandard, out ISemanticVersion parsed)
{
try
{
parsed = new SemanticVersion(version, true);
parsed = new SemanticVersion(version, allowNonStandard);
return true;
}
catch
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace StardewModdingAPI.Toolkit.Serialization.Converters
{
/// <summary>Handles deserialization of <see cref="ISemanticVersion"/>, allowing for non-standard extensions.</summary>
internal class NonStandardSemanticVersionConverter : SemanticVersionConverter
{
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
public NonStandardSemanticVersionConverter()
{
this.AllowNonStandard = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters
/// <summary>Handles deserialization of <see cref="ISemanticVersion"/>.</summary>
internal class SemanticVersionConverter : JsonConverter
{
/*********
** Fields
*********/
/// <summary>Whether to allow non-standard extensions to semantic versioning.</summary>
protected bool AllowNonStandard { get; set; }


/*********
** Accessors
*********/
Expand Down Expand Up @@ -78,7 +85,7 @@ private ISemanticVersion ReadString(string str, string path)
{
if (string.IsNullOrWhiteSpace(str))
return null;
if (!SemanticVersion.TryParse(str, out ISemanticVersion version))
if (!SemanticVersion.TryParse(str, allowNonStandard: this.AllowNonStandard, out ISemanticVersion version))
throw new SParseException($"Can't parse semantic version from invalid value '{str}', should be formatted like 1.2, 1.2.30, or 1.2.30-beta (path: {path}).");
return version;
}
Expand Down
14 changes: 13 additions & 1 deletion src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,19 @@ public static string GetFriendlyPlatformName(Platform platform)
}
catch { }
#endif
return (platform == Platform.Mac ? "MacOS " : "") + Environment.OSVersion;

string name = Environment.OSVersion.ToString();
switch (platform)
{
case Platform.Android:
name = $"Android {name}";
break;

case Platform.Mac:
name = $"MacOS {name}";
break;
}
return name;
}

/// <summary>Get the name of the Stardew Valley executable.</summary>
Expand Down
Loading

0 comments on commit 66079f2

Please sign in to comment.