summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForMap.cs90
-rw-r--r--src/SMAPI/Framework/Content/ContentCache.cs21
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs41
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs17
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs2
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs14
-rw-r--r--src/SMAPI/Framework/Input/GamePadStateBuilder.cs19
-rw-r--r--src/SMAPI/Framework/InternalExtensions.cs7
-rw-r--r--src/SMAPI/Framework/Logging/LogManager.cs33
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs5
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs10
-rw-r--r--src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs2
-rw-r--r--src/SMAPI/Framework/SCore.cs33
-rw-r--r--src/SMAPI/Framework/SGame.cs162
-rw-r--r--src/SMAPI/Framework/SModHooks.cs30
15 files changed, 241 insertions, 245 deletions
diff --git a/src/SMAPI/Framework/Content/AssetDataForMap.cs b/src/SMAPI/Framework/Content/AssetDataForMap.cs
index 4f810948..0a5fa7e7 100644
--- a/src/SMAPI/Framework/Content/AssetDataForMap.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForMap.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using StardewModdingAPI.Toolkit.Utilities;
+using StardewValley;
using xTile;
using xTile.Layers;
using xTile.Tiles;
@@ -25,18 +26,17 @@ namespace StardewModdingAPI.Framework.Content
: base(locale, assetName, data, getNormalizedPath, onDataReplaced) { }
/// <inheritdoc />
- /// <remarks>Derived from <see cref="StardewValley.GameLocation.ApplyMapOverride"/> with a few changes:
+ /// <remarks>Derived from <see cref="GameLocation.ApplyMapOverride(Map,string,Rectangle?,Rectangle?)"/> with a few changes:
/// - can be applied directly to the maps when loading, before the location is created;
- /// - added support for source/target areas;
+ /// - added support for patch modes (overlay, replace by layer, or fully replace);
/// - added disambiguation if source has a modified version of the same tilesheet, instead of copying tiles into the target tilesheet;
- /// - changed to always overwrite tiles within the target area (to avoid edge cases where some tiles are only partly applied);
/// - fixed copying tilesheets (avoid "The specified TileSheet was not created for use with this map" error);
/// - fixed tilesheets not added at the end (via z_ prefix), which can cause crashes in game code which depends on hardcoded tilesheet indexes;
/// - fixed issue where different tilesheets are linked by ID.
/// </remarks>
- public void PatchMap(Map source, Rectangle? sourceArea = null, Rectangle? targetArea = null)
+ public void PatchMap(Map source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMapMode patchMode = PatchMapMode.Overlay)
{
- var target = this.Data;
+ Map target = this.Data;
// get areas
{
@@ -84,10 +84,13 @@ namespace StardewModdingAPI.Framework.Content
tilesheetMap[sourceSheet] = targetSheet;
}
- // get layer map
- IDictionary<Layer, Layer> layerMap = source.Layers.ToDictionary(p => p, p => target.GetLayer(p.Id));
+ // get target layers
+ IDictionary<Layer, Layer> sourceToTargetLayers = source.Layers.ToDictionary(p => p, p => target.GetLayer(p.Id));
+ HashSet<Layer> orphanedTargetLayers = new HashSet<Layer>(target.Layers.Except(sourceToTargetLayers.Values));
// apply tiles
+ bool replaceAll = patchMode == PatchMapMode.Replace;
+ bool replaceByLayer = patchMode == PatchMapMode.ReplaceByLayer;
for (int x = 0; x < sourceArea.Value.Width; x++)
{
for (int y = 0; y < sourceArea.Value.Height; y++)
@@ -96,47 +99,37 @@ namespace StardewModdingAPI.Framework.Content
Point sourcePos = new Point(sourceArea.Value.X + x, sourceArea.Value.Y + y);
Point targetPos = new Point(targetArea.Value.X + x, targetArea.Value.Y + y);
+ // replace tiles on target-only layers
+ if (replaceAll)
+ {
+ foreach (Layer targetLayer in orphanedTargetLayers)
+ targetLayer.Tiles[targetPos.X, targetPos.Y] = null;
+ }
+
// merge layers
foreach (Layer sourceLayer in source.Layers)
{
// get layer
- Layer targetLayer = layerMap[sourceLayer];
+ Layer targetLayer = sourceToTargetLayers[sourceLayer];
if (targetLayer == null)
{
target.AddLayer(targetLayer = new Layer(sourceLayer.Id, target, target.Layers[0].LayerSize, Layer.m_tileSize));
- layerMap[sourceLayer] = target.GetLayer(sourceLayer.Id);
+ sourceToTargetLayers[sourceLayer] = target.GetLayer(sourceLayer.Id);
}
// copy layer properties
targetLayer.Properties.CopyFrom(sourceLayer.Properties);
- // copy tiles
+ // create new tile
Tile sourceTile = sourceLayer.Tiles[sourcePos.X, sourcePos.Y];
- Tile targetTile;
- switch (sourceTile)
- {
- case StaticTile _:
- targetTile = new StaticTile(targetLayer, tilesheetMap[sourceTile.TileSheet], sourceTile.BlendMode, sourceTile.TileIndex);
- break;
-
- case AnimatedTile animatedTile:
- {
- StaticTile[] tileFrames = new StaticTile[animatedTile.TileFrames.Length];
- for (int frame = 0; frame < animatedTile.TileFrames.Length; ++frame)
- {
- StaticTile frameTile = animatedTile.TileFrames[frame];
- tileFrames[frame] = new StaticTile(targetLayer, tilesheetMap[frameTile.TileSheet], frameTile.BlendMode, frameTile.TileIndex);
- }
- targetTile = new AnimatedTile(targetLayer, tileFrames, animatedTile.FrameInterval);
- }
- break;
-
- default: // null or unhandled type
- targetTile = null;
- break;
- }
- targetTile?.Properties.CopyFrom(sourceTile.Properties);
- targetLayer.Tiles[targetPos.X, targetPos.Y] = targetTile;
+ Tile newTile = sourceTile != null
+ ? this.CreateTile(sourceTile, targetLayer, tilesheetMap[sourceTile.TileSheet])
+ : null;
+ newTile?.Properties.CopyFrom(sourceTile.Properties);
+
+ // replace tile
+ if (newTile != null || replaceByLayer || replaceAll)
+ targetLayer.Tiles[targetPos.X, targetPos.Y] = newTile;
}
}
}
@@ -146,6 +139,33 @@ namespace StardewModdingAPI.Framework.Content
/*********
** Private methods
*********/
+ /// <summary>Create a new tile for the target map.</summary>
+ /// <param name="sourceTile">The source tile to copy.</param>
+ /// <param name="targetLayer">The target layer.</param>
+ /// <param name="targetSheet">The target tilesheet.</param>
+ private Tile CreateTile(Tile sourceTile, Layer targetLayer, TileSheet targetSheet)
+ {
+ switch (sourceTile)
+ {
+ case StaticTile _:
+ return new StaticTile(targetLayer, targetSheet, sourceTile.BlendMode, sourceTile.TileIndex);
+
+ case AnimatedTile animatedTile:
+ {
+ StaticTile[] tileFrames = new StaticTile[animatedTile.TileFrames.Length];
+ for (int frame = 0; frame < animatedTile.TileFrames.Length; ++frame)
+ {
+ StaticTile frameTile = animatedTile.TileFrames[frame];
+ tileFrames[frame] = new StaticTile(targetLayer, targetSheet, frameTile.BlendMode, frameTile.TileIndex);
+ }
+
+ return new AnimatedTile(targetLayer, tileFrames, animatedTile.FrameInterval);
+ }
+
+ default: // null or unhandled type
+ return null;
+ }
+ }
/// <summary>Normalize a map tilesheet path for comparison. This value should *not* be used as the actual tilesheet path.</summary>
/// <param name="path">The path to normalize.</param>
private string NormalizeTilesheetPathForComparison(string path)
diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs
index 7edc9ab9..8e0c6228 100644
--- a/src/SMAPI/Framework/Content/ContentCache.cs
+++ b/src/SMAPI/Framework/Content/ContentCache.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
-using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework.Reflection;
using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
@@ -18,9 +17,6 @@ namespace StardewModdingAPI.Framework.Content
/// <summary>The underlying asset cache.</summary>
private readonly IDictionary<string, object> Cache;
- /// <summary>Applies platform-specific asset key normalization so it's consistent with the underlying cache.</summary>
- private readonly Func<string, string> NormalizeAssetNameForPlatform;
-
/*********
** Accessors
@@ -48,17 +44,7 @@ namespace StardewModdingAPI.Framework.Content
/// <param name="reflection">Simplifies access to private game code.</param>
public ContentCache(LocalizedContentManager contentManager, Reflector reflection)
{
- // init
this.Cache = reflection.GetField<Dictionary<string, object>>(contentManager, "loadedAssets").GetValue();
-
- // get key normalization logic
- if (Constants.GameFramework == GameFramework.Xna)
- {
- IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath");
- this.NormalizeAssetNameForPlatform = path => method.Invoke<string>(path);
- }
- else
- this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic
}
/****
@@ -75,23 +61,24 @@ namespace StardewModdingAPI.Framework.Content
/****
** Normalize
****/
- /// <summary>Normalize path separators in a file path. For asset keys, see <see cref="NormalizeKey"/> instead.</summary>
+ /// <summary>Normalize path separators in an asset name.</summary>
/// <param name="path">The file path to normalize.</param>
[Pure]
public string NormalizePathSeparators(string path)
{
- return PathUtilities.NormalizePath(path);
+ return PathUtilities.NormalizeAssetName(path);
}
/// <summary>Normalize a cache key so it's consistent with the underlying cache.</summary>
/// <param name="key">The asset key.</param>
+ /// <remarks>This is equivalent to <see cref="NormalizePathSeparators"/> with added file extension logic.</remarks>
[Pure]
public string NormalizeKey(string key)
{
key = this.NormalizePathSeparators(key);
return key.EndsWith(".xnb", StringComparison.OrdinalIgnoreCase)
? key.Substring(0, key.Length - 4)
- : this.NormalizeAssetNameForPlatform(key);
+ : key;
}
/****
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index d0e759c2..b6f1669a 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -64,6 +64,9 @@ namespace StardewModdingAPI.Framework
/// <summary>An unmodified content manager which doesn't intercept assets, used to compare asset data.</summary>
private readonly LocalizedContentManager VanillaContentManager;
+ /// <summary>The language enum values indexed by locale code.</summary>
+ private Lazy<IDictionary<string, LocalizedContentManager.LanguageCode>> LocaleCodes;
+
/*********
** Accessors
@@ -133,6 +136,7 @@ namespace StardewModdingAPI.Framework
this.ContentManagers.Add(contentManagerForAssetPropagation);
this.VanillaContentManager = new LocalizedContentManager(serviceProvider, rootDirectory);
this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, this.Monitor, reflection, aggressiveMemoryOptimizations);
+ this.LocaleCodes = new Lazy<IDictionary<string, LocalizedContentManager.LanguageCode>>(this.GetLocaleCodes);
}
/// <summary>Get a new content manager which handles reading files from the game content folder with support for interception.</summary>
@@ -195,6 +199,10 @@ namespace StardewModdingAPI.Framework
/// <summary>Perform any cleanup needed when the locale changes.</summary>
public void OnLocaleChanged()
{
+ // rebuild locale cache (which may change due to custom mod languages)
+ this.LocaleCodes = new Lazy<IDictionary<string, LocalizedContentManager.LanguageCode>>(this.GetLocaleCodes);
+
+ // reload affected content
this.ContentManagerLock.InReadLock(() =>
{
foreach (IContentManager contentManager in this.ContentManagers)
@@ -408,6 +416,25 @@ namespace StardewModdingAPI.Framework
return tilesheets ?? new TilesheetReference[0];
}
+ /// <summary>Get the language enum which corresponds to a locale code (e.g. <see cref="LocalizedContentManager.LanguageCode.fr"/> given <c>fr-FR</c>).</summary>
+ /// <param name="locale">The locale code to search. This must exactly match the language; no fallback is performed.</param>
+ /// <param name="language">The matched language enum, if any.</param>
+ /// <returns>Returns whether a valid language was found.</returns>
+ public bool TryGetLanguageEnum(string locale, out LocalizedContentManager.LanguageCode language)
+ {
+ return this.LocaleCodes.Value.TryGetValue(locale, out language);
+ }
+
+ /// <summary>Get the locale code which corresponds to a language enum (e.g. <c>fr-FR</c> given <see cref="LocalizedContentManager.LanguageCode.fr"/>).</summary>
+ /// <param name="language">The language enum to search.</param>
+ public string GetLocaleCode(LocalizedContentManager.LanguageCode language)
+ {
+ if (language == LocalizedContentManager.LanguageCode.mod && LocalizedContentManager.CurrentModLanguage == null)
+ return null;
+
+ return Game1.content.LanguageCodeString(language);
+ }
+
/// <summary>Dispose held resources.</summary>
public void Dispose()
{
@@ -457,5 +484,19 @@ namespace StardewModdingAPI.Framework
return false;
}
}
+
+ /// <summary>Get the language enums (like <see cref="LocalizedContentManager.LanguageCode.ja"/>) indexed by locale code (like <c>ja-JP</c>).</summary>
+ private IDictionary<string, LocalizedContentManager.LanguageCode> GetLocaleCodes()
+ {
+ IDictionary<string, LocalizedContentManager.LanguageCode> map = new Dictionary<string, LocalizedContentManager.LanguageCode>();
+ foreach (LocalizedContentManager.LanguageCode code in Enum.GetValues(typeof(LocalizedContentManager.LanguageCode)))
+ {
+ string locale = this.GetLocaleCode(code);
+ if (locale != null)
+ map[locale] = code;
+ }
+
+ return map;
+ }
}
}
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 7244a534..5645c0fa 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -38,9 +38,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>A callback to invoke when the content manager is being disposed.</summary>
private readonly Action<BaseContentManager> OnDisposing;
- /// <summary>The language enum values indexed by locale code.</summary>
- protected IDictionary<string, LanguageCode> LanguageCodes { get; }
-
/// <summary>A list of disposable assets.</summary>
private readonly List<WeakReference<IDisposable>> Disposables = new List<WeakReference<IDisposable>>();
@@ -92,7 +89,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.AggressiveMemoryOptimizations = aggressiveMemoryOptimizations;
// get asset data
- this.LanguageCodes = this.GetKeyLocales().ToDictionary(p => p.Value, p => p.Key, StringComparer.OrdinalIgnoreCase);
this.BaseDisposableReferences = reflection.GetField<List<IDisposable>>(this, "disposableAssets").GetValue();
}
@@ -292,7 +288,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
if (lastSepIndex >= 0)
{
string suffix = cacheKey.Substring(lastSepIndex + 1, cacheKey.Length - lastSepIndex - 1);
- if (this.LanguageCodes.ContainsKey(suffix))
+ if (this.Coordinator.TryGetLanguageEnum(suffix, out _))
{
assetName = cacheKey.Substring(0, lastSepIndex);
localeCode = cacheKey.Substring(lastSepIndex + 1, cacheKey.Length - lastSepIndex - 1);
@@ -311,17 +307,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="language">The language to check.</param>
protected abstract bool IsNormalizedKeyLoaded(string normalizedAssetName, LanguageCode language);
- /// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary>
- private IDictionary<LanguageCode, string> GetKeyLocales()
- {
- // create locale => code map
- IDictionary<LanguageCode, string> map = new Dictionary<LanguageCode, string>();
- foreach (LanguageCode code in Enum.GetValues(typeof(LanguageCode)))
- map[code] = this.GetLocale(code);
-
- return map;
- }
-
/// <summary>Get the asset name from a cache key.</summary>
/// <param name="cacheKey">The input cache key.</param>
private string GetAssetName(string cacheKey)
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index 38bcf153..7a49dd36 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -249,7 +249,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
// extract language code
int splitIndex = rawAsset.LastIndexOf('.');
- if (splitIndex != -1 && this.LanguageCodes.TryGetValue(rawAsset.Substring(splitIndex + 1), out language))
+ if (splitIndex != -1 && this.Coordinator.TryGetLanguageEnum(rawAsset.Substring(splitIndex + 1), out language))
{
assetName = rawAsset.Substring(0, splitIndex);
return true;
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index d24ffb81..beb90a5d 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -2,12 +2,12 @@ using System;
using System.Globalization;
using System.IO;
using System.Linq;
+using BmFont;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.Reflection;
-using StardewModdingAPI.Internal;
using StardewModdingAPI.Toolkit.Serialization;
using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
@@ -130,6 +130,14 @@ namespace StardewModdingAPI.Framework.ContentManagers
}
break;
+ // unpacked Bitmap font
+ case ".fnt":
+ {
+ string source = File.ReadAllText(file.FullName);
+ asset = (T)(object)new XmlSource(source);
+ }
+ break;
+
// unpacked data
case ".json":
{
@@ -172,13 +180,11 @@ namespace StardewModdingAPI.Framework.ContentManagers
break;
default:
- throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.json', '.png', '.tbin', or '.xnb'.");
+ throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.fnt', '.json', '.png', '.tbin', or '.xnb'.");
}
}
catch (Exception ex) when (!(ex is SContentLoadException))
{
- if (ex.GetInnermostException() is DllNotFoundException dllEx && dllEx.Message == "libgdiplus.dylib")
- throw GetContentError("couldn't find libgdiplus, which is needed to load mod images. Make sure Mono is installed and you're running the game through the normal launcher.");
throw new SContentLoadException($"The content manager failed loading content asset '{assetName}' from {this.Name}.", ex);
}
diff --git a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
index f5f2d916..b0bb7f80 100644
--- a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
@@ -157,11 +158,8 @@ namespace StardewModdingAPI.Framework.Input
yield break;
// buttons
- foreach (var pair in this.ButtonStates)
- {
- if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
- yield return button.ToSButton();
- }
+ foreach (Buttons button in this.GetPressedGamePadButtons())
+ yield return button.ToSButton();
// triggers
if (this.LeftTrigger > 0.2f)
@@ -201,7 +199,7 @@ namespace StardewModdingAPI.Framework.Input
rightThumbStick: this.RightStickPos,
leftTrigger: this.LeftTrigger,
rightTrigger: this.RightTrigger,
- buttons: this.GetButtonBitmask() // MonoGame requires one bitmask here; don't specify multiple values
+ buttons: this.GetPressedGamePadButtons().ToArray()
);
return this.State.Value;
@@ -211,17 +209,14 @@ namespace StardewModdingAPI.Framework.Input
/*********
** Private methods
*********/
- /// <summary>Get a bitmask representing the pressed buttons.</summary>
- private Buttons GetButtonBitmask()
+ /// <summary>Get the pressed gamepad buttons.</summary>
+ private IEnumerable<Buttons> GetPressedGamePadButtons()
{
- Buttons flag = 0;
foreach (var pair in this.ButtonStates)
{
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
- flag |= button;
+ yield return button;
}
-
- return flag;
}
}
}
diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs
index 6c9a5f3b..4cb77a45 100644
--- a/src/SMAPI/Framework/InternalExtensions.cs
+++ b/src/SMAPI/Framework/InternalExtensions.cs
@@ -6,7 +6,6 @@ using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Reflection;
-using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI.Framework
@@ -150,11 +149,7 @@ namespace StardewModdingAPI.Framework
/// <param name="reflection">The reflection helper with which to access private fields.</param>
public static bool IsOpen(this SpriteBatch spriteBatch, Reflector reflection)
{
- string fieldName = Constants.GameFramework == GameFramework.Xna
- ? "inBeginEndPair"
- : "_beginCalled";
-
- return reflection.GetField<bool>(Game1.spriteBatch, fieldName).GetValue();
+ return reflection.GetField<bool>(spriteBatch, "_beginCalled").GetValue();
}
}
}
diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs
index f2876146..5a291d0a 100644
--- a/src/SMAPI/Framework/Logging/LogManager.cs
+++ b/src/SMAPI/Framework/Logging/LogManager.cs
@@ -250,36 +250,7 @@ namespace StardewModdingAPI.Framework.Logging
/// <param name="exception">The exception details.</param>
public void LogFatalLaunchError(Exception exception)
{
- switch (exception)
- {
- // audio crash
- case InvalidOperationException ex when ex.Source == "Microsoft.Xna.Framework.Xact" && ex.StackTrace.Contains("Microsoft.Xna.Framework.Audio.AudioEngine..ctor"):
- this.Monitor.Log("The game couldn't load audio. Do you have speakers or headphones plugged in?", LogLevel.Error);
- this.Monitor.Log($"Technical details: {ex.GetLogSummary()}");
- break;
-
- // missing content folder exception
- case FileNotFoundException ex when ex.Message == "Couldn't find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.": // path in error is hardcoded regardless of install path
- this.Monitor.Log("The game can't find its Content\\XACT\\FarmerSounds.xgs file. You can usually fix this by resetting your content files (see https://smapi.io/troubleshoot#reset-content ), or by uninstalling and reinstalling the game.", LogLevel.Error);
- this.Monitor.Log($"Technical details: {ex.GetLogSummary()}");
- break;
-
- // path too long exception
- case PathTooLongException _:
- {
- string[] affectedPaths = PathUtilities.GetTooLongPaths(Constants.ModsPath).ToArray();
- string message = affectedPaths.Any()
- ? $"SMAPI can't launch because some of your mod files exceed the maximum path length on {Constants.Platform}.\nIf you need help fixing this error, see https://smapi.io/help\n\nAffected paths:\n {string.Join("\n ", affectedPaths)}"
- : $"The game failed to launch: {exception.GetLogSummary()}";
- this.MonitorForGame.Log(message, LogLevel.Error);
- }
- break;
-
- // generic exception
- default:
- this.MonitorForGame.Log($"The game failed to launch: {exception.GetLogSummary()}", LogLevel.Error);
- break;
- }
+ this.MonitorForGame.Log($"The game failed to launch: {exception.GetLogSummary()}", LogLevel.Error);
}
/****
@@ -290,7 +261,7 @@ namespace StardewModdingAPI.Framework.Logging
/// <param name="customSettings">The custom SMAPI settings.</param>
public void LogIntro(string modsPath, IDictionary<string, object> customSettings)
{
- // log platform & patches
+ // log platform
this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info);
// log basic info
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
index 57a76a35..cb5fa2ae 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
@@ -53,16 +53,15 @@ namespace StardewModdingAPI.Framework.ModLoading
*********/
/// <summary>Construct an instance.</summary>
/// <param name="targetPlatform">The current game platform.</param>
- /// <param name="framework">The game framework running the game.</param>
/// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <param name="paranoidMode">Whether to detect paranoid mode issues.</param>
/// <param name="rewriteMods">Whether to rewrite mods for compatibility.</param>
- public AssemblyLoader(Platform targetPlatform, GameFramework framework, IMonitor monitor, bool paranoidMode, bool rewriteMods)
+ public AssemblyLoader(Platform targetPlatform, IMonitor monitor, bool paranoidMode, bool rewriteMods)
{
this.Monitor = monitor;
this.ParanoidMode = paranoidMode;
this.RewriteMods = rewriteMods;
- this.AssemblyMap = this.TrackForDisposal(Constants.GetAssemblyMap(targetPlatform, framework));
+ this.AssemblyMap = this.TrackForDisposal(Constants.GetAssemblyMap(targetPlatform));
// init resolver
this.AssemblyDefinitionResolver = this.TrackForDisposal(new AssemblyDefinitionResolver());
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
index aefd1c20..a064f503 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
@@ -4,7 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
- /// <summary>Provides <see cref="SpriteBatch"/> method signatures that can be injected into mod code for compatibility between Linux/macOS or Windows.</summary>
+ /// <summary>Provides <see cref="SpriteBatch"/> method signatures that can be injected into mod code for compatibility with mods written for XNA Framework before Stardew Valley 1.5.5.</summary>
/// <remarks>This is public to support SMAPI rewriting and should not be referenced directly by mods.</remarks>
[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "Used via assembly rewriting")]
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Linux/macOS.")]
@@ -19,14 +19,6 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
/****
- ** MonoGame signatures
- ****/
- public new void Begin(SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState, Effect effect, Matrix? matrix)
- {
- base.Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, matrix ?? Matrix.Identity);
- }
-
- /****
** XNA signatures
****/
public new void Begin()
diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
index 8d1b6034..5acba569 100644
--- a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
+++ b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
@@ -24,7 +24,7 @@ namespace StardewModdingAPI.Framework.Reflection
/// <summary>Construct an instance.</summary>
public InterfaceProxyFactory()
{
- AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName($"StardewModdingAPI.Proxies, Version={this.GetType().Assembly.GetName().Version}, Culture=neutral"), AssemblyBuilderAccess.Run);
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"StardewModdingAPI.Proxies, Version={this.GetType().Assembly.GetName().Version}, Culture=neutral"), AssemblyBuilderAccess.Run);
this.ModuleBuilder = assemblyBuilder.DefineDynamicModule("StardewModdingAPI.Proxies");
}
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 6dffb1de..55a7f083 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -11,14 +11,10 @@ using System.Runtime.ExceptionServices;
using System.Security;
using System.Text;
using System.Threading;
-using System.Threading.Tasks;
using Microsoft.Xna.Framework;
#if SMAPI_FOR_WINDOWS
using Microsoft.Win32;
#endif
-#if SMAPI_FOR_XNA
-using System.Windows.Forms;
-#endif
using Newtonsoft.Json;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Events;
@@ -224,10 +220,6 @@ namespace StardewModdingAPI.Framework
this.Toolkit.JsonHelper.JsonSettings.Converters.Add(converter);
// add error handlers
-#if SMAPI_FOR_XNA
- Application.ThreadException += (sender, e) => this.Monitor.Log($"Critical thread exception: {e.Exception.GetLogSummary()}", LogLevel.Error);
- Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
-#endif
AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error);
// add more lenient assembly resolver
@@ -243,7 +235,7 @@ namespace StardewModdingAPI.Framework
monitor: this.Monitor,
reflection: this.Reflection,
eventManager: this.EventManager,
- modHooks: new SModHooks(this.OnNewDayAfterFade),
+ modHooks: new SModHooks(this.OnNewDayAfterFade, this.Monitor),
multiplayer: this.Multiplayer,
exitGameImmediately: this.ExitGameImmediately,
@@ -657,13 +649,6 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log("Game loader done.");
}
- if (instance.NewDayTask?.Status == TaskStatus.Created)
- {
- this.Monitor.Log("New day task synchronizing...");
- instance.NewDayTask.RunSynchronously();
- this.Monitor.Log("New day task done.");
- }
-
// While a background task is in progress, the game may make changes to the game
// state while mods are running their code. This is risky, because data changes can
// conflict (e.g. collection changed during enumeration errors) and data may change
@@ -673,7 +658,7 @@ namespace StardewModdingAPI.Framework
// a small chance that the task will finish after we defer but before the game checks,
// which means technically events should be raised, but the effects of missing one
// update tick are negligible and not worth the complications of bypassing Game1.Update.
- if (instance.NewDayTask