summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Installer/unix-launcher.sh6
-rw-r--r--src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs27
-rw-r--r--src/SMAPI.Mods.SaveBackup/ModEntry.cs107
-rw-r--r--src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj2
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs6
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs2
-rw-r--r--src/SMAPI/Framework/Models/SConfig.cs3
-rw-r--r--src/SMAPI/IAssetDataForImage.cs4
-rw-r--r--src/SMAPI/Program.cs18
-rw-r--r--src/SMAPI/StardewModdingAPI.config.json10
10 files changed, 130 insertions, 55 deletions
diff --git a/src/SMAPI.Installer/unix-launcher.sh b/src/SMAPI.Installer/unix-launcher.sh
index 6e796461..1e969c20 100644
--- a/src/SMAPI.Installer/unix-launcher.sh
+++ b/src/SMAPI.Installer/unix-launcher.sh
@@ -74,11 +74,11 @@ else
elif $COMMAND xterm 2>/dev/null; then
xterm -e "$LAUNCHER"
elif $COMMAND xfce4-terminal 2>/dev/null; then
- xfce4-terminal -e "$LAUNCHER"
+ xfce4-terminal -e "env TERM=xterm; $LAUNCHER"
elif $COMMAND gnome-terminal 2>/dev/null; then
- gnome-terminal -e "$LAUNCHER"
+ gnome-terminal -e "env TERM=xterm; $LAUNCHER"
elif $COMMAND konsole 2>/dev/null; then
- konsole -e "$LAUNCHER"
+ konsole -p Environment=TERM=xterm -e "$LAUNCHER"
elif $COMMAND terminal 2>/dev/null; then
terminal -e "$LAUNCHER"
else
diff --git a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs
index ba2e671d..3fec8215 100644
--- a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs
+++ b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs
@@ -73,11 +73,7 @@ namespace StardewModdingAPI.ModBuildConfig.Framework
continue;
// ignore release zips
- if (this.EqualsInvariant(file.Extension, ".zip"))
- continue;
-
- // ignore Json.NET (bundled into SMAPI)
- if (this.EqualsInvariant(file.Name, "Newtonsoft.Json.dll") || this.EqualsInvariant(file.Name, "Newtonsoft.Json.xml"))
+ if (this.ShouldIgnore(file))
continue;
// add file
@@ -145,6 +141,27 @@ namespace StardewModdingAPI.ModBuildConfig.Framework
/*********
** Private methods
*********/
+ /// <summary>Get whether a build output file should be ignored.</summary>
+ /// <param name="file">The file info.</param>
+ private bool ShouldIgnore(FileInfo file)
+ {
+ return
+ // release zips
+ this.EqualsInvariant(file.Extension, ".zip")
+
+ // Json.NET (bundled into SMAPI)
+ || this.EqualsInvariant(file.Name, "Newtonsoft.Json.dll")
+ || this.EqualsInvariant(file.Name, "Newtonsoft.Json.xml")
+
+ // code analysis files
+ || file.Name.EndsWith(".CodeAnalysisLog.xml", StringComparison.InvariantCultureIgnoreCase)
+ || file.Name.EndsWith(".lastcodeanalysissucceeded", StringComparison.InvariantCultureIgnoreCase)
+
+ // OS metadata files
+ || this.EqualsInvariant(file.Name, ".DS_Store")
+ || this.EqualsInvariant(file.Name, "Thumbs.db");
+ }
+
/// <summary>Get a case-insensitive dictionary matching the given JSON.</summary>
/// <param name="json">The JSON to parse.</param>
private IDictionary<string, object> Parse(string json)
diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
index e9e62752..78578c3c 100644
--- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs
+++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
@@ -1,8 +1,9 @@
using System;
-using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
+using System.Reflection;
using StardewModdingAPI.Mods.SaveBackup.Framework;
using StardewValley;
@@ -27,25 +28,89 @@ namespace StardewModdingAPI.Mods.SaveBackup
{
try
{
- // read config
ModConfig config = this.Helper.ReadConfig<ModConfig>();
// init backup folder
- DirectoryInfo folder = new DirectoryInfo(Path.Combine(this.Helper.DirectoryPath, "backups"));
- folder.Create();
+ DirectoryInfo backupFolder = new DirectoryInfo(Path.Combine(this.Helper.DirectoryPath, "backups"));
+ backupFolder.Create();
// back up saves
+ this.CreateBackup(backupFolder);
+ this.PruneBackups(backupFolder, config.BackupsToKeep);
+ }
+ catch (Exception ex)
+ {
+ this.Monitor.Log($"Error backing up saves: {ex}");
+ }
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Back up the current saves.</summary>
+ /// <param name="backupFolder">The folder containing save backups.</param>
+ private void CreateBackup(DirectoryInfo backupFolder)
+ {
+ try
+ {
+ // get target path
+ FileInfo targetFile = new FileInfo(Path.Combine(backupFolder.FullName, this.FileName));
+ if (targetFile.Exists)
+ targetFile.Delete(); //return;
+
+ // create zip
+ // due to limitations with the bundled Mono on Mac, we can't reference System.IO.Compression.
+ this.Monitor.Log($"Adding {targetFile.Name}...", LogLevel.Trace);
+ switch (Constants.TargetPlatform)
{
- FileInfo file = new FileInfo(Path.Combine(folder.FullName, this.FileName));
- if (!file.Exists)
- {
- this.Monitor.Log($"Adding {file.Name}...", LogLevel.Trace);
- ZipFile.CreateFromDirectory(Constants.SavesPath, file.FullName, CompressionLevel.Fastest, includeBaseDirectory: false);
- }
+ case GamePlatform.Linux:
+ case GamePlatform.Windows:
+ {
+ Assembly coreAssembly = Assembly.Load("System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
+ Assembly fsAssembly = Assembly.Load("System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
+ Type compressionLevelType = coreAssembly.GetType("System.IO.Compression.CompressionLevel") ?? throw new InvalidOperationException("Can't load CompressionLevel type.");
+ Type zipFileType = fsAssembly.GetType("System.IO.Compression.ZipFile") ?? throw new InvalidOperationException("Can't load ZipFile type.");
+ MethodInfo createMethod = zipFileType.GetMethod("CreateFromDirectory", new[] { typeof(string), typeof(string), compressionLevelType, typeof(bool) }) ?? throw new InvalidOperationException("Can't load ZipFile.CreateFromDirectory method.");
+ createMethod.Invoke(null, new object[] { Constants.SavesPath, targetFile.FullName, CompressionLevel.Fastest, false });
+ }
+ break;
+
+ case GamePlatform.Mac:
+ {
+ DirectoryInfo saveFolder = new DirectoryInfo(Constants.SavesPath);
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = "zip",
+ Arguments = $"-rq \"{targetFile.FullName}\" \"{saveFolder.Name}\" -x \"*.DS_Store\" -x \"__MACOSX\"",
+ WorkingDirectory = $"{Constants.SavesPath}/../",
+ CreateNoWindow = true
+ };
+ new Process { StartInfo = startInfo }.Start();
+ }
+ break;
}
+ }
+ 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);
+ }
+ }
+
+ /// <summary>Remove old backups if we've exceeded the limit.</summary>
+ /// <param name="backupFolder">The folder containing save backups.</param>
+ /// <param name="backupsToKeep">The number of backups to keep.</param>
+ private void PruneBackups(DirectoryInfo backupFolder, int backupsToKeep)
+ {
+ try
+ {
+ var oldBackups = backupFolder
+ .GetFiles()
+ .OrderByDescending(p => p.CreationTimeUtc)
+ .Skip(backupsToKeep);
- // prune old saves
- foreach (FileInfo file in this.GetOldBackups(folder, config.BackupsToKeep))
+ foreach (FileInfo file in oldBackups)
{
try
{
@@ -60,23 +125,9 @@ namespace StardewModdingAPI.Mods.SaveBackup
}
catch (Exception ex)
{
- this.Monitor.Log($"Error backing up saves: {ex}");
+ this.Monitor.Log("Couldn't remove old backups (see log file for details).", LogLevel.Warn);
+ this.Monitor.Log(ex.ToString(), LogLevel.Trace);
}
}
-
-
- /*********
- ** Private methods
- *********/
- /// <summary>Get backups ordered by creation date.</summary>
- /// <param name="folder">The folder to search.</param>
- /// <param name="skip">The number of backups to skip.</param>
- private IEnumerable<FileInfo> GetOldBackups(DirectoryInfo folder, int skip)
- {
- return folder
- .GetFiles()
- .OrderByDescending(p => p.CreationTimeUtc)
- .Skip(skip);
- }
}
}
diff --git a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj
index 89e92a8a..44fff536 100644
--- a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj
+++ b/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj
@@ -31,8 +31,6 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
- <Reference Include="System.IO.Compression" />
- <Reference Include="System.IO.Compression.FileSystem" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\build\GlobalAssemblyInfo.cs">
diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs
index 1eef2afb..5c7b87de 100644
--- a/src/SMAPI/Framework/Content/AssetDataForImage.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs
@@ -4,7 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace StardewModdingAPI.Framework.Content
{
- /// <summary>Encapsulates access and changes to dictionary content being read from a data file.</summary>
+ /// <summary>Encapsulates access and changes to image content being read from a data file.</summary>
internal class AssetDataForImage : AssetData<Texture2D>, IAssetDataForImage
{
/*********
@@ -29,6 +29,8 @@ namespace StardewModdingAPI.Framework.Content
public void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace)
{
// get texture
+ if (source == null)
+ throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
Texture2D target = this.Data;
// get areas
@@ -36,8 +38,6 @@ namespace StardewModdingAPI.Framework.Content
targetArea = targetArea ?? new Rectangle(0, 0, Math.Min(sourceArea.Value.Width, target.Width), Math.Min(sourceArea.Value.Height, target.Height));
// validate
- if (source == null)
- throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
if (sourceArea.Value.X < 0 || sourceArea.Value.Y < 0 || sourceArea.Value.Right > source.Width || sourceArea.Value.Bottom > source.Height)
throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
if (targetArea.Value.X < 0 || targetArea.Value.Y < 0 || targetArea.Value.Right > target.Width || targetArea.Value.Bottom > target.Height)
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 5e8efa62..27e40ab4 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -160,7 +160,7 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>Whether input should be suppressed in the current context.</summary>
private bool ShouldSuppressNow()
{
- return Game1.chatBox != null && !Game1.chatBox.isActive();
+ return Game1.chatBox == null || !Game1.chatBox.isActive();
}
/// <summary>Apply input suppression to the given input states.</summary>
diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs
index e201e966..98614933 100644
--- a/src/SMAPI/Framework/Models/SConfig.cs
+++ b/src/SMAPI/Framework/Models/SConfig.cs
@@ -28,5 +28,8 @@ namespace StardewModdingAPI.Framework.Models
/// <summary>The console color scheme to use.</summary>
public MonitorColorScheme ColorScheme { get; set; }
+
+ /// <summary>The mod IDs SMAPI should ignore when performing update checks or validating update keys.</summary>
+ public string[] SuppressUpdateChecks { get; set; }
}
}
diff --git a/src/SMAPI/IAssetDataForImage.cs b/src/SMAPI/IAssetDataForImage.cs
index 4584a20e..1109194f 100644
--- a/src/SMAPI/IAssetDataForImage.cs
+++ b/src/SMAPI/IAssetDataForImage.cs
@@ -1,10 +1,10 @@
-using System;
+using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace StardewModdingAPI
{
- /// <summary>Encapsulates access and changes to dictionary content being read from a data file.</summary>
+ /// <summary>Encapsulates access and changes to image content being read from a data file.</summary>
public interface IAssetDataForImage : IAssetData<Texture2D>
{
/*********
diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs
index 340d2ddb..aeb9b9fb 100644
--- a/src/SMAPI/Program.cs
+++ b/src/SMAPI/Program.cs
@@ -94,14 +94,7 @@ namespace StardewModdingAPI
new Regex(@"^loadPreferences\(\); begin", RegexOptions.Compiled | RegexOptions.CultureInvariant),
new Regex(@"^savePreferences\(\); async=", RegexOptions.Compiled | RegexOptions.CultureInvariant),
new Regex(@"^Multiplayer auth success$", RegexOptions.Compiled | RegexOptions.CultureInvariant),
- new Regex(@"^DebugOutput: added CLOUD", RegexOptions.Compiled | RegexOptions.CultureInvariant)
- };
-
- /// <summary>The mod IDs for which to not show missing update key warnings.</summary>
- private readonly string[] AllowMissingUpdateKeys =
- {
- "SMAPI.ConsoleCommands",
- "SMAPI.SaveBackup"
+ new Regex(@"^DebugOutput: (?:added CLOUD|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant)
};
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
@@ -615,11 +608,15 @@ namespace StardewModdingAPI
{
try
{
+ HashSet<string> suppressUpdateChecks = new HashSet<string>(this.Settings.SuppressUpdateChecks, StringComparer.InvariantCultureIgnoreCase);
+
// prepare update keys
Dictionary<string, IModMetadata[]> modsByKey =
(
from mod in mods
- where mod.Manifest?.UpdateKeys != null
+ where
+ mod.Manifest?.UpdateKeys != null
+ && !suppressUpdateChecks.Contains(mod.Manifest.UniqueID)
from key in mod.Manifest.UpdateKeys
select new { key, mod }
)
@@ -732,6 +729,7 @@ namespace StardewModdingAPI
{
this.Monitor.Log("Loading mods...", LogLevel.Trace);
+ HashSet<string> suppressUpdateChecks = new HashSet<string>(this.Settings.SuppressUpdateChecks, StringComparer.InvariantCultureIgnoreCase);
IDictionary<IModMetadata, string[]> skippedMods = new Dictionary<IModMetadata, string[]>();
void TrackSkip(IModMetadata mod, string userReasonPhrase, string devReasonPhrase = null) => skippedMods[mod] = new[] { userReasonPhrase, devReasonPhrase };
@@ -789,7 +787,7 @@ namespace StardewModdingAPI
: $" {metadata.DisplayName}...", LogLevel.Trace);
// show warnings
- if (metadata.HasManifest() && !metadata.HasUpdateKeys() && !this.AllowMissingUpdateKeys.Contains(metadata.Manifest.UniqueID))
+ if (metadata.HasManifest() && !metadata.HasUpdateKeys() && !suppressUpdateChecks.Contains(metadata.Manifest.UniqueID))
metadata.SetWarning(ModWarning.NoUpdateKeys);
// validate status
diff --git a/src/SMAPI/StardewModdingAPI.config.json b/src/SMAPI/StardewModdingAPI.config.json
index 6725dbbd..7aac6e4c 100644
--- a/src/SMAPI/StardewModdingAPI.config.json
+++ b/src/SMAPI/StardewModdingAPI.config.json
@@ -50,5 +50,13 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha
* - 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"
+ "ColorScheme": "AutoDetect",
+
+ /**
+ * The mod IDs SMAPI should ignore when performing update checks or validating update keys.
+ */
+ "SuppressUpdateChecks": [
+ "SMAPI.ConsoleCommands",
+ "SMAPI.SaveBackup"
+ ]
}